Skip to content

feat!: modernize CLI with subcommand structure (v2.0.0)#53

Merged
frankbria merged 1 commit intomainfrom
feature/subcommand-cli-refactor
Feb 3, 2026
Merged

feat!: modernize CLI with subcommand structure (v2.0.0)#53
frankbria merged 1 commit intomainfrom
feature/subcommand-cli-refactor

Conversation

@frankbria
Copy link
Owner

@frankbria frankbria commented Feb 3, 2026

Summary

  • Refactor CLI from hyphenated commands to modern subcommand structure
  • Maintain backward compatibility with deprecation warnings
  • Bump version to 2.0.0 (breaking change)

Command Changes

Old (Deprecated) New
mcp-serve mcp serve
watch-merges watch merges
merge-status merge status
sandbox-run sandbox run
sandbox-logs sandbox logs
sandbox-download sandbox download
sandbox-kill sandbox kill
sandbox-list sandbox list
sandbox-status sandbox status

Backward Compatibility

Old commands still work but show deprecation warnings:

⚠ Warning: "merge-status" is deprecated
  Use "merge status" instead
  The old command will be removed in v3.0.0

Implementation Details

  • Created parent command groups (mcp, watch, merge, sandbox) using Commander.js
  • Extracted action handlers into shared functions to avoid code duplication
  • Added cli-deprecation.ts helper module for deprecation warnings
  • Added 28 new tests covering subcommand structure and backward compatibility

Test plan

  • All 28 new CLI subcommand tests pass
  • Full test suite (1006 tests) passes
  • New subcommand syntax works (parallel-cc sandbox run --help)
  • Old commands show deprecation warnings when executed
  • Version reports 2.0.0

Summary by CodeRabbit

  • New Features

    • CLI restructured to subcommand form (mcp, watch, merge, sandbox, templates, config, budget) with new sandbox subcommands (run, logs, download, kill, list, status) and consolidated merge/watch flows.
    • Deprecation warnings and aliases added for legacy hyphenated commands.
  • Tests

    • Added comprehensive CLI tests validating new subcommand help, behavior, backward compatibility, and version reporting.
  • Documentation

    • Docs updated to reflect v2.0.0 changes and deprecation notes.
  • Chores

    • Version bumped from 1.0.0 to 2.0.0.

@coderabbitai
Copy link

coderabbitai bot commented Feb 3, 2026

Walkthrough

CLI reorganized from hyphenated commands to subcommands (e.g., mcp serve, watch merges); package version bumped to 2.0.0; new deprecation helpers added to emit warnings for legacy hyphenated commands; tests added to validate subcommand surface and backward compatibility.

Changes

Cohort / File(s) Summary
Version and Docs
package.json, CLAUDE.md
Bump version 1.0.0 → 2.0.0; documentation updated to describe subcommand syntax and deprecation notes.
Deprecation Helpers
src/cli-deprecation.ts
New public module exporting showDeprecationWarning(oldCmd, newCmd) and DEPRECATED_COMMANDS mapping; emits colored stderr warnings about removal in v3.0.0.
CLI Core
src/cli.ts
Major refactor introducing grouped subcommands (mcp, watch, merge, sandbox) with new handler functions (e.g., handleSandboxRun, handleWatchMerges); legacy hyphenated commands registered as deprecated aliases that call new handlers and emit warnings; added JSON output paths.
Tests
tests/cli-subcommands.test.ts
New vitest suite exercising new subcommand help/behavior, deprecated command warnings, and version reporting (2.0.0).

Sequence Diagrams

sequenceDiagram
    participant User
    participant CLI as CLI Parser
    participant Dep as Deprecation Check
    participant Handler as Command Handler
    participant Out as Output (stdout/stderr)

    User->>CLI: Invoke command (e.g., "mcp-serve" or "mcp serve")
    CLI->>Dep: Check DEPRECATED_COMMANDS
    alt deprecated
        Dep->>Out: showDeprecationWarning(old,new)
        Dep->>Handler: Route to new handler
    else not deprecated
        CLI->>Handler: Dispatch to handler
    end
    Handler->>Out: Return result (JSON/text)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

🐰 I hop through code and softly sing,
Hyphens leap to spaces with a spring,
Warnings whisper what will go away,
New handlers guide the CLI's play,
Version two hops on its merry way. 🥕

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat!: modernize CLI with subcommand structure (v2.0.0)' directly and clearly summarizes the main change: refactoring the CLI to use subcommands and bumping to v2.0.0.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/subcommand-cli-refactor

Comment @coderabbitai help to get the list of available commands and usage tips.

@frankbria frankbria linked an issue Feb 3, 2026 that may be closed by this pull request
@github-actions
Copy link

github-actions bot commented Feb 3, 2026

Review Summary

This is a well-executed CLI modernization that transitions from hyphenated commands to a proper subcommand structure. The changes follow good software engineering practices and maintain backward compatibility through deprecation warnings.

✅ Strengths

  1. Clean Architecture: The refactoring creates logical command groups (, , , , , , ) that align with modern CLI conventions
  2. Backward Compatibility: All old commands remain functional with clear deprecation warnings that redirect users to new syntax
  3. Code Reuse: Shared handler functions (, , , etc.) eliminate duplication between old/new commands
  4. Comprehensive Tests: 28 new tests verify subcommand structure, backward compatibility, and command option preservation
  5. Clear Deprecation Path: Warnings specify v3.0.0 as removal target, giving users time to migrate

🔍 Minor Observations

  1. Version Bump: The jump from v0.5.0 to v2.0.0 is appropriate given this is a breaking change to command syntax, though the core functionality remains the same

  2. Deprecation Module: The new module is clean and well-documented. The mapping provides a single source of truth for command translations

  3. One Small Inconsistency: Lines 3552-3557 show as a "backward compatibility alias" rather than a deprecated command (different from the pattern used for , , etc.). This doesn't show a deprecation warning - it's just an alias. Consider making this consistent with other deprecated commands for v3.0.0 removal

  4. Test Coverage: Tests verify help output and command structure but don't validate actual command execution behavior with real options. This is acceptable given the scope (CLI structure change), but future tests could verify end-to-end command execution

🎯 Recommendations

  1. Consider adding a migration guide in CLAUDE.md or README.md to help users transition from old to new command syntax

  2. **Consistency on **: Either show a deprecation warning for or document explicitly that it's a permanent alias (not deprecated)

  3. Documentation Update: The CLAUDE.md changes (lines 52-42) are thorough and reflect the new command structure well

Summary

This is a solid, production-ready refactoring that improves CLI ergonomics while respecting existing users. The code is clean, well-tested, and follows the project's conventions. The deprecation warnings are user-friendly and informative.

Status: ✅ Approve with minor suggestions

@macroscopeapp
Copy link
Contributor

macroscopeapp bot commented Feb 3, 2026

Modernize the parallel-cc CLI to v2.0.0 by introducing subcommand groups (mcp serve, watch merges, merge status, sandbox *) and deprecating hyphenated commands with warnings for removal in v3.0.0

Introduce grouped subcommands across MCP, watch, merge, and sandbox, add deprecation warnings for legacy hyphenated commands via cli-deprecation.showDeprecationWarning, and update version reporting to 2.0.0. Documentation and tests are updated to reflect the new syntax.

📍Where to Start

Start with command definitions and deprecation handling in cli.ts, then review the warning utility and mapping in cli-deprecation.ts.


Macroscope summarized 378d332.

@github-actions
Copy link

github-actions bot commented Feb 3, 2026

I've posted a comprehensive review of PR #53. The comment includes:

  • Strengths: Clean architecture, backward compatibility, code reuse, comprehensive tests, and clear deprecation path
  • Minor observations: Version bump appropriateness, clean deprecation module, a small inconsistency with budget-status (treated as alias rather than deprecated command), and test coverage notes
  • Recommendations: Add a migration guide, make budget-status consistent with other deprecated commands, and the documentation updates are already thorough

The PR is production-ready and modernizes the CLI structure while respecting existing users through deprecation warnings.

Overall Status: ✅ Approve with minor suggestions

New%20session%20-%202026-02-03T07%3A03%3A56.186Z
opencode session  |  github run

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
CLAUDE.md (1)

988-993: ⚠️ Potential issue | 🟡 Minor

Minor inconsistency in coding standards section.

The coding standards section states "Use hyphens only when it makes sense semantically (e.g., sandbox-run as a single action)" — but sandbox-run is now deprecated in favor of sandbox run. Consider updating this example to avoid confusion.

📝 Suggested fix
 Prefer proper subcommands over hyphenated command names:
 - **Preferred:** `parallel-cc templates list`, `parallel-cc templates show <name>`
 - **Avoid:** `parallel-cc templates-list`, `parallel-cc templates-show <name>`
 
-Use hyphens only when it makes sense semantically (e.g., `sandbox-run` as a single action) or to maintain backward compatibility with existing commands.
+Hyphenated commands like `sandbox-run` are deprecated and maintained only for backward compatibility; prefer subcommands like `sandbox run`.
src/cli.ts (1)

2004-2009: ⚠️ Potential issue | 🟡 Minor

Outdated command reference in dry-run output.

The dry-run message still references the deprecated hyphenated command sandbox-kill instead of the new subcommand syntax sandbox kill.

📝 Proposed fix
       if (!options.json) {
         console.log(chalk.yellow('\n✓ DRY RUN complete - skipping execution'));
         console.log(chalk.dim('  Sandbox will remain active for inspection'));
-        console.log(chalk.dim(`  Use: parallel-cc sandbox-kill --session-id ${sessionId}`));
+        console.log(chalk.dim(`  Use: parallel-cc sandbox kill --session-id ${sessionId}`));
       }
🧹 Nitpick comments (1)
tests/cli-subcommands.test.ts (1)

13-18: Remove unused imports.

Command from 'commander', fs, and os are imported but never used in this test file.

🧹 Proposed fix
 import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
-import { Command } from 'commander';
 import { execSync, spawnSync } from 'child_process';
 import * as path from 'path';
-import * as fs from 'fs';
-import * as os from 'os';

BREAKING CHANGE: Commands now use subcommand syntax instead of hyphens.
Old hyphenated commands are deprecated and will be removed in v3.0.0.

Command changes:
- mcp-serve → mcp serve
- watch-merges → watch merges
- merge-status → merge status
- sandbox-run → sandbox run
- sandbox-logs → sandbox logs
- sandbox-download → sandbox download
- sandbox-kill → sandbox kill
- sandbox-list → sandbox list
- sandbox-status → sandbox status

Implementation:
- Add parent command groups (mcp, watch, merge, sandbox)
- Extract action handlers into shared functions for code reuse
- Keep deprecated commands with warnings pointing to new syntax
- Add cli-deprecation.ts helper module
- Add 28 new tests for CLI subcommand structure
- Update version to 2.0.0
- Update CLAUDE.md documentation
@frankbria frankbria force-pushed the feature/subcommand-cli-refactor branch from b0b790d to 378d332 Compare February 3, 2026 07:09
Comment on lines +2612 to +2613
// Terminate sandbox
const termResult = await sandboxManager.terminateSandbox(session.sandbox_id);
Copy link
Contributor

Choose a reason for hiding this comment

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

🟡 Medium

src/cli.ts:2612

terminateSandbox returns { success: false } when the sandbox isn't in activeSandboxes. Since the SandboxManager is newly instantiated, the map is empty. Consider calling getOrReconnectSandbox before terminateSandbox to populate the map.

-    // Terminate sandbox
-    const termResult = await sandboxManager.terminateSandbox(session.sandbox_id);
+    // Reconnect to sandbox before termination
+    const sandbox = await sandboxManager.getOrReconnectSandbox(session.sandbox_id);
+    if (!sandbox) {
+      const error = 'Failed to connect to sandbox (may have been terminated)';
+      if (options.json) {
+        console.log(JSON.stringify({ success: false, error }));
+      } else {
+        console.error(chalk.red(`✗ ${error}`));
+      }
+      process.exit(1);
+    }
+
+    // Terminate sandbox
+    const termResult = await sandboxManager.terminateSandbox(session.sandbox_id);

🚀 Want me to fix this? Reply ex: "fix it for me".

} else {
console.error(chalk.red(`✗ Session not found: ${sessionId}`));
}
process.exit(1);
Copy link
Contributor

Choose a reason for hiding this comment

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

🟢 Low

src/cli.ts:2605

Avoid calling process.exit(...) inside error paths; it skips finally and prevents cleanup (e.g., coordinator.close() and tarball removal). Suggest throwing or storing an exit code, let finally run cleanup, then call process.exit(...) afterward.

🚀 Want me to fix this? Reply ex: "fix it for me".

await fs.mkdir(options.output, { recursive: true });

// Download files
const downloadResult = await downloadChangedFiles(sandbox, '/workspace', options.output);
Copy link
Contributor

Choose a reason for hiding this comment

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

🟡 Medium

src/cli.ts:2518

Consider resolving options.output to an absolute path before passing to downloadChangedFiles, since validatePath requires absolute paths. Relative paths like ./downloads will fail.

Suggested change
const downloadResult = await downloadChangedFiles(sandbox, '/workspace', options.output);
const downloadResult = await downloadChangedFiles(sandbox, '/workspace', path.resolve(options.output));

🚀 Want me to fix this? Reply ex: "fix it for me".

@github-actions
Copy link

github-actions bot commented Feb 3, 2026

Review Summary

This is a well-executed CLI modernization that transitions from hyphenated commands to a proper subcommand structure. The implementation follows good software engineering practices and maintains backward compatibility through deprecation warnings.

✅ Strengths

  1. Clean Architecture: The refactoring creates logical command groups (mcp, watch, merge, sandbox) that align with modern CLI conventions and improve discoverability
  2. Backward Compatibility: All old commands remain functional with clear deprecation warnings that redirect users to new syntax
  3. Code Reuse: Shared handler functions (handleWatchMerges, handleMergeStatus, handleSandboxRun, etc.) eliminate duplication between old/new commands
  4. Comprehensive Tests: 28 new tests verify subcommand structure, backward compatibility, deprecation warnings, and command option preservation
  5. Clear Deprecation Path: Warnings specify v3.0.0 as removal target, giving users time to migrate
  6. Version Bump: Jump to 2.0.0 is appropriate given the breaking change to command syntax

🔍 Minor Issues Found

  1. Inconsistent treatment of budget-status (cli.ts:3551-3557)

    • budget-status is documented as a "backward compatibility alias" rather than a deprecated command
    • Unlike other hyphenated commands, it doesn't show a deprecation warning
    • Not listed in DEPRECATED_COMMANDS mapping in cli-deprecation.ts
    • Recommendation: Either:
      • Add deprecation warning for consistency, OR
      • Document explicitly that this is a permanent alias (not deprecated)
  2. Outdated reference in dry-run output (cli.ts:2004-2009)

    • The dry-run message still references the deprecated sandbox-kill command
    • Should use new sandbox kill syntax
    • console.log(chalk.dim( Use: parallel-cc sandbox-kill --session-id ${sessionId}));
    • Should be: console.log(chalk.dim( Use: parallel-cc sandbox kill --session-id ${sessionId}));
  3. Unused imports in test file (tests/cli-subcommands.test.ts:13-18)

    • Command from 'commander', fs, and os are imported but never used
    • Minor cleanup opportunity
  4. Documentation example (CLAUDE.md:988-993)

    • Coding standards section mentions sandbox-run as an example of hyphenated commands
    • This command is now deprecated
    • Could confuse readers

🎯 Recommendations

  1. Add a migration guide in CLAUDE.md or README.md to help users transition from old to new command syntax
  2. Decide on budget-status: Make it either a deprecated command (with warning) or a permanent alias (documented as such)
  3. Fix the dry-run message to use new subcommand syntax
  4. Clean up unused test imports
  5. Update CLAUDE.md example to avoid referencing deprecated commands

Summary

This is a solid, production-ready refactoring that significantly improves CLI ergonomics while respecting existing users. The code is clean, well-tested, and follows the project's conventions. The deprecation warnings are user-friendly and informative.

Status: ✅ Approve with minor suggestions

@github-actions
Copy link

github-actions bot commented Feb 3, 2026

Review comment posted: #53 (comment)

New%20session%20-%202026-02-03T07%3A10%3A04.126Z
opencode session  |  github run

console.error(chalk.red(`✗ Failed to list sessions: ${errorMessage}`));
}
});
process.exit(1);
Copy link
Contributor

Choose a reason for hiding this comment

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

🟢 Low

src/cli.ts:2729

Calling process.exit() inside try/catch prevents finally from running, leaking resources (e.g., coordinator.close(), tarball cleanup). Suggest centralizing exit: throw errors or store an exitCode and call process.exit() once after finally (or at the top level).

🚀 Want me to fix this? Reply ex: "fix it for me".

@frankbria frankbria merged commit 15b5d23 into main Feb 3, 2026
8 checks passed
@frankbria frankbria deleted the feature/subcommand-cli-refactor branch February 3, 2026 07:15
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.

Change CLI from hyphenated commands to subcommands

1 participant