popeye-cli 2.1.0 → 2.7.0

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 (356) hide show
  1. package/dist/adapters/gemini.d.ts +14 -0
  2. package/dist/adapters/gemini.d.ts.map +1 -1
  3. package/dist/adapters/gemini.js +41 -6
  4. package/dist/adapters/gemini.js.map +1 -1
  5. package/dist/adapters/grok.d.ts +14 -0
  6. package/dist/adapters/grok.d.ts.map +1 -1
  7. package/dist/adapters/grok.js +42 -6
  8. package/dist/adapters/grok.js.map +1 -1
  9. package/dist/adapters/openai.d.ts +10 -0
  10. package/dist/adapters/openai.d.ts.map +1 -1
  11. package/dist/adapters/openai.js +44 -5
  12. package/dist/adapters/openai.js.map +1 -1
  13. package/dist/cli/commands/create.js +1 -1
  14. package/dist/cli/commands/create.js.map +1 -1
  15. package/dist/cli/interactive.d.ts.map +1 -1
  16. package/dist/cli/interactive.js +328 -21
  17. package/dist/cli/interactive.js.map +1 -1
  18. package/dist/generators/all.d.ts.map +1 -1
  19. package/dist/generators/all.js +25 -2
  20. package/dist/generators/all.js.map +1 -1
  21. package/dist/generators/doc-parser.d.ts +21 -6
  22. package/dist/generators/doc-parser.d.ts.map +1 -1
  23. package/dist/generators/doc-parser.js +55 -4
  24. package/dist/generators/doc-parser.js.map +1 -1
  25. package/dist/generators/templates/fullstack.js +1 -1
  26. package/dist/generators/templates/website-components.js +1 -1
  27. package/dist/generators/templates/website-components.js.map +1 -1
  28. package/dist/generators/templates/website-config.d.ts +4 -1
  29. package/dist/generators/templates/website-config.d.ts.map +1 -1
  30. package/dist/generators/templates/website-config.js +17 -11
  31. package/dist/generators/templates/website-config.js.map +1 -1
  32. package/dist/generators/templates/website-conversion.js +1 -1
  33. package/dist/generators/templates/website-conversion.js.map +1 -1
  34. package/dist/generators/templates/website-landing.js +1 -1
  35. package/dist/generators/templates/website-landing.js.map +1 -1
  36. package/dist/generators/templates/website-layout.d.ts +36 -4
  37. package/dist/generators/templates/website-layout.d.ts.map +1 -1
  38. package/dist/generators/templates/website-layout.js +466 -23
  39. package/dist/generators/templates/website-layout.js.map +1 -1
  40. package/dist/generators/templates/website-pricing.js +1 -1
  41. package/dist/generators/templates/website-pricing.js.map +1 -1
  42. package/dist/generators/templates/website-sections.js +1 -1
  43. package/dist/generators/templates/website-sections.js.map +1 -1
  44. package/dist/generators/templates/website-seo.d.ts.map +1 -1
  45. package/dist/generators/templates/website-seo.js +4 -1
  46. package/dist/generators/templates/website-seo.js.map +1 -1
  47. package/dist/generators/templates/website.d.ts +1 -1
  48. package/dist/generators/templates/website.d.ts.map +1 -1
  49. package/dist/generators/templates/website.js +1 -1
  50. package/dist/generators/templates/website.js.map +1 -1
  51. package/dist/generators/website-content-ai.d.ts +52 -0
  52. package/dist/generators/website-content-ai.d.ts.map +1 -0
  53. package/dist/generators/website-content-ai.js +141 -0
  54. package/dist/generators/website-content-ai.js.map +1 -0
  55. package/dist/generators/website-content-scanner.d.ts +1 -1
  56. package/dist/generators/website-content-scanner.d.ts.map +1 -1
  57. package/dist/generators/website-content-scanner.js +98 -1
  58. package/dist/generators/website-content-scanner.js.map +1 -1
  59. package/dist/generators/website-context.d.ts +34 -1
  60. package/dist/generators/website-context.d.ts.map +1 -1
  61. package/dist/generators/website-context.js +131 -9
  62. package/dist/generators/website-context.js.map +1 -1
  63. package/dist/generators/website-debug.d.ts +12 -0
  64. package/dist/generators/website-debug.d.ts.map +1 -1
  65. package/dist/generators/website-debug.js +16 -0
  66. package/dist/generators/website-debug.js.map +1 -1
  67. package/dist/generators/website.d.ts.map +1 -1
  68. package/dist/generators/website.js +26 -4
  69. package/dist/generators/website.js.map +1 -1
  70. package/dist/pipeline/artifact-manager.d.ts.map +1 -1
  71. package/dist/pipeline/artifact-manager.js +3 -0
  72. package/dist/pipeline/artifact-manager.js.map +1 -1
  73. package/dist/pipeline/auto-recovery.d.ts +56 -0
  74. package/dist/pipeline/auto-recovery.d.ts.map +1 -0
  75. package/dist/pipeline/auto-recovery.js +185 -0
  76. package/dist/pipeline/auto-recovery.js.map +1 -0
  77. package/dist/pipeline/change-request.d.ts +39 -0
  78. package/dist/pipeline/change-request.d.ts.map +1 -1
  79. package/dist/pipeline/change-request.js +40 -1
  80. package/dist/pipeline/change-request.js.map +1 -1
  81. package/dist/pipeline/check-runner.d.ts +30 -1
  82. package/dist/pipeline/check-runner.d.ts.map +1 -1
  83. package/dist/pipeline/check-runner.js +122 -1
  84. package/dist/pipeline/check-runner.js.map +1 -1
  85. package/dist/pipeline/command-resolver.d.ts.map +1 -1
  86. package/dist/pipeline/command-resolver.js +33 -2
  87. package/dist/pipeline/command-resolver.js.map +1 -1
  88. package/dist/pipeline/consensus/arbitrator-query.d.ts +22 -0
  89. package/dist/pipeline/consensus/arbitrator-query.d.ts.map +1 -0
  90. package/dist/pipeline/consensus/arbitrator-query.js +70 -0
  91. package/dist/pipeline/consensus/arbitrator-query.js.map +1 -0
  92. package/dist/pipeline/consensus/consensus-runner.d.ts +131 -7
  93. package/dist/pipeline/consensus/consensus-runner.d.ts.map +1 -1
  94. package/dist/pipeline/consensus/consensus-runner.js +809 -35
  95. package/dist/pipeline/consensus/consensus-runner.js.map +1 -1
  96. package/dist/pipeline/cr-lifecycle.d.ts +42 -0
  97. package/dist/pipeline/cr-lifecycle.d.ts.map +1 -0
  98. package/dist/pipeline/cr-lifecycle.js +89 -0
  99. package/dist/pipeline/cr-lifecycle.js.map +1 -0
  100. package/dist/pipeline/gate-engine.d.ts +1 -0
  101. package/dist/pipeline/gate-engine.d.ts.map +1 -1
  102. package/dist/pipeline/gate-engine.js +27 -8
  103. package/dist/pipeline/gate-engine.js.map +1 -1
  104. package/dist/pipeline/migration.d.ts.map +1 -1
  105. package/dist/pipeline/migration.js +3 -26
  106. package/dist/pipeline/migration.js.map +1 -1
  107. package/dist/pipeline/orchestrator.d.ts +1 -1
  108. package/dist/pipeline/orchestrator.d.ts.map +1 -1
  109. package/dist/pipeline/orchestrator.js +311 -16
  110. package/dist/pipeline/orchestrator.js.map +1 -1
  111. package/dist/pipeline/packets/consensus-packet-builder.d.ts +15 -4
  112. package/dist/pipeline/packets/consensus-packet-builder.d.ts.map +1 -1
  113. package/dist/pipeline/packets/consensus-packet-builder.js +29 -17
  114. package/dist/pipeline/packets/consensus-packet-builder.js.map +1 -1
  115. package/dist/pipeline/phases/architecture.d.ts.map +1 -1
  116. package/dist/pipeline/phases/architecture.js +5 -3
  117. package/dist/pipeline/phases/architecture.js.map +1 -1
  118. package/dist/pipeline/phases/audit.d.ts.map +1 -1
  119. package/dist/pipeline/phases/audit.js +5 -3
  120. package/dist/pipeline/phases/audit.js.map +1 -1
  121. package/dist/pipeline/phases/consensus-architecture.d.ts.map +1 -1
  122. package/dist/pipeline/phases/consensus-architecture.js +10 -1
  123. package/dist/pipeline/phases/consensus-architecture.js.map +1 -1
  124. package/dist/pipeline/phases/consensus-master-plan.d.ts.map +1 -1
  125. package/dist/pipeline/phases/consensus-master-plan.js +10 -3
  126. package/dist/pipeline/phases/consensus-master-plan.js.map +1 -1
  127. package/dist/pipeline/phases/consensus-role-plans.d.ts.map +1 -1
  128. package/dist/pipeline/phases/consensus-role-plans.js +10 -1
  129. package/dist/pipeline/phases/consensus-role-plans.js.map +1 -1
  130. package/dist/pipeline/phases/done.d.ts.map +1 -1
  131. package/dist/pipeline/phases/done.js +9 -4
  132. package/dist/pipeline/phases/done.js.map +1 -1
  133. package/dist/pipeline/phases/intake.d.ts +1 -0
  134. package/dist/pipeline/phases/intake.d.ts.map +1 -1
  135. package/dist/pipeline/phases/intake.js +56 -13
  136. package/dist/pipeline/phases/intake.js.map +1 -1
  137. package/dist/pipeline/phases/phase-context.d.ts +2 -0
  138. package/dist/pipeline/phases/phase-context.d.ts.map +1 -1
  139. package/dist/pipeline/phases/phase-context.js +3 -1
  140. package/dist/pipeline/phases/phase-context.js.map +1 -1
  141. package/dist/pipeline/phases/production-gate.d.ts.map +1 -1
  142. package/dist/pipeline/phases/production-gate.js +28 -3
  143. package/dist/pipeline/phases/production-gate.js.map +1 -1
  144. package/dist/pipeline/phases/qa-validation.d.ts.map +1 -1
  145. package/dist/pipeline/phases/qa-validation.js +38 -5
  146. package/dist/pipeline/phases/qa-validation.js.map +1 -1
  147. package/dist/pipeline/phases/recovery-loop.d.ts +2 -0
  148. package/dist/pipeline/phases/recovery-loop.d.ts.map +1 -1
  149. package/dist/pipeline/phases/recovery-loop.js +200 -6
  150. package/dist/pipeline/phases/recovery-loop.js.map +1 -1
  151. package/dist/pipeline/phases/review.d.ts.map +1 -1
  152. package/dist/pipeline/phases/review.js +58 -28
  153. package/dist/pipeline/phases/review.js.map +1 -1
  154. package/dist/pipeline/phases/role-planning.d.ts.map +1 -1
  155. package/dist/pipeline/phases/role-planning.js +20 -5
  156. package/dist/pipeline/phases/role-planning.js.map +1 -1
  157. package/dist/pipeline/phases/stuck.d.ts.map +1 -1
  158. package/dist/pipeline/phases/stuck.js +10 -0
  159. package/dist/pipeline/phases/stuck.js.map +1 -1
  160. package/dist/pipeline/repo-snapshot.d.ts.map +1 -1
  161. package/dist/pipeline/repo-snapshot.js +3 -0
  162. package/dist/pipeline/repo-snapshot.js.map +1 -1
  163. package/dist/pipeline/role-execution-adapter.d.ts +2 -1
  164. package/dist/pipeline/role-execution-adapter.d.ts.map +1 -1
  165. package/dist/pipeline/role-execution-adapter.js +22 -7
  166. package/dist/pipeline/role-execution-adapter.js.map +1 -1
  167. package/dist/pipeline/skill-loader.d.ts +19 -0
  168. package/dist/pipeline/skill-loader.d.ts.map +1 -1
  169. package/dist/pipeline/skill-loader.js +22 -0
  170. package/dist/pipeline/skill-loader.js.map +1 -1
  171. package/dist/pipeline/skills/constitution-generator.d.ts +51 -0
  172. package/dist/pipeline/skills/constitution-generator.d.ts.map +1 -0
  173. package/dist/pipeline/skills/constitution-generator.js +210 -0
  174. package/dist/pipeline/skills/constitution-generator.js.map +1 -0
  175. package/dist/pipeline/skills/coverage-gate.d.ts +44 -0
  176. package/dist/pipeline/skills/coverage-gate.d.ts.map +1 -0
  177. package/dist/pipeline/skills/coverage-gate.js +143 -0
  178. package/dist/pipeline/skills/coverage-gate.js.map +1 -0
  179. package/dist/pipeline/skills/generator.d.ts +65 -0
  180. package/dist/pipeline/skills/generator.d.ts.map +1 -0
  181. package/dist/pipeline/skills/generator.js +221 -0
  182. package/dist/pipeline/skills/generator.js.map +1 -0
  183. package/dist/pipeline/skills/role-map.d.ts +38 -0
  184. package/dist/pipeline/skills/role-map.d.ts.map +1 -0
  185. package/dist/pipeline/skills/role-map.js +234 -0
  186. package/dist/pipeline/skills/role-map.js.map +1 -0
  187. package/dist/pipeline/skills/types.d.ts +47 -0
  188. package/dist/pipeline/skills/types.d.ts.map +1 -0
  189. package/dist/pipeline/skills/types.js +5 -0
  190. package/dist/pipeline/skills/types.js.map +1 -0
  191. package/dist/pipeline/skills/usage-registry.d.ts +48 -0
  192. package/dist/pipeline/skills/usage-registry.d.ts.map +1 -0
  193. package/dist/pipeline/skills/usage-registry.js +55 -0
  194. package/dist/pipeline/skills/usage-registry.js.map +1 -0
  195. package/dist/pipeline/strategy-context.d.ts +20 -0
  196. package/dist/pipeline/strategy-context.d.ts.map +1 -0
  197. package/dist/pipeline/strategy-context.js +55 -0
  198. package/dist/pipeline/strategy-context.js.map +1 -0
  199. package/dist/pipeline/type-defs/artifacts.d.ts +30 -5
  200. package/dist/pipeline/type-defs/artifacts.d.ts.map +1 -1
  201. package/dist/pipeline/type-defs/artifacts.js +5 -0
  202. package/dist/pipeline/type-defs/artifacts.js.map +1 -1
  203. package/dist/pipeline/type-defs/audit.d.ts +28 -13
  204. package/dist/pipeline/type-defs/audit.d.ts.map +1 -1
  205. package/dist/pipeline/type-defs/checks.d.ts +19 -8
  206. package/dist/pipeline/type-defs/checks.d.ts.map +1 -1
  207. package/dist/pipeline/type-defs/checks.js +4 -0
  208. package/dist/pipeline/type-defs/checks.js.map +1 -1
  209. package/dist/pipeline/type-defs/packets.d.ts +119 -18
  210. package/dist/pipeline/type-defs/packets.d.ts.map +1 -1
  211. package/dist/pipeline/type-defs/packets.js +17 -1
  212. package/dist/pipeline/type-defs/packets.js.map +1 -1
  213. package/dist/pipeline/type-defs/state.d.ts +165 -16
  214. package/dist/pipeline/type-defs/state.d.ts.map +1 -1
  215. package/dist/pipeline/type-defs/state.js +26 -1
  216. package/dist/pipeline/type-defs/state.js.map +1 -1
  217. package/dist/shared/text-utils.d.ts +23 -0
  218. package/dist/shared/text-utils.d.ts.map +1 -0
  219. package/dist/shared/text-utils.js +66 -0
  220. package/dist/shared/text-utils.js.map +1 -0
  221. package/dist/shared/website-strategy-format.d.ts +18 -0
  222. package/dist/shared/website-strategy-format.d.ts.map +1 -0
  223. package/dist/shared/website-strategy-format.js +47 -0
  224. package/dist/shared/website-strategy-format.js.map +1 -0
  225. package/dist/state/index.d.ts +2 -0
  226. package/dist/state/index.d.ts.map +1 -1
  227. package/dist/state/index.js +57 -8
  228. package/dist/state/index.js.map +1 -1
  229. package/dist/types/consensus.d.ts +1 -0
  230. package/dist/types/consensus.d.ts.map +1 -1
  231. package/dist/types/consensus.js.map +1 -1
  232. package/dist/types/website-strategy.d.ts +1 -1
  233. package/dist/types/workflow.d.ts +447 -0
  234. package/dist/types/workflow.d.ts.map +1 -1
  235. package/dist/types/workflow.js +3 -0
  236. package/dist/types/workflow.js.map +1 -1
  237. package/dist/upgrade/handlers.d.ts.map +1 -1
  238. package/dist/upgrade/handlers.js +6 -3
  239. package/dist/upgrade/handlers.js.map +1 -1
  240. package/dist/workflow/consensus.d.ts.map +1 -1
  241. package/dist/workflow/consensus.js +1 -0
  242. package/dist/workflow/consensus.js.map +1 -1
  243. package/dist/workflow/website-strategy.d.ts.map +1 -1
  244. package/dist/workflow/website-strategy.js +2 -29
  245. package/dist/workflow/website-strategy.js.map +1 -1
  246. package/dist/workflow/website-updater.d.ts.map +1 -1
  247. package/dist/workflow/website-updater.js +3 -2
  248. package/dist/workflow/website-updater.js.map +1 -1
  249. package/package.json +1 -1
  250. package/src/adapters/gemini.ts +51 -6
  251. package/src/adapters/grok.ts +51 -6
  252. package/src/adapters/openai.ts +53 -5
  253. package/src/cli/commands/create.ts +1 -1
  254. package/src/cli/interactive.ts +337 -20
  255. package/src/generators/all.ts +25 -2
  256. package/src/generators/doc-parser.ts +75 -15
  257. package/src/generators/templates/fullstack.ts +1 -1
  258. package/src/generators/templates/website-components.ts +1 -1
  259. package/src/generators/templates/website-config.ts +23 -11
  260. package/src/generators/templates/website-conversion.ts +1 -1
  261. package/src/generators/templates/website-landing.ts +1 -1
  262. package/src/generators/templates/website-layout.ts +491 -23
  263. package/src/generators/templates/website-pricing.ts +1 -1
  264. package/src/generators/templates/website-sections.ts +1 -1
  265. package/src/generators/templates/website-seo.ts +4 -1
  266. package/src/generators/templates/website.ts +3 -0
  267. package/src/generators/website-content-ai.ts +186 -0
  268. package/src/generators/website-content-scanner.ts +113 -1
  269. package/src/generators/website-context.ts +151 -12
  270. package/src/generators/website-debug.ts +26 -0
  271. package/src/generators/website.ts +28 -3
  272. package/src/pipeline/artifact-manager.ts +3 -0
  273. package/src/pipeline/auto-recovery.ts +283 -0
  274. package/src/pipeline/change-request.ts +63 -1
  275. package/src/pipeline/check-runner.ts +141 -2
  276. package/src/pipeline/command-resolver.ts +34 -2
  277. package/src/pipeline/consensus/arbitrator-query.ts +101 -0
  278. package/src/pipeline/consensus/consensus-runner.ts +1099 -42
  279. package/src/pipeline/cr-lifecycle.ts +103 -0
  280. package/src/pipeline/gate-engine.ts +36 -8
  281. package/src/pipeline/migration.ts +5 -30
  282. package/src/pipeline/orchestrator.ts +367 -16
  283. package/src/pipeline/packets/consensus-packet-builder.ts +44 -18
  284. package/src/pipeline/phases/architecture.ts +6 -3
  285. package/src/pipeline/phases/audit.ts +6 -3
  286. package/src/pipeline/phases/consensus-architecture.ts +10 -1
  287. package/src/pipeline/phases/consensus-master-plan.ts +10 -3
  288. package/src/pipeline/phases/consensus-role-plans.ts +10 -1
  289. package/src/pipeline/phases/done.ts +15 -4
  290. package/src/pipeline/phases/intake.ts +67 -14
  291. package/src/pipeline/phases/phase-context.ts +6 -1
  292. package/src/pipeline/phases/production-gate.ts +41 -3
  293. package/src/pipeline/phases/qa-validation.ts +51 -5
  294. package/src/pipeline/phases/recovery-loop.ts +229 -7
  295. package/src/pipeline/phases/review.ts +73 -30
  296. package/src/pipeline/phases/role-planning.ts +23 -5
  297. package/src/pipeline/phases/stuck.ts +10 -0
  298. package/src/pipeline/repo-snapshot.ts +3 -0
  299. package/src/pipeline/role-execution-adapter.ts +30 -4
  300. package/src/pipeline/skill-loader.ts +33 -0
  301. package/src/pipeline/skills/constitution-generator.ts +236 -0
  302. package/src/pipeline/skills/coverage-gate.ts +199 -0
  303. package/src/pipeline/skills/generator.ts +287 -0
  304. package/src/pipeline/skills/role-map.ts +248 -0
  305. package/src/pipeline/skills/types.ts +53 -0
  306. package/src/pipeline/skills/usage-registry.ts +87 -0
  307. package/src/pipeline/strategy-context.ts +60 -0
  308. package/src/pipeline/type-defs/artifacts.ts +5 -0
  309. package/src/pipeline/type-defs/checks.ts +4 -0
  310. package/src/pipeline/type-defs/packets.ts +18 -1
  311. package/src/pipeline/type-defs/state.ts +26 -1
  312. package/src/shared/text-utils.ts +70 -0
  313. package/src/shared/website-strategy-format.ts +56 -0
  314. package/src/state/index.ts +60 -8
  315. package/src/types/consensus.ts +1 -0
  316. package/src/types/workflow.ts +6 -0
  317. package/src/upgrade/handlers.ts +9 -3
  318. package/src/workflow/consensus.ts +1 -0
  319. package/src/workflow/website-strategy.ts +2 -36
  320. package/src/workflow/website-updater.ts +4 -2
  321. package/tests/adapters/gemini.test.ts +165 -0
  322. package/tests/adapters/grok.test.ts +137 -0
  323. package/tests/adapters/openai.test.ts +128 -0
  324. package/tests/generators/doc-parser.test.ts +88 -9
  325. package/tests/generators/quality-gate.test.ts +19 -3
  326. package/tests/generators/website-components.test.ts +34 -0
  327. package/tests/generators/website-content-ai.test.ts +308 -0
  328. package/tests/generators/website-content-scanner.test.ts +86 -0
  329. package/tests/generators/website-context.test.ts +3 -2
  330. package/tests/integration/smokestack-scaffold.test.ts +385 -0
  331. package/tests/pipeline/auto-recovery.test.ts +337 -0
  332. package/tests/pipeline/change-request.test.ts +70 -0
  333. package/tests/pipeline/command-resolver.test.ts +42 -0
  334. package/tests/pipeline/consensus/arbitrator-query.test.ts +107 -0
  335. package/tests/pipeline/consensus-runner.test.ts +1333 -10
  336. package/tests/pipeline/consensus-scoring.test.ts +602 -18
  337. package/tests/pipeline/gate-engine.test.ts +34 -0
  338. package/tests/pipeline/install-check.test.ts +261 -0
  339. package/tests/pipeline/migration.test.ts +4 -3
  340. package/tests/pipeline/orchestrator.test.ts +1506 -15
  341. package/tests/pipeline/packets/builders.test.ts +29 -6
  342. package/tests/pipeline/phases/role-planning.strategy.test.ts +204 -0
  343. package/tests/pipeline/pipeline-persistence.test.ts +230 -0
  344. package/tests/pipeline/recovery-loop-guidance.test.ts +280 -0
  345. package/tests/pipeline/role-execution-adapter.test.ts +88 -0
  346. package/tests/pipeline/skills/constitution-generator.test.ts +201 -0
  347. package/tests/pipeline/skills/coverage-gate.test.ts +370 -0
  348. package/tests/pipeline/skills/generator.test.ts +213 -0
  349. package/tests/pipeline/skills/role-map.test.ts +198 -0
  350. package/tests/pipeline/skills/usage-registry.test.ts +114 -0
  351. package/tests/pipeline/strategy-context.test.ts +148 -0
  352. package/tests/shared/text-utils.test.ts +155 -0
  353. package/tests/state/progress-analysis.test.ts +375 -0
  354. package/tests/upgrade/handlers.test.ts +33 -2
  355. package/tests/workflow/consensus.test.ts +6 -0
  356. package/tsconfig.json +1 -1
@@ -0,0 +1,165 @@
1
+ /**
2
+ * Tests for Gemini adapter - parseConsensusResponse
3
+ */
4
+
5
+ import { describe, it, expect } from 'vitest';
6
+ import { parseConsensusResponse } from '../../src/adapters/gemini.js';
7
+
8
+ describe('Gemini parseConsensusResponse', () => {
9
+ it('should parse a complete response with blocking issues', () => {
10
+ const response = `
11
+ ANALYSIS:
12
+ Well-structured plan with clear goals.
13
+
14
+ STRENGTHS:
15
+ - Good module separation
16
+ - Clear API design
17
+
18
+ CONCERNS:
19
+ - Consider adding rate limiting
20
+
21
+ BLOCKING_ISSUES:
22
+ - Missing authentication middleware
23
+ - No input validation strategy
24
+
25
+ RECOMMENDATIONS:
26
+ - Add rate limiting middleware
27
+
28
+ CONSENSUS: 72%
29
+ `;
30
+
31
+ const result = parseConsensusResponse(response);
32
+
33
+ expect(result.score).toBe(72);
34
+ expect(result.approved).toBe(false);
35
+ expect(result.concerns).toEqual(['Consider adding rate limiting']);
36
+ expect(result.blockingIssues).toEqual([
37
+ 'Missing authentication middleware',
38
+ 'No input validation strategy',
39
+ ]);
40
+ expect(result.recommendations).toEqual(['Add rate limiting middleware']);
41
+ });
42
+
43
+ it('should return empty blocking issues when "None"', () => {
44
+ const response = `
45
+ ANALYSIS:
46
+ Excellent plan.
47
+
48
+ STRENGTHS:
49
+ - Comprehensive coverage
50
+
51
+ CONCERNS:
52
+ - Minor naming inconsistencies
53
+
54
+ BLOCKING_ISSUES:
55
+ - None
56
+
57
+ RECOMMENDATIONS:
58
+ - Standardize naming conventions
59
+
60
+ CONSENSUS: 96%
61
+ `;
62
+
63
+ const result = parseConsensusResponse(response);
64
+
65
+ expect(result.score).toBe(96);
66
+ expect(result.approved).toBe(true);
67
+ expect(result.blockingIssues).toEqual([]);
68
+ expect(result.concerns).toHaveLength(1);
69
+ });
70
+
71
+ it('should handle missing BLOCKING_ISSUES section (backward compat)', () => {
72
+ const response = `
73
+ ANALYSIS:
74
+ Good plan overall.
75
+
76
+ STRENGTHS:
77
+ - Solid architecture design
78
+
79
+ CONCERNS:
80
+ - Some performance issue to watch
81
+
82
+ RECOMMENDATIONS:
83
+ - Optimize database queries
84
+
85
+ CONSENSUS: 88%
86
+ `;
87
+
88
+ const result = parseConsensusResponse(response);
89
+
90
+ expect(result.blockingIssues).toEqual([]);
91
+ expect(result.score).toBe(88);
92
+ });
93
+
94
+ it('should filter none-variant blocking issues like "No blocking issues found"', () => {
95
+ const response = `
96
+ ANALYSIS:
97
+ Good plan with solid foundation.
98
+
99
+ STRENGTHS:
100
+ - Clean design
101
+
102
+ CONCERNS:
103
+ - Minor performance concern
104
+
105
+ BLOCKING_ISSUES:
106
+ - No blocking issues found
107
+
108
+ RECOMMENDATIONS:
109
+ - Optimize queries
110
+
111
+ CONSENSUS: 91%
112
+ `;
113
+ const result = parseConsensusResponse(response);
114
+ expect(result.blockingIssues).toEqual([]);
115
+ });
116
+
117
+ it('should filter "None identified" from blocking issues', () => {
118
+ const response = `
119
+ ANALYSIS:
120
+ Thorough review complete.
121
+
122
+ STRENGTHS:
123
+ - Well-structured code
124
+
125
+ CONCERNS:
126
+ - Could use more tests
127
+
128
+ BLOCKING_ISSUES:
129
+ - None identified
130
+
131
+ RECOMMENDATIONS:
132
+ - Add integration tests
133
+
134
+ CONSENSUS: 89%
135
+ `;
136
+ const result = parseConsensusResponse(response);
137
+ expect(result.blockingIssues).toEqual([]);
138
+ });
139
+
140
+ it('should handle ALL-CAPS format for blocking issues', () => {
141
+ const response = `
142
+ ANALYSIS:
143
+ Detailed review of the plan.
144
+
145
+ STRENGTHS:
146
+ - Good structure
147
+
148
+ CONCERNS:
149
+ - Minor issue noted
150
+
151
+ BLOCKING_ISSUES:
152
+ - Critical security flaw
153
+
154
+ RECOMMENDATIONS:
155
+ - Fix security
156
+
157
+ CONSENSUS: 60%
158
+ `;
159
+
160
+ const result = parseConsensusResponse(response);
161
+
162
+ expect(result.blockingIssues).toEqual(['Critical security flaw']);
163
+ expect(result.recommendations).toEqual(['Fix security']);
164
+ });
165
+ });
@@ -0,0 +1,137 @@
1
+ /**
2
+ * Tests for Grok adapter - parseConsensusResponse
3
+ */
4
+
5
+ import { describe, it, expect } from 'vitest';
6
+ import { parseConsensusResponse } from '../../src/adapters/grok.js';
7
+
8
+ describe('Grok parseConsensusResponse', () => {
9
+ it('should parse a complete response with blocking issues', () => {
10
+ const response = `
11
+ ANALYSIS:
12
+ Solid plan with room for improvement.
13
+
14
+ STRENGTHS:
15
+ - Clean API design
16
+ - Good test coverage plan
17
+
18
+ CONCERNS:
19
+ - Consider adding monitoring
20
+
21
+ BLOCKING_ISSUES:
22
+ - Missing database migration strategy
23
+ - No rollback plan defined
24
+
25
+ RECOMMENDATIONS:
26
+ - Add observability layer
27
+
28
+ CONSENSUS: 70%
29
+ `;
30
+
31
+ const result = parseConsensusResponse(response);
32
+
33
+ expect(result.score).toBe(70);
34
+ expect(result.approved).toBe(false);
35
+ expect(result.concerns).toEqual(['Consider adding monitoring']);
36
+ expect(result.blockingIssues).toEqual([
37
+ 'Missing database migration strategy',
38
+ 'No rollback plan defined',
39
+ ]);
40
+ });
41
+
42
+ it('should return empty blocking issues when "None"', () => {
43
+ const response = `
44
+ ANALYSIS:
45
+ Great plan.
46
+
47
+ STRENGTHS:
48
+ - Well-structured
49
+
50
+ CONCERNS:
51
+ - Minor style inconsistencies
52
+
53
+ BLOCKING_ISSUES:
54
+ - None
55
+
56
+ RECOMMENDATIONS:
57
+ - Apply consistent formatting
58
+
59
+ CONSENSUS: 95%
60
+ `;
61
+
62
+ const result = parseConsensusResponse(response);
63
+
64
+ expect(result.score).toBe(95);
65
+ expect(result.approved).toBe(true);
66
+ expect(result.blockingIssues).toEqual([]);
67
+ });
68
+
69
+ it('should filter none-variant blocking issues like "No blocking issues found"', () => {
70
+ const response = `
71
+ ANALYSIS:
72
+ Solid implementation plan.
73
+
74
+ STRENGTHS:
75
+ - Good architecture
76
+
77
+ CONCERNS:
78
+ - Consider monitoring
79
+
80
+ BLOCKING_ISSUES:
81
+ - No blocking issues found
82
+
83
+ RECOMMENDATIONS:
84
+ - Add monitoring
85
+
86
+ CONSENSUS: 93%
87
+ `;
88
+ const result = parseConsensusResponse(response);
89
+ expect(result.blockingIssues).toEqual([]);
90
+ });
91
+
92
+ it('should filter "None identified" from blocking issues', () => {
93
+ const response = `
94
+ ANALYSIS:
95
+ Well-considered approach.
96
+
97
+ STRENGTHS:
98
+ - Comprehensive coverage
99
+
100
+ CONCERNS:
101
+ - Minor style issues
102
+
103
+ BLOCKING_ISSUES:
104
+ - None identified
105
+
106
+ RECOMMENDATIONS:
107
+ - Standardize formatting
108
+
109
+ CONSENSUS: 91%
110
+ `;
111
+ const result = parseConsensusResponse(response);
112
+ expect(result.blockingIssues).toEqual([]);
113
+ });
114
+
115
+ it('should handle missing BLOCKING_ISSUES section (backward compat)', () => {
116
+ const response = `
117
+ ANALYSIS:
118
+ Reasonable plan.
119
+
120
+ STRENGTHS:
121
+ - Good overall approach
122
+
123
+ CONCERNS:
124
+ - Needs more detail
125
+
126
+ RECOMMENDATIONS:
127
+ - Expand on implementation details
128
+
129
+ CONSENSUS: 82%
130
+ `;
131
+
132
+ const result = parseConsensusResponse(response);
133
+
134
+ expect(result.blockingIssues).toEqual([]);
135
+ expect(result.score).toBe(82);
136
+ });
137
+ });
@@ -22,6 +22,9 @@ CONCERNS:
22
22
  - No deployment plan
23
23
  - Security considerations not addressed
24
24
 
25
+ BLOCKING_ISSUES:
26
+ - None
27
+
25
28
  RECOMMENDATIONS:
26
29
  - Add error handling middleware
27
30
  - Include deployment configuration
@@ -37,6 +40,7 @@ CONSENSUS: 85%
37
40
  expect(result.analysis).toContain('well-structured plan');
38
41
  expect(result.strengths).toContain('Clear project structure');
39
42
  expect(result.concerns).toContain('Missing error handling strategy');
43
+ expect(result.blockingIssues).toEqual([]);
40
44
  expect(result.recommendations).toContain('Add error handling middleware');
41
45
  expect(result.rawResponse).toBe(response);
42
46
  });
@@ -52,6 +56,9 @@ STRENGTHS:
52
56
  CONCERNS:
53
57
  - None
54
58
 
59
+ BLOCKING_ISSUES:
60
+ - None
61
+
55
62
  RECOMMENDATIONS:
56
63
  - None needed
57
64
 
@@ -62,6 +69,7 @@ CONSENSUS: 98%
62
69
 
63
70
  expect(result.score).toBe(98);
64
71
  expect(result.approved).toBe(true);
72
+ expect(result.blockingIssues).toEqual([]);
65
73
  });
66
74
 
67
75
  it('should handle missing sections gracefully', () => {
@@ -78,6 +86,7 @@ CONSENSUS: 70%
78
86
  expect(result.analysis).toBe('');
79
87
  expect(result.strengths).toEqual([]);
80
88
  expect(result.concerns).toEqual([]);
89
+ expect(result.blockingIssues).toEqual([]);
81
90
  });
82
91
 
83
92
  it('should handle missing score', () => {
@@ -110,6 +119,9 @@ CONCERNS:
110
119
  1. First concern
111
120
  2. Second concern
112
121
 
122
+ BLOCKING_ISSUES:
123
+ - None
124
+
113
125
  RECOMMENDATIONS:
114
126
  - Recommendation one
115
127
  - Recommendation two
@@ -121,6 +133,7 @@ CONSENSUS: 80%
121
133
 
122
134
  expect(result.strengths).toHaveLength(4);
123
135
  expect(result.concerns).toHaveLength(2);
136
+ expect(result.blockingIssues).toEqual([]);
124
137
  expect(result.recommendations).toHaveLength(2);
125
138
  });
126
139
 
@@ -142,4 +155,119 @@ CONSENSUS: 80%
142
155
  expect(parseConsensusResponse('CONSENSUS: 0%').score).toBe(0);
143
156
  expect(parseConsensusResponse('CONSENSUS: 100%').score).toBe(100);
144
157
  });
158
+
159
+ it('should parse blocking issues as separate field', () => {
160
+ const response = `
161
+ ANALYSIS: Good plan.
162
+
163
+ STRENGTHS:
164
+ - Solid architecture
165
+
166
+ CONCERNS:
167
+ - Consider adding caching
168
+
169
+ BLOCKING_ISSUES:
170
+ - Missing authentication flow
171
+ - No database migration strategy
172
+
173
+ RECOMMENDATIONS:
174
+ - Add caching layer
175
+
176
+ CONSENSUS: 72%
177
+ `;
178
+ const result = parseConsensusResponse(response);
179
+ expect(result.blockingIssues).toEqual([
180
+ 'Missing authentication flow',
181
+ 'No database migration strategy',
182
+ ]);
183
+ expect(result.concerns).toEqual(['Consider adding caching']);
184
+ });
185
+
186
+ it('should return empty blocking issues when "None"', () => {
187
+ const response = `
188
+ ANALYSIS: Good plan.
189
+
190
+ STRENGTHS:
191
+ - Solid
192
+
193
+ CONCERNS:
194
+ - Minor naming issues in the module structure
195
+
196
+ BLOCKING_ISSUES:
197
+ - None
198
+
199
+ RECOMMENDATIONS:
200
+ - Improve module names
201
+
202
+ CONSENSUS: 95%
203
+ `;
204
+ const result = parseConsensusResponse(response);
205
+ expect(result.blockingIssues).toEqual([]);
206
+ expect(result.approved).toBe(true);
207
+ });
208
+
209
+ it('should filter none-variant blocking issues like "No blocking issues found"', () => {
210
+ const response = `
211
+ ANALYSIS: Good plan.
212
+
213
+ STRENGTHS:
214
+ - Solid architecture
215
+
216
+ CONCERNS:
217
+ - Minor naming issues
218
+
219
+ BLOCKING_ISSUES:
220
+ - No blocking issues found
221
+
222
+ RECOMMENDATIONS:
223
+ - Improve naming
224
+
225
+ CONSENSUS: 92%
226
+ `;
227
+ const result = parseConsensusResponse(response);
228
+ expect(result.blockingIssues).toEqual([]);
229
+ });
230
+
231
+ it('should filter "None identified" from blocking issues', () => {
232
+ const response = `
233
+ ANALYSIS: Solid plan overall.
234
+
235
+ STRENGTHS:
236
+ - Good design choices
237
+
238
+ CONCERNS:
239
+ - Consider caching
240
+
241
+ BLOCKING_ISSUES:
242
+ - None identified
243
+
244
+ RECOMMENDATIONS:
245
+ - Add caching layer
246
+
247
+ CONSENSUS: 90%
248
+ `;
249
+ const result = parseConsensusResponse(response);
250
+ expect(result.blockingIssues).toEqual([]);
251
+ });
252
+
253
+ it('should handle missing BLOCKING_ISSUES section (backward compat)', () => {
254
+ // Old-format response without BLOCKING_ISSUES section
255
+ const response = `
256
+ ANALYSIS: Good plan.
257
+
258
+ STRENGTHS:
259
+ - Fine overall structure
260
+
261
+ CONCERNS:
262
+ - Some concern about performance
263
+
264
+ RECOMMENDATIONS:
265
+ - A recommendation for optimization
266
+
267
+ CONSENSUS: 90%
268
+ `;
269
+ const result = parseConsensusResponse(response);
270
+ expect(result.blockingIssues).toEqual([]);
271
+ expect(result.concerns).toHaveLength(1);
272
+ });
145
273
  });
@@ -104,18 +104,97 @@ describe('isSuspiciousProductName', () => {
104
104
  });
105
105
 
106
106
  describe('extractPricing', () => {
107
- it('extracts pricing tiers from markdown table', () => {
107
+ it('extracts pricing tiers from markdown table with provenance', () => {
108
108
  const docs = `## Pricing\n| Plan | Price |\n|---|---|\n| Free | Free |\n| Pro | $99/month minimum |\n| Enterprise | Custom pricing |`;
109
- const tiers = extractPricing(docs);
110
- expect(tiers).toBeDefined();
111
- expect(tiers!.length).toBe(3);
112
- expect(tiers![0].name).toContain('Free');
113
- expect(tiers![1].price).toBe('$99');
114
- expect(tiers![2].price).toBe('Custom');
109
+ const result = extractPricing(docs);
110
+ expect(result.source).toBe('docs');
111
+ expect(result.tiers.length).toBe(3);
112
+ expect(result.tiers[0].name).toContain('Free');
113
+ expect(result.tiers[1].price).toBe('$99');
114
+ expect(result.tiers[2].price).toBe('Custom');
115
+ expect(result.evidence).toBeDefined();
116
+ expect(result.evidence!.extractionMethod).toBe('known_plan_names');
117
+ expect(result.evidence!.matchedRows).toBe(3);
115
118
  });
116
119
 
117
- it('returns undefined when no pricing found', () => {
120
+ it('returns source none when no pricing found', () => {
118
121
  const docs = '# Product\nJust a product.';
119
- expect(extractPricing(docs)).toBeUndefined();
122
+ const result = extractPricing(docs);
123
+ expect(result.source).toBe('none');
124
+ expect(result.tiers).toEqual([]);
125
+ expect(result.evidence).toBeUndefined();
126
+ });
127
+
128
+ it('extracts Gateco-style pricing with emoji-prefixed rows and <br> tags', () => {
129
+ const docs = [
130
+ '## Pricing Overview',
131
+ '| Plan | Price | Users |',
132
+ '|---|---|---|',
133
+ '| Free | Free | Up to 5 |',
134
+ '| Pro | $99/month<br>minimum | Unlimited |',
135
+ '| Enterprise | Custom | Unlimited |',
136
+ ].join('\n');
137
+ const result = extractPricing(docs);
138
+ expect(result.source).toBe('docs');
139
+ expect(result.tiers.length).toBe(3);
140
+ expect(result.tiers[0].name).toBe('Free');
141
+ expect(result.tiers[0].price).toBe('Free');
142
+ expect(result.tiers[1].name).toBe('Pro');
143
+ expect(result.tiers[1].price).toBe('$99');
144
+ expect(result.tiers[2].name).toBe('Enterprise');
145
+ expect(result.tiers[2].price).toBe('Custom');
146
+ });
147
+
148
+ it('falls back to table_fallback for nonstandard plan names', () => {
149
+ const docs = [
150
+ '## Pricing',
151
+ '| Plan | Price |',
152
+ '|---|---|',
153
+ '| Hobby | Free |',
154
+ '| Scale | $49/mo |',
155
+ '| Organization | Custom |',
156
+ ].join('\n');
157
+ const result = extractPricing(docs);
158
+ expect(result.source).toBe('docs');
159
+ expect(result.tiers.length).toBe(3);
160
+ expect(result.evidence!.extractionMethod).toBe('table_fallback');
161
+ expect(result.tiers[0].name).toBe('Hobby');
162
+ expect(result.tiers[1].name).toBe('Scale');
163
+ expect(result.tiers[2].name).toBe('Organization');
164
+ });
165
+
166
+ it('detects price in 3rd column via header scan', () => {
167
+ const docs = [
168
+ '## Pricing',
169
+ '| Plan | Features | Price |',
170
+ '|---|---|---|',
171
+ '| Hobby | 5 projects | Free |',
172
+ '| Scale | Unlimited | $49/mo |',
173
+ ].join('\n');
174
+ const result = extractPricing(docs);
175
+ expect(result.source).toBe('docs');
176
+ expect(result.tiers.length).toBe(2);
177
+ expect(result.tiers[0].price).toBe('Free');
178
+ expect(result.tiers[1].price).toBe('$49');
179
+ });
180
+
181
+ it('skips separator rows and header-like rows in fallback', () => {
182
+ const docs = [
183
+ '## Pricing',
184
+ '| Plan | Price |',
185
+ '|---|---|',
186
+ '| Plan | $10 |', // header-like row, should skip
187
+ '| Hobby | Free |',
188
+ ].join('\n');
189
+ const result = extractPricing(docs);
190
+ // "Plan" row should be skipped by the /^(Plan|Tier|Name|Feature)/i filter
191
+ expect(result.tiers.every((t) => t.name !== 'Plan')).toBe(true);
192
+ });
193
+
194
+ it('returns empty tiers for pricing section with no table', () => {
195
+ const docs = '## Pricing\nContact us for pricing details.';
196
+ const result = extractPricing(docs);
197
+ expect(result.source).toBe('none');
198
+ expect(result.tiers).toEqual([]);
120
199
  });
121
200
  });
@@ -75,7 +75,7 @@ describe('validateWebsiteContextOrThrow', () => {
75
75
  });
76
76
 
77
77
  it('still throws when passed is false from validateWebsiteContext', () => {
78
- // Context with multiple blocking issues
78
+ // Context with multiple blocking issues (strategy absence is not a factor)
79
79
  const context = makeContext({
80
80
  productName: 'my-app',
81
81
  rawDocs: '',
@@ -87,6 +87,13 @@ describe('validateWebsiteContextOrThrow', () => {
87
87
  /Website generation blocked/
88
88
  );
89
89
  });
90
+
91
+ it('does not throw on missing strategy alone', () => {
92
+ // Strategy absence should never cause validation failure
93
+ const context = makeContext({ strategy: undefined });
94
+
95
+ expect(() => validateWebsiteContextOrThrow(context, 'gateco')).not.toThrow();
96
+ });
90
97
  });
91
98
 
92
99
  describe('validateWebsiteContext (soft mode)', () => {
@@ -168,7 +175,7 @@ describe('validateWebsiteContext (soft mode)', () => {
168
175
  expect(result.warnings.some((w) => /description/i.test(w))).toBe(true);
169
176
  });
170
177
 
171
- it('clamps score to 0 when everything is wrong', () => {
178
+ it('clamps score to floor when everything is wrong', () => {
172
179
  const context: WebsiteContentContext = {
173
180
  productName: 'my-app',
174
181
  features: [],
@@ -177,7 +184,16 @@ describe('validateWebsiteContext (soft mode)', () => {
177
184
  };
178
185
  const result = validateWebsiteContext(context, 'my-app');
179
186
 
180
- expect(result.contentScore).toBe(0);
187
+ // Score is low but no longer 0 since strategy penalty (-15) was removed
188
+ expect(result.contentScore).toBeLessThanOrEqual(15);
181
189
  expect(result.passed).toBe(false);
182
190
  });
191
+
192
+ it('does not emit strategy-related issues when strategy is undefined', () => {
193
+ const context = makeContext({ strategy: undefined });
194
+ const result = validateWebsiteContext(context, 'gateco');
195
+
196
+ // Strategy absence should not produce any issues or warnings about strategy
197
+ expect(result.issues.some((i) => /strategy/i.test(i))).toBe(false);
198
+ });
183
199
  });
@@ -9,6 +9,7 @@ import {
9
9
  generateWebsiteFooter,
10
10
  generateWebsiteNavigation,
11
11
  } from '../../src/generators/templates/website-components.js';
12
+ import { getWebsiteProjectFiles } from '../../src/generators/website.js';
12
13
  import type { WebsiteContentContext } from '../../src/generators/website-context.js';
13
14
  import type { WebsiteStrategyDocument } from '../../src/types/website-strategy.js';
14
15
 
@@ -132,6 +133,39 @@ describe('generateWebsiteFooter', () => {
132
133
  expect(footer).toContain('Resources');
133
134
  expect(footer).toContain('Legal');
134
135
  });
136
+
137
+ it('all default footer hrefs have corresponding generated pages', () => {
138
+ const footer = generateWebsiteFooter('deploy-ai', contextNoLogo);
139
+ const generatedFiles = getWebsiteProjectFiles('deploy-ai');
140
+
141
+ // Extract all href values from the default footer
142
+ const hrefPattern = /href:\s*'([^']+)'/g;
143
+ let match;
144
+ const hrefs: string[] = [];
145
+ while ((match = hrefPattern.exec(footer)) !== null) {
146
+ hrefs.push(match[1]);
147
+ }
148
+
149
+ // Build set of generated page routes from file paths
150
+ const pageRoutes = new Set<string>();
151
+ for (const file of generatedFiles) {
152
+ const pageMatch = file.match(/^src\/app(.*)\/page\.tsx$/);
153
+ if (pageMatch) {
154
+ pageRoutes.add(pageMatch[1] || '/');
155
+ }
156
+ }
157
+ // Also add root route
158
+ if (generatedFiles.includes('src/app/page.tsx')) {
159
+ pageRoutes.add('/');
160
+ }
161
+
162
+ // Every non-anchor internal href should correspond to a generated page
163
+ for (const href of hrefs) {
164
+ if (href.startsWith('/#')) continue; // Anchor links are fine
165
+ if (!href.startsWith('/')) continue; // External links are fine
166
+ expect(pageRoutes.has(href)).toBe(true);
167
+ }
168
+ });
135
169
  });
136
170
 
137
171
  describe('generateWebsiteNavigation', () => {