diff --git a/.claude/commands/issue/execute.md b/.claude/commands/issue/execute.md index c31567b3..fd5f43ae 100644 --- a/.claude/commands/issue/execute.md +++ b/.claude/commands/issue/execute.md @@ -1,6 +1,6 @@ --- name: execute -description: Execute queue with codex using DAG-based parallel orchestration (solution-level) +description: Execute queue with DAG-based parallel orchestration (one commit per solution) argument-hint: "[--worktree] [--queue ]" allowed-tools: TodoWrite(*), Bash(*), Read(*), AskUserQuestion(*) --- @@ -49,7 +49,8 @@ Phase 2: Dispatch Parallel Batch (DAG-driven) │ ├─ Executor calls: ccw issue detail (READ-ONLY) │ ├─ Executor gets FULL SOLUTION with all tasks │ ├─ Executor implements all tasks sequentially (T1 → T2 → T3) - │ ├─ Executor tests + commits per task + │ ├─ Executor tests + verifies each task + │ ├─ Executor commits ONCE per solution (with formatted summary) │ ├─ Executor calls: ccw issue done │ └─ (if worktree) Cleanup: merge branch, remove worktree └─ Wait for batch completion @@ -205,7 +206,7 @@ cd "\${WORKTREE_PATH}" ` : ''; const worktreeCleanup = useWorktree ? ` -### Step 4: Worktree Completion (User Choice) +### Step 5: Worktree Completion (User Choice) After all tasks complete, prompt for merge strategy: @@ -282,12 +283,34 @@ For each task: 1. Follow task.implementation steps 2. Run task.test commands 3. Verify task.acceptance criteria -4. Commit using task.commit specification +(Do NOT commit after each task) -### Step 3: Report Completion -When ALL tasks in solution are done: +### Step 3: Commit Solution (Once) +After ALL tasks pass, commit once with formatted summary: \`\`\`bash -ccw issue done ${solutionId} --result '{"summary": "...", "files_modified": [...], "tasks_completed": N}' +git add +git commit -m "[type](scope): [solution.description] + +## Solution Summary +- Solution-ID: ${solutionId} +- Tasks: T1, T2, ... + +## Tasks Completed +- [T1] task1.title: action +- [T2] task2.title: action + +## Files Modified +- file1.ts +- file2.ts + +## Verification +- All tests passed +- All acceptance criteria verified" +\`\`\` + +### Step 4: Report Completion +\`\`\`bash +ccw issue done ${solutionId} --result '{"summary": "...", "files_modified": [...], "commit": {"hash": "...", "type": "feat"}, "tasks_completed": N}' \`\`\` If any task failed: @@ -350,6 +373,7 @@ if (refreshedDag.ready_count > 0) { │ │ detail S-1 │ │ detail S-2 │ │ │ │ → gets full solution │ │ → gets full solution │ │ │ │ [T1→T2→T3 sequential]│ │ [T1→T2 sequential] │ │ +│ │ commit (1x solution) │ │ commit (1x solution) │ │ │ │ done S-1 │ │ done S-2 │ │ │ └──────────────────────┘ └──────────────────────┘ │ │ │ @@ -361,6 +385,7 @@ if (refreshedDag.ready_count > 0) { **Why this works for parallel:** - `detail ` is READ-ONLY → no race conditions - Each executor handles **all tasks within a solution** sequentially +- **One commit per solution** with formatted summary (not per-task) - `done ` updates only its own solution status - `queue dag` recalculates ready solutions after each batch - Solutions in same batch have NO file conflicts diff --git a/.codex/prompts/issue-execute.md b/.codex/prompts/issue-execute.md index f5512db1..90d5031b 100644 --- a/.codex/prompts/issue-execute.md +++ b/.codex/prompts/issue-execute.md @@ -1,5 +1,5 @@ --- -description: Execute all solutions from issue queue with git commit after each task +description: Execute all solutions from issue queue with git commit after each solution argument-hint: "[--worktree] [--queue ]" --- @@ -7,7 +7,7 @@ argument-hint: "[--worktree] [--queue ]" ## Core Principle -**Serial Execution**: Execute solutions ONE BY ONE from the issue queue via `ccw issue next`. For each solution, complete all tasks sequentially (implement → test → commit per task). Continue autonomously until queue is empty. +**Serial Execution**: Execute solutions ONE BY ONE from the issue queue via `ccw issue next`. For each solution, complete all tasks sequentially (implement → test → verify), then commit once per solution with formatted summary. Continue autonomously until queue is empty. ## Worktree Mode (Recommended for Parallel Execution) @@ -150,9 +150,9 @@ WHILE solution exists: - IMPLEMENT: Follow task.implementation steps - TEST: Run task.test commands - VERIFY: Check task.acceptance criteria - - COMMIT: Stage files, commit with task.commit.message_template - 3. Report completion via ccw issue done - 4. Fetch next solution via ccw issue next + 3. COMMIT: Stage all files, commit once with formatted summary + 4. Report completion via ccw issue done + 5. Fetch next solution via ccw issue next WHEN queue empty: Output final summary @@ -275,9 +275,9 @@ update_plan({ }) ``` -**After completing each task** (commit done), mark it as completed: +**After completing each task** (verification passed), mark it as completed: ```javascript -// Mark task as completed +// Mark task as completed (commit happens at solution level) update_plan({ explanation: `Completed ${task.id}: ${task.title}`, plan: tasks.map(t => ({ @@ -360,41 +360,76 @@ All criteria met: YES **If any criterion fails**: Go back to IMPLEMENT phase and fix. -### Phase D: COMMIT - -After all phases pass, commit the changes for this task: - -```bash -# Stage all modified files -git add path/to/file1.ts path/to/file2.ts ... - -# Commit with task message template -git commit -m "$(cat <<'EOF' -[task.commit.message_template] - -Solution-ID: [solution_id] -Issue-ID: [issue_id] -Task-ID: [task.id] -EOF -)" -``` - -**Output format:** -``` -## Committed: [task.title] - -**Commit**: [commit hash] -**Message**: [commit message] -**Files**: N files changed -``` - ### Repeat for Next Task Continue to next task in `solution.tasks` array until all tasks are complete. +**Note**: Do NOT commit after each task. Commits happen at solution level after all tasks pass. + +## Step 3.5: Commit Solution + +After ALL tasks in the solution pass implementation, testing, and verification, commit once for the entire solution: + +```bash +# Stage all modified files from all tasks +git add path/to/file1.ts path/to/file2.ts ... + +# Commit with formatted solution summary +git commit -m "$(cat <<'EOF' +[commit_type](scope): [solution.description - brief] + +## Solution Summary +- **Solution-ID**: [solution_id] +- **Issue-ID**: [issue_id] +- **Risk/Impact/Complexity**: [solution.analysis.risk]/[solution.analysis.impact]/[solution.analysis.complexity] + +## Tasks Completed +- [T1] [task1.title]: [task1.action] [task1.scope] +- [T2] [task2.title]: [task2.action] [task2.scope] +- ... + +## Files Modified +- path/to/file1.ts +- path/to/file2.ts +- ... + +## Verification +- All unit tests passed +- All acceptance criteria verified +EOF +)" +``` + +**Commit Type Selection**: +- `feat`: New feature or capability +- `fix`: Bug fix +- `refactor`: Code restructuring without behavior change +- `test`: Adding or updating tests +- `docs`: Documentation changes +- `chore`: Maintenance tasks + +**Output format:** +``` +## Solution Committed: [solution_id] + +**Commit**: [commit hash] +**Type**: [commit_type] +**Scope**: [scope] + +**Summary**: +[solution.description] + +**Tasks**: [N] tasks completed +- [x] T1: [task1.title] +- [x] T2: [task2.title] +... + +**Files**: [M] files changed +``` + ## Step 4: Report Completion -After ALL tasks in the solution are complete, report to queue system: +After ALL tasks in the solution are complete and committed, report to queue system: ```javascript // ccw auto-detects worktree and uses main repo's .workflow/ @@ -402,7 +437,7 @@ shell_command({ command: `ccw issue done ${item_id} --result '${JSON.stringify({ files_modified: ["path1", "path2"], tests_passed: true, - commits: [{ task_id: "T1", hash: "abc123" }], + commit: { hash: "abc123", type: "feat", tasks: ["T1", "T2"] }, summary: "[What was accomplished]" })}'` }) @@ -427,7 +462,9 @@ const result = shell_command({ command: "ccw issue next" }) **Output progress:** ``` -✓ [N/M] Completed: [item_id] - [solution.approach] +✓ [N/M] Completed: [item_id] - [solution.description] + Commit: [commit_hash] ([commit_type]) + Tasks: [task_count] completed → Fetching next solution... ``` @@ -444,13 +481,14 @@ When `ccw issue next` returns `{ "status": "empty" }`: **Total Solutions Executed**: N **Total Tasks Executed**: M +**Total Commits**: N (one per solution) -**All Commits**: -| # | Solution | Task | Commit | -|---|----------|------|--------| -| 1 | S-1 | T1 | abc123 | -| 2 | S-1 | T2 | def456 | -| 3 | S-2 | T1 | ghi789 | +**Solution Commits**: +| # | Solution | Tasks | Commit | Type | +|---|----------|-------|--------|------| +| 1 | SOL-xxx-1 | T1, T2 | abc123 | feat | +| 2 | SOL-xxx-2 | T1 | def456 | fix | +| 3 | SOL-yyy-1 | T1, T2, T3 | ghi789 | refactor | **Files Modified**: - path/to/file1.ts @@ -463,11 +501,11 @@ When `ccw issue next` returns `{ "status": "empty" }`: ## Execution Rules 1. **Never stop mid-queue** - Continue until queue is empty -2. **One solution at a time** - Fully complete (all tasks + report) before moving on -3. **Sequential within solution** - Complete each task (including commit) before next -4. **Tests MUST pass** - Do not proceed to commit if tests fail -5. **Commit after each task** - Each task gets its own commit -6. **Self-verify** - All acceptance criteria must pass before commit +2. **One solution at a time** - Fully complete (all tasks + commit + report) before moving on +3. **Sequential within solution** - Complete each task's implement/test/verify before next task +4. **Tests MUST pass** - Do not proceed if any task's tests fail +5. **One commit per solution** - All tasks share a single commit with formatted summary +6. **Self-verify** - All acceptance criteria must pass before solution commit 7. **Report accurately** - Use `ccw issue done` after each solution 8. **Handle failures gracefully** - If a solution fails, report via `ccw issue done --fail` and continue to next 9. **Track with update_plan** - Use update_plan tool for task progress tracking @@ -480,9 +518,9 @@ When `ccw issue next` returns `{ "status": "empty" }`: | `ccw issue next` returns empty | All done - output final summary | | Tests fail | Fix code, re-run tests | | Verification fails | Go back to implement phase | -| Git commit fails | Check staging, retry commit | +| Solution commit fails | Check staging, retry commit | | `ccw issue done` fails | Log error, continue to next solution | -| Unrecoverable error | Call `ccw issue done --fail`, continue to next | +| Any task unrecoverable | Call `ccw issue done --fail`, continue to next solution | ## CLI Command Reference diff --git a/ccw/src/core/routes/codexlens-routes.ts b/ccw/src/core/routes/codexlens-routes.ts index 738de5b7..60ffd014 100644 --- a/ccw/src/core/routes/codexlens-routes.ts +++ b/ccw/src/core/routes/codexlens-routes.ts @@ -1181,10 +1181,10 @@ export async function handleCodexLensRoutes(ctx: RouteContext): Promise try { const venvStatus = await checkVenvStatus(); - // Default reranker config + // Default reranker config (matches fastembed default) const rerankerConfig = { - backend: 'onnx', - model_name: 'cross-encoder/ms-marco-MiniLM-L-6-v2', + backend: 'fastembed', + model_name: 'Xenova/ms-marco-MiniLM-L-6-v2', api_provider: 'siliconflow', api_key_set: false, available_backends: ['onnx', 'api', 'litellm', 'legacy'], diff --git a/ccw/src/templates/dashboard-js/views/api-settings.js b/ccw/src/templates/dashboard-js/views/api-settings.js index 5e209e05..f9a35427 100644 --- a/ccw/src/templates/dashboard-js/views/api-settings.js +++ b/ccw/src/templates/dashboard-js/views/api-settings.js @@ -1076,7 +1076,8 @@ function renderProviderList() { var container = document.getElementById('provider-list'); if (!container) return; - var providers = apiSettingsData.providers || []; + // Guard against null apiSettingsData + var providers = (apiSettingsData && apiSettingsData.providers) ? apiSettingsData.providers : []; var query = providerSearchQuery.toLowerCase(); // Filter providers @@ -1147,6 +1148,12 @@ function renderProviderDetail(providerId) { var container = document.getElementById('provider-detail-panel'); if (!container) return; + // Guard against null apiSettingsData + if (!apiSettingsData || !apiSettingsData.providers) { + renderProviderEmptyState(); + return; + } + var provider = apiSettingsData.providers.find(function(p) { return p.id === providerId; }); if (!provider) { renderProviderEmptyState(); @@ -1370,6 +1377,9 @@ function toggleModelGroup(series) { expandedModelGroups.add(series); } + // Guard against null apiSettingsData + if (!apiSettingsData || !apiSettingsData.providers) return; + var provider = apiSettingsData.providers.find(function(p) { return p.id === selectedProviderId; }); if (provider) { renderModelTree(provider); @@ -1379,10 +1389,20 @@ function toggleModelGroup(series) { /** * Switch model tab (LLM / Embedding) */ -function switchModelTab(tab) { +async function switchModelTab(tab) { activeModelTab = tab; expandedModelGroups.clear(); + // Guard against null apiSettingsData or providers - try to load if not available + if (!apiSettingsData || !apiSettingsData.providers) { + console.warn('[API Settings] switchModelTab: loading data first...'); + await loadApiSettings(true); + if (!apiSettingsData || !apiSettingsData.providers) { + console.error('[API Settings] Failed to load API settings data'); + return; + } + } + var provider = apiSettingsData.providers.find(function(p) { return p.id === selectedProviderId; }); if (provider) { renderProviderDetail(selectedProviderId); diff --git a/ccw/src/templates/dashboard-js/views/codexlens-manager.js b/ccw/src/templates/dashboard-js/views/codexlens-manager.js index af7edc32..89e1fc06 100644 --- a/ccw/src/templates/dashboard-js/views/codexlens-manager.js +++ b/ccw/src/templates/dashboard-js/views/codexlens-manager.js @@ -1693,9 +1693,14 @@ async function loadRerankerModelList() { try { // Get current reranker config var response = await fetch('/api/codexlens/reranker/config'); + if (!response.ok) { + throw new Error('Failed to load reranker config: ' + response.status); + } var config = await response.json(); - var currentModel = config.model_name || 'Xenova/ms-marco-MiniLM-L-6-v2'; - var currentBackend = config.backend || 'fastembed'; + + // Handle API response format + var currentModel = config.model_name || config.result?.reranker_model || 'Xenova/ms-marco-MiniLM-L-6-v2'; + var currentBackend = config.backend || config.result?.reranker_backend || 'fastembed'; var html = '
'; @@ -1713,8 +1718,19 @@ async function loadRerankerModelList() { // Show models for local backend only if (currentBackend === 'fastembed' || currentBackend === 'onnx') { + // Helper to match model names (handles different prefixes like Xenova/ vs cross-encoder/) + function modelMatches(current, target) { + if (!current || !target) return false; + // Exact match + if (current === target) return true; + // Match by base name (after last /) + var currentBase = current.split('/').pop(); + var targetBase = target.split('/').pop(); + return currentBase === targetBase; + } + RERANKER_MODELS.forEach(function(model) { - var isActive = currentModel === model.name; + var isActive = modelMatches(currentModel, model.name); var statusIcon = isActive ? '' : ''; @@ -1870,7 +1886,12 @@ async function loadGpuDevicesForModeSelector() { if (!gpuSelect) return; try { - var response = await fetch('/api/codexlens/gpu/devices'); + var response = await fetch('/api/codexlens/gpu/list'); + if (!response.ok) { + console.warn('[CodexLens] GPU list endpoint returned:', response.status); + gpuSelect.innerHTML = ''; + return; + } var result = await response.json(); var html = ''; @@ -3785,19 +3806,12 @@ async function checkIndexHealth() { var lastIndexTime = currentIndex.lastModified ? new Date(currentIndex.lastModified) : null; - // Get git commits since last index + // Estimate staleness based on time (git API not available) var commitsSince = 0; - try { - var gitResponse = await fetch('/api/git/commits-since?since=' + encodeURIComponent(currentIndex.lastModified || '')); - var gitData = await gitResponse.json(); - commitsSince = gitData.count || 0; - } catch (gitErr) { - console.warn('[CodexLens] Could not get git history:', gitErr); - // Fallback: estimate based on time - if (lastIndexTime) { - var hoursSince = (Date.now() - lastIndexTime.getTime()) / (1000 * 60 * 60); - commitsSince = Math.floor(hoursSince / 2); // Rough estimate - } + if (lastIndexTime) { + var hoursSince = (Date.now() - lastIndexTime.getTime()) / (1000 * 60 * 60); + // Rough estimate: assume ~2 commits per hour on active projects + commitsSince = Math.floor(hoursSince / 2); } // Determine health status