@agile-vibe-coding/avc 0.1.0 → 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 (290) hide show
  1. package/README.md +2 -0
  2. package/cli/agent-loader.js +21 -0
  3. package/cli/agents/agent-selector.md +129 -0
  4. package/cli/agents/architecture-recommender.md +418 -0
  5. package/cli/agents/database-deep-dive.md +470 -0
  6. package/cli/agents/database-recommender.md +634 -0
  7. package/cli/agents/doc-distributor.md +176 -0
  8. package/cli/agents/documentation-updater.md +203 -0
  9. package/cli/agents/epic-story-decomposer.md +280 -0
  10. package/cli/agents/feature-context-generator.md +91 -0
  11. package/cli/agents/gap-checker-epic.md +52 -0
  12. package/cli/agents/impact-checker-story.md +51 -0
  13. package/cli/agents/migration-guide-generator.md +305 -0
  14. package/cli/agents/mission-scope-generator.md +79 -0
  15. package/cli/agents/mission-scope-validator.md +112 -0
  16. package/cli/agents/project-context-extractor.md +107 -0
  17. package/cli/agents/project-documentation-creator.json +226 -0
  18. package/cli/agents/project-documentation-creator.md +595 -0
  19. package/cli/agents/question-prefiller.md +269 -0
  20. package/cli/agents/refiner-epic.md +39 -0
  21. package/cli/agents/refiner-story.md +42 -0
  22. package/cli/agents/solver-epic-api.json +15 -0
  23. package/cli/agents/solver-epic-api.md +39 -0
  24. package/cli/agents/solver-epic-backend.json +15 -0
  25. package/cli/agents/solver-epic-backend.md +39 -0
  26. package/cli/agents/solver-epic-cloud.json +15 -0
  27. package/cli/agents/solver-epic-cloud.md +39 -0
  28. package/cli/agents/solver-epic-data.json +15 -0
  29. package/cli/agents/solver-epic-data.md +39 -0
  30. package/cli/agents/solver-epic-database.json +15 -0
  31. package/cli/agents/solver-epic-database.md +39 -0
  32. package/cli/agents/solver-epic-developer.json +15 -0
  33. package/cli/agents/solver-epic-developer.md +39 -0
  34. package/cli/agents/solver-epic-devops.json +15 -0
  35. package/cli/agents/solver-epic-devops.md +39 -0
  36. package/cli/agents/solver-epic-frontend.json +15 -0
  37. package/cli/agents/solver-epic-frontend.md +39 -0
  38. package/cli/agents/solver-epic-mobile.json +15 -0
  39. package/cli/agents/solver-epic-mobile.md +39 -0
  40. package/cli/agents/solver-epic-qa.json +15 -0
  41. package/cli/agents/solver-epic-qa.md +39 -0
  42. package/cli/agents/solver-epic-security.json +15 -0
  43. package/cli/agents/solver-epic-security.md +39 -0
  44. package/cli/agents/solver-epic-solution-architect.json +15 -0
  45. package/cli/agents/solver-epic-solution-architect.md +39 -0
  46. package/cli/agents/solver-epic-test-architect.json +15 -0
  47. package/cli/agents/solver-epic-test-architect.md +39 -0
  48. package/cli/agents/solver-epic-ui.json +15 -0
  49. package/cli/agents/solver-epic-ui.md +39 -0
  50. package/cli/agents/solver-epic-ux.json +15 -0
  51. package/cli/agents/solver-epic-ux.md +39 -0
  52. package/cli/agents/solver-story-api.json +15 -0
  53. package/cli/agents/solver-story-api.md +39 -0
  54. package/cli/agents/solver-story-backend.json +15 -0
  55. package/cli/agents/solver-story-backend.md +39 -0
  56. package/cli/agents/solver-story-cloud.json +15 -0
  57. package/cli/agents/solver-story-cloud.md +39 -0
  58. package/cli/agents/solver-story-data.json +15 -0
  59. package/cli/agents/solver-story-data.md +39 -0
  60. package/cli/agents/solver-story-database.json +15 -0
  61. package/cli/agents/solver-story-database.md +39 -0
  62. package/cli/agents/solver-story-developer.json +15 -0
  63. package/cli/agents/solver-story-developer.md +39 -0
  64. package/cli/agents/solver-story-devops.json +15 -0
  65. package/cli/agents/solver-story-devops.md +39 -0
  66. package/cli/agents/solver-story-frontend.json +15 -0
  67. package/cli/agents/solver-story-frontend.md +39 -0
  68. package/cli/agents/solver-story-mobile.json +15 -0
  69. package/cli/agents/solver-story-mobile.md +39 -0
  70. package/cli/agents/solver-story-qa.json +15 -0
  71. package/cli/agents/solver-story-qa.md +39 -0
  72. package/cli/agents/solver-story-security.json +15 -0
  73. package/cli/agents/solver-story-security.md +39 -0
  74. package/cli/agents/solver-story-solution-architect.json +15 -0
  75. package/cli/agents/solver-story-solution-architect.md +39 -0
  76. package/cli/agents/solver-story-test-architect.json +15 -0
  77. package/cli/agents/solver-story-test-architect.md +39 -0
  78. package/cli/agents/solver-story-ui.json +15 -0
  79. package/cli/agents/solver-story-ui.md +39 -0
  80. package/cli/agents/solver-story-ux.json +15 -0
  81. package/cli/agents/solver-story-ux.md +39 -0
  82. package/cli/agents/story-doc-enricher.md +133 -0
  83. package/cli/agents/suggestion-business-analyst.md +88 -0
  84. package/cli/agents/suggestion-deployment-architect.md +263 -0
  85. package/cli/agents/suggestion-product-manager.md +129 -0
  86. package/cli/agents/suggestion-security-specialist.md +156 -0
  87. package/cli/agents/suggestion-technical-architect.md +269 -0
  88. package/cli/agents/suggestion-ux-researcher.md +93 -0
  89. package/cli/agents/task-subtask-decomposer.md +188 -0
  90. package/cli/agents/validator-documentation.json +152 -0
  91. package/cli/agents/validator-documentation.md +453 -0
  92. package/cli/agents/validator-epic-api.json +93 -0
  93. package/cli/agents/validator-epic-api.md +137 -0
  94. package/cli/agents/validator-epic-backend.json +93 -0
  95. package/cli/agents/validator-epic-backend.md +130 -0
  96. package/cli/agents/validator-epic-cloud.json +93 -0
  97. package/cli/agents/validator-epic-cloud.md +137 -0
  98. package/cli/agents/validator-epic-data.json +93 -0
  99. package/cli/agents/validator-epic-data.md +130 -0
  100. package/cli/agents/validator-epic-database.json +93 -0
  101. package/cli/agents/validator-epic-database.md +137 -0
  102. package/cli/agents/validator-epic-developer.json +74 -0
  103. package/cli/agents/validator-epic-developer.md +153 -0
  104. package/cli/agents/validator-epic-devops.json +74 -0
  105. package/cli/agents/validator-epic-devops.md +153 -0
  106. package/cli/agents/validator-epic-frontend.json +74 -0
  107. package/cli/agents/validator-epic-frontend.md +153 -0
  108. package/cli/agents/validator-epic-mobile.json +93 -0
  109. package/cli/agents/validator-epic-mobile.md +130 -0
  110. package/cli/agents/validator-epic-qa.json +93 -0
  111. package/cli/agents/validator-epic-qa.md +130 -0
  112. package/cli/agents/validator-epic-security.json +74 -0
  113. package/cli/agents/validator-epic-security.md +154 -0
  114. package/cli/agents/validator-epic-solution-architect.json +74 -0
  115. package/cli/agents/validator-epic-solution-architect.md +156 -0
  116. package/cli/agents/validator-epic-test-architect.json +93 -0
  117. package/cli/agents/validator-epic-test-architect.md +130 -0
  118. package/cli/agents/validator-epic-ui.json +93 -0
  119. package/cli/agents/validator-epic-ui.md +130 -0
  120. package/cli/agents/validator-epic-ux.json +93 -0
  121. package/cli/agents/validator-epic-ux.md +130 -0
  122. package/cli/agents/validator-selector.md +211 -0
  123. package/cli/agents/validator-story-api.json +104 -0
  124. package/cli/agents/validator-story-api.md +152 -0
  125. package/cli/agents/validator-story-backend.json +104 -0
  126. package/cli/agents/validator-story-backend.md +152 -0
  127. package/cli/agents/validator-story-cloud.json +104 -0
  128. package/cli/agents/validator-story-cloud.md +152 -0
  129. package/cli/agents/validator-story-data.json +104 -0
  130. package/cli/agents/validator-story-data.md +152 -0
  131. package/cli/agents/validator-story-database.json +104 -0
  132. package/cli/agents/validator-story-database.md +152 -0
  133. package/cli/agents/validator-story-developer.json +104 -0
  134. package/cli/agents/validator-story-developer.md +152 -0
  135. package/cli/agents/validator-story-devops.json +104 -0
  136. package/cli/agents/validator-story-devops.md +152 -0
  137. package/cli/agents/validator-story-frontend.json +104 -0
  138. package/cli/agents/validator-story-frontend.md +152 -0
  139. package/cli/agents/validator-story-mobile.json +104 -0
  140. package/cli/agents/validator-story-mobile.md +152 -0
  141. package/cli/agents/validator-story-qa.json +104 -0
  142. package/cli/agents/validator-story-qa.md +152 -0
  143. package/cli/agents/validator-story-security.json +104 -0
  144. package/cli/agents/validator-story-security.md +152 -0
  145. package/cli/agents/validator-story-solution-architect.json +104 -0
  146. package/cli/agents/validator-story-solution-architect.md +152 -0
  147. package/cli/agents/validator-story-test-architect.json +104 -0
  148. package/cli/agents/validator-story-test-architect.md +152 -0
  149. package/cli/agents/validator-story-ui.json +104 -0
  150. package/cli/agents/validator-story-ui.md +152 -0
  151. package/cli/agents/validator-story-ux.json +104 -0
  152. package/cli/agents/validator-story-ux.md +152 -0
  153. package/cli/ansi-colors.js +21 -0
  154. package/cli/build-docs.js +298 -0
  155. package/cli/ceremony-history.js +369 -0
  156. package/cli/command-logger.js +245 -0
  157. package/cli/components/static-output.js +63 -0
  158. package/cli/console-output-manager.js +94 -0
  159. package/cli/docs-sync.js +306 -0
  160. package/cli/epic-story-validator.js +1174 -0
  161. package/cli/evaluation-prompts.js +1008 -0
  162. package/cli/execution-context.js +195 -0
  163. package/cli/generate-summary-table.js +340 -0
  164. package/cli/index.js +3 -25
  165. package/cli/init-model-config.js +697 -0
  166. package/cli/init.js +1765 -100
  167. package/cli/kanban-server-manager.js +228 -0
  168. package/cli/llm-claude.js +109 -0
  169. package/cli/llm-gemini.js +115 -0
  170. package/cli/llm-mock.js +233 -0
  171. package/cli/llm-openai.js +233 -0
  172. package/cli/llm-provider.js +300 -0
  173. package/cli/llm-token-limits.js +102 -0
  174. package/cli/llm-verifier.js +454 -0
  175. package/cli/logger.js +32 -5
  176. package/cli/message-constants.js +58 -0
  177. package/cli/message-manager.js +334 -0
  178. package/cli/message-types.js +96 -0
  179. package/cli/messaging-api.js +297 -0
  180. package/cli/model-pricing.js +169 -0
  181. package/cli/model-query-engine.js +468 -0
  182. package/cli/model-recommendation-analyzer.js +495 -0
  183. package/cli/model-selector.js +269 -0
  184. package/cli/output-buffer.js +107 -0
  185. package/cli/process-manager.js +332 -0
  186. package/cli/repl-ink.js +5840 -504
  187. package/cli/repl-old.js +4 -4
  188. package/cli/seed-processor.js +792 -0
  189. package/cli/sprint-planning-processor.js +1813 -0
  190. package/cli/template-processor.js +2306 -108
  191. package/cli/templates/project.md +25 -8
  192. package/cli/templates/vitepress-config.mts.template +34 -0
  193. package/cli/token-tracker.js +520 -0
  194. package/cli/tools/generate-story-validators.js +317 -0
  195. package/cli/tools/generate-validators.js +669 -0
  196. package/cli/update-checker.js +19 -17
  197. package/cli/update-notifier.js +4 -4
  198. package/cli/validation-router.js +605 -0
  199. package/cli/verification-tracker.js +563 -0
  200. package/kanban/README.md +386 -0
  201. package/kanban/client/README.md +205 -0
  202. package/kanban/client/components.json +20 -0
  203. package/kanban/client/dist/assets/index-CiD8PS2e.js +306 -0
  204. package/kanban/client/dist/assets/index-nLh0m82Q.css +1 -0
  205. package/kanban/client/dist/index.html +16 -0
  206. package/kanban/client/dist/vite.svg +1 -0
  207. package/kanban/client/index.html +15 -0
  208. package/kanban/client/package-lock.json +9442 -0
  209. package/kanban/client/package.json +44 -0
  210. package/kanban/client/postcss.config.js +6 -0
  211. package/kanban/client/public/vite.svg +1 -0
  212. package/kanban/client/src/App.jsx +622 -0
  213. package/kanban/client/src/components/ProjectFileEditorPopup.jsx +117 -0
  214. package/kanban/client/src/components/ceremony/AskArchPopup.jsx +416 -0
  215. package/kanban/client/src/components/ceremony/AskModelPopup.jsx +616 -0
  216. package/kanban/client/src/components/ceremony/CeremonyWorkflowModal.jsx +946 -0
  217. package/kanban/client/src/components/ceremony/EpicStorySelectionModal.jsx +254 -0
  218. package/kanban/client/src/components/ceremony/SponsorCallModal.jsx +619 -0
  219. package/kanban/client/src/components/ceremony/SprintPlanningModal.jsx +704 -0
  220. package/kanban/client/src/components/ceremony/steps/ArchitectureStep.jsx +150 -0
  221. package/kanban/client/src/components/ceremony/steps/CompleteStep.jsx +154 -0
  222. package/kanban/client/src/components/ceremony/steps/DatabaseStep.jsx +202 -0
  223. package/kanban/client/src/components/ceremony/steps/DeploymentStep.jsx +123 -0
  224. package/kanban/client/src/components/ceremony/steps/MissionStep.jsx +106 -0
  225. package/kanban/client/src/components/ceremony/steps/ReviewAnswersStep.jsx +125 -0
  226. package/kanban/client/src/components/ceremony/steps/RunningStep.jsx +228 -0
  227. package/kanban/client/src/components/kanban/CardDetailModal.jsx +559 -0
  228. package/kanban/client/src/components/kanban/EpicSection.jsx +146 -0
  229. package/kanban/client/src/components/kanban/FilterToolbar.jsx +222 -0
  230. package/kanban/client/src/components/kanban/GroupingSelector.jsx +57 -0
  231. package/kanban/client/src/components/kanban/KanbanBoard.jsx +211 -0
  232. package/kanban/client/src/components/kanban/KanbanCard.jsx +138 -0
  233. package/kanban/client/src/components/kanban/KanbanColumn.jsx +90 -0
  234. package/kanban/client/src/components/kanban/RefineWorkItemPopup.jsx +789 -0
  235. package/kanban/client/src/components/layout/LoadingScreen.jsx +82 -0
  236. package/kanban/client/src/components/process/ProcessMonitorBar.jsx +80 -0
  237. package/kanban/client/src/components/settings/AgentEditorPopup.jsx +171 -0
  238. package/kanban/client/src/components/settings/AgentsTab.jsx +353 -0
  239. package/kanban/client/src/components/settings/ApiKeysTab.jsx +113 -0
  240. package/kanban/client/src/components/settings/CeremonyModelsTab.jsx +98 -0
  241. package/kanban/client/src/components/settings/CostThresholdsTab.jsx +94 -0
  242. package/kanban/client/src/components/settings/ModelPricingTab.jsx +204 -0
  243. package/kanban/client/src/components/settings/ServersTab.jsx +121 -0
  244. package/kanban/client/src/components/settings/SettingsModal.jsx +84 -0
  245. package/kanban/client/src/components/stats/CostModal.jsx +353 -0
  246. package/kanban/client/src/components/ui/badge.jsx +27 -0
  247. package/kanban/client/src/components/ui/dialog.jsx +121 -0
  248. package/kanban/client/src/components/ui/tabs.jsx +85 -0
  249. package/kanban/client/src/hooks/__tests__/useGrouping.test.js +232 -0
  250. package/kanban/client/src/hooks/useGrouping.js +118 -0
  251. package/kanban/client/src/hooks/useWebSocket.js +120 -0
  252. package/kanban/client/src/lib/__tests__/api.test.js +196 -0
  253. package/kanban/client/src/lib/__tests__/status-grouping.test.js +94 -0
  254. package/kanban/client/src/lib/api.js +401 -0
  255. package/kanban/client/src/lib/status-grouping.js +144 -0
  256. package/kanban/client/src/lib/utils.js +11 -0
  257. package/kanban/client/src/main.jsx +10 -0
  258. package/kanban/client/src/store/__tests__/kanbanStore.test.js +164 -0
  259. package/kanban/client/src/store/ceremonyStore.js +172 -0
  260. package/kanban/client/src/store/filterStore.js +201 -0
  261. package/kanban/client/src/store/kanbanStore.js +115 -0
  262. package/kanban/client/src/store/processStore.js +65 -0
  263. package/kanban/client/src/store/sprintPlanningStore.js +33 -0
  264. package/kanban/client/src/styles/globals.css +59 -0
  265. package/kanban/client/tailwind.config.js +77 -0
  266. package/kanban/client/vite.config.js +28 -0
  267. package/kanban/client/vitest.config.js +28 -0
  268. package/kanban/dev-start.sh +47 -0
  269. package/kanban/package.json +12 -0
  270. package/kanban/server/index.js +516 -0
  271. package/kanban/server/routes/ceremony.js +305 -0
  272. package/kanban/server/routes/costs.js +157 -0
  273. package/kanban/server/routes/processes.js +50 -0
  274. package/kanban/server/routes/settings.js +303 -0
  275. package/kanban/server/routes/websocket.js +276 -0
  276. package/kanban/server/routes/work-items.js +347 -0
  277. package/kanban/server/services/CeremonyService.js +1190 -0
  278. package/kanban/server/services/FileSystemScanner.js +95 -0
  279. package/kanban/server/services/FileWatcher.js +144 -0
  280. package/kanban/server/services/HierarchyBuilder.js +196 -0
  281. package/kanban/server/services/ProcessRegistry.js +122 -0
  282. package/kanban/server/services/WorkItemReader.js +123 -0
  283. package/kanban/server/services/WorkItemRefineService.js +510 -0
  284. package/kanban/server/start.js +49 -0
  285. package/kanban/server/utils/kanban-logger.js +132 -0
  286. package/kanban/server/utils/markdown.js +91 -0
  287. package/kanban/server/utils/status-grouping.js +107 -0
  288. package/kanban/server/workers/sponsor-call-worker.js +84 -0
  289. package/kanban/server/workers/sprint-planning-worker.js +130 -0
  290. package/package.json +34 -7
@@ -0,0 +1,228 @@
1
+ import { exec } from 'child_process';
2
+ import { promisify } from 'util';
3
+ import path from 'path';
4
+ import fs from 'fs';
5
+ import net from 'net';
6
+ import http from 'http';
7
+
8
+ const execAsync = promisify(exec);
9
+
10
+ /**
11
+ * Kanban Server Manager
12
+ * Manages lifecycle of the AVC Kanban Board server
13
+ */
14
+ export class KanbanServerManager {
15
+ constructor(projectRoot = process.cwd()) {
16
+ this.projectRoot = projectRoot;
17
+ this.avcDir = path.join(projectRoot, '.avc');
18
+ this.avcProjectPath = path.join(this.avcDir, 'project');
19
+ }
20
+
21
+ /**
22
+ * Check if .avc/project directory exists
23
+ */
24
+ hasWorkItems() {
25
+ return fs.existsSync(this.avcProjectPath);
26
+ }
27
+
28
+ /**
29
+ * Get kanban server port from avc.json config
30
+ * Returns default port 4174 if not configured
31
+ */
32
+ getPort() {
33
+ const configPath = path.join(this.avcDir, 'avc.json');
34
+
35
+ if (!fs.existsSync(configPath)) {
36
+ return 4174; // Default port
37
+ }
38
+
39
+ try {
40
+ const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
41
+ return config.settings?.kanban?.port || 4174;
42
+ } catch (error) {
43
+ console.warn(`Could not read port from avc.json: ${error.message}`);
44
+ return 4174;
45
+ }
46
+ }
47
+
48
+ /**
49
+ * Check if a port is in use
50
+ * @param {number} port - Port number to check
51
+ * @returns {Promise<boolean>} - True if port is in use
52
+ */
53
+ async isPortInUse(port) {
54
+ return new Promise((resolve) => {
55
+ const server = net.createServer();
56
+
57
+ server.once('error', (err) => {
58
+ if (err.code === 'EADDRINUSE') {
59
+ resolve(true); // Port is in use
60
+ } else {
61
+ resolve(false);
62
+ }
63
+ });
64
+
65
+ server.once('listening', () => {
66
+ server.close();
67
+ resolve(false); // Port is available
68
+ });
69
+
70
+ server.listen(port, '127.0.0.1');
71
+ });
72
+ }
73
+
74
+ /**
75
+ * Check if the server on this port is the AVC Kanban Board
76
+ * Makes HTTP request to /api/health and checks for AVC kanban response
77
+ * @param {number} port - Port number to check
78
+ * @returns {Promise<boolean>} - True if it's confirmed to be AVC kanban server
79
+ */
80
+ async isKanbanServer(port) {
81
+ return new Promise((resolve) => {
82
+ const req = http.get(`http://localhost:${port}/api/health`, {
83
+ timeout: 2000,
84
+ }, (res) => {
85
+ let data = '';
86
+
87
+ res.on('data', (chunk) => {
88
+ data += chunk;
89
+ });
90
+
91
+ res.on('end', () => {
92
+ try {
93
+ const json = JSON.parse(data);
94
+ // Check if it's our AVC kanban server
95
+ const isKanban = json.projectRoot === this.projectRoot;
96
+ resolve(isKanban);
97
+ } catch {
98
+ resolve(false);
99
+ }
100
+ });
101
+ });
102
+
103
+ req.on('error', () => {
104
+ resolve(false); // Can't connect or verify
105
+ });
106
+
107
+ req.on('timeout', () => {
108
+ req.destroy();
109
+ resolve(false);
110
+ });
111
+ });
112
+ }
113
+
114
+ /**
115
+ * Find which process is using a port
116
+ * Works cross-platform (Linux, macOS, Windows)
117
+ * @param {number} port - Port number to check
118
+ * @returns {Promise<{pid: number, command: string} | null>} - Process info or null if not found
119
+ */
120
+ async findProcessUsingPort(port) {
121
+ try {
122
+ let command;
123
+ let parseOutput;
124
+
125
+ if (process.platform === 'win32') {
126
+ // Windows: netstat -ano | findstr :PORT
127
+ command = `netstat -ano | findstr :${port}`;
128
+ parseOutput = (output) => {
129
+ const lines = output.split('\n');
130
+ for (const line of lines) {
131
+ if (
132
+ line.includes(`0.0.0.0:${port}`) ||
133
+ line.includes(`127.0.0.1:${port}`) ||
134
+ line.includes(`[::]:${port}`)
135
+ ) {
136
+ const parts = line.trim().split(/\s+/);
137
+ const pid = parseInt(parts[parts.length - 1]);
138
+ if (pid && !isNaN(pid)) {
139
+ return { pid, command: 'Unknown' };
140
+ }
141
+ }
142
+ }
143
+ return null;
144
+ };
145
+ } else {
146
+ // Linux/macOS: lsof -i :PORT
147
+ command = `lsof -i :${port} -t -sTCP:LISTEN`;
148
+ parseOutput = (output) => {
149
+ const pid = parseInt(output.trim());
150
+ if (pid && !isNaN(pid)) {
151
+ // Try to get process name
152
+ try {
153
+ const { execSync } = require('child_process');
154
+ const psOutput = execSync(`ps -p ${pid} -o comm=`, { encoding: 'utf8' });
155
+ return { pid, command: psOutput.trim() };
156
+ } catch {
157
+ return { pid, command: 'Unknown' };
158
+ }
159
+ }
160
+ return null;
161
+ };
162
+ }
163
+
164
+ const { stdout } = await execAsync(command);
165
+ return parseOutput(stdout);
166
+ } catch (error) {
167
+ // Command failed (no process found) or permission error
168
+ return null;
169
+ }
170
+ }
171
+
172
+ /**
173
+ * Kill a process by PID
174
+ * @param {number} pid - Process ID to kill
175
+ * @returns {Promise<boolean>} - True if kill succeeded
176
+ */
177
+ async killProcess(pid) {
178
+ try {
179
+ if (process.platform === 'win32') {
180
+ await execAsync(`taskkill /F /PID ${pid}`);
181
+ } else {
182
+ await execAsync(`kill -9 ${pid}`);
183
+ }
184
+ return true;
185
+ } catch (error) {
186
+ console.error(`Failed to kill process ${pid}:`, error.message);
187
+ return false;
188
+ }
189
+ }
190
+
191
+ /**
192
+ * Get the frontend dev server URL (Vite)
193
+ * @returns {string} Frontend URL
194
+ */
195
+ getFrontendUrl() {
196
+ const config = this.getConfig();
197
+ const frontendPort = config.settings?.kanban?.frontendPort || 5173;
198
+ return `http://localhost:${frontendPort}`;
199
+ }
200
+
201
+ /**
202
+ * Get the backend API server URL
203
+ * @returns {string} Backend URL
204
+ */
205
+ getBackendUrl() {
206
+ const port = this.getPort();
207
+ return `http://localhost:${port}`;
208
+ }
209
+
210
+ /**
211
+ * Get AVC configuration
212
+ * @returns {object} Configuration object
213
+ */
214
+ getConfig() {
215
+ const configPath = path.join(this.avcDir, 'avc.json');
216
+
217
+ if (!fs.existsSync(configPath)) {
218
+ return { settings: {} };
219
+ }
220
+
221
+ try {
222
+ return JSON.parse(fs.readFileSync(configPath, 'utf8'));
223
+ } catch (error) {
224
+ console.warn(`Could not read avc.json: ${error.message}`);
225
+ return { settings: {} };
226
+ }
227
+ }
228
+ }
@@ -0,0 +1,109 @@
1
+ import Anthropic from '@anthropic-ai/sdk';
2
+ import { jsonrepair } from 'jsonrepair';
3
+ import { LLMProvider } from './llm-provider.js';
4
+ import { getMaxTokensForModel } from './llm-token-limits.js';
5
+
6
+ export class ClaudeProvider extends LLMProvider {
7
+ constructor(model) { super('claude', model); }
8
+
9
+ _createClient() {
10
+ const apiKey = process.env.ANTHROPIC_API_KEY;
11
+ if (!apiKey) throw new Error('ANTHROPIC_API_KEY not set. Add it to your .env file.');
12
+ // 5-minute timeout per request; SDK retries disabled so our retryWithBackoff
13
+ // handles all retries with full logging visibility.
14
+ return new Anthropic({ apiKey, timeout: 5 * 60 * 1000, maxRetries: 0 });
15
+ }
16
+
17
+ async _callProvider(prompt, maxTokens, systemInstructions) {
18
+ const params = {
19
+ model: this.model,
20
+ max_tokens: maxTokens,
21
+ messages: [{ role: 'user', content: prompt }]
22
+ };
23
+
24
+ if (systemInstructions) {
25
+ params.system = systemInstructions;
26
+ }
27
+
28
+ const response = await this._client.messages.create(params);
29
+ this._trackTokens(response.usage);
30
+ return response.content[0].text;
31
+ }
32
+
33
+ async generateJSON(prompt, agentInstructions = null) {
34
+ if (!this._client) {
35
+ this._client = this._createClient();
36
+ }
37
+
38
+ const fullPrompt = agentInstructions ? `${agentInstructions}\n\n${prompt}` : prompt;
39
+
40
+ // Use model-specific maximum tokens
41
+ const maxTokens = getMaxTokensForModel(this.model);
42
+
43
+ const response = await this._withRetry(
44
+ () => this._client.messages.create({
45
+ model: this.model,
46
+ max_tokens: maxTokens,
47
+ messages: [{
48
+ role: 'user',
49
+ content: fullPrompt
50
+ }],
51
+ system: 'You are a helpful assistant that always returns valid JSON. Your response must be a valid JSON object or array, nothing else.'
52
+ }),
53
+ 'JSON generation (Claude)'
54
+ );
55
+
56
+ this._trackTokens(response.usage);
57
+ const content = response.content[0].text;
58
+
59
+ // Extract JSON from response (handle markdown code blocks)
60
+ // Strip markdown code fences if present (more robust)
61
+ let jsonStr = content.trim();
62
+ if (jsonStr.startsWith('```')) {
63
+ // Remove opening fence (```json or ```)
64
+ jsonStr = jsonStr.replace(/^```(?:json)?\s*\n?/, '');
65
+ // Remove closing fence
66
+ jsonStr = jsonStr.replace(/\n?\s*```\s*$/, '');
67
+ jsonStr = jsonStr.trim();
68
+ }
69
+
70
+ try {
71
+ return JSON.parse(jsonStr);
72
+ } catch (firstError) {
73
+ // Only attempt repair when the content looks like JSON (starts with { or [)
74
+ // — avoids silently accepting completely non-JSON responses
75
+ if (jsonStr.startsWith('{') || jsonStr.startsWith('[')) {
76
+ try {
77
+ return JSON.parse(jsonrepair(jsonStr));
78
+ } catch { /* fall through to throw */ }
79
+ }
80
+ throw new Error(`Failed to parse JSON response: ${firstError.message}\n\nResponse was:\n${content}`);
81
+ }
82
+ }
83
+
84
+ async generateText(prompt, agentInstructions = null) {
85
+ if (!this._client) {
86
+ this._client = this._createClient();
87
+ }
88
+
89
+ const fullPrompt = agentInstructions ? `${agentInstructions}\n\n${prompt}` : prompt;
90
+
91
+ // Use model-specific maximum tokens
92
+ const maxTokens = getMaxTokensForModel(this.model);
93
+
94
+ const response = await this._withRetry(
95
+ () => this._client.messages.create({
96
+ model: this.model,
97
+ max_tokens: maxTokens,
98
+ messages: [{
99
+ role: 'user',
100
+ content: fullPrompt
101
+ }]
102
+ }),
103
+ 'Text generation (Claude)'
104
+ );
105
+
106
+ this._trackTokens(response.usage);
107
+ return response.content[0].text;
108
+ }
109
+ }
@@ -0,0 +1,115 @@
1
+ import { GoogleGenAI } from '@google/genai';
2
+ import { jsonrepair } from 'jsonrepair';
3
+ import { LLMProvider } from './llm-provider.js';
4
+ import { getMaxTokensForModel } from './llm-token-limits.js';
5
+
6
+ export class GeminiProvider extends LLMProvider {
7
+ constructor(model = 'gemini-2.5-flash') { super('gemini', model); }
8
+
9
+ _createClient() {
10
+ const apiKey = process.env.GEMINI_API_KEY;
11
+ if (!apiKey) throw new Error('GEMINI_API_KEY not set. Add it to your .env file.');
12
+ return new GoogleGenAI({ apiKey });
13
+ }
14
+
15
+ async _callProvider(prompt, maxTokens, systemInstructions) {
16
+ const params = {
17
+ model: this.model,
18
+ contents: prompt,
19
+ generationConfig: { maxOutputTokens: maxTokens }
20
+ };
21
+
22
+ if (systemInstructions) {
23
+ params.systemInstruction = systemInstructions;
24
+ }
25
+
26
+ const response = await this._client.models.generateContent(params);
27
+ if (!response.text) {
28
+ throw new Error('Gemini returned no text (possible safety filter block).');
29
+ }
30
+ this._trackTokens(response.usageMetadata);
31
+ return response.text;
32
+ }
33
+
34
+ async generateJSON(prompt, agentInstructions = null) {
35
+ if (!this._client) {
36
+ this._client = this._createClient();
37
+ }
38
+
39
+ const fullPrompt = agentInstructions ? `${agentInstructions}\n\n${prompt}` : prompt;
40
+
41
+ // Use model-specific maximum tokens
42
+ const maxTokens = getMaxTokensForModel(this.model);
43
+
44
+ const params = {
45
+ model: this.model,
46
+ contents: fullPrompt,
47
+ generationConfig: {
48
+ responseMimeType: 'application/json', // Gemini's native JSON mode
49
+ maxOutputTokens: maxTokens
50
+ }
51
+ };
52
+
53
+ const response = await this._withRetry(
54
+ () => this._client.models.generateContent(params),
55
+ 'JSON generation (Gemini)'
56
+ );
57
+ if (!response.text) {
58
+ throw new Error('Gemini returned no text (possible safety filter block).');
59
+ }
60
+
61
+ this._trackTokens(response.usageMetadata);
62
+ const content = response.text;
63
+
64
+ // Strip markdown code fences if present (more robust)
65
+ let jsonStr = content.trim();
66
+ if (jsonStr.startsWith('```')) {
67
+ // Remove opening fence (```json or ```)
68
+ jsonStr = jsonStr.replace(/^```(?:json)?\s*\n?/, '');
69
+ // Remove closing fence
70
+ jsonStr = jsonStr.replace(/\n?\s*```\s*$/, '');
71
+ jsonStr = jsonStr.trim();
72
+ }
73
+
74
+ try {
75
+ return JSON.parse(jsonStr);
76
+ } catch (firstError) {
77
+ if (jsonStr.startsWith('{') || jsonStr.startsWith('[')) {
78
+ try {
79
+ return JSON.parse(jsonrepair(jsonStr));
80
+ } catch { /* fall through to throw */ }
81
+ }
82
+ throw new Error(`Failed to parse JSON response: ${firstError.message}\n\nResponse was:\n${content}`);
83
+ }
84
+ }
85
+
86
+ async generateText(prompt, agentInstructions = null) {
87
+ if (!this._client) {
88
+ this._client = this._createClient();
89
+ }
90
+
91
+ const fullPrompt = agentInstructions ? `${agentInstructions}\n\n${prompt}` : prompt;
92
+
93
+ // Use model-specific maximum tokens
94
+ const maxTokens = getMaxTokensForModel(this.model);
95
+
96
+ const params = {
97
+ model: this.model,
98
+ contents: fullPrompt,
99
+ generationConfig: {
100
+ maxOutputTokens: maxTokens
101
+ }
102
+ };
103
+
104
+ const response = await this._withRetry(
105
+ () => this._client.models.generateContent(params),
106
+ 'Text generation (Gemini)'
107
+ );
108
+ if (!response.text) {
109
+ throw new Error('Gemini returned no text (possible safety filter block).');
110
+ }
111
+
112
+ this._trackTokens(response.usageMetadata);
113
+ return response.text;
114
+ }
115
+ }
@@ -0,0 +1,233 @@
1
+ /**
2
+ * MockLLMProvider — instant canned responses for E2E testing.
3
+ * Activated when AVC_LLM_MOCK=1 is set in the environment.
4
+ *
5
+ * Detects what kind of response to return by inspecting the prompt text.
6
+ */
7
+ export class MockLLMProvider {
8
+ constructor() {
9
+ this.providerName = 'mock';
10
+ this.model = 'mock-model';
11
+ this.tokenUsage = { inputTokens: 0, outputTokens: 0, totalCalls: 0 };
12
+ }
13
+
14
+ async validateApiKey() {
15
+ return { valid: true };
16
+ }
17
+
18
+ getTokenUsage() {
19
+ return {
20
+ inputTokens: this.tokenUsage.inputTokens,
21
+ outputTokens: this.tokenUsage.outputTokens,
22
+ totalTokens: this.tokenUsage.inputTokens + this.tokenUsage.outputTokens,
23
+ totalCalls: this.tokenUsage.totalCalls,
24
+ estimatedCost: 0,
25
+ provider: 'mock',
26
+ model: 'mock-model'
27
+ };
28
+ }
29
+
30
+ _track(prompt = '') {
31
+ this.tokenUsage.inputTokens += Math.ceil(prompt.length / 4);
32
+ this.tokenUsage.outputTokens += 50;
33
+ this.tokenUsage.totalCalls++;
34
+ }
35
+
36
+ /** generateJSON — detect call type from agent instructions (most reliable discriminator) */
37
+ async generateJSON(prompt, agentInstructions = null) {
38
+ this._track(prompt);
39
+
40
+ const p = (prompt || '').toLowerCase();
41
+ // Use agent instructions filename/content as the primary discriminator — it's
42
+ // more reliable than prompt text which can contain overlapping keywords.
43
+ const agent = (agentInstructions || '').toLowerCase();
44
+
45
+ // Validation calls (validator-documentation.md / validator-context.md)
46
+ // validator-documentation.md contains "validationStatus" and "overallScore" as output fields
47
+ if (agent.includes('validationstatus') || agent.includes('overallscore') ||
48
+ p.includes('validate the following')) {
49
+ return {
50
+ validationStatus: 'acceptable',
51
+ overallScore: 90,
52
+ issues: [],
53
+ contentIssues: [],
54
+ structuralIssues: [],
55
+ applicationFlowGaps: [],
56
+ strengths: ['Well-structured document (mock validation)'],
57
+ improvementPriorities: [],
58
+ readyForPublication: true,
59
+ readyForUse: true
60
+ };
61
+ }
62
+
63
+ // Database recommendation (database-recommender.md)
64
+ // database-recommender.md uniquely contains "hasDatabaseNeeds" as an output field
65
+ if (agent.includes('hasdatabaseneeds') || p.includes('determine if it needs a database')) {
66
+ return {
67
+ hasDatabaseNeeds: true,
68
+ comparison: {
69
+ sqlOption: {
70
+ database: 'PostgreSQL',
71
+ specificVersion: 'PostgreSQL 16',
72
+ bestFor: 'Relational data with ACID guarantees',
73
+ strengths: ['Strong consistency', 'Rich query language', 'Mature ecosystem'],
74
+ weaknesses: ['Schema migrations required'],
75
+ estimatedCosts: { monthly: '$0 (local Docker)' }
76
+ },
77
+ nosqlOption: {
78
+ database: 'MongoDB',
79
+ specificVersion: 'MongoDB 7',
80
+ bestFor: 'Flexible document storage',
81
+ strengths: ['Schema flexibility', 'Easy horizontal scaling'],
82
+ weaknesses: ['Eventual consistency by default'],
83
+ estimatedCosts: { monthly: '$0 (local Docker)' }
84
+ },
85
+ keyMetrics: {
86
+ estimatedReadWriteRatio: '70/30',
87
+ expectedThroughput: 'Low-medium (< 1000 req/s)',
88
+ dataComplexity: 'Medium — relational entities with joins'
89
+ }
90
+ },
91
+ recommendation: 'sql',
92
+ confidence: 85,
93
+ reasoning: 'Mock: task management apps benefit from relational integrity'
94
+ };
95
+ }
96
+
97
+ // Architecture recommendations (architecture-recommender.md)
98
+ // architecture-recommender.md uniquely contains "requiresCloudProvider" as an output field
99
+ if (agent.includes('requirescloudprovider') || p.includes('recommend 3-5') || p.includes('deployment architectures')) {
100
+ return {
101
+ architectures: [
102
+ {
103
+ name: 'Local Hybrid Stack',
104
+ description: 'Express.js/FastAPI backend on localhost with PostgreSQL in Docker',
105
+ requiresCloudProvider: false,
106
+ bestFor: 'Experienced developers who want fast debugging with database isolation',
107
+ migrationPath: {
108
+ targetCloud: 'AWS ECS / Azure Container Apps / GCP Cloud Run',
109
+ steps: [
110
+ 'Containerize backend with Docker',
111
+ 'Push images to ECR/ACR/GCR',
112
+ 'Deploy to container orchestration service'
113
+ ]
114
+ }
115
+ },
116
+ {
117
+ name: 'Full Docker Compose',
118
+ description: 'All services in Docker Compose — database, backend, and frontend',
119
+ requiresCloudProvider: false,
120
+ bestFor: 'Teams who want identical environments across all machines',
121
+ migrationPath: {
122
+ targetCloud: 'AWS ECS / GCP Cloud Run',
123
+ steps: ['Convert docker-compose.yml to ECS task definitions', 'Set up managed database']
124
+ }
125
+ }
126
+ ]
127
+ };
128
+ }
129
+
130
+ // Question prefilling (question-prefiller.md)
131
+ // question-prefiller.md uniquely contains "TARGET_USERS" as an output field
132
+ if (agent.includes('target_users') || p.includes('target_users')) {
133
+ return {
134
+ TARGET_USERS: 'Developers and project teams managing software development tasks',
135
+ DEPLOYMENT_TARGET: 'Local development environment using Docker Compose; ready to migrate to AWS ECS or Azure Container Apps for production',
136
+ TECHNICAL_CONSIDERATIONS: 'Node.js/Express.js or FastAPI backend, React 18 + Vite frontend, PostgreSQL 16 in Docker for local development with production migration path',
137
+ SECURITY_AND_COMPLIANCE_REQUIREMENTS: 'JWT authentication with refresh tokens, bcrypt password hashing, HTTPS in production, standard OWASP security practices'
138
+ };
139
+ }
140
+
141
+ // Context generation (project-context-generator.md)
142
+ // project-context-generator.md uniquely contains "contextMarkdown" as an output field
143
+ if (agent.includes('contextmarkdown') || agent.includes('context generator')) {
144
+ const mockContext = `# Project Context
145
+
146
+ **Mission:** Build a test task manager app
147
+ **Architecture:** Local Hybrid Stack
148
+ **Database:** PostgreSQL 16
149
+ **Tech Stack:** Node.js, Express.js, React 18, Vite
150
+ **Deployment:** Local Docker Compose → AWS ECS
151
+ `;
152
+ return {
153
+ contextMarkdown: mockContext,
154
+ tokenCount: Math.ceil(mockContext.length / 4),
155
+ withinBudget: true
156
+ };
157
+ }
158
+
159
+ // Generic fallback
160
+ return { result: 'Mock JSON response', success: true };
161
+ }
162
+
163
+ /** generate — return a mock sponsor-call document */
164
+ async generate(prompt, maxTokens = 256, systemInstructions = null) {
165
+ this._track(prompt);
166
+
167
+ const p = (prompt || '').toLowerCase();
168
+
169
+ // Document generation
170
+ if (p.includes('sponsor') || p.includes('project brief') || p.includes('enhance')) {
171
+ return `# Sponsor Call — Test Task Manager
172
+
173
+ ## Mission Statement
174
+ Build a test task manager app to help teams manage development tasks efficiently.
175
+
176
+ ## Initial Scope & Key Features
177
+ MVP with task creation and basic authentication.
178
+
179
+ ## Target Users
180
+ Developers and project teams managing software development tasks.
181
+
182
+ ## Deployment Target
183
+ Local development environment with Docker Compose. Ready to migrate to AWS ECS when needed.
184
+
185
+ ## Technical Considerations
186
+ Node.js/Express.js backend, React 18 + Vite frontend, PostgreSQL 16 in Docker.
187
+
188
+ ## Security & Compliance
189
+ JWT authentication with refresh tokens, bcrypt password hashing, HTTPS in production.
190
+
191
+ ## Architecture
192
+ Local Hybrid Stack: backend on localhost, database in Docker for isolation.
193
+
194
+ ---
195
+ *Generated by AVC mock provider for E2E testing*
196
+ `;
197
+ }
198
+
199
+ // Improvement pass (iterative validation improve step)
200
+ if (p.includes('improve') || p.includes('enhancement')) {
201
+ return `# Sponsor Call — Test Task Manager (Improved)
202
+
203
+ ## Mission Statement
204
+ Build a comprehensive test task manager app for development teams.
205
+
206
+ ## Initial Scope & Key Features
207
+ MVP with task creation, assignment, and basic JWT authentication.
208
+
209
+ ## Target Users
210
+ Software development teams and individual developers.
211
+
212
+ ## Deployment Target
213
+ Local development with Docker Compose, production on AWS ECS.
214
+
215
+ ## Technical Considerations
216
+ Express.js/Node.js backend, React 18 frontend, PostgreSQL 16 in Docker container.
217
+
218
+ ## Security & Compliance
219
+ JWT + bcrypt authentication, OWASP security practices.
220
+
221
+ ---
222
+ *Improved by AVC mock provider for E2E testing*
223
+ `;
224
+ }
225
+
226
+ return 'Mock text response from AVC E2E mock provider.';
227
+ }
228
+
229
+ /** generateText — alias for generate (used by migration guide generator) */
230
+ async generateText(prompt, agentInstructions = null) {
231
+ return this.generate(prompt, 4096, agentInstructions);
232
+ }
233
+ }