@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,454 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import { fileURLToPath } from 'url';
4
+
5
+ const __filename = fileURLToPath(import.meta.url);
6
+ const __dirname = path.dirname(__filename);
7
+
8
+ /**
9
+ * LLM-based verification engine
10
+ *
11
+ * CONFIGURATION-DRIVEN VALIDATION:
12
+ * - All validation logic defined in JSON rule files
13
+ * - Fast-path optimizations configurable per rule (not hardcoded)
14
+ * - Hardcoded helpers exist (JSON parsing, regex) but triggered by JSON config
15
+ * - Each rule checks ONE thing and fixes ONE thing (atomic)
16
+ *
17
+ * Fast-Path Types Available:
18
+ * - 'json-parse': Validate JSON syntax programmatically
19
+ * - 'json-fields': Check required fields programmatically
20
+ * - 'none': Always use LLM (no fast-path)
21
+ *
22
+ * Usage:
23
+ * const verifier = new LLMVerifier(llmProvider, 'project-documentation-creator');
24
+ * const result = await verifier.verify(content, progressCallback);
25
+ */
26
+ export class LLMVerifier {
27
+ constructor(llmProvider, agentName, tracker = null) {
28
+ this.llmProvider = llmProvider;
29
+ this.agentName = agentName;
30
+ this.tracker = tracker; // Optional verification tracker
31
+ this.rules = this.loadRules();
32
+ }
33
+
34
+ /**
35
+ * Fast-path: Programmatically unwrap JSON from markdown code fence
36
+ * @param {string} content - Content that may be wrapped
37
+ * @returns {object} { isWrapped: boolean, unwrapped: string }
38
+ */
39
+ unwrapJsonCodeFence(content) {
40
+ const trimmed = content.trim();
41
+
42
+ // Pattern 1: ```json\n...\n```
43
+ const pattern1 = /^```json\s*\n([\s\S]*)\n```$/;
44
+ const match1 = trimmed.match(pattern1);
45
+ if (match1) {
46
+ return { isWrapped: true, unwrapped: match1[1].trim() };
47
+ }
48
+
49
+ // Pattern 2: ```\n...\n``` (generic code fence)
50
+ const pattern2 = /^```\s*\n([\s\S]*)\n```$/;
51
+ const match2 = trimmed.match(pattern2);
52
+ if (match2) {
53
+ // Check if content looks like JSON
54
+ const unwrapped = match2[1].trim();
55
+ if (unwrapped.startsWith('{') || unwrapped.startsWith('[')) {
56
+ return { isWrapped: true, unwrapped };
57
+ }
58
+ }
59
+
60
+ return { isWrapped: false, unwrapped: content };
61
+ }
62
+
63
+ /**
64
+ * Fast-path: Check if content is valid JSON
65
+ * @param {string} content - Content to check
66
+ * @returns {object} { canFastPath: boolean, violated: boolean, reason: string }
67
+ */
68
+ fastPathValidJson(content) {
69
+ // Check for markdown code fence
70
+ const { isWrapped, unwrapped } = this.unwrapJsonCodeFence(content);
71
+
72
+ if (isWrapped) {
73
+ return { canFastPath: true, violated: true, reason: 'markdown-fence' };
74
+ }
75
+
76
+ // Try parsing JSON
77
+ try {
78
+ JSON.parse(unwrapped);
79
+ return { canFastPath: true, violated: false };
80
+ } catch (e) {
81
+ // Parse error - might be fixable by LLM
82
+ return { canFastPath: false, violated: true, reason: e.message };
83
+ }
84
+ }
85
+
86
+ /**
87
+ * Fast-path: Check if required fields present
88
+ * @param {string} content - JSON content
89
+ * @param {array} requiredFields - Field names to check
90
+ * @returns {object} { canFastPath: boolean, violated: boolean, missingFields: array }
91
+ */
92
+ fastPathRequiredFields(content, requiredFields) {
93
+ try {
94
+ // First unwrap if needed
95
+ const { unwrapped } = this.unwrapJsonCodeFence(content);
96
+ const obj = JSON.parse(unwrapped);
97
+ const missing = requiredFields.filter(field => !(field in obj));
98
+
99
+ if (missing.length === 0) {
100
+ return { canFastPath: true, violated: false };
101
+ } else {
102
+ return { canFastPath: true, violated: true, missingFields: missing };
103
+ }
104
+ } catch (e) {
105
+ // Can't parse - let LLM handle
106
+ return { canFastPath: false };
107
+ }
108
+ }
109
+
110
+ /**
111
+ * Execute fast-path optimization if configured
112
+ * @param {string} content - Content to check
113
+ * @param {Object} rule - Verification rule with fastPath config
114
+ * @returns {Promise<Object>} { canFastPath: boolean, violated: boolean, reason: string }
115
+ */
116
+ async executeFastPath(content, rule) {
117
+ if (!rule.fastPath?.enabled) {
118
+ return { canFastPath: false };
119
+ }
120
+
121
+ const type = rule.fastPath.type;
122
+
123
+ switch (type) {
124
+ case 'json-parse':
125
+ // JSON parsing fast-path
126
+ return this.fastPathValidJson(content);
127
+
128
+ case 'json-fields':
129
+ // Required fields fast-path
130
+ const fields = rule.fastPath.requiredFields || [];
131
+ return this.fastPathRequiredFields(content, fields);
132
+
133
+ case 'none':
134
+ default:
135
+ // No fast-path, use LLM
136
+ return { canFastPath: false };
137
+ }
138
+ }
139
+
140
+ /**
141
+ * Load verification rules from JSON file
142
+ * @returns {Array} Enabled verification rules
143
+ */
144
+ loadRules() {
145
+ const rulesPath = path.join(__dirname, 'agents', `${this.agentName}.json`);
146
+
147
+ if (!fs.existsSync(rulesPath)) {
148
+ console.warn(`Warning: No verification rules found for agent: ${this.agentName}`);
149
+ return [];
150
+ }
151
+
152
+ try {
153
+ const data = JSON.parse(fs.readFileSync(rulesPath, 'utf8'));
154
+
155
+ // Filter to enabled rules only
156
+ const enabledRules = data.verifications.filter(r => r.enabled !== false);
157
+
158
+ return enabledRules;
159
+ } catch (error) {
160
+ console.error(`Error loading verification rules from ${rulesPath}:`, error.message);
161
+ return [];
162
+ }
163
+ }
164
+
165
+ /**
166
+ * Check if rule is violated
167
+ * @param {string} content - Content to check
168
+ * @param {Object} rule - Verification rule
169
+ * @returns {Promise<boolean>} True if rule is violated (needs fixing)
170
+ */
171
+ async checkRule(content, rule) {
172
+ try {
173
+ if (this.tracker) {
174
+ this.tracker.startRuleCheck(rule);
175
+ }
176
+
177
+ // Try fast-path if configured in rule
178
+ if (rule.fastPath?.enabled) {
179
+ const fastPathResult = await this.executeFastPath(content, rule);
180
+ if (fastPathResult.canFastPath) {
181
+ console.log(`[DEBUG] Fast-path used for ${rule.id}: ${fastPathResult.violated ? 'VIOLATED' : 'PASSED'}${fastPathResult.reason ? ` (${fastPathResult.reason})` : ''}${fastPathResult.missingFields ? ` (missing: ${fastPathResult.missingFields.join(', ')})` : ''}`);
182
+ if (this.tracker) {
183
+ this.tracker.endRuleCheck(fastPathResult.violated ? 'YES' : 'NO');
184
+ }
185
+ return fastPathResult.violated;
186
+ }
187
+ }
188
+
189
+ // Fallback to LLM check
190
+ console.log(`[DEBUG] Fast-path not available for ${rule.id}, using LLM`);
191
+ const prompt = rule.check.prompt.replace('{content}', content);
192
+ const maxTokens = rule.check.maxTokens || 10;
193
+
194
+ const response = await this.llmProvider.generate(prompt, maxTokens);
195
+ const answer = response.trim().toUpperCase();
196
+
197
+ // Check if response matches expected pattern (YES means violation found)
198
+ let result = false;
199
+ if (rule.check.expectedResponse === 'YES|NO') {
200
+ result = answer === 'YES';
201
+ }
202
+
203
+ if (this.tracker) {
204
+ this.tracker.endRuleCheck(answer);
205
+ }
206
+
207
+ console.log(`[DEBUG] checkRule - Rule: ${rule.id}, Result: ${answer}`);
208
+ return result;
209
+ } catch (error) {
210
+ console.error(`Error checking rule ${rule.id}:`, error.message);
211
+ if (this.tracker) {
212
+ this.tracker.endRuleCheck('ERROR');
213
+ this.tracker.completeRule();
214
+ }
215
+ return false; // Skip this rule on error
216
+ }
217
+ }
218
+
219
+ /**
220
+ * Fix content according to rule
221
+ * @param {string} content - Content to fix
222
+ * @param {Object} rule - Verification rule
223
+ * @returns {Promise<string>} Fixed content
224
+ */
225
+ async fixContent(content, rule) {
226
+ try {
227
+ if (this.tracker) {
228
+ this.tracker.startRuleFix(content.length);
229
+ }
230
+
231
+ // Fast-path fix if configured
232
+ if (rule.fastPath?.enabled && rule.fastPath.type === 'json-parse') {
233
+ const { isWrapped, unwrapped } = this.unwrapJsonCodeFence(content);
234
+ if (isWrapped) {
235
+ console.log('[DEBUG] Fast-path: Unwrapping JSON code fence (no LLM call)');
236
+ if (this.tracker) {
237
+ this.tracker.endRuleFix(unwrapped.length);
238
+ }
239
+ return unwrapped;
240
+ }
241
+ }
242
+
243
+ // Fallback to LLM fix
244
+ const prompt = rule.fix.prompt.replace('{content}', content);
245
+ const maxTokens = rule.fix.maxTokens || 4096;
246
+
247
+ console.log(`[DEBUG] fixContent - Rule: ${rule.id}, Fixing content (length: ${content.length})`);
248
+ const fixed = await this.llmProvider.generate(prompt, maxTokens);
249
+ console.log(`[DEBUG] fixContent - Rule: ${rule.id}, LLM returned ${fixed.length} chars`);
250
+ console.log(`[DEBUG] fixContent - Rule: ${rule.id}, Raw output preview:`, fixed.substring(0, 300));
251
+
252
+ const trimmed = fixed.trim();
253
+ console.log(`[DEBUG] fixContent - Rule: ${rule.id}, After trim: ${trimmed.length} chars`);
254
+
255
+ if (this.tracker) {
256
+ this.tracker.endRuleFix(trimmed.length);
257
+ }
258
+
259
+ return trimmed;
260
+ } catch (error) {
261
+ console.error(`Error fixing with rule ${rule.id}:`, error.message);
262
+ return content; // Return original content on error
263
+ }
264
+ }
265
+
266
+ /**
267
+ * Verify and fix content using all enabled rules
268
+ * @param {string} content - Content to verify
269
+ * @param {Function} progressCallback - Optional callback (mainMsg, substep)
270
+ * @returns {Promise<Object>} { content, rulesApplied }
271
+ */
272
+ async verify(content, progressCallback = null) {
273
+ // Check cache first
274
+ if (this.tracker && this.tracker.verificationCache) {
275
+ const contentHash = this.tracker.hashContent(content);
276
+ const cacheKey = `${this.agentName}-${contentHash}`;
277
+
278
+ if (this.tracker.verificationCache.has(cacheKey)) {
279
+ console.log(`[DEBUG] Cache HIT: Reusing verification for ${this.agentName} (hash: ${contentHash})`);
280
+ return this.tracker.verificationCache.get(cacheKey);
281
+ }
282
+
283
+ console.log(`[DEBUG] Cache MISS: Running verification for ${this.agentName} (hash: ${contentHash})`);
284
+ }
285
+
286
+ if (this.tracker) {
287
+ this.tracker.startSession(this.agentName, content);
288
+ }
289
+
290
+ console.log(`[DEBUG] verify - Starting verification with ${this.rules.length} rules`);
291
+ console.log(`[DEBUG] verify - Input content length: ${content.length}`);
292
+ console.log(`[DEBUG] verify - Input content preview:`, content.substring(0, 300));
293
+
294
+ let current = content;
295
+ const applied = [];
296
+
297
+ // If no rules loaded, return original content
298
+ if (this.rules.length === 0) {
299
+ return { content: current, rulesApplied: [] };
300
+ }
301
+
302
+ // PHASE 1: Check all rules in parallel
303
+ console.log(`[DEBUG] verify - Phase 1: Checking ${this.rules.length} rules in parallel`);
304
+ if (progressCallback) {
305
+ progressCallback(null, `Checking ${this.rules.length} rules...`);
306
+ await new Promise(resolve => setTimeout(resolve, 20));
307
+ }
308
+
309
+ const checkPromises = this.rules.map(async (rule) => {
310
+ // Check if rule should be skipped based on profiling
311
+ if (this.tracker && this.tracker.shouldSkipRule(this.agentName, rule.id)) {
312
+ return { rule, violated: false, error: null, skipped: true };
313
+ }
314
+
315
+ try {
316
+ const violated = await this.checkRule(current, rule);
317
+
318
+ // Update rule profile
319
+ if (this.tracker) {
320
+ this.tracker.updateRuleProfile(this.agentName, rule.id, violated);
321
+ }
322
+
323
+ return { rule, violated, error: null, skipped: false };
324
+ } catch (error) {
325
+ console.error(`Error checking rule ${rule.id}:`, error.message);
326
+ return { rule, violated: false, error: error.message, skipped: false };
327
+ }
328
+ });
329
+
330
+ const checkResults = await Promise.all(checkPromises);
331
+
332
+ // PHASE 2: Fix violations sequentially
333
+ console.log(`[DEBUG] verify - Phase 2: Fixing violations sequentially`);
334
+ const violatedRules = checkResults.filter(r => r.violated && !r.error);
335
+ console.log(`[DEBUG] verify - Found ${violatedRules.length} violations:`, violatedRules.map(r => r.rule.id));
336
+
337
+ for (const { rule, violated } of violatedRules) {
338
+ // SAFEGUARD: Double-check that rule was actually violated
339
+ if (!violated) {
340
+ console.warn(`[WARN] verify - Skipping fix for ${rule.id} - violated flag is false (defensive check)`);
341
+ if (this.tracker) {
342
+ this.tracker.completeRule();
343
+ }
344
+ continue;
345
+ }
346
+
347
+ // Report progress: fixing
348
+ if (progressCallback) {
349
+ progressCallback(null, `Fixing: ${rule.name}...`);
350
+ await new Promise(resolve => setTimeout(resolve, 20));
351
+ }
352
+
353
+ try {
354
+ const beforeLength = current.length;
355
+
356
+ // Apply fix
357
+ const fixed = await this.fixContent(current, rule);
358
+
359
+ // Only update if fix actually changed content
360
+ if (fixed !== current) {
361
+ const afterLength = fixed.length;
362
+ const changePercent = Math.abs((afterLength - beforeLength) / beforeLength * 100);
363
+ const changeChars = afterLength - beforeLength;
364
+
365
+ // SAFEGUARD: Warn on aggressive content changes
366
+ if (changePercent > 30) {
367
+ console.warn(`[WARN] verify - Rule ${rule.id} caused ${changePercent.toFixed(1)}% content change (${changeChars > 0 ? '+' : ''}${changeChars} chars)`);
368
+ console.warn(`[WARN] verify - Before: ${beforeLength} chars, After: ${afterLength} chars`);
369
+ console.warn(`[WARN] verify - This may indicate an overly aggressive fix. Review rule prompt.`);
370
+ } else {
371
+ console.log(`[DEBUG] verify - Rule ${rule.id} changed content by ${changePercent.toFixed(1)}% (${changeChars > 0 ? '+' : ''}${changeChars} chars)`);
372
+ }
373
+
374
+ current = fixed;
375
+ applied.push({
376
+ id: rule.id,
377
+ name: rule.name,
378
+ severity: rule.severity,
379
+ description: rule.description
380
+ });
381
+ } else {
382
+ console.log(`[DEBUG] verify - Rule ${rule.id} fix did not change content (no-op fix)`);
383
+ }
384
+ } catch (error) {
385
+ console.error(`Error fixing rule ${rule.id}:`, error.message);
386
+ }
387
+
388
+ if (this.tracker) {
389
+ this.tracker.completeRule();
390
+ }
391
+ }
392
+
393
+ // Complete tracking for rules that didn't violate
394
+ const passedRules = checkResults.filter(r => !r.violated || r.error);
395
+ for (const { rule } of passedRules) {
396
+ if (this.tracker) {
397
+ this.tracker.completeRule();
398
+ }
399
+ }
400
+
401
+ console.log(`[DEBUG] verify - Completed with ${applied.length} rules applied:`, applied.map(r => r.id));
402
+ console.log(`[DEBUG] verify - Final content length: ${current.length}`);
403
+ console.log(`[DEBUG] verify - Final content preview:`, current.substring(0, 300));
404
+
405
+ if (this.tracker) {
406
+ this.tracker.endSession(current, applied);
407
+ this.tracker.logSessionSummary();
408
+ }
409
+
410
+ const result = {
411
+ content: current,
412
+ rulesApplied: applied,
413
+ noViolations: applied.length === 0, // Track if this was a perfect verification
414
+ timestamp: Date.now()
415
+ };
416
+
417
+ // Store in cache
418
+ if (this.tracker && this.tracker.verificationCache) {
419
+ const contentHash = this.tracker.hashContent(content);
420
+ const cacheKey = `${this.agentName}-${contentHash}`;
421
+ this.tracker.verificationCache.set(cacheKey, result);
422
+
423
+ if (applied.length === 0) {
424
+ console.log(`[DEBUG] Cached PERFECT verification result for ${this.agentName} (hash: ${contentHash}) - no violations found`);
425
+ } else {
426
+ console.log(`[DEBUG] Cached verification result for ${this.agentName} (hash: ${contentHash}) - ${applied.length} fixes applied`);
427
+ }
428
+ }
429
+
430
+ return result;
431
+ }
432
+
433
+ /**
434
+ * Get list of all rules for this agent
435
+ * @returns {Array} Rule metadata (id, name, severity, description)
436
+ */
437
+ getRules() {
438
+ return this.rules.map(r => ({
439
+ id: r.id,
440
+ name: r.name,
441
+ severity: r.severity,
442
+ description: r.description,
443
+ enabled: r.enabled !== false
444
+ }));
445
+ }
446
+
447
+ /**
448
+ * Get count of enabled rules
449
+ * @returns {number} Number of enabled rules
450
+ */
451
+ getRuleCount() {
452
+ return this.rules.length;
453
+ }
454
+ }
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Message Constants - Reusable message definitions
3
+ *
4
+ * Centralized message strings to prevent duplication and ensure consistency.
5
+ * Use these constants instead of hardcoded strings throughout the codebase.
6
+ */
7
+
8
+ /**
9
+ * Common error messages
10
+ */
11
+ export const MESSAGES = {
12
+ /**
13
+ * Project not initialized error
14
+ */
15
+ PROJECT_NOT_INITIALIZED: {
16
+ error: 'Project not initialized',
17
+ help: 'Please run /init first to create the project structure.'
18
+ },
19
+
20
+ /**
21
+ * Ceremony headers with titles and documentation URLs
22
+ */
23
+ CEREMONY_HEADERS: {
24
+ 'sponsor-call': {
25
+ title: 'Sponsor Call Ceremony',
26
+ url: 'https://agilevibecoding.org/ceremonies/sponsor-call'
27
+ },
28
+ 'sprint-planning': {
29
+ title: 'Sprint Planning Ceremony',
30
+ url: 'https://agilevibecoding.org/ceremonies/sprint-planning'
31
+ },
32
+ 'seed': {
33
+ title: 'Seed Ceremony',
34
+ url: 'https://agilevibecoding.org/ceremonies/seed'
35
+ }
36
+ }
37
+ };
38
+
39
+ /**
40
+ * Helper function to get full "project not initialized" error message
41
+ * @returns {string} Complete error message with help text
42
+ */
43
+ export function getProjectNotInitializedMessage() {
44
+ return `${MESSAGES.PROJECT_NOT_INITIALIZED.error}\n\n${MESSAGES.PROJECT_NOT_INITIALIZED.help}`;
45
+ }
46
+
47
+ /**
48
+ * Helper function to get ceremony header
49
+ * @param {string} ceremonyName - Name of ceremony ('sponsor-call', 'sprint-planning', 'seed')
50
+ * @returns {object} Object with title and url properties
51
+ */
52
+ export function getCeremonyHeader(ceremonyName) {
53
+ const header = MESSAGES.CEREMONY_HEADERS[ceremonyName];
54
+ if (!header) {
55
+ throw new Error(`Unknown ceremony: ${ceremonyName}`);
56
+ }
57
+ return header;
58
+ }