feat(cli): add /cd slash command for in-session workspace switch - #1316
feat(cli): add /cd slash command for in-session workspace switch#1316jarvis24young wants to merge 1 commit into
Conversation
b57aa65 to
8a14ed9
Compare
Adds a `/cd <path>` slash command to the CLI chat mode that re-points the active session's working directory without restarting it. The session id, message history, and prompt-cache prefix are preserved; subsequent turns simply execute against the new cwd. Ported from Claude Code's `/cd` semantics (changelog 2.1.169). The key design choice is splitting "logical cwd" from "persistence anchor": - `SessionConfig.workspace_path` (existing) continues to drive tool execution and `build_workspace_binding` — so subsequent turns run in the new cwd. - A new `SessionConfig.storage_workspace_path` (optional, serde-default `None`, backward-compatible) freezes the original workspace on the first `/cd`. Storage helpers (`CoreSessionStorePort::resolve_storage_path_for_config`, `SessionManager::effective_session_workspace_path`) prefer this anchor so the session file, turn snapshots, and prompt cache stay rooted at the original directory and remain discoverable from its workspace listing. - `start_dialog_turn_internal` resolves its fallback finalize storage path via `effective_session_workspace_path` instead of the live workspace binding, so safety-net turn persistence honors the anchor. - Forked subagents reset `storage_workspace_path = None` so a child session's anchor follows its own (current) workspace, not the parent's post-`/cd` history. CLI resolution handles `~`/`~/...` expansion, relative paths joined against the current cwd, ASCII quote stripping, and rejects Windows drive-relative forms (`C:foo`) that would otherwise be silently anchored to the shell's per-drive cwd. The core update runs before the adapter mutation so a core-side failure leaves session state internally consistent. Switching is rejected while a turn is in flight. Pre-`/cd` sessions and existing on-disk session files are unaffected: `storage_workspace_path` deserializes to `None` and the helper falls back to `workspace_path`, preserving prior behavior byte-for-byte.
8a14ed9 to
56b6bc6
Compare
wsp1911
left a comment
There was a problem hiding this comment.
Review 意见
-
核心语义不对:
/cd不应直接修改正在运行 session 的 workspace
这个 PR 当前实现是把当前会话的session.config.workspace_path改成新路径,同时保留同一个 session id、同一段历史和原存储目录。BitFun 桌面端的多工作区语义是“切换到目标 workspace,并打开/创建目标 workspace 下的会话”,而不是把 A workspace 的会话直接改成 B workspace 的会话。
这样会把旧项目上下文、消息历史、memory、workspace id、usage、session listing 和新项目 cwd 混在一起,agent 很容易基于旧 repo 的假设在新 repo 里操作。建议重做为 workspace switch flow:保存当前会话,切到目标 workspace,恢复目标 workspace 最近会话或新建会话;当前 session 仍归属原 workspace。 -
workspace_path更新不完整,会留下旧 workspace 的派生身份
PR 只更新了session.config.workspace_path,但没有同步重算或清空workspace_id、remote identity 等派生信息。当前build_workspace_binding会优先使用已有workspace_id,导致后续工具 cwd 可能是新路径,但 workspace-scoped metadata、related dirs、注册信息仍可能来自旧 workspace。 -
存储锚点和 CLI 命令语义会错位
PR 试图用storage_workspace_path让 session 文件继续留在原 workspace,但/cd后 CLI adapter 的 workspace 已经变成新目录。这样/usage、/sessions、session delete/restore 等命令会按新 workspace 查找,而当前会话仍存储在旧 workspace,容易出现 usage 找不到、会话列表丢失、删除错目录或删除失败。 -
remote workspace 和多工作区边界没有设计
/cd通过本地canonicalize校验目标路径,只支持本地文件系统语义。若 CLI 后续或部分路径涉及 remote workspace,这个命令既没有 remote 支持,也没有明确 unsupported-state。按仓库规则,不能让 remote 场景静默变成错误路径或本地路径。 -
测试覆盖不足
当前测试主要覆盖命令注册和 path helper。这个功能改变 session persistence/workspace binding 语义,至少需要覆盖:切换后下一轮工具 cwd、session list/restore/delete、usage report、workspace_id 更新、存储目录保持、fork/subagent 行为,以及失败回滚。 -
PR 目前不能直接重放到主线
当前主线已经把SessionConfigowner 移到bitfun-agent-runtime,src/crates/assembly/core/src/agentic/core/session.rs只是 re-export。PR 在旧位置加storage_workspace_path会和主线冲突;rebase 后应改到 runtime owner crate,并按当前 session storage/index 逻辑重新适配。
|
感谢贡献,由于问题较多,暂时关闭 |
Summary
Adds a
/cd <path>slash command to the CLI chat mode that re-points the active session's working directory without restarting the session. The session id, message history, and prompt-cache prefix are preserved; subsequent turns simply execute against the new cwd.Ported from Claude Code's
/cdsemantics (changelog 2.1.169).Fixes # (open — please link if there is a tracking issue)
Type and Areas
Motivation / Impact
Today, switching the working directory in a CLI session requires
/clear+ restart (losing prompt cache) or relaunching the binary with a different--workspaceflag./cdlets users pivot context mid-session — common when an agent task spans multiple repos, or when the user realizes halfway through that the wrong directory was opened.Key design choice: logical cwd is split from persistence anchor.
SessionConfig.workspace_path(existing) continues to drive tool execution —build_workspace_bindingreads it, so subsequent turns run in the new cwd.SessionConfig.storage_workspace_path(optional, serde-defaultNone, backward-compatible) freezes the original workspace on the first/cd. Storage helpers prefer this anchor, so the session file, turn snapshots, and prompt cache stay rooted at the original directory and remain discoverable from its workspace listing.This matches the documented
/cdsemantics: prompt-cache prefix and session id stay intact, and the session stays listed under its original workspace (UX tradeoff called out in Reviewer Notes).Verification
Build + tests on top of
origin/main(commitb57aa652):New unit tests:
commands::tests::test_cd_registered—/cdis in COMMAND_SPECSmodes::chat::cd_helper_tests::*(10 tests) — quote stripping, tilde expansion, relative/absolute resolution, Windows drive-relative rejectionManual sanity (CLI):
/cdwith no arg prints current workspace;/cd ~/projectsswitches;/cd nonexistentreports an error and leaves state untouched;/cdduring a processing turn is rejected.Reviewer Notes
Design walkthrough
SessionManager::update_session_workspace_pathis the storage-side entry point. On first invocation it freezes the existing non-emptyworkspace_pathintostorage_workspace_path. Subsequent calls only mutateworkspace_path. The in-memory update is followed by a persistence save routed througheffective_session_workspace_path(which now prefers the storage anchor).ConversationCoordinator::update_session_workspace_pathis a thin pass-through with empty-path validation.start_dialog_turn_internalresolves its fallback finalize storage path viaeffective_session_workspace_pathinstead ofsession_workspace.session_storage_path(), so safety-net turn persistence honors the anchor. The livesession_workspace(used for tool execution) still readsconfig.workspace_path— that is the bug fix's whole point.fork_agent::build_child_session_configresetsstorage_workspace_path = Noneso child subagent sessions get their own anchor (rather than inheriting the parent's post-/cdhistory).Backward compatibility
storage_workspace_pathis#[serde(default, skip_serializing_if = "Option::is_none")]. Old session files on disk deserialize toNoneand the storage helper falls back toworkspace_path, byte-for-byte preserving prior behavior.SessionConfigdoes not setdeny_unknown_fields, so older clients reading newer files also work.Known UX tradeoff (by design)
After
/cd /new_dir, the session remains listed under its original workspace directory (so it stays discoverable where the user opened it). It will not appear in/new_dir's session list. This matches Claude Code's behavior and preserves prompt-cache locality. A dual-listing/index-relocation feature is a possible follow-up but is intentionally out of scope here.Review process
The implementation went through 4 rounds of independent review by Codex (GPT-5). Round 1 surfaced that the CLI-only fix was insufficient because
start_dialog_turn_internalbuildsWorkspaceBindingfromsession.config.workspace_path, not the passed-inworkspace_pathparameter — so tool calls would still land in the old cwd. Round 2 caught that turn snapshots and prompt cache writes would diverge from the session file location after/cd, plus a partial-failure inconsistency in the CLI. Rounds 3 and 4 confirmed the split-anchor design closes those issues and validated subagent / remote / serde-compat edge cases. All findings are resolved; the design notes above encode the constraints learned from that process.Checklist