Skip to content

Add /cd command - #4890

Merged
wenshao merged 10 commits into
QwenLM:mainfrom
qqqys:feat/cd-command
Jun 12, 2026
Merged

Add /cd command#4890
wenshao merged 10 commits into
QwenLM:mainfrom
qqqys:feat/cd-command

Conversation

@qqqys

@qqqys qqqys commented Jun 9, 2026

Copy link
Copy Markdown
Collaborator

What this PR does

Adds a /cd <path> slash command that changes the active session working directory without restarting the CLI. The command validates the target directory, prompts before trusting a new workspace path, updates workspace roots and cwd-backed services, migrates the active session transcript/runtime/worktree files to the new workspace session directory, refreshes system and directory context, and keeps path completion usable for directory arguments.

cd

Why it's needed

Users currently need to restart the CLI when they want the session to operate from a different project directory. This makes multi-repo or parent/child workspace navigation awkward, leaves no first-class way to move the active tool context during a session, and would otherwise leave the active conversation artifacts attached to the previous workspace after changing directories.

Reviewer Test Plan

How to verify

Run the focused CLI tests for the new slash command, completion/parser behavior, command registration, and slash command processor integration. Run the focused core tests for config relocation, client context refresh, workspace context root replacement, and session artifact migration. Build, lint, and typecheck the repo to confirm the change compiles across packages.

Evidence (Before & After)

Before: /cd was not registered as a builtin command, so users could not change the session working directory from inside the CLI. After: /cd <path> validates and applies a new working directory, handles trust confirmation for untrusted paths, moves active session artifacts into the destination workspace session directory, refreshes directory/system context, and reports non-fatal memory refresh failures as warnings.

Tested on

OS Status
🍏 macOS ✅ tested
🪟 Windows ⚠️ not tested
🐧 Linux ⚠️ not tested

Environment (optional)

Local macOS worktree with Node.js project dependencies already installed. Verified with npx vitest run src/ui/commands/cdCommand.test.ts src/ui/commands/directoryCommand.test.tsx src/utils/commands.test.ts src/services/BuiltinCommandLoader.test.ts src/ui/hooks/slashCommandProcessor.test.ts from packages/cli, npx vitest run src/config/config.test.ts src/core/client.test.ts src/utils/workspaceContext.test.ts from packages/core, focused reruns of npx vitest run src/ui/commands/cdCommand.test.ts and npx vitest run src/config/config.test.ts, plus npm run build, npm run typecheck, npm run lint -- --quiet, and Prettier check for the touched files.

Risk & Scope

  • Main risk or tradeoff: changing cwd during a live session touches several cached services, persisted session files, and model context paths, so the implementation flushes pending recording writes before moving artifacts, rolls back already-moved artifacts if migration fails, resets cwd-derived services, and appends a directory-change context note.
  • Not validated / out of scope: full npm run preflight, Windows manual verification, and Linux manual verification were not run locally.
  • Breaking changes / migration notes: none expected.

Linked Issues

Closes #4879

中文说明

What this PR does

新增 /cd <path> slash command,用于在不重启 CLI 的情况下切换当前会话的工作目录。该命令会校验目标目录,在新 workspace 路径未被信任时请求确认,更新 workspace roots 和依赖 cwd 的服务,把当前会话的 transcript/runtime/worktree 文件迁移到新 workspace 的 session 目录,刷新 system/directory context,并为目录参数保留路径补全能力。

Why it's needed

用户现在如果想让会话从另一个项目目录运行,通常需要重启 CLI。多仓库或父子 workspace 之间切换时这很不方便,也缺少一个在会话中移动 active tool context 的一等入口;如果只切换 cwd 而不迁移会话文件,当前 conversation artifact 仍会留在旧 workspace 下。

Reviewer Test Plan

How to verify

运行聚焦的 CLI 测试,覆盖新 slash command、补全/解析行为、命令注册和 slash command processor 集成。运行聚焦的 core 测试,覆盖 config relocation、client context refresh、workspace context root replacement 和 session artifact migration。再运行 build、lint 与 typecheck,确认跨 package 编译通过。

Evidence (Before & After)

Before: /cd 不是 builtin command,用户无法在 CLI 内切换会话工作目录。After: /cd <path> 会校验并应用新的工作目录,为未信任路径处理确认流程,把当前 session artifacts 移到目标 workspace 的 session 目录,刷新 directory/system context,并把非致命的 memory refresh 失败作为 warning 返回。

Tested on

OS Status
🍏 macOS ✅ tested
🪟 Windows ⚠️ not tested
🐧 Linux ⚠️ not tested

Environment (optional)

本地 macOS worktree,项目依赖已安装。验证命令包括在 packages/cli 下运行 npx vitest run src/ui/commands/cdCommand.test.ts src/ui/commands/directoryCommand.test.tsx src/utils/commands.test.ts src/services/BuiltinCommandLoader.test.ts src/ui/hooks/slashCommandProcessor.test.ts,在 packages/core 下运行 npx vitest run src/config/config.test.ts src/core/client.test.ts src/utils/workspaceContext.test.ts,本轮聚焦重跑 npx vitest run src/ui/commands/cdCommand.test.tsnpx vitest run src/config/config.test.ts,以及从仓库根目录运行 npm run buildnpm run typechecknpm run lint -- --quiet 和 touched files 的 Prettier check。

Risk & Scope

  • Main risk or tradeoff: 在 live session 中切换 cwd 会影响多个缓存服务、持久化 session 文件和模型上下文路径,因此实现会先 flush pending recording writes,再迁移 artifacts;如果迁移失败会回滚已移动的 artifacts,并显式重置依赖 cwd 的服务、追加 directory-change context note。
  • Not validated / out of scope: 本地没有运行完整 npm run preflight,也没有进行 Windows 和 Linux 手工验证。
  • Breaking changes / migration notes: 预期没有。

Linked Issues

Closes #4879

@qqqys
qqqys force-pushed the feat/cd-command branch from e931c17 to 2506e3e Compare June 9, 2026 07:11
@qqqys qqqys changed the title [codex] Add /cd command Add /cd command Jun 9, 2026
@qqqys
qqqys marked this pull request as ready for review June 9, 2026 07:32
@tanzhenxin tanzhenxin added the type/feature-request New feature or enhancement request label Jun 9, 2026
@qqqys
qqqys marked this pull request as draft June 9, 2026 09:18
@qqqys
qqqys force-pushed the feat/cd-command branch from 2506e3e to f787f93 Compare June 9, 2026 09:21
@qqqys
qqqys marked this pull request as ready for review June 9, 2026 09:22
@qqqys
qqqys force-pushed the feat/cd-command branch from f787f93 to 58e3129 Compare June 9, 2026 09:55
qqqys added 2 commits June 9, 2026 19:07
…d-command

# Conflicts:
#	packages/cli/src/ui/hooks/slashCommandProcessor.ts
@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Qwen Code review did not complete successfully: Qwen review timed out after 55 minutes. See workflow logs.

this.chatRecordingService?.resetStoragePaths();
await this.refreshCurrentRuntimeStatus(expected);
this.workspaceContext.applyRootDirectories(workspaceDirectories);
this.fileDiscoveryService = null;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Suggestion] After /cd, several project-scoped services are not invalidated: extensionManager (project-level extensions from the old directory remain loaded), hookSystem (hooks initialized with old config paths), toolRegistry (MCP server configs from the old project), and mcpServers. Only fileDiscoveryService, sessionService, fileHistoryService, and the file read cache are cleared.

After changing to a different project directory, project-level extensions, hooks, and MCP servers from the old project continue to operate. Users would expect the new directory's project configuration to take effect.

Consider invalidating or refreshing these services here, or document the limitation if a full refresh is too costly for a synchronous /cd operation.

— qwen3.7-max via Qwen Code /review

}
const workspaceDirectories = WorkspaceContext.resolveRootDirectories(
expected,
this.explicitIncludeDirectories,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Suggestion] this.explicitIncludeDirectories (set at startup from --include-dir CLI flag) is passed verbatim to resolveRootDirectories. After /cd to a completely different directory tree, old include directories remain in the workspace scope — even if they're outside the new project.

For example: qwen --include-dir /secret/project-b started in /home/user/project-a, then /cd /tmp — the workspace still includes /secret/project-b.

Consider clearing explicitIncludeDirectories on /cd, or at minimum warn the user that the original include dirs are still in scope.

— qwen3.7-max via Qwen Code /review

) => Promise<void>;
private initialized: boolean = false;
readonly storage: Storage;
storage: Storage;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Suggestion] storage was readonly storage: Storage and is now storage: Storage (public mutable). relocateWorkingDirectory is the only code that reassigns this field, so external mutation is not intended. Keep it private to preserve encapsulation — other code that reads config.storage should go through a getter.

Suggested change
storage: Storage;
private storage: Storage;

— qwen3.7-max via Qwen Code /review

}
}

setRootDirectories(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Suggestion] setRootDirectories has zero callers anywhere in the codebase. relocateWorkingDirectory uses resolveRootDirectories (static) + applyRootDirectories directly, bypassing this wrapper. Per the project's convention of not adding speculative abstractions, consider removing this until it's actually needed.

— qwen3.7-max via Qwen Code /review

} from '../../config/trustedFolders.js';
import { t } from '../../i18n/index.js';

const pendingTrustedPathConfirmations = new Map<string, string>();

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Suggestion] pendingTrustedPathConfirmations is a module-level Map that only shrinks when the user confirms (delete on line 156). If the user cancels or dismisses the trust prompt, the entry persists for the process lifetime. In long-running sessions or daemon mode, repeated /cd attempts to different untrusted directories cause unbounded growth.

Consider clearing stale entries — either at the start of each /cd invocation, on any non-confirming command, or with a simple size cap:

if (pendingTrustedPathConfirmations.size > 50) {
  pendingTrustedPathConfirmations.clear();
}

— qwen3.7-max via Qwen Code /review

@wenshao

wenshao commented Jun 9, 2026

Copy link
Copy Markdown
Collaborator

Local runtime verification report (Linux)

Built this branch (571f55045) and drove the real TUI under tmux on Linux 6.12 / Node v22.22.2 with a live model (glm-4.7) — covering the Linux verification the PR marks as not done. Unit tests: all author-listed suites pass locally (113 cli + 403 core).

What works well end-to-end

Scenario Result
/cd /abs/path ✅ "Moved to …" message, footer path updates immediately, process.cwd really changes (Shell pwd → new dir), relative read_file resolves in the new dir
Session artifact migration <sessionId>.jsonl + .runtime.json physically moved from ~/.qwen/projects/-…-projA/chats/ to the target project's chats dir; missing .worktree.json skipped; second hop (projB → dir with space) also moved correctly into the sanitized -…-dir-with-space storage dir; runtime.json.work_dir updated
Model context refresh ✅ after /cd, the model answers the new cwd without running any tool (injected directory-change note + refreshed directory context)
Error handling ✅ bare /cd → usage; nonexistent → "Couldn't find a directory at …"; file target → "… is not a directory."; same dir → "Already in …"
Paths with spaces /cd '../dir with space' works (the parseSlashCommand verbatim-args change + quote stripping)
Completion ✅ directory completion popup works for the path argument (auto-appended trailing / handled fine)
Trust flow (folderTrust enabled) /cd to an untrusted dir shows the confirm dialog with the read/edit/execute disclosure; on Yes the move happens first and only then is the folder persisted to trustedFolders.json (good ordering); footer/cwd update as usual

Also checked: reading a file from the old workspace after /cd still succeeds under YOLO — but a control test showed files outside both workspaces are equally readable under YOLO, so that is standard YOLO behavior, not a workspace-root leak from this PR.

🔴 Blocking: a migrated session can no longer be resumed — from anywhere

Repro (real TUI):

  1. Start in projA, exchange a message (session 910ae84f-… created under -tmp-pr4890-ws-projA/chats/).
  2. /cd /tmp/pr4890-ws/projB (artifacts move to projB's chats dir — verified on disk), quit.
  3. From projB: qwen --resume 910ae84f-…"No saved session found with ID 910ae84f-…".
  4. From projB: qwen --resume (picker) → "No sessions found. Start a new session with qwen." — even though the session file sits in this project's chats dir.
  5. From projA: file was moved away, so it's gone there too.

Root cause: SessionService.loadSession() (and the listSessions() iteration) validates session ownership with getProjectHash(firstRecord.cwd) !== this.projectHash → reject. The first JSONL record's cwd is forever the original directory, so a migrated file can never pass the check in its new home — and it's no longer present in its old home. The check is pre-existing main logic (it exists to disambiguate sanitized-path collisions in shared chats dirs), so the migration as implemented moves files into a directory where every consumer rejects them.

Net effect: /cd makes the active session unresumable everywhere, which is strictly worse than not migrating at all (without migration it would at least remain resumable from the old workspace). Since carrying the conversation artifacts to the new workspace is one of the PR's stated goals, this needs a fix before merge — e.g. make migration write something the ownership check accepts (update/append a record or sidecar with the new project hash), or teach loadSession/listSessions to also accept a session whose runtime.json.work_dir (already updated by this PR) maps to the current project.

The new unit tests verify the file moves but never attempt a resume after migration, which is how this slipped through — worth adding as a regression test alongside the fix.

🔴 CI is red, and both failures are PR-caused (not the known main flakes)

  1. Lint job fails in the check-i18n step (reproduced locally): Extra key in zh.js / zh-TW.js (not in en.js): "Move this session to a new working directory" — the new command description was added to the two Chinese locales but not to the en.js baseline. Trivial fix.
  2. Windows test job fails on this PR's own new tests: config.test.ts > relocateWorkingDirectory should move current session artifacts… and …should refresh runtime status…. This is distinct from the dev.test.js launcher failures currently flaking on main — these two are introduced by this PR (Windows is listed as not tested by the author). Likely path/realpath semantics; needs a look on a Windows runner.

Minor notes (non-blocking)

  • Workspace-level settings of the target directory are not reloaded after /cd (the session keeps the launch workspace's merged settings). Not claimed by the PR, but worth a line in docs since "moved" sessions behave differently from fresh sessions in that directory.
  • pendingTrustedPathConfirmations is a module-level map keyed by raw invocation; entries for never-confirmed prompts linger for the process lifetime. Cosmetic.

Conclusion

The interactive /cd experience itself is solid on Linux — directory switch, context refresh, trust gating, error handling, and the storage-file moves all behave as designed, and the EXDEV-safe move + rollback code is careful. But the migrated session being invisible to --resume/the picker defeats the migration's purpose and loses previously-available resumability, and CI is red from two PR-caused failures. Recommend: fix the resume/ownership mismatch (with a resume-after-/cd regression test), add the missing en.js key, and fix the Windows relocation tests before merge.

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Qwen Code review did not complete successfully: Qwen review timed out after 55 minutes. See workflow logs.

}
}

applyRootDirectories(resolved: ResolvedWorkspaceDirectories): void {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Critical] applyRootDirectories replaces this.directories and this.initialDirectories with new sets built solely from the primary directory + explicitIncludeDirectories. Any directories previously added at runtime via /directory add (which mutates this.directories via addDirectory) are silently dropped after /cd. The user's workspace configuration is lost with no warning.

Suggested change
applyRootDirectories(resolved: ResolvedWorkspaceDirectories): void {
applyRootDirectories(resolved: ResolvedWorkspaceDirectories): void {
const newDirectories = resolved.directories;
const newInitialDirectories = resolved.initialDirectories;
// Preserve runtime-added directories that aren't in the new initial set
for (const existing of this.directories) {
if (!this.initialDirectories.has(existing)) {
newDirectories.add(existing);
}
}
const directoriesChanged =
newDirectories.size !== this.directories.size ||
![...newDirectories].every((d) => this.directories.has(d));
const initialDirectoriesChanged =
newInitialDirectories.size !== this.initialDirectories.size ||
![...newInitialDirectories].every((d) => this.initialDirectories.has(d));
this.directories = newDirectories;
this.initialDirectories = newInitialDirectories;
this.resolvedPathCache.clear();
if (directoriesChanged || initialDirectoriesChanged) {
this.notifyDirectoriesChanged();
}
}

— DeepSeek/deepseek-v4-pro via Qwen Code /review

@wenshao

wenshao commented Jun 10, 2026

Copy link
Copy Markdown
Collaborator

Local runtime verification report #2 (Linux) — head cb6f9afba

Re-verified the updated branch on Linux 6.12 / Node v22.22.2: rebuilt this head and drove the real TUI under tmux with a live model (glm-4.7), focusing on the two new commits (c474ca806 trust-confirmation cap, cb6f9afba migrated-session resume fix) plus a regression sweep of the scenarios from my previous report on 571f55045.

✅ Previous blocker is fixed: migrated sessions resume correctly

Full lifecycle re-run end-to-end (real TUI, real model, files inspected on disk at every hop):

Step Result
projA → message → /cd projB → quit → qwen --resume <id> from projB ✅ resumes; history intact — model answers the earlier codeword without tools
Second hop from the resumed session: /cd ../projC (relative path) ✅ artifacts move again; runtime.json.work_dir → projC
--resume picker from projC ✅ session listed and resumes with both hops of history; relative read_file resolves in projC
Re-resume after picker-resume (runtime.json rewritten by new pid) ✅ stays consistent (session_id unchanged, work_dir=projC)
Negative: picker from original projA ✅ "No sessions found" (no duplicate/stale visibility)
Negative: --resume <id> from projA ✅ correctly rejected
Sanitized-path collision (x y vs x-y sharing one chats dir) ✅ disambiguation intact; each project sees only its own session — the new runtime-status fallback does not false-accept sessions lacking a runtime.json (headless -p sessions)

The fix (sessionBelongsToCurrentProject: first-record cwd hash, else runtime.json.work_dir hash) matches what I suggested, and the new unit tests cover list + load of a migrated session.

✅ Other items from last report, re-verified on this head

  • i18n: en.js key added; npm run check-i18n passes locally; CI Lint is now green.
  • Trust-confirmation cap: MAX_PENDING_TRUST_CONFIRMATIONS = 50 with unit test; normal trust flow re-verified live (dialog with read/edit/execute disclosure → Yes: move happens, then folder persisted to trustedFolders.json; No: clean abort — no move, no trust entry, no chats dir created).
  • Regression sweep: bare /cd → usage; nonexistent → "Couldn't find a directory"; file target → "is not a directory"; same dir → "Already in"; footer/cwd update; completion popup — all behave as before.
  • Unit tests: author-listed suites all pass locally — 114 cli + 458 core (incl. the new sessionService migration tests). CI: Ubuntu ✅ macOS ✅ CodeQL ✅.

🔴 Still open: Windows CI red on this PR's own tests (unchanged)

Test (windows-latest) fails on the same two PR-introduced tests as last time — config.test.ts > relocateWorkingDirectory should move current session artifacts… and …should refresh runtime status…, both AssertionError: expected "spy" to be called with arguments: [ …(2) ] (the fs.renameSync(old, new) / runtime-status path assertions). 2 failed / 10350 passed — these are the run's only failures, so it's not the known main-branch dev.test.js flake. Worth determining on a Windows machine whether it's only a test-mock/path-separator artifact or a real canonicalization issue in the relocation path (e.g. drive-letter casing feeding getProjectHash) — the latter would put migrated artifacts in a wrong project dir on real Windows.

🟡 New finding: the ownership fix only covers listSessions/loadSession — 7 other consumers still reject migrated sessions

sessionService.ts still has raw getProjectHash(records[0].cwd) !== this.projectHash checks in removeSession (L771), renameSession (L856), forkSession (L931), countSessionMessages (L423), findSessionsByTitle (L1060), the title-dedup scan (L1133), and sessionExists (L1176). Since the first record's cwd is forever the original directory, every one of these denies a migrated session in its new home. Live-verified consequences (real TUI):

  1. /delete: the migrated session is listed (via the fixed listSessions) but deleting it fails — "✕ Failed to delete session. Session not found." — file stays on disk. Since it's also gone from the old project, a migrated session becomes undeletable from anywhere via the UI.
  2. In-TUI /resume <id>: fails with "No session found with ID …" for a migrated session, while CLI --resume <same id> from the same directory succeeds — resumeCommand pre-validates with the unfixed sessionExists.
  3. /branch immediately after /cd: "✕ No conversation to branch." despite a real conversation (control test without /cd: branching works) — branchCommand gates on sessionExists(currentId). So the live, just-moved session loses /branch until something rewrites its first record.
  4. Same mechanism, not individually tested: resume-by-title (gemini.tsxfindSessionsByTitle), ACP/Zed sessionExists/renameSession by id. (/rename of the current session works — it goes through the recording service, not renameSession.)

Suggested fix: route all of these through the same sessionBelongsToCurrentProject helper (one-line change per site), plus a regression test for "delete/branch/resume-in-TUI after /cd" to lock it in.

Conclusion

The previously blocking resume regression is genuinely fixed — the whole migrate → resume → re-migrate → re-resume chain now works, with sensible negative behavior and no collision regressions. Lint is green. Remaining before merge, in my view: (a) the Windows job is red on this PR's own two relocation tests and needs a fix or a Windows-side investigation; (b) the ownership-check fallback should be extended to the remaining seven call sites — /delete, in-TUI /resume, and /branch-after-/cd are user-visible breakages of the same root cause the last round fixed for resume, and /branch breaks in the live session right after using the new command. With (a) green and (b) routed through the shared helper, this looks merge-ready to me.

中文版

本地运行时验证报告 #2(Linux)— head cb6f9afba

在 Linux 6.12 / Node v22.22.2 上对更新后的分支做了第二轮验证:重新构建本 head,在 tmux 中用真实 TUI + 真实模型(glm-4.7)驱动,重点覆盖两个新 commit(c474ca806 trust 确认上限、cb6f9afba 迁移会话 resume 修复),并对上一份报告(基于 571f55045)中的场景做了回归扫查。

✅ 上轮阻塞缺陷已修复:迁移后的会话可以正常 resume

端到端重跑完整生命周期(真实 TUI、真实模型,每一跳都检查磁盘文件):

步骤 结果
projA → 发消息 → /cd projB → 退出 → 在 projB 执行 qwen --resume <id> ✅ 成功恢复;历史完整——模型不调用任何工具直接答出此前的标记词
resume 出的会话里二跳:/cd ../projC(相对路径) ✅ 工件再次迁移;runtime.json.work_dir → projC
在 projC 打开 --resume picker ✅ 会话被列出且可恢复,两跳历史完整;相对路径 read_file 在 projC 中解析
picker 恢复后再次退出重连(runtime.json 已被新 pid 重写) ✅ 保持一致(session_id 不变,work_dir=projC)
反向验证:在原目录 projA 打开 picker ✅ "No sessions found"(无重复/过期可见性)
反向验证:在 projA 执行 --resume <id> ✅ 正确拒绝
净化路径碰撞(x yx-y 共享同一 chats 目录) ✅ 消歧逻辑完好;各项目只看到自己的会话——新的 runtime-status fallback 不会误收没有 runtime.json 的会话(headless -p 会话)

修复方案(sessionBelongsToCurrentProject:先比对首记录 cwd hash,否则回退到 runtime.json.work_dir hash)与我上轮的建议一致,且新增单测覆盖了迁移会话的 list + load。

✅ 上轮报告的其他事项,已在本 head 复验

  • i18n:en.js key 已补;本地 npm run check-i18n 通过;CI Lint 已转绿
  • Trust 确认上限:MAX_PENDING_TRUST_CONFIRMATIONS = 50 并附单测;trust 流程实测正常(对话框含读/改/执行披露 → Yes:先迁移、后将目录持久化到 trustedFolders.json;No:干净中止——不迁移、不写 trust 条目、不创建 chats 目录)。
  • 回归扫查:裸 /cd → usage;不存在的路径 → "Couldn't find a directory";文件目标 → "is not a directory";同目录 → "Already in";footer/cwd 更新、补全弹窗——行为与上轮一致。
  • 单元测试:作者列出的套件本地全部通过——114 cli + 458 core(含新增 sessionService 迁移测试)。CI:Ubuntu ✅ macOS ✅ CodeQL ✅。

🔴 仍未解决:Windows CI 在本 PR 自带测试上仍红(与上轮相同)

Test (windows-latest) 失败的仍是同样两个本 PR 引入的测试——config.test.ts > relocateWorkingDirectory should move current session artifacts……should refresh runtime status…,均为 AssertionError: expected "spy" to be called with arguments: [ …(2) ](fs.renameSync(old, new) / runtime-status 路径断言)。2 failed / 10350 passed——是该 run 仅有的失败,不是 main 分支已知的 dev.test.js flake。建议在 Windows 机器上确认:只是测试 mock/路径分隔符问题,还是 relocation 路径上真实的规范化问题(例如盘符大小写进入 getProjectHash)——若是后者,真实 Windows 上迁移工件会落到错误的 project 目录。

🟡 新发现:ownership 修复只覆盖了 listSessions/loadSession——还有 7 处消费方仍拒绝迁移会话

sessionService.ts 中仍有裸的 getProjectHash(records[0].cwd) !== this.projectHash 校验:removeSession(L771)、renameSession(L856)、forkSession(L931)、countSessionMessages(L423)、findSessionsByTitle(L1060)、title 去重扫描(L1133)、sessionExists(L1176)。由于首记录的 cwd 永远是原目录,这些校验都会在新家拒绝迁移会话。实测后果(真实 TUI):

  1. /delete:迁移会话会被列出(经由已修复的 listSessions),但删除失败——"✕ Failed to delete session. Session not found."——文件留在磁盘。又因为旧项目里也没有它,迁移会话在 UI 层面从任何地方都删不掉
  2. TUI 内 /resume <id>:对迁移会话报 "No session found with ID …",而同目录下 CLI --resume <同一 id> 却成功——resumeCommand 用未修复的 sessionExists 做前置校验。
  3. /cd 后立即 /branch:"✕ No conversation to branch.",尽管对话真实存在(对照组:不 /cd 时分支正常)——branchCommand 依赖 sessionExists(currentId)。也就是说刚迁移完的活动会话立即失去 /branch 能力。
  4. 同一机制、未逐一实测:按标题 resume(gemini.tsxfindSessionsByTitle)、ACP/Zed 的按 id sessionExists/renameSession。(对当前会话的 /rename 正常——它走 recording service,不经过 renameSession。)

建议修复:把上述全部调用点统一路由到 sessionBelongsToCurrentProject helper(每处一行改动),并补一条"/cd 之后 delete/branch/TUI 内 resume"的回归测试。

结论

上轮的阻塞性 resume 缺陷已确实修复——迁移 → resume → 再迁移 → 再 resume 的完整链路现在可用,反向行为合理,碰撞消歧无回归,Lint 已绿。我认为合并前还需:(a) Windows job 在本 PR 自带的两个 relocation 测试上仍红,需要修复或在 Windows 侧排查;(b) ownership 校验的 fallback 应扩展到其余七处调用点——/delete、TUI 内 /resume/cd/branch 是与上轮 resume 同根因的用户可见破坏,且 /branch 在刚用完新命令的活动会话里立即失效。(a) 转绿、(b) 统一走共享 helper 后,我认为即可合并。

wenshao
wenshao previously approved these changes Jun 10, 2026
@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Qwen Code review did not complete successfully: Qwen review timed out after 55 minutes. See workflow logs.

qqqys and others added 2 commits June 10, 2026 11:06
Resolve dev.test.js by taking main's version: the branch carried its own
copy of the Windows path-normalization fix, and the auto-merge with
main's variant left a duplicate, unused module-level normalizePath that
failed lint (no-unused-vars).

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
wenshao
wenshao previously approved these changes Jun 10, 2026

@qwen-code-ci-bot qwen-code-ci-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

No high-confidence critical or suggestion issues found. The /cd command implementation is well-structured with proper rollback logic, symlink TOCTOU guards, trust confirmation, and comprehensive test coverage. Lint, typecheck, and all 523 tests pass. Remaining concerns from prior review rounds (session ownership at 7 call sites, Windows CI) are already tracked in existing comments. ✅ — qwen3.7-max via Qwen Code /review

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Qwen Code review did not complete successfully: Qwen review timed out after 55 minutes. See workflow logs.

@DragonnZhang DragonnZhang left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

No new review findings on this pass. The blocking issue from the earlier review (migrated sessions not resumable) has been resolved in commits cb6f9af and 0a18c8d. The sessionBelongsToCurrentProject fallback via runtime status is sound, and applyRootDirectories now correctly preserves runtime-added directories. All CI code-quality checks pass (Lint, Test on Linux/macOS/Windows, CodeQL). The only failing check is the review-pr workflow itself, which is CI infrastructure, not a code defect. Downgraded from Approve to Comment: CI reporting review-pr as failing. -- claude-sonnet-4 via Qwen Code /review

@wenshao

wenshao commented Jun 11, 2026

Copy link
Copy Markdown
Collaborator

Local runtime verification report #3 (Linux) — head 7addd9756

Third round on the updated branch, Linux 6.12 / Node v22.22.2: synced the worktree to this head, real npm ci + full bundle rebuild (bundle stamped GIT_COMMIT_INFO: 7addd9756), and drove the real TUI under tmux with a live model (glm-4.7), focusing on the four commits since my report #2 (f86547e4d, 0a18c8d3a, f92d746a0, merge 7addd9756). Disk state (~/.qwen/projects/<dir>/chats/*.jsonl + *.runtime.json) inspected at every hop.

✅ Report #2 blocker (a) resolved: Windows CI is green, and the fix is test-only

f86547e4d switches the two failing relocation tests from new Storage(baseParams.targetDir) (raw path) to new Storage(config.getTargetDir()) (the canonicalized path the production code actually uses) — confirming the failure was a test-fixture canonicalization artifact, not a real relocation bug. Test (windows-latest) now passes (20m59s), as do ubuntu/macos/Lint/CodeQL. The only red check is the Qwen review bot timing out, which is unrelated to this change.

✅ Report #2 blocker (b) resolved: all ownership checks now accept migrated sessions — live-verified

0a18c8d3a routes the seven remaining raw getProjectHash(records[0].cwd) comparisons (removeSession, renameSession, forkSession, countSessionMessages, findSessionsByTitle, title-dedup, sessionExists) through the shared sessionBelongsToCurrentProject helper — all nine ownership checks now use it — with new unit tests. The three user-visible breakages from report #2, re-tested end-to-end in the real TUI:

Scenario (after projA → msg → /cd projB/cd ../projC relative hop) #2 Now
/delete the migrated session from projC listed but "Failed to delete" — undeletable anywhere ✅ deletes; .jsonl verified gone from disk
in-TUI /resume <id> of the migrated session "No session found with ID …" ✅ switches with full history (model recalls codeword without tools)
/rename + quit + --resume <title> from projC (findSessionsByTitle) rejected (same root cause) ✅ resumes by title, both hops of history intact

Negative checks still correct on this head: --resume <id> and the picker from projA/projB (old homes) are rejected / show "No sessions found" — the fallback doesn't leak sessions across projects. renameSession/countSessionMessages (ACP-facing) are covered by the new unit tests (cli 114 + core 481 all pass locally).

✅ New fix f92d746a0 verified: runtime-added workspace dirs survive /cd

/dir add /tmp/cd3/projX/cd /tmp/cd3/projB/dir show now lists projB + projX (previously the runtime-added dir was wiped by the root swap); a live read_file of projX/x.txt returns its contents, so the preserved dir is functionally part of the workspace, not just display. The old root projA is correctly dropped from /dir show. (Note: read_file of a path outside the workspace also succeeds in default approval mode — verified with a no-/cd control session, so that's baseline tool behavior, not a /cd hole.)

✅ Regression sweep on this head

Absolute + relative /cd hops with artifact migration and runtime.json.work_dir updates; trust flow with folderTrust enabled (dialog with read/edit/execute disclosure → No: "Operation cancelled.", no move, no trust entry, no chats dir created; Yes: move + trustedFolders.json entry persisted); bare /cd → usage; nonexistent → "Couldn't find a directory"; file target → "is not a directory"; same dir → "Already in"; footer cwd updates; directory completion popup — all as before.

🔴 Still broken, new failure mode: /branch after /cd — fork load fails and leaks an orphaned session file

Report #2's /branch breakage has moved one layer deeper rather than gone away. Live sequence projA → msg → /cd projB/branch:

  • Where is the config saved? #2 (old): ✕ No conversation to branch. (sessionExists rejected the migrated parent — now fixed)
  • This head: ✕ Failed to branch conversation: Failed to load newly forked session

Root cause (code + disk evidence): forkSession copies the records rewriting sessionId to the new UUID but keeps each record's cwd (forever the pre-/cd projA). useBranchCommand.ts then calls loadSession(newSessionId) (step 4) before config.startNewSession (step 5) — but for the fork, sessionBelongsToCurrentProject(newId, cwd=projA) fails both ways: the first-record hash mismatches, and the runtime-status fallback reads chats/<newId>.runtime.json, which is only written by startNewSession. Ordering deadlock — the load that gates the swap can never pass for a fork of a migrated session. (Control: /branch without a prior /cd works fine on this head; in that flow the first-record hash matches so the sidecar isn't needed at load time.)

Worse, the failure leaks state: step 3 already created the fork .jsonl on disk, and the catch block rolls back core state but never unlinks it. The orphan (first-record cwd=projA, no runtime.json) is then invisible to listSessions from both projA (file isn't in its chats dir) and projB (ownership check fails) — so it can't be deleted via the UI from anywhere, and it doesn't migrate on subsequent /cd hops (verified: it stayed in projB's chats dir after the parent moved on to projC). Every /branch attempt after a /cd leaks one such file.

Suggested fix:

  1. Make the fork belong to where it's created: have forkSession stamp the copied records' cwd (at minimum the first record) with the current target dir — or give loadSession a skip-ownership option for the just-created fork (the caller knows it made it). Stamping also fixes the picker showing the stale projA path for the fork.
  2. In the useBranchCommand catch path, best-effort delete the fork file created in step 3 so a failed branch doesn't strand artifacts.
  3. One trap for the fix: on a successful branch the parent's runtime.json is superseded by the fork's (observed in the control run — after /branch, only the fork had a sidecar). For a migrated parent that sidecar is exactly what keeps it reachable, so a fix that only makes the fork loadable would leave the parent invisible afterwards — and the post-branch hint "To resume the original: /resume <parentId>" would fail. Re-stamping the fork records' cwd (option 1) avoids this only for the fork; the parent likely needs its sidecar preserved or its first record re-stamped during relocation.
  4. Regression test: "fork/branch a session that was relocated via /cd, then load + list both fork and parent."

🟡 Footnote (pre-existing, not this PR)

/delete removes the session .jsonl but leaves its .runtime.json sidecar behind — reproduced with a never-migrated control session too, and the sidecar infra predates this PR, so not a regression here. Worth an eventual cleanup since stale sidecars now participate in ownership decisions.

Conclusion

Both report-#2 merge blockers are genuinely resolved and live-verified: Windows CI is green via a legitimate test-only fix, and the ownership unification makes /delete, in-TUI /resume, and title-based resume work on migrated sessions, with cross-project rejection intact. The workspace-dirs preservation fix also checks out. The one remaining user-visible defect is /branch after /cd: still broken on this head (new failure mode further down the same root-cause chain) and now leaking undeletable orphaned session files per attempt. Since /branch is the documented escape hatch right after /cd (the success path even advertises /resume of the original), I'd fix this before merge — items 1–2 above are small and the rest of the command is in good shape.

中文版

本地运行时验证报告 #3(Linux)— head 7addd9756

第三轮验证,Linux 6.12 / Node v22.22.2:worktree 同步到本 head,真实 npm ci + 完整 bundle 重建(bundle 内嵌 GIT_COMMIT_INFO: 7addd9756),tmux 中以真实 TUI + 真实模型(glm-4.7)驱动,重点覆盖报告 #2 之后的四个 commit(f86547e4d0a18c8d3af92d746a0、merge 7addd9756)。每一跳都检查磁盘状态(~/.qwen/projects/<dir>/chats/*.jsonl + *.runtime.json)。

✅ 报告 #2 阻塞项 (a) 已解决:Windows CI 转绿,且修复仅涉及测试

f86547e4d 把两个失败的 relocation 测试从 new Storage(baseParams.targetDir)(原始路径)改为 new Storage(config.getTargetDir())(生产代码实际使用的规范化路径)——证实失败是测试夹具的路径规范化问题,不是真实的 relocation 缺陷。Test (windows-latest) 现已通过(20m59s),ubuntu/macos/Lint/CodeQL 同绿。唯一的红色检查是 Qwen review bot 超时,与本变更无关。

✅ 报告 #2 阻塞项 (b) 已解决:所有 ownership 校验接受迁移会话——已实测

0a18c8d3a 把其余 7 处裸 getProjectHash(records[0].cwd) 比较(removeSessionrenameSessionforkSessioncountSessionMessagesfindSessionsByTitle、title 去重、sessionExists)统一路由到共享的 sessionBelongsToCurrentProject helper——至此全部 9 处 ownership 校验都走该 helper——并新增单测。报告 #2 的三个用户可见破坏,真实 TUI 端到端重测:

场景(projA → 发消息 → /cd projB → 相对路径 /cd ../projC 二跳后) #2 现在
在 projC /delete 迁移会话 列出但 "Failed to delete"——任何地方都删不掉 ✅ 删除成功;磁盘确认 .jsonl 已移除
TUI 内 /resume <id> 迁移会话 "No session found with ID …" ✅ 切换成功且历史完整(模型不用工具直接答出标记词)
/rename + 退出 + 在 projC --resume <title>(findSessionsByTitle) 同根因被拒 ✅ 按标题恢复,两跳历史完整

反向校验在本 head 仍正确:从 projA/projB(旧家)--resume <id> 被拒、picker 显示 "No sessions found"——fallback 不会让会话跨项目泄露。renameSession/countSessionMessages(ACP 侧)由新单测覆盖(本地 cli 114 + core 481 全部通过)。

✅ 新修复 f92d746a0 验证通过:运行时添加的 workspace 目录在 /cd 后保留

/dir add /tmp/cd3/projX/cd /tmp/cd3/projB/dir show 现在列出 projB + projX(此前根替换会清掉运行时添加的目录);实测 read_file 读取 projX/x.txt 返回内容,说明保留的目录是功能性的 workspace 成员而非仅显示。旧根 projA 正确地从 /dir show 移除。(注:默认审批模式下 read_file 读 workspace 路径也会成功——用无 /cd 的对照会话验证过,这是工具基线行为,不是 /cd 留下的口子。)

✅ 本 head 回归扫查

绝对 + 相对路径 /cd 多跳、工件迁移、runtime.json.work_dir 更新;trust 流程(启用 folderTrust:对话框含读/改/执行披露 → No:"Operation cancelled."、不迁移、不写 trust、不建 chats 目录;Yes:迁移 + trustedFolders.json 持久化);裸 /cd → usage;不存在路径 → "Couldn't find a directory";文件目标 → "is not a directory";同目录 → "Already in";footer cwd 更新;目录补全弹窗——全部与此前一致。

🔴 仍然损坏、新失败形态:/cd/branch——fork 加载失败并泄漏孤儿会话文件

报告 #2/branch 破坏没有消失,而是下沉了一层。实测序列 projA → 发消息 → /cd projB/branch:

  • Where is the config saved? #2(旧):✕ No conversation to branch.(sessionExists 拒绝迁移的父会话——现已修复)
  • 本 head:✕ Failed to branch conversation: Failed to load newly forked session

根因(代码 + 磁盘证据):forkSession 复制记录时把 sessionId 改写为新 UUID,但保留每条记录的 cwd(永远是 /cd 前的 projA)。useBranchCommand.ts 随后在 config.startNewSession(第 5 步)之前调用 loadSession(newSessionId)(第 4 步)——而对 fork 来说,sessionBelongsToCurrentProject(newId, cwd=projA) 两条路都不通:首记录 hash 不匹配,runtime-status fallback 要读 chats/<newId>.runtime.json,而该文件恰恰要等 startNewSession 才写入。时序死锁——门控切换的加载对"迁移会话的 fork"永远不可能通过。(对照组:本 head 上不经 /cd/branch 正常;该流程首记录 hash 直接匹配,加载时不需要边车文件。)

更糟的是失败会泄漏状态:第 3 步已经在磁盘创建了 fork .jsonl,catch 块只回滚内存状态、从不删除它。这个孤儿(首记录 cwd=projA、无 runtime.json)对 projA(文件不在它的 chats 目录)和 projB(ownership 校验失败)的 listSessions 都不可见——UI 层面从任何地方都删不掉,后续 /cd 也不会带走它(实测:父会话迁到 projC 后它仍留在 projB 的 chats 目录)。/cd 之后每尝试一次 /branch 就泄漏一个文件。

修复建议:

  1. 让 fork 归属于它的创建地:forkSession 把复制记录的 cwd(至少首记录)改写为当前 target dir——或给 loadSession 加一个跳过 ownership 的选项供刚创建 fork 的调用方使用(调用方明确知道是自己刚建的)。改写 cwd 同时能修正 picker 中 fork 显示过期 projA 路径的问题。
  2. useBranchCommand 的 catch 路径 best-effort 删除第 3 步创建的 fork 文件,失败的 branch 不应留下工件。
  3. 修复时的一个坑:branch 成功路径上父会话的 runtime.json 会被 fork 的取代(对照组观察到——/branch 后只有 fork 有边车文件)。对迁移过的父会话,这个边车恰是它保持可达的依据,只让 fork 可加载的修复会让父会话事后不可见——branch 成功后提示的 "To resume the original: /resume <parentId>" 会失效。方案 1 的 cwd 改写只救 fork;父会话大概率需要在 relocation 时保留边车或改写首记录。
  4. 回归测试:"fork/branch 一个经 /cd 迁移过的会话,然后 load + list fork 和父会话"。

🟡 脚注(既有行为,非本 PR)

/delete 删除会话 .jsonl 但留下 .runtime.json 边车——用从未迁移的对照会话同样复现,且边车基建先于本 PR 存在,不算本 PR 回归。但既然过期边车现在参与 ownership 判定,值得后续清理。

结论

报告 #2 的两个合并阻塞项都已确实解决并经实测:Windows CI 通过正当的测试侧修复转绿;ownership 统一让 /delete、TUI 内 /resume、按标题恢复在迁移会话上全部可用,且跨项目拒绝完好。workspace 目录保留修复同样验证通过。剩余的唯一用户可见缺陷是 /cd/branch:本 head 仍坏(同根因链上更深一层的新失败形态),且每次尝试都泄漏无法删除的孤儿会话文件。鉴于 /branch/cd 之后的标准逃生通道(成功路径甚至会提示 /resume 原会话),建议合并前修复——上面第 1–2 项改动很小,命令的其余部分状态良好。

@qqqys
qqqys dismissed stale reviews from qwen-code-ci-bot and wenshao via 7481b5d June 12, 2026 00:16

@DragonnZhang DragonnZhang left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM. Well-structured implementation with thorough test coverage. Key areas reviewed:

  • Trust confirmation flow: Correctly resolves paths before prompting and re-validates after confirmation (TOCTOU protection via realpath comparison).
  • Session artifact migration: Proper rollback on failure, including cross-device (EXDEV) fallback with copy+unlink and cleanup of partial copies.
  • relocateWorkingDirectory: Sound ordering — finalize/flush recording service, move artifacts, then update config state. Rollback restores cwd, storage, and transcript path.
  • sessionBelongsToCurrentProject: Correct use of runtime status sidecar to identify migrated sessions whose first-record cwd no longer matches the project hash.
  • parseSlashCommand whitespace fix: The commandText.slice(argsStart).trim() approach correctly preserves internal whitespace in command arguments, with indexOf(part, argsStart) tracking consumed positions to avoid false matches when argument text repeats a command/subcommand name.
  • applyRootDirectories: Correctly preserves runtime-added (non-initial) directories when swapping roots.
  • Branch cleanup: Good addition of removeSession for failed branch sessions.

No blocking issues found.

@wenshao wenshao left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

No high-confidence findings. Downgraded from Approve to Comment: CI failing (review-pr). Implementation is well-structured with proper rollback logic, symlink TOCTOU guards, trust confirmation flow, and comprehensive test coverage (595 tests pass, tsc/eslint clean). 8 low-confidence suggestions identified for human review (stale SessionStart context, Config state consistency around async gaps, parseSlashCommand global whitespace change, EXDEV fallback hardening, test coverage gaps, observability logging). 5 prior-round inline comments at current commit not re-reported. — qwen3.7-max via Qwen Code /review

@wenshao

wenshao commented Jun 12, 2026

Copy link
Copy Markdown
Collaborator

Local runtime verification (maintainer)

Built this PR locally (7481b5d51) and exercised /cd end-to-end in a real interactive TUI session (tmux-driven, real model qwen3.7-max doing actual tool calls), using an isolated $HOME so folder-trust and session state started clean.

Environment: macOS (Darwin 25.5.0), Node v22.22.2, tmux 3.6a.

Focused unit tests (from the PR test plan)

  • packages/cli — cdCommand / directoryCommand / commands / BuiltinCommandLoader / slashCommandProcessor: 114 passed (5 files)
  • packages/core — config / client / workspaceContext / sessionService / sessionService.rename: 481 passed (5 files)
  • npm run build clean (tsc OK, eslint 0 errors)
  • CI on this PR: Lint / CodeQL / Tests on ubuntu + macos + windows all green, which partially compensates the "not tested on Windows" note at the unit level (manual Windows verification still pending). The failing review-pr job is the review-automation workflow, not a build/test check.

Interactive verification matrix (real TUI, real model)

# Scenario Result
1 Command registration — popup shows cd <path> with description and argument hint
2 /cd (no args) → Usage: /cd <path>
3 /cd /nonexistent-dir-xyzCouldn't find a directory at …
4 /cd marker-a.txt (a file) → … is not a directory.
5 /cd .Already in … (realpath-normalized; macOS /tmp/private/tmp handled correctly)
6 Path completion — /cd ../ suggests only directories (../proj-a/, ../proj-b/)
7 /cd ../proj-b (relative path) → Moved to /private/tmp/cd-test/proj-b.
8 Active session artifacts (<id>.jsonl + <id>.runtime.json) moved to the destination workspace chats/ dir; non-active sessions stayed behind in the old workspace
9 Model side after cd — directory-change note visible to the model ("startup directory context above is stale … now resolve from …"), ListFiles . resolves in the new cwd, and project QWEN.md is re-loaded (reply prefix flipped [PROJ-A][PROJ-B])
10 /directory show → workspace root fully replaced, no stale old root
11 /cd ~ → tilde expands to home
12 folderTrust enabled, untrusted target → confirmation dialog with the expected wording; NoOperation cancelled. and stays put; Yes → moved and trustedFolders.json gains the TRUST_FOLDER entry
13 /cd typed while the model is streaming → held in the input queue and executed after the turn finishes; no mid-stream relocation
14 Round-trip a → b → a then restart with --continue → relocated transcript resumes fully, conversation context intact (model recalls earlier content), and the current dir's QWEN.md is the one loaded after resume (verified by asking the model to quote it)
15 Quoted path with spaces — /cd "../dir with space" → parsed, trust-confirmed, moved; artifacts migrated into the sanitized storage dir (…-dir-with-space)

Observations (non-blocking)

  1. While a response is streaming, /cd is intercepted by the input queue ("Press ↑ to edit queued messages") and runs once idle, so the in-command isIdleRef guard acts as a second line of defense for normal typing. Behavior is sane either way.
  2. After resuming a relocated session, the model can keep imitating the previous project's reply style present in transcript history (cosmetic; the loaded QWEN.md was verified to be the current directory's).
  3. Debug logs from the whole run contain no relocation-related errors (the only stack traces were provider-side title-generation 400s, reproducible independently of /cd).

Verdict: runtime behavior matches the PR description on macOS — error paths, trust flow, session migration, context refresh, completion, and resume-after-relocation all work as advertised in real usage.

@wenshao
wenshao merged commit 2cfa32f into QwenLM:main Jun 12, 2026
27 of 28 checks passed
doudouOUC pushed a commit that referenced this pull request Jun 15, 2026
* feat(cli): add /cd command

* fix(cli): stabilize cd command checks

* fix(cli): cap pending cd trust confirmations

* fix(core): allow resuming migrated cd sessions

* test(core): fix cd relocation path expectations

* fix(core): accept migrated sessions in all project checks

* fix(core): preserve runtime workspace dirs on cd

* fix(cli): keep branched relocated sessions loadable

---------

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

type/feature-request New feature or enhancement request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add /cd command to move the current session working directory

5 participants