@agile-vibe-coding/avc 0.2.3 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +475 -3
- package/cli/agents/agent-selector.md +23 -0
- package/cli/agents/code-implementer.md +117 -0
- package/cli/agents/code-validator.md +80 -0
- package/cli/agents/context-reviewer-epic.md +101 -0
- package/cli/agents/context-reviewer-story.md +92 -0
- package/cli/agents/context-writer-epic.md +145 -0
- package/cli/agents/context-writer-story.md +111 -0
- package/cli/agents/doc-writer-epic.md +42 -0
- package/cli/agents/doc-writer-story.md +43 -0
- package/cli/agents/duplicate-detector.md +110 -0
- package/cli/agents/epic-story-decomposer.md +318 -39
- package/cli/agents/mission-scope-generator.md +68 -4
- package/cli/agents/mission-scope-validator.md +40 -6
- package/cli/agents/project-context-extractor.md +21 -6
- package/cli/agents/scaffolding-generator.md +99 -0
- package/cli/agents/seed-validator.md +71 -0
- package/cli/agents/story-scope-reviewer.md +147 -0
- package/cli/agents/story-splitter.md +83 -0
- package/cli/agents/validator-documentation.json +31 -0
- package/cli/agents/validator-documentation.md +3 -1
- package/cli/api-reference-tool.js +368 -0
- package/cli/checks/catalog.json +76 -0
- package/cli/checks/code/quality.json +26 -0
- package/cli/checks/code/testing.json +14 -0
- package/cli/checks/code/traceability.json +26 -0
- package/cli/checks/cross-refs/epic.json +171 -0
- package/cli/checks/cross-refs/story.json +149 -0
- package/cli/checks/epic/api.json +114 -0
- package/cli/checks/epic/backend.json +126 -0
- package/cli/checks/epic/cloud.json +126 -0
- package/cli/checks/epic/data.json +102 -0
- package/cli/checks/epic/database.json +114 -0
- package/cli/checks/epic/developer.json +182 -0
- package/cli/checks/epic/devops.json +174 -0
- package/cli/checks/epic/frontend.json +162 -0
- package/cli/checks/epic/mobile.json +102 -0
- package/cli/checks/epic/qa.json +90 -0
- package/cli/checks/epic/security.json +184 -0
- package/cli/checks/epic/solution-architect.json +192 -0
- package/cli/checks/epic/test-architect.json +90 -0
- package/cli/checks/epic/ui.json +102 -0
- package/cli/checks/epic/ux.json +90 -0
- package/cli/checks/fixes/epic-fix-template.md +10 -0
- package/cli/checks/fixes/story-fix-template.md +10 -0
- package/cli/checks/story/api.json +186 -0
- package/cli/checks/story/backend.json +102 -0
- package/cli/checks/story/cloud.json +102 -0
- package/cli/checks/story/data.json +210 -0
- package/cli/checks/story/database.json +102 -0
- package/cli/checks/story/developer.json +168 -0
- package/cli/checks/story/devops.json +102 -0
- package/cli/checks/story/frontend.json +174 -0
- package/cli/checks/story/mobile.json +102 -0
- package/cli/checks/story/qa.json +210 -0
- package/cli/checks/story/security.json +198 -0
- package/cli/checks/story/solution-architect.json +230 -0
- package/cli/checks/story/test-architect.json +210 -0
- package/cli/checks/story/ui.json +102 -0
- package/cli/checks/story/ux.json +102 -0
- package/cli/coding-order.js +401 -0
- package/cli/dependency-checker.js +72 -0
- package/cli/epic-story-validator.js +284 -799
- package/cli/index.js +0 -0
- package/cli/init-model-config.js +17 -10
- package/cli/init.js +514 -92
- package/cli/kanban-server-manager.js +1 -2
- package/cli/llm-claude.js +98 -31
- package/cli/llm-gemini.js +29 -5
- package/cli/llm-local.js +493 -0
- package/cli/llm-openai.js +262 -41
- package/cli/llm-provider.js +147 -8
- package/cli/llm-token-limits.js +113 -4
- package/cli/llm-verifier.js +209 -1
- package/cli/llm-xiaomi.js +143 -0
- package/cli/message-constants.js +3 -12
- package/cli/messaging-api.js +6 -12
- package/cli/micro-check-fixer.js +335 -0
- package/cli/micro-check-runner.js +449 -0
- package/cli/micro-check-scorer.js +148 -0
- package/cli/micro-check-validator.js +538 -0
- package/cli/model-pricing.js +23 -0
- package/cli/model-selector.js +3 -2
- package/cli/prompt-logger.js +57 -0
- package/cli/repl-ink.js +106 -346
- package/cli/repl-old.js +1 -2
- package/cli/seed-processor.js +194 -24
- package/cli/sprint-planning-processor.js +2638 -289
- package/cli/template-processor.js +50 -3
- package/cli/token-tracker.js +50 -23
- package/cli/tools/generate-story-validators.js +1 -1
- package/cli/validation-router.js +70 -8
- package/cli/worktree-runner.js +654 -0
- package/kanban/client/dist/assets/index-D_KC5EQT.css +1 -0
- package/kanban/client/dist/assets/index-DjY5zqW7.js +351 -0
- package/kanban/client/dist/index.html +2 -2
- package/kanban/client/src/App.jsx +43 -14
- package/kanban/client/src/components/ceremony/AskArchPopup.jsx +7 -3
- package/kanban/client/src/components/ceremony/AskModelPopup.jsx +23 -10
- package/kanban/client/src/components/ceremony/CeremonyWorkflowModal.jsx +320 -133
- package/kanban/client/src/components/ceremony/ProviderSwitcherButton.jsx +290 -0
- package/kanban/client/src/components/ceremony/SponsorCallModal.jsx +80 -13
- package/kanban/client/src/components/ceremony/SprintPlanningModal.jsx +156 -22
- package/kanban/client/src/components/ceremony/steps/ArchitectureStep.jsx +11 -11
- package/kanban/client/src/components/ceremony/steps/CompleteStep.jsx +3 -21
- package/kanban/client/src/components/ceremony/steps/ReviewAnswersStep.jsx +214 -10
- package/kanban/client/src/components/ceremony/steps/RunningStep.jsx +23 -2
- package/kanban/client/src/components/kanban/CardDetailModal.jsx +97 -10
- package/kanban/client/src/components/kanban/GroupingSelector.jsx +7 -1
- package/kanban/client/src/components/kanban/KanbanCard.jsx +23 -14
- package/kanban/client/src/components/kanban/RefineWorkItemPopup.jsx +9 -14
- package/kanban/client/src/components/kanban/RunButton.jsx +162 -0
- package/kanban/client/src/components/kanban/SeedButton.jsx +176 -0
- package/kanban/client/src/components/settings/AgentsTab.jsx +103 -75
- package/kanban/client/src/components/settings/ApiKeysTab.jsx +31 -2
- package/kanban/client/src/components/settings/CeremonyModelsTab.jsx +9 -2
- package/kanban/client/src/components/settings/CheckEditorPopup.jsx +507 -0
- package/kanban/client/src/components/settings/CostThresholdsTab.jsx +3 -2
- package/kanban/client/src/components/settings/ModelPricingTab.jsx +72 -7
- package/kanban/client/src/components/settings/OpenAIAuthSection.jsx +412 -0
- package/kanban/client/src/components/settings/SettingsModal.jsx +4 -4
- package/kanban/client/src/components/stats/CostModal.jsx +34 -3
- package/kanban/client/src/hooks/useGrouping.js +59 -0
- package/kanban/client/src/lib/api.js +118 -4
- package/kanban/client/src/lib/status-grouping.js +10 -0
- package/kanban/client/src/store/kanbanStore.js +8 -0
- package/kanban/server/index.js +23 -2
- package/kanban/server/routes/ceremony.js +153 -4
- package/kanban/server/routes/costs.js +9 -3
- package/kanban/server/routes/openai-oauth.js +366 -0
- package/kanban/server/routes/settings.js +447 -14
- package/kanban/server/routes/websocket.js +7 -2
- package/kanban/server/routes/work-items.js +141 -1
- package/kanban/server/services/CeremonyService.js +275 -24
- package/kanban/server/services/TaskRunnerService.js +261 -0
- package/kanban/server/workers/run-task-worker.js +121 -0
- package/kanban/server/workers/seed-worker.js +94 -0
- package/kanban/server/workers/sponsor-call-worker.js +14 -6
- package/kanban/server/workers/sprint-planning-worker.js +94 -12
- package/package.json +2 -3
- package/cli/agents/solver-epic-api.json +0 -15
- package/cli/agents/solver-epic-api.md +0 -39
- package/cli/agents/solver-epic-backend.json +0 -15
- package/cli/agents/solver-epic-backend.md +0 -39
- package/cli/agents/solver-epic-cloud.json +0 -15
- package/cli/agents/solver-epic-cloud.md +0 -39
- package/cli/agents/solver-epic-data.json +0 -15
- package/cli/agents/solver-epic-data.md +0 -39
- package/cli/agents/solver-epic-database.json +0 -15
- package/cli/agents/solver-epic-database.md +0 -39
- package/cli/agents/solver-epic-developer.json +0 -15
- package/cli/agents/solver-epic-developer.md +0 -39
- package/cli/agents/solver-epic-devops.json +0 -15
- package/cli/agents/solver-epic-devops.md +0 -39
- package/cli/agents/solver-epic-frontend.json +0 -15
- package/cli/agents/solver-epic-frontend.md +0 -39
- package/cli/agents/solver-epic-mobile.json +0 -15
- package/cli/agents/solver-epic-mobile.md +0 -39
- package/cli/agents/solver-epic-qa.json +0 -15
- package/cli/agents/solver-epic-qa.md +0 -39
- package/cli/agents/solver-epic-security.json +0 -15
- package/cli/agents/solver-epic-security.md +0 -39
- package/cli/agents/solver-epic-solution-architect.json +0 -15
- package/cli/agents/solver-epic-solution-architect.md +0 -39
- package/cli/agents/solver-epic-test-architect.json +0 -15
- package/cli/agents/solver-epic-test-architect.md +0 -39
- package/cli/agents/solver-epic-ui.json +0 -15
- package/cli/agents/solver-epic-ui.md +0 -39
- package/cli/agents/solver-epic-ux.json +0 -15
- package/cli/agents/solver-epic-ux.md +0 -39
- package/cli/agents/solver-story-api.json +0 -15
- package/cli/agents/solver-story-api.md +0 -39
- package/cli/agents/solver-story-backend.json +0 -15
- package/cli/agents/solver-story-backend.md +0 -39
- package/cli/agents/solver-story-cloud.json +0 -15
- package/cli/agents/solver-story-cloud.md +0 -39
- package/cli/agents/solver-story-data.json +0 -15
- package/cli/agents/solver-story-data.md +0 -39
- package/cli/agents/solver-story-database.json +0 -15
- package/cli/agents/solver-story-database.md +0 -39
- package/cli/agents/solver-story-developer.json +0 -15
- package/cli/agents/solver-story-developer.md +0 -39
- package/cli/agents/solver-story-devops.json +0 -15
- package/cli/agents/solver-story-devops.md +0 -39
- package/cli/agents/solver-story-frontend.json +0 -15
- package/cli/agents/solver-story-frontend.md +0 -39
- package/cli/agents/solver-story-mobile.json +0 -15
- package/cli/agents/solver-story-mobile.md +0 -39
- package/cli/agents/solver-story-qa.json +0 -15
- package/cli/agents/solver-story-qa.md +0 -39
- package/cli/agents/solver-story-security.json +0 -15
- package/cli/agents/solver-story-security.md +0 -39
- package/cli/agents/solver-story-solution-architect.json +0 -15
- package/cli/agents/solver-story-solution-architect.md +0 -39
- package/cli/agents/solver-story-test-architect.json +0 -15
- package/cli/agents/solver-story-test-architect.md +0 -39
- package/cli/agents/solver-story-ui.json +0 -15
- package/cli/agents/solver-story-ui.md +0 -39
- package/cli/agents/solver-story-ux.json +0 -15
- package/cli/agents/solver-story-ux.md +0 -39
- package/cli/agents/validator-epic-api.json +0 -93
- package/cli/agents/validator-epic-api.md +0 -137
- package/cli/agents/validator-epic-backend.json +0 -93
- package/cli/agents/validator-epic-backend.md +0 -130
- package/cli/agents/validator-epic-cloud.json +0 -93
- package/cli/agents/validator-epic-cloud.md +0 -137
- package/cli/agents/validator-epic-data.json +0 -93
- package/cli/agents/validator-epic-data.md +0 -130
- package/cli/agents/validator-epic-database.json +0 -93
- package/cli/agents/validator-epic-database.md +0 -137
- package/cli/agents/validator-epic-developer.json +0 -74
- package/cli/agents/validator-epic-developer.md +0 -153
- package/cli/agents/validator-epic-devops.json +0 -74
- package/cli/agents/validator-epic-devops.md +0 -153
- package/cli/agents/validator-epic-frontend.json +0 -74
- package/cli/agents/validator-epic-frontend.md +0 -153
- package/cli/agents/validator-epic-mobile.json +0 -93
- package/cli/agents/validator-epic-mobile.md +0 -130
- package/cli/agents/validator-epic-qa.json +0 -93
- package/cli/agents/validator-epic-qa.md +0 -130
- package/cli/agents/validator-epic-security.json +0 -74
- package/cli/agents/validator-epic-security.md +0 -154
- package/cli/agents/validator-epic-solution-architect.json +0 -74
- package/cli/agents/validator-epic-solution-architect.md +0 -156
- package/cli/agents/validator-epic-test-architect.json +0 -93
- package/cli/agents/validator-epic-test-architect.md +0 -130
- package/cli/agents/validator-epic-ui.json +0 -93
- package/cli/agents/validator-epic-ui.md +0 -130
- package/cli/agents/validator-epic-ux.json +0 -93
- package/cli/agents/validator-epic-ux.md +0 -130
- package/cli/agents/validator-story-api.json +0 -104
- package/cli/agents/validator-story-api.md +0 -152
- package/cli/agents/validator-story-backend.json +0 -104
- package/cli/agents/validator-story-backend.md +0 -152
- package/cli/agents/validator-story-cloud.json +0 -104
- package/cli/agents/validator-story-cloud.md +0 -152
- package/cli/agents/validator-story-data.json +0 -104
- package/cli/agents/validator-story-data.md +0 -152
- package/cli/agents/validator-story-database.json +0 -104
- package/cli/agents/validator-story-database.md +0 -152
- package/cli/agents/validator-story-developer.json +0 -104
- package/cli/agents/validator-story-developer.md +0 -152
- package/cli/agents/validator-story-devops.json +0 -104
- package/cli/agents/validator-story-devops.md +0 -152
- package/cli/agents/validator-story-frontend.json +0 -104
- package/cli/agents/validator-story-frontend.md +0 -152
- package/cli/agents/validator-story-mobile.json +0 -104
- package/cli/agents/validator-story-mobile.md +0 -152
- package/cli/agents/validator-story-qa.json +0 -104
- package/cli/agents/validator-story-qa.md +0 -152
- package/cli/agents/validator-story-security.json +0 -104
- package/cli/agents/validator-story-security.md +0 -152
- package/cli/agents/validator-story-solution-architect.json +0 -104
- package/cli/agents/validator-story-solution-architect.md +0 -152
- package/cli/agents/validator-story-test-architect.json +0 -104
- package/cli/agents/validator-story-test-architect.md +0 -152
- package/cli/agents/validator-story-ui.json +0 -104
- package/cli/agents/validator-story-ui.md +0 -152
- package/cli/agents/validator-story-ux.json +0 -104
- package/cli/agents/validator-story-ux.md +0 -152
- package/kanban/client/dist/assets/index-CiD8PS2e.js +0 -306
- package/kanban/client/dist/assets/index-nLh0m82Q.css +0 -1
package/cli/init.js
CHANGED
|
@@ -11,6 +11,60 @@ import { MESSAGES, getCeremonyHeader } from './message-constants.js';
|
|
|
11
11
|
import { sendError, sendWarning, sendSuccess, sendInfo, sendOutput, sendIndented, sendSectionHeader } from './messaging-api.js';
|
|
12
12
|
import { boldCyan, yellow, green, cyan } from './ansi-colors.js';
|
|
13
13
|
|
|
14
|
+
/**
|
|
15
|
+
* Trace log written directly to /tmp/avc-init.log so we can diagnose mkdir
|
|
16
|
+
* failures that occur before .avc/ exists (where normal logging goes).
|
|
17
|
+
*/
|
|
18
|
+
function initTrace(message, data = null) {
|
|
19
|
+
try {
|
|
20
|
+
const ts = new Date().toISOString();
|
|
21
|
+
const line = data
|
|
22
|
+
? `[${ts}] ${message} ${JSON.stringify(data)}\n`
|
|
23
|
+
: `[${ts}] ${message}\n`;
|
|
24
|
+
fs.appendFileSync('/tmp/avc-init.log', line);
|
|
25
|
+
} catch { /* never let tracing break init */ }
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Reliable recursive mkdir for WSL2 /mnt/ Windows paths.
|
|
30
|
+
*
|
|
31
|
+
* Two-layer strategy:
|
|
32
|
+
* 1. Walk the tree manually and call plain mkdirSync() for each segment
|
|
33
|
+
* (avoids Node's { recursive:true } which can race on DrvFS/9P).
|
|
34
|
+
* 2. If mkdirSync() still fails with ENOENT (VFS dentry-cache stale —
|
|
35
|
+
* stat() says parent exists but mkdir() syscall disagrees), fall back
|
|
36
|
+
* to a subprocess `mkdir -p`. The subprocess starts with a clean
|
|
37
|
+
* dentry cache and sees the filesystem state the kernel actually has.
|
|
38
|
+
*/
|
|
39
|
+
function mkdirp(dirPath) {
|
|
40
|
+
initTrace('mkdirp enter', { dirPath, exists: fs.existsSync(dirPath) });
|
|
41
|
+
if (fs.existsSync(dirPath)) return;
|
|
42
|
+
const parent = path.dirname(dirPath);
|
|
43
|
+
if (parent !== dirPath) mkdirp(parent);
|
|
44
|
+
try {
|
|
45
|
+
fs.mkdirSync(dirPath);
|
|
46
|
+
initTrace('mkdirp created via mkdirSync', { dirPath });
|
|
47
|
+
} catch (err) {
|
|
48
|
+
if (err.code === 'EEXIST') return;
|
|
49
|
+
if (err.code === 'ENOENT') {
|
|
50
|
+
// WSL2/DrvFS: VFS dentry cache reports parent as present but the 9P
|
|
51
|
+
// server disagrees at mkdir() time. Spawn a fresh process whose cache
|
|
52
|
+
// is clean — shell mkdir -p goes straight to the 9P server correctly.
|
|
53
|
+
initTrace('mkdirp mkdirSync ENOENT — falling back to shell mkdir -p', { dirPath, parentExists: fs.existsSync(parent) });
|
|
54
|
+
try {
|
|
55
|
+
execSync(`mkdir -p ${JSON.stringify(dirPath)}`, { stdio: 'pipe' });
|
|
56
|
+
initTrace('mkdirp created via shell mkdir -p', { dirPath });
|
|
57
|
+
return;
|
|
58
|
+
} catch (shellErr) {
|
|
59
|
+
initTrace('mkdirp shell mkdir -p also failed', { dirPath, shellErr: shellErr.message });
|
|
60
|
+
if (!fs.existsSync(dirPath)) throw err; // throw original ENOENT
|
|
61
|
+
return; // shell failed but dir now exists — tolerate
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
throw err;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
14
68
|
/**
|
|
15
69
|
* Write a structured entry to the active command log file only.
|
|
16
70
|
* Uses [DEBUG] prefix so ConsoleOutputManager routes to file, never terminal.
|
|
@@ -125,7 +179,7 @@ class ProjectInitiator {
|
|
|
125
179
|
*/
|
|
126
180
|
createAvcFolder() {
|
|
127
181
|
if (!this.hasAvcFolder()) {
|
|
128
|
-
|
|
182
|
+
mkdirp(this.avcDir);
|
|
129
183
|
return true;
|
|
130
184
|
}
|
|
131
185
|
return false;
|
|
@@ -143,7 +197,7 @@ class ProjectInitiator {
|
|
|
143
197
|
*/
|
|
144
198
|
createSrcFolder() {
|
|
145
199
|
if (!this.hasSrcFolder()) {
|
|
146
|
-
|
|
200
|
+
mkdirp(this.srcDir);
|
|
147
201
|
return true;
|
|
148
202
|
}
|
|
149
203
|
return false;
|
|
@@ -161,7 +215,7 @@ class ProjectInitiator {
|
|
|
161
215
|
*/
|
|
162
216
|
createWorktreesFolder() {
|
|
163
217
|
if (!this.hasWorktreesFolder()) {
|
|
164
|
-
|
|
218
|
+
mkdirp(this.worktreesDir);
|
|
165
219
|
return true;
|
|
166
220
|
}
|
|
167
221
|
return false;
|
|
@@ -207,6 +261,64 @@ class ProjectInitiator {
|
|
|
207
261
|
model: 'claude-sonnet-4-6'
|
|
208
262
|
}
|
|
209
263
|
},
|
|
264
|
+
providerPresets: {
|
|
265
|
+
claude: {
|
|
266
|
+
provider: 'claude', defaultModel: 'claude-sonnet-4-6',
|
|
267
|
+
stages: {
|
|
268
|
+
suggestions: { provider: 'claude', model: 'claude-sonnet-4-6' },
|
|
269
|
+
documentation: { provider: 'claude', model: 'claude-sonnet-4-6' },
|
|
270
|
+
'architecture-recommendation': { provider: 'claude', model: 'claude-opus-4-6' },
|
|
271
|
+
'question-prefilling': { provider: 'claude', model: 'claude-haiku-4-5-20251001' }
|
|
272
|
+
},
|
|
273
|
+
validation: {
|
|
274
|
+
provider: 'claude', model: 'claude-haiku-4-5-20251001',
|
|
275
|
+
documentation: { provider: 'claude', model: 'claude-haiku-4-5-20251001' },
|
|
276
|
+
refinement: { provider: 'claude', model: 'claude-sonnet-4-6' }
|
|
277
|
+
}
|
|
278
|
+
},
|
|
279
|
+
gemini: {
|
|
280
|
+
provider: 'gemini', defaultModel: 'gemini-2.5-flash',
|
|
281
|
+
stages: {
|
|
282
|
+
suggestions: { provider: 'gemini', model: 'gemini-2.5-flash' },
|
|
283
|
+
documentation: { provider: 'gemini', model: 'gemini-2.5-flash' },
|
|
284
|
+
'architecture-recommendation': { provider: 'gemini', model: 'gemini-2.5-pro' },
|
|
285
|
+
'question-prefilling': { provider: 'gemini', model: 'gemini-2.5-flash-lite' }
|
|
286
|
+
},
|
|
287
|
+
validation: {
|
|
288
|
+
provider: 'gemini', model: 'gemini-2.5-flash-lite',
|
|
289
|
+
documentation: { provider: 'gemini', model: 'gemini-2.5-flash-lite' },
|
|
290
|
+
refinement: { provider: 'gemini', model: 'gemini-2.5-flash' }
|
|
291
|
+
}
|
|
292
|
+
},
|
|
293
|
+
openai: {
|
|
294
|
+
provider: 'openai', defaultModel: 'gpt-5.4',
|
|
295
|
+
stages: {
|
|
296
|
+
suggestions: { provider: 'openai', model: 'gpt-5.4' },
|
|
297
|
+
documentation: { provider: 'openai', model: 'gpt-5.4' },
|
|
298
|
+
'architecture-recommendation': { provider: 'openai', model: 'gpt-5.4' },
|
|
299
|
+
'question-prefilling': { provider: 'openai', model: 'gpt-5-mini' }
|
|
300
|
+
},
|
|
301
|
+
validation: {
|
|
302
|
+
provider: 'openai', model: 'gpt-5.4',
|
|
303
|
+
documentation: { provider: 'openai', model: 'gpt-5.4' },
|
|
304
|
+
refinement: { provider: 'openai', model: 'gpt-5.4' }
|
|
305
|
+
}
|
|
306
|
+
},
|
|
307
|
+
xiaomi: {
|
|
308
|
+
provider: 'xiaomi', defaultModel: 'mimo-v2-pro',
|
|
309
|
+
stages: {
|
|
310
|
+
suggestions: { provider: 'xiaomi', model: 'mimo-v2-flash' },
|
|
311
|
+
documentation: { provider: 'xiaomi', model: 'mimo-v2-pro' },
|
|
312
|
+
'architecture-recommendation': { provider: 'xiaomi', model: 'mimo-v2-pro' },
|
|
313
|
+
'question-prefilling': { provider: 'xiaomi', model: 'mimo-v2-pro' }
|
|
314
|
+
},
|
|
315
|
+
validation: {
|
|
316
|
+
provider: 'xiaomi', model: 'mimo-v2-flash',
|
|
317
|
+
documentation: { provider: 'xiaomi', model: 'mimo-v2-pro' },
|
|
318
|
+
refinement: { provider: 'xiaomi', model: 'mimo-v2-pro' }
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
},
|
|
210
322
|
agents: [
|
|
211
323
|
{
|
|
212
324
|
name: 'project-documentation-creator',
|
|
@@ -253,21 +365,64 @@ class ProjectInitiator {
|
|
|
253
365
|
validation: {
|
|
254
366
|
provider: 'claude',
|
|
255
367
|
model: 'claude-sonnet-4-6',
|
|
256
|
-
useContextualSelection: true
|
|
368
|
+
useContextualSelection: true,
|
|
369
|
+
epicConcurrency: 2,
|
|
370
|
+
concurrency: 5,
|
|
371
|
+
maxFixAttempts: 3
|
|
257
372
|
},
|
|
258
|
-
'
|
|
373
|
+
'context-generation': {
|
|
259
374
|
provider: 'claude',
|
|
260
375
|
model: 'claude-sonnet-4-6'
|
|
261
376
|
},
|
|
262
|
-
|
|
377
|
+
'doc-generation': {
|
|
263
378
|
provider: 'claude',
|
|
264
379
|
model: 'claude-sonnet-4-6'
|
|
265
380
|
},
|
|
266
|
-
|
|
381
|
+
enrichment: {
|
|
267
382
|
provider: 'claude',
|
|
268
|
-
model: 'claude-
|
|
269
|
-
|
|
270
|
-
|
|
383
|
+
model: 'claude-sonnet-4-6'
|
|
384
|
+
}
|
|
385
|
+
},
|
|
386
|
+
providerPresets: {
|
|
387
|
+
claude: {
|
|
388
|
+
provider: 'claude', defaultModel: 'claude-sonnet-4-6',
|
|
389
|
+
stages: {
|
|
390
|
+
decomposition: { provider: 'claude', model: 'claude-opus-4-6' },
|
|
391
|
+
validation: { provider: 'claude', model: 'claude-sonnet-4-6', useContextualSelection: true, epicConcurrency: 2, concurrency: 5, maxFixAttempts: 3 },
|
|
392
|
+
'context-generation': { provider: 'claude', model: 'claude-sonnet-4-6' },
|
|
393
|
+
'doc-generation': { provider: 'claude', model: 'claude-sonnet-4-6' },
|
|
394
|
+
enrichment: { provider: 'claude', model: 'claude-sonnet-4-6' }
|
|
395
|
+
}
|
|
396
|
+
},
|
|
397
|
+
gemini: {
|
|
398
|
+
provider: 'gemini', defaultModel: 'gemini-2.5-flash',
|
|
399
|
+
stages: {
|
|
400
|
+
decomposition: { provider: 'gemini', model: 'gemini-2.5-pro' },
|
|
401
|
+
validation: { provider: 'gemini', model: 'gemini-2.5-flash', useContextualSelection: true, epicConcurrency: 2, concurrency: 5, maxFixAttempts: 3 },
|
|
402
|
+
'context-generation': { provider: 'gemini', model: 'gemini-2.5-flash' },
|
|
403
|
+
'doc-generation': { provider: 'gemini', model: 'gemini-2.5-flash' },
|
|
404
|
+
enrichment: { provider: 'gemini', model: 'gemini-2.5-flash' }
|
|
405
|
+
}
|
|
406
|
+
},
|
|
407
|
+
openai: {
|
|
408
|
+
provider: 'openai', defaultModel: 'gpt-5.4',
|
|
409
|
+
stages: {
|
|
410
|
+
decomposition: { provider: 'openai', model: 'gpt-5.4' },
|
|
411
|
+
validation: { provider: 'openai', model: 'gpt-5.4', useContextualSelection: true, epicConcurrency: 2, concurrency: 5, maxFixAttempts: 3 },
|
|
412
|
+
'context-generation': { provider: 'openai', model: 'gpt-5.4' },
|
|
413
|
+
'doc-generation': { provider: 'openai', model: 'gpt-5.4' },
|
|
414
|
+
enrichment: { provider: 'openai', model: 'gpt-5.4' }
|
|
415
|
+
}
|
|
416
|
+
},
|
|
417
|
+
xiaomi: {
|
|
418
|
+
provider: 'xiaomi', defaultModel: 'mimo-v2-pro',
|
|
419
|
+
stages: {
|
|
420
|
+
decomposition: { provider: 'xiaomi', model: 'mimo-v2-pro' },
|
|
421
|
+
validation: { provider: 'xiaomi', model: 'mimo-v2-flash', useContextualSelection: true, epicConcurrency: 2, concurrency: 5, maxFixAttempts: 3 },
|
|
422
|
+
'context-generation': { provider: 'xiaomi', model: 'mimo-v2-pro' },
|
|
423
|
+
'doc-generation': { provider: 'xiaomi', model: 'mimo-v2-pro' },
|
|
424
|
+
enrichment: { provider: 'xiaomi', model: 'mimo-v2-pro' }
|
|
425
|
+
}
|
|
271
426
|
}
|
|
272
427
|
},
|
|
273
428
|
agents: [
|
|
@@ -276,11 +431,6 @@ class ProjectInitiator {
|
|
|
276
431
|
instruction: 'epic-story-decomposer.md',
|
|
277
432
|
stage: 'decomposition'
|
|
278
433
|
},
|
|
279
|
-
{
|
|
280
|
-
name: 'doc-distributor',
|
|
281
|
-
instruction: 'doc-distributor.md',
|
|
282
|
-
stage: 'doc-distribution'
|
|
283
|
-
},
|
|
284
434
|
{
|
|
285
435
|
name: 'project-context-extractor',
|
|
286
436
|
instruction: 'project-context-extractor.md',
|
|
@@ -291,6 +441,26 @@ class ProjectInitiator {
|
|
|
291
441
|
instruction: 'agent-selector.md',
|
|
292
442
|
stage: 'validation'
|
|
293
443
|
},
|
|
444
|
+
{
|
|
445
|
+
name: 'context-writer-epic',
|
|
446
|
+
instruction: 'context-writer-epic.md',
|
|
447
|
+
stage: 'context-generation'
|
|
448
|
+
},
|
|
449
|
+
{
|
|
450
|
+
name: 'context-writer-story',
|
|
451
|
+
instruction: 'context-writer-story.md',
|
|
452
|
+
stage: 'context-generation'
|
|
453
|
+
},
|
|
454
|
+
{
|
|
455
|
+
name: 'doc-writer-epic',
|
|
456
|
+
instruction: 'doc-writer-epic.md',
|
|
457
|
+
stage: 'doc-generation'
|
|
458
|
+
},
|
|
459
|
+
{
|
|
460
|
+
name: 'doc-writer-story',
|
|
461
|
+
instruction: 'doc-writer-story.md',
|
|
462
|
+
stage: 'doc-generation'
|
|
463
|
+
},
|
|
294
464
|
{
|
|
295
465
|
name: 'story-doc-enricher',
|
|
296
466
|
instruction: 'story-doc-enricher.md',
|
|
@@ -307,11 +477,48 @@ class ProjectInitiator {
|
|
|
307
477
|
provider: 'claude',
|
|
308
478
|
model: 'claude-opus-4-6'
|
|
309
479
|
},
|
|
310
|
-
'
|
|
480
|
+
'context-generation': {
|
|
311
481
|
provider: 'claude',
|
|
312
482
|
model: 'claude-sonnet-4-6'
|
|
313
483
|
}
|
|
314
484
|
},
|
|
485
|
+
providerPresets: {
|
|
486
|
+
claude: {
|
|
487
|
+
provider: 'claude', defaultModel: 'claude-sonnet-4-6',
|
|
488
|
+
stages: {
|
|
489
|
+
decomposition: { provider: 'claude', model: 'claude-opus-4-6' },
|
|
490
|
+
'context-generation': { provider: 'claude', model: 'claude-sonnet-4-6' }
|
|
491
|
+
}
|
|
492
|
+
},
|
|
493
|
+
gemini: {
|
|
494
|
+
provider: 'gemini', defaultModel: 'gemini-2.5-flash',
|
|
495
|
+
stages: {
|
|
496
|
+
decomposition: { provider: 'gemini', model: 'gemini-2.5-pro' },
|
|
497
|
+
'context-generation': { provider: 'gemini', model: 'gemini-2.5-flash' }
|
|
498
|
+
}
|
|
499
|
+
},
|
|
500
|
+
openai: {
|
|
501
|
+
provider: 'openai', defaultModel: 'gpt-5.4',
|
|
502
|
+
stages: {
|
|
503
|
+
decomposition: { provider: 'openai', model: 'gpt-5.4' },
|
|
504
|
+
'context-generation': { provider: 'openai', model: 'gpt-5.4' }
|
|
505
|
+
}
|
|
506
|
+
},
|
|
507
|
+
xiaomi: {
|
|
508
|
+
provider: 'xiaomi', defaultModel: 'mimo-v2-pro',
|
|
509
|
+
stages: {
|
|
510
|
+
decomposition: { provider: 'xiaomi', model: 'mimo-v2-pro' },
|
|
511
|
+
'context-generation': { provider: 'xiaomi', model: 'mimo-v2-pro' }
|
|
512
|
+
}
|
|
513
|
+
},
|
|
514
|
+
local: {
|
|
515
|
+
provider: 'local', defaultModel: 'qwen/qwen3-coder-next',
|
|
516
|
+
stages: {
|
|
517
|
+
decomposition: { provider: 'local', model: 'qwen/qwen3-coder-next' },
|
|
518
|
+
'context-generation': { provider: 'local', model: 'qwen/qwen3-coder-next' }
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
},
|
|
315
522
|
agents: [
|
|
316
523
|
{
|
|
317
524
|
name: 'task-subtask-decomposer',
|
|
@@ -329,6 +536,72 @@ class ProjectInitiator {
|
|
|
329
536
|
stage: 'decomposition'
|
|
330
537
|
}
|
|
331
538
|
]
|
|
539
|
+
},
|
|
540
|
+
{
|
|
541
|
+
name: 'run',
|
|
542
|
+
provider: 'claude',
|
|
543
|
+
defaultModel: 'claude-sonnet-4-6',
|
|
544
|
+
stages: {
|
|
545
|
+
'code-generation': {
|
|
546
|
+
provider: 'claude',
|
|
547
|
+
model: 'claude-sonnet-4-6'
|
|
548
|
+
},
|
|
549
|
+
'code-validation': {
|
|
550
|
+
provider: 'claude',
|
|
551
|
+
model: 'claude-sonnet-4-6'
|
|
552
|
+
}
|
|
553
|
+
},
|
|
554
|
+
providerPresets: {
|
|
555
|
+
claude: {
|
|
556
|
+
provider: 'claude', defaultModel: 'claude-sonnet-4-6',
|
|
557
|
+
stages: {
|
|
558
|
+
'code-generation': { provider: 'claude', model: 'claude-sonnet-4-6' },
|
|
559
|
+
'code-validation': { provider: 'claude', model: 'claude-sonnet-4-6' }
|
|
560
|
+
}
|
|
561
|
+
},
|
|
562
|
+
gemini: {
|
|
563
|
+
provider: 'gemini', defaultModel: 'gemini-2.5-flash',
|
|
564
|
+
stages: {
|
|
565
|
+
'code-generation': { provider: 'gemini', model: 'gemini-2.5-flash' },
|
|
566
|
+
'code-validation': { provider: 'gemini', model: 'gemini-2.5-flash' }
|
|
567
|
+
}
|
|
568
|
+
},
|
|
569
|
+
openai: {
|
|
570
|
+
provider: 'openai', defaultModel: 'gpt-5.4',
|
|
571
|
+
stages: {
|
|
572
|
+
'code-generation': { provider: 'openai', model: 'gpt-5.4' },
|
|
573
|
+
'code-validation': { provider: 'openai', model: 'gpt-5.4' }
|
|
574
|
+
}
|
|
575
|
+
},
|
|
576
|
+
xiaomi: {
|
|
577
|
+
provider: 'xiaomi', defaultModel: 'mimo-v2-pro',
|
|
578
|
+
stages: {
|
|
579
|
+
'code-generation': { provider: 'xiaomi', model: 'mimo-v2-pro' },
|
|
580
|
+
'code-validation': { provider: 'xiaomi', model: 'mimo-v2-flash' }
|
|
581
|
+
}
|
|
582
|
+
},
|
|
583
|
+
local: {
|
|
584
|
+
provider: 'local', defaultModel: 'qwen/qwen3-coder-next',
|
|
585
|
+
stages: {
|
|
586
|
+
'code-generation': { provider: 'local', model: 'qwen/qwen3-coder-next' },
|
|
587
|
+
'code-validation': { provider: 'local', model: 'qwen/qwen3-coder-next' }
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
},
|
|
591
|
+
maxValidationIterations: 3,
|
|
592
|
+
acceptanceThreshold: 80,
|
|
593
|
+
agents: [
|
|
594
|
+
{
|
|
595
|
+
name: 'code-implementer',
|
|
596
|
+
instruction: 'code-implementer.md',
|
|
597
|
+
stage: 'code-generation'
|
|
598
|
+
},
|
|
599
|
+
{
|
|
600
|
+
name: 'code-validator',
|
|
601
|
+
instruction: 'code-validator.md',
|
|
602
|
+
stage: 'code-validation'
|
|
603
|
+
}
|
|
604
|
+
]
|
|
332
605
|
}
|
|
333
606
|
],
|
|
334
607
|
missionGenerator: {
|
|
@@ -340,7 +613,8 @@ class ProjectInitiator {
|
|
|
340
613
|
costThresholds: {
|
|
341
614
|
'sponsor-call': 2,
|
|
342
615
|
'sprint-planning': 2,
|
|
343
|
-
'seed': 2
|
|
616
|
+
'seed': 2,
|
|
617
|
+
'run': 2
|
|
344
618
|
},
|
|
345
619
|
questionnaire: {
|
|
346
620
|
defaults: {
|
|
@@ -449,26 +723,26 @@ class ProjectInitiator {
|
|
|
449
723
|
|
|
450
724
|
// OpenAI models (prices per 1M tokens in USD)
|
|
451
725
|
// Source: https://openai.com/api/pricing
|
|
452
|
-
'gpt-5.
|
|
726
|
+
'gpt-5.4': {
|
|
453
727
|
provider: 'openai',
|
|
454
|
-
displayName: 'GPT-5.
|
|
728
|
+
displayName: 'GPT-5.4',
|
|
455
729
|
pricing: {
|
|
456
|
-
input:
|
|
457
|
-
output:
|
|
730
|
+
input: 2.50,
|
|
731
|
+
output: 15.00,
|
|
458
732
|
unit: 'million',
|
|
459
733
|
source: 'https://openai.com/api/pricing',
|
|
460
|
-
lastUpdated: '2026-
|
|
734
|
+
lastUpdated: '2026-03-06'
|
|
461
735
|
}
|
|
462
736
|
},
|
|
463
|
-
'gpt-5.
|
|
737
|
+
'gpt-5.4-pro': {
|
|
464
738
|
provider: 'openai',
|
|
465
|
-
displayName: 'GPT-5.
|
|
739
|
+
displayName: 'GPT-5.4 Pro',
|
|
466
740
|
pricing: {
|
|
467
|
-
input:
|
|
468
|
-
output:
|
|
741
|
+
input: 30.00,
|
|
742
|
+
output: 180.00,
|
|
469
743
|
unit: 'million',
|
|
470
744
|
source: 'https://openai.com/api/pricing',
|
|
471
|
-
lastUpdated: '2026-
|
|
745
|
+
lastUpdated: '2026-03-06'
|
|
472
746
|
}
|
|
473
747
|
},
|
|
474
748
|
'gpt-5-mini': {
|
|
@@ -482,50 +756,53 @@ class ProjectInitiator {
|
|
|
482
756
|
lastUpdated: '2026-02-24'
|
|
483
757
|
}
|
|
484
758
|
},
|
|
485
|
-
'
|
|
759
|
+
'gpt-5-nano': {
|
|
486
760
|
provider: 'openai',
|
|
487
|
-
displayName: '
|
|
761
|
+
displayName: 'GPT-5 nano',
|
|
488
762
|
pricing: {
|
|
489
|
-
input:
|
|
490
|
-
output:
|
|
763
|
+
input: 0.05,
|
|
764
|
+
output: 0.40,
|
|
491
765
|
unit: 'million',
|
|
492
766
|
source: 'https://openai.com/api/pricing',
|
|
493
|
-
lastUpdated: '2026-
|
|
767
|
+
lastUpdated: '2026-03-06'
|
|
494
768
|
}
|
|
495
769
|
},
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
770
|
+
|
|
771
|
+
// Xiaomi MiMo models (prices per 1M tokens in USD)
|
|
772
|
+
// Source: https://platform.xiaomimimo.com
|
|
773
|
+
'mimo-v2-flash': {
|
|
774
|
+
provider: 'xiaomi',
|
|
775
|
+
displayName: 'MiMo V2 Flash',
|
|
499
776
|
pricing: {
|
|
500
|
-
input:
|
|
501
|
-
output:
|
|
777
|
+
input: 0.09,
|
|
778
|
+
output: 0.29,
|
|
502
779
|
unit: 'million',
|
|
503
|
-
source: 'https://
|
|
504
|
-
lastUpdated: '2026-
|
|
780
|
+
source: 'https://platform.xiaomimimo.com',
|
|
781
|
+
lastUpdated: '2026-03-25'
|
|
505
782
|
}
|
|
506
783
|
},
|
|
507
|
-
'
|
|
508
|
-
provider: '
|
|
509
|
-
displayName: '
|
|
784
|
+
'mimo-v2-pro': {
|
|
785
|
+
provider: 'xiaomi',
|
|
786
|
+
displayName: 'MiMo V2 Pro',
|
|
510
787
|
pricing: {
|
|
511
|
-
input:
|
|
512
|
-
output:
|
|
788
|
+
input: 1.00,
|
|
789
|
+
output: 3.00,
|
|
513
790
|
unit: 'million',
|
|
514
|
-
source: 'https://
|
|
515
|
-
lastUpdated: '2026-
|
|
791
|
+
source: 'https://platform.xiaomimimo.com',
|
|
792
|
+
lastUpdated: '2026-03-25'
|
|
516
793
|
}
|
|
517
794
|
},
|
|
518
|
-
'
|
|
519
|
-
provider: '
|
|
520
|
-
displayName: '
|
|
795
|
+
'mimo-v2-omni': {
|
|
796
|
+
provider: 'xiaomi',
|
|
797
|
+
displayName: 'MiMo V2 Omni',
|
|
521
798
|
pricing: {
|
|
522
|
-
input:
|
|
523
|
-
output:
|
|
799
|
+
input: 0.40,
|
|
800
|
+
output: 2.00,
|
|
524
801
|
unit: 'million',
|
|
525
|
-
source: 'https://
|
|
526
|
-
lastUpdated: '2026-
|
|
802
|
+
source: 'https://platform.xiaomimimo.com',
|
|
803
|
+
lastUpdated: '2026-03-25'
|
|
527
804
|
}
|
|
528
|
-
}
|
|
805
|
+
},
|
|
529
806
|
}
|
|
530
807
|
}
|
|
531
808
|
};
|
|
@@ -549,7 +826,7 @@ class ProjectInitiator {
|
|
|
549
826
|
|
|
550
827
|
// Upgrade null cost thresholds to default (2 USD)
|
|
551
828
|
if (mergedConfig.settings?.costThresholds) {
|
|
552
|
-
for (const ceremony of ['sponsor-call', 'sprint-planning', 'seed']) {
|
|
829
|
+
for (const ceremony of ['sponsor-call', 'sprint-planning', 'seed', 'run']) {
|
|
553
830
|
if (mergedConfig.settings.costThresholds[ceremony] === null) {
|
|
554
831
|
mergedConfig.settings.costThresholds[ceremony] = 2;
|
|
555
832
|
}
|
|
@@ -611,6 +888,11 @@ class ProjectInitiator {
|
|
|
611
888
|
key: 'OPENAI_API_KEY',
|
|
612
889
|
comment: 'OpenAI API Key (alternative LLM provider)',
|
|
613
890
|
url: 'https://platform.openai.com/api-keys'
|
|
891
|
+
},
|
|
892
|
+
{
|
|
893
|
+
key: 'XIAOMI_API_KEY',
|
|
894
|
+
comment: 'Xiaomi MiMo API Key (alternative LLM provider)',
|
|
895
|
+
url: 'https://platform.xiaomimimo.com/#/console/api-keys'
|
|
614
896
|
}
|
|
615
897
|
];
|
|
616
898
|
|
|
@@ -714,11 +996,11 @@ class ProjectInitiator {
|
|
|
714
996
|
|
|
715
997
|
// Create directory structure
|
|
716
998
|
if (!fs.existsSync(vitepressDir)) {
|
|
717
|
-
|
|
999
|
+
mkdirp(vitepressDir);
|
|
718
1000
|
}
|
|
719
1001
|
|
|
720
1002
|
if (!fs.existsSync(publicDir)) {
|
|
721
|
-
|
|
1003
|
+
mkdirp(publicDir);
|
|
722
1004
|
}
|
|
723
1005
|
|
|
724
1006
|
// Create VitePress config
|
|
@@ -765,7 +1047,7 @@ Documentation for this project will be generated automatically once the project
|
|
|
765
1047
|
*/
|
|
766
1048
|
writeProgress(progress, progressPath) {
|
|
767
1049
|
if (!fs.existsSync(this.avcDir)) {
|
|
768
|
-
|
|
1050
|
+
mkdirp(this.avcDir);
|
|
769
1051
|
}
|
|
770
1052
|
fs.writeFileSync(progressPath, JSON.stringify(progress, null, 2), 'utf8');
|
|
771
1053
|
}
|
|
@@ -885,25 +1167,117 @@ Documentation for this project will be generated automatically once the project
|
|
|
885
1167
|
const envVarMap = {
|
|
886
1168
|
'claude': 'ANTHROPIC_API_KEY',
|
|
887
1169
|
'gemini': 'GEMINI_API_KEY',
|
|
888
|
-
'openai': 'OPENAI_API_KEY'
|
|
1170
|
+
'openai': 'OPENAI_API_KEY',
|
|
1171
|
+
'xiaomi': 'XIAOMI_API_KEY'
|
|
889
1172
|
};
|
|
890
1173
|
|
|
891
1174
|
const urlMap = {
|
|
892
1175
|
'claude': 'https://console.anthropic.com/settings/keys',
|
|
893
1176
|
'gemini': 'https://aistudio.google.com/app/apikey',
|
|
894
|
-
'openai': 'https://platform.openai.com/api-keys'
|
|
1177
|
+
'openai': 'https://platform.openai.com/api-keys',
|
|
1178
|
+
'xiaomi': 'https://platform.xiaomimimo.com/#/console/api-keys'
|
|
895
1179
|
};
|
|
896
1180
|
|
|
1181
|
+
// Check if a provider has any valid auth credential (API key OR oauth token)
|
|
1182
|
+
const hasProviderAuth = (provider) => {
|
|
1183
|
+
if (provider === 'openai') {
|
|
1184
|
+
const oauthFile = path.join(this.projectRoot, '.avc', 'openai-oauth.json');
|
|
1185
|
+
return !!(process.env.OPENAI_API_KEY ||
|
|
1186
|
+
(process.env.OPENAI_AUTH_MODE === 'oauth' && fs.existsSync(oauthFile)));
|
|
1187
|
+
}
|
|
1188
|
+
return !!process.env[envVarMap[provider]];
|
|
1189
|
+
};
|
|
1190
|
+
|
|
1191
|
+
const authLabel = (provider) => {
|
|
1192
|
+
if (provider === 'openai' && process.env.OPENAI_AUTH_MODE === 'oauth') return 'OpenAI OAuth token';
|
|
1193
|
+
return envVarMap[provider];
|
|
1194
|
+
};
|
|
1195
|
+
|
|
1196
|
+
// Local provider needs no API key — skip validation entirely
|
|
1197
|
+
if (mainProvider === 'local') {
|
|
1198
|
+
// Still validate the validation provider if it's a cloud provider
|
|
1199
|
+
if (validationEnabled && validationProvider && validationProvider !== 'local') {
|
|
1200
|
+
const validationEnvVar = envVarMap[validationProvider];
|
|
1201
|
+
if (!validationEnvVar) {
|
|
1202
|
+
return {
|
|
1203
|
+
valid: false,
|
|
1204
|
+
message: `Unknown validation provider "${validationProvider}".\n Supported providers: claude, gemini, openai, xiaomi, local`
|
|
1205
|
+
};
|
|
1206
|
+
}
|
|
1207
|
+
if (!hasProviderAuth(validationProvider)) {
|
|
1208
|
+
return {
|
|
1209
|
+
valid: false,
|
|
1210
|
+
validationProviderMissing: true,
|
|
1211
|
+
message: `${validationEnvVar} not found in .env file (needed for validation provider).`
|
|
1212
|
+
};
|
|
1213
|
+
}
|
|
1214
|
+
}
|
|
1215
|
+
return { valid: true };
|
|
1216
|
+
}
|
|
1217
|
+
|
|
897
1218
|
// Validate main provider
|
|
898
1219
|
const mainEnvVar = envVarMap[mainProvider];
|
|
899
1220
|
if (!mainEnvVar) {
|
|
900
1221
|
return {
|
|
901
1222
|
valid: false,
|
|
902
|
-
message: `Unknown provider "${mainProvider}".\n Supported providers: claude, gemini, openai`
|
|
1223
|
+
message: `Unknown provider "${mainProvider}".\n Supported providers: claude, gemini, openai, xiaomi, local`
|
|
903
1224
|
};
|
|
904
1225
|
}
|
|
905
1226
|
|
|
906
|
-
|
|
1227
|
+
// Helper: switch ALL ceremonies in avc.json to the fallback provider/model.
|
|
1228
|
+
// Updates ceremony-level provider + defaultModel and every stage override.
|
|
1229
|
+
const switchCeremonyProvider = (resolved) => {
|
|
1230
|
+
try {
|
|
1231
|
+
const freshConfig = JSON.parse(fs.readFileSync(this.avcConfigPath, 'utf8'));
|
|
1232
|
+
for (const c of (freshConfig.settings?.ceremonies || [])) {
|
|
1233
|
+
const preset = c.providerPresets?.[resolved.provider];
|
|
1234
|
+
const fallbackModel = preset?.defaultModel || resolved.model;
|
|
1235
|
+
|
|
1236
|
+
c.provider = resolved.provider;
|
|
1237
|
+
c.defaultModel = fallbackModel;
|
|
1238
|
+
|
|
1239
|
+
// Apply preset stage config (model + extra props like concurrency)
|
|
1240
|
+
if (c.stages && typeof c.stages === 'object') {
|
|
1241
|
+
for (const stageName of Object.keys(c.stages)) {
|
|
1242
|
+
const presetStage = preset?.stages?.[stageName];
|
|
1243
|
+
if (presetStage) {
|
|
1244
|
+
Object.assign(c.stages[stageName], presetStage);
|
|
1245
|
+
} else {
|
|
1246
|
+
c.stages[stageName].provider = resolved.provider;
|
|
1247
|
+
c.stages[stageName].model = fallbackModel;
|
|
1248
|
+
}
|
|
1249
|
+
}
|
|
1250
|
+
}
|
|
1251
|
+
|
|
1252
|
+
// Apply preset validation models or fall back to default model
|
|
1253
|
+
if (c.validation && typeof c.validation === 'object') {
|
|
1254
|
+
const presetVal = preset?.validation;
|
|
1255
|
+
c.validation.provider = resolved.provider;
|
|
1256
|
+
c.validation.model = presetVal?.model || fallbackModel;
|
|
1257
|
+
for (const [k, v] of Object.entries(c.validation)) {
|
|
1258
|
+
if (v && typeof v === 'object' && typeof v.provider === 'string') {
|
|
1259
|
+
const presetSub = presetVal?.[k];
|
|
1260
|
+
v.provider = resolved.provider;
|
|
1261
|
+
v.model = presetSub?.model || presetVal?.model || fallbackModel;
|
|
1262
|
+
}
|
|
1263
|
+
}
|
|
1264
|
+
}
|
|
1265
|
+
}
|
|
1266
|
+
fs.writeFileSync(this.avcConfigPath, JSON.stringify(freshConfig, null, 2), 'utf8');
|
|
1267
|
+
fileLog('INFO', `Switched all ceremony models to ${resolved.provider} using presets in avc.json`);
|
|
1268
|
+
} catch (writeErr) {
|
|
1269
|
+
fileLog('WARN', `Could not persist provider switch: ${writeErr.message}`);
|
|
1270
|
+
}
|
|
1271
|
+
};
|
|
1272
|
+
|
|
1273
|
+
if (!hasProviderAuth(mainProvider)) {
|
|
1274
|
+
// Try to find any available fallback provider
|
|
1275
|
+
const resolved = await LLMProvider.resolveAvailableProvider(mainProvider, mainModel);
|
|
1276
|
+
if (resolved.fellBack) {
|
|
1277
|
+
fileLog('WARN', `Pre-ceremony fallback: ${mainProvider}→${resolved.provider} (no API key for ${mainProvider})`);
|
|
1278
|
+
switchCeremonyProvider(resolved);
|
|
1279
|
+
return { valid: true };
|
|
1280
|
+
}
|
|
907
1281
|
return {
|
|
908
1282
|
valid: false,
|
|
909
1283
|
message: `${mainEnvVar} not found in .env file.\n\n Steps to fix:\n 1. Open .env file in the current directory\n 2. Add your API key: ${mainEnvVar}=your-key-here\n 3. Save the file and run /sponsor-call again\n\n Get your API key:\n • ${urlMap[mainProvider]}`
|
|
@@ -915,6 +1289,13 @@ Documentation for this project will be generated automatically once the project
|
|
|
915
1289
|
try {
|
|
916
1290
|
result = await LLMProvider.validate(mainProvider, mainModel);
|
|
917
1291
|
} catch (error) {
|
|
1292
|
+
// API key exists but validation failed — try fallback
|
|
1293
|
+
const resolved = await LLMProvider.resolveAvailableProvider(mainProvider, mainModel);
|
|
1294
|
+
if (resolved.fellBack) {
|
|
1295
|
+
fileLog('WARN', `Pre-ceremony fallback after validation failure: ${mainProvider}→${resolved.provider}`);
|
|
1296
|
+
switchCeremonyProvider(resolved);
|
|
1297
|
+
return { valid: true };
|
|
1298
|
+
}
|
|
918
1299
|
const parsedError = this.parseApiError(error.message || error);
|
|
919
1300
|
return {
|
|
920
1301
|
valid: false,
|
|
@@ -923,6 +1304,13 @@ Documentation for this project will be generated automatically once the project
|
|
|
923
1304
|
}
|
|
924
1305
|
|
|
925
1306
|
if (!result.valid) {
|
|
1307
|
+
// API call failed — try fallback
|
|
1308
|
+
const resolved = await LLMProvider.resolveAvailableProvider(mainProvider, mainModel);
|
|
1309
|
+
if (resolved.fellBack) {
|
|
1310
|
+
fileLog('WARN', `Pre-ceremony fallback after API failure: ${mainProvider}→${resolved.provider}`);
|
|
1311
|
+
switchCeremonyProvider(resolved);
|
|
1312
|
+
return { valid: true };
|
|
1313
|
+
}
|
|
926
1314
|
const parsedError = this.parseApiError(result.error || 'Unknown error');
|
|
927
1315
|
return {
|
|
928
1316
|
valid: false,
|
|
@@ -931,47 +1319,82 @@ Documentation for this project will be generated automatically once the project
|
|
|
931
1319
|
}
|
|
932
1320
|
|
|
933
1321
|
// Validate validation provider if enabled and different from main
|
|
934
|
-
if (validationEnabled && validationProvider && validationProvider !== mainProvider) {
|
|
1322
|
+
if (validationEnabled && validationProvider && validationProvider !== mainProvider && validationProvider !== 'local') {
|
|
935
1323
|
const validationEnvVar = envVarMap[validationProvider];
|
|
936
1324
|
|
|
937
1325
|
if (!validationEnvVar) {
|
|
938
1326
|
return {
|
|
939
1327
|
valid: false,
|
|
940
|
-
message: `Unknown validation provider "${validationProvider}".\n Supported providers: claude, gemini, openai`
|
|
1328
|
+
message: `Unknown validation provider "${validationProvider}".\n Supported providers: claude, gemini, openai, xiaomi, local`
|
|
941
1329
|
};
|
|
942
1330
|
}
|
|
943
1331
|
|
|
944
|
-
if (!
|
|
945
|
-
//
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
1332
|
+
if (!hasProviderAuth(validationProvider)) {
|
|
1333
|
+
// Auto-switch validation to use the main provider (which we already verified works)
|
|
1334
|
+
fileLog('WARN', `Validation provider ${validationProvider} has no key — switching to main provider ${mainProvider}`);
|
|
1335
|
+
try {
|
|
1336
|
+
const freshConfig = JSON.parse(fs.readFileSync(this.avcConfigPath, 'utf8'));
|
|
1337
|
+
for (const c of (freshConfig.settings?.ceremonies || [])) {
|
|
1338
|
+
if (c.validation && typeof c.validation === 'object') {
|
|
1339
|
+
c.validation.provider = mainProvider;
|
|
1340
|
+
c.validation.model = mainModel;
|
|
1341
|
+
for (const [k, v] of Object.entries(c.validation)) {
|
|
1342
|
+
if (v && typeof v === 'object' && typeof v.provider === 'string') {
|
|
1343
|
+
v.provider = mainProvider;
|
|
1344
|
+
v.model = mainModel;
|
|
1345
|
+
}
|
|
1346
|
+
}
|
|
1347
|
+
}
|
|
1348
|
+
}
|
|
1349
|
+
fs.writeFileSync(this.avcConfigPath, JSON.stringify(freshConfig, null, 2), 'utf8');
|
|
1350
|
+
} catch {}
|
|
1351
|
+
return { valid: true };
|
|
957
1352
|
}
|
|
958
1353
|
|
|
959
1354
|
try {
|
|
960
1355
|
result = await LLMProvider.validate(validationProvider, validationModel);
|
|
961
1356
|
} catch (error) {
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
1357
|
+
// Validation provider failed — auto-switch to main provider
|
|
1358
|
+
fileLog('WARN', `Validation provider ${validationProvider} failed — switching to main provider ${mainProvider}`);
|
|
1359
|
+
try {
|
|
1360
|
+
const freshConfig = JSON.parse(fs.readFileSync(this.avcConfigPath, 'utf8'));
|
|
1361
|
+
for (const c of (freshConfig.settings?.ceremonies || [])) {
|
|
1362
|
+
if (c.validation && typeof c.validation === 'object') {
|
|
1363
|
+
c.validation.provider = mainProvider;
|
|
1364
|
+
c.validation.model = mainModel;
|
|
1365
|
+
for (const [k, v] of Object.entries(c.validation)) {
|
|
1366
|
+
if (v && typeof v === 'object' && typeof v.provider === 'string') {
|
|
1367
|
+
v.provider = mainProvider;
|
|
1368
|
+
v.model = mainModel;
|
|
1369
|
+
}
|
|
1370
|
+
}
|
|
1371
|
+
}
|
|
1372
|
+
}
|
|
1373
|
+
fs.writeFileSync(this.avcConfigPath, JSON.stringify(freshConfig, null, 2), 'utf8');
|
|
1374
|
+
} catch {}
|
|
1375
|
+
return { valid: true };
|
|
967
1376
|
}
|
|
968
1377
|
|
|
969
1378
|
if (!result.valid) {
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
1379
|
+
// Validation provider API call failed — auto-switch to main provider
|
|
1380
|
+
fileLog('WARN', `Validation provider ${validationProvider} API call failed — switching to main provider ${mainProvider}`);
|
|
1381
|
+
try {
|
|
1382
|
+
const freshConfig = JSON.parse(fs.readFileSync(this.avcConfigPath, 'utf8'));
|
|
1383
|
+
for (const c of (freshConfig.settings?.ceremonies || [])) {
|
|
1384
|
+
if (c.validation && typeof c.validation === 'object') {
|
|
1385
|
+
c.validation.provider = mainProvider;
|
|
1386
|
+
c.validation.model = mainModel;
|
|
1387
|
+
for (const [k, v] of Object.entries(c.validation)) {
|
|
1388
|
+
if (v && typeof v === 'object' && typeof v.provider === 'string') {
|
|
1389
|
+
v.provider = mainProvider;
|
|
1390
|
+
v.model = mainModel;
|
|
1391
|
+
}
|
|
1392
|
+
}
|
|
1393
|
+
}
|
|
1394
|
+
}
|
|
1395
|
+
fs.writeFileSync(this.avcConfigPath, JSON.stringify(freshConfig, null, 2), 'utf8');
|
|
1396
|
+
} catch {}
|
|
1397
|
+
return { valid: true };
|
|
975
1398
|
}
|
|
976
1399
|
|
|
977
1400
|
}
|
|
@@ -1080,7 +1503,7 @@ Documentation for this project will be generated automatically once the project
|
|
|
1080
1503
|
avcConfig: this.hasAvcConfig(),
|
|
1081
1504
|
});
|
|
1082
1505
|
|
|
1083
|
-
sendOutput('Project initialized —
|
|
1506
|
+
sendOutput('Project initialized — open the Kanban board to get started.');
|
|
1084
1507
|
|
|
1085
1508
|
return;
|
|
1086
1509
|
}
|
|
@@ -1132,8 +1555,6 @@ Documentation for this project will be generated automatically once the project
|
|
|
1132
1555
|
});
|
|
1133
1556
|
|
|
1134
1557
|
ceremonies.forEach(c => {
|
|
1135
|
-
const ceremonyUrl = `https://agilevibecoding.org/ceremonies/${c.name}.html`;
|
|
1136
|
-
|
|
1137
1558
|
const hasMainKey = configurator.availableProviders.includes(c.mainProvider);
|
|
1138
1559
|
const stageDetails = {};
|
|
1139
1560
|
Object.keys(c.stages).forEach(stageName => {
|
|
@@ -1441,13 +1862,13 @@ Documentation for this project will be generated automatically once the project
|
|
|
1441
1862
|
* @returns {Promise<object>} Result with epicsCreated, storiesCreated, tokenUsage, model
|
|
1442
1863
|
*/
|
|
1443
1864
|
async sprintPlanningWithCallback(progressCallback = null, options = {}) {
|
|
1444
|
-
fileLog('INFO', 'sprintPlanningWithCallback() called', { projectRoot: this.projectRoot });
|
|
1865
|
+
fileLog('INFO', 'sprintPlanningWithCallback() called', { projectRoot: this.projectRoot, resumeFrom: options.resumeFrom || null });
|
|
1445
1866
|
if (!this.isAvcProject()) {
|
|
1446
1867
|
throw new Error('Project not initialized. Run /init first.');
|
|
1447
1868
|
}
|
|
1448
1869
|
const { SprintPlanningProcessor } = await import('./sprint-planning-processor.js');
|
|
1449
1870
|
const processor = new SprintPlanningProcessor(options);
|
|
1450
|
-
return await processor.execute(progressCallback);
|
|
1871
|
+
return await processor.execute(progressCallback, { resumeFrom: options.resumeFrom || null });
|
|
1451
1872
|
}
|
|
1452
1873
|
|
|
1453
1874
|
/**
|
|
@@ -1749,6 +2170,7 @@ Documentation for this project will be generated automatically once the project
|
|
|
1749
2170
|
sendIndented('• ANTHROPIC_API_KEY', 1);
|
|
1750
2171
|
sendIndented('• GEMINI_API_KEY', 1);
|
|
1751
2172
|
sendIndented('• OPENAI_API_KEY', 1);
|
|
2173
|
+
sendIndented('• XIAOMI_API_KEY', 1);
|
|
1752
2174
|
sendIndented('• (and any other API keys you added)', 1);
|
|
1753
2175
|
sendOutput('If these API keys are not used elsewhere in your project,');
|
|
1754
2176
|
sendOutput('you may want to manually delete the .env file or remove');
|