Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 26 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,9 +120,9 @@ Every implementation ends with `dev-reviewer` checking:
```bash
# No clone needed — run directly with bunx or npx:
cd /path/to/your/project
bunx claude-dev-kit@latest
bunx claude-dev-kit@latest install
# or
npx claude-dev-kit@latest
npx claude-dev-kit@latest install
```

Or if you prefer to clone first:
Expand All @@ -132,6 +132,27 @@ git clone https://github.com/evandempsey/claude-dev-kit /tmp/cdk
bash /tmp/cdk/scripts/install.sh /path/to/your/project
```

### CLI subcommands

| Command | Description |
|---------|-------------|
| `claude-dev-kit install [target]` | Full install: copy `.claude/`, hook deps, MCP wizard (default) |
| `claude-dev-kit update [target]` | Migration only — pull new agents/skills/hooks, no prompts |
| `claude-dev-kit mcp [target]` | Run MCP wizard only (add integrations to existing project) |
| `claude-dev-kit version` | Print installed kit version |
| `claude-dev-kit help` | Print usage summary |

```bash
# Update an existing install non-interactively (e.g. in CI)
bunx claude-dev-kit@latest update

# Add/reconfigure MCP integrations only
bunx claude-dev-kit@latest mcp

# Run fully non-interactively (skips all prompts)
CI=true bunx claude-dev-kit@latest install
```

### What the installer does

**Phase 1 — File install:**
Expand Down Expand Up @@ -176,8 +197,8 @@ All MCPs are installed with `--scope project` — they activate only in this pro
### MCP-only install (add integrations to existing project)

```bash
bunx claude-dev-kit@latest --mcp-only
# or
bunx claude-dev-kit@latest mcp
# or (legacy flag still works)
bash /path/to/install.sh --mcp-only
```

Expand Down Expand Up @@ -327,7 +348,7 @@ Some agent packs require additional MCPs or external tooling. They ship dormant

| Pack | Requirement | How to activate |
|------|-------------|------------------|
| **Designer** (`designer` + 4 sub-agents) | Figma MCP | Run `bash scripts/install.sh --mcp-only` and select **Figma** under Design Tools. Or select the **Designer** pack in Phase 1.5 during a fresh install — the installer will auto-prompt for your Figma token. |
| **Designer** (`designer` + 4 sub-agents) | Figma MCP | Run `bunx claude-dev-kit@latest mcp` and select **Figma** under Design Tools. Or select the **Designer** pack in Phase 1.5 during a fresh install — the installer will auto-prompt for your Figma token. |
| **DevOps** *(planned)* | — | Future release. |
| **Data** *(planned)* | — | Future release. |

Expand Down
120 changes: 90 additions & 30 deletions bin/claude-dev-kit.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,47 +4,107 @@
const { spawnSync } = require('child_process');
const path = require('path');
const os = require('os');
const fs = require('fs');

const kitRoot = path.join(__dirname, '..');
const args = process.argv.slice(2);
const argv = process.argv.slice(2);

// ── Non-Windows: always use bash ─────────────────────────────────────────────
if (os.platform() !== 'win32') {
const scriptPath = path.join(kitRoot, 'scripts', 'install.sh');
const result = spawnSync('bash', [scriptPath, ...args], { stdio: 'inherit' });
process.exit(result.status ?? 1);
function printHelp() {
console.log(`
Claude Dev Kit — CLI

Usage:
claude-dev-kit <command> [target] [options]

Commands:
install [target] Full install: copy .claude/, install hook deps, run MCP wizard
update [target] Migration only: pull in new agents/skills/hooks without prompts
mcp [target] Run the MCP wizard only (configure integrations)
version Print the installed kit version
help Print this help summary

Options:
--help Print usage for any subcommand

Environment:
CI=true Run install/update non-interactively (skip all prompts)
TARGET=<path> Alternative to passing target as a positional argument

Examples:
bunx claude-dev-kit@latest install
bunx claude-dev-kit@latest install /path/to/project
bunx claude-dev-kit@latest update
bunx claude-dev-kit@latest mcp
bunx claude-dev-kit@latest version
CI=true bunx claude-dev-kit@latest install
`.trim());
}

// ── Windows: try bash (Git Bash / WSL) first, then PowerShell ────────────────
function hasBash() {
const r = spawnSync('bash', ['--version'], { stdio: 'pipe' });
return r.status === 0;
function printVersion() {
const pkgPath = path.join(kitRoot, 'package.json');
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
console.log(pkg.version);
}

if (hasBash()) {
function runScript(phase, scriptArgs) {
const scriptPath = path.join(kitRoot, 'scripts', 'install.sh');
const result = spawnSync('bash', [scriptPath, ...args], { stdio: 'inherit' });

if (os.platform() !== 'win32') {
const result = spawnSync('bash', [scriptPath, `--phase=${phase}`, ...scriptArgs], { stdio: 'inherit' });
process.exit(result.status ?? 1);
}

// ── Windows: try bash (Git Bash / WSL) first, then PowerShell ──────────────
function hasBash() {
return spawnSync('bash', ['--version'], { stdio: 'pipe' }).status === 0;
}

if (hasBash()) {
const result = spawnSync('bash', [scriptPath, `--phase=${phase}`, ...scriptArgs], { stdio: 'inherit' });
process.exit(result.status ?? 1);
}

// No bash — fall back to PowerShell (install and mcp phases only)
const ps1Path = path.join(kitRoot, 'scripts', 'install.ps1');
const psArgs = ['-ExecutionPolicy', 'Bypass', '-File', ps1Path];
if (phase === 'mcp') psArgs.push('-McpOnly');
for (const arg of scriptArgs) psArgs.push(arg);

const pwsh = spawnSync('pwsh', ['--version'], { stdio: 'pipe' }).status === 0 ? 'pwsh' : 'powershell';
const result = spawnSync(pwsh, psArgs, { stdio: 'inherit' });
process.exit(result.status ?? 1);
}

// No bash — fall back to PowerShell
const ps1Path = path.join(kitRoot, 'scripts', 'install.ps1');

// Translate CLI args to PowerShell param style
// e.g. --mcp-only -> -McpOnly, positional target dir stays positional
const psArgs = ['-ExecutionPolicy', 'Bypass', '-File', ps1Path];
for (const arg of args) {
if (arg === '--mcp-only') {
psArgs.push('-McpOnly');
} else {
psArgs.push(arg);
}
// ── Parse subcommand ──────────────────────────────────────────────────────────
const [subcommand, ...rest] = argv;

if (!subcommand || subcommand === '--help' || subcommand === '-h' || subcommand === 'help') {
printHelp();
process.exit(0);
}

// Prefer pwsh (PowerShell 7+) over legacy powershell.exe (5.x)
const pwsh = spawnSync('pwsh', ['--version'], { stdio: 'pipe' }).status === 0
? 'pwsh'
: 'powershell';
if (subcommand === 'version' || subcommand === '--version' || subcommand === '-v') {
printVersion();
process.exit(0);
}

const result = spawnSync(pwsh, psArgs, { stdio: 'inherit' });
process.exit(result.status ?? 1);
if (rest.includes('--help') || rest.includes('-h')) {
printHelp();
process.exit(0);
}

switch (subcommand) {
case 'install':
runScript('install', rest);
break;
case 'update':
runScript('update', rest);
break;
case 'mcp':
runScript('mcp', rest);
break;
default:
console.error(`Unknown command: ${subcommand}`);
console.error('Run "claude-dev-kit help" for usage.');
process.exit(1);
}
77 changes: 67 additions & 10 deletions scripts/install.sh
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
#!/usr/bin/env bash
# Claude Dev Kit — Installer v2.1
# Claude Dev Kit — Installer v2.2
#
# Copies .claude/ into your project, installs hook deps,
# then runs an MCP wizard to configure Claude's integrations
# (Git platform, ticket system, design tools, code search).
#
# Usage:
# bash install.sh [target-directory]
# bash install.sh [--phase=install|update|mcp] [target-directory]
# TARGET=/path/to/project bash install.sh
# bash install.sh --mcp-only (skip file copy, just configure MCPs)
# bash install.sh --mcp-only (alias for --phase=mcp)

set -euo pipefail

Expand Down Expand Up @@ -101,14 +101,26 @@ mcp_add() {
# ─── Main ─────────────────────────────────────────────────────────────────────
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
KIT_ROOT="$(dirname "$SCRIPT_DIR")"
MCP_ONLY=false

if [[ "${1:-}" == "--mcp-only" ]]; then
MCP_ONLY=true
TARGET="${TARGET:-$(pwd)}"
else
TARGET="${1:-${TARGET:-$(pwd)}}"
fi
# ── Arg parsing: --phase=install|update|mcp, --mcp-only (legacy alias) ───────
PHASE="install"
POSITIONAL_ARGS=()

for arg in "$@"; do
case "$arg" in
--phase=install) PHASE="install" ;;
--phase=update) PHASE="update" ;;
--phase=mcp) PHASE="mcp" ;;
--mcp-only) PHASE="mcp" ;; # backward-compat alias
*) POSITIONAL_ARGS+=("$arg") ;;
esac
done

TARGET="${POSITIONAL_ARGS[0]:-${TARGET:-$(pwd)}}"

# Derive legacy MCP_ONLY for sections that still check it
MCP_ONLY=false
[[ "$PHASE" == "mcp" ]] && MCP_ONLY=true

# Install log — all subprocess output goes here instead of being suppressed
LOG_FILE="$TARGET/.claude/install.log"
Expand All @@ -119,6 +131,51 @@ echo -e "${BOLD}║ Claude Dev Kit — Installer ║${NC}"
echo -e "${BOLD}╚═══════════════════════════════════════╝${NC}"
echo ""

# ─── Phase: update (migration only, non-interactive) ─────────────────────────
if [[ "$PHASE" == "update" ]]; then
header "Update: pulling in latest agents, skills, and hooks"
echo -e " ${DIM}Source: $KIT_ROOT${NC}"
echo -e " ${DIM}Target: $TARGET${NC}"
echo ""

if ! CI=true bash "$SCRIPT_DIR/migrate.sh" "$KIT_ROOT" "$TARGET"; then
error "Migration failed — check output above"
exit 1
fi

# Ensure log file exists now that .claude/ is present
mkdir -p "$TARGET/.claude"
: > "$LOG_FILE"

# Install hook dependencies
HOOK_DIR="$TARGET/.claude/hooks/skill-activation-prompt"
if [[ -f "$HOOK_DIR/package.json" ]]; then
info "Installing skill-activation-prompt hook dependencies..."
pushd "$HOOK_DIR" > /dev/null
if command -v bun &>/dev/null; then
if ! bun install --silent >> "$LOG_FILE" 2>&1; then
warn "bun install failed — see $LOG_FILE for details"
fi
elif command -v npm &>/dev/null; then
if ! npm install --silent >> "$LOG_FILE" 2>&1; then
warn "npm install failed — see $LOG_FILE for details"
fi
else
warn "Neither bun nor npm found. Run manually: cd $HOOK_DIR && npm install"
fi
popd > /dev/null
success "Hook dependencies installed"
fi

echo ""
header "Update Complete"
echo ""
echo -e " ${GREEN}✓${NC} .claude/ updated in $TARGET/.claude"
echo -e " ${DIM} User-customized files were preserved${NC}"
echo ""
exit 0
fi

# ─── Phase 1: File Installation ───────────────────────────────────────────────
if [[ "$MCP_ONLY" == "false" ]]; then
header "Phase 1: Install .claude/ into your project"
Expand Down
Loading