feat: update execution commands to commit once per solution and enhance reranker model handling

This commit is contained in:
catlog22
2026-01-04 15:09:47 +08:00
parent 7e3d9007cd
commit 27a0129f72
5 changed files with 176 additions and 79 deletions

View File

@@ -1,6 +1,6 @@
--- ---
name: execute 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 <queue-id>]" argument-hint: "[--worktree] [--queue <queue-id>]"
allowed-tools: TodoWrite(*), Bash(*), Read(*), AskUserQuestion(*) allowed-tools: TodoWrite(*), Bash(*), Read(*), AskUserQuestion(*)
--- ---
@@ -49,7 +49,8 @@ Phase 2: Dispatch Parallel Batch (DAG-driven)
│ ├─ Executor calls: ccw issue detail <id> (READ-ONLY) │ ├─ Executor calls: ccw issue detail <id> (READ-ONLY)
│ ├─ Executor gets FULL SOLUTION with all tasks │ ├─ Executor gets FULL SOLUTION with all tasks
│ ├─ Executor implements all tasks sequentially (T1 → T2 → T3) │ ├─ 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 <id> │ ├─ Executor calls: ccw issue done <id>
│ └─ (if worktree) Cleanup: merge branch, remove worktree │ └─ (if worktree) Cleanup: merge branch, remove worktree
└─ Wait for batch completion └─ Wait for batch completion
@@ -205,7 +206,7 @@ cd "\${WORKTREE_PATH}"
` : ''; ` : '';
const worktreeCleanup = useWorktree ? ` const worktreeCleanup = useWorktree ? `
### Step 4: Worktree Completion (User Choice) ### Step 5: Worktree Completion (User Choice)
After all tasks complete, prompt for merge strategy: After all tasks complete, prompt for merge strategy:
@@ -282,12 +283,34 @@ For each task:
1. Follow task.implementation steps 1. Follow task.implementation steps
2. Run task.test commands 2. Run task.test commands
3. Verify task.acceptance criteria 3. Verify task.acceptance criteria
4. Commit using task.commit specification (Do NOT commit after each task)
### Step 3: Report Completion ### Step 3: Commit Solution (Once)
When ALL tasks in solution are done: After ALL tasks pass, commit once with formatted summary:
\`\`\`bash \`\`\`bash
ccw issue done ${solutionId} --result '{"summary": "...", "files_modified": [...], "tasks_completed": N}' git add <all-modified-files>
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: If any task failed:
@@ -350,6 +373,7 @@ if (refreshedDag.ready_count > 0) {
│ │ detail S-1 │ │ detail S-2 │ │ │ │ detail S-1 │ │ detail S-2 │ │
│ │ → gets full solution │ │ → gets full solution │ │ │ │ → gets full solution │ │ → gets full solution │ │
│ │ [T1→T2→T3 sequential]│ │ [T1→T2 sequential] │ │ │ │ [T1→T2→T3 sequential]│ │ [T1→T2 sequential] │ │
│ │ commit (1x solution) │ │ commit (1x solution) │ │
│ │ done S-1 │ │ done S-2 │ │ │ │ done S-1 │ │ done S-2 │ │
│ └──────────────────────┘ └──────────────────────┘ │ │ └──────────────────────┘ └──────────────────────┘ │
│ │ │ │
@@ -361,6 +385,7 @@ if (refreshedDag.ready_count > 0) {
**Why this works for parallel:** **Why this works for parallel:**
- `detail <id>` is READ-ONLY → no race conditions - `detail <id>` is READ-ONLY → no race conditions
- Each executor handles **all tasks within a solution** sequentially - Each executor handles **all tasks within a solution** sequentially
- **One commit per solution** with formatted summary (not per-task)
- `done <id>` updates only its own solution status - `done <id>` updates only its own solution status
- `queue dag` recalculates ready solutions after each batch - `queue dag` recalculates ready solutions after each batch
- Solutions in same batch have NO file conflicts - Solutions in same batch have NO file conflicts

View File

@@ -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 <queue-id>]" argument-hint: "[--worktree] [--queue <queue-id>]"
--- ---
@@ -7,7 +7,7 @@ argument-hint: "[--worktree] [--queue <queue-id>]"
## Core Principle ## 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) ## Worktree Mode (Recommended for Parallel Execution)
@@ -150,9 +150,9 @@ WHILE solution exists:
- IMPLEMENT: Follow task.implementation steps - IMPLEMENT: Follow task.implementation steps
- TEST: Run task.test commands - TEST: Run task.test commands
- VERIFY: Check task.acceptance criteria - VERIFY: Check task.acceptance criteria
- COMMIT: Stage files, commit with task.commit.message_template 3. COMMIT: Stage all files, commit once with formatted summary
3. Report completion via ccw issue done <item_id> 4. Report completion via ccw issue done <item_id>
4. Fetch next solution via ccw issue next 5. Fetch next solution via ccw issue next
WHEN queue empty: WHEN queue empty:
Output final summary 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 ```javascript
// Mark task as completed // Mark task as completed (commit happens at solution level)
update_plan({ update_plan({
explanation: `Completed ${task.id}: ${task.title}`, explanation: `Completed ${task.id}: ${task.title}`,
plan: tasks.map(t => ({ plan: tasks.map(t => ({
@@ -360,41 +360,76 @@ All criteria met: YES
**If any criterion fails**: Go back to IMPLEMENT phase and fix. **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 ### Repeat for Next Task
Continue to next task in `solution.tasks` array until all tasks are complete. 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 ## 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 ```javascript
// ccw auto-detects worktree and uses main repo's .workflow/ // 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({ command: `ccw issue done ${item_id} --result '${JSON.stringify({
files_modified: ["path1", "path2"], files_modified: ["path1", "path2"],
tests_passed: true, tests_passed: true,
commits: [{ task_id: "T1", hash: "abc123" }], commit: { hash: "abc123", type: "feat", tasks: ["T1", "T2"] },
summary: "[What was accomplished]" summary: "[What was accomplished]"
})}'` })}'`
}) })
@@ -427,7 +462,9 @@ const result = shell_command({ command: "ccw issue next" })
**Output progress:** **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... → Fetching next solution...
``` ```
@@ -444,13 +481,14 @@ When `ccw issue next` returns `{ "status": "empty" }`:
**Total Solutions Executed**: N **Total Solutions Executed**: N
**Total Tasks Executed**: M **Total Tasks Executed**: M
**Total Commits**: N (one per solution)
**All Commits**: **Solution Commits**:
| # | Solution | Task | Commit | | # | Solution | Tasks | Commit | Type |
|---|----------|------|--------| |---|----------|-------|--------|------|
| 1 | S-1 | T1 | abc123 | | 1 | SOL-xxx-1 | T1, T2 | abc123 | feat |
| 2 | S-1 | T2 | def456 | | 2 | SOL-xxx-2 | T1 | def456 | fix |
| 3 | S-2 | T1 | ghi789 | | 3 | SOL-yyy-1 | T1, T2, T3 | ghi789 | refactor |
**Files Modified**: **Files Modified**:
- path/to/file1.ts - path/to/file1.ts
@@ -463,11 +501,11 @@ When `ccw issue next` returns `{ "status": "empty" }`:
## Execution Rules ## Execution Rules
1. **Never stop mid-queue** - Continue until queue is empty 1. **Never stop mid-queue** - Continue until queue is empty
2. **One solution at a time** - Fully complete (all tasks + report) before moving on 2. **One solution at a time** - Fully complete (all tasks + commit + report) before moving on
3. **Sequential within solution** - Complete each task (including commit) before next 3. **Sequential within solution** - Complete each task's implement/test/verify before next task
4. **Tests MUST pass** - Do not proceed to commit if tests fail 4. **Tests MUST pass** - Do not proceed if any task's tests fail
5. **Commit after each task** - Each task gets its own commit 5. **One commit per solution** - All tasks share a single commit with formatted summary
6. **Self-verify** - All acceptance criteria must pass before commit 6. **Self-verify** - All acceptance criteria must pass before solution commit
7. **Report accurately** - Use `ccw issue done` after each solution 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 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 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 | | `ccw issue next` returns empty | All done - output final summary |
| Tests fail | Fix code, re-run tests | | Tests fail | Fix code, re-run tests |
| Verification fails | Go back to implement phase | | 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 | | `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 ## CLI Command Reference

View File

@@ -1181,10 +1181,10 @@ export async function handleCodexLensRoutes(ctx: RouteContext): Promise<boolean>
try { try {
const venvStatus = await checkVenvStatus(); const venvStatus = await checkVenvStatus();
// Default reranker config // Default reranker config (matches fastembed default)
const rerankerConfig = { const rerankerConfig = {
backend: 'onnx', backend: 'fastembed',
model_name: 'cross-encoder/ms-marco-MiniLM-L-6-v2', model_name: 'Xenova/ms-marco-MiniLM-L-6-v2',
api_provider: 'siliconflow', api_provider: 'siliconflow',
api_key_set: false, api_key_set: false,
available_backends: ['onnx', 'api', 'litellm', 'legacy'], available_backends: ['onnx', 'api', 'litellm', 'legacy'],

View File

@@ -1076,7 +1076,8 @@ function renderProviderList() {
var container = document.getElementById('provider-list'); var container = document.getElementById('provider-list');
if (!container) return; if (!container) return;
var providers = apiSettingsData.providers || []; // Guard against null apiSettingsData
var providers = (apiSettingsData && apiSettingsData.providers) ? apiSettingsData.providers : [];
var query = providerSearchQuery.toLowerCase(); var query = providerSearchQuery.toLowerCase();
// Filter providers // Filter providers
@@ -1147,6 +1148,12 @@ function renderProviderDetail(providerId) {
var container = document.getElementById('provider-detail-panel'); var container = document.getElementById('provider-detail-panel');
if (!container) return; if (!container) return;
// Guard against null apiSettingsData
if (!apiSettingsData || !apiSettingsData.providers) {
renderProviderEmptyState();
return;
}
var provider = apiSettingsData.providers.find(function(p) { return p.id === providerId; }); var provider = apiSettingsData.providers.find(function(p) { return p.id === providerId; });
if (!provider) { if (!provider) {
renderProviderEmptyState(); renderProviderEmptyState();
@@ -1370,6 +1377,9 @@ function toggleModelGroup(series) {
expandedModelGroups.add(series); expandedModelGroups.add(series);
} }
// Guard against null apiSettingsData
if (!apiSettingsData || !apiSettingsData.providers) return;
var provider = apiSettingsData.providers.find(function(p) { return p.id === selectedProviderId; }); var provider = apiSettingsData.providers.find(function(p) { return p.id === selectedProviderId; });
if (provider) { if (provider) {
renderModelTree(provider); renderModelTree(provider);
@@ -1379,10 +1389,20 @@ function toggleModelGroup(series) {
/** /**
* Switch model tab (LLM / Embedding) * Switch model tab (LLM / Embedding)
*/ */
function switchModelTab(tab) { async function switchModelTab(tab) {
activeModelTab = tab; activeModelTab = tab;
expandedModelGroups.clear(); 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; }); var provider = apiSettingsData.providers.find(function(p) { return p.id === selectedProviderId; });
if (provider) { if (provider) {
renderProviderDetail(selectedProviderId); renderProviderDetail(selectedProviderId);

View File

@@ -1693,9 +1693,14 @@ async function loadRerankerModelList() {
try { try {
// Get current reranker config // Get current reranker config
var response = await fetch('/api/codexlens/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 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 = '<div class="space-y-2">'; var html = '<div class="space-y-2">';
@@ -1713,8 +1718,19 @@ async function loadRerankerModelList() {
// Show models for local backend only // Show models for local backend only
if (currentBackend === 'fastembed' || currentBackend === 'onnx') { 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) { RERANKER_MODELS.forEach(function(model) {
var isActive = currentModel === model.name; var isActive = modelMatches(currentModel, model.name);
var statusIcon = isActive var statusIcon = isActive
? '<i data-lucide="check-circle" class="w-3.5 h-3.5 text-success"></i>' ? '<i data-lucide="check-circle" class="w-3.5 h-3.5 text-success"></i>'
: '<i data-lucide="circle" class="w-3.5 h-3.5 text-muted"></i>'; : '<i data-lucide="circle" class="w-3.5 h-3.5 text-muted"></i>';
@@ -1870,7 +1886,12 @@ async function loadGpuDevicesForModeSelector() {
if (!gpuSelect) return; if (!gpuSelect) return;
try { 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 = '<option value="auto">Auto</option>';
return;
}
var result = await response.json(); var result = await response.json();
var html = '<option value="auto">Auto</option>'; var html = '<option value="auto">Auto</option>';
@@ -3785,19 +3806,12 @@ async function checkIndexHealth() {
var lastIndexTime = currentIndex.lastModified ? new Date(currentIndex.lastModified) : null; 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; 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) { if (lastIndexTime) {
var hoursSince = (Date.now() - lastIndexTime.getTime()) / (1000 * 60 * 60); var hoursSince = (Date.now() - lastIndexTime.getTime()) / (1000 * 60 * 60);
commitsSince = Math.floor(hoursSince / 2); // Rough estimate // Rough estimate: assume ~2 commits per hour on active projects
} commitsSince = Math.floor(hoursSince / 2);
} }
// Determine health status // Determine health status