feat: add install command detection to worktree creation
After creating a worktree, detect the project type and suggest the appropriate install command: - Node.js: bun/pnpm/yarn/npm based on lock file - Python: uv/poetry/pip based on lock file - Rust: cargo build - Go: go mod download - Generic: Makefile Custom scripts/setup-worktree.sh takes precedence over auto-detection. Ported from coherence-mcp. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
19602c632b
commit
1afdd05ea6
1 changed files with 105 additions and 2 deletions
|
|
@ -7,11 +7,79 @@
|
|||
//! - Branch: `feature-description` (number prefix stripped)
|
||||
//! - Worktree: `feature-description`
|
||||
|
||||
use std::path::Path;
|
||||
|
||||
use blue_core::{DocType, ProjectState, Worktree as StoreWorktree};
|
||||
use serde_json::{json, Value};
|
||||
|
||||
use crate::error::ServerError;
|
||||
|
||||
/// Detect the appropriate install command for a project
|
||||
///
|
||||
/// Checks for package manager lock files and project files in priority order.
|
||||
/// Returns None if a setup script exists (takes precedence) or no package manager detected.
|
||||
fn detect_install_command(path: &Path) -> Option<String> {
|
||||
// Custom setup script takes precedence
|
||||
if path.join("scripts/setup-worktree.sh").exists() {
|
||||
return None;
|
||||
}
|
||||
|
||||
// Node.js - check lock files for package manager
|
||||
if path.join("package.json").exists() {
|
||||
if path.join("bun.lockb").exists() {
|
||||
return Some("bun install".into());
|
||||
}
|
||||
if path.join("pnpm-lock.yaml").exists() {
|
||||
return Some("pnpm install".into());
|
||||
}
|
||||
if path.join("yarn.lock").exists() {
|
||||
return Some("yarn install".into());
|
||||
}
|
||||
return Some("npm install".into());
|
||||
}
|
||||
|
||||
// Python
|
||||
if path.join("pyproject.toml").exists() {
|
||||
if path.join("uv.lock").exists() {
|
||||
return Some("uv sync".into());
|
||||
}
|
||||
if path.join("poetry.lock").exists() {
|
||||
return Some("poetry install".into());
|
||||
}
|
||||
return Some("pip install -e .".into());
|
||||
}
|
||||
if path.join("requirements.txt").exists() {
|
||||
return Some("pip install -r requirements.txt".into());
|
||||
}
|
||||
|
||||
// Rust
|
||||
if path.join("Cargo.toml").exists() {
|
||||
return Some("cargo build".into());
|
||||
}
|
||||
|
||||
// Go
|
||||
if path.join("go.mod").exists() {
|
||||
return Some("go mod download".into());
|
||||
}
|
||||
|
||||
// Generic Makefile
|
||||
if path.join("Makefile").exists() {
|
||||
return Some("make".into());
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
/// Check for a custom setup script
|
||||
fn detect_setup_script(path: &Path) -> Option<String> {
|
||||
let script_path = path.join("scripts/setup-worktree.sh");
|
||||
if script_path.exists() {
|
||||
Some("./scripts/setup-worktree.sh".into())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Strip RFC number prefix from title
|
||||
///
|
||||
/// Converts `0007-consistent-branch-naming` to `consistent-branch-naming`
|
||||
|
|
@ -92,15 +160,50 @@ pub fn handle_create(state: &ProjectState, args: &Value) -> Result<Value, Server
|
|||
let _ = state.store.update_document_status(DocType::Rfc, title, "in-progress");
|
||||
}
|
||||
|
||||
// Detect install command and setup script
|
||||
let install_command = detect_install_command(&worktree_path);
|
||||
let setup_script = detect_setup_script(&worktree_path);
|
||||
|
||||
// Build hint message
|
||||
let setup_hint = if let Some(ref script) = setup_script {
|
||||
format!("Run `{}` to set up.", script)
|
||||
} else if let Some(ref cmd) = install_command {
|
||||
format!("Run `{}` to install dependencies.", cmd)
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
|
||||
let hint = format!(
|
||||
"cd {} to start working. {}",
|
||||
worktree_path.display(),
|
||||
setup_hint
|
||||
);
|
||||
|
||||
Ok(json!({
|
||||
"status": "success",
|
||||
"title": title,
|
||||
"branch": branch_name,
|
||||
"path": worktree_path.display().to_string(),
|
||||
"install_command": install_command,
|
||||
"setup_script": setup_script,
|
||||
"message": blue_core::voice::success(
|
||||
&format!("Created worktree for '{}'", title),
|
||||
Some(&format!("cd {} to start working", worktree_path.display()))
|
||||
)
|
||||
Some(&hint.trim())
|
||||
),
|
||||
"next_action": {
|
||||
"tool": if setup_script.is_some() || install_command.is_some() {
|
||||
"Bash"
|
||||
} else {
|
||||
"blue_rfc_validate"
|
||||
},
|
||||
"hint": if setup_script.is_some() {
|
||||
"Run setup script to configure the worktree"
|
||||
} else if install_command.is_some() {
|
||||
"Install dependencies before starting work"
|
||||
} else {
|
||||
"Check RFC plan progress as you implement"
|
||||
}
|
||||
}
|
||||
}))
|
||||
}
|
||||
Err(e) => Ok(json!({
|
||||
|
|
|
|||
Loading…
Reference in a new issue