Skip to content

feat(parsers): add Command Code CLI session support#76

Open
abhinay-hat wants to merge 2 commits into
yigitkonur:mainfrom
abhinay-hat:feat/command-code-parser
Open

feat(parsers): add Command Code CLI session support#76
abhinay-hat wants to merge 2 commits into
yigitkonur:mainfrom
abhinay-hat:feat/command-code-parser

Conversation

@abhinay-hat

@abhinay-hat abhinay-hat commented Jun 11, 2026

Copy link
Copy Markdown

Add command-code (npm i -g command-code) as 17th supported tool. Discovers sessions from ~/.commandcode/projects/, extracts
messages and tool activity. 984 tests pass, TypeScript builds clean.


Open in Devin Review

Summary by cubic

Adds command-code CLI session support as the 17th tool. Sessions are discovered from ~/.commandcode/projects/, user/assistant messages are extracted cleanly, and tool activity is summarized for handoffs.

  • New Features

    • Discovers sessions at ~/.commandcode/projects//.jsonl and reads .meta.json for title/model.
    • Extracts user/assistant text by joining text blocks; skips reasoning and tool-call/result blocks.
    • Summarizes shell_command and file read/write calls via the SummaryCollector.
    • Registers adapter command-code with binary cmdc (fallbacks: cmd, command-code, commandcode), native resume --resume <id>, and COMMAND_CODE_HOME override.
    • Adds fixtures and unit/E2E tests; updates TOOL_NAMES to 17.
  • Migration

    • Install command-code globally: npm i -g command-code. Sessions in ~/.commandcode/projects/ will be auto-detected.
    • Optionally set COMMAND_CODE_HOME. Resume with cmdc --resume <id>.

Written for commit 4bb5328. Summary will update on new commits.

Review in cubic

abhinay-hat and others added 2 commits June 11, 2026 15:51
Adds command-code (npm i -g command-code) as the 17th supported tool.
Discovers sessions from ~/.commandcode/projects/<cwd-slug>/<uuid>.jsonl,
reads title/model from <uuid>.meta.json, extracts user/assistant messages
by joining text content blocks (skipping reasoning/tool-call/tool-result),
and summarizes shell_command and file tool calls via SummaryCollector.

Registry: binaryName=cmdc, fallbacks=[cmd,command-code,commandcode],
native resume via --resume <session-id>.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Devin Review found 6 potential issues.

Open in Devin Review

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📝 Info: New parser follows all 5 required checklist items for adding a new tool

Verified against the AGENTS.md checklist:

  1. ✅ Tool name added to TOOL_NAMES in src/types/tool-names.ts:24
  2. ✅ Parser file created at src/parsers/command-code.ts with both required exports
  3. ✅ Registered in src/parsers/registry.ts:944-957
  4. ✅ Fixture factory createCommandCodeFixture() added in src/__tests__/fixtures/index.ts:1293
  5. ✅ Conversion tests added in src/__tests__/unit-conversions.test.ts

The implementation is consistent with existing parsers like qwen-code.ts in structure.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment thread src/parsers/registry.ts
storagePath: '~/.commandcode/projects/*/',
envVar: 'COMMAND_CODE_HOME',
binaryName: 'cmdc',
binaryFallbacks: ['cmd', 'command-code', 'commandcode'],

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔴 cmd in binaryFallbacks resolves to Windows Command Prompt, causing incorrect tool detection and execution

The binaryFallbacks array includes 'cmd' as a fallback binary name (src/parsers/registry.ts:951). On Windows, cmd always resolves to cmd.exe (the Windows Command Prompt), which means:

  1. resolveToolBinaryName('command-code') at src/utils/resume.ts:313 will find cmd via which/where and return it as the resolved binary, even when Command Code is not installed.
  2. getAvailableTools() will incorrectly report command-code as available on all Windows systems.
  3. Cross-tool handoff will invoke cmd.exe /c cmd <handoff_prompt> (via runCommand at src/utils/resume.ts:276), passing the full handoff markdown prompt through the Windows command interpreter instead of the intended tool.

This affects any Windows user who doesn't have cmdc installed — the tool appears available but executes against the wrong binary.

Suggested change
binaryFallbacks: ['cmd', 'command-code', 'commandcode'],
binaryFallbacks: ['command-code', 'commandcode'],
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines +57 to +65
export async function parseCommandCodeSessions(): Promise<UnifiedSession[]> {
const sessions: UnifiedSession[] = [];

let projectDirs: string[];
try {
projectDirs = listSubdirectories(PROJECTS_DIR);
} catch {
return sessions;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📝 Info: Parser correctly uses async streaming JSONL helpers instead of readFileSync

The command-code parser uses scanJsonlFile from src/utils/jsonl.ts for reading JSONL data (lines 91 and 137), and fsp.readFile (node:fs/promises) for the small meta.json file. This complies with the REVIEW.md rule against fs.readFileSync in parser code. The listSubdirectories call at line 62 does use synchronous fs.readdirSync internally, but this is the same shared helper used by gemini, copilot, kiro, qwen-code, and opencode parsers — it's an accepted pre-existing pattern for directory listing (the REVIEW.md rule specifically mentions readFileSync/writeFileSync, not readdirSync).

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines +75 to +77
} catch {
continue;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📝 Info: Catch blocks have non-empty bodies but lack logger.debug calls

The catch blocks at lines 44, 63, and 75 swallow errors silently without calling logger.debug. While the REVIEW.md convention recommends logger.debug in catch blocks, these blocks are not technically empty (they have return/continue statements) so they won't trigger Biome's noEmptyBlockStatements error. This same pattern exists in other parsers like qwen-code.ts:491 (catch { continue; }) and kimi.ts:158 (catch { return undefined; }). However, adding logger.debug would improve debuggability — especially at line 75 where directory read failures are silently skipped during session discovery.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines +14 to +16
const COMMAND_CODE_HOME =
process.env.COMMAND_CODE_HOME ?? path.join(homeDir(), '.commandcode');
const PROJECTS_DIR = path.join(COMMAND_CODE_HOME, 'projects');

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📝 Info: COMMAND_CODE_HOME evaluated at module load time — consistent with other parsers

The COMMAND_CODE_HOME and PROJECTS_DIR constants are computed at module-load time (lines 14-16). This means if the environment variable changes after import, the change won't be reflected. This is the same pattern used by other parsers (e.g., qwen-code, kimi) and is acceptable since the CLI is a short-lived process. The envVar: 'COMMAND_CODE_HOME' in the registry entry correctly declares this for cache invalidation purposes.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

} else {
const filePath = (input.path ?? input.file_path ?? input.filePath ?? '') as string;
if (filePath) {
const isWrite = /write|edit|patch|create/i.test(toolName);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📝 Info: Tool classification uses regex on toolName which may miss edge cases

At line 163, /write|edit|patch|create/i.test(toolName) classifies tools as write operations. This regex could match tool names containing these substrings unexpectedly (e.g., a hypothetical read_created_at tool would be classified as write). However, this is a reasonable heuristic for an unknown tool's operations and matches the defensive approach used elsewhere in the codebase. The read_file tool wouldn't match because read isn't in the regex.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant