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,236 @@
1
+ /**
2
+ * Deterministic constitution generation — no AI call required.
3
+ * Produces skills/POPEYE_CONSTITUTION.md from templates + inferred tech stack.
4
+ * Includes pipeline governance invariants that never change.
5
+ */
6
+
7
+ import { existsSync, mkdirSync, writeFileSync } from 'node:fs';
8
+ import { join } from 'node:path';
9
+
10
+ import type { OutputLanguage } from '../../types/project.js';
11
+ import type { ConstitutionContext, TechStack } from './types.js';
12
+
13
+ // ─── Constants ──────────────────────────────────────────
14
+
15
+ const CONSTITUTION_FILENAME = 'POPEYE_CONSTITUTION.md';
16
+ const PIPELINE_VERSION = '1.0';
17
+
18
+ // ─── Public API ─────────────────────────────────────────
19
+
20
+ /**
21
+ * Generate the project constitution file if it doesn't already exist.
22
+ * Entirely deterministic — built from templates and tech stack data.
23
+ *
24
+ * @param context - Constitution generation context
25
+ */
26
+ export function generateConstitution(context: ConstitutionContext): void {
27
+ const { skillsDir } = context;
28
+
29
+ if (shouldSkipConstitution(skillsDir)) {
30
+ return;
31
+ }
32
+
33
+ if (!existsSync(skillsDir)) {
34
+ mkdirSync(skillsDir, { recursive: true });
35
+ }
36
+
37
+ const content = buildConstitutionContent(context);
38
+ const constitutionPath = join(skillsDir, CONSTITUTION_FILENAME);
39
+ writeFileSync(constitutionPath, content, 'utf-8');
40
+ }
41
+
42
+ /**
43
+ * Check if constitution generation should be skipped.
44
+ * Returns true if the file already exists (hand-written or prior run).
45
+ *
46
+ * @param skillsDir - Path to the skills directory
47
+ * @returns true if generation should be skipped
48
+ */
49
+ export function shouldSkipConstitution(skillsDir: string): boolean {
50
+ const constitutionPath = join(skillsDir, CONSTITUTION_FILENAME);
51
+ return existsSync(constitutionPath);
52
+ }
53
+
54
+ // ─── Content Assembly ───────────────────────────────────
55
+
56
+ /**
57
+ * Build the full constitution markdown content.
58
+ *
59
+ * @param context - Constitution generation context
60
+ * @returns Complete markdown string
61
+ */
62
+ function buildConstitutionContent(context: ConstitutionContext): string {
63
+ const { projectName, language, techStack, sessionGuidance } = context;
64
+ const date = new Date().toISOString().split('T')[0];
65
+
66
+ const sections = [
67
+ `# Project Constitution: ${projectName}`,
68
+ '',
69
+ `Generated: ${date} | Language: ${language} | Pipeline: v${PIPELINE_VERSION}`,
70
+ '',
71
+ getTechStackSection(techStack),
72
+ getArchitectureRules(techStack),
73
+ getCodeQualityRules(),
74
+ getGovernanceRules(),
75
+ getConstraintsSection(language, sessionGuidance),
76
+ getImmutabilitySection(),
77
+ ];
78
+
79
+ return sections.join('\n');
80
+ }
81
+
82
+ // ─── Template Sections ──────────────────────────────────
83
+
84
+ /**
85
+ * Generate the tech stack section from inferred stack data.
86
+ *
87
+ * @param techStack - Inferred tech stack
88
+ * @returns Markdown section
89
+ */
90
+ export function getTechStackSection(techStack: TechStack): string {
91
+ const lines = ['## Tech Stack'];
92
+ if (techStack.language) lines.push(`- Language: ${techStack.language}`);
93
+ if (techStack.backend) lines.push(`- Framework: ${techStack.backend}`);
94
+ if (techStack.frontend) lines.push(`- Frontend: ${techStack.frontend}`);
95
+ if (techStack.database) lines.push(`- Database: ${techStack.database}`);
96
+ if (techStack.orm) lines.push(`- ORM: ${techStack.orm}`);
97
+ if (techStack.testing) lines.push(`- Testing: ${techStack.testing}`);
98
+ lines.push('');
99
+ return lines.join('\n');
100
+ }
101
+
102
+ /**
103
+ * Generate architecture rules based on the tech stack.
104
+ *
105
+ * @param techStack - Inferred tech stack
106
+ * @returns Markdown section
107
+ */
108
+ export function getArchitectureRules(techStack: TechStack): string {
109
+ const rules: string[] = [];
110
+ let ruleNum = 1;
111
+
112
+ if (techStack.backend?.includes('FastAPI')) {
113
+ rules.push(`${ruleNum++}. All API endpoints MUST use async/await`);
114
+ }
115
+ if (techStack.backend?.includes('Express')) {
116
+ rules.push(`${ruleNum++}. Use Express middleware pattern for cross-cutting concerns`);
117
+ }
118
+ if (techStack.backend?.includes('Django')) {
119
+ rules.push(`${ruleNum++}. Follow Django app structure conventions`);
120
+ }
121
+ if (techStack.orm?.includes('SQLAlchemy')) {
122
+ rules.push(`${ruleNum++}. Database access exclusively via SQLAlchemy ORM`);
123
+ }
124
+ if (techStack.orm?.includes('Prisma')) {
125
+ rules.push(`${ruleNum++}. Database access exclusively via Prisma client`);
126
+ }
127
+ if (techStack.language?.includes('Python')) {
128
+ rules.push(`${ruleNum++}. Environment variables via python-dotenv, never hardcoded`);
129
+ rules.push(`${ruleNum++}. PEP8 style with type hints on all functions`);
130
+ }
131
+ if (techStack.language?.includes('TypeScript')) {
132
+ rules.push(`${ruleNum++}. TypeScript strict mode, no implicit any`);
133
+ rules.push(`${ruleNum++}. Environment variables via dotenv, never hardcoded`);
134
+ }
135
+ if (techStack.frontend?.includes('React')) {
136
+ rules.push(`${ruleNum++}. React components use functional patterns with hooks`);
137
+ }
138
+ if (techStack.frontend?.includes('Next')) {
139
+ rules.push(`${ruleNum++}. Next.js App Router conventions for routing and layouts`);
140
+ }
141
+
142
+ // Always add a generic rule if nothing specific matched
143
+ if (rules.length === 0) {
144
+ rules.push('1. Environment variables never hardcoded in source code');
145
+ rules.push('2. Clear separation of concerns between modules');
146
+ }
147
+
148
+ return ['## Architecture Rules', ...rules, ''].join('\n');
149
+ }
150
+
151
+ /**
152
+ * Generate code quality rules (constant across all projects).
153
+ *
154
+ * @returns Markdown section
155
+ */
156
+ export function getCodeQualityRules(): string {
157
+ return [
158
+ '## Code Quality',
159
+ '1. Maximum 500 lines per source file',
160
+ '2. Unit tests for every module (happy path + edge case + failure)',
161
+ '3. Standard logging (no unstructured print statements)',
162
+ '4. Docstrings/JSDoc on public functions',
163
+ '',
164
+ ].join('\n');
165
+ }
166
+
167
+ /**
168
+ * Generate governance rules (pipeline invariants, constant).
169
+ *
170
+ * @returns Markdown section
171
+ */
172
+ function getGovernanceRules(): string {
173
+ return [
174
+ '## Governance Rules',
175
+ '1. Consensus threshold: 0.95 with minimum 2 reviewers',
176
+ '2. All artifacts are immutable once stored (new versions create new files)',
177
+ '3. No placeholder content in production code or generated output',
178
+ '4. Gate failures route to RECOVERY_LOOP before phase retry',
179
+ '5. Constitution modifications during pipeline execution are forbidden',
180
+ '6. Change Requests required for scope changes after INTAKE',
181
+ '',
182
+ ].join('\n');
183
+ }
184
+
185
+ /**
186
+ * Generate language-specific and session-specific constraints.
187
+ *
188
+ * @param language - Project language
189
+ * @param sessionGuidance - Optional session guidance text
190
+ * @returns Markdown section
191
+ */
192
+ export function getConstraintsSection(
193
+ language: OutputLanguage,
194
+ sessionGuidance?: string,
195
+ ): string {
196
+ const lines = ['## Project Constraints'];
197
+
198
+ const langConstraints: Record<string, string[]> = {
199
+ python: ['- Python 3.11+ required', '- Use virtual environment (venv) for all operations'],
200
+ typescript: ['- Node.js 18+ required', '- ESM modules (import/export, .js extensions)'],
201
+ fullstack: [
202
+ '- Python 3.11+ for backend, Node.js 18+ for frontend',
203
+ '- Monorepo structure with clear app boundaries',
204
+ ],
205
+ website: ['- Node.js 18+ required', '- SSG/SSR optimization for performance and SEO'],
206
+ all: [
207
+ '- Python 3.11+ for backend, Node.js 18+ for frontend and website',
208
+ '- Monorepo structure with clear app boundaries',
209
+ ],
210
+ };
211
+
212
+ const constraints = langConstraints[language] ?? langConstraints.python;
213
+ lines.push(...constraints);
214
+
215
+ if (sessionGuidance) {
216
+ lines.push('', '### Session-Specific Guidance');
217
+ lines.push(sessionGuidance.slice(0, 500));
218
+ }
219
+
220
+ lines.push('');
221
+ return lines.join('\n');
222
+ }
223
+
224
+ /**
225
+ * Generate the immutability notice (constant).
226
+ *
227
+ * @returns Markdown section
228
+ */
229
+ function getImmutabilitySection(): string {
230
+ return [
231
+ '## Immutability',
232
+ 'This document MUST NOT be modified during pipeline execution.',
233
+ 'Any modification triggers constitution verification failure at next gate.',
234
+ '',
235
+ ].join('\n');
236
+ }
@@ -0,0 +1,199 @@
1
+ /**
2
+ * Skill Coverage Gate — deterministic assertion that every active role
3
+ * has recorded usage (or is explicitly exempt).
4
+ *
5
+ * Called at CONSENSUS_ROLE_PLANS and PRODUCTION_GATE gates.
6
+ */
7
+
8
+ import type { PipelineRole, PipelinePhase, PipelineState } from '../types.js';
9
+ import type { SkillUsageEvent } from './usage-registry.js';
10
+
11
+ // ─── Phase Order (must match orchestrator/gate phase sequence) ────
12
+
13
+ /** Canonical phase order — used for phase-aware deferral in coverage checks. */
14
+ export const PHASE_ORDER: PipelinePhase[] = [
15
+ 'INTAKE', 'CONSENSUS_MASTER_PLAN', 'ARCHITECTURE', 'CONSENSUS_ARCHITECTURE',
16
+ 'ROLE_PLANNING', 'CONSENSUS_ROLE_PLANS', 'IMPLEMENTATION', 'QA_VALIDATION',
17
+ 'REVIEW', 'AUDIT', 'PRODUCTION_GATE', 'RECOVERY_LOOP', 'DONE', 'STUCK',
18
+ ];
19
+
20
+ // ─── Required Usage Configuration ────────────────────────
21
+
22
+ export interface RoleUsageRequirement {
23
+ phases: PipelinePhase[];
24
+ minEvents: number;
25
+ conditional?: 'always' | 'if_recovery' | 'if_arbitrated' | 'if_journal_triggered';
26
+ }
27
+
28
+ export const ROLE_REQUIRED_USAGE: Record<PipelineRole, RoleUsageRequirement> = {
29
+ DISPATCHER: { phases: [], minEvents: 0 },
30
+ ARCHITECT: { phases: ['ARCHITECTURE'], minEvents: 1 },
31
+ DB_EXPERT: { phases: ['ROLE_PLANNING'], minEvents: 1 },
32
+ BACKEND_PROGRAMMER: { phases: ['ROLE_PLANNING'], minEvents: 1 },
33
+ FRONTEND_PROGRAMMER: { phases: ['ROLE_PLANNING'], minEvents: 1 },
34
+ WEBSITE_PROGRAMMER: { phases: ['ROLE_PLANNING'], minEvents: 1 },
35
+ UI_UX_SPECIALIST: { phases: ['ROLE_PLANNING'], minEvents: 1 },
36
+ MARKETING_EXPERT: { phases: ['ROLE_PLANNING'], minEvents: 1 },
37
+ SOCIAL_EXPERT: { phases: ['ROLE_PLANNING'], minEvents: 1 },
38
+ QA_TESTER: { phases: ['ROLE_PLANNING', 'QA_VALIDATION'], minEvents: 1 },
39
+ REVIEWER: { phases: ['REVIEW'], minEvents: 1 },
40
+ ARBITRATOR: { phases: [], minEvents: 0, conditional: 'if_arbitrated' },
41
+ DEBUGGER: { phases: ['RECOVERY_LOOP'], minEvents: 0, conditional: 'if_recovery' },
42
+ AUDITOR: { phases: ['AUDIT'], minEvents: 1 },
43
+ JOURNALIST: {
44
+ phases: [
45
+ 'CONSENSUS_MASTER_PLAN', 'CONSENSUS_ARCHITECTURE', 'CONSENSUS_ROLE_PLANS',
46
+ 'AUDIT', 'PRODUCTION_GATE', 'RECOVERY_LOOP', 'DONE',
47
+ ],
48
+ minEvents: 1,
49
+ conditional: 'if_journal_triggered',
50
+ },
51
+ RELEASE_MANAGER: { phases: ['DONE'], minEvents: 1 },
52
+ };
53
+
54
+ // ─── Coverage Result ─────────────────────────────────────
55
+
56
+ export interface CoverageMissing {
57
+ role: PipelineRole;
58
+ expectedPhases: PipelinePhase[];
59
+ reason: string;
60
+ }
61
+
62
+ export interface CoverageResult {
63
+ pass: boolean;
64
+ missing: CoverageMissing[];
65
+ covered: PipelineRole[];
66
+ /** Roles skipped because their required phases haven't been reached yet (v2.4.5) */
67
+ deferred: PipelineRole[];
68
+ }
69
+
70
+ // ─── Assertion Logic ─────────────────────────────────────
71
+
72
+ /**
73
+ * Assert that all active roles have recorded skill usage
74
+ * according to their requirements.
75
+ *
76
+ * Args:
77
+ * activeRoles: Roles currently active in the pipeline.
78
+ * events: All recorded skill usage events.
79
+ * pipeline: Full pipeline state for conditional checks.
80
+ * currentPhase: Current pipeline phase for phase-aware deferral (v2.4.5).
81
+ * Omit for strict mode (checks all roles regardless of phase).
82
+ *
83
+ * Returns:
84
+ * CoverageResult with pass/fail and details.
85
+ */
86
+ export function assertSkillCoverage(
87
+ activeRoles: PipelineRole[],
88
+ events: SkillUsageEvent[],
89
+ pipeline: PipelineState,
90
+ currentPhase?: PipelinePhase,
91
+ ): CoverageResult {
92
+ const missing: CoverageMissing[] = [];
93
+ const covered: PipelineRole[] = [];
94
+ const deferred: PipelineRole[] = [];
95
+
96
+ // Resolve phase index; -1 means unknown/omitted -> strict mode (check all)
97
+ const currentIdx = currentPhase ? PHASE_ORDER.indexOf(currentPhase) : -1;
98
+
99
+ for (const role of activeRoles) {
100
+ const requirement = ROLE_REQUIRED_USAGE[role];
101
+ if (!requirement) {
102
+ // Reason: Unknown role — skip rather than crash
103
+ continue;
104
+ }
105
+
106
+ // Meta-only roles (DISPATCHER) with minEvents 0 and no conditional
107
+ if (requirement.minEvents === 0 && !requirement.conditional) {
108
+ covered.push(role);
109
+ continue;
110
+ }
111
+
112
+ // Conditional roles — check if their condition is met
113
+ if (requirement.conditional) {
114
+ const isRequired = isConditionalRequired(requirement.conditional, pipeline);
115
+ if (!isRequired) {
116
+ // Condition not met — not required, count as covered
117
+ covered.push(role);
118
+ continue;
119
+ }
120
+ }
121
+
122
+ // v2.4.5: Phase-aware deferral — skip roles whose phases are all after currentPhase.
123
+ // Only applies when currentIdx >= 0 (known phase). Unknown phase = strict mode.
124
+ if (currentIdx >= 0 && requirement.phases.length > 0) {
125
+ const anyPhaseReached = requirement.phases.some(
126
+ (p) => PHASE_ORDER.indexOf(p) <= currentIdx,
127
+ );
128
+ if (!anyPhaseReached) {
129
+ // Reason: Role's required phases are all after currentPhase — defer check
130
+ deferred.push(role);
131
+ continue;
132
+ }
133
+ }
134
+
135
+ // Check if role has at least minEvents usage events
136
+ const roleEvents = events.filter((e) => e.role === role);
137
+ const effectiveMin = Math.max(requirement.minEvents, 1);
138
+
139
+ if (roleEvents.length >= effectiveMin) {
140
+ covered.push(role);
141
+ } else {
142
+ missing.push({
143
+ role,
144
+ expectedPhases: requirement.phases,
145
+ reason: roleEvents.length === 0
146
+ ? `No skill usage recorded for ${role}`
147
+ : `Only ${roleEvents.length}/${effectiveMin} usage events for ${role}`,
148
+ });
149
+ }
150
+ }
151
+
152
+ return {
153
+ pass: missing.length === 0,
154
+ missing,
155
+ covered,
156
+ deferred,
157
+ };
158
+ }
159
+
160
+ // ─── Conditional Helpers ─────────────────────────────────
161
+
162
+ function isConditionalRequired(
163
+ conditional: NonNullable<RoleUsageRequirement['conditional']>,
164
+ pipeline: PipelineState,
165
+ ): boolean {
166
+ switch (conditional) {
167
+ case 'always':
168
+ return true;
169
+
170
+ case 'if_recovery':
171
+ return pipeline.recoveryCount > 0;
172
+
173
+ case 'if_arbitrated':
174
+ return hasArbitratedConsensus(pipeline);
175
+
176
+ case 'if_journal_triggered':
177
+ return hasJournalTriggered(pipeline);
178
+
179
+ default:
180
+ return false;
181
+ }
182
+ }
183
+
184
+ /** Check if any arbitration occurred during consensus phases. */
185
+ function hasArbitratedConsensus(pipeline: PipelineState): boolean {
186
+ // Reason: Arbitration artifacts are created when consensus requires arbitrator intervention
187
+ const arbitrationArtifacts = pipeline.artifacts.filter((a) => a.type === 'arbitration');
188
+ return arbitrationArtifacts.length > 0;
189
+ }
190
+
191
+ /** Check if any journalist-triggering phases have completed. */
192
+ function hasJournalTriggered(pipeline: PipelineState): boolean {
193
+ const journalPhases: PipelinePhase[] = [
194
+ 'CONSENSUS_MASTER_PLAN', 'CONSENSUS_ARCHITECTURE', 'CONSENSUS_ROLE_PLANS',
195
+ 'AUDIT', 'PRODUCTION_GATE', 'RECOVERY_LOOP', 'DONE',
196
+ ];
197
+ const completedPhases = new Set(Object.keys(pipeline.gateResults));
198
+ return journalPhases.some((phase) => completedPhases.has(phase));
199
+ }