Skip to content

feat: CLI update command (PR-I2 of 2-PR sequence)#290

Merged
HumanBean17 merged 3 commits into
masterfrom
worktree-pr-i2-update-subcommand
Jun 8, 2026
Merged

feat: CLI update command (PR-I2 of 2-PR sequence)#290
HumanBean17 merged 3 commits into
masterfrom
worktree-pr-i2-update-subcommand

Conversation

@HumanBean17

Copy link
Copy Markdown
Owner

Summary

Implements the update subcommand that refreshes shipped artifacts (skill, agent, MCP entry) after pip upgrade.

Features

  • Host detection: Scans project + user config files for java-codebase-rag MCP entries
  • Artifact refresh: Overwrites skill/agent files from package data, updates MCP command path
  • Index update: Runs incremental LanceDB update if index exists
  • Dry-run mode: Previews changes without writing files

Changes

  • Add detect_configured_hosts() function to scan for configured hosts
  • Add refresh_artifacts() function to refresh skill, agent, and MCP files
  • Add run_update() orchestrator for the update pipeline
  • Add update subcommand to CLI with --force and --dry-run flags
  • Add 12 new tests for update functionality

Test plan

  • All 12 new tests pass
  • Existing test suite passes
  • ruff check . is clean
  • update --help prints usage
  • update after install completes with exit 0
  • update --dry-run reports what would change without writing
  • update with no configured hosts exits with code 2

Part of

This implements PR-I2 from plans/active/PLAN-CLI-INSTALL.md.

🤖 Generated with Claude Code

HumanBean17 and others added 2 commits June 8, 2026 09:49
Implements the `update` subcommand that refreshes shipped artifacts
(skill, agent, MCP entry) after pip upgrade.

Features:
- Host detection: scans project + user config files for java-codebase-rag MCP entries
- Artifact refresh: overwrites skill/agent files from package data, updates MCP command path
- Index update: runs incremental LanceDB update if index exists
- Dry-run mode: previews changes without writing files

Changes:
- Add `detect_configured_hosts()` function to scan for configured hosts
- Add `refresh_artifacts()` function to refresh skill, agent, and MCP files
- Add `run_update()` orchestrator for the update pipeline
- Add `update` subcommand to CLI with --force and --dry-run flags
- Add 12 new tests for update functionality

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Add MCP server name constant (_MCP_SERVER_NAME) to replace hardcoded strings
- Add exit code constants (EXIT_SUCCESS, EXIT_PARTIAL, EXIT_FATAL)
- Remove duplicate _INCREMENT_WARNING_LINES, import from cli.py instead

These changes address code quality issues identified during review:
- Eliminate stringly-typed code with constants
- Reduce duplication by sharing constants across modules
- Improve maintainability with named exit codes

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@HumanBean17

Copy link
Copy Markdown
Owner Author

Review: PR-I2

Tests pass (65/65), ruff is clean, and the scope matches the plan. A few issues to address:

Critical

SystemExit leaks through _refresh_mcp_config (installer.py:1020)

resolve_mcp_command(non_interactive=True) raises SystemExit(2) when the binary isn't on PATH. SystemExit inherits from BaseException, so the outer except Exception as e at line 1095 won't catch it. If java-codebase-rag-mcp isn't on PATH, the entire update command aborts with a bare exit 2 instead of returning a graceful ArtifactResult failure.

Fix: catch SystemExit explicitly, or resolve the command path before calling _refresh_mcp_config and pass it in (like merge_mcp_config takes mcp_command as a parameter).

Important

Duplication between _refresh_mcp_config and merge_mcp_config (installer.py:1000-1096 vs 420-465)

The JSON read / compare / atomic-write logic is nearly identical. The only real differences are the force/dry_run branching and the return type (ArtifactResult vs bool). Consider factoring the shared write-atomic logic into a common helper, or having _refresh_mcp_config call merge_mcp_config internally and wrap its result.

run_update swallows partial failures (installer.py:1152-1172)

If some artifacts failed to refresh (warnings printed at lines 1137-1141), but the function then hits an early return at line 1155, 1164, or 1172, it returns 0 despite partial failures. The exit code should reflect partial failure (1) when any artifact failed.

Minor

  • EXIT_* constants unused (installer.py:33-35): the refactor added EXIT_SUCCESS/EXIT_PARTIAL/EXIT_FATAL but run_update uses raw 0/1/2 literals. Either use them or remove them.
  • test_update_no_index_skips_increment sets up fake_stdout but never asserts on the captured output.
  • No test for missing java-codebase-rag-mcp binary inside _refresh_mcp_config — the most interesting edge case for the update flow.

Verdict

Fix the SystemExit leak before merge. Items 2-3 are worth addressing here too. Items 4-6 are optional polish.

Critical:
- Fix SystemExit leak in _refresh_mcp_config: catch SystemExit from resolve_mcp_command and return ArtifactResult instead of crashing
- Add outer SystemExit handler for robustness

Important:
- Fix run_update partial failure handling: return exit code 1 when any artifact refresh fails, instead of returning 0
- Track has_artifact_failures and use it in all early returns

New Test:
- Add test_update_missing_mcp_binary_returns_partial_failure to verify MCP binary missing case

Also:
- Use EXIT_* constants consistently instead of raw 0/1/2 literals

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@HumanBean17 HumanBean17 merged commit 017bd12 into master Jun 8, 2026
1 check passed
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