@agile-vibe-coding/avc 0.1.1 → 0.2.3

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 (289) hide show
  1. package/cli/agent-loader.js +21 -0
  2. package/cli/agents/agent-selector.md +129 -0
  3. package/cli/agents/architecture-recommender.md +418 -0
  4. package/cli/agents/database-deep-dive.md +470 -0
  5. package/cli/agents/database-recommender.md +634 -0
  6. package/cli/agents/doc-distributor.md +176 -0
  7. package/cli/agents/documentation-updater.md +203 -0
  8. package/cli/agents/epic-story-decomposer.md +280 -0
  9. package/cli/agents/feature-context-generator.md +91 -0
  10. package/cli/agents/gap-checker-epic.md +52 -0
  11. package/cli/agents/impact-checker-story.md +51 -0
  12. package/cli/agents/migration-guide-generator.md +305 -0
  13. package/cli/agents/mission-scope-generator.md +79 -0
  14. package/cli/agents/mission-scope-validator.md +112 -0
  15. package/cli/agents/project-context-extractor.md +107 -0
  16. package/cli/agents/project-documentation-creator.json +226 -0
  17. package/cli/agents/project-documentation-creator.md +595 -0
  18. package/cli/agents/question-prefiller.md +269 -0
  19. package/cli/agents/refiner-epic.md +39 -0
  20. package/cli/agents/refiner-story.md +42 -0
  21. package/cli/agents/solver-epic-api.json +15 -0
  22. package/cli/agents/solver-epic-api.md +39 -0
  23. package/cli/agents/solver-epic-backend.json +15 -0
  24. package/cli/agents/solver-epic-backend.md +39 -0
  25. package/cli/agents/solver-epic-cloud.json +15 -0
  26. package/cli/agents/solver-epic-cloud.md +39 -0
  27. package/cli/agents/solver-epic-data.json +15 -0
  28. package/cli/agents/solver-epic-data.md +39 -0
  29. package/cli/agents/solver-epic-database.json +15 -0
  30. package/cli/agents/solver-epic-database.md +39 -0
  31. package/cli/agents/solver-epic-developer.json +15 -0
  32. package/cli/agents/solver-epic-developer.md +39 -0
  33. package/cli/agents/solver-epic-devops.json +15 -0
  34. package/cli/agents/solver-epic-devops.md +39 -0
  35. package/cli/agents/solver-epic-frontend.json +15 -0
  36. package/cli/agents/solver-epic-frontend.md +39 -0
  37. package/cli/agents/solver-epic-mobile.json +15 -0
  38. package/cli/agents/solver-epic-mobile.md +39 -0
  39. package/cli/agents/solver-epic-qa.json +15 -0
  40. package/cli/agents/solver-epic-qa.md +39 -0
  41. package/cli/agents/solver-epic-security.json +15 -0
  42. package/cli/agents/solver-epic-security.md +39 -0
  43. package/cli/agents/solver-epic-solution-architect.json +15 -0
  44. package/cli/agents/solver-epic-solution-architect.md +39 -0
  45. package/cli/agents/solver-epic-test-architect.json +15 -0
  46. package/cli/agents/solver-epic-test-architect.md +39 -0
  47. package/cli/agents/solver-epic-ui.json +15 -0
  48. package/cli/agents/solver-epic-ui.md +39 -0
  49. package/cli/agents/solver-epic-ux.json +15 -0
  50. package/cli/agents/solver-epic-ux.md +39 -0
  51. package/cli/agents/solver-story-api.json +15 -0
  52. package/cli/agents/solver-story-api.md +39 -0
  53. package/cli/agents/solver-story-backend.json +15 -0
  54. package/cli/agents/solver-story-backend.md +39 -0
  55. package/cli/agents/solver-story-cloud.json +15 -0
  56. package/cli/agents/solver-story-cloud.md +39 -0
  57. package/cli/agents/solver-story-data.json +15 -0
  58. package/cli/agents/solver-story-data.md +39 -0
  59. package/cli/agents/solver-story-database.json +15 -0
  60. package/cli/agents/solver-story-database.md +39 -0
  61. package/cli/agents/solver-story-developer.json +15 -0
  62. package/cli/agents/solver-story-developer.md +39 -0
  63. package/cli/agents/solver-story-devops.json +15 -0
  64. package/cli/agents/solver-story-devops.md +39 -0
  65. package/cli/agents/solver-story-frontend.json +15 -0
  66. package/cli/agents/solver-story-frontend.md +39 -0
  67. package/cli/agents/solver-story-mobile.json +15 -0
  68. package/cli/agents/solver-story-mobile.md +39 -0
  69. package/cli/agents/solver-story-qa.json +15 -0
  70. package/cli/agents/solver-story-qa.md +39 -0
  71. package/cli/agents/solver-story-security.json +15 -0
  72. package/cli/agents/solver-story-security.md +39 -0
  73. package/cli/agents/solver-story-solution-architect.json +15 -0
  74. package/cli/agents/solver-story-solution-architect.md +39 -0
  75. package/cli/agents/solver-story-test-architect.json +15 -0
  76. package/cli/agents/solver-story-test-architect.md +39 -0
  77. package/cli/agents/solver-story-ui.json +15 -0
  78. package/cli/agents/solver-story-ui.md +39 -0
  79. package/cli/agents/solver-story-ux.json +15 -0
  80. package/cli/agents/solver-story-ux.md +39 -0
  81. package/cli/agents/story-doc-enricher.md +133 -0
  82. package/cli/agents/suggestion-business-analyst.md +88 -0
  83. package/cli/agents/suggestion-deployment-architect.md +263 -0
  84. package/cli/agents/suggestion-product-manager.md +129 -0
  85. package/cli/agents/suggestion-security-specialist.md +156 -0
  86. package/cli/agents/suggestion-technical-architect.md +269 -0
  87. package/cli/agents/suggestion-ux-researcher.md +93 -0
  88. package/cli/agents/task-subtask-decomposer.md +188 -0
  89. package/cli/agents/validator-documentation.json +152 -0
  90. package/cli/agents/validator-documentation.md +453 -0
  91. package/cli/agents/validator-epic-api.json +93 -0
  92. package/cli/agents/validator-epic-api.md +137 -0
  93. package/cli/agents/validator-epic-backend.json +93 -0
  94. package/cli/agents/validator-epic-backend.md +130 -0
  95. package/cli/agents/validator-epic-cloud.json +93 -0
  96. package/cli/agents/validator-epic-cloud.md +137 -0
  97. package/cli/agents/validator-epic-data.json +93 -0
  98. package/cli/agents/validator-epic-data.md +130 -0
  99. package/cli/agents/validator-epic-database.json +93 -0
  100. package/cli/agents/validator-epic-database.md +137 -0
  101. package/cli/agents/validator-epic-developer.json +74 -0
  102. package/cli/agents/validator-epic-developer.md +153 -0
  103. package/cli/agents/validator-epic-devops.json +74 -0
  104. package/cli/agents/validator-epic-devops.md +153 -0
  105. package/cli/agents/validator-epic-frontend.json +74 -0
  106. package/cli/agents/validator-epic-frontend.md +153 -0
  107. package/cli/agents/validator-epic-mobile.json +93 -0
  108. package/cli/agents/validator-epic-mobile.md +130 -0
  109. package/cli/agents/validator-epic-qa.json +93 -0
  110. package/cli/agents/validator-epic-qa.md +130 -0
  111. package/cli/agents/validator-epic-security.json +74 -0
  112. package/cli/agents/validator-epic-security.md +154 -0
  113. package/cli/agents/validator-epic-solution-architect.json +74 -0
  114. package/cli/agents/validator-epic-solution-architect.md +156 -0
  115. package/cli/agents/validator-epic-test-architect.json +93 -0
  116. package/cli/agents/validator-epic-test-architect.md +130 -0
  117. package/cli/agents/validator-epic-ui.json +93 -0
  118. package/cli/agents/validator-epic-ui.md +130 -0
  119. package/cli/agents/validator-epic-ux.json +93 -0
  120. package/cli/agents/validator-epic-ux.md +130 -0
  121. package/cli/agents/validator-selector.md +211 -0
  122. package/cli/agents/validator-story-api.json +104 -0
  123. package/cli/agents/validator-story-api.md +152 -0
  124. package/cli/agents/validator-story-backend.json +104 -0
  125. package/cli/agents/validator-story-backend.md +152 -0
  126. package/cli/agents/validator-story-cloud.json +104 -0
  127. package/cli/agents/validator-story-cloud.md +152 -0
  128. package/cli/agents/validator-story-data.json +104 -0
  129. package/cli/agents/validator-story-data.md +152 -0
  130. package/cli/agents/validator-story-database.json +104 -0
  131. package/cli/agents/validator-story-database.md +152 -0
  132. package/cli/agents/validator-story-developer.json +104 -0
  133. package/cli/agents/validator-story-developer.md +152 -0
  134. package/cli/agents/validator-story-devops.json +104 -0
  135. package/cli/agents/validator-story-devops.md +152 -0
  136. package/cli/agents/validator-story-frontend.json +104 -0
  137. package/cli/agents/validator-story-frontend.md +152 -0
  138. package/cli/agents/validator-story-mobile.json +104 -0
  139. package/cli/agents/validator-story-mobile.md +152 -0
  140. package/cli/agents/validator-story-qa.json +104 -0
  141. package/cli/agents/validator-story-qa.md +152 -0
  142. package/cli/agents/validator-story-security.json +104 -0
  143. package/cli/agents/validator-story-security.md +152 -0
  144. package/cli/agents/validator-story-solution-architect.json +104 -0
  145. package/cli/agents/validator-story-solution-architect.md +152 -0
  146. package/cli/agents/validator-story-test-architect.json +104 -0
  147. package/cli/agents/validator-story-test-architect.md +152 -0
  148. package/cli/agents/validator-story-ui.json +104 -0
  149. package/cli/agents/validator-story-ui.md +152 -0
  150. package/cli/agents/validator-story-ux.json +104 -0
  151. package/cli/agents/validator-story-ux.md +152 -0
  152. package/cli/ansi-colors.js +21 -0
  153. package/cli/build-docs.js +29 -8
  154. package/cli/ceremony-history.js +369 -0
  155. package/cli/command-logger.js +49 -12
  156. package/cli/components/static-output.js +63 -0
  157. package/cli/console-output-manager.js +94 -0
  158. package/cli/docs-sync.js +306 -0
  159. package/cli/epic-story-validator.js +1174 -0
  160. package/cli/evaluation-prompts.js +1008 -0
  161. package/cli/execution-context.js +195 -0
  162. package/cli/generate-summary-table.js +340 -0
  163. package/cli/index.js +0 -0
  164. package/cli/init-model-config.js +697 -0
  165. package/cli/init.js +1311 -274
  166. package/cli/kanban-server-manager.js +228 -0
  167. package/cli/llm-claude.js +83 -1
  168. package/cli/llm-gemini.js +85 -0
  169. package/cli/llm-mock.js +233 -0
  170. package/cli/llm-openai.js +233 -0
  171. package/cli/llm-provider.js +240 -3
  172. package/cli/llm-token-limits.js +102 -0
  173. package/cli/llm-verifier.js +454 -0
  174. package/cli/message-constants.js +58 -0
  175. package/cli/message-manager.js +334 -0
  176. package/cli/message-types.js +96 -0
  177. package/cli/messaging-api.js +297 -0
  178. package/cli/model-pricing.js +169 -0
  179. package/cli/model-query-engine.js +468 -0
  180. package/cli/model-recommendation-analyzer.js +495 -0
  181. package/cli/model-selector.js +269 -0
  182. package/cli/output-buffer.js +107 -0
  183. package/cli/process-manager.js +73 -2
  184. package/cli/repl-ink.js +4988 -1217
  185. package/cli/repl-old.js +4 -4
  186. package/cli/seed-processor.js +792 -0
  187. package/cli/sprint-planning-processor.js +1813 -0
  188. package/cli/template-processor.js +2102 -105
  189. package/cli/templates/project.md +25 -8
  190. package/cli/templates/vitepress-config.mts.template +5 -4
  191. package/cli/token-tracker.js +520 -0
  192. package/cli/tools/generate-story-validators.js +317 -0
  193. package/cli/tools/generate-validators.js +669 -0
  194. package/cli/update-checker.js +19 -17
  195. package/cli/update-notifier.js +4 -4
  196. package/cli/validation-router.js +605 -0
  197. package/cli/verification-tracker.js +563 -0
  198. package/kanban/README.md +386 -0
  199. package/kanban/client/README.md +205 -0
  200. package/kanban/client/components.json +20 -0
  201. package/kanban/client/dist/assets/index-CiD8PS2e.js +306 -0
  202. package/kanban/client/dist/assets/index-nLh0m82Q.css +1 -0
  203. package/kanban/client/dist/index.html +16 -0
  204. package/kanban/client/dist/vite.svg +1 -0
  205. package/kanban/client/index.html +15 -0
  206. package/kanban/client/package-lock.json +9442 -0
  207. package/kanban/client/package.json +44 -0
  208. package/kanban/client/postcss.config.js +6 -0
  209. package/kanban/client/public/vite.svg +1 -0
  210. package/kanban/client/src/App.jsx +622 -0
  211. package/kanban/client/src/components/ProjectFileEditorPopup.jsx +117 -0
  212. package/kanban/client/src/components/ceremony/AskArchPopup.jsx +416 -0
  213. package/kanban/client/src/components/ceremony/AskModelPopup.jsx +616 -0
  214. package/kanban/client/src/components/ceremony/CeremonyWorkflowModal.jsx +946 -0
  215. package/kanban/client/src/components/ceremony/EpicStorySelectionModal.jsx +254 -0
  216. package/kanban/client/src/components/ceremony/SponsorCallModal.jsx +619 -0
  217. package/kanban/client/src/components/ceremony/SprintPlanningModal.jsx +704 -0
  218. package/kanban/client/src/components/ceremony/steps/ArchitectureStep.jsx +150 -0
  219. package/kanban/client/src/components/ceremony/steps/CompleteStep.jsx +154 -0
  220. package/kanban/client/src/components/ceremony/steps/DatabaseStep.jsx +202 -0
  221. package/kanban/client/src/components/ceremony/steps/DeploymentStep.jsx +123 -0
  222. package/kanban/client/src/components/ceremony/steps/MissionStep.jsx +106 -0
  223. package/kanban/client/src/components/ceremony/steps/ReviewAnswersStep.jsx +125 -0
  224. package/kanban/client/src/components/ceremony/steps/RunningStep.jsx +228 -0
  225. package/kanban/client/src/components/kanban/CardDetailModal.jsx +559 -0
  226. package/kanban/client/src/components/kanban/EpicSection.jsx +146 -0
  227. package/kanban/client/src/components/kanban/FilterToolbar.jsx +222 -0
  228. package/kanban/client/src/components/kanban/GroupingSelector.jsx +57 -0
  229. package/kanban/client/src/components/kanban/KanbanBoard.jsx +211 -0
  230. package/kanban/client/src/components/kanban/KanbanCard.jsx +138 -0
  231. package/kanban/client/src/components/kanban/KanbanColumn.jsx +90 -0
  232. package/kanban/client/src/components/kanban/RefineWorkItemPopup.jsx +789 -0
  233. package/kanban/client/src/components/layout/LoadingScreen.jsx +82 -0
  234. package/kanban/client/src/components/process/ProcessMonitorBar.jsx +80 -0
  235. package/kanban/client/src/components/settings/AgentEditorPopup.jsx +171 -0
  236. package/kanban/client/src/components/settings/AgentsTab.jsx +353 -0
  237. package/kanban/client/src/components/settings/ApiKeysTab.jsx +113 -0
  238. package/kanban/client/src/components/settings/CeremonyModelsTab.jsx +98 -0
  239. package/kanban/client/src/components/settings/CostThresholdsTab.jsx +94 -0
  240. package/kanban/client/src/components/settings/ModelPricingTab.jsx +204 -0
  241. package/kanban/client/src/components/settings/ServersTab.jsx +121 -0
  242. package/kanban/client/src/components/settings/SettingsModal.jsx +84 -0
  243. package/kanban/client/src/components/stats/CostModal.jsx +353 -0
  244. package/kanban/client/src/components/ui/badge.jsx +27 -0
  245. package/kanban/client/src/components/ui/dialog.jsx +121 -0
  246. package/kanban/client/src/components/ui/tabs.jsx +85 -0
  247. package/kanban/client/src/hooks/__tests__/useGrouping.test.js +232 -0
  248. package/kanban/client/src/hooks/useGrouping.js +118 -0
  249. package/kanban/client/src/hooks/useWebSocket.js +120 -0
  250. package/kanban/client/src/lib/__tests__/api.test.js +196 -0
  251. package/kanban/client/src/lib/__tests__/status-grouping.test.js +94 -0
  252. package/kanban/client/src/lib/api.js +401 -0
  253. package/kanban/client/src/lib/status-grouping.js +144 -0
  254. package/kanban/client/src/lib/utils.js +11 -0
  255. package/kanban/client/src/main.jsx +10 -0
  256. package/kanban/client/src/store/__tests__/kanbanStore.test.js +164 -0
  257. package/kanban/client/src/store/ceremonyStore.js +172 -0
  258. package/kanban/client/src/store/filterStore.js +201 -0
  259. package/kanban/client/src/store/kanbanStore.js +115 -0
  260. package/kanban/client/src/store/processStore.js +65 -0
  261. package/kanban/client/src/store/sprintPlanningStore.js +33 -0
  262. package/kanban/client/src/styles/globals.css +59 -0
  263. package/kanban/client/tailwind.config.js +77 -0
  264. package/kanban/client/vite.config.js +28 -0
  265. package/kanban/client/vitest.config.js +28 -0
  266. package/kanban/dev-start.sh +47 -0
  267. package/kanban/package.json +12 -0
  268. package/kanban/server/index.js +516 -0
  269. package/kanban/server/routes/ceremony.js +305 -0
  270. package/kanban/server/routes/costs.js +157 -0
  271. package/kanban/server/routes/processes.js +50 -0
  272. package/kanban/server/routes/settings.js +303 -0
  273. package/kanban/server/routes/websocket.js +276 -0
  274. package/kanban/server/routes/work-items.js +347 -0
  275. package/kanban/server/services/CeremonyService.js +1190 -0
  276. package/kanban/server/services/FileSystemScanner.js +95 -0
  277. package/kanban/server/services/FileWatcher.js +144 -0
  278. package/kanban/server/services/HierarchyBuilder.js +196 -0
  279. package/kanban/server/services/ProcessRegistry.js +122 -0
  280. package/kanban/server/services/WorkItemReader.js +123 -0
  281. package/kanban/server/services/WorkItemRefineService.js +510 -0
  282. package/kanban/server/start.js +49 -0
  283. package/kanban/server/utils/kanban-logger.js +132 -0
  284. package/kanban/server/utils/markdown.js +91 -0
  285. package/kanban/server/utils/status-grouping.js +107 -0
  286. package/kanban/server/workers/sponsor-call-worker.js +84 -0
  287. package/kanban/server/workers/sprint-planning-worker.js +130 -0
  288. package/package.json +18 -5
  289. package/cli/agents/documentation.md +0 -302
@@ -0,0 +1,269 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Model Selector - Multi-Provider Model Evaluation Tool
5
+ * Queries Claude, OpenAI, and Gemini with evaluation prompts
6
+ * to collect model recommendations for each AVC stage
7
+ */
8
+
9
+ import fs from 'fs';
10
+ import path from 'path';
11
+ import { fileURLToPath } from 'url';
12
+ import { EVALUATION_PROMPTS, getPromptStats } from './evaluation-prompts.js';
13
+ import { ModelQueryEngine } from './model-query-engine.js';
14
+ import { ModelRecommendationAnalyzer } from './model-recommendation-analyzer.js';
15
+ import { sendError, sendWarning, sendSuccess, sendInfo, sendOutput, sendIndented, sendSectionHeader } from './messaging-api.js';
16
+
17
+ const __filename = fileURLToPath(import.meta.url);
18
+ const __dirname = path.dirname(__filename);
19
+
20
+ /**
21
+ * Ensure _temp directory exists
22
+ */
23
+ function ensureTempDir() {
24
+ const tempDir = path.join(process.cwd(), '_temp');
25
+ if (!fs.existsSync(tempDir)) {
26
+ fs.mkdirSync(tempDir, { recursive: true });
27
+ }
28
+ return tempDir;
29
+ }
30
+
31
+ /**
32
+ * Display banner
33
+ */
34
+ function displayBanner() {
35
+ console.log('\n╔══════════════════════════════════════════════════════════════╗');
36
+ console.log('║ Multi-Provider Model Selection Evaluator ║');
37
+ console.log('║ Queries Claude, OpenAI, and Gemini for recommendations ║');
38
+ console.log('╚══════════════════════════════════════════════════════════════╝\n');
39
+ }
40
+
41
+ /**
42
+ * Display environment check
43
+ */
44
+ function displayEnvironmentCheck() {
45
+ sendSectionHeader('Checking API keys');
46
+
47
+ const keys = {
48
+ 'ANTHROPIC_API_KEY': !!process.env.ANTHROPIC_API_KEY,
49
+ 'OPENAI_API_KEY': !!process.env.OPENAI_API_KEY,
50
+ 'GEMINI_API_KEY': !!process.env.GEMINI_API_KEY
51
+ };
52
+
53
+ for (const [key, available] of Object.entries(keys)) {
54
+ if (available) {
55
+ sendIndented(`${key}: Found`, 1);
56
+ } else {
57
+ sendIndented(`${key}: Not found`, 1);
58
+ }
59
+ }
60
+
61
+ const availableCount = Object.values(keys).filter(v => v).length;
62
+
63
+ sendOutput(`\n ${availableCount}/3 providers available`);
64
+
65
+ if (availableCount === 0) {
66
+ sendError('No API keys found. Please add at least one to your .env file.');
67
+ process.exit(1);
68
+ }
69
+
70
+ return availableCount;
71
+ }
72
+
73
+ /**
74
+ * Display prompt statistics
75
+ */
76
+ function displayPromptStats() {
77
+ const stats = getPromptStats();
78
+
79
+ sendSectionHeader('Evaluation Overview');
80
+ sendIndented(`Total prompts: ${stats.totalPrompts}`, 1);
81
+ sendIndented(`Ceremonies: ${stats.ceremonies} (${stats.ceremonyList.join(', ')})`, 1);
82
+ sendIndented(`Estimated total API calls: ${stats.estimatedTotalCalls} per provider`, 1);
83
+ sendIndented('Impact distribution:', 1);
84
+ sendIndented(`- CRITICAL: ${stats.impactDistribution.CRITICAL}`, 2);
85
+ sendIndented(`- VERY HIGH: ${stats.impactDistribution['VERY HIGH']}`, 2);
86
+ sendIndented(`- HIGH: ${stats.impactDistribution.HIGH}`, 2);
87
+ sendIndented(`- MEDIUM: ${stats.impactDistribution.MEDIUM}`, 2);
88
+ }
89
+
90
+ /**
91
+ * Progress callback for query engine
92
+ */
93
+ function createProgressCallback() {
94
+ let currentPrompt = 0;
95
+
96
+ return (progress) => {
97
+ if (progress.type === 'prompt-start') {
98
+ currentPrompt = progress.current;
99
+ sendOutput(`\n[${progress.current}/${progress.total}] Processing: ${progress.ceremony}/${progress.stage}`);
100
+ } else if (progress.type === 'prompt-complete') {
101
+ const { successCount, failureCount, totalTime } = progress;
102
+ sendIndented(`Complete: ${successCount} success, ${failureCount} failed (${totalTime.toFixed(1)}s)`, 1);
103
+ }
104
+ };
105
+ }
106
+
107
+ /**
108
+ * Write JSON output file
109
+ */
110
+ function writeJSONOutput(data, outputPath) {
111
+ sendInfo(`Writing JSON output to ${outputPath}...`);
112
+ fs.writeFileSync(outputPath, JSON.stringify(data, null, 2), 'utf-8');
113
+ sendIndented('JSON file written', 1);
114
+ }
115
+
116
+ /**
117
+ * Write Markdown output file
118
+ */
119
+ function writeMarkdownOutput(content, outputPath) {
120
+ sendInfo(`Writing Markdown report to ${outputPath}...`);
121
+ fs.writeFileSync(outputPath, content, 'utf-8');
122
+ sendIndented('Markdown report written', 1);
123
+ }
124
+
125
+ /**
126
+ * Display summary
127
+ */
128
+ function displaySummary(summary) {
129
+ console.log('\n╔══════════════════════════════════════════════════════════════╗');
130
+ console.log('║ Execution Summary ║');
131
+ console.log('╚══════════════════════════════════════════════════════════════╝\n');
132
+
133
+ console.log(`Total prompts evaluated: ${summary.totalPrompts}`);
134
+ console.log(`Successful queries: ${summary.successfulQueries}`);
135
+ console.log(`Failed queries: ${summary.failedQueries}`);
136
+ console.log(`\nExecution time: ${summary.executionTime}`);
137
+
138
+ console.log('\nCost breakdown:');
139
+ for (const [provider, cost] of Object.entries(summary.totalCost)) {
140
+ if (provider !== 'total') {
141
+ console.log(` ${provider}: $${cost.toFixed(4)}`);
142
+ }
143
+ }
144
+ console.log(` TOTAL: $${summary.totalCost.total.toFixed(4)}`);
145
+ }
146
+
147
+ /**
148
+ * Display analysis summary
149
+ */
150
+ function displayAnalysisSummary(statistics) {
151
+ console.log('\n╔══════════════════════════════════════════════════════════════╗');
152
+ console.log('║ Analysis Summary ║');
153
+ console.log('╚══════════════════════════════════════════════════════════════╝\n');
154
+
155
+ console.log('Consensus Statistics:');
156
+ console.log(` Full consensus: ${statistics.consensus.full} (${statistics.consensusRate.full})`);
157
+ console.log(` Partial consensus: ${statistics.consensus.partial} (${statistics.consensusRate.partial})`);
158
+ console.log(` No consensus: ${statistics.consensus.none} (${statistics.consensusRate.none})`);
159
+
160
+ console.log('\nDefault Alignment:');
161
+ console.log(` Perfect: ${statistics.defaultAlignment.perfect} stages`);
162
+ console.log(` Partial: ${statistics.defaultAlignment.partial} stages`);
163
+ console.log(` None: ${statistics.defaultAlignment.none} stages`);
164
+
165
+ console.log('\nRecommendations:');
166
+ console.log(` Upgrade suggestions: ${statistics.upgradeRecommendations} stages`);
167
+ console.log(` Downgrade suggestions: ${statistics.downgradeRecommendations} stages`);
168
+ }
169
+
170
+ /**
171
+ * Main execution function
172
+ */
173
+ async function main() {
174
+ try {
175
+ displayBanner();
176
+
177
+ // Check environment
178
+ const availableProviders = displayEnvironmentCheck();
179
+
180
+ // Display stats
181
+ displayPromptStats();
182
+
183
+ // Confirm execution
184
+ sendWarning('This will execute multiple API calls to all available providers.');
185
+ sendIndented('Estimated cost: $0.15-0.30 depending on available providers.', 1);
186
+ sendIndented('Press Ctrl+C to cancel, or wait 5 seconds to continue...', 1);
187
+
188
+ // Wait 5 seconds for user to cancel
189
+ await new Promise(resolve => setTimeout(resolve, 5000));
190
+
191
+ sendInfo('Starting evaluation...');
192
+
193
+ // Initialize query engine
194
+ const engine = new ModelQueryEngine();
195
+
196
+ sendInfo('Initializing providers...');
197
+ const initResult = await engine.initializeProviders();
198
+
199
+ sendIndented(`${initResult.readyCount} provider(s) initialized`, 1);
200
+
201
+ if (initResult.errors) {
202
+ sendWarning('Some providers failed to initialize:');
203
+ for (const error of initResult.errors) {
204
+ sendIndented(`- ${error.provider}: ${error.error}`, 1);
205
+ }
206
+ }
207
+
208
+ // Run evaluation
209
+ sendInfo('Querying providers (this may take several minutes)...');
210
+
211
+ const progressCallback = createProgressCallback();
212
+ const results = await engine.evaluateAll(EVALUATION_PROMPTS, progressCallback);
213
+
214
+ sendSuccess('All evaluations complete!');
215
+
216
+ // Analyze results
217
+ sendInfo('Analyzing results...');
218
+ const analyzer = new ModelRecommendationAnalyzer(results.evaluations);
219
+ const analysis = analyzer.analyze();
220
+ sendIndented('Analysis complete', 1);
221
+
222
+ // Ensure _temp directory exists
223
+ const tempDir = ensureTempDir();
224
+
225
+ // Write JSON output
226
+ const jsonPath = path.join(tempDir, 'model-recommendations.json');
227
+ const jsonOutput = {
228
+ ...results,
229
+ analysis: analysis.analyses,
230
+ statistics: analysis.statistics
231
+ };
232
+ writeJSONOutput(jsonOutput, jsonPath);
233
+
234
+ // Write Markdown report
235
+ const markdownPath = path.join(tempDir, 'MODEL_RECOMMENDATIONS_REPORT.md');
236
+ const markdownReport = analyzer.generateMarkdownReport();
237
+ writeMarkdownOutput(markdownReport, markdownPath);
238
+
239
+ // Display summaries
240
+ displaySummary(results.summary);
241
+ displayAnalysisSummary(analysis.statistics);
242
+
243
+ // Final message
244
+ sendOutput('\n╔══════════════════════════════════════════════════════════════╗');
245
+ sendOutput('║ Evaluation Complete! ║');
246
+ sendOutput('╚══════════════════════════════════════════════════════════════╝');
247
+ sendSectionHeader('Output files');
248
+ sendIndented(`- JSON: ${jsonPath}`, 1);
249
+ sendIndented(`- Report: ${markdownPath}`, 1);
250
+
251
+ sendSectionHeader('Next steps');
252
+ sendIndented('1. Review the markdown report for provider recommendations', 1);
253
+ sendIndented('2. Compare consensus vs current defaults', 1);
254
+ sendIndented('3. Consider cost vs quality trade-offs', 1);
255
+ sendIndented('4. Update model configurations in AVC if desired', 1);
256
+
257
+ } catch (error) {
258
+ sendError(`ERROR: ${error.message}`);
259
+ sendOutput(`\nStack trace: ${error.stack}`);
260
+ process.exit(1);
261
+ }
262
+ }
263
+
264
+ // Run if executed directly
265
+ if (import.meta.url === `file://${process.argv[1]}`) {
266
+ main();
267
+ }
268
+
269
+ export { main };
@@ -0,0 +1,107 @@
1
+ /**
2
+ * OutputBuffer - Manages accumulated output as item array for Static rendering
3
+ *
4
+ * Each append() call creates one item with a unique ID, compatible with
5
+ * Ink's <Static> component which requires stable keys and never erases items.
6
+ *
7
+ * Items accumulate across commands (like a natural terminal log).
8
+ * The clear() method inserts a blank separator line between commands
9
+ * instead of erasing — Static committed content cannot be removed.
10
+ */
11
+ export class OutputBuffer {
12
+ constructor() {
13
+ this.items = [];
14
+ this.itemCounter = 0;
15
+ this.listeners = [];
16
+ }
17
+
18
+ /**
19
+ * Append content as a new item
20
+ * @param {string} content - Content to append (may contain newlines)
21
+ * @param {string|null} type - Optional message type: 'ERROR'|'WARNING'|'SUCCESS'|'INFO'|null
22
+ */
23
+ append(content, type = null) {
24
+ if (!content) return;
25
+
26
+ this.items.push({ id: ++this.itemCounter, content, type });
27
+ this.notifyListeners();
28
+ }
29
+
30
+ /**
31
+ * Insert a blank separator between commands.
32
+ * Items cannot be removed from Static rendering, so this adds a
33
+ * visual separator instead of erasing previous content.
34
+ */
35
+ clear() {
36
+ if (this.items.length > 0) {
37
+ this.items.push({ id: ++this.itemCounter, content: '' });
38
+ this.notifyListeners();
39
+ }
40
+ }
41
+
42
+ /**
43
+ * Get all items (for Static rendering)
44
+ * @returns {{id: number, content: string}[]} Copy of items array
45
+ */
46
+ getItems() {
47
+ return [...this.items];
48
+ }
49
+
50
+ /**
51
+ * Get item count
52
+ * @returns {number} Number of items
53
+ */
54
+ getItemCount() {
55
+ return this.items.length;
56
+ }
57
+
58
+ /**
59
+ * Get all lines as flat string array (for test compatibility)
60
+ * @returns {string[]} All content split by newlines
61
+ */
62
+ getLines() {
63
+ return this.items.flatMap(item => item.content.split('\n'));
64
+ }
65
+
66
+ /**
67
+ * Get line count (for backward compatibility)
68
+ * @returns {number} Total number of lines across all items
69
+ */
70
+ getLineCount() {
71
+ return this.getLines().length;
72
+ }
73
+
74
+ /**
75
+ * Reset buffer completely - removes all items.
76
+ * Used in tests for isolation between test cases.
77
+ */
78
+ reset() {
79
+ this.items = [];
80
+ this.itemCounter = 0;
81
+ this.notifyListeners();
82
+ }
83
+
84
+ /**
85
+ * Subscribe to buffer changes
86
+ * @param {Function} listener - Callback function (items) => void
87
+ * @returns {Function} Unsubscribe function
88
+ */
89
+ subscribe(listener) {
90
+ this.listeners.push(listener);
91
+ return () => {
92
+ this.listeners = this.listeners.filter(l => l !== listener);
93
+ };
94
+ }
95
+
96
+ /**
97
+ * Notify all listeners of buffer change
98
+ * @private
99
+ */
100
+ notifyListeners() {
101
+ const items = this.getItems();
102
+ this.listeners.forEach(listener => listener(items));
103
+ }
104
+ }
105
+
106
+ // Singleton instance
107
+ export const outputBuffer = new OutputBuffer();
@@ -1,4 +1,4 @@
1
- import { spawn } from 'child_process';
1
+ import { spawn, fork } from 'child_process';
2
2
  import { EventEmitter } from 'events';
3
3
 
4
4
  /**
@@ -73,6 +73,63 @@ export class BackgroundProcessManager extends EventEmitter {
73
73
  return id;
74
74
  }
75
75
 
76
+ /**
77
+ * Fork a background process with an IPC channel.
78
+ * Identical metadata schema to startProcess(); also registers an IPC message handler.
79
+ * @param {string} name - Human-readable name
80
+ * @param {string} modulePath - Absolute path to the Node.js module to fork
81
+ * @param {string[]} args - Module arguments
82
+ * @param {Function} onMessage - Called with each IPC message from the child
83
+ * @returns {{ id: string, child: ChildProcess }}
84
+ */
85
+ forkProcess(name, modulePath, args = [], onMessage) {
86
+ const id = `${this.sanitizeName(name)}-${Date.now()}`;
87
+
88
+ const child = fork(modulePath, args, {
89
+ stdio: ['ignore', 'pipe', 'pipe', 'ipc'],
90
+ });
91
+
92
+ const metadata = {
93
+ id,
94
+ name,
95
+ command: modulePath,
96
+ pid: child.pid,
97
+ status: 'running',
98
+ startTime: new Date().toISOString(),
99
+ exitCode: null,
100
+ exitSignal: null,
101
+ output: [],
102
+ process: child
103
+ };
104
+
105
+ this.processes.set(id, metadata);
106
+
107
+ // Capture stdout / stderr (same as startProcess)
108
+ child.stdout?.on('data', (data) => {
109
+ this.appendOutput(id, 'stdout', data.toString());
110
+ });
111
+
112
+ child.stderr?.on('data', (data) => {
113
+ this.appendOutput(id, 'stderr', data.toString());
114
+ });
115
+
116
+ // Handle process exit / error
117
+ child.on('exit', (code, signal) => {
118
+ this.handleProcessExit(id, code, signal);
119
+ });
120
+
121
+ child.on('error', (error) => {
122
+ this.handleProcessError(id, error);
123
+ });
124
+
125
+ // Register IPC message handler
126
+ if (onMessage) child.on('message', onMessage);
127
+
128
+ this.emit('process-started', { id, name });
129
+
130
+ return { id, child };
131
+ }
132
+
76
133
  /**
77
134
  * Stop a running process
78
135
  */
@@ -175,7 +232,12 @@ export class BackgroundProcessManager extends EventEmitter {
175
232
 
176
233
  metadata.exitCode = code;
177
234
  metadata.exitSignal = signal;
178
- metadata.status = code === 0 ? 'exited' : 'crashed';
235
+
236
+ // Don't overwrite 'stopped' status (intentional termination via stopProcess)
237
+ // Only set crashed/exited if process wasn't manually stopped
238
+ if (metadata.status !== 'stopped') {
239
+ metadata.status = code === 0 ? 'exited' : 'crashed';
240
+ }
179
241
 
180
242
  this.emit('process-exited', {
181
243
  id,
@@ -184,6 +246,15 @@ export class BackgroundProcessManager extends EventEmitter {
184
246
  signal,
185
247
  status: metadata.status
186
248
  });
249
+
250
+ // Auto-cleanup finished processes after 3 seconds
251
+ // Gives user time to see final status before removal
252
+ setTimeout(() => {
253
+ if (this.processes.has(id)) {
254
+ this.processes.delete(id);
255
+ this.emit('process-removed', { id, name: metadata.name });
256
+ }
257
+ }, 3000);
187
258
  }
188
259
 
189
260
  /**