feat: CLI install command (PR-I1 of 2-PR sequence)#288
Conversation
This commit implements the `install` subcommand as the first PR in the CLI Install plan. The install command provides an interactive setup wizard that guides users through: 1. Java source detection (Maven/Gradle) 2. Embedding model selection 3. Agent host configuration (claude-code, qwen-code, gigacode) 4. Artifact deployment (MCP config, skill, agent) 5. YAML config generation and .gitignore update Key features: - Interactive prompts via questionary with non-interactive mode - Multi-host support (configure multiple agents in one run) - Re-run detection (updates existing config or fresh start) - Atomic MCP config merge (preserves existing keys) - Package data for skill/agent artifacts Files added: - java_codebase_rag/installer.py: Core installer logic - java_codebase_rag/install_data/: Package data (skill + agent) - tests/test_installer.py: 47 unit tests - tests/test_installer_integration.py: 2 integration tests (behind JAVA_CODEBASE_RAG_RUN_HEAVY) Files modified: - pyproject.toml: Added questionary>=2.0 dependency and package_data - java_codebase_rag/cli.py: Added install subcommand with flags Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- C1: Create .git dir in integration test fixtures so .gitignore assertions pass - I1: Call run_init_if_needed in run_install orchestrator (was missing) - I2: Remove dead code in resolve_model (unreachable non_interactive check) - I4: Fix potential UnboundLocalError in merge_mcp_config exception handler (use tmp_name variable instead of tmp context manager) - M1: Remove unused managed_keys set in generate_yaml_config Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
HumanBean17
left a comment
There was a problem hiding this comment.
Code Review: PR-I1 — CLI install command
Solid implementation overall. The 6-stage pipeline is well-factored, the prompt() helper cleanly abstracts TTY/non-TTY dispatch, atomic MCP writes are good practice, and test coverage is thorough. Three issues worth fixing before merge:
Bugs
1. --model silently ignored in non-interactive mode (installer.py:817)
def resolve_model(model_input: str | None, *, non_interactive: bool) -> str:
if non_interactive or not model_input: # BUG: short-circuits on non_interactive
return "auto"install --non-interactive --model /path/to/model.gguf silently discards the model flag. The condition should check for a provided model before short-circuiting on non_interactive.
2. _deploy_mcp_config ignores merge_mcp_config return value (installer.py:1133)
merge_mcp_config returns False on JSON parse errors, but _deploy_mcp_config always returns success=True. A corrupt .mcp.json or .claude.json is silently treated as a successful deployment. Should propagate the result.
3. Shipped SKILL.md has stale ontology version 16 (install_data/skills/explore-codebase/SKILL.md:457)
The codebase ontology is 17 (ONTOLOGY_VERSION = 17 in ast_java.py:86), but the shipped SKILL.md reads **Ontology: 16**. The original skills/explore-codebase/SKILL.md also says 16 — both need updating to 17.
Design issues
4. Inconsistent SystemExit handling in run_install (installer.py:1459)
resolve_mcp_command can raise SystemExit(2) but isn't wrapped in try/except like detect_java_directories and select_hosts are. The process still exits with code 2, but the pattern is inconsistent.
5. Partial failure detection uses fragile suffix-based check (installer.py:1474-1478)
if all(r.success for r in results if r.path.suffix in [".json", ".yml", ".yaml"]):This determines critical vs non-critical failures by file extension. Consider tagging ArtifactResult with an artifact_type field instead.
6. Shipped artifacts are static copies with no sync mechanism
install_data/ files are copies of repo-root originals. No build step or CI check ensures they stay in sync. An ontology bump or tool description change could drift undetected.
Missing tests vs plan
The plan specifies 54 named tests; implementation has 49 unit + 2 integration. Notable gaps:
| Plan # | Test | Why it matters |
|---|---|---|
| 12 | test_yaml_generation_does_not_write_source_root_or_index_dir |
Guards against config key regression |
| 34 | test_confirm_source_root_interactive_changes_path |
Non-default path flow |
| 35 | test_confirm_source_root_interactive_invalid_path_reprompts |
Re-prompt loop |
| 42, 44-45 | test_resolve_mcp_command_not_found_interactive_* |
Interactive fallback path |
| 50 | test_select_hosts_interactive_all_checked_by_default |
Checkbox default behavior |
The plan contract says: "If you add, drop, or rename tests, update the plan/prompt text in the same change." The plan file hasn't been updated to reflect the drops.
Summary
Fix items 1-3 (bugs), update the plan file for the test drops, and this is ready to merge. Items 4-6 are non-blocking improvements that can be addressed in a follow-up or in PR-I2.
merge_mcp_config now raises ValueError on JSON parse errors instead of returning False, distinguishing real failures from "already up to date" no-ops. _deploy_mcp_config catches ValueError and reports it as a failed artifact. Added test for invalid JSON case. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…gy version) 1. --model no longer silently ignored in non-interactive mode — provided paths are resolved; missing paths fall back to "auto" with a warning. 2. merge_mcp_config IO errors now raise RuntimeError instead of returning False, so _deploy_mcp_config correctly reports failure. 3. Ontology version bumped from 16 to 17 in both shipped and repo-root SKILL.md files. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Hardcoded .venv/bin/python doesn't exist in CI where Python is at /opt/hostedtoolcache/Python/... sys.executable resolves correctly in all environments. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
61daefa to
9b7284b
Compare
update_gitignore skips non-git directories. The subprocess-based integration tests run in a temp copy that lacks .git/, so the .gitignore assertion fails. Create .git/ before running install. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Summary
Implements the
installsubcommand as PR-I1 of the CLI Install plan (plans/active/PLAN-CLI-INSTALL.md) andpropose/active/CLI-INSTALL-PROPOSE.md.The
installcommand provides an interactive 6-stage setup wizard:.gitignoreupdateKey features:
--non-interactive --agent <host>for CI/automationNo ontology bump, no re-index required - This is a CLI/UX feature only.
Files Changed
New files
java_codebase_rag/installer.py- Core installer logic (920 lines)java_codebase_rag/install_data/- Package data for skill + agent artifactstests/test_installer.py- 47 unit tests covering all stagestests/test_installer_integration.py- 2 integration tests (gated behind JAVA_CODEBASE_RAG_RUN_HEAVY)Modified
pyproject.toml- Addedquestionary>=2.0dependency and package_data configurationjava_codebase_rag/cli.py- Added install subcommand with--non-interactive,--agent,--scope,--modelflagsTest Plan
install --non-interactive --agent claude-codecompletes on bank-chat fixture (exit 0)install --non-interactive --agent claude-code --agent qwen-codemulti-host completes (exit 0)Integration tests are behind
JAVA_CODEBASE_RAG_RUN_HEAVY=1(same as other e2e tests pertests/README.md).Usage Examples
Dependencies
questionary>=2.0for interactive promptscli_format.pyandcli_progress.pyfor display)Next Steps
PR-I2 will implement the
updatesubcommand to refresh shipped artifacts afterpip install --upgrade.Co-Authored-By: Claude Opus 4.7 noreply@anthropic.com