diff --git a/.claude/workflows/tool-strategy.md b/.claude/workflows/tool-strategy.md index 9ca703e5..7e336586 100644 --- a/.claude/workflows/tool-strategy.md +++ b/.claude/workflows/tool-strategy.md @@ -26,35 +26,44 @@ ccw tool exec classify_folders '{"path": "./src"}' **Available Tools**: `ccw tool list` -### edit_file Tool (AI-Powered Editing) +### edit_file Tool **When to Use**: Edit tool fails 1+ times on same file -### Usage - -**Best for**: Code block replacements, function rewrites, multi-line changes - ```bash -ccw tool exec edit_file --path "file.py" --old "def old(): - pass" --new "def new(): - return True" +# CLI shorthand +ccw tool exec edit_file --path "file.py" --old "old code" --new "new code" + +# JSON (recommended) +ccw tool exec edit_file '{"path": "file.py", "oldText": "old", "newText": "new"}' + +# dryRun - preview without modifying +ccw tool exec edit_file '{"path": "file.py", "oldText": "old", "newText": "new", "dryRun": true}' + +# Multiple edits +ccw tool exec edit_file '{"path": "file.py", "edits": [{"oldText": "a", "newText": "b"}, {"oldText": "c", "newText": "d"}]}' + +# Line mode +ccw tool exec edit_file '{"path": "file.py", "mode": "line", "operation": "insert_after", "line": 10, "text": "new"}' ``` -**Parameters**: -- `--path`: File path to edit -- `--old`: Text to find and replace -- `--new`: New text to insert +**Parameters**: `path`*, `oldText`, `newText`, `edits[]`, `dryRun`, `replaceAll`, `mode` (update|line) -**Features**: -- ✅ Exact text matching (precise and predictable) -- ✅ Auto line ending adaptation (CRLF/LF) -- ✅ No JSON escaping issues -- ✅ Multi-line text supported with quotes +### write_file Tool + +**When to Use**: Create new files or overwrite existing content + +```bash +ccw tool exec write_file '{"path": "file.txt", "content": "Hello"}' +ccw tool exec write_file '{"path": "file.txt", "content": "new", "backup": true}' +``` + +**Parameters**: `path`*, `content`*, `createDirectories`, `backup`, `encoding` ### Fallback Strategy -1. **Edit fails 1+ times** → Use `ccw tool exec edit_file` -2. **Still fails** → Use Write to recreate file +1. **Edit fails 1+ times** → `ccw tool exec edit_file` +2. **Still fails** → `ccw tool exec write_file` ## ⚡ sed Line Operations (Line Mode Alternative) diff --git a/ccw/package.json b/ccw/package.json index a72b5d52..3a984e7a 100644 --- a/ccw/package.json +++ b/ccw/package.json @@ -1,6 +1,6 @@ { "name": "ccw", - "version": "1.0.0", + "version": "6.1.4", "description": "Claude Code Workflow CLI - Dashboard viewer for workflow sessions and reviews", "type": "module", "main": "src/index.js", diff --git a/ccw/src/commands/install.js b/ccw/src/commands/install.js index 826595ff..7e0c6d70 100644 --- a/ccw/src/commands/install.js +++ b/ccw/src/commands/install.js @@ -331,6 +331,13 @@ async function copyDirectory(src, dest, manifest = null, excludeDirs = []) { */ function getVersion() { try { + // First try root package.json (parent of ccw) + const rootPkgPath = join(getSourceDir(), 'package.json'); + if (existsSync(rootPkgPath)) { + const pkg = JSON.parse(readFileSync(rootPkgPath, 'utf8')); + if (pkg.version) return pkg.version; + } + // Fallback to ccw package.json const pkgPath = join(getPackageRoot(), 'package.json'); const pkg = JSON.parse(readFileSync(pkgPath, 'utf8')); return pkg.version || '1.0.0'; diff --git a/ccw/src/commands/upgrade.js b/ccw/src/commands/upgrade.js index fffa8d99..3efa2287 100644 --- a/ccw/src/commands/upgrade.js +++ b/ccw/src/commands/upgrade.js @@ -32,6 +32,13 @@ function getSourceDir() { */ function getVersion() { try { + // First try root package.json (parent of ccw) + const rootPkgPath = join(getSourceDir(), 'package.json'); + if (existsSync(rootPkgPath)) { + const pkg = JSON.parse(readFileSync(rootPkgPath, 'utf8')); + if (pkg.version) return pkg.version; + } + // Fallback to ccw package.json const pkgPath = join(getPackageRoot(), 'package.json'); const pkg = JSON.parse(readFileSync(pkgPath, 'utf8')); return pkg.version || '1.0.0'; diff --git a/ccw/src/core/server.js b/ccw/src/core/server.js index 1e9b801c..584697f2 100644 --- a/ccw/src/core/server.js +++ b/ccw/src/core/server.js @@ -459,6 +459,58 @@ export async function startServer(options = {}) { return; } + // API: CCW Upgrade + if (pathname === '/api/ccw/upgrade' && req.method === 'POST') { + handlePostRequest(req, res, async (body) => { + const { path: installPath } = body; + + try { + const { spawn } = await import('child_process'); + + // Run ccw upgrade command + const args = installPath ? ['upgrade', '--all'] : ['upgrade', '--all']; + const upgradeProcess = spawn('ccw', args, { + shell: true, + stdio: ['ignore', 'pipe', 'pipe'] + }); + + let stdout = ''; + let stderr = ''; + + upgradeProcess.stdout.on('data', (data) => { + stdout += data.toString(); + }); + + upgradeProcess.stderr.on('data', (data) => { + stderr += data.toString(); + }); + + return new Promise((resolve) => { + upgradeProcess.on('close', (code) => { + if (code === 0) { + resolve({ success: true, message: 'Upgrade completed', output: stdout }); + } else { + resolve({ success: false, error: stderr || 'Upgrade failed', output: stdout, status: 500 }); + } + }); + + upgradeProcess.on('error', (err) => { + resolve({ success: false, error: err.message, status: 500 }); + }); + + // Timeout after 2 minutes + setTimeout(() => { + upgradeProcess.kill(); + resolve({ success: false, error: 'Upgrade timed out', status: 504 }); + }, 120000); + }); + } catch (err) { + return { success: false, error: err.message, status: 500 }; + } + }); + return; + } + // API: CLI Execution History if (pathname === '/api/cli/history') { const projectPath = url.searchParams.get('path') || initialPath; diff --git a/ccw/src/templates/dashboard-css/10-cli.css b/ccw/src/templates/dashboard-css/10-cli.css index 2cfaad0c..85a462ca 100644 --- a/ccw/src/templates/dashboard-css/10-cli.css +++ b/ccw/src/templates/dashboard-css/10-cli.css @@ -13,8 +13,9 @@ .cli-manager-grid { display: grid; - grid-template-columns: 1fr 1fr; + grid-template-columns: 1.2fr 0.8fr; gap: 1.25rem; + align-items: start; } @media (max-width: 768px) { @@ -46,12 +47,15 @@ display: flex; align-items: center; justify-content: space-between; - padding: 0.875rem 1rem; + padding: 0.625rem 0.75rem; border-bottom: 1px solid hsl(var(--border)); background: hsl(var(--muted) / 0.3); } .cli-status-header h3 { + display: flex; + align-items: center; + gap: 0.5rem; font-size: 0.8125rem; font-weight: 600; color: hsl(var(--foreground)); @@ -59,30 +63,57 @@ letter-spacing: -0.01em; } +.cli-status-header h3 i { + color: hsl(var(--muted-foreground)); +} + .cli-tools-grid { display: grid; grid-template-columns: repeat(3, 1fr); - gap: 0.625rem; - padding: 0.875rem; + gap: 0.5rem; + padding: 0.5rem 0.625rem; } .cli-tool-card { - padding: 0.875rem 0.75rem; + padding: 0.625rem 0.5rem; border-radius: 0.5rem; background: hsl(var(--background)); text-align: center; - border: 1px solid hsl(var(--border)); + border: 1.5px solid hsl(var(--border)); transition: all 0.2s ease; } .cli-tool-card.available { - border-color: hsl(var(--success) / 0.4); - background: hsl(var(--success) / 0.03); + background: hsl(var(--background)); } .cli-tool-card.available:hover { - border-color: hsl(var(--success) / 0.6); - background: hsl(var(--success) / 0.06); + box-shadow: 0 2px 8px hsl(var(--foreground) / 0.08); +} + +/* Tool-specific border colors */ +.cli-tool-card.tool-gemini.available { + border-color: hsl(210 80% 55% / 0.5); +} + +.cli-tool-card.tool-gemini.available:hover { + border-color: hsl(210 80% 55% / 0.7); +} + +.cli-tool-card.tool-qwen.available { + border-color: hsl(280 70% 55% / 0.5); +} + +.cli-tool-card.tool-qwen.available:hover { + border-color: hsl(280 70% 55% / 0.7); +} + +.cli-tool-card.tool-codex.available { + border-color: hsl(142 71% 45% / 0.5); +} + +.cli-tool-card.tool-codex.available:hover { + border-color: hsl(142 71% 45% / 0.7); } .cli-tool-card.unavailable { @@ -94,8 +125,8 @@ display: flex; align-items: center; justify-content: center; - gap: 0.5rem; - margin-bottom: 0.375rem; + gap: 0.375rem; + margin-bottom: 0.1875rem; } .cli-tool-status { @@ -134,7 +165,7 @@ .cli-tool-info { font-size: 0.6875rem; - margin-bottom: 0.5rem; + margin-bottom: 0.3125rem; color: hsl(var(--muted-foreground)); } @@ -222,6 +253,9 @@ } .cli-history-header h3 { + display: flex; + align-items: center; + gap: 0.5rem; font-size: 0.8125rem; font-weight: 600; color: hsl(var(--foreground)); @@ -229,6 +263,10 @@ letter-spacing: -0.01em; } +.cli-history-header h3 i { + color: hsl(var(--muted-foreground)); +} + .cli-history-controls { display: flex; align-items: center; @@ -683,7 +721,7 @@ /* CCW Install Content */ .ccw-install-content { - padding: 0.875rem; + padding: 0.5rem 0.625rem; } /* CCW Empty State */ @@ -727,7 +765,7 @@ .ccw-carousel-card { flex: 0 0 100%; min-width: 0; - padding: 1rem; + padding: 0.625rem 0.75rem; background: hsl(var(--background)); border: 1px solid hsl(var(--border)); border-radius: 0.5rem; @@ -744,18 +782,28 @@ display: flex; align-items: center; justify-content: space-between; - margin-bottom: 0.75rem; + margin-bottom: 0.375rem; +} + +.ccw-card-header-right { + display: flex; + align-items: center; + gap: 0.375rem; } .ccw-card-mode { display: flex; align-items: center; - gap: 0.5rem; + gap: 0.375rem; font-weight: 600; - font-size: 0.875rem; + font-size: 0.8125rem; color: hsl(var(--foreground)); } +.btn-icon-sm { + padding: 0.25rem; +} + .ccw-card-mode.global { color: hsl(var(--primary)); } @@ -776,13 +824,13 @@ /* Carousel Card Path */ .ccw-card-path { - font-size: 0.75rem; + font-size: 0.6875rem; color: hsl(var(--muted-foreground)); font-family: 'SF Mono', 'Consolas', 'Liberation Mono', monospace; background: hsl(var(--muted) / 0.5); - padding: 0.5rem 0.625rem; + padding: 0.3125rem 0.5rem; border-radius: 0.375rem; - margin-bottom: 0.75rem; + margin-bottom: 0.375rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; @@ -791,10 +839,9 @@ /* Carousel Card Meta */ .ccw-card-meta { display: flex; - gap: 1rem; - font-size: 0.6875rem; + gap: 0.75rem; + font-size: 0.625rem; color: hsl(var(--muted-foreground)); - margin-bottom: 0.75rem; } .ccw-card-meta span { @@ -803,14 +850,7 @@ gap: 0.25rem; } -/* Carousel Card Actions */ -.ccw-card-actions { - display: flex; - justify-content: flex-end; - gap: 0.375rem; - padding-top: 0.75rem; - border-top: 1px solid hsl(var(--border)); -} +/* Carousel Card Actions - moved to header */ /* Carousel Navigation Buttons */ .ccw-carousel-btn { @@ -844,7 +884,7 @@ display: flex; justify-content: center; gap: 0.5rem; - margin-top: 0.75rem; + margin-top: 0.5rem; } .ccw-carousel-dot { diff --git a/ccw/src/templates/dashboard-js/components/cli-history.js b/ccw/src/templates/dashboard-js/components/cli-history.js index f16d0b41..c2bc4382 100644 --- a/ccw/src/templates/dashboard-js/components/cli-history.js +++ b/ccw/src/templates/dashboard-js/components/cli-history.js @@ -56,7 +56,7 @@ function renderCliHistory() { if (cliExecutionHistory.length === 0) { container.innerHTML = `