Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
bd46b5a
test: prove direct pipe byte pump framing
lawrencecchen Aug 23, 2026
0e81167
test(tui): pin the attach --pipe-io relay contract (red)
lawrencecchen Aug 25, 2026
50e7d3e
feat(tui): attach --pipe-io byte relay for embedder-fed surfaces
lawrencecchen Aug 25, 2026
1b362be
style(tui): cargo fmt for pipe_io
lawrencecchen Aug 25, 2026
78f7681
style(tui): cargo fmt for pipe-io tests
lawrencecchen Aug 25, 2026
9597e9f
fix(tui): make PipeBytePump test sender droppable without partial move
lawrencecchen Aug 25, 2026
572e734
feat(app): manual-IO data path for the tui terminal backend
lawrencecchen Aug 25, 2026
04d9267
fix(tui): pipe-io classifies terminal-close vs daemon-loss with a probe
lawrencecchen Aug 25, 2026
683a8ca
fix(app): bound unexplained tui relay failures in a visible failed state
lawrencecchen Aug 25, 2026
ff0be34
style(tui): apply hosted rustfmt patch for classify_daemon_loss
lawrencecchen Aug 25, 2026
1fa2c1b
fix(tui): pipe-io claims terminal geometry so embedder resizes apply
lawrencecchen Aug 25, 2026
0fce771
fix(terminal): feed remote output off-main through a drained serial q…
lawrencecchen Aug 25, 2026
09c5553
fix(app): manual-IO pump attaches at the current grid, not only on re…
lawrencecchen Aug 25, 2026
9bb6850
fix(tui,app): daemon-restart windows retry instead of failing the pane
lawrencecchen Aug 25, 2026
4db830d
style(tui): rustfmt for the dead-socket relay test
lawrencecchen Aug 25, 2026
12759b1
fix(app): classify relay exits only after stderr EOF
lawrencecchen Aug 25, 2026
584e841
debug(app): log relay exit status and stderr tail in debug builds
lawrencecchen Aug 25, 2026
befdff9
fix(tests): import CmuxTerminal for the remote-output feed test
lawrencecchen Aug 25, 2026
09bb3fe
Merge remote-tracking branch 'origin/feat-tui-attach-spike' into feat…
lawrencecchen Aug 28, 2026
7cff93c
chore: adopt main's ghostty and bonsplit submodule pins
lawrencecchen Aug 28, 2026
2512780
fix: resolve xcstrings merge corruption (markers + stale duplicate bl…
lawrencecchen Aug 28, 2026
ba64d22
fix: resolve committed conflict markers; adopt main's remote-output lane
lawrencecchen Aug 28, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,19 @@ public struct BetaFeaturesCatalogSection: SettingCatalogSection {
userDefaultsKey: "terminal.beta.tuiBackend.enabled"
)

/// Manual-IO variant of the cmux-tui terminal backend: instead of
/// running `cmux-tui attach` as the surface command (exec bridge), the
/// surface runs in Ghostty's manual-mirror IO mode and an app-side pump
/// relays bytes to/from the daemon through `attach --pipe-io`. The
/// surface parses the daemon terminal's own byte stream, so input
/// encodings always match the daemon's mode state. Requires
/// `tuiTerminalBackend`; defaults off (exec bridge).
public let tuiTerminalBackendManualIO = DefaultsKey<Bool>(
id: "terminal.beta.tuiBackend.manualIO",
defaultValue: false,
userDefaultsKey: "terminal.beta.tuiBackend.manualIO"
)

/// Path to the cmux-tui binary used by the `tuiTerminalBackend` spike.
/// Dev-only setting with a spike-only default pointing at a locally
/// installed npm binary; there is no bundled artifact yet (that is build
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ public struct BetaFeaturesSection: View {
@State private var customSidebars: DefaultsValueModel<Bool>
@State private var remoteTmux: DefaultsValueModel<Bool>
@State private var tuiTerminalBackend: DefaultsValueModel<Bool>
@State private var tuiTerminalBackendManualIO: DefaultsValueModel<Bool>
@State private var workspaceTodoControls: DefaultsValueModel<Bool>
@State private var workspaceTodosChecklistStyle: DefaultsValueModel<WorkspaceTodoChecklistStyle>

Expand All @@ -25,6 +26,7 @@ public struct BetaFeaturesSection: View {
_customSidebars = State(initialValue: DefaultsValueModel(store: defaultsStore, key: catalog.betaFeatures.customSidebars))
_remoteTmux = State(initialValue: DefaultsValueModel(store: defaultsStore, key: catalog.betaFeatures.remoteTmux))
_tuiTerminalBackend = State(initialValue: DefaultsValueModel(store: defaultsStore, key: catalog.betaFeatures.tuiTerminalBackend))
_tuiTerminalBackendManualIO = State(initialValue: DefaultsValueModel(store: defaultsStore, key: catalog.betaFeatures.tuiTerminalBackendManualIO))
_workspaceTodoControls = State(initialValue: DefaultsValueModel(store: defaultsStore, key: catalog.betaFeatures.workspaceTodoControls))
_workspaceTodosChecklistStyle = State(initialValue: DefaultsValueModel(store: defaultsStore, key: catalog.betaFeatures.workspaceTodosChecklistStyle))
}
Expand All @@ -51,6 +53,8 @@ public struct BetaFeaturesSection: View {
SettingsCardDivider()
tuiTerminalBackendRow
SettingsCardDivider()
tuiTerminalBackendManualIORow
SettingsCardDivider()
workspaceTodoControlsRow
SettingsCardDivider()
workspaceTodosChecklistStyleRow
Expand All @@ -68,6 +72,7 @@ public struct BetaFeaturesSection: View {
customSidebars,
remoteTmux,
tuiTerminalBackend,
tuiTerminalBackendManualIO,
workspaceTodoControls,
workspaceTodosChecklistStyle,
]
Expand Down Expand Up @@ -234,6 +239,23 @@ public struct BetaFeaturesSection: View {
}
}

@ViewBuilder
private var tuiTerminalBackendManualIORow: some View {
SettingsCardRow(
configurationReview: .settingsOnly,
searchAnchorID: "setting:betaFeatures:tuiTerminalBackendManualIO",
String(localized: "settings.betaFeatures.tuiTerminalBackendManualIO", defaultValue: "cmux-tui Manual-IO Data Path"),
subtitle: tuiTerminalBackendManualIO.current
? String(localized: "settings.betaFeatures.tuiTerminalBackendManualIO.subtitleOn", defaultValue: "Daemon-backed terminals feed bytes straight into the Ghostty surface (no attach subprocess in the pane). Requires the cmux-tui Terminal Backend toggle.")
: String(localized: "settings.betaFeatures.tuiTerminalBackendManualIO.subtitleOff", defaultValue: "Daemon-backed terminals keep running the attach client as the surface command.")
) {
Toggle("", isOn: Binding(get: { tuiTerminalBackendManualIO.current }, set: { tuiTerminalBackendManualIO.set($0) }))
.labelsHidden()
.controlSize(.small)
.accessibilityIdentifier("SettingsBetaTuiTerminalBackendManualIOToggle")
}
}

}

/// Small warning callout with a yellow triangle, used at the top of
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -660,7 +660,8 @@ extension TerminalSurface {
manualIONoReflow = value
}

/// Enqueues remote tmux `%output` for the terminal parser.
/// Enqueues remote output (tmux `%output`, tui pipe-io bytes) for the
/// terminal parser.
///
/// The native parser runs on the surface generation's FIFO output lane and
/// this method returns without waiting for Ghostty's renderer-state mutex.
Expand Down
63 changes: 63 additions & 0 deletions Resources/Localizable.xcstrings
Original file line number Diff line number Diff line change
Expand Up @@ -174903,6 +174903,27 @@
}
}
},
"settings.betaFeatures.tuiTerminalBackendManualIO.subtitleOn": {
"extractionState": "manual",
"localizations": {
"en": { "stringUnit": { "state": "translated", "value": "Daemon-backed terminals feed bytes straight into the Ghostty surface (no attach subprocess in the pane). Requires the cmux-tui Terminal Backend toggle." } },
"ja": { "stringUnit": { "state": "translated", "value": "デーモン管理のターミナルがGhosttyサーフェスへ直接バイトを送ります(ペイン内にattachサブプロセスなし)。cmux-tuiターミナルバックエンドの有効化が必要です。" } }
}
},
"settings.betaFeatures.tuiTerminalBackendManualIO.subtitleOff": {
"extractionState": "manual",
"localizations": {
"en": { "stringUnit": { "state": "translated", "value": "Daemon-backed terminals keep running the attach client as the surface command." } },
"ja": { "stringUnit": { "state": "translated", "value": "デーモン管理のターミナルは引き続きattachクライアントをサーフェスコマンドとして実行します。" } }
}
},
"settings.betaFeatures.tuiTerminalBackendManualIO": {
"extractionState": "manual",
"localizations": {
"en": { "stringUnit": { "state": "translated", "value": "cmux-tui Manual-IO Data Path" } },
"ja": { "stringUnit": { "state": "translated", "value": "cmux-tui マニュアルIOデータパス" } }
}
},
"settings.betaFeatures.warning": {
"extractionState": "manual",
"localizations": {
Expand Down Expand Up @@ -254478,6 +254499,48 @@
}
}
},
"tui.overlay.reconnecting.title": {
"extractionState": "manual",
"localizations": {
"en": { "stringUnit": { "state": "translated", "value": "Reconnecting to the terminal session" } },
"ja": { "stringUnit": { "state": "translated", "value": "ターミナルセッションに再接続中" } }
}
},
"tui.overlay.reconnecting.detail": {
"extractionState": "manual",
"localizations": {
"en": { "stringUnit": { "state": "translated", "value": "The session daemon is unreachable (attempt %lld). The terminal shows its last state; input is paused." } },
"ja": { "stringUnit": { "state": "translated", "value": "セッションデーモンに接続できません(試行 %lld 回目)。ターミナルは最後の状態を表示しており、入力は一時停止中です。" } }
}
},
"tui.overlay.failed.title": {
"extractionState": "manual",
"localizations": {
"en": { "stringUnit": { "state": "translated", "value": "Terminal backend unavailable" } },
"ja": { "stringUnit": { "state": "translated", "value": "ターミナルバックエンドを利用できません" } }
}
},
"tui.overlay.failed.detail": {
"extractionState": "manual",
"localizations": {
"en": { "stringUnit": { "state": "translated", "value": "The relay for this daemon-backed terminal keeps failing. Check the cmux-tui binary path in Settings, then retry." } },
"ja": { "stringUnit": { "state": "translated", "value": "デーモン管理ターミナルのリレーが繰り返し失敗しています。設定でcmux-tuiバイナリのパスを確認してから再試行してください。" } }
}
},
"tui.overlay.ended.title": {
"extractionState": "manual",
"localizations": {
"en": { "stringUnit": { "state": "translated", "value": "Terminal session ended" } },
"ja": { "stringUnit": { "state": "translated", "value": "ターミナルセッションが終了しました" } }
}
},
"tui.overlay.ended.detail": {
"extractionState": "manual",
"localizations": {
"en": { "stringUnit": { "state": "translated", "value": "The daemon-backed terminal has ended. Close the tab, or keep it to read the final screen." } },
"ja": { "stringUnit": { "state": "translated", "value": "デーモン管理のターミナルが終了しました。タブを閉じるか、最後の画面を確認するために残せます。" } }
}
},
"uiTest.bonsplit.action.title": {
"localizations": {
"en": {
Expand Down
Loading
Loading