@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.
Files changed (262) hide show
  1. package/README.md +475 -3
  2. package/cli/agents/agent-selector.md +23 -0
  3. package/cli/agents/code-implementer.md +117 -0
  4. package/cli/agents/code-validator.md +80 -0
  5. package/cli/agents/context-reviewer-epic.md +101 -0
  6. package/cli/agents/context-reviewer-story.md +92 -0
  7. package/cli/agents/context-writer-epic.md +145 -0
  8. package/cli/agents/context-writer-story.md +111 -0
  9. package/cli/agents/doc-writer-epic.md +42 -0
  10. package/cli/agents/doc-writer-story.md +43 -0
  11. package/cli/agents/duplicate-detector.md +110 -0
  12. package/cli/agents/epic-story-decomposer.md +318 -39
  13. package/cli/agents/mission-scope-generator.md +68 -4
  14. package/cli/agents/mission-scope-validator.md +40 -6
  15. package/cli/agents/project-context-extractor.md +21 -6
  16. package/cli/agents/scaffolding-generator.md +99 -0
  17. package/cli/agents/seed-validator.md +71 -0
  18. package/cli/agents/story-scope-reviewer.md +147 -0
  19. package/cli/agents/story-splitter.md +83 -0
  20. package/cli/agents/validator-documentation.json +31 -0
  21. package/cli/agents/validator-documentation.md +3 -1
  22. package/cli/api-reference-tool.js +368 -0
  23. package/cli/checks/catalog.json +76 -0
  24. package/cli/checks/code/quality.json +26 -0
  25. package/cli/checks/code/testing.json +14 -0
  26. package/cli/checks/code/traceability.json +26 -0
  27. package/cli/checks/cross-refs/epic.json +171 -0
  28. package/cli/checks/cross-refs/story.json +149 -0
  29. package/cli/checks/epic/api.json +114 -0
  30. package/cli/checks/epic/backend.json +126 -0
  31. package/cli/checks/epic/cloud.json +126 -0
  32. package/cli/checks/epic/data.json +102 -0
  33. package/cli/checks/epic/database.json +114 -0
  34. package/cli/checks/epic/developer.json +182 -0
  35. package/cli/checks/epic/devops.json +174 -0
  36. package/cli/checks/epic/frontend.json +162 -0
  37. package/cli/checks/epic/mobile.json +102 -0
  38. package/cli/checks/epic/qa.json +90 -0
  39. package/cli/checks/epic/security.json +184 -0
  40. package/cli/checks/epic/solution-architect.json +192 -0
  41. package/cli/checks/epic/test-architect.json +90 -0
  42. package/cli/checks/epic/ui.json +102 -0
  43. package/cli/checks/epic/ux.json +90 -0
  44. package/cli/checks/fixes/epic-fix-template.md +10 -0
  45. package/cli/checks/fixes/story-fix-template.md +10 -0
  46. package/cli/checks/story/api.json +186 -0
  47. package/cli/checks/story/backend.json +102 -0
  48. package/cli/checks/story/cloud.json +102 -0
  49. package/cli/checks/story/data.json +210 -0
  50. package/cli/checks/story/database.json +102 -0
  51. package/cli/checks/story/developer.json +168 -0
  52. package/cli/checks/story/devops.json +102 -0
  53. package/cli/checks/story/frontend.json +174 -0
  54. package/cli/checks/story/mobile.json +102 -0
  55. package/cli/checks/story/qa.json +210 -0
  56. package/cli/checks/story/security.json +198 -0
  57. package/cli/checks/story/solution-architect.json +230 -0
  58. package/cli/checks/story/test-architect.json +210 -0
  59. package/cli/checks/story/ui.json +102 -0
  60. package/cli/checks/story/ux.json +102 -0
  61. package/cli/coding-order.js +401 -0
  62. package/cli/dependency-checker.js +72 -0
  63. package/cli/epic-story-validator.js +284 -799
  64. package/cli/index.js +0 -0
  65. package/cli/init-model-config.js +17 -10
  66. package/cli/init.js +514 -92
  67. package/cli/kanban-server-manager.js +1 -2
  68. package/cli/llm-claude.js +98 -31
  69. package/cli/llm-gemini.js +29 -5
  70. package/cli/llm-local.js +493 -0
  71. package/cli/llm-openai.js +262 -41
  72. package/cli/llm-provider.js +147 -8
  73. package/cli/llm-token-limits.js +113 -4
  74. package/cli/llm-verifier.js +209 -1
  75. package/cli/llm-xiaomi.js +143 -0
  76. package/cli/message-constants.js +3 -12
  77. package/cli/messaging-api.js +6 -12
  78. package/cli/micro-check-fixer.js +335 -0
  79. package/cli/micro-check-runner.js +449 -0
  80. package/cli/micro-check-scorer.js +148 -0
  81. package/cli/micro-check-validator.js +538 -0
  82. package/cli/model-pricing.js +23 -0
  83. package/cli/model-selector.js +3 -2
  84. package/cli/prompt-logger.js +57 -0
  85. package/cli/repl-ink.js +106 -346
  86. package/cli/repl-old.js +1 -2
  87. package/cli/seed-processor.js +194 -24
  88. package/cli/sprint-planning-processor.js +2638 -289
  89. package/cli/template-processor.js +50 -3
  90. package/cli/token-tracker.js +50 -23
  91. package/cli/tools/generate-story-validators.js +1 -1
  92. package/cli/validation-router.js +70 -8
  93. package/cli/worktree-runner.js +654 -0
  94. package/kanban/client/dist/assets/index-D_KC5EQT.css +1 -0
  95. package/kanban/client/dist/assets/index-DjY5zqW7.js +351 -0
  96. package/kanban/client/dist/index.html +2 -2
  97. package/kanban/client/src/App.jsx +43 -14
  98. package/kanban/client/src/components/ceremony/AskArchPopup.jsx +7 -3
  99. package/kanban/client/src/components/ceremony/AskModelPopup.jsx +23 -10
  100. package/kanban/client/src/components/ceremony/CeremonyWorkflowModal.jsx +320 -133
  101. package/kanban/client/src/components/ceremony/ProviderSwitcherButton.jsx +290 -0
  102. package/kanban/client/src/components/ceremony/SponsorCallModal.jsx +80 -13
  103. package/kanban/client/src/components/ceremony/SprintPlanningModal.jsx +156 -22
  104. package/kanban/client/src/components/ceremony/steps/ArchitectureStep.jsx +11 -11
  105. package/kanban/client/src/components/ceremony/steps/CompleteStep.jsx +3 -21
  106. package/kanban/client/src/components/ceremony/steps/ReviewAnswersStep.jsx +214 -10
  107. package/kanban/client/src/components/ceremony/steps/RunningStep.jsx +23 -2
  108. package/kanban/client/src/components/kanban/CardDetailModal.jsx +97 -10
  109. package/kanban/client/src/components/kanban/GroupingSelector.jsx +7 -1
  110. package/kanban/client/src/components/kanban/KanbanCard.jsx +23 -14
  111. package/kanban/client/src/components/kanban/RefineWorkItemPopup.jsx +9 -14
  112. package/kanban/client/src/components/kanban/RunButton.jsx +162 -0
  113. package/kanban/client/src/components/kanban/SeedButton.jsx +176 -0
  114. package/kanban/client/src/components/settings/AgentsTab.jsx +103 -75
  115. package/kanban/client/src/components/settings/ApiKeysTab.jsx +31 -2
  116. package/kanban/client/src/components/settings/CeremonyModelsTab.jsx +9 -2
  117. package/kanban/client/src/components/settings/CheckEditorPopup.jsx +507 -0
  118. package/kanban/client/src/components/settings/CostThresholdsTab.jsx +3 -2
  119. package/kanban/client/src/components/settings/ModelPricingTab.jsx +72 -7
  120. package/kanban/client/src/components/settings/OpenAIAuthSection.jsx +412 -0
  121. package/kanban/client/src/components/settings/SettingsModal.jsx +4 -4
  122. package/kanban/client/src/components/stats/CostModal.jsx +34 -3
  123. package/kanban/client/src/hooks/useGrouping.js +59 -0
  124. package/kanban/client/src/lib/api.js +118 -4
  125. package/kanban/client/src/lib/status-grouping.js +10 -0
  126. package/kanban/client/src/store/kanbanStore.js +8 -0
  127. package/kanban/server/index.js +23 -2
  128. package/kanban/server/routes/ceremony.js +153 -4
  129. package/kanban/server/routes/costs.js +9 -3
  130. package/kanban/server/routes/openai-oauth.js +366 -0
  131. package/kanban/server/routes/settings.js +447 -14
  132. package/kanban/server/routes/websocket.js +7 -2
  133. package/kanban/server/routes/work-items.js +141 -1
  134. package/kanban/server/services/CeremonyService.js +275 -24
  135. package/kanban/server/services/TaskRunnerService.js +261 -0
  136. package/kanban/server/workers/run-task-worker.js +121 -0
  137. package/kanban/server/workers/seed-worker.js +94 -0
  138. package/kanban/server/workers/sponsor-call-worker.js +14 -6
  139. package/kanban/server/workers/sprint-planning-worker.js +94 -12
  140. package/package.json +2 -3
  141. package/cli/agents/solver-epic-api.json +0 -15
  142. package/cli/agents/solver-epic-api.md +0 -39
  143. package/cli/agents/solver-epic-backend.json +0 -15
  144. package/cli/agents/solver-epic-backend.md +0 -39
  145. package/cli/agents/solver-epic-cloud.json +0 -15
  146. package/cli/agents/solver-epic-cloud.md +0 -39
  147. package/cli/agents/solver-epic-data.json +0 -15
  148. package/cli/agents/solver-epic-data.md +0 -39
  149. package/cli/agents/solver-epic-database.json +0 -15
  150. package/cli/agents/solver-epic-database.md +0 -39
  151. package/cli/agents/solver-epic-developer.json +0 -15
  152. package/cli/agents/solver-epic-developer.md +0 -39
  153. package/cli/agents/solver-epic-devops.json +0 -15
  154. package/cli/agents/solver-epic-devops.md +0 -39
  155. package/cli/agents/solver-epic-frontend.json +0 -15
  156. package/cli/agents/solver-epic-frontend.md +0 -39
  157. package/cli/agents/solver-epic-mobile.json +0 -15
  158. package/cli/agents/solver-epic-mobile.md +0 -39
  159. package/cli/agents/solver-epic-qa.json +0 -15
  160. package/cli/agents/solver-epic-qa.md +0 -39
  161. package/cli/agents/solver-epic-security.json +0 -15
  162. package/cli/agents/solver-epic-security.md +0 -39
  163. package/cli/agents/solver-epic-solution-architect.json +0 -15
  164. package/cli/agents/solver-epic-solution-architect.md +0 -39
  165. package/cli/agents/solver-epic-test-architect.json +0 -15
  166. package/cli/agents/solver-epic-test-architect.md +0 -39
  167. package/cli/agents/solver-epic-ui.json +0 -15
  168. package/cli/agents/solver-epic-ui.md +0 -39
  169. package/cli/agents/solver-epic-ux.json +0 -15
  170. package/cli/agents/solver-epic-ux.md +0 -39
  171. package/cli/agents/solver-story-api.json +0 -15
  172. package/cli/agents/solver-story-api.md +0 -39
  173. package/cli/agents/solver-story-backend.json +0 -15
  174. package/cli/agents/solver-story-backend.md +0 -39
  175. package/cli/agents/solver-story-cloud.json +0 -15
  176. package/cli/agents/solver-story-cloud.md +0 -39
  177. package/cli/agents/solver-story-data.json +0 -15
  178. package/cli/agents/solver-story-data.md +0 -39
  179. package/cli/agents/solver-story-database.json +0 -15
  180. package/cli/agents/solver-story-database.md +0 -39
  181. package/cli/agents/solver-story-developer.json +0 -15
  182. package/cli/agents/solver-story-developer.md +0 -39
  183. package/cli/agents/solver-story-devops.json +0 -15
  184. package/cli/agents/solver-story-devops.md +0 -39
  185. package/cli/agents/solver-story-frontend.json +0 -15
  186. package/cli/agents/solver-story-frontend.md +0 -39
  187. package/cli/agents/solver-story-mobile.json +0 -15
  188. package/cli/agents/solver-story-mobile.md +0 -39
  189. package/cli/agents/solver-story-qa.json +0 -15
  190. package/cli/agents/solver-story-qa.md +0 -39
  191. package/cli/agents/solver-story-security.json +0 -15
  192. package/cli/agents/solver-story-security.md +0 -39
  193. package/cli/agents/solver-story-solution-architect.json +0 -15
  194. package/cli/agents/solver-story-solution-architect.md +0 -39
  195. package/cli/agents/solver-story-test-architect.json +0 -15
  196. package/cli/agents/solver-story-test-architect.md +0 -39
  197. package/cli/agents/solver-story-ui.json +0 -15
  198. package/cli/agents/solver-story-ui.md +0 -39
  199. package/cli/agents/solver-story-ux.json +0 -15
  200. package/cli/agents/solver-story-ux.md +0 -39
  201. package/cli/agents/validator-epic-api.json +0 -93
  202. package/cli/agents/validator-epic-api.md +0 -137
  203. package/cli/agents/validator-epic-backend.json +0 -93
  204. package/cli/agents/validator-epic-backend.md +0 -130
  205. package/cli/agents/validator-epic-cloud.json +0 -93
  206. package/cli/agents/validator-epic-cloud.md +0 -137
  207. package/cli/agents/validator-epic-data.json +0 -93
  208. package/cli/agents/validator-epic-data.md +0 -130
  209. package/cli/agents/validator-epic-database.json +0 -93
  210. package/cli/agents/validator-epic-database.md +0 -137
  211. package/cli/agents/validator-epic-developer.json +0 -74
  212. package/cli/agents/validator-epic-developer.md +0 -153
  213. package/cli/agents/validator-epic-devops.json +0 -74
  214. package/cli/agents/validator-epic-devops.md +0 -153
  215. package/cli/agents/validator-epic-frontend.json +0 -74
  216. package/cli/agents/validator-epic-frontend.md +0 -153
  217. package/cli/agents/validator-epic-mobile.json +0 -93
  218. package/cli/agents/validator-epic-mobile.md +0 -130
  219. package/cli/agents/validator-epic-qa.json +0 -93
  220. package/cli/agents/validator-epic-qa.md +0 -130
  221. package/cli/agents/validator-epic-security.json +0 -74
  222. package/cli/agents/validator-epic-security.md +0 -154
  223. package/cli/agents/validator-epic-solution-architect.json +0 -74
  224. package/cli/agents/validator-epic-solution-architect.md +0 -156
  225. package/cli/agents/validator-epic-test-architect.json +0 -93
  226. package/cli/agents/validator-epic-test-architect.md +0 -130
  227. package/cli/agents/validator-epic-ui.json +0 -93
  228. package/cli/agents/validator-epic-ui.md +0 -130
  229. package/cli/agents/validator-epic-ux.json +0 -93
  230. package/cli/agents/validator-epic-ux.md +0 -130
  231. package/cli/agents/validator-story-api.json +0 -104
  232. package/cli/agents/validator-story-api.md +0 -152
  233. package/cli/agents/validator-story-backend.json +0 -104
  234. package/cli/agents/validator-story-backend.md +0 -152
  235. package/cli/agents/validator-story-cloud.json +0 -104
  236. package/cli/agents/validator-story-cloud.md +0 -152
  237. package/cli/agents/validator-story-data.json +0 -104
  238. package/cli/agents/validator-story-data.md +0 -152
  239. package/cli/agents/validator-story-database.json +0 -104
  240. package/cli/agents/validator-story-database.md +0 -152
  241. package/cli/agents/validator-story-developer.json +0 -104
  242. package/cli/agents/validator-story-developer.md +0 -152
  243. package/cli/agents/validator-story-devops.json +0 -104
  244. package/cli/agents/validator-story-devops.md +0 -152
  245. package/cli/agents/validator-story-frontend.json +0 -104
  246. package/cli/agents/validator-story-frontend.md +0 -152
  247. package/cli/agents/validator-story-mobile.json +0 -104
  248. package/cli/agents/validator-story-mobile.md +0 -152
  249. package/cli/agents/validator-story-qa.json +0 -104
  250. package/cli/agents/validator-story-qa.md +0 -152
  251. package/cli/agents/validator-story-security.json +0 -104
  252. package/cli/agents/validator-story-security.md +0 -152
  253. package/cli/agents/validator-story-solution-architect.json +0 -104
  254. package/cli/agents/validator-story-solution-architect.md +0 -152
  255. package/cli/agents/validator-story-test-architect.json +0 -104
  256. package/cli/agents/validator-story-test-architect.md +0 -152
  257. package/cli/agents/validator-story-ui.json +0 -104
  258. package/cli/agents/validator-story-ui.md +0 -152
  259. package/cli/agents/validator-story-ux.json +0 -104
  260. package/cli/agents/validator-story-ux.md +0 -152
  261. package/kanban/client/dist/assets/index-CiD8PS2e.js +0 -306
  262. 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
- fs.mkdirSync(this.avcDir, { recursive: true });
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
- fs.mkdirSync(this.srcDir, { recursive: true });
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
- fs.mkdirSync(this.worktreesDir, { recursive: true });
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
- 'doc-distribution': {
373
+ 'context-generation': {
259
374
  provider: 'claude',
260
375
  model: 'claude-sonnet-4-6'
261
376
  },
262
- enrichment: {
377
+ 'doc-generation': {
263
378
  provider: 'claude',
264
379
  model: 'claude-sonnet-4-6'
265
380
  },
266
- solver: {
381
+ enrichment: {
267
382
  provider: 'claude',
268
- model: 'claude-haiku-4-5-20251001',
269
- maxIterations: 3,
270
- acceptanceThreshold: 95
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
- 'doc-distribution': {
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.2': {
726
+ 'gpt-5.4': {
453
727
  provider: 'openai',
454
- displayName: 'GPT-5.2',
728
+ displayName: 'GPT-5.4',
455
729
  pricing: {
456
- input: 1.75,
457
- output: 14.00,
730
+ input: 2.50,
731
+ output: 15.00,
458
732
  unit: 'million',
459
733
  source: 'https://openai.com/api/pricing',
460
- lastUpdated: '2026-02-24'
734
+ lastUpdated: '2026-03-06'
461
735
  }
462
736
  },
463
- 'gpt-5.1': {
737
+ 'gpt-5.4-pro': {
464
738
  provider: 'openai',
465
- displayName: 'GPT-5.1',
739
+ displayName: 'GPT-5.4 Pro',
466
740
  pricing: {
467
- input: 1.25,
468
- output: 10.00,
741
+ input: 30.00,
742
+ output: 180.00,
469
743
  unit: 'million',
470
744
  source: 'https://openai.com/api/pricing',
471
- lastUpdated: '2026-02-24'
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
- 'o4-mini': {
759
+ 'gpt-5-nano': {
486
760
  provider: 'openai',
487
- displayName: 'o4-mini',
761
+ displayName: 'GPT-5 nano',
488
762
  pricing: {
489
- input: 1.10,
490
- output: 4.40,
763
+ input: 0.05,
764
+ output: 0.40,
491
765
  unit: 'million',
492
766
  source: 'https://openai.com/api/pricing',
493
- lastUpdated: '2026-02-24'
767
+ lastUpdated: '2026-03-06'
494
768
  }
495
769
  },
496
- 'o3': {
497
- provider: 'openai',
498
- displayName: 'o3',
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: 2.00,
501
- output: 8.00,
777
+ input: 0.09,
778
+ output: 0.29,
502
779
  unit: 'million',
503
- source: 'https://openai.com/api/pricing',
504
- lastUpdated: '2026-02-24'
780
+ source: 'https://platform.xiaomimimo.com',
781
+ lastUpdated: '2026-03-25'
505
782
  }
506
783
  },
507
- 'o3-mini': {
508
- provider: 'openai',
509
- displayName: 'o3-mini',
784
+ 'mimo-v2-pro': {
785
+ provider: 'xiaomi',
786
+ displayName: 'MiMo V2 Pro',
510
787
  pricing: {
511
- input: 0.50,
512
- output: 2.00,
788
+ input: 1.00,
789
+ output: 3.00,
513
790
  unit: 'million',
514
- source: 'https://openai.com/api/pricing',
515
- lastUpdated: '2026-02-24'
791
+ source: 'https://platform.xiaomimimo.com',
792
+ lastUpdated: '2026-03-25'
516
793
  }
517
794
  },
518
- 'gpt-5.2-codex': {
519
- provider: 'openai',
520
- displayName: 'GPT-5.2-Codex',
795
+ 'mimo-v2-omni': {
796
+ provider: 'xiaomi',
797
+ displayName: 'MiMo V2 Omni',
521
798
  pricing: {
522
- input: 1.75,
523
- output: 14.00,
799
+ input: 0.40,
800
+ output: 2.00,
524
801
  unit: 'million',
525
- source: 'https://openai.com/api/pricing',
526
- lastUpdated: '2026-02-24'
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
- fs.mkdirSync(vitepressDir, { recursive: true });
999
+ mkdirp(vitepressDir);
718
1000
  }
719
1001
 
720
1002
  if (!fs.existsSync(publicDir)) {
721
- fs.mkdirSync(publicDir, { recursive: true });
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
- fs.mkdirSync(this.avcDir, { recursive: true });
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
- if (!process.env[mainEnvVar]) {
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 (!process.env[validationEnvVar]) {
945
- // Enhanced error message with 3 options
946
- return {
947
- valid: false,
948
- validationProviderMissing: true,
949
- ceremonyConfig: {
950
- mainProvider,
951
- mainModel,
952
- validationProvider,
953
- validationModel
954
- },
955
- message: `Validation Provider API Key Missing\n\nYour ceremony is configured to use:\n • Generation: ${mainProvider} (${mainModel}) ✓\n • Validation: ${validationProvider} (${validationModel}) ✗ (${validationEnvVar} not found)\n\nYou have 3 options:\n\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\nOption 1: Add the missing API key\n\n 1. Get API key: ${urlMap[validationProvider]}\n 2. Add to .env file: ${validationEnvVar}=your-key-here\n 3. Run /sponsor-call again\n\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\nOption 2: Disable validation (faster, lower quality)\n\n 1. Edit .avc/avc.json\n 2. Find "sponsor-call" ceremony config\n 3. Set:\n "validation": {\n "enabled": false\n }\n 4. Run /sponsor-call again\n\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\nOption 3: Use same provider for validation (simpler setup)\n\n 1. Edit .avc/avc.json\n 2. Find "sponsor-call" ceremony config\n 3. Change:\n "validation": {\n "enabled": true,\n "provider": "${mainProvider}",\n "model": "${mainModel}"\n }\n 4. Run /sponsor-call again\n\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━`
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
- const parsedError = this.parseApiError(error.message || error);
963
- return {
964
- valid: false,
965
- message: `${validationEnvVar} validation failed.\n\n ${parsedError}\n\n Get a new API key if needed:\n • ${urlMap[validationProvider]}`
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
- const parsedError = this.parseApiError(result.error || 'Unknown error');
971
- return {
972
- valid: false,
973
- message: `${validationEnvVar} is set but API call failed.\n\n ${parsedError}\n\n Get a new API key if needed:\n • ${urlMap[validationProvider]}`
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 — set your API keys in .env (Anthropic, Gemini, OpenAI) then open the Kanban board to get started.');
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');