feat(sidebar): include the session directory in the copied resume command#221
feat(sidebar): include the session directory in the copied resume command#2211fanwang wants to merge 1 commit into
Conversation
…mand "Copy Resume Command" copied `claude --resume <id>`, which resumes in whatever directory the terminal happens to be in — so users had to manually cd into the project first. Prefix the command with `cd "<cwd>"` using the project's resolved path (the encoded project dir is the session's launch cwd), quoted so paths with spaces survive the paste. Falls back to the bare command when the path can't be resolved. The command builder is extracted as a pure, unit-tested helper (buildResumeCommand).
There was a problem hiding this comment.
Code Review
This pull request introduces a helper function buildResumeCommand to automatically change directories to the session's working directory before resuming a Claude Code session, updating the context menu to use this command. The feedback suggests normalizing Windows backslashes to forward slashes to prevent shell syntax errors on cross-platform environments, along with adding a corresponding unit test.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| export function buildResumeCommand(sessionId: string, cwd?: string): string { | ||
| const resume = `claude --resume ${sessionId}`; | ||
| if (!cwd) { | ||
| return resume; | ||
| } | ||
| return `cd "${cwd}" && ${resume}`; | ||
| } |
There was a problem hiding this comment.
When generating shell commands with paths on Windows, backslashes (\) can cause issues when pasted into POSIX-like shells (such as Git Bash, WSL, or macOS/Linux terminals if accessing a cross-mounted drive). Specifically, a trailing backslash (e.g., C:\path\to\project\) will escape the closing double quote (\"), leading to an unclosed quote syntax error in bash/zsh.
Since Windows CMD, PowerShell, and POSIX shells all support forward slashes (/) for directory navigation, we can normalize the path by replacing all backslashes with forward slashes. This ensures the command is robust and cross-platform.
| export function buildResumeCommand(sessionId: string, cwd?: string): string { | |
| const resume = `claude --resume ${sessionId}`; | |
| if (!cwd) { | |
| return resume; | |
| } | |
| return `cd "${cwd}" && ${resume}`; | |
| } | |
| export function buildResumeCommand(sessionId: string, cwd?: string): string { | |
| const resume = `claude --resume ${sessionId}`; | |
| if (!cwd) { | |
| return resume; | |
| } | |
| const normalizedCwd = cwd.replace(/\\/g, '/'); | |
| return `cd "${normalizedCwd}" && ${resume}`; | |
| } |
|
|
||
| it('falls back to the bare command for an empty working directory', () => { | ||
| expect(buildResumeCommand('abc-123', '')).toBe('claude --resume abc-123'); | ||
| }); |
There was a problem hiding this comment.
Add a unit test to verify that Windows backslashes are correctly normalized to forward slashes in the generated command.
it('normalizes Windows backslashes to forward slashes', () => {
expect(buildResumeCommand('abc-123', 'C:\\Users\\me\\project')).toBe(
'cd "C:/Users/me/project" && claude --resume abc-123'
);
});
it('falls back to the bare command for an empty working directory', () => {
expect(buildResumeCommand('abc-123', '')).toBe('claude --resume abc-123');
});
📝 WalkthroughWalkthroughAdds a ChangesResume Command with Project Path
Suggested labels
🚥 Pre-merge checks | ✅ 2✅ Passed checks (2 passed)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
ESLint install failed: private package registry requires authentication. Disable ESLint in CodeRabbit settings or use public packages. 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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
test/renderer/utils/resumeCommand.test.ts (1)
3-3: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winUse the
@rendereralias for this import.Reaching into
srcvia../../../makes the test brittle and sidesteps the repo's import convention.@renderer/utils/resumeCommandkeeps this as a direct file import without coupling the test to directory depth.Suggested change
-import { buildResumeCommand } from '../../../src/renderer/utils/resumeCommand'; +import { buildResumeCommand } from '`@renderer/utils/resumeCommand`';As per coding guidelines, "Use path aliases for imports" and "Renderer utils, hooks, and types should NOT use barrel exports - import directly from specific files."
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@test/renderer/utils/resumeCommand.test.ts` at line 3, The test import is using a brittle relative path instead of the repo’s renderer alias. Update the import in resumeCommand.test.ts to use `@renderer/utils/resumeCommand` directly, matching the import convention for renderer utils and avoiding coupling the test to directory depth.Source: Coding guidelines
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/renderer/utils/resumeCommand.ts`:
- Around line 10-15: The buildResumeCommand helper is inserting both cwd and
sessionId directly into a shell command, which can break on special characters
and allow shell expansion; update buildResumeCommand to use POSIX-safe single
quoting for both arguments before assembling the resume command. Keep the
existing command structure, but ensure the quoted cwd is used in the cd step and
the quoted sessionId is passed to claude --resume.
---
Nitpick comments:
In `@test/renderer/utils/resumeCommand.test.ts`:
- Line 3: The test import is using a brittle relative path instead of the repo’s
renderer alias. Update the import in resumeCommand.test.ts to use
`@renderer/utils/resumeCommand` directly, matching the import convention for
renderer utils and avoiding coupling the test to directory depth.
🪄 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: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 7c366c4f-1b22-4afa-bcb4-759aaf8efd79
📒 Files selected for processing (3)
src/renderer/components/sidebar/SessionContextMenu.tsxsrc/renderer/utils/resumeCommand.tstest/renderer/utils/resumeCommand.test.ts
| export function buildResumeCommand(sessionId: string, cwd?: string): string { | ||
| const resume = `claude --resume ${sessionId}`; | ||
| if (!cwd) { | ||
| return resume; | ||
| } | ||
| return `cd "${cwd}" && ${resume}`; |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '--- file ---\n'
cat -n src/renderer/utils/resumeCommand.ts
printf '\n--- usages ---\n'
rg -n "buildResumeCommand|resumeCommand" src -S
printf '\n--- nearby related helpers ---\n'
rg -n "quote.*Arg|shell|escape.*arg|escape.*shell|cd \"" src/renderer src/main src/shared -SRepository: matt1398/claude-devtools
Length of output: 253
🏁 Script executed:
#!/bin/bash
set -euo pipefail
python3 - <<'PY'
from pathlib import Path
p = Path('src/renderer/utils/resumeCommand.ts')
print(p.read_text())
PYRepository: matt1398/claude-devtools
Length of output: 802
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo '--- usages of buildResumeCommand ---'
rg -n "buildResumeCommand" src -S
echo
echo '--- nearby source for resumeCommand ---'
sed -n '1,120p' src/renderer/utils/resumeCommand.ts
echo
echo '--- sessionId/cwd data sources ---'
rg -n "\bsessionId\b|\bcwd\b" src/renderer src/shared src/main -S | sed -n '1,220p'Repository: matt1398/claude-devtools
Length of output: 24239
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo '--- SessionContextMenu ---'
sed -n '1,220p' src/renderer/components/sidebar/SessionContextMenu.tsx
echo
echo '--- projectPath / cwd provenance ---'
rg -n "projectPath" src/renderer/components/sidebar/SessionContextMenu.tsx src/renderer src/main -S
echo
echo '--- session id definition / shape ---'
rg -n "type .*Session|interface .*Session|id: string;|sessionId: string" src/main/types src/shared/types src/renderer/types -S | sed -n '1,220p'Repository: matt1398/claude-devtools
Length of output: 27534
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo '--- session id parsing/generation ---'
rg -n "sessionId.*(uuid|random|generate|basename|jsonl|id =|id:)|path.basename\\(.*sessionId|extract.*sessionId|session file" src/main src/renderer src/shared -S | sed -n '1,220p'
echo
echo '--- session-related type definitions ---'
sed -n '1,220p' src/main/types/domain.tsRepository: matt1398/claude-devtools
Length of output: 14395
Quote both shell arguments in buildResumeCommand.
cwd is inserted into cd "..." && ..., which still allows shell expansion and breaks on embedded quotes/newlines. sessionId is unquoted too. Use POSIX-safe single quoting before copying the command.
Possible fix for POSIX shells
+function quotePosixArg(value: string): string {
+ return `'${value.replace(/'/g, "'\\''")}'`;
+}
+
export function buildResumeCommand(sessionId: string, cwd?: string): string {
- const resume = `claude --resume ${sessionId}`;
+ const resume = `claude --resume ${quotePosixArg(sessionId)}`;
if (!cwd) {
return resume;
}
- return `cd "${cwd}" && ${resume}`;
+ return `cd ${quotePosixArg(cwd)} && ${resume}`;
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| export function buildResumeCommand(sessionId: string, cwd?: string): string { | |
| const resume = `claude --resume ${sessionId}`; | |
| if (!cwd) { | |
| return resume; | |
| } | |
| return `cd "${cwd}" && ${resume}`; | |
| function quotePosixArg(value: string): string { | |
| return `'${value.replace(/'/g, "'\\''")}'`; | |
| } | |
| export function buildResumeCommand(sessionId: string, cwd?: string): string { | |
| const resume = `claude --resume ${quotePosixArg(sessionId)}`; | |
| if (!cwd) { | |
| return resume; | |
| } | |
| return `cd ${quotePosixArg(cwd)} && ${resume}`; | |
| } |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/renderer/utils/resumeCommand.ts` around lines 10 - 15, The
buildResumeCommand helper is inserting both cwd and sessionId directly into a
shell command, which can break on special characters and allow shell expansion;
update buildResumeCommand to use POSIX-safe single quoting for both arguments
before assembling the resume command. Keep the existing command structure, but
ensure the quoted cwd is used in the cd step and the quoted sessionId is passed
to claude --resume.
Why
The sidebar's "Copy Resume Command" copies
claude --resume <id>. That resumesin whatever directory the terminal happens to be in, so you have to manually
cdinto the project first — the friction #34 set out to remove.What
Prefixes the copied command with
cd "<cwd>", using the project's resolved path(the encoded project directory is the session's launch cwd). The directory is
double-quoted so paths with spaces survive the paste. Falls back to the bare
claude --resume <id>when the path can't be resolved.The command string is built by a small pure helper (
buildResumeCommand), sothe behaviour is unit-tested directly.
Validation
pnpm typecheck,pnpm lint,pnpm test, andpnpm buildare clean. Four newunit tests cover the bare command, the cwd prefix, space-quoting, and the
empty-path fallback.
Note: this touches
SessionContextMenu.tsx, which #215 also edits. The changeis additive (only the resume string plus a store lookup), so it should rebase
cleanly whichever lands first.
Refs #34.
Summary by CodeRabbit