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
@@ -13,7 +13,7 @@ import type { AuditFinding, ArtifactEntry, ChangeRequest } from '../types.js';
13
13
  import type { ArtifactManager } from '../artifact-manager.js';
14
14
 
15
15
  export async function runAudit(context: PhaseContext): Promise<PhaseResult> {
16
- const { pipeline, artifactManager, skillLoader, projectDir } = context;
16
+ const { pipeline, artifactManager, skillLoader, skillUsageRegistry, projectDir } = context;
17
17
  const artifacts = [];
18
18
 
19
19
  try {
@@ -23,8 +23,8 @@ export async function runAudit(context: PhaseContext): Promise<PhaseResult> {
23
23
  artifacts.push(snapshotEntry);
24
24
  pipeline.latestRepoSnapshot = artifactManager.toArtifactRef(snapshotEntry);
25
25
 
26
- // 2. Load auditor skill
27
- const auditorSkill = skillLoader.loadSkill('AUDITOR');
26
+ // 2. Load auditor skill with metadata
27
+ const { definition: auditorSkill, meta: auditorMeta } = skillLoader.loadSkillWithMeta('AUDITOR');
28
28
 
29
29
  // 3. Run audit checks via Claude
30
30
  const { executePrompt } = await import('../../adapters/claude.js');
@@ -53,6 +53,9 @@ export async function runAudit(context: PhaseContext): Promise<PhaseResult> {
53
53
  const auditResult = await executePrompt(auditPrompt);
54
54
  const auditResponse = auditResult.response;
55
55
 
56
+ // Record skill usage — auditor skill injected into audit prompt
57
+ skillUsageRegistry.record('AUDITOR', 'AUDIT', 'system_prompt', auditorMeta.source, auditorMeta.version);
58
+
56
59
  // 4. Parse findings from audit response (simplified extraction)
57
60
  const findings = parseAuditFindings(auditResponse);
58
61
 
@@ -44,6 +44,7 @@ export async function runConsensusArchitecture(context: PhaseContext): Promise<P
44
44
  const masterPlanArtifact = pipeline.artifacts.find((a) => a.type === 'master_plan');
45
45
 
46
46
  // 3. Build plan packet
47
+ // v2.4.4: version tracks plan revision count for recovery loop convergence
47
48
  const planPacket = buildPlanPacket({
48
49
  phase: 'CONSENSUS_ARCHITECTURE',
49
50
  submittedBy: 'ARCHITECT',
@@ -61,11 +62,18 @@ export async function runConsensusArchitecture(context: PhaseContext): Promise<P
61
62
  ],
62
63
  dependencies: [],
63
64
  constraints: [],
65
+ version: pipeline.recoveryCount + 1,
64
66
  });
65
67
 
66
68
  // 4. Run consensus
69
+ // v2.4.4: pass revisionDirective from sessionGuidance so reviewers see prior feedback
67
70
  const gateDef = gateEngine.getGateDefinition('CONSENSUS_ARCHITECTURE');
68
- const consensusPacket = await consensusRunner.runStructuredConsensus(planPacket, gateDef);
71
+ const revisionDirective = pipeline.recoveryCount > 0 && pipeline.sessionGuidance?.trim()
72
+ ? pipeline.sessionGuidance
73
+ : undefined;
74
+ const consensusPacket = await consensusRunner.runStructuredConsensus(planPacket, gateDef, {
75
+ revisionDirective,
76
+ });
69
77
 
70
78
  // 5. Store consensus artifact
71
79
  const consensusEntry = artifactManager.createAndStoreJson(
@@ -85,6 +93,7 @@ export async function runConsensusArchitecture(context: PhaseContext): Promise<P
85
93
  missingArtifacts: [],
86
94
  failedChecks: [],
87
95
  consensusScore: consensusPacket.consensus_result.score,
96
+ finalStatus: consensusPacket.final_status, // v2.4.3: propagate for gate engine
88
97
  timestamp: new Date().toISOString(),
89
98
  };
90
99
 
@@ -35,13 +35,14 @@ export async function runConsensusMasterPlan(context: PhaseContext): Promise<Pha
35
35
  artifacts.push(snapshotEntry);
36
36
  pipeline.latestRepoSnapshot = artifactManager.toArtifactRef(snapshotEntry);
37
37
 
38
- // 2. Find master plan artifact
39
- const masterPlanArtifact = pipeline.artifacts.find((a) => a.type === 'master_plan');
38
+ // 2. Find latest master plan artifact (v2.4.3: reverse to get latest revision, not stale v1)
39
+ const masterPlanArtifact = [...pipeline.artifacts].reverse().find((a) => a.type === 'master_plan');
40
40
  if (!masterPlanArtifact) {
41
41
  return failureResult('CONSENSUS_MASTER_PLAN', 'No master plan artifact found');
42
42
  }
43
43
 
44
44
  // 3. Build plan packet
45
+ // v2.4.2: version tracks plan revision count for recovery loop convergence
45
46
  const planPacket = buildPlanPacket({
46
47
  phase: 'CONSENSUS_MASTER_PLAN',
47
48
  submittedBy: 'DISPATCHER',
@@ -57,11 +58,16 @@ export async function runConsensusMasterPlan(context: PhaseContext): Promise<Pha
57
58
  ],
58
59
  dependencies: [],
59
60
  constraints: [],
61
+ version: pipeline.recoveryCount + 1,
60
62
  });
61
63
 
62
64
  // 4. Run structured consensus
65
+ // v2.4.2: pass revisionDirective from sessionGuidance so reviewers see prior feedback
63
66
  const gateDef = gateEngine.getGateDefinition('CONSENSUS_MASTER_PLAN');
64
- const consensusPacket = await consensusRunner.runStructuredConsensus(planPacket, gateDef);
67
+ const revisionDirective = pipeline.recoveryCount > 0 ? pipeline.sessionGuidance : undefined;
68
+ const consensusPacket = await consensusRunner.runStructuredConsensus(planPacket, gateDef, {
69
+ revisionDirective,
70
+ });
65
71
 
66
72
  // 5. Store consensus artifact
67
73
  const consensusEntry = artifactManager.createAndStoreJson(
@@ -81,6 +87,7 @@ export async function runConsensusMasterPlan(context: PhaseContext): Promise<Pha
81
87
  missingArtifacts: [],
82
88
  failedChecks: [],
83
89
  consensusScore: consensusPacket.consensus_result.score,
90
+ finalStatus: consensusPacket.final_status, // v2.4.3: propagate for gate engine
84
91
  timestamp: new Date().toISOString(),
85
92
  };
86
93
 
@@ -44,6 +44,7 @@ export async function runConsensusRolePlans(context: PhaseContext): Promise<Phas
44
44
  const masterPlanArtifact = pipeline.artifacts.find((a) => a.type === 'master_plan');
45
45
 
46
46
  // 3. Build plan packet referencing all role plans
47
+ // v2.4.4: version tracks plan revision count for recovery loop convergence
47
48
  const planPacket = buildPlanPacket({
48
49
  phase: 'CONSENSUS_ROLE_PLANS',
49
50
  submittedBy: 'DISPATCHER',
@@ -62,11 +63,18 @@ export async function runConsensusRolePlans(context: PhaseContext): Promise<Phas
62
63
  ],
63
64
  dependencies: [],
64
65
  constraints: [],
66
+ version: pipeline.recoveryCount + 1,
65
67
  });
66
68
 
67
69
  // 4. Run consensus
70
+ // v2.4.4: pass revisionDirective from sessionGuidance so reviewers see prior feedback
68
71
  const gateDef = gateEngine.getGateDefinition('CONSENSUS_ROLE_PLANS');
69
- const consensusPacket = await consensusRunner.runStructuredConsensus(planPacket, gateDef);
72
+ const revisionDirective = pipeline.recoveryCount > 0 && pipeline.sessionGuidance?.trim()
73
+ ? pipeline.sessionGuidance
74
+ : undefined;
75
+ const consensusPacket = await consensusRunner.runStructuredConsensus(planPacket, gateDef, {
76
+ revisionDirective,
77
+ });
70
78
 
71
79
  // 5. Store consensus artifact
72
80
  const consensusEntry = artifactManager.createAndStoreJson(
@@ -86,6 +94,7 @@ export async function runConsensusRolePlans(context: PhaseContext): Promise<Phas
86
94
  missingArtifacts: [],
87
95
  failedChecks: [],
88
96
  consensusScore: consensusPacket.consensus_result.score,
97
+ finalStatus: consensusPacket.final_status, // v2.4.3: propagate for gate engine
89
98
  timestamp: new Date().toISOString(),
90
99
  };
91
100
 
@@ -7,12 +7,12 @@ import type { PhaseContext, PhaseResult } from './phase-context.js';
7
7
  import { successResult, failureResult } from './phase-context.js';
8
8
 
9
9
  export async function runDone(context: PhaseContext): Promise<PhaseResult> {
10
- const { pipeline, artifactManager, skillLoader } = context;
10
+ const { pipeline, artifactManager, skillLoader, skillUsageRegistry } = context;
11
11
  const artifacts = [];
12
12
 
13
13
  try {
14
- // 1. Load release manager skill
15
- const rmSkill = skillLoader.loadSkill('RELEASE_MANAGER');
14
+ // 1. Load release manager skill with metadata
15
+ const { definition: rmSkill, meta: rmMeta } = skillLoader.loadSkillWithMeta('RELEASE_MANAGER');
16
16
 
17
17
  // 2. Generate release notes
18
18
  const { executePrompt } = await import('../../adapters/claude.js');
@@ -31,6 +31,9 @@ export async function runDone(context: PhaseContext): Promise<PhaseResult> {
31
31
  const releaseResult = await executePrompt(releasePrompt);
32
32
  const releaseResponse = releaseResult.response;
33
33
 
34
+ // Record skill usage — release manager skill injected into prompt
35
+ skillUsageRegistry.record('RELEASE_MANAGER', 'DONE', 'system_prompt', rmMeta.source, rmMeta.version);
36
+
34
37
  // 3. Create release notes artifact
35
38
  const releaseEntry = artifactManager.createAndStoreText(
36
39
  'release_notes',
@@ -55,9 +58,17 @@ export async function runDone(context: PhaseContext): Promise<PhaseResult> {
55
58
  );
56
59
  artifacts.push(rollbackEntry);
57
60
 
61
+ // 6. Store skill usage log artifact
62
+ const usageLogEntry = artifactManager.createAndStoreJson(
63
+ 'skill_usage_log',
64
+ pipeline.skillUsageEvents ?? [],
65
+ 'DONE',
66
+ );
67
+ artifacts.push(usageLogEntry);
68
+
58
69
  pipeline.artifacts.push(...artifacts);
59
70
 
60
- // 6. Final INDEX.md update
71
+ // 7. Final INDEX.md update
61
72
  artifactManager.updateIndex(pipeline.artifacts);
62
73
 
63
74
  return successResult('DONE', artifacts, 'Pipeline complete. Release artifacts created.');
@@ -2,12 +2,19 @@
2
2
  * INTAKE phase — normalize user prompt into structured Master Plan v1.
3
3
  * Reuses expandIdea() and createPlan() from workflow.
4
4
  * v1.1: Creates constitution artifact and stores hash.
5
+ * v1.2: Generates project-specific skills and constitution.
5
6
  */
6
7
 
8
+ import { join } from 'node:path';
9
+
7
10
  import type { PhaseContext, PhaseResult } from './phase-context.js';
8
11
  import { successResult, failureResult } from './phase-context.js';
9
12
  import { generateRepoSnapshot, createSnapshotArtifact } from '../repo-snapshot.js';
10
13
  import { createConstitutionArtifact, computeConstitutionHash } from '../constitution.js';
14
+ import { getActiveRoles, inferTechStack } from '../skills/role-map.js';
15
+ import { generateProjectSkills } from '../skills/generator.js';
16
+ import { generateConstitution } from '../skills/constitution-generator.js';
17
+ import type { OutputLanguage } from '../../types/project.js';
11
18
 
12
19
  export async function runIntake(context: PhaseContext): Promise<PhaseResult> {
13
20
  const { projectDir, pipeline, artifactManager } = context;
@@ -20,14 +27,7 @@ export async function runIntake(context: PhaseContext): Promise<PhaseResult> {
20
27
  artifacts.push(snapshotEntry);
21
28
  pipeline.latestRepoSnapshot = artifactManager.toArtifactRef(snapshotEntry);
22
29
 
23
- // 2. Create constitution artifact and store hash
24
- const constitutionEntry = createConstitutionArtifact(projectDir, artifactManager);
25
- if (constitutionEntry) {
26
- artifacts.push(constitutionEntry);
27
- }
28
- pipeline.constitutionHash = computeConstitutionHash(projectDir);
29
-
30
- // 3. Store additional_context artifact if session guidance provided
30
+ // 2. Store additional_context artifact if session guidance provided
31
31
  const guidance = pipeline.sessionGuidance ?? '';
32
32
  if (guidance) {
33
33
  const ctxEntry = artifactManager.createAndStoreText(
@@ -38,6 +38,9 @@ export async function runIntake(context: PhaseContext): Promise<PhaseResult> {
38
38
  artifacts.push(ctxEntry);
39
39
  }
40
40
 
41
+ // 3. Push pre-AI artifacts to pipeline state now (survives if AI calls fail below)
42
+ pipeline.artifacts.push(...artifacts);
43
+
41
44
  // 4. Expand idea using existing workflow
42
45
  const { expandIdea, createPlan } = await import('../../workflow/plan-mode.js');
43
46
  const expandedIdea = await expandIdea(
@@ -45,20 +48,70 @@ export async function runIntake(context: PhaseContext): Promise<PhaseResult> {
45
48
  context.state.language,
46
49
  );
47
50
 
48
- // 5. Create master plan — prepend guidance so planner sees constraints first
49
- const planInput = guidance
50
- ? `${guidance}\n\n---\n\n${expandedIdea}`
51
- : expandedIdea;
51
+ // 5. Determine active roles
52
+ const language = context.state.language as OutputLanguage;
53
+ pipeline.activeRoles = getActiveRoles(language);
54
+
55
+ // 6-8. Generate project-specific skills and constitution (non-fatal)
56
+ const skillsDir = join(projectDir, 'skills');
57
+ try {
58
+ const projectName = context.state.name ?? 'Project';
59
+
60
+ await generateProjectSkills(
61
+ {
62
+ language,
63
+ expandedSpec: expandedIdea,
64
+ snapshot,
65
+ sessionGuidance: guidance || undefined,
66
+ activeRoles: pipeline.activeRoles,
67
+ skillsDir,
68
+ projectName,
69
+ },
70
+ artifactManager,
71
+ );
72
+
73
+ const techStack = inferTechStack(language, snapshot, expandedIdea);
74
+ generateConstitution({
75
+ language,
76
+ projectName,
77
+ techStack,
78
+ expandedSpec: expandedIdea,
79
+ sessionGuidance: guidance || undefined,
80
+ skillsDir,
81
+ });
82
+
83
+ // Clear skill loader cache so it picks up new .md files
84
+ context.skillLoader.clearCache();
85
+ } catch {
86
+ // Skill/constitution generation is non-fatal — pipeline continues with defaults
87
+ }
88
+
89
+ // 9. Create constitution artifact and store hash (AFTER generation)
90
+ const constitutionEntry = createConstitutionArtifact(projectDir, artifactManager);
91
+ if (constitutionEntry) {
92
+ artifacts.push(constitutionEntry);
93
+ pipeline.artifacts.push(constitutionEntry);
94
+ }
95
+ pipeline.constitutionHash = computeConstitutionHash(projectDir);
96
+
97
+ // 10. Create master plan — prepend guidance so planner sees constraints first
98
+ // Detect revision directive and instruct plan to include "Addressed Reviewer Feedback" section
99
+ const isRevision = guidance.includes('--- REVISION DIRECTIVE ---');
100
+ const planInput = isRevision
101
+ ? `${guidance}\n\nIMPORTANT: Include a "## Addressed Reviewer Feedback" section mapping each Required Change to the concrete revision made.\n\n${expandedIdea}`
102
+ : guidance
103
+ ? `${guidance}\n\n---\n\n${expandedIdea}`
104
+ : expandedIdea;
52
105
  const plan = await createPlan(planInput, '', context.state.language);
53
106
 
54
- // 6. Store master plan as artifact
107
+ // 11. Store master plan as artifact
55
108
  const planEntry = artifactManager.createAndStoreText(
56
109
  'master_plan',
57
110
  plan,
58
111
  'INTAKE',
59
112
  );
60
113
  artifacts.push(planEntry);
61
- pipeline.artifacts.push(...artifacts);
114
+ pipeline.artifacts.push(planEntry);
62
115
 
63
116
  return successResult('INTAKE', artifacts, 'Master Plan v1 created');
64
117
  } catch (err) {
@@ -8,6 +8,7 @@ import type { GateEngine } from '../gate-engine.js';
8
8
  import type { SkillLoader } from '../skill-loader.js';
9
9
  import type { ConsensusRunner } from '../consensus/consensus-runner.js';
10
10
  import type { ProjectState } from '../../types/workflow.js';
11
+ import type { SkillUsageRegistry } from '../skills/usage-registry.js';
11
12
 
12
13
  // ─── PhaseContext ────────────────────────────────────────
13
14
 
@@ -19,6 +20,7 @@ export interface PhaseContext {
19
20
  artifactManager: ArtifactManager;
20
21
  gateEngine: GateEngine;
21
22
  consensusRunner: ConsensusRunner;
23
+ skillUsageRegistry: SkillUsageRegistry;
22
24
  }
23
25
 
24
26
  // ─── PhaseResult ─────────────────────────────────────────
@@ -39,7 +41,7 @@ export async function triggerJournalist(
39
41
  artifacts: ArtifactEntry[],
40
42
  context: PhaseContext,
41
43
  ): Promise<ArtifactEntry | null> {
42
- const skill = context.skillLoader.loadSkill('JOURNALIST');
44
+ const { definition: skill, meta } = context.skillLoader.loadSkillWithMeta('JOURNALIST');
43
45
 
44
46
  const traceContent = [
45
47
  `# Journalist Trace — ${phase}`,
@@ -55,6 +57,9 @@ export async function triggerJournalist(
55
57
  `${skill.systemPrompt.slice(0, 200)}...`,
56
58
  ].join('\n');
57
59
 
60
+ // Record skill usage — journalist skill injected into trace context
61
+ context.skillUsageRegistry.record('JOURNALIST', phase, 'other', meta.source, meta.version);
62
+
58
63
  const entry = context.artifactManager.createAndStoreText(
59
64
  'journalist_trace',
60
65
  traceContent,
@@ -4,10 +4,22 @@
4
4
  * v1.1: Adds start check and env check.
5
5
  */
6
6
 
7
+ import { join } from 'node:path';
8
+ import { existsSync } from 'node:fs';
9
+
7
10
  import type { PhaseContext, PhaseResult } from './phase-context.js';
8
11
  import { successResult, failureResult, triggerJournalist } from './phase-context.js';
9
12
  import { resolveCommands } from '../command-resolver.js';
10
- import { runAllChecks, runPlaceholderScan, runStartCheck, runEnvCheck, storeCheckResults } from '../check-runner.js';
13
+ import {
14
+ runAllChecks,
15
+ runPlaceholderScan,
16
+ runStartCheck,
17
+ runEnvCheck,
18
+ runCheck,
19
+ storeCheckResults,
20
+ shouldSkipInstall,
21
+ writeInstallMarker,
22
+ } from '../check-runner.js';
11
23
  import { generateRepoSnapshot } from '../repo-snapshot.js';
12
24
 
13
25
  export async function runProductionGate(context: PhaseContext): Promise<PhaseResult> {
@@ -20,6 +32,25 @@ export async function runProductionGate(context: PhaseContext): Promise<PhaseRes
20
32
  const commands = resolveCommands(snapshot);
21
33
  pipeline.resolvedCommands = commands;
22
34
 
35
+ // 1.5. Install dependencies if needed (skips if unchanged since QA_VALIDATION)
36
+ if (commands.install) {
37
+ const installCwd = commands.install_cwd
38
+ ? join(projectDir, commands.install_cwd)
39
+ : projectDir;
40
+ const skipInstall = shouldSkipInstall(projectDir, snapshot);
41
+ if (!skipInstall) {
42
+ const installResult = await runCheck('install', commands.install, installCwd);
43
+ if (installResult.status === 'fail') {
44
+ const stored = storeCheckResults([installResult], artifactManager, 'PRODUCTION_GATE');
45
+ artifacts.push(...stored);
46
+ pipeline.artifacts.push(...artifacts);
47
+ pipeline.gateChecks['PRODUCTION_GATE'] = [installResult];
48
+ return failureResult('PRODUCTION_GATE', 'Dependency installation failed', installResult.stderr_summary ?? '');
49
+ }
50
+ writeInstallMarker(projectDir, snapshot);
51
+ }
52
+ }
53
+
23
54
  // 2. Run all checks
24
55
  const checkResults = await runAllChecks(commands, projectDir);
25
56
 
@@ -52,7 +83,14 @@ export async function runProductionGate(context: PhaseContext): Promise<PhaseRes
52
83
  );
53
84
  const hasPlaceholders = placeholderResult.status === 'fail';
54
85
  const auditPassed = pipeline.artifacts.some((a) => a.type === 'audit_report');
55
- const passed = failedChecks.length === 0 && auditPassed;
86
+
87
+ // Detect website projects — placeholder_scan blocks for these
88
+ const isWebsiteProject =
89
+ existsSync(join(projectDir, 'next.config.mjs')) ||
90
+ existsSync(join(projectDir, 'next.config.js')) ||
91
+ existsSync(join(projectDir, 'src', 'app', 'layout.tsx'));
92
+ const placeholderBlocking = hasPlaceholders && isWebsiteProject;
93
+ const passed = failedChecks.length === 0 && auditPassed && !placeholderBlocking;
56
94
 
57
95
  // 9. Create production readiness report
58
96
  const report = [
@@ -77,7 +115,7 @@ export async function runProductionGate(context: PhaseContext): Promise<PhaseRes
77
115
  `- Env: ${findCheckStatus(checkResults, 'env_check')}`,
78
116
  `- Start: ${findCheckStatus(checkResults, 'start')}`,
79
117
  `- Audit: ${auditPassed ? 'PASS' : 'MISSING'}`,
80
- `- Placeholders: ${hasPlaceholders ? 'WARNING' : 'CLEAN'}`,
118
+ `- Placeholders: ${hasPlaceholders ? (placeholderBlocking ? 'FAIL (blocking for website)' : 'WARNING') : 'CLEAN'}`,
81
119
  ].join('\n');
82
120
 
83
121
  const reportEntry = artifactManager.createAndStoreText(
@@ -3,23 +3,60 @@
3
3
  * Runs tests via checkRunner. Creates qa_validation artifact.
4
4
  */
5
5
 
6
+ import { join } from 'node:path';
7
+
6
8
  import type { PhaseContext, PhaseResult } from './phase-context.js';
7
9
  import { successResult, failureResult } from './phase-context.js';
8
10
  import { resolveCommands } from '../command-resolver.js';
9
- import { runCheck, storeCheckResults } from '../check-runner.js';
11
+ import {
12
+ runCheck,
13
+ storeCheckResults,
14
+ shouldSkipInstall,
15
+ writeInstallMarker,
16
+ invalidateInstallMarker,
17
+ } from '../check-runner.js';
10
18
  import { generateRepoSnapshot } from '../repo-snapshot.js';
11
19
 
12
20
  export async function runQaValidation(context: PhaseContext): Promise<PhaseResult> {
13
- const { pipeline, artifactManager, projectDir } = context;
21
+ const { pipeline, artifactManager, skillLoader, skillUsageRegistry, projectDir } = context;
14
22
  const artifacts = [];
15
23
 
16
24
  try {
17
- // 1. Resolve test command
25
+ // 1. Load QA_TESTER skill and record usage
26
+ const { definition: _qaSkill, meta: qaMeta } = skillLoader.loadSkillWithMeta('QA_TESTER');
27
+ skillUsageRegistry.record('QA_TESTER', 'QA_VALIDATION', 'system_prompt', qaMeta.source, qaMeta.version);
28
+
29
+ // 2. Resolve test command
18
30
  const snapshot = await generateRepoSnapshot(projectDir);
19
31
  const commands = resolveCommands(snapshot);
20
32
  pipeline.resolvedCommands = commands;
21
33
 
22
- // 2. Run test command
34
+ // 2.5. Install dependencies if needed
35
+ if (commands.install) {
36
+ const installCwd = commands.install_cwd
37
+ ? join(projectDir, commands.install_cwd)
38
+ : projectDir;
39
+ const skipInstall = shouldSkipInstall(projectDir, snapshot);
40
+ if (!skipInstall) {
41
+ const installResult = await runCheck('install', commands.install, installCwd);
42
+ const stored = storeCheckResults([installResult], artifactManager, 'QA_VALIDATION');
43
+ artifacts.push(...stored);
44
+
45
+ if (!pipeline.gateChecks['QA_VALIDATION']) {
46
+ pipeline.gateChecks['QA_VALIDATION'] = [];
47
+ }
48
+ pipeline.gateChecks['QA_VALIDATION'].push(installResult);
49
+
50
+ if (installResult.status === 'fail') {
51
+ pipeline.artifacts.push(...artifacts);
52
+ return failureResult('QA_VALIDATION', 'Dependency installation failed', installResult.stderr_summary ?? '');
53
+ }
54
+
55
+ writeInstallMarker(projectDir, snapshot);
56
+ }
57
+ }
58
+
59
+ // 3. Run test command
23
60
  if (commands.test) {
24
61
  const testResult = await runCheck('test', commands.test, projectDir);
25
62
  const stored = storeCheckResults([testResult], artifactManager, 'QA_VALIDATION');
@@ -30,9 +67,18 @@ export async function runQaValidation(context: PhaseContext): Promise<PhaseResul
30
67
  pipeline.gateChecks['QA_VALIDATION'] = [];
31
68
  }
32
69
  pipeline.gateChecks['QA_VALIDATION'].push(testResult);
70
+
71
+ // Invalidate install marker on missing-module errors
72
+ if (testResult.status === 'fail' && testResult.stderr_summary) {
73
+ const missingModule = /Cannot find module|ModuleNotFoundError|Failed to resolve import/
74
+ .test(testResult.stderr_summary);
75
+ if (missingModule) {
76
+ invalidateInstallMarker(projectDir);
77
+ }
78
+ }
33
79
  }
34
80
 
35
- // 3. Create QA validation summary artifact
81
+ // 4. Create QA validation summary artifact
36
82
  const qaReport = [
37
83
  '# QA Validation Report',
38
84
  '',