feat: continue external Codex / Claude / Cursor sessions in their own CLI - #560
feat: continue external Codex / Claude / Cursor sessions in their own CLI#560Harry19081 wants to merge 8 commits into
Conversation
Comparison: ORGII continue-in-CLI vs cc-switch session manager(From reading cc-switch's Resume coverage. cc-switch emits resume commands for 5 of its 7 providers: Correctness depth. cc-switch templates Integration model. cc-switch launches an external terminal (Terminal/iTerm/Ghostty/kitty/WezTerm/Kaku/Alacritty/Warp/custom, AppleScript/ What cc-switch has that we deliberately don't (candidate follow-ups):
What we have that cc-switch doesn't: managed-session integration (status/dedup/usage), per-provider availability gating, launch-profile awareness, a scriptable |
d95255e to
f6b45ab
Compare
New orgtrack_core::sources::cli_resume maps an imported session (claude_code / codex_app / cursor_cli) to the invocation its owning CLI accepts: claude --resume <uuid> (original cwd required — Claude keys session storage on the project path), codex resume <thread-uuid> (extracted from the rollout stem), cursor-agent --resume <chat-id>. Cursor IDE composers are deliberately unsupported: their ids share no space with cursor-agent's chat store. The desktop app exposes it as external_history_cli_resume_plan, folding in the host-only freshness checks (workspace dir still exists, source store still on disk).
Imported Claude Code / Codex / Cursor CLI sessions get a 'Continue in <CLI>' header action next to the fork button. It reuses the existing chat-panel TUI launch flow end to end: launch-profile command resolution, a managed code_sessions row (runner='tui') for ORGII_SESSION_ID lifecycle attribution and managed-mirror dedup, and the session's recorded workspace as cwd. Disabled states explain exactly why (CLI not installed, original folder gone for Claude's cwd-scoped resume, source store deleted). Sources with no CLI resume path (Cursor IDE composers and the rest) simply don't render the button — the backend plan is the single source of truth.
orgtrack resume <session-id> scans only the provider that owns the id, plans the invocation via core's cli_resume, and execs it from the session's recorded workspace (--print emits the cd-prefixed command line instead). Verified against real local history: claude/codex/cursor-agent command lines all resolve, and Claude's cwd requirement is enforced — resuming from another directory provably fails upstream.
Verified against the installed binaries and their own stores: - opencode --session <ses_id> — central db, ids match session.id exactly - mimo --session <ses_id> — OpenCode fork, identical flag surface - cline --id <id> — global sessions.db, ids match sessions.session_id - omp --session <transcript-path> — pi-family id lookup is scoped to the current project's session dir, so the plan addresses the session file by absolute path instead (works from anywhere) Still out, with reasons in the module doc: cursor_ide/windsurf/warp/trae/ qoder (app-bound, no CLI surface) and zcode/qoder_cli/workbuddy (no binary present to verify the flag shape).
…oser copy, source-model preselect
Three imported-session UX fixes around continuation:
- Sources no CLI can reopen (Cursor IDE, Windsurf, Trae, Warp, Qoder,
ZCode, WorkBuddy, Qoder CLI) no longer render the chat composer — they
are pure read-only replays. The capability lives on the source
descriptor (cliResume {agentType, displayName}) so the composer gate and
the header continue-button share one sync source of truth, and the
header skips the backend plan round-trip for never-resumable sources.
- The composer placeholder now says what typing actually does — fork into
a new ORGII session — and names the native alternative per source
('…or resume in Claude Code from the header'), in all 13 locales.
- The fork setup dialog preselects the imported session's own model: when
no agent was explicitly chosen (user pick or collab agent hint), the
source session's model outranks the fallback agent's configured model
whenever the selected account offers it. Extracted as a pure helper with
unit tests; collab forks with agent hints keep their existing order.
f6b45ab to
9880eb7
Compare
- Quote resumed/launched CLI commands for the chat-panel PTY's actual default shell: PowerShell on Windows, POSIX elsewhere. POSIX '\'' escaping was corrupting backslash-heavy Windows paths (e.g. omp's --session <path>) since PowerShell is the Windows PTY default, not a POSIX shell. appendCliCommandArgs/formatCliTuiCommand take an injectable platform flag (defaults to the real OS) so both quoting styles are covered by tests regardless of host OS. - handleOpenCliTerminal now looks up an already-open terminal tab bound to the same agent/resolved-command/cwd before spawning a new one, since the backend mints a fresh managed session on every call and a repeat "Continue in <CLI>" click would otherwise launch a second CLI process against the same resumed conversation. Lookup extracted to a pure, unit-tested helper. - Extracted the duplicated deriveExpectedProcess (SessionContinueCliHeaderExtras, useChatPanelLaunch) into cliTerminalSession.ts and fixed it to unwrap a leading quoted binary instead of naively splitting on whitespace. - Simplified ChatViewPostHistoryOverlays' composer placeholder: the fork-imported fallback branch was unreachable (the composer's parent render gate already requires a CLI-resume descriptor).
shell_quote (used by CliResumePlan::display_command and orgtrack resume's cwd `cd` prefix) only escaped for POSIX shells. On Windows the printed command is copy-pasted into PowerShell, where POSIX '\''-style escaping mangles backslash-heavy paths (e.g. omp's --session <path>). Both functions now pick PowerShell- or POSIX-style quoting from the host OS, with a _for_shell variant that takes the target platform explicitly so tests can cover both without #[cfg(windows)]-gating the test itself. Also fixes a stale doc comment on resume_source_for_session_id: it dispatches all seven CLI-resumable imported sources, not three.
The TUI launch path wrote the CLI command terminated with LF, which Windows PowerShell + PSReadLine leaves sitting unexecuted at a continuation prompt - the resume terminal opened with the command typed but never run. Terminals send CR for Enter, and POSIX shells accept CR as line-accept too (ICRNL/readline), so terminate with CR on every platform. TerminalService.ts already follows this convention. Real-machine verified on Windows 11: Continue in Claude Code now spawns claude.exe with the resume args on a single click, and a second click focuses the existing terminal tab without spawning a second process.
What
Imported external sessions can now be continued in the CLI that owns them — the cc-switch-style resume flow, integrated with ORGII's existing CLI TUI support instead of an external terminal.
code_sessionsrow (runner='tui') so ORGII_SESSION_ID lifecycle attribution and the managed-mirror dedup work exactly like GUI-launched CLI sessions.orgtrack resume <session-id>(and--print) execs the same plan from a terminal.orgtrack_core::sources::cli_resumeis the single mapping both hosts share;external_history_cli_resume_planexposes it to the frontend with host-side freshness checks (binary installed, cwd exists, source store on disk → disabled states explain why).Support matrix (each verified against the installed binary and its own store)
claude --resume <uuid>codex resume <thread-uuid>rollout-<ts>-<uuid>stem; parent-flags-before-subcommand ordering verifiedcursor-agent --resume <chat-id>opencode --session <ses_id>session.idin its central db exactlymimo --session <ses_id>mimo --helpcline --id <id>sessions.session_idin its global db exactlyomp --session <transcript-path>Not resumable, and why:
cursor_ide(composer ids share no space with cursor-agent's chat store — 0/11 overlap on a real machine),windsurf/warp/trae/qoder(app-bound stores, no CLI surface),zcode/qoder_cli/workbuddy(CLIs likely resume, but no binary was present to verify the flag shape — the module doc marks them as the extension point).Testing
cargo test -p orgtrack_core cli_resume— 11 unit tests (id-shape gating per provider, codex stem extraction, omp path addressing, quoting, cache lookup incl. subagent/unsupported rejection)cargo test -p orgtrack_cli(29), clippy clean for touched code, app lib compilespnpm typecheck, eslint clean;cliTerminalSessionvitest 5/5; full ChatPanel suite 793/793orgtrack resume --printproduced correct command lines for real sessions of all seven providers present on this machine; id spaces cross-checked against opencode's and cline's own SQLite stores; i18n keys in all 13 localesImported-session chat pane behavior (round 3)