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
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>]"
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 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 <id>
│ └─ (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 <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:
@@ -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 <id>` 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 <id>` updates only its own solution status
- `queue dag` recalculates ready solutions after each batch
- 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>]"
---
@@ -7,7 +7,7 @@ argument-hint: "[--worktree] [--queue <queue-id>]"
## 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 <item_id>
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 <item_id>
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

View File

@@ -1181,10 +1181,10 @@ export async function handleCodexLensRoutes(ctx: RouteContext): Promise<boolean>
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'],

View File

@@ -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);

View File

@@ -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 = '<div class="space-y-2">';
@@ -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
? '<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>';
@@ -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 = '<option value="auto">Auto</option>';
return;
}
var result = await response.json();
var html = '<option value="auto">Auto</option>';
@@ -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