@agile-vibe-coding/avc 0.2.3 → 0.3.1

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 (261) hide show
  1. package/cli/agents/agent-selector.md +23 -0
  2. package/cli/agents/code-implementer.md +117 -0
  3. package/cli/agents/code-validator.md +80 -0
  4. package/cli/agents/context-reviewer-epic.md +101 -0
  5. package/cli/agents/context-reviewer-story.md +92 -0
  6. package/cli/agents/context-writer-epic.md +145 -0
  7. package/cli/agents/context-writer-story.md +111 -0
  8. package/cli/agents/doc-writer-epic.md +42 -0
  9. package/cli/agents/doc-writer-story.md +43 -0
  10. package/cli/agents/duplicate-detector.md +110 -0
  11. package/cli/agents/epic-story-decomposer.md +318 -39
  12. package/cli/agents/mission-scope-generator.md +68 -4
  13. package/cli/agents/mission-scope-validator.md +40 -6
  14. package/cli/agents/project-context-extractor.md +21 -6
  15. package/cli/agents/scaffolding-generator.md +99 -0
  16. package/cli/agents/seed-validator.md +71 -0
  17. package/cli/agents/story-scope-reviewer.md +147 -0
  18. package/cli/agents/story-splitter.md +83 -0
  19. package/cli/agents/validator-documentation.json +31 -0
  20. package/cli/agents/validator-documentation.md +3 -1
  21. package/cli/api-reference-tool.js +368 -0
  22. package/cli/checks/catalog.json +76 -0
  23. package/cli/checks/code/quality.json +26 -0
  24. package/cli/checks/code/testing.json +14 -0
  25. package/cli/checks/code/traceability.json +26 -0
  26. package/cli/checks/cross-refs/epic.json +171 -0
  27. package/cli/checks/cross-refs/story.json +149 -0
  28. package/cli/checks/epic/api.json +114 -0
  29. package/cli/checks/epic/backend.json +126 -0
  30. package/cli/checks/epic/cloud.json +126 -0
  31. package/cli/checks/epic/data.json +102 -0
  32. package/cli/checks/epic/database.json +114 -0
  33. package/cli/checks/epic/developer.json +182 -0
  34. package/cli/checks/epic/devops.json +174 -0
  35. package/cli/checks/epic/frontend.json +162 -0
  36. package/cli/checks/epic/mobile.json +102 -0
  37. package/cli/checks/epic/qa.json +90 -0
  38. package/cli/checks/epic/security.json +184 -0
  39. package/cli/checks/epic/solution-architect.json +192 -0
  40. package/cli/checks/epic/test-architect.json +90 -0
  41. package/cli/checks/epic/ui.json +102 -0
  42. package/cli/checks/epic/ux.json +90 -0
  43. package/cli/checks/fixes/epic-fix-template.md +10 -0
  44. package/cli/checks/fixes/story-fix-template.md +10 -0
  45. package/cli/checks/story/api.json +186 -0
  46. package/cli/checks/story/backend.json +102 -0
  47. package/cli/checks/story/cloud.json +102 -0
  48. package/cli/checks/story/data.json +210 -0
  49. package/cli/checks/story/database.json +102 -0
  50. package/cli/checks/story/developer.json +168 -0
  51. package/cli/checks/story/devops.json +102 -0
  52. package/cli/checks/story/frontend.json +174 -0
  53. package/cli/checks/story/mobile.json +102 -0
  54. package/cli/checks/story/qa.json +210 -0
  55. package/cli/checks/story/security.json +198 -0
  56. package/cli/checks/story/solution-architect.json +230 -0
  57. package/cli/checks/story/test-architect.json +210 -0
  58. package/cli/checks/story/ui.json +102 -0
  59. package/cli/checks/story/ux.json +102 -0
  60. package/cli/coding-order.js +401 -0
  61. package/cli/dependency-checker.js +72 -0
  62. package/cli/epic-story-validator.js +284 -799
  63. package/cli/index.js +0 -0
  64. package/cli/init-model-config.js +17 -10
  65. package/cli/init.js +514 -92
  66. package/cli/kanban-server-manager.js +1 -2
  67. package/cli/llm-claude.js +98 -31
  68. package/cli/llm-gemini.js +29 -5
  69. package/cli/llm-local.js +493 -0
  70. package/cli/llm-openai.js +262 -41
  71. package/cli/llm-provider.js +147 -8
  72. package/cli/llm-token-limits.js +113 -4
  73. package/cli/llm-verifier.js +209 -1
  74. package/cli/llm-xiaomi.js +143 -0
  75. package/cli/message-constants.js +3 -12
  76. package/cli/messaging-api.js +6 -12
  77. package/cli/micro-check-fixer.js +335 -0
  78. package/cli/micro-check-runner.js +449 -0
  79. package/cli/micro-check-scorer.js +148 -0
  80. package/cli/micro-check-validator.js +538 -0
  81. package/cli/model-pricing.js +23 -0
  82. package/cli/model-selector.js +3 -2
  83. package/cli/prompt-logger.js +57 -0
  84. package/cli/repl-ink.js +106 -346
  85. package/cli/repl-old.js +1 -2
  86. package/cli/seed-processor.js +194 -24
  87. package/cli/sprint-planning-processor.js +2638 -289
  88. package/cli/template-processor.js +50 -3
  89. package/cli/token-tracker.js +50 -23
  90. package/cli/tools/generate-story-validators.js +1 -1
  91. package/cli/validation-router.js +70 -8
  92. package/cli/worktree-runner.js +654 -0
  93. package/kanban/client/dist/assets/index-D_KC5EQT.css +1 -0
  94. package/kanban/client/dist/assets/index-DjY5zqW7.js +351 -0
  95. package/kanban/client/dist/index.html +2 -2
  96. package/kanban/client/src/App.jsx +43 -14
  97. package/kanban/client/src/components/ceremony/AskArchPopup.jsx +7 -3
  98. package/kanban/client/src/components/ceremony/AskModelPopup.jsx +23 -10
  99. package/kanban/client/src/components/ceremony/CeremonyWorkflowModal.jsx +320 -133
  100. package/kanban/client/src/components/ceremony/ProviderSwitcherButton.jsx +290 -0
  101. package/kanban/client/src/components/ceremony/SponsorCallModal.jsx +80 -13
  102. package/kanban/client/src/components/ceremony/SprintPlanningModal.jsx +156 -22
  103. package/kanban/client/src/components/ceremony/steps/ArchitectureStep.jsx +11 -11
  104. package/kanban/client/src/components/ceremony/steps/CompleteStep.jsx +3 -21
  105. package/kanban/client/src/components/ceremony/steps/ReviewAnswersStep.jsx +214 -10
  106. package/kanban/client/src/components/ceremony/steps/RunningStep.jsx +23 -2
  107. package/kanban/client/src/components/kanban/CardDetailModal.jsx +97 -10
  108. package/kanban/client/src/components/kanban/GroupingSelector.jsx +7 -1
  109. package/kanban/client/src/components/kanban/KanbanCard.jsx +23 -14
  110. package/kanban/client/src/components/kanban/RefineWorkItemPopup.jsx +9 -14
  111. package/kanban/client/src/components/kanban/RunButton.jsx +162 -0
  112. package/kanban/client/src/components/kanban/SeedButton.jsx +176 -0
  113. package/kanban/client/src/components/settings/AgentsTab.jsx +103 -75
  114. package/kanban/client/src/components/settings/ApiKeysTab.jsx +31 -2
  115. package/kanban/client/src/components/settings/CeremonyModelsTab.jsx +9 -2
  116. package/kanban/client/src/components/settings/CheckEditorPopup.jsx +507 -0
  117. package/kanban/client/src/components/settings/CostThresholdsTab.jsx +3 -2
  118. package/kanban/client/src/components/settings/ModelPricingTab.jsx +72 -7
  119. package/kanban/client/src/components/settings/OpenAIAuthSection.jsx +412 -0
  120. package/kanban/client/src/components/settings/SettingsModal.jsx +4 -4
  121. package/kanban/client/src/components/stats/CostModal.jsx +34 -3
  122. package/kanban/client/src/hooks/useGrouping.js +59 -0
  123. package/kanban/client/src/lib/api.js +118 -4
  124. package/kanban/client/src/lib/status-grouping.js +10 -0
  125. package/kanban/client/src/store/kanbanStore.js +8 -0
  126. package/kanban/server/index.js +23 -2
  127. package/kanban/server/routes/ceremony.js +153 -4
  128. package/kanban/server/routes/costs.js +9 -3
  129. package/kanban/server/routes/openai-oauth.js +366 -0
  130. package/kanban/server/routes/settings.js +447 -14
  131. package/kanban/server/routes/websocket.js +7 -2
  132. package/kanban/server/routes/work-items.js +141 -1
  133. package/kanban/server/services/CeremonyService.js +275 -24
  134. package/kanban/server/services/TaskRunnerService.js +261 -0
  135. package/kanban/server/workers/run-task-worker.js +121 -0
  136. package/kanban/server/workers/seed-worker.js +94 -0
  137. package/kanban/server/workers/sponsor-call-worker.js +14 -6
  138. package/kanban/server/workers/sprint-planning-worker.js +94 -12
  139. package/package.json +2 -3
  140. package/cli/agents/solver-epic-api.json +0 -15
  141. package/cli/agents/solver-epic-api.md +0 -39
  142. package/cli/agents/solver-epic-backend.json +0 -15
  143. package/cli/agents/solver-epic-backend.md +0 -39
  144. package/cli/agents/solver-epic-cloud.json +0 -15
  145. package/cli/agents/solver-epic-cloud.md +0 -39
  146. package/cli/agents/solver-epic-data.json +0 -15
  147. package/cli/agents/solver-epic-data.md +0 -39
  148. package/cli/agents/solver-epic-database.json +0 -15
  149. package/cli/agents/solver-epic-database.md +0 -39
  150. package/cli/agents/solver-epic-developer.json +0 -15
  151. package/cli/agents/solver-epic-developer.md +0 -39
  152. package/cli/agents/solver-epic-devops.json +0 -15
  153. package/cli/agents/solver-epic-devops.md +0 -39
  154. package/cli/agents/solver-epic-frontend.json +0 -15
  155. package/cli/agents/solver-epic-frontend.md +0 -39
  156. package/cli/agents/solver-epic-mobile.json +0 -15
  157. package/cli/agents/solver-epic-mobile.md +0 -39
  158. package/cli/agents/solver-epic-qa.json +0 -15
  159. package/cli/agents/solver-epic-qa.md +0 -39
  160. package/cli/agents/solver-epic-security.json +0 -15
  161. package/cli/agents/solver-epic-security.md +0 -39
  162. package/cli/agents/solver-epic-solution-architect.json +0 -15
  163. package/cli/agents/solver-epic-solution-architect.md +0 -39
  164. package/cli/agents/solver-epic-test-architect.json +0 -15
  165. package/cli/agents/solver-epic-test-architect.md +0 -39
  166. package/cli/agents/solver-epic-ui.json +0 -15
  167. package/cli/agents/solver-epic-ui.md +0 -39
  168. package/cli/agents/solver-epic-ux.json +0 -15
  169. package/cli/agents/solver-epic-ux.md +0 -39
  170. package/cli/agents/solver-story-api.json +0 -15
  171. package/cli/agents/solver-story-api.md +0 -39
  172. package/cli/agents/solver-story-backend.json +0 -15
  173. package/cli/agents/solver-story-backend.md +0 -39
  174. package/cli/agents/solver-story-cloud.json +0 -15
  175. package/cli/agents/solver-story-cloud.md +0 -39
  176. package/cli/agents/solver-story-data.json +0 -15
  177. package/cli/agents/solver-story-data.md +0 -39
  178. package/cli/agents/solver-story-database.json +0 -15
  179. package/cli/agents/solver-story-database.md +0 -39
  180. package/cli/agents/solver-story-developer.json +0 -15
  181. package/cli/agents/solver-story-developer.md +0 -39
  182. package/cli/agents/solver-story-devops.json +0 -15
  183. package/cli/agents/solver-story-devops.md +0 -39
  184. package/cli/agents/solver-story-frontend.json +0 -15
  185. package/cli/agents/solver-story-frontend.md +0 -39
  186. package/cli/agents/solver-story-mobile.json +0 -15
  187. package/cli/agents/solver-story-mobile.md +0 -39
  188. package/cli/agents/solver-story-qa.json +0 -15
  189. package/cli/agents/solver-story-qa.md +0 -39
  190. package/cli/agents/solver-story-security.json +0 -15
  191. package/cli/agents/solver-story-security.md +0 -39
  192. package/cli/agents/solver-story-solution-architect.json +0 -15
  193. package/cli/agents/solver-story-solution-architect.md +0 -39
  194. package/cli/agents/solver-story-test-architect.json +0 -15
  195. package/cli/agents/solver-story-test-architect.md +0 -39
  196. package/cli/agents/solver-story-ui.json +0 -15
  197. package/cli/agents/solver-story-ui.md +0 -39
  198. package/cli/agents/solver-story-ux.json +0 -15
  199. package/cli/agents/solver-story-ux.md +0 -39
  200. package/cli/agents/validator-epic-api.json +0 -93
  201. package/cli/agents/validator-epic-api.md +0 -137
  202. package/cli/agents/validator-epic-backend.json +0 -93
  203. package/cli/agents/validator-epic-backend.md +0 -130
  204. package/cli/agents/validator-epic-cloud.json +0 -93
  205. package/cli/agents/validator-epic-cloud.md +0 -137
  206. package/cli/agents/validator-epic-data.json +0 -93
  207. package/cli/agents/validator-epic-data.md +0 -130
  208. package/cli/agents/validator-epic-database.json +0 -93
  209. package/cli/agents/validator-epic-database.md +0 -137
  210. package/cli/agents/validator-epic-developer.json +0 -74
  211. package/cli/agents/validator-epic-developer.md +0 -153
  212. package/cli/agents/validator-epic-devops.json +0 -74
  213. package/cli/agents/validator-epic-devops.md +0 -153
  214. package/cli/agents/validator-epic-frontend.json +0 -74
  215. package/cli/agents/validator-epic-frontend.md +0 -153
  216. package/cli/agents/validator-epic-mobile.json +0 -93
  217. package/cli/agents/validator-epic-mobile.md +0 -130
  218. package/cli/agents/validator-epic-qa.json +0 -93
  219. package/cli/agents/validator-epic-qa.md +0 -130
  220. package/cli/agents/validator-epic-security.json +0 -74
  221. package/cli/agents/validator-epic-security.md +0 -154
  222. package/cli/agents/validator-epic-solution-architect.json +0 -74
  223. package/cli/agents/validator-epic-solution-architect.md +0 -156
  224. package/cli/agents/validator-epic-test-architect.json +0 -93
  225. package/cli/agents/validator-epic-test-architect.md +0 -130
  226. package/cli/agents/validator-epic-ui.json +0 -93
  227. package/cli/agents/validator-epic-ui.md +0 -130
  228. package/cli/agents/validator-epic-ux.json +0 -93
  229. package/cli/agents/validator-epic-ux.md +0 -130
  230. package/cli/agents/validator-story-api.json +0 -104
  231. package/cli/agents/validator-story-api.md +0 -152
  232. package/cli/agents/validator-story-backend.json +0 -104
  233. package/cli/agents/validator-story-backend.md +0 -152
  234. package/cli/agents/validator-story-cloud.json +0 -104
  235. package/cli/agents/validator-story-cloud.md +0 -152
  236. package/cli/agents/validator-story-data.json +0 -104
  237. package/cli/agents/validator-story-data.md +0 -152
  238. package/cli/agents/validator-story-database.json +0 -104
  239. package/cli/agents/validator-story-database.md +0 -152
  240. package/cli/agents/validator-story-developer.json +0 -104
  241. package/cli/agents/validator-story-developer.md +0 -152
  242. package/cli/agents/validator-story-devops.json +0 -104
  243. package/cli/agents/validator-story-devops.md +0 -152
  244. package/cli/agents/validator-story-frontend.json +0 -104
  245. package/cli/agents/validator-story-frontend.md +0 -152
  246. package/cli/agents/validator-story-mobile.json +0 -104
  247. package/cli/agents/validator-story-mobile.md +0 -152
  248. package/cli/agents/validator-story-qa.json +0 -104
  249. package/cli/agents/validator-story-qa.md +0 -152
  250. package/cli/agents/validator-story-security.json +0 -104
  251. package/cli/agents/validator-story-security.md +0 -152
  252. package/cli/agents/validator-story-solution-architect.json +0 -104
  253. package/cli/agents/validator-story-solution-architect.md +0 -152
  254. package/cli/agents/validator-story-test-architect.json +0 -104
  255. package/cli/agents/validator-story-test-architect.md +0 -152
  256. package/cli/agents/validator-story-ui.json +0 -104
  257. package/cli/agents/validator-story-ui.md +0 -152
  258. package/cli/agents/validator-story-ux.json +0 -104
  259. package/cli/agents/validator-story-ux.md +0 -152
  260. package/kanban/client/dist/assets/index-CiD8PS2e.js +0 -306
  261. package/kanban/client/dist/assets/index-nLh0m82Q.css +0 -1
@@ -0,0 +1,368 @@
1
+ /**
2
+ * api-reference-tool.js
3
+ *
4
+ * Provides an OpenAI-compatible tool definition and handler that fetches
5
+ * real API reference documentation from the internet. Designed to be used
6
+ * with local LLMs that support tool/function calling so that context writers
7
+ * can look up accurate payload formats, field names, and auth mechanisms
8
+ * instead of hallucinating them.
9
+ */
10
+
11
+ // ---------------------------------------------------------------------------
12
+ // Known API documentation sources
13
+ // ---------------------------------------------------------------------------
14
+
15
+ /**
16
+ * Maps service names to documentation URLs.
17
+ * Each entry can have:
18
+ * - `openapi` — OpenAPI/Swagger spec URL (JSON or YAML)
19
+ * - `docs` — Human-readable docs index URL
20
+ * - `topics` — Map of topic keywords → specific doc URLs
21
+ */
22
+ // No hardcoded URLs — all API references fetched dynamically via Context7.
23
+ // This avoids stale/broken URLs and ensures consistent, up-to-date documentation.
24
+ const SERVICE_REGISTRY = {};
25
+
26
+ // Aliases: normalize common service name variants
27
+ const SERVICE_ALIASES = {
28
+ // Twilio variants
29
+ 'twilio-whatsapp': 'twilio',
30
+ 'twilio-sms': 'twilio',
31
+ // Meta/WhatsApp variants (model uses many forms)
32
+ 'meta': 'whatsapp',
33
+ 'meta-cloud-api': 'whatsapp',
34
+ 'meta cloud api': 'whatsapp',
35
+ 'whatsapp-cloud': 'whatsapp',
36
+ 'whatsapp-business': 'whatsapp',
37
+ 'whatsapp cloud api': 'whatsapp',
38
+ 'whatsapp business api': 'whatsapp',
39
+ // Express variants
40
+ 'express.js': 'express',
41
+ 'expressjs': 'express',
42
+ // AWS variants
43
+ 's3': 'aws-s3',
44
+ 'amazon-s3': 'aws-s3',
45
+ // React ecosystem
46
+ 'react-query': 'tanstack-query',
47
+ 'tanstack query': 'tanstack-query',
48
+ '@tanstack/react-query': 'tanstack-query',
49
+ };
50
+
51
+ // ---------------------------------------------------------------------------
52
+ // Dynamic discovery via Context7 (Upstash)
53
+ // ---------------------------------------------------------------------------
54
+
55
+ const CONTEXT7_BASE = 'https://context7.com/api/v2';
56
+
57
+ /**
58
+ * Fetch topic-specific documentation from Context7.
59
+ * Two-step: resolve library ID → fetch docs.
60
+ * Works without API key; optional CONTEXT7_API_KEY env var for higher rate limits.
61
+ * @returns {{ libraryId: string, text: string } | null}
62
+ */
63
+ async function fetchFromContext7(serviceName, topic) {
64
+ const headers = {};
65
+ const apiKey = process.env.CONTEXT7_API_KEY;
66
+ if (apiKey) headers['Authorization'] = `Bearer ${apiKey}`;
67
+
68
+ // Step 1: Resolve library ID
69
+ const searchUrl = `${CONTEXT7_BASE}/libs/search?query=${encodeURIComponent(serviceName)}`;
70
+ const searchResult = await fetchWithLimit(searchUrl, 10_000, headers);
71
+ if (!searchResult.ok) return null;
72
+
73
+ let libraryId;
74
+ try {
75
+ const data = JSON.parse(searchResult.body);
76
+ const libs = data.libraries || data;
77
+ if (!Array.isArray(libs) || libs.length === 0) return null;
78
+ // Pick highest trust match — require trust >= 5 to avoid fuzzy noise
79
+ // (Context7 never returns empty results; garbage queries get fuzzy matches)
80
+ const best = libs.sort((a, b) => (b.trust || 0) - (a.trust || 0))[0];
81
+ if ((best.trust || 0) < 5) return null;
82
+ libraryId = best.id; // format: "owner/repo" e.g. "stripe/stripe-node"
83
+ } catch { return null; }
84
+
85
+ // Step 2: Fetch topic-specific documentation
86
+ const contextUrl = `${CONTEXT7_BASE}/context?libraryId=${encodeURIComponent(libraryId)}&query=${encodeURIComponent(topic)}&type=txt&tokenLimit=5000`;
87
+ const contextResult = await fetchWithLimit(contextUrl, 12_000, headers);
88
+ if (!contextResult.ok) return null;
89
+
90
+ const text = contextResult.body?.trim();
91
+ if (!text || text.length < 50) return null;
92
+
93
+ return { libraryId, text };
94
+ }
95
+
96
+ // ---------------------------------------------------------------------------
97
+ // Tool definition (OpenAI function-calling format)
98
+ // ---------------------------------------------------------------------------
99
+
100
+ export const API_REFERENCE_TOOL = {
101
+ type: 'function',
102
+ function: {
103
+ name: 'fetch_api_reference',
104
+ description:
105
+ 'Fetch API reference documentation for any external service or API. ' +
106
+ 'Supports thousands of libraries and APIs — documentation is discovered automatically. ' +
107
+ 'Use this when you need accurate payload formats, field names, authentication mechanisms, ' +
108
+ 'endpoint signatures, or webhook specifications.',
109
+ parameters: {
110
+ type: 'object',
111
+ properties: {
112
+ service: {
113
+ type: 'string',
114
+ description:
115
+ 'Service or API name (e.g. "twilio", "stripe", "prisma", "shopify", "express", "supabase")',
116
+ },
117
+ topic: {
118
+ type: 'string',
119
+ description:
120
+ 'Specific topic to look up (e.g. "webhook-payload", "authentication", "send-message", "signature-verification", "rate-limit")',
121
+ },
122
+ },
123
+ required: ['service', 'topic'],
124
+ },
125
+ },
126
+ };
127
+
128
+ // ---------------------------------------------------------------------------
129
+ // Fetch helper with timeout and size limit
130
+ // ---------------------------------------------------------------------------
131
+
132
+ const FETCH_TIMEOUT_MS = 15_000;
133
+ const MAX_BODY_BYTES = 512_000; // 500 KB — enough for most doc pages
134
+
135
+ async function fetchWithLimit(url, timeoutMs = FETCH_TIMEOUT_MS, extraHeaders = {}) {
136
+ const controller = new AbortController();
137
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
138
+ try {
139
+ const resp = await fetch(url, {
140
+ signal: controller.signal,
141
+ headers: { 'Accept': 'text/html, application/json, text/plain, */*', ...extraHeaders },
142
+ });
143
+ if (!resp.ok) {
144
+ return { ok: false, error: `HTTP ${resp.status} ${resp.statusText}` };
145
+ }
146
+ const contentType = resp.headers.get('content-type') || '';
147
+ const buffer = await resp.arrayBuffer();
148
+ const body = new TextDecoder().decode(buffer.slice(0, MAX_BODY_BYTES));
149
+ return { ok: true, body, contentType, truncated: buffer.byteLength > MAX_BODY_BYTES };
150
+ } catch (err) {
151
+ return { ok: false, error: err.name === 'AbortError' ? 'Request timed out' : err.message };
152
+ } finally {
153
+ clearTimeout(timer);
154
+ }
155
+ }
156
+
157
+ // ---------------------------------------------------------------------------
158
+ // Content extractors
159
+ // ---------------------------------------------------------------------------
160
+
161
+ /**
162
+ * Extract relevant text from an HTML page — strips tags, scripts, styles,
163
+ * and collapses whitespace. Returns a readable text summary.
164
+ */
165
+ function extractTextFromHTML(html, maxChars = 8000) {
166
+ let text = html;
167
+ // Remove script, style, nav, footer, header blocks
168
+ text = text.replace(/<(script|style|nav|footer|header|aside|svg)\b[^>]*>[\s\S]*?<\/\1>/gi, ' ');
169
+ // Remove HTML comments
170
+ text = text.replace(/<!--[\s\S]*?-->/g, ' ');
171
+ // Convert common block elements to newlines
172
+ text = text.replace(/<\/(p|div|h[1-6]|li|tr|br|hr)\s*>/gi, '\n');
173
+ text = text.replace(/<(br|hr)\s*\/?>/gi, '\n');
174
+ // Strip remaining tags
175
+ text = text.replace(/<[^>]+>/g, ' ');
176
+ // Decode basic HTML entities
177
+ text = text.replace(/&amp;/g, '&').replace(/&lt;/g, '<').replace(/&gt;/g, '>')
178
+ .replace(/&quot;/g, '"').replace(/&#39;/g, "'").replace(/&nbsp;/g, ' ');
179
+ // Collapse whitespace
180
+ text = text.replace(/[ \t]+/g, ' ').replace(/\n[ \t]+/g, '\n').replace(/\n{3,}/g, '\n\n');
181
+ return text.trim().slice(0, maxChars);
182
+ }
183
+
184
+ /**
185
+ * Extract a relevant section from an OpenAPI spec JSON for a given topic.
186
+ */
187
+ function extractFromOpenAPI(specJson, topic) {
188
+ const topicLower = topic.toLowerCase();
189
+ const lines = [];
190
+ const paths = specJson.paths || {};
191
+
192
+ // Find paths matching the topic keywords
193
+ const keywords = topicLower.split(/[-_\s]+/);
194
+ const matchingPaths = Object.entries(paths).filter(([pathStr]) => {
195
+ const pathLower = pathStr.toLowerCase();
196
+ return keywords.some(kw => kw.length >= 3 && pathLower.includes(kw));
197
+ });
198
+
199
+ // Limit to first 5 matching paths
200
+ for (const [pathStr, methods] of matchingPaths.slice(0, 5)) {
201
+ lines.push(`\n### ${pathStr}`);
202
+ for (const [method, spec] of Object.entries(methods)) {
203
+ if (typeof spec !== 'object' || !spec) continue;
204
+ lines.push(`**${method.toUpperCase()}** — ${spec.summary || spec.description || ''}`);
205
+ // Request body schema
206
+ const reqBody = spec.requestBody?.content;
207
+ if (reqBody) {
208
+ for (const [contentType, media] of Object.entries(reqBody)) {
209
+ lines.push(`- Content-Type: ${contentType}`);
210
+ if (media.schema?.properties) {
211
+ const props = Object.entries(media.schema.properties).slice(0, 15);
212
+ for (const [prop, propSpec] of props) {
213
+ const req = (media.schema.required || []).includes(prop) ? ' (required)' : '';
214
+ lines.push(` - ${prop}: ${propSpec.type || 'any'}${req} — ${propSpec.description || ''}`);
215
+ }
216
+ }
217
+ }
218
+ }
219
+ // Response schema summary
220
+ const responses = spec.responses || {};
221
+ const successResp = responses['200'] || responses['201'] || responses['204'];
222
+ if (successResp) {
223
+ lines.push(`- Success: ${successResp.description || 'OK'}`);
224
+ }
225
+ }
226
+ }
227
+
228
+ if (lines.length === 0) {
229
+ // Fallback: show info section
230
+ const info = specJson.info || {};
231
+ return `API: ${info.title || 'Unknown'} (v${info.version || '?'})\n` +
232
+ `${info.description || ''}\n\n` +
233
+ `No paths matching topic "${topic}" found. Available paths (first 20):\n` +
234
+ Object.keys(paths).slice(0, 20).map(p => `- ${p}`).join('\n');
235
+ }
236
+
237
+ const info = specJson.info || {};
238
+ return `API: ${info.title || 'Unknown'} (v${info.version || '?'})\n` +
239
+ `Topic: ${topic}\n` +
240
+ lines.join('\n');
241
+ }
242
+
243
+ // ---------------------------------------------------------------------------
244
+ // Tool handler
245
+ // ---------------------------------------------------------------------------
246
+
247
+ /**
248
+ * Handle a fetch_api_reference tool call.
249
+ * @param {{ service: string, topic: string }} args - Tool call arguments
250
+ * @returns {Promise<string>} The fetched API reference text
251
+ */
252
+ export async function handleFetchApiReference({ service, topic }) {
253
+ const serviceLower = (service || '').toLowerCase().trim();
254
+ const topicLower = (topic || '').toLowerCase().trim();
255
+
256
+ // Resolve aliases
257
+ const resolvedService = SERVICE_ALIASES[serviceLower] || serviceLower;
258
+ const registry = SERVICE_REGISTRY[resolvedService];
259
+
260
+ // Tier 0: Curated registry (fastest, best quality for known services)
261
+ if (registry) {
262
+ // 1. Try topic-specific URL first
263
+ const topicUrl = findTopicUrl(registry.topics, topicLower);
264
+ if (topicUrl) {
265
+ console.log(`[DEBUG] API reference tool: fetching ${resolvedService}/${topicLower} from ${topicUrl}`);
266
+ const result = await fetchWithLimit(topicUrl);
267
+ if (result.ok) {
268
+ const text = extractTextFromHTML(result.body);
269
+ if (text.length > 100) {
270
+ return `## ${resolvedService} — ${topic}\nSource: ${topicUrl}\n\n${text}`;
271
+ }
272
+ } else {
273
+ console.log(`[DEBUG] API reference fetch failed: ${result.error}`);
274
+ }
275
+ }
276
+
277
+ // 2. Try OpenAPI spec for structured data
278
+ if (registry.openapi) {
279
+ console.log(`[DEBUG] API reference tool: fetching OpenAPI spec for ${resolvedService}`);
280
+ const specResult = await fetchWithLimit(registry.openapi, 20_000);
281
+ if (specResult.ok) {
282
+ try {
283
+ const spec = JSON.parse(specResult.body);
284
+ const extracted = extractFromOpenAPI(spec, topicLower);
285
+ if (extracted) {
286
+ return `## ${resolvedService} — ${topic} (from OpenAPI spec)\n\n${extracted}`;
287
+ }
288
+ } catch {
289
+ // Not valid JSON or truncated — fall through
290
+ }
291
+ }
292
+ }
293
+
294
+ // 3. Fall back to general docs page
295
+ if (registry.docs) {
296
+ console.log(`[DEBUG] API reference tool: falling back to general docs for ${resolvedService}`);
297
+ const docsResult = await fetchWithLimit(registry.docs);
298
+ if (docsResult.ok) {
299
+ const text = extractTextFromHTML(docsResult.body, 4000);
300
+ return `## ${resolvedService} — general documentation\nSource: ${registry.docs}\n\n${text}\n\n` +
301
+ `Note: Could not find specific docs for topic "${topic}". Above is the general API docs page.`;
302
+ }
303
+ }
304
+ }
305
+
306
+ // Tier 1: Dynamic discovery via Context7
307
+ console.log(`[DEBUG] API reference: "${service}" not in registry, trying Context7`);
308
+ const ctx7 = await fetchFromContext7(serviceLower, topicLower);
309
+ if (ctx7) {
310
+ return `## ${service} — ${topic} (via Context7: ${ctx7.libraryId})\n\n${ctx7.text}`;
311
+ }
312
+
313
+ return `Could not find API documentation for "${service}/${topic}". ` +
314
+ `The service may not have indexed documentation available. ` +
315
+ `Use your training knowledge as a fallback.`;
316
+ }
317
+
318
+ /**
319
+ * Find the best matching topic URL from the topics map.
320
+ */
321
+ function findTopicUrl(topics, topicLower) {
322
+ if (!topics) return null;
323
+
324
+ // Exact match
325
+ if (topics[topicLower]) return topics[topicLower];
326
+
327
+ // Partial match — find topic key that shares keywords with the query
328
+ const queryWords = topicLower.split(/[-_\s]+/);
329
+ let bestMatch = null;
330
+ let bestOverlap = 0;
331
+
332
+ for (const [key, url] of Object.entries(topics)) {
333
+ const keyWords = key.split(/[-_\s]+/);
334
+ const overlap = queryWords.filter(w => keyWords.includes(w)).length;
335
+ if (overlap > bestOverlap) {
336
+ bestOverlap = overlap;
337
+ bestMatch = url;
338
+ }
339
+ }
340
+
341
+ return bestOverlap > 0 ? bestMatch : null;
342
+ }
343
+
344
+ // ---------------------------------------------------------------------------
345
+ // Exports for provider integration
346
+ // ---------------------------------------------------------------------------
347
+
348
+ /**
349
+ * All tools available for context generation.
350
+ * Providers can pass this array in the `tools` parameter of chat completions.
351
+ */
352
+ export const CONTEXT_GENERATION_TOOLS = [API_REFERENCE_TOOL];
353
+
354
+ /**
355
+ * Dispatch a tool call by name.
356
+ * @param {string} name - Tool function name
357
+ * @param {Object} args - Tool call arguments (parsed JSON)
358
+ * @returns {Promise<string>} Tool result text
359
+ */
360
+ export async function dispatchToolCall(name, args) {
361
+ if (name === 'fetch_api_reference') {
362
+ return handleFetchApiReference(args);
363
+ }
364
+ return `Unknown tool: ${name}`;
365
+ }
366
+
367
+ // Exported for unit testing
368
+ export { findTopicUrl, extractFromOpenAPI, extractTextFromHTML, fetchFromContext7 };
@@ -0,0 +1,76 @@
1
+ {
2
+ "version": "1.0.0",
3
+ "description": "Micro-check catalog for AVC validation system",
4
+ "tiers": {
5
+ "1": "Independent micro-checks — one YES/NO question per LLM call",
6
+ "2": "Cross-reference checks — validate consistency across perspectives",
7
+ "3": "Programmatic pattern detection — pure JS, no LLM"
8
+ },
9
+ "perspectives": [
10
+ "solution-architect",
11
+ "security",
12
+ "developer",
13
+ "devops",
14
+ "cloud",
15
+ "backend",
16
+ "database",
17
+ "api",
18
+ "frontend",
19
+ "ui",
20
+ "ux",
21
+ "mobile",
22
+ "data",
23
+ "qa",
24
+ "test-architect"
25
+ ],
26
+ "scopes": ["epic", "story"],
27
+ "checkCounts": {
28
+ "epic": {
29
+ "tier1": 157,
30
+ "tier2": 15,
31
+ "byPerspective": {
32
+ "solution-architect": 16,
33
+ "security": 15,
34
+ "developer": 16,
35
+ "devops": 14,
36
+ "cloud": 10,
37
+ "backend": 10,
38
+ "database": 9,
39
+ "api": 9,
40
+ "frontend": 13,
41
+ "ui": 8,
42
+ "ux": 7,
43
+ "mobile": 8,
44
+ "data": 8,
45
+ "qa": 7,
46
+ "test-architect": 7
47
+ }
48
+ },
49
+ "story": {
50
+ "tier1": 185,
51
+ "tier2": 13,
52
+ "byPerspective": {
53
+ "solution-architect": 19,
54
+ "security": 16,
55
+ "developer": 14,
56
+ "devops": 8,
57
+ "cloud": 8,
58
+ "backend": 8,
59
+ "database": 8,
60
+ "api": 15,
61
+ "frontend": 14,
62
+ "ui": 8,
63
+ "ux": 8,
64
+ "mobile": 8,
65
+ "data": 17,
66
+ "qa": 17,
67
+ "test-architect": 17
68
+ }
69
+ },
70
+ "total": {
71
+ "tier1": 342,
72
+ "tier2": 28,
73
+ "all": 370
74
+ }
75
+ }
76
+ }
@@ -0,0 +1,26 @@
1
+ [
2
+ {
3
+ "id": "qual-01",
4
+ "severity": "major",
5
+ "question": "Are ALL functions 25 lines or fewer (excluding JSDoc comments and blank lines)?",
6
+ "evidenceGuide": "Count executable lines per function body. List any function exceeding 25 lines with its actual line count. Orchestration methods up to 50 lines are acceptable if each line is a single function call."
7
+ },
8
+ {
9
+ "id": "qual-02",
10
+ "severity": "major",
11
+ "question": "Are business logic functions pure (no file I/O, no network calls, no database access, no console output)?",
12
+ "evidenceGuide": "Check non-boundary functions for side-effect calls: fs.*, fetch, database queries, console.*. Side effects must be isolated in clearly named boundary functions (e.g., readFromDatabase, writeToFile, sendApiRequest)."
13
+ },
14
+ {
15
+ "id": "qual-03",
16
+ "severity": "minor",
17
+ "question": "Do function names use domain vocabulary from the documentation chain rather than generic programming terms?",
18
+ "evidenceGuide": "Compare function names against domain nouns and verbs found in the task's context.md and doc.md. Flag generic names like processData, handleRequest, doWork, updateDB. Prefer domain terms like bookAppointment, validateSlotAvailability, sendReminderMessage."
19
+ },
20
+ {
21
+ "id": "qual-04",
22
+ "severity": "minor",
23
+ "question": "Is each source file named after its primary exported function using kebab-case with the hierarchy prefix?",
24
+ "evidenceGuide": "Compare file names to their primary export. Expected pattern: e0001-s0002-t0003-function-name.js for export e0001_s0002_t0003_functionName."
25
+ }
26
+ ]
@@ -0,0 +1,14 @@
1
+ [
2
+ {
3
+ "id": "test-01",
4
+ "severity": "critical",
5
+ "question": "Do all test describe blocks reference acceptance criterion IDs in the format taskId#ACn (e.g., context-0001-0002-0003#AC1)?",
6
+ "evidenceGuide": "Check every describe() string in test files for an AC ID reference. The format must include the full task ID and AC number. List any describe blocks without a valid reference."
7
+ },
8
+ {
9
+ "id": "test-02",
10
+ "severity": "major",
11
+ "question": "Is there no orphan code — does every function (exported or helper) have a @satisfies tag or belong to a module whose primary export has one?",
12
+ "evidenceGuide": "List any functions that cannot be traced to an acceptance criterion through either a direct @satisfies tag or membership in a file whose primary export has one."
13
+ }
14
+ ]
@@ -0,0 +1,26 @@
1
+ [
2
+ {
3
+ "id": "trace-01",
4
+ "severity": "critical",
5
+ "question": "Do ALL exported functions and classes have the correct hierarchy prefix e{X}_s{Y}_t{Z}_ matching the task ID?",
6
+ "evidenceGuide": "Check every export statement. The prefix must match the task's position in the hierarchy: e{epicNum}_s{storyNum}_t{taskNum}_. List any exports missing or using wrong prefix."
7
+ },
8
+ {
9
+ "id": "trace-02",
10
+ "severity": "critical",
11
+ "question": "Does every generated file have a provenance header with @file, @story, @task, @agent, and @generated JSDoc tags?",
12
+ "evidenceGuide": "Check the first JSDoc comment block at the top of each file for all five required tags. List any files missing tags."
13
+ },
14
+ {
15
+ "id": "trace-03",
16
+ "severity": "critical",
17
+ "question": "Does every exported function have a JSDoc comment with a @satisfies tag referencing a specific acceptance criterion (e.g., context-XXXX-XXXX-XXXX#AC1)?",
18
+ "evidenceGuide": "Check the JSDoc block above each exported function for a @satisfies tag with a valid AC reference. List any exports without it."
19
+ },
20
+ {
21
+ "id": "trace-04",
22
+ "severity": "major",
23
+ "question": "Is every acceptance criterion from the task's work.json covered by at least one exported function (@satisfies) AND at least one test (describe block)?",
24
+ "evidenceGuide": "Cross-reference the acceptance criteria array from work.json against @satisfies tags in source files and describe() strings in test files. List any uncovered ACs."
25
+ }
26
+ ]