Skip to content

feat(desktop): v2 workspace setup script execution#3359

Merged
Kitenite merged 12 commits into
mainfrom
v2-workspace-setup-plan
Apr 12, 2026
Merged

feat(desktop): v2 workspace setup script execution#3359
Kitenite merged 12 commits into
mainfrom
v2-workspace-setup-plan

Conversation

@Kitenite
Copy link
Copy Markdown
Collaborator

@Kitenite Kitenite commented Apr 11, 2026

Summary

  • Add OSC 133 (FinalTerm standard) shell readiness detection to host-service terminal sessions, vendored from WezTerm (MIT). Shell wrappers updated to emit 133;A (prompt ready), 133;C (command start), 133;D (command finished + exit code) instead of our custom OSC 777 marker.
  • Add initialCommand support to createTerminalSessionInternal and ensureSession tRPC — commands are queued behind shellReadyPromise and written to the PTY only after the shell is ready. Fixes the preset race condition where commands fired before shell init completed.
  • Move command delivery entirely host-service-side: presets now await ensureSession({ initialCommand }) before adding panes. initialCommand removed from TerminalPaneData and the renderer-side WebSocket delivery effect deleted.
  • During v2 workspace creation, if .superset/setup.sh exists, the host-service creates a terminal session with the setup command. Returns terminals: [{ id, role, label }]. The pending page pre-populates the workspace pane layout before navigating, so TerminalPane attaches to already-running sessions with buffered output.

Test plan

  • Create v2 workspace with .superset/setup.sh + runSetupScript enabled — workspace opens with "Workspace Setup" terminal showing setup output
  • Create v2 workspace without setup script — workspace opens with empty state
  • Run a preset with heavy shell init (direnv/nvm) — command waits for shell ready, no garbled output
  • Verify shell readiness timeout (15s) degrades gracefully for unsupported shells
  • Verify bun test packages/host-service/src/terminal/env.test.ts passes
  • Verify bun test apps/desktop/src/main/lib/agent-setup/shell-wrappers.test.ts passes
  • Verify bun run typecheck passes

Summary by cubic

Runs v2 workspace setup scripts and preset commands by creating host-side terminal sessions that queue initial commands until the shell is ready (OSC 133;A). A “Workspace Setup” terminal is pre-started, panes attach to buffered output, and setup errors return as warnings.

  • New Features

    • Host-service accepts initialCommand in createTerminalSessionInternal and terminal.ensureSession; commands wait for shell readiness with a 15s timeout fallback.
    • During v2 workspace creation, if .superset/setup.sh exists and runSetupScript is enabled, a setup terminal starts and the API returns terminals: [{ id, role, label }]; the renderer pre-builds the pane layout so panes attach to running sessions.
  • Refactors

    • Standardized on OSC 133;A in zsh/bash/fish and dropped 133;C/133;D; extracted the scanner to @superset/shared and switched v1 desktop and host-service to it.
    • Moved command delivery to the host-service; removed initialCommand from TerminalPaneData and the renderer-side delivery effect; presets now call await terminal.ensureSession({ initialCommand }) before adding panes.
    • Robustness and UX: scanner re-tests after mismatches and flushes held bytes; workspace creation surfaces setup terminal failures via returned warnings; local schema switches from initialCommands to terminals with buildSetupPaneLayout and docs added; preset execution now shows a toast if session creation fails.

Written for commit 3909cf8. Summary will update on new commits.

Summary by CodeRabbit

  • New Features

    • Workspace creation now pre-starts setup terminals and pre-populates pane layouts so setup scripts run automatically and attach on open.
    • Preset execution now creates host-side terminal sessions per command and scopes execution to the current workspace.
  • Bug Fixes

    • More reliable shell readiness detection and safer delivery of initial commands to terminals, reducing timing-related failures.
  • Documentation

    • Added end-to-end guide for workspace setup and preset execution.

Add initialCommand support to createTerminalSessionInternal and
ensureSession tRPC. Commands are queued behind shellReadyPromise
(OSC 133;A detection from Phase 1) and written to the PTY only after
the shell is ready.

Update v2 preset execution to create sessions with commands on the
host-service before adding panes. Remove initialCommand from
TerminalPaneData and delete the renderer-side WebSocket delivery
effect — command delivery is now entirely host-service-side.
During v2 workspace creation, if .superset/setup.sh exists and
runSetupScript is enabled, the host-service now creates a terminal
session with the setup command via createTerminalSessionInternal.
The command runs after shell readiness (OSC 133;A), and output
buffers until the renderer connects.

Returns terminals array [{id, role, label}] instead of initialCommands.
The pending page pre-populates the workspace pane layout with terminal
panes referencing the host-provided terminalIds before navigating, so
TerminalPane mounts and attaches to already-running sessions.
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 11, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Replaced OSC 777 readiness signaling with OSC 133 semantic prompt markers across shells; added a shared OSC 133 scanner and per-session readiness gating; routed initialCommand through host-side session creation; persisted terminal descriptors and pre-populated pane layouts in the renderer; updated tests and docs.

Changes

Cohort / File(s) Summary
Shell wrappers & tests
apps/desktop/src/main/lib/agent-setup/shell-wrappers.ts, apps/desktop/src/main/lib/agent-setup/shell-wrappers.test.ts, packages/host-service/src/terminal/env.test.ts, apps/desktop/src/main/terminal-host/session-shell-ready.test.ts
Replaced OSC 777 marker with OSC 133 in zsh/bash/fish wrappers; tests relaxed exact-string expectations and assert presence/position of OSC 133 fragments and escaped sequences.
Host-service terminal runtime
packages/host-service/src/terminal/terminal.ts, packages/host-service/src/terminal/shell-launch.ts
Integrated per-session shell-ready state and scanner; createTerminalSessionInternal accepts initialCommand?: string and queues writes until shell-ready; fish init emits OSC 133 hooks.
TRPC & workspace creation
packages/host-service/src/trpc/router/terminal/terminal.ts, packages/host-service/src/trpc/router/workspace-creation/workspace-creation.ts
ensureSession input accepts optional initialCommand; workspace creation now creates terminal sessions for setup scripts and returns terminals descriptors instead of initialCommands.
Session & shared scanner module
apps/desktop/src/main/terminal-host/session.ts, packages/shared/src/shell-ready-scanner.ts, packages/shared/package.json, apps/desktop/src/main/terminal-host/pty-subprocess-ipc.ts
Added shared shell-ready-scanner with incremental OSC 133 detection; session code uses per-session scan state to strip/detect markers; removed old SHELL_READY_MARKER export.
Renderer: pending workspaces & pane layout
apps/desktop/src/renderer/routes/_authenticated/_dashboard/pending/$pendingId/buildSetupPaneLayout.ts, apps/desktop/src/renderer/routes/_authenticated/_dashboard/pending/$pendingId/page.tsx, apps/desktop/src/renderer/routes/_authenticated/components/.../useSubmitWorkspace/useSubmitWorkspace.ts, apps/desktop/src/renderer/routes/_authenticated/providers/CollectionsProvider/dashboardSidebarLocal/schema.ts, docs/V2_WORKSPACE_SETUP_SCRIPTS.md
Replaced initialCommands with terminals array in pending workspace schema; added builder to generate pane layouts from terminal descriptors; persist paneLayout on successful creation; added design doc detailing OSC 133 approach.
Preset execution & terminal pane model
apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/useV2PresetExecution/useV2PresetExecution.ts, apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/page.tsx, apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/types.ts, apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/TerminalPane/TerminalPane.tsx
useV2PresetExecution now requires workspaceId and creates host-side sessions per command (uses returned terminalIds); removed initialCommand from TerminalPaneData and removed initial-command dispatch from TerminalPane.
Docs & tests
docs/V2_WORKSPACE_SETUP_SCRIPTS.md, various tests
New documentation describing OSC 133-based readiness and session-queued initialCommand flow; tests updated to reflect OSC 133 markers and scanner behavior.

Sequence Diagram(s)

mermaid
sequenceDiagram
participant Frontend as Frontend (Renderer)
participant Router as Workspace Router (trpc)
participant Host as Host Service
participant PTY as PTY Process
participant Scanner as ShellReadyScanner
participant WS as Terminal WebSocket

Frontend->>Router: create workspace (runSetupScript: true)
Router->>Host: createTerminalSessionInternal({ terminalId, workspaceId, initialCommand })
Host->>PTY: spawn PTY, attach reader/writer
PTY->>Host: stream bytes (may include OSC 133;A)
Host->>Scanner: scanForShellReady(state, bytes)
Scanner-->>Host: matched=true
Host->>Host: resolve shellReadyPromise
Host->>PTY: write queued initialCommand
Host-->>Frontend: return terminal descriptor (id, role, label)
Frontend->>WS: attach to terminal websocket using terminalId
WS->>Host: connect to session stream (receive PTY output)

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

"I nibble at bytes, I mark the prompt,
OSC one-three-three — a tiny tromp.
I queue the commands till shells declare,
then hop them off with tender care.
🐰✨"

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 27.78% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main feature: adding support for v2 workspace setup script execution.
Description check ✅ Passed The pull request description is comprehensive and well-structured, covering objectives, test plan, and implementation details.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch v2-workspace-setup-plan

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 11, 2026

🚀 Preview Deployment

🔗 Preview Links

Service Status Link
Neon Database (Neon) View Branch
Fly.io Electric (Fly.io) View App
Vercel API (Vercel) Open Preview
Vercel Web (Vercel) Open Preview
Vercel Marketing (Vercel) Open Preview
Vercel Admin (Vercel) Open Preview
Vercel Docs (Vercel) Open Preview

Preview updates automatically with new commits

Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

4 issues found across 16 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/useV2PresetExecution/useV2PresetExecution.ts">

<violation number="1" location="apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/useV2PresetExecution/useV2PresetExecution.ts:67">
P2: `executePreset` now returns a rejecting Promise, but callers invoke it as `void` without error handling. Wrap the async flow in an internal `try/catch` (or ensure callers await/catch) to avoid unhandled promise rejections.

(Based on your team's feedback about handling async errors explicitly.) [FEEDBACK_USED]</violation>
</file>

<file name="apps/desktop/src/main/lib/agent-setup/shell-wrappers.test.ts">

<violation number="1" location="apps/desktop/src/main/lib/agent-setup/shell-wrappers.test.ts:845">
P3: This `not.toContain("777")` check is flaky because the temp path embedded in the init-command can legitimately include `777`.</violation>
</file>

<file name="packages/host-service/src/terminal/terminal.ts">

<violation number="1" location="packages/host-service/src/terminal/terminal.ts:175">
P2: On prefix mismatch, the current character is flushed to output without re-testing it against position 0 of `OSC_133_A`. If `ch` is `\x1b` (which is `OSC_133_A[0]`), a valid marker that immediately follows a stale ESC byte will be missed. After resetting, check whether `ch` starts a new match and hold it instead of flushing.</violation>
</file>

<file name="packages/host-service/src/trpc/router/workspace-creation/workspace-creation.ts">

<violation number="1" location="packages/host-service/src/trpc/router/workspace-creation/workspace-creation.ts:484">
P2: Handle the `{ error }` result from `createTerminalSessionInternal` instead of silently skipping setup terminal creation; otherwise setup-script failures are invisible and hard to diagnose.

(Based on your team's feedback about handling async/error failures explicitly and avoiding silent failure paths.) [FEEDBACK_USED]</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment thread packages/host-service/src/terminal/terminal.ts Outdated
Comment thread packages/host-service/src/trpc/router/workspace-creation/workspace-creation.ts Outdated
Comment thread apps/desktop/src/main/lib/agent-setup/shell-wrappers.test.ts Outdated
@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented Apr 11, 2026

Greptile Summary

This PR delivers three major improvements for the desktop terminal experience:

  1. OSC 133 shell readiness detection — replaces the custom OSC 777 protocol with the FinalTerm/WezTerm-compatible OSC 133 semantic prompt standard. Shell wrappers for zsh, bash, and fish are updated to emit 133;A (prompt ready), 133;C (command start), and 133;D;{exit} (command done). A per-session byte scanner in the host-service detects the 133;A marker and resolves a shellReadyPromise before writing any initialCommand to the PTY.

  2. Race-condition fix for preset commands — presets previously delivered commands to the renderer via WebSocket before the shell was initialized. Now, the host-service creates the session with initialCommand queued behind shellReadyPromise, and a 15-second graceful timeout unblocks writes for unsupported shells.

  3. V2 workspace setup script execution — on workspace creation, if .superset/setup.sh exists and runSetupScript is enabled, a terminal session is created immediately on the host-service with the setup command. The pending page pre-populates the workspace pane layout with buildSetupPaneLayout before navigating, so TerminalPane attaches to the already-running session with buffered output.

The architecture is sound: sessions are created host-side and the renderer simply attaches, eliminating the renderer-side initialCommand delivery effect. The byte scanner is incremental and handles cross-chunk partial matches correctly.

Key observations:

  • The shellReadyState machine (pending → ready/timed_out/unsupported) is clean and idempotent
  • resolveShellReady correctly clears both the timeout and the scanner's held bytes on transition
  • OSC 133;A scanning works correctly for the first shell ready signal; subsequent 133;C/D markers pass through to the terminal unmodified
  • The initialCommands field is still present in the pendingWorkspaceSchema and useSubmitWorkspace.ts insert — it's harmless but is now dead code alongside the new terminals field

Confidence Score: 4/5

Safe to merge; core shell readiness detection and preset race-condition fix are correct, with only minor robustness and dead-code cleanup items remaining.

The primary features (OSC 133 shell readiness detection, initialCommand queueing, v2 setup script execution) all work correctly. The shellReadyState machine is idempotent, the byte scanner handles cross-chunk partial matches properly, and the TerminalPane attach-to-existing-session flow is sound. The two flagged items are P2: the bash DEBUG trap produces spurious 133;C/D markers in subsequent prompts (harmless for current xterm.js integration since it doesn't render OSC 133 zones) and there's a missing .catch() on the shellReadyPromise callback. The initialCommands dead-code field is harmless. No blocking issues.

apps/desktop/src/main/lib/agent-setup/shell-wrappers.ts (bash DEBUG trap), packages/host-service/src/terminal/terminal.ts (missing .catch)

Important Files Changed

Filename Overview
packages/host-service/src/terminal/terminal.ts Core OSC 133 shell readiness scanner and initialCommand queueing — logic is sound; missing .catch() on shellReadyPromise.then() is the one notable gap
apps/desktop/src/main/lib/agent-setup/shell-wrappers.ts Shell wrappers updated to emit OSC 133;A/C/D; bash DEBUG trap implementation may emit spurious 133;C before each PROMPT_COMMAND invocation after the first cycle
packages/host-service/src/trpc/router/workspace-creation/workspace-creation.ts Setup terminal session created host-side during workspace creation; replaces old initialCommands return with terminals array; error path is correctly handled
apps/desktop/src/renderer/routes/_authenticated/_dashboard/pending/$pendingId/buildSetupPaneLayout.ts New helper that converts terminal descriptors from workspace creation into a WorkspaceState pane layout; straightforward and correct
apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/useV2PresetExecution/useV2PresetExecution.ts Preset execution now creates sessions with initialCommand via ensureSession rather than delivering commands renderer-side; race condition fix is clean
apps/desktop/src/renderer/routes/_authenticated/providers/CollectionsProvider/dashboardSidebarLocal/schema.ts terminals field added to pendingWorkspaceSchema; initialCommands still present as dead code alongside the new field

Sequence Diagram

sequenceDiagram
    participant R as Renderer
    participant HS as HostService
    participant PTY as PTY

    R->>HS: workspaceCreation.create
    HS->>PTY: spawn shell
    HS->>HS: queue initialCommand behind shellReadyPromise
    HS-->>R: workspace plus terminals array
    PTY->>HS: onData shell ready marker detected
    HS->>HS: resolveShellReady promise settles
    HS->>PTY: pty.write initialCommand
    R->>R: buildSetupPaneLayout from terminals
    R->>HS: ensureSession returns existing session
    R->>HS: WebSocket attaches and replays buffer
Loading

Comments Outside Diff (1)

  1. apps/desktop/src/renderer/routes/_authenticated/components/DashboardNewWorkspaceModal/components/DashboardNewWorkspaceForm/PromptGroup/hooks/useSubmitWorkspace/useSubmitWorkspace.ts, line 70-71 (link)

    P2 initialCommands: null is now dead code

    The initialCommands field is still inserted here but is no longer consumed anywhere — the workspace creation flow now uses terminals instead. The schema in dashboardSidebarLocal/schema.ts still declares initialCommands: z.array(z.string()).nullable().default(null), which means both the schema field and this insert are dead code. This is harmless (Zod's default(null) keeps it backward-compatible), but it could be removed to reduce confusion about which field is authoritative for setup terminal state.

Reviews (1): Last reviewed commit: "feat(desktop): create setup terminal dur..." | Re-trigger Greptile

Comment thread apps/desktop/src/main/lib/agent-setup/shell-wrappers.ts Outdated
Comment thread packages/host-service/src/terminal/terminal.ts
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/useV2PresetExecution/useV2PresetExecution.ts (1)

66-169: ⚠️ Potential issue | 🔴 Critical

Type mismatch: executePreset is now async but callers expect sync.

The implementation at line 67 declares executePreset as async (preset: V2TerminalPresetRow) => { ... }, but consumers (useWorkspaceHotkeys, V2PresetsBar, V2PresetBarItem) all declare it with type (preset: V2TerminalPresetRow) => void. Call sites invoke it without awaiting:

  • useWorkspaceHotkeys.ts:250if (preset) executePreset(preset);
  • V2PresetBarItem.tsx:93, 112onClick={() => onExecutePreset(preset)} and context menu selection

This silently discards the returned promise, causing:

  1. Unhandled rejections — if ensureSession.mutateAsync() fails, the error is never caught
  2. Race conditions — rapid hotkey presses or button clicks could interleave addTab/addPane mutations before prior awaits complete

Update consumer type signatures to (preset: V2TerminalPresetRow) => Promise<void> and handle errors. For fire-and-forget hotkey invocations, add explicit .catch() or void operators.

🧹 Nitpick comments (2)
packages/host-service/src/terminal/env.test.ts (1)

237-246: Assert the full fish marker set here too.

The production init command now includes 133;A, 133;C, and 133;D, but this test only guards the ready marker. Adding the other two here keeps packages/host-service/src/terminal/shell-launch.ts aligned with apps/desktop/src/main/lib/agent-setup/shell-wrappers.test.ts.

Suggested assertion update
 		expect(args[0]).toBe("-l");
 		expect(args[1]).toBe("--init-command");
 		expect(args[2]).toContain("_superset_bin");
 		expect(args[2]).toContain("133;A");
+		expect(args[2]).toContain("133;C");
+		expect(args[2]).toContain("133;D");
+		expect(args[2]).not.toContain("777");
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/host-service/src/terminal/env.test.ts` around lines 237 - 246,
Update the fish unit test to assert the full init-command marker trio instead of
only the ready marker: inside the "fish uses init-command" test that calls
getShellLaunchArgs, keep the existing checks for args[0] and args[1] but change
the args[2] assertions to verify it contains all three markers "133;A", "133;C",
and "133;D" (matching the init command built in shell-launch.ts) so the test
aligns with apps/desktop's agent-setup/shell-wrappers.test.ts.
packages/host-service/src/terminal/terminal.ts (1)

162-194: Consider handling ST terminator for broader OSC 133 compatibility.

The scanner only recognizes BEL (\x07) as the OSC string terminator. Per the FinalTerm spec, ST (\x1b\\) is also valid. While the shell wrappers likely emit BEL consistently, terminals configured differently would timeout and degrade gracefully—acceptable fallback behavior.

If broader compatibility becomes needed, you could extend the scanner to also match \x1b\\ after the 133;A prefix.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/host-service/src/terminal/terminal.ts` around lines 162 - 194, The
scanner scanForShellReady currently only treats BEL ('\x07') as the OSC
terminator; update it to also recognize the ST terminator sequence ESC '\\'
(0x1b followed by '\\') after matching the OSC_133_A prefix: when
session.oscMatchPos >= OSC_133_A.length and you encounter '\x1b', peek the next
character in data (i+1) and if it is '\\' consume both chars, clear
session.oscHeldBytes, reset session.oscMatchPos, call
resolveShellReady(session,"ready"), append the remainder data.slice(i+2) to
output and break; if the peek fails (end of buffer or not '\\') continue
accumulating into session.oscHeldBytes as before. Ensure state resets mirror the
existing BEL-path behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/desktop/src/main/lib/agent-setup/shell-wrappers.ts`:
- Around line 289-318: Wrap existing PROMPT_COMMAND and any existing DEBUG trap
instead of appending/replacing: save the current PROMPT_COMMAND (array or
scalar) and replace it with a wrapper that calls __superset_semantic_precmd
first (so it captures the original command exit code in ret) and then invokes
the saved/original PROMPT_COMMAND handlers; likewise, capture the current DEBUG
trap (via trap -p DEBUG or reading $BASH_COMMAND) and install a new DEBUG trap
that calls __superset_bash_preexec and then calls the original DEBUG
trap/handler so you don't clobber user tooling. Ensure you reference and
preserve __superset_semantic_precmd, PROMPT_COMMAND, __superset_bash_preexec and
the DEBUG trap when composing the wrappers.
- Around line 225-240: The precmd/preexec hooks currently capture the exit
status too late and directly reassign shell hook arrays unsafely; modify
__superset_semantic_preexec to capture the user's command exit status into a
dedicated variable (e.g., __superset_semantic_last_ret) before other precmd
hooks run and change __superset_semantic_precmd to emit the OSC 133;D;<ret>
using that captured variable separate from the final A emission, and wrap the
array modifications for precmd_functions and preexec_functions in the same
defensive pattern used in buildZshPrecmdHook (append with redirection
suppression like 2>/dev/null || true) so readonly hook arrays do not break
startup while preserving existing hook names
(__superset_semantic_precmd_executing, __superset_semantic_precmd,
__superset_semantic_preexec, precmd_functions, preexec_functions).

---

Nitpick comments:
In `@packages/host-service/src/terminal/env.test.ts`:
- Around line 237-246: Update the fish unit test to assert the full init-command
marker trio instead of only the ready marker: inside the "fish uses
init-command" test that calls getShellLaunchArgs, keep the existing checks for
args[0] and args[1] but change the args[2] assertions to verify it contains all
three markers "133;A", "133;C", and "133;D" (matching the init command built in
shell-launch.ts) so the test aligns with apps/desktop's
agent-setup/shell-wrappers.test.ts.

In `@packages/host-service/src/terminal/terminal.ts`:
- Around line 162-194: The scanner scanForShellReady currently only treats BEL
('\x07') as the OSC terminator; update it to also recognize the ST terminator
sequence ESC '\\' (0x1b followed by '\\') after matching the OSC_133_A prefix:
when session.oscMatchPos >= OSC_133_A.length and you encounter '\x1b', peek the
next character in data (i+1) and if it is '\\' consume both chars, clear
session.oscHeldBytes, reset session.oscMatchPos, call
resolveShellReady(session,"ready"), append the remainder data.slice(i+2) to
output and break; if the peek fails (end of buffer or not '\\') continue
accumulating into session.oscHeldBytes as before. Ensure state resets mirror the
existing BEL-path behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a08e55c2-e198-4f79-88dd-70a8c535abfe

📥 Commits

Reviewing files that changed from the base of the PR and between c8f8dff and 94c20a2.

📒 Files selected for processing (16)
  • apps/desktop/src/main/lib/agent-setup/shell-wrappers.test.ts
  • apps/desktop/src/main/lib/agent-setup/shell-wrappers.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/pending/$pendingId/buildSetupPaneLayout.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/pending/$pendingId/page.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/TerminalPane/TerminalPane.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/useV2PresetExecution/useV2PresetExecution.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/page.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/types.ts
  • apps/desktop/src/renderer/routes/_authenticated/components/DashboardNewWorkspaceModal/components/DashboardNewWorkspaceForm/PromptGroup/hooks/useSubmitWorkspace/useSubmitWorkspace.ts
  • apps/desktop/src/renderer/routes/_authenticated/providers/CollectionsProvider/dashboardSidebarLocal/schema.ts
  • docs/V2_WORKSPACE_SETUP_SCRIPTS.md
  • packages/host-service/src/terminal/env.test.ts
  • packages/host-service/src/terminal/shell-launch.ts
  • packages/host-service/src/terminal/terminal.ts
  • packages/host-service/src/trpc/router/terminal/terminal.ts
  • packages/host-service/src/trpc/router/workspace-creation/workspace-creation.ts
💤 Files with no reviewable changes (2)
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/TerminalPane/TerminalPane.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/types.ts

Comment thread apps/desktop/src/main/lib/agent-setup/shell-wrappers.ts Outdated
Comment thread apps/desktop/src/main/lib/agent-setup/shell-wrappers.ts Outdated
Extract the shell readiness scanner (character-by-character OSC 133;A
matching) into packages/shared/src/shell-ready-scanner.ts. Both v1
desktop (session.ts) and v2 host-service (terminal.ts) now import
from the shared module.

V1 switches from the custom OSC 777 marker to the standard OSC 133
protocol, matching the shell wrappers updated in the first commit.
All 19 v1 shell-ready tests pass with the new marker.
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
apps/desktop/src/main/terminal-host/session-shell-ready.test.ts (1)

10-11: Add one OSC 133-with-params case.

packages/shared/src/shell-ready-scanner.ts also accepts optional params before the BEL terminator, but every test here still uses the bare \x1b]133;A\x07 form. A single ;cl=... case would cover that shared-parser path too.

➕ Suggested test case
+	it("handles OSC 133 markers with params", () => {
+		const { session, proc } = createTestSession("/bin/zsh");
+		spawnAndReady(session, proc);
+
+		sendData(proc, "\x1b]133;A;cl=m;aid=123\x07prompt$ ");
+
+		session.write("test\n");
+		expect(getWrittenData(proc)).toEqual(["test\n"]);
+	});
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/desktop/src/main/terminal-host/session-shell-ready.test.ts` around lines
10 - 11, Add a new test in session-shell-ready.test.ts that covers the OSC 133
variant with params (e.g. "\x1b]133;A;cl=some-value\x07") so the shared parser
in packages/shared/src/shell-ready-scanner.ts that accepts optional params
before the BEL is exercised; create a new constant or inline marker that appends
a ";cl=..." param to SHELL_READY_MARKER and add an assertion mirroring the
existing bare-marker test (use the same test helper/expectations as the existing
SHELL_READY_MARKER case).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@apps/desktop/src/main/terminal-host/session-shell-ready.test.ts`:
- Around line 10-11: Add a new test in session-shell-ready.test.ts that covers
the OSC 133 variant with params (e.g. "\x1b]133;A;cl=some-value\x07") so the
shared parser in packages/shared/src/shell-ready-scanner.ts that accepts
optional params before the BEL is exercised; create a new constant or inline
marker that appends a ";cl=..." param to SHELL_READY_MARKER and add an assertion
mirroring the existing bare-marker test (use the same test helper/expectations
as the existing SHELL_READY_MARKER case).

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 56a61988-be28-40c1-941e-475ebb1efd57

📥 Commits

Reviewing files that changed from the base of the PR and between 94c20a2 and c5999b0.

📒 Files selected for processing (5)
  • apps/desktop/src/main/terminal-host/session-shell-ready.test.ts
  • apps/desktop/src/main/terminal-host/session.ts
  • packages/host-service/src/terminal/terminal.ts
  • packages/shared/package.json
  • packages/shared/src/shell-ready-scanner.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/host-service/src/terminal/terminal.ts

We only consume 133;A for shell readiness detection. Emitting 133;C
and 133;D via DEBUG trap (bash) and preexec hooks (zsh/fish) brought
complexity we don't need — the bash DEBUG trap was also fundamentally
buggy, firing within PROMPT_COMMAND and producing spurious 133;C
emissions inside precmd.

Simplify to a single precmd hook per shell that emits 133;A. Matches
kitty's bash approach. If we ever need command-finished tracking, we
can add bash-preexec or PS0 (Bash 4.4+) at that point.
…atch

- Setup terminal creation failures now surface via the `warnings` array
  instead of being silently dropped.
- Scanner re-tests the current character after a mismatch — a valid
  OSC 133;A marker that immediately follows a stale ESC byte is no
  longer lost.
executePreset is async and can reject if ensureSession fails (network,
host down). Callers invoke as fire-and-forget — without a try/catch,
errors become unhandled promise rejections and the user sees the
preset silently not open. Wrap the body in try/catch with a toast.
@Kitenite Kitenite merged commit d798441 into main Apr 12, 2026
14 checks passed
@Kitenite Kitenite deleted the v2-workspace-setup-plan branch April 12, 2026 00:29
MocA-Love pushed a commit to MocA-Love/superset that referenced this pull request Apr 13, 2026
* Shell readiness

* feat(host-service): host-side initial command delivery via ensureSession

Add initialCommand support to createTerminalSessionInternal and
ensureSession tRPC. Commands are queued behind shellReadyPromise
(OSC 133;A detection from Phase 1) and written to the PTY only after
the shell is ready.

Update v2 preset execution to create sessions with commands on the
host-service before adding panes. Remove initialCommand from
TerminalPaneData and delete the renderer-side WebSocket delivery
effect — command delivery is now entirely host-service-side.

* feat(desktop): create setup terminal during workspace creation

During v2 workspace creation, if .superset/setup.sh exists and
runSetupScript is enabled, the host-service now creates a terminal
session with the setup command via createTerminalSessionInternal.
The command runs after shell readiness (OSC 133;A), and output
buffers until the renderer connects.

Returns terminals array [{id, role, label}] instead of initialCommands.
The pending page pre-populates the workspace pane layout with terminal
panes referencing the host-provided terminalIds before navigating, so
TerminalPane mounts and attaches to already-running sessions.

* refactor: extract OSC 133 scanner into @superset/shared, update v1

Extract the shell readiness scanner (character-by-character OSC 133;A
matching) into packages/shared/src/shell-ready-scanner.ts. Both v1
desktop (session.ts) and v2 host-service (terminal.ts) now import
from the shared module.

V1 switches from the custom OSC 777 marker to the standard OSC 133
protocol, matching the shell wrappers updated in the first commit.
All 19 v1 shell-ready tests pass with the new marker.

* Lint

* chore: remove dead SHELL_READY_MARKER constant, clean up stale comment

* Lint

* chore: remove dead initialCommands field from pendingWorkspaceSchema

* refactor(shell-wrappers): emit only OSC 133;A, drop C/D

We only consume 133;A for shell readiness detection. Emitting 133;C
and 133;D via DEBUG trap (bash) and preexec hooks (zsh/fish) brought
complexity we don't need — the bash DEBUG trap was also fundamentally
buggy, firing within PROMPT_COMMAND and producing spurious 133;C
emissions inside precmd.

Simplify to a single precmd hook per shell that emits 133;A. Matches
kitty's bash approach. If we ever need command-finished tracking, we
can add bash-preexec or PS0 (Bash 4.4+) at that point.

* fix: surface setup terminal errors and re-test marker on scanner mismatch

- Setup terminal creation failures now surface via the `warnings` array
  instead of being silently dropped.
- Scanner re-tests the current character after a mismatch — a valid
  OSC 133;A marker that immediately follows a stale ESC byte is no
  longer lost.

* Lint

* fix(preset): show toast on executePreset failure

executePreset is async and can reject if ensureSession fails (network,
host down). Callers invoke as fire-and-forget — without a try/catch,
errors become unhandled promise rejections and the user sees the
preset silently not open. Wrap the body in try/catch with a toast.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant