Repository navigation
Conversation
…anscript is filed under An account-switch restart started the new shell in the tab's start folder, and a cold restore revived the shell in the last folder the terminal reported (OSC 7), which can be a sub-folder rather than the session's project. `claude --resume` takes its project from the process cwd, so the session came back in the wrong folder: Claude asked to trust it and ran without the project's CLAUDE.md and hooks. Codex was unaffected because `codex resume` returns to the folder its rollout records. Both relaunch paths now pick the folder whose Claude encoding names the transcript's `projects/<bucket>`. The account-switch restart checks the pane's last reported folder (mounted panes), the tab's start folder and the worktree, each with its parents, for host-native local panes only. The daemon's cold restore checks the requested and recovered folders for local Claude resumes. When nothing matches, the folder is chosen as before. Moves the Claude project-dir encoding to src/shared so the renderer can use it. Fixes stablyai#31545 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info
📝 Walkthrough
Priority: ➖ Normal Merge Risk: ⚪ Minimal · up to
|
There was a problem hiding this comment.
Actionable comments posted: 1
ℹ️ Review info
⚙️ Run configuration
- Source mode: Auto
- Repository: Unavailable
- Branch: Unavailable
- File: No configuration file from this repository applied
- Commit: Unavailable
- Layers: Repository UI
- Review profile: CHILL
- Plan: Advanced
- Run ID:
6beacb45-c467-40b2-b84a-c6772b3a3d27
📒 Files selected for processing: 17
src/main/ai-vault/claude-project-dir-encoding.tssrc/main/ai-vault/session-cwd-bucket-layouts.tssrc/main/daemon/cold-restore-startup-cwd.tssrc/main/daemon/daemon-pty-adapter-history-checkpoints.test.tssrc/main/daemon/daemon-pty-session-spawn.tssrc/main/ipc/pty/ipc/spawn-options-claude-resume.test.tssrc/main/ipc/pty/spawn-options-assembly.tssrc/main/providers/pty-provider-contract.tssrc/main/worktree-retirement-discovery.tssrc/renderer/src/components/terminal-pane/codex-detached-pane-restart.test.tssrc/renderer/src/components/terminal-pane/codex-detached-pane-restart.tssrc/renderer/src/components/terminal-pane/use-terminal-pane-process-exit-actions.test.tssrc/renderer/src/components/terminal-pane/use-terminal-pane-process-exit-actions.tssrc/renderer/src/lib/agent-account-restart-startup.test.tssrc/renderer/src/lib/agent-account-restart-startup.tssrc/shared/claude-project-dir-encoding.test.tssrc/shared/claude-project-dir-encoding.ts
💤 Files with no reviewable changes: 1
- src/main/ai-vault/claude-project-dir-encoding.ts
Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 9 remain after this review.
…et fits two folders /a/foo-bar and /a/foo/bar both encode to -a-foo-bar, so a bucket name alone cannot choose between them. findClaudeTranscriptProjectFolder now collects the distinct matching folders and returns null unless exactly one matches, so the cold-restore and account-switch callers keep their existing folder choice. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Thanks @asunghong — your diagnosis drove this. #33527 now records each session's start folder from Claude's hooks, and #33659 (merged, with your co-author credit) makes the account-switch restart use it, so the transcript-bucket matching isn't needed. Closing in favour of those. |
… it was started in (#33659) Claude account-switch restarts now pass the folder the restarted shell opens in (tab start folder, else workspace), so #33527's `cd <start folder> &&` resume prefix applies and a session started in a subfolder resumes there. Codex account restarts benefit the same way. Refs #31545 Supersedes #32033 Co-authored-by: ASH <7201776+asunghong@users.noreply.github.com>
ELI5
When Orca restarts a Claude terminal (after you switch Claude accounts, or when Orca's terminal service comes back after a restart or update), it types
claude --resume <session-id>into a fresh shell. That shell could start in a sub-folder (the last folder the terminal reported, or the tab's start folder) instead of the session's project, so Claude treated the sub-folder as a new project: it asked "trust this folder?" and, once accepted, ran without the project'sCLAUDE.md/AGENTS.mdand hooks. Now Orca starts the relaunch in the folder Claude filed the session under.What Changed
Before
tab.startupCwd ?? worktree path), whatever folder the session belongs to.claude --resumecan land in<project-dir>/<sub-folder>: trust prompt, project rules and hooks missing.After
<CLAUDE_CONFIG_DIR>/projects/<encoded launch folder>/<session-id>.jsonl).Mechanism
src/shared/claude-project-dir-encoding.ts(moved unchanged fromsrc/main/ai-vault/so the renderer can use it) gainsfindClaudeTranscriptProjectFolder(transcriptPath, candidates): it checks each candidate and its parent folders and returns the first one that encodes to the bucket name, or null.resolveAgentAccountRestartResumeStartupchecks the pane's last reported folder (mounted panes), the tab's start folder and the worktree path, and returns the match ascwd. The mounted (use-terminal-pane-process-exit-actions.ts) and detached (codex-detached-pane-restart.ts) restart executors spawn there.PtySpawnOptions.claudeResumeTranscriptPath(spawn-options-assembly.ts). The daemon adapter's cold-restore folder choice (newsrc/main/daemon/cold-restore-startup-cwd.ts) prefers the matching folder among the requested and recovered folders, then keeps the existing "recovered folder unless it was deleted" rule.Why
Claude Code resolves
--resumeagainst the project bucket of its cwd and loads project config from the cwd. Codex resumes into the cwd recorded in its rollout, which is why only Claude panes showed this. The pane's provider session already carries the hook-reportedtranscriptPath, so its bucket name identifies the right folder with no file IO.Alternatives considered:
cd <sub-folder> && claude).cwdfield from the transcript JSONL: adds file IO to the restart path, and that field records the working folder per message, which can change during the session.cd <dir> &&to the resume line: needs per-shell quoting and leaves the user's shell in a different folder after the agent exits.Linked Issue
Part of #31545
Scope: this PR fixes the wrong-folder relaunch (item 1 of the issue) on the account-switch restart and the daemon cold-restore paths. Other
--resumepaths that start a fresh shell in the tab's folder (hibernation wake, a fresh cold-restore resume when the daemon has no history) are unchanged, and WSL panes keep today's folder (their transcript and OSC 7 paths are guest paths; matching them against UNC worktree paths is a follow-up). The lost effort level (item 2), duplicate processes for one session id (item 3) and showing which sessions moved (item 4) are left for follow-ups. Launch arguments Orca recorded for the pane (for example--model) are already replayed on resume; an effort changed inside the session with/effortis saved in the account profile's own settings, which Orca does not observe, so carrying it needs a separate design.Visual Proof
N/A: no UI change. The change is which folder a relaunched Claude session starts in; it is covered by the unit tests below. A before/after recording was not captured.
Testing
New or extended tests:
src/shared/claude-project-dir-encoding.test.ts: walking up from a sub-folder, a session started in a sub-folder, falling through to a later candidate, Windows separators and drive root, a UNC walk that stops at the share, and no-match cases.src/renderer/src/lib/agent-account-restart-startup.test.ts: a Claude restart resolves the session's folder from the pane's sub-folder; no match leaves the folder to the tab; a WSL pane's guest folder is never used.src/renderer/src/components/terminal-pane/codex-detached-pane-restart.test.ts: an unmounted Claude pane whose tab starts in a sub-folder respawns in the session's folder.src/renderer/src/components/terminal-pane/use-terminal-pane-process-exit-actions.test.ts: a mounted pane hands its last folder to the resolver and spawns in the resolved folder.src/main/ipc/pty/ipc/spawn-options-claude-resume.test.ts: only a local Claude resume hands the transcript path to the provider (not SSH, not Codex).src/main/daemon/daemon-pty-adapter-history-checkpoints.test.ts: a cold-restored Claude resume revives in the transcript's folder, not the recovered sub-folder.Run locally (macOS, Node, Vitest on Node):
vitest run --config config/vitest.config.tson the new and changed tests plus every suite importing a changed module (account switch, restart readiness, spawn options, ai-vault bucket layouts, worktree retirement): all passed. Each new test fails with its production change reverted.src/renderer/src/components/terminal-pane,src/main/ipc/pty,src/main/ai-vault*and the Claude account libraries (910 files): no new failures. The few failures seen there also occur on the base commit in the same environment (daemon tests that need a Unix socket under/tmp, two suites that fail on base, and one timing-sensitive suite that is flaky on base).node config/scripts/run-typecheck-projects-in-parallel.mjs --compiler=nativefor the node, web and cli projects: passed.node config/scripts/check-changed-code-quality.mjs, the max-lines, path-literal, main-sync-spawn, compat-boundary and process-host ratchets,oxlint(default and anti-slop configs) andoxfmt --checkon changed files: passed./tmp; CI covers it. Linux, Windows and SSH were not tested by hand.AI Disclosure
Investigation, fix and tests were written with Claude Code (Claude Opus 5.5) and checked by a separate AI review pass. The author reported the bug (#31545) and has not yet tested this build by hand.
Review
AI review summary:
connectionId; Claude account-switch restarts are local-only already.normalizeAgentProviderSession.Agent skill upstream boundary
Notes
Ensure no issues in: Security, Cross-platform support (Linux, Windows, Mac), Remote SSH, Mobile, general backwards compatibility, performance
Checklist
N/Awith reason (N/A: no UI change, see Visual Proof)pnpm lint,pnpm typecheck,pnpm test, andpnpm buildpass (or CI will cover; local preferred)🤖 Generated with Claude Code