popeye-cli 1.10.0 → 2.1.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 (326) hide show
  1. package/CHANGELOG.md +114 -0
  2. package/CONTRIBUTING.md +38 -3
  3. package/README.md +104 -18
  4. package/dist/adapters/gemini.js +3 -3
  5. package/dist/adapters/openai.js +2 -2
  6. package/dist/adapters/openai.js.map +1 -1
  7. package/dist/auth/gemini.js +1 -1
  8. package/dist/cli/commands/create.d.ts.map +1 -1
  9. package/dist/cli/commands/create.js +11 -5
  10. package/dist/cli/commands/create.js.map +1 -1
  11. package/dist/cli/commands/resume.d.ts.map +1 -1
  12. package/dist/cli/commands/resume.js +9 -1
  13. package/dist/cli/commands/resume.js.map +1 -1
  14. package/dist/cli/interactive.d.ts.map +1 -1
  15. package/dist/cli/interactive.js +29 -3
  16. package/dist/cli/interactive.js.map +1 -1
  17. package/dist/config/defaults.d.ts.map +1 -1
  18. package/dist/config/defaults.js +7 -2
  19. package/dist/config/defaults.js.map +1 -1
  20. package/dist/config/index.d.ts +1 -7
  21. package/dist/config/index.d.ts.map +1 -1
  22. package/dist/config/popeye-md.d.ts +32 -0
  23. package/dist/config/popeye-md.d.ts.map +1 -0
  24. package/dist/config/popeye-md.js +111 -0
  25. package/dist/config/popeye-md.js.map +1 -0
  26. package/dist/config/schema.d.ts +3 -21
  27. package/dist/config/schema.d.ts.map +1 -1
  28. package/dist/config/schema.js +21 -8
  29. package/dist/config/schema.js.map +1 -1
  30. package/dist/pipeline/artifact-manager.d.ts +47 -0
  31. package/dist/pipeline/artifact-manager.d.ts.map +1 -0
  32. package/dist/pipeline/artifact-manager.js +251 -0
  33. package/dist/pipeline/artifact-manager.js.map +1 -0
  34. package/dist/pipeline/artifact-validators.d.ts +29 -0
  35. package/dist/pipeline/artifact-validators.d.ts.map +1 -0
  36. package/dist/pipeline/artifact-validators.js +173 -0
  37. package/dist/pipeline/artifact-validators.js.map +1 -0
  38. package/dist/pipeline/bridges/review-bridge.d.ts +70 -0
  39. package/dist/pipeline/bridges/review-bridge.d.ts.map +1 -0
  40. package/dist/pipeline/bridges/review-bridge.js +266 -0
  41. package/dist/pipeline/bridges/review-bridge.js.map +1 -0
  42. package/dist/pipeline/change-request.d.ts +47 -0
  43. package/dist/pipeline/change-request.d.ts.map +1 -0
  44. package/dist/pipeline/change-request.js +91 -0
  45. package/dist/pipeline/change-request.js.map +1 -0
  46. package/dist/pipeline/check-runner.d.ts +47 -0
  47. package/dist/pipeline/check-runner.d.ts.map +1 -0
  48. package/dist/pipeline/check-runner.js +417 -0
  49. package/dist/pipeline/check-runner.js.map +1 -0
  50. package/dist/pipeline/command-resolver.d.ts +9 -0
  51. package/dist/pipeline/command-resolver.d.ts.map +1 -0
  52. package/dist/pipeline/command-resolver.js +140 -0
  53. package/dist/pipeline/command-resolver.js.map +1 -0
  54. package/dist/pipeline/consensus/consensus-runner.d.ts +44 -0
  55. package/dist/pipeline/consensus/consensus-runner.d.ts.map +1 -0
  56. package/dist/pipeline/consensus/consensus-runner.js +212 -0
  57. package/dist/pipeline/consensus/consensus-runner.js.map +1 -0
  58. package/dist/pipeline/constitution.d.ts +45 -0
  59. package/dist/pipeline/constitution.d.ts.map +1 -0
  60. package/dist/pipeline/constitution.js +82 -0
  61. package/dist/pipeline/constitution.js.map +1 -0
  62. package/dist/pipeline/gate-engine.d.ts +55 -0
  63. package/dist/pipeline/gate-engine.d.ts.map +1 -0
  64. package/dist/pipeline/gate-engine.js +270 -0
  65. package/dist/pipeline/gate-engine.js.map +1 -0
  66. package/dist/pipeline/index.d.ts +26 -0
  67. package/dist/pipeline/index.d.ts.map +1 -0
  68. package/dist/pipeline/index.js +35 -0
  69. package/dist/pipeline/index.js.map +1 -0
  70. package/dist/pipeline/migration.d.ts +15 -0
  71. package/dist/pipeline/migration.d.ts.map +1 -0
  72. package/dist/pipeline/migration.js +76 -0
  73. package/dist/pipeline/migration.js.map +1 -0
  74. package/dist/pipeline/orchestrator.d.ts +30 -0
  75. package/dist/pipeline/orchestrator.d.ts.map +1 -0
  76. package/dist/pipeline/orchestrator.js +242 -0
  77. package/dist/pipeline/orchestrator.js.map +1 -0
  78. package/dist/pipeline/packets/audit-report-builder.d.ts +11 -0
  79. package/dist/pipeline/packets/audit-report-builder.d.ts.map +1 -0
  80. package/dist/pipeline/packets/audit-report-builder.js +32 -0
  81. package/dist/pipeline/packets/audit-report-builder.js.map +1 -0
  82. package/dist/pipeline/packets/consensus-packet-builder.d.ts +35 -0
  83. package/dist/pipeline/packets/consensus-packet-builder.d.ts.map +1 -0
  84. package/dist/pipeline/packets/consensus-packet-builder.js +80 -0
  85. package/dist/pipeline/packets/consensus-packet-builder.js.map +1 -0
  86. package/dist/pipeline/packets/index.d.ts +12 -0
  87. package/dist/pipeline/packets/index.d.ts.map +1 -0
  88. package/dist/pipeline/packets/index.js +8 -0
  89. package/dist/pipeline/packets/index.js.map +1 -0
  90. package/dist/pipeline/packets/plan-packet-builder.d.ts +21 -0
  91. package/dist/pipeline/packets/plan-packet-builder.d.ts.map +1 -0
  92. package/dist/pipeline/packets/plan-packet-builder.js +27 -0
  93. package/dist/pipeline/packets/plan-packet-builder.js.map +1 -0
  94. package/dist/pipeline/packets/rca-packet-builder.d.ts +19 -0
  95. package/dist/pipeline/packets/rca-packet-builder.d.ts.map +1 -0
  96. package/dist/pipeline/packets/rca-packet-builder.js +22 -0
  97. package/dist/pipeline/packets/rca-packet-builder.js.map +1 -0
  98. package/dist/pipeline/phases/architecture.d.ts +7 -0
  99. package/dist/pipeline/phases/architecture.d.ts.map +1 -0
  100. package/dist/pipeline/phases/architecture.js +60 -0
  101. package/dist/pipeline/phases/architecture.js.map +1 -0
  102. package/dist/pipeline/phases/audit.d.ts +8 -0
  103. package/dist/pipeline/phases/audit.d.ts.map +1 -0
  104. package/dist/pipeline/phases/audit.js +144 -0
  105. package/dist/pipeline/phases/audit.js.map +1 -0
  106. package/dist/pipeline/phases/consensus-architecture.d.ts +7 -0
  107. package/dist/pipeline/phases/consensus-architecture.d.ts.map +1 -0
  108. package/dist/pipeline/phases/consensus-architecture.js +84 -0
  109. package/dist/pipeline/phases/consensus-architecture.js.map +1 -0
  110. package/dist/pipeline/phases/consensus-master-plan.d.ts +7 -0
  111. package/dist/pipeline/phases/consensus-master-plan.d.ts.map +1 -0
  112. package/dist/pipeline/phases/consensus-master-plan.js +81 -0
  113. package/dist/pipeline/phases/consensus-master-plan.js.map +1 -0
  114. package/dist/pipeline/phases/consensus-role-plans.d.ts +7 -0
  115. package/dist/pipeline/phases/consensus-role-plans.d.ts.map +1 -0
  116. package/dist/pipeline/phases/consensus-role-plans.js +85 -0
  117. package/dist/pipeline/phases/consensus-role-plans.js.map +1 -0
  118. package/dist/pipeline/phases/done.d.ts +7 -0
  119. package/dist/pipeline/phases/done.d.ts.map +1 -0
  120. package/dist/pipeline/phases/done.js +45 -0
  121. package/dist/pipeline/phases/done.js.map +1 -0
  122. package/dist/pipeline/phases/implementation.d.ts +8 -0
  123. package/dist/pipeline/phases/implementation.d.ts.map +1 -0
  124. package/dist/pipeline/phases/implementation.js +45 -0
  125. package/dist/pipeline/phases/implementation.js.map +1 -0
  126. package/dist/pipeline/phases/index.d.ts +20 -0
  127. package/dist/pipeline/phases/index.d.ts.map +1 -0
  128. package/dist/pipeline/phases/index.js +19 -0
  129. package/dist/pipeline/phases/index.js.map +1 -0
  130. package/dist/pipeline/phases/intake.d.ts +8 -0
  131. package/dist/pipeline/phases/intake.d.ts.map +1 -0
  132. package/dist/pipeline/phases/intake.js +49 -0
  133. package/dist/pipeline/phases/intake.js.map +1 -0
  134. package/dist/pipeline/phases/phase-context.d.ts +30 -0
  135. package/dist/pipeline/phases/phase-context.d.ts.map +1 -0
  136. package/dist/pipeline/phases/phase-context.js +33 -0
  137. package/dist/pipeline/phases/phase-context.js.map +1 -0
  138. package/dist/pipeline/phases/production-gate.d.ts +8 -0
  139. package/dist/pipeline/phases/production-gate.d.ts.map +1 -0
  140. package/dist/pipeline/phases/production-gate.js +84 -0
  141. package/dist/pipeline/phases/production-gate.js.map +1 -0
  142. package/dist/pipeline/phases/qa-validation.d.ts +7 -0
  143. package/dist/pipeline/phases/qa-validation.d.ts.map +1 -0
  144. package/dist/pipeline/phases/qa-validation.js +50 -0
  145. package/dist/pipeline/phases/qa-validation.js.map +1 -0
  146. package/dist/pipeline/phases/recovery-loop.d.ts +7 -0
  147. package/dist/pipeline/phases/recovery-loop.d.ts.map +1 -0
  148. package/dist/pipeline/phases/recovery-loop.js +93 -0
  149. package/dist/pipeline/phases/recovery-loop.js.map +1 -0
  150. package/dist/pipeline/phases/review.d.ts +8 -0
  151. package/dist/pipeline/phases/review.d.ts.map +1 -0
  152. package/dist/pipeline/phases/review.js +127 -0
  153. package/dist/pipeline/phases/review.js.map +1 -0
  154. package/dist/pipeline/phases/role-planning.d.ts +7 -0
  155. package/dist/pipeline/phases/role-planning.d.ts.map +1 -0
  156. package/dist/pipeline/phases/role-planning.js +75 -0
  157. package/dist/pipeline/phases/role-planning.js.map +1 -0
  158. package/dist/pipeline/phases/stuck.d.ts +7 -0
  159. package/dist/pipeline/phases/stuck.d.ts.map +1 -0
  160. package/dist/pipeline/phases/stuck.js +51 -0
  161. package/dist/pipeline/phases/stuck.js.map +1 -0
  162. package/dist/pipeline/repo-snapshot.d.ts +24 -0
  163. package/dist/pipeline/repo-snapshot.d.ts.map +1 -0
  164. package/dist/pipeline/repo-snapshot.js +343 -0
  165. package/dist/pipeline/repo-snapshot.js.map +1 -0
  166. package/dist/pipeline/role-execution-adapter.d.ts +59 -0
  167. package/dist/pipeline/role-execution-adapter.d.ts.map +1 -0
  168. package/dist/pipeline/role-execution-adapter.js +159 -0
  169. package/dist/pipeline/role-execution-adapter.js.map +1 -0
  170. package/dist/pipeline/skill-loader.d.ts +34 -0
  171. package/dist/pipeline/skill-loader.d.ts.map +1 -0
  172. package/dist/pipeline/skill-loader.js +156 -0
  173. package/dist/pipeline/skill-loader.js.map +1 -0
  174. package/dist/pipeline/skills/defaults.d.ts +16 -0
  175. package/dist/pipeline/skills/defaults.d.ts.map +1 -0
  176. package/dist/pipeline/skills/defaults.js +189 -0
  177. package/dist/pipeline/skills/defaults.js.map +1 -0
  178. package/dist/pipeline/type-defs/artifacts.d.ts +207 -0
  179. package/dist/pipeline/type-defs/artifacts.d.ts.map +1 -0
  180. package/dist/pipeline/type-defs/artifacts.js +67 -0
  181. package/dist/pipeline/type-defs/artifacts.js.map +1 -0
  182. package/dist/pipeline/type-defs/audit.d.ts +259 -0
  183. package/dist/pipeline/type-defs/audit.d.ts.map +1 -0
  184. package/dist/pipeline/type-defs/audit.js +54 -0
  185. package/dist/pipeline/type-defs/audit.js.map +1 -0
  186. package/dist/pipeline/type-defs/checks.d.ts +82 -0
  187. package/dist/pipeline/type-defs/checks.d.ts.map +1 -0
  188. package/dist/pipeline/type-defs/checks.js +38 -0
  189. package/dist/pipeline/type-defs/checks.js.map +1 -0
  190. package/dist/pipeline/type-defs/enums.d.ts +43 -0
  191. package/dist/pipeline/type-defs/enums.d.ts.map +1 -0
  192. package/dist/pipeline/type-defs/enums.js +55 -0
  193. package/dist/pipeline/type-defs/enums.js.map +1 -0
  194. package/dist/pipeline/type-defs/index.d.ts +12 -0
  195. package/dist/pipeline/type-defs/index.d.ts.map +1 -0
  196. package/dist/pipeline/type-defs/index.js +12 -0
  197. package/dist/pipeline/type-defs/index.js.map +1 -0
  198. package/dist/pipeline/type-defs/packets.d.ts +821 -0
  199. package/dist/pipeline/type-defs/packets.d.ts.map +1 -0
  200. package/dist/pipeline/type-defs/packets.js +109 -0
  201. package/dist/pipeline/type-defs/packets.js.map +1 -0
  202. package/dist/pipeline/type-defs/snapshot.d.ts +52 -0
  203. package/dist/pipeline/type-defs/snapshot.d.ts.map +1 -0
  204. package/dist/pipeline/type-defs/snapshot.js +35 -0
  205. package/dist/pipeline/type-defs/snapshot.js.map +1 -0
  206. package/dist/pipeline/type-defs/state.d.ts +455 -0
  207. package/dist/pipeline/type-defs/state.d.ts.map +1 -0
  208. package/dist/pipeline/type-defs/state.js +90 -0
  209. package/dist/pipeline/type-defs/state.js.map +1 -0
  210. package/dist/pipeline/types.d.ts +16 -0
  211. package/dist/pipeline/types.d.ts.map +1 -0
  212. package/dist/pipeline/types.js +16 -0
  213. package/dist/pipeline/types.js.map +1 -0
  214. package/dist/types/audit.d.ts +6 -6
  215. package/dist/types/consensus.d.ts +5 -1
  216. package/dist/types/consensus.d.ts.map +1 -1
  217. package/dist/types/consensus.js +15 -4
  218. package/dist/types/consensus.js.map +1 -1
  219. package/dist/types/index.d.ts +1 -1
  220. package/dist/types/index.d.ts.map +1 -1
  221. package/dist/types/index.js +1 -1
  222. package/dist/types/index.js.map +1 -1
  223. package/dist/types/project.d.ts +1 -1
  224. package/dist/types/project.d.ts.map +1 -1
  225. package/dist/types/project.js +39 -10
  226. package/dist/types/project.js.map +1 -1
  227. package/dist/types/workflow.d.ts +1 -7
  228. package/dist/types/workflow.d.ts.map +1 -1
  229. package/dist/types/workflow.js +1 -1
  230. package/dist/types/workflow.js.map +1 -1
  231. package/dist/upgrade/handlers.js +5 -5
  232. package/dist/upgrade/handlers.js.map +1 -1
  233. package/dist/workflow/index.d.ts.map +1 -1
  234. package/dist/workflow/index.js +52 -0
  235. package/dist/workflow/index.js.map +1 -1
  236. package/dist/workflow/website-strategy.js +1 -1
  237. package/dist/workflow/website-strategy.js.map +1 -1
  238. package/package.json +1 -1
  239. package/skills/PHASE_GATE_ENGINE_SPEC.md +113 -20
  240. package/skills/POPEYE_FULL_AUTONOMY_PIPELINE.md +66 -13
  241. package/src/adapters/gemini.ts +3 -3
  242. package/src/adapters/openai.ts +2 -2
  243. package/src/auth/gemini.ts +1 -1
  244. package/src/cli/commands/create.ts +12 -6
  245. package/src/cli/commands/resume.ts +9 -1
  246. package/src/cli/interactive.ts +32 -3
  247. package/src/config/defaults.ts +7 -2
  248. package/src/config/popeye-md.ts +139 -0
  249. package/src/config/schema.ts +21 -8
  250. package/src/pipeline/artifact-manager.ts +339 -0
  251. package/src/pipeline/artifact-validators.ts +224 -0
  252. package/src/pipeline/bridges/review-bridge.ts +371 -0
  253. package/src/pipeline/change-request.ts +119 -0
  254. package/src/pipeline/check-runner.ts +504 -0
  255. package/src/pipeline/command-resolver.ts +168 -0
  256. package/src/pipeline/consensus/consensus-runner.ts +317 -0
  257. package/src/pipeline/constitution.ts +109 -0
  258. package/src/pipeline/gate-engine.ts +347 -0
  259. package/src/pipeline/index.ts +82 -0
  260. package/src/pipeline/migration.ts +91 -0
  261. package/src/pipeline/orchestrator.ts +322 -0
  262. package/src/pipeline/packets/audit-report-builder.ts +47 -0
  263. package/src/pipeline/packets/consensus-packet-builder.ts +112 -0
  264. package/src/pipeline/packets/index.ts +15 -0
  265. package/src/pipeline/packets/plan-packet-builder.ts +52 -0
  266. package/src/pipeline/packets/rca-packet-builder.ts +38 -0
  267. package/src/pipeline/phases/architecture.ts +73 -0
  268. package/src/pipeline/phases/audit.ts +193 -0
  269. package/src/pipeline/phases/consensus-architecture.ts +104 -0
  270. package/src/pipeline/phases/consensus-master-plan.ts +100 -0
  271. package/src/pipeline/phases/consensus-role-plans.ts +105 -0
  272. package/src/pipeline/phases/done.ts +68 -0
  273. package/src/pipeline/phases/implementation.ts +52 -0
  274. package/src/pipeline/phases/index.ts +21 -0
  275. package/src/pipeline/phases/intake.ts +68 -0
  276. package/src/pipeline/phases/phase-context.ts +86 -0
  277. package/src/pipeline/phases/production-gate.ts +113 -0
  278. package/src/pipeline/phases/qa-validation.ts +63 -0
  279. package/src/pipeline/phases/recovery-loop.ts +120 -0
  280. package/src/pipeline/phases/review.ts +149 -0
  281. package/src/pipeline/phases/role-planning.ts +92 -0
  282. package/src/pipeline/phases/stuck.ts +62 -0
  283. package/src/pipeline/repo-snapshot.ts +395 -0
  284. package/src/pipeline/role-execution-adapter.ts +238 -0
  285. package/src/pipeline/skill-loader.ts +192 -0
  286. package/src/pipeline/skills/defaults.ts +215 -0
  287. package/src/pipeline/type-defs/artifacts.ts +82 -0
  288. package/src/pipeline/type-defs/audit.ts +67 -0
  289. package/src/pipeline/type-defs/checks.ts +47 -0
  290. package/src/pipeline/type-defs/enums.ts +62 -0
  291. package/src/pipeline/type-defs/index.ts +12 -0
  292. package/src/pipeline/type-defs/packets.ts +131 -0
  293. package/src/pipeline/type-defs/snapshot.ts +55 -0
  294. package/src/pipeline/type-defs/state.ts +167 -0
  295. package/src/pipeline/types.ts +16 -0
  296. package/src/types/consensus.ts +16 -4
  297. package/src/types/index.ts +1 -0
  298. package/src/types/project.ts +39 -10
  299. package/src/types/workflow.ts +1 -1
  300. package/src/upgrade/handlers.ts +5 -5
  301. package/src/workflow/index.ts +52 -0
  302. package/src/workflow/website-strategy.ts +1 -1
  303. package/tests/cli/model-command.test.ts +19 -9
  304. package/tests/config/config.test.ts +3 -3
  305. package/tests/config/popeye-md.test.ts +168 -0
  306. package/tests/pipeline/artifact-manager.test.ts +183 -0
  307. package/tests/pipeline/artifact-validators.test.ts +207 -0
  308. package/tests/pipeline/bridges/review-bridge.test.ts +243 -0
  309. package/tests/pipeline/change-request.test.ts +180 -0
  310. package/tests/pipeline/check-runner.test.ts +157 -0
  311. package/tests/pipeline/command-resolver.test.ts +159 -0
  312. package/tests/pipeline/consensus-runner.test.ts +206 -0
  313. package/tests/pipeline/consensus-scoring.test.ts +163 -0
  314. package/tests/pipeline/constitution.test.ts +122 -0
  315. package/tests/pipeline/gate-engine.test.ts +195 -0
  316. package/tests/pipeline/migration.test.ts +133 -0
  317. package/tests/pipeline/orchestrator.test.ts +614 -0
  318. package/tests/pipeline/packets/builders.test.ts +347 -0
  319. package/tests/pipeline/repo-snapshot.test.ts +189 -0
  320. package/tests/pipeline/role-execution-adapter.test.ts +299 -0
  321. package/tests/pipeline/session-guidance.test.ts +205 -0
  322. package/tests/pipeline/skill-loader.test.ts +186 -0
  323. package/tests/pipeline/start-env-checks.test.ts +123 -0
  324. package/tests/pipeline/types.test.ts +156 -0
  325. package/tests/types/consensus.test.ts +1 -1
  326. package/tests/workflow/pipeline-bootstrap.test.ts +162 -0
@@ -0,0 +1,68 @@
1
+ /**
2
+ * INTAKE phase — normalize user prompt into structured Master Plan v1.
3
+ * Reuses expandIdea() and createPlan() from workflow.
4
+ * v1.1: Creates constitution artifact and stores hash.
5
+ */
6
+
7
+ import type { PhaseContext, PhaseResult } from './phase-context.js';
8
+ import { successResult, failureResult } from './phase-context.js';
9
+ import { generateRepoSnapshot, createSnapshotArtifact } from '../repo-snapshot.js';
10
+ import { createConstitutionArtifact, computeConstitutionHash } from '../constitution.js';
11
+
12
+ export async function runIntake(context: PhaseContext): Promise<PhaseResult> {
13
+ const { projectDir, pipeline, artifactManager } = context;
14
+ const artifacts = [];
15
+
16
+ try {
17
+ // 1. Generate repo snapshot
18
+ const snapshot = await generateRepoSnapshot(projectDir);
19
+ const snapshotEntry = createSnapshotArtifact(snapshot, artifactManager, 'INTAKE');
20
+ artifacts.push(snapshotEntry);
21
+ pipeline.latestRepoSnapshot = artifactManager.toArtifactRef(snapshotEntry);
22
+
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
31
+ const guidance = pipeline.sessionGuidance ?? '';
32
+ if (guidance) {
33
+ const ctxEntry = artifactManager.createAndStoreText(
34
+ 'additional_context',
35
+ guidance,
36
+ 'INTAKE',
37
+ );
38
+ artifacts.push(ctxEntry);
39
+ }
40
+
41
+ // 4. Expand idea using existing workflow
42
+ const { expandIdea, createPlan } = await import('../../workflow/plan-mode.js');
43
+ const expandedIdea = await expandIdea(
44
+ context.state.specification ?? context.state.idea ?? '',
45
+ context.state.language,
46
+ );
47
+
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;
52
+ const plan = await createPlan(planInput, '', context.state.language);
53
+
54
+ // 6. Store master plan as artifact
55
+ const planEntry = artifactManager.createAndStoreText(
56
+ 'master_plan',
57
+ plan,
58
+ 'INTAKE',
59
+ );
60
+ artifacts.push(planEntry);
61
+ pipeline.artifacts.push(...artifacts);
62
+
63
+ return successResult('INTAKE', artifacts, 'Master Plan v1 created');
64
+ } catch (err) {
65
+ const message = err instanceof Error ? err.message : 'Unknown error during intake';
66
+ return failureResult('INTAKE', 'Failed to create master plan', message);
67
+ }
68
+ }
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Shared PhaseContext type and helpers for all phase implementations.
3
+ */
4
+
5
+ import type { PipelinePhase, PipelineState, ArtifactEntry } from '../types.js';
6
+ import type { ArtifactManager } from '../artifact-manager.js';
7
+ import type { GateEngine } from '../gate-engine.js';
8
+ import type { SkillLoader } from '../skill-loader.js';
9
+ import type { ConsensusRunner } from '../consensus/consensus-runner.js';
10
+ import type { ProjectState } from '../../types/workflow.js';
11
+
12
+ // ─── PhaseContext ────────────────────────────────────────
13
+
14
+ export interface PhaseContext {
15
+ state: ProjectState;
16
+ pipeline: PipelineState;
17
+ projectDir: string;
18
+ skillLoader: SkillLoader;
19
+ artifactManager: ArtifactManager;
20
+ gateEngine: GateEngine;
21
+ consensusRunner: ConsensusRunner;
22
+ }
23
+
24
+ // ─── PhaseResult ─────────────────────────────────────────
25
+
26
+ export interface PhaseResult {
27
+ phase: PipelinePhase;
28
+ success: boolean;
29
+ artifacts: ArtifactEntry[];
30
+ message: string;
31
+ error?: string;
32
+ }
33
+
34
+ // ─── Journalist Helper (P1-F) ────────────────────────────
35
+
36
+ /** Trigger journalist after consensus/audit/production phases */
37
+ export async function triggerJournalist(
38
+ phase: PipelinePhase,
39
+ artifacts: ArtifactEntry[],
40
+ context: PhaseContext,
41
+ ): Promise<ArtifactEntry | null> {
42
+ const skill = context.skillLoader.loadSkill('JOURNALIST');
43
+
44
+ const traceContent = [
45
+ `# Journalist Trace — ${phase}`,
46
+ ``,
47
+ `**Timestamp:** ${new Date().toISOString()}`,
48
+ `**Phase:** ${phase}`,
49
+ ``,
50
+ `## Artifacts Recorded`,
51
+ ``,
52
+ ...artifacts.map((a) => `- [${a.type}] v${a.version}: ${a.path}`),
53
+ ``,
54
+ `## Skill: ${skill.role}`,
55
+ `${skill.systemPrompt.slice(0, 200)}...`,
56
+ ].join('\n');
57
+
58
+ const entry = context.artifactManager.createAndStoreText(
59
+ 'journalist_trace',
60
+ traceContent,
61
+ phase,
62
+ );
63
+
64
+ // Update INDEX.md with all current artifacts
65
+ context.artifactManager.updateIndex(context.pipeline.artifacts);
66
+
67
+ return entry;
68
+ }
69
+
70
+ // ─── Phase Result Helpers ────────────────────────────────
71
+
72
+ export function successResult(
73
+ phase: PipelinePhase,
74
+ artifacts: ArtifactEntry[],
75
+ message: string,
76
+ ): PhaseResult {
77
+ return { phase, success: true, artifacts, message };
78
+ }
79
+
80
+ export function failureResult(
81
+ phase: PipelinePhase,
82
+ message: string,
83
+ error?: string,
84
+ ): PhaseResult {
85
+ return { phase, success: false, artifacts: [], message, error };
86
+ }
@@ -0,0 +1,113 @@
1
+ /**
2
+ * PRODUCTION_GATE phase — binary PASS/FAIL production-ready decision.
3
+ * Uses commandResolver + checkRunner. Runs placeholder scan (P2-2).
4
+ * v1.1: Adds start check and env check.
5
+ */
6
+
7
+ import type { PhaseContext, PhaseResult } from './phase-context.js';
8
+ import { successResult, failureResult, triggerJournalist } from './phase-context.js';
9
+ import { resolveCommands } from '../command-resolver.js';
10
+ import { runAllChecks, runPlaceholderScan, runStartCheck, runEnvCheck, storeCheckResults } from '../check-runner.js';
11
+ import { generateRepoSnapshot } from '../repo-snapshot.js';
12
+
13
+ export async function runProductionGate(context: PhaseContext): Promise<PhaseResult> {
14
+ const { pipeline, artifactManager, projectDir } = context;
15
+ const artifacts = [];
16
+
17
+ try {
18
+ // 1. Resolve commands from snapshot
19
+ const snapshot = await generateRepoSnapshot(projectDir);
20
+ const commands = resolveCommands(snapshot);
21
+ pipeline.resolvedCommands = commands;
22
+
23
+ // 2. Run all checks
24
+ const checkResults = await runAllChecks(commands, projectDir);
25
+
26
+ // 3. Run placeholder scan (P2-2)
27
+ const placeholderResult = runPlaceholderScan(projectDir);
28
+ checkResults.push(placeholderResult);
29
+
30
+ // 4. Run env check (v1.1)
31
+ const envResult = runEnvCheck(projectDir, snapshot);
32
+ checkResults.push(envResult);
33
+
34
+ // 5. Run start check if start command exists (v1.1)
35
+ if (commands.start) {
36
+ const startResult = await runStartCheck(commands.start, projectDir, {
37
+ port: snapshot.ports_entrypoints[0]?.port,
38
+ });
39
+ checkResults.push(startResult);
40
+ }
41
+
42
+ // 6. Store check results as artifacts
43
+ const checkArtifacts = storeCheckResults(checkResults, artifactManager, 'PRODUCTION_GATE');
44
+ artifacts.push(...checkArtifacts);
45
+
46
+ // 7. Store in pipeline gate checks
47
+ pipeline.gateChecks['PRODUCTION_GATE'] = checkResults;
48
+
49
+ // 8. Determine PASS/FAIL
50
+ const failedChecks = checkResults.filter(
51
+ (r) => r.status === 'fail' && r.check_type !== 'placeholder_scan',
52
+ );
53
+ const hasPlaceholders = placeholderResult.status === 'fail';
54
+ const auditPassed = pipeline.artifacts.some((a) => a.type === 'audit_report');
55
+ const passed = failedChecks.length === 0 && auditPassed;
56
+
57
+ // 9. Create production readiness report
58
+ const report = [
59
+ '# Production Readiness Report',
60
+ '',
61
+ `**Timestamp:** ${new Date().toISOString()}`,
62
+ `**Verdict:** ${passed ? 'PASS' : 'FAIL'}`,
63
+ '',
64
+ '## Check Results',
65
+ '',
66
+ ...checkResults.map((r) =>
67
+ `- **${r.check_type}**: ${r.status} ${r.duration_ms > 0 ? `(${r.duration_ms}ms)` : ''}`,
68
+ ),
69
+ '',
70
+ hasPlaceholders ? '## Warning: Placeholder content detected\n' + (placeholderResult.stderr_summary ?? '') : '',
71
+ '',
72
+ '## Gate Status',
73
+ `- Build: ${findCheckStatus(checkResults, 'build')}`,
74
+ `- Tests: ${findCheckStatus(checkResults, 'test')}`,
75
+ `- Lint: ${findCheckStatus(checkResults, 'lint')}`,
76
+ `- Typecheck: ${findCheckStatus(checkResults, 'typecheck')}`,
77
+ `- Env: ${findCheckStatus(checkResults, 'env_check')}`,
78
+ `- Start: ${findCheckStatus(checkResults, 'start')}`,
79
+ `- Audit: ${auditPassed ? 'PASS' : 'MISSING'}`,
80
+ `- Placeholders: ${hasPlaceholders ? 'WARNING' : 'CLEAN'}`,
81
+ ].join('\n');
82
+
83
+ const reportEntry = artifactManager.createAndStoreText(
84
+ 'production_readiness',
85
+ report,
86
+ 'PRODUCTION_GATE',
87
+ );
88
+ artifacts.push(reportEntry);
89
+
90
+ pipeline.artifacts.push(...artifacts);
91
+
92
+ // 10. Journalist trigger
93
+ await triggerJournalist('PRODUCTION_GATE', artifacts, context);
94
+
95
+ return successResult(
96
+ 'PRODUCTION_GATE',
97
+ artifacts,
98
+ passed ? 'Production Gate PASS' : `Production Gate FAIL: ${failedChecks.length} failed checks`,
99
+ );
100
+ } catch (err) {
101
+ const message = err instanceof Error ? err.message : 'Unknown error';
102
+ return failureResult('PRODUCTION_GATE', 'Production gate failed', message);
103
+ }
104
+ }
105
+
106
+ function findCheckStatus(
107
+ results: { check_type: string; status: string }[],
108
+ type: string,
109
+ ): string {
110
+ const r = results.find((c) => c.check_type === type);
111
+ if (!r) return 'SKIP';
112
+ return r.status.toUpperCase();
113
+ }
@@ -0,0 +1,63 @@
1
+ /**
2
+ * QA_VALIDATION phase — execute QA plan and validate critical paths.
3
+ * Runs tests via checkRunner. Creates qa_validation artifact.
4
+ */
5
+
6
+ import type { PhaseContext, PhaseResult } from './phase-context.js';
7
+ import { successResult, failureResult } from './phase-context.js';
8
+ import { resolveCommands } from '../command-resolver.js';
9
+ import { runCheck, storeCheckResults } from '../check-runner.js';
10
+ import { generateRepoSnapshot } from '../repo-snapshot.js';
11
+
12
+ export async function runQaValidation(context: PhaseContext): Promise<PhaseResult> {
13
+ const { pipeline, artifactManager, projectDir } = context;
14
+ const artifacts = [];
15
+
16
+ try {
17
+ // 1. Resolve test command
18
+ const snapshot = await generateRepoSnapshot(projectDir);
19
+ const commands = resolveCommands(snapshot);
20
+ pipeline.resolvedCommands = commands;
21
+
22
+ // 2. Run test command
23
+ if (commands.test) {
24
+ const testResult = await runCheck('test', commands.test, projectDir);
25
+ const stored = storeCheckResults([testResult], artifactManager, 'QA_VALIDATION');
26
+ artifacts.push(...stored);
27
+
28
+ // Store in pipeline gate checks
29
+ if (!pipeline.gateChecks['QA_VALIDATION']) {
30
+ pipeline.gateChecks['QA_VALIDATION'] = [];
31
+ }
32
+ pipeline.gateChecks['QA_VALIDATION'].push(testResult);
33
+ }
34
+
35
+ // 3. Create QA validation summary artifact
36
+ const qaReport = [
37
+ '# QA Validation Report',
38
+ '',
39
+ `**Timestamp:** ${new Date().toISOString()}`,
40
+ `**Test Command:** ${commands.test ?? 'none'}`,
41
+ `**Test Status:** ${pipeline.gateChecks['QA_VALIDATION']?.[0]?.status ?? 'skip'}`,
42
+ '',
43
+ '## Results',
44
+ '',
45
+ pipeline.gateChecks['QA_VALIDATION']?.map((r) =>
46
+ `- ${r.check_type}: ${r.status} (${r.duration_ms}ms)`,
47
+ ).join('\n') ?? 'No checks run',
48
+ ].join('\n');
49
+
50
+ const qaEntry = artifactManager.createAndStoreText(
51
+ 'qa_validation',
52
+ qaReport,
53
+ 'QA_VALIDATION',
54
+ );
55
+ artifacts.push(qaEntry);
56
+
57
+ pipeline.artifacts.push(...artifacts);
58
+ return successResult('QA_VALIDATION', artifacts, 'QA validation complete');
59
+ } catch (err) {
60
+ const message = err instanceof Error ? err.message : 'Unknown error';
61
+ return failureResult('QA_VALIDATION', 'QA validation failed', message);
62
+ }
63
+ }
@@ -0,0 +1,120 @@
1
+ /**
2
+ * RECOVERY_LOOP phase — self-heal using RCA, not guesswork.
3
+ * Routes via requires_phase_rewind_to (P1-3). Max 5 iterations.
4
+ */
5
+
6
+ import type { PipelinePhase } from '../types.js';
7
+ import type { PhaseContext, PhaseResult } from './phase-context.js';
8
+ import { successResult, failureResult, triggerJournalist } from './phase-context.js';
9
+ import { buildRCAPacket } from '../packets/rca-packet-builder.js';
10
+
11
+ export async function runRecoveryLoop(context: PhaseContext): Promise<PhaseResult> {
12
+ const { pipeline, artifactManager, skillLoader } = context;
13
+ const artifacts = [];
14
+
15
+ try {
16
+ // 1. Load debugger skill
17
+ const debuggerSkill = skillLoader.loadSkill('DEBUGGER');
18
+
19
+ // 2. Gather failure evidence
20
+ const failedPhase = pipeline.failedPhase;
21
+ const failedGateResult = failedPhase ? pipeline.gateResults[failedPhase] : undefined;
22
+ const failedChecks = failedPhase ? pipeline.gateChecks[failedPhase] ?? [] : [];
23
+
24
+ const failureEvidence = [
25
+ `Failed phase: ${failedPhase ?? 'unknown'}`,
26
+ failedGateResult
27
+ ? `Gate blockers: ${failedGateResult.blockers.join(', ')}`
28
+ : 'No gate result available',
29
+ failedChecks.length > 0
30
+ ? `Failed checks: ${failedChecks.filter((c) => c.status === 'fail').map((c) => `${c.check_type}: ${c.stderr_summary?.slice(0, 200) ?? 'no details'}`).join('; ')}`
31
+ : 'No check failures',
32
+ ].join('\n');
33
+
34
+ // 3. Generate RCA via Claude with Debugger skill
35
+ const { executePrompt } = await import('../../adapters/claude.js');
36
+ const guidance = pipeline.sessionGuidance;
37
+ const rcaPrompt = [
38
+ debuggerSkill.systemPrompt,
39
+ '',
40
+ ...(guidance ? ['## User Guidance', guidance, ''] : []),
41
+ '## Failure Evidence',
42
+ failureEvidence,
43
+ '',
44
+ '## Instructions',
45
+ 'Produce a Root Cause Analysis:',
46
+ '1. Precise root cause',
47
+ '2. Origin phase',
48
+ '3. Responsible role',
49
+ '4. Corrective actions',
50
+ '5. Whether phase rewind is needed (and to which phase)',
51
+ '6. Prevention recommendation',
52
+ ].join('\n');
53
+
54
+ const rcaResult = await executePrompt(rcaPrompt);
55
+ const rcaResponse = rcaResult.response;
56
+
57
+ // 4. Build RCA packet
58
+ const rcaPacket = buildRCAPacket({
59
+ incidentSummary: `Gate failure at ${failedPhase ?? 'unknown'} (recovery iteration ${pipeline.recoveryCount})`,
60
+ symptoms: failedGateResult?.blockers ?? ['Gate failed'],
61
+ rootCause: rcaResponse.slice(0, 500),
62
+ responsibleLayer: failedPhase ?? 'IMPLEMENTATION',
63
+ originPhase: failedPhase ?? 'IMPLEMENTATION',
64
+ governanceGap: 'Detected during gate evaluation',
65
+ correctiveActions: ['See RCA report for details'],
66
+ prevention: 'See RCA report for details',
67
+ rewindTo: determineRewindTarget(rcaResponse, failedPhase),
68
+ });
69
+
70
+ // 5. Store RCA as artifacts
71
+ const rcaJsonEntry = artifactManager.createAndStoreJson(
72
+ 'rca_report',
73
+ rcaPacket,
74
+ 'RECOVERY_LOOP',
75
+ );
76
+ artifacts.push(rcaJsonEntry);
77
+
78
+ const rcaTextEntry = artifactManager.createAndStoreText(
79
+ 'rca_report',
80
+ `# RCA Report\n\n${rcaResponse}`,
81
+ 'RECOVERY_LOOP',
82
+ );
83
+ artifacts.push(rcaTextEntry);
84
+
85
+ pipeline.artifacts.push(...artifacts);
86
+
87
+ // 6. Journalist trigger
88
+ await triggerJournalist('RECOVERY_LOOP', artifacts, context);
89
+
90
+ return successResult(
91
+ 'RECOVERY_LOOP',
92
+ artifacts,
93
+ `RCA complete: recovery iteration ${pipeline.recoveryCount}`,
94
+ );
95
+ } catch (err) {
96
+ const message = err instanceof Error ? err.message : 'Unknown error';
97
+ return failureResult('RECOVERY_LOOP', 'Recovery loop failed', message);
98
+ }
99
+ }
100
+
101
+ /** Determine rewind target from RCA response */
102
+ function determineRewindTarget(
103
+ _rcaResponse: string,
104
+ failedPhase: PipelinePhase | undefined,
105
+ ): PipelinePhase | undefined {
106
+ // If the failure was in production gate or audit, rewind to implementation
107
+ if (failedPhase === 'PRODUCTION_GATE' || failedPhase === 'AUDIT') {
108
+ return 'IMPLEMENTATION';
109
+ }
110
+ // If in QA, rewind to implementation
111
+ if (failedPhase === 'QA_VALIDATION') {
112
+ return 'IMPLEMENTATION';
113
+ }
114
+ // For consensus failures, rewind to the phase being validated
115
+ if (failedPhase === 'CONSENSUS_MASTER_PLAN') return 'INTAKE';
116
+ if (failedPhase === 'CONSENSUS_ARCHITECTURE') return 'ARCHITECTURE';
117
+ if (failedPhase === 'CONSENSUS_ROLE_PLANS') return 'ROLE_PLANNING';
118
+
119
+ return undefined;
120
+ }
@@ -0,0 +1,149 @@
1
+ /**
2
+ * REVIEW phase — verify implementation matches approved plans.
3
+ * Detects drift via snapshot diff (P1-E).
4
+ * v1.1: Creates Change Requests when drift is detected.
5
+ */
6
+
7
+ import type { PhaseContext, PhaseResult } from './phase-context.js';
8
+ import { successResult, failureResult } from './phase-context.js';
9
+ import { generateRepoSnapshot, createSnapshotArtifact, diffSnapshots } from '../repo-snapshot.js';
10
+ import type { RepoSnapshot, ChangeRequest } from '../types.js';
11
+ import { buildChangeRequest, formatChangeRequest, routeChangeRequest } from '../change-request.js';
12
+ import { existsSync, readFileSync } from 'node:fs';
13
+ import { join } from 'node:path';
14
+
15
+ export async function runReview(context: PhaseContext): Promise<PhaseResult> {
16
+ const { pipeline, artifactManager, projectDir } = context;
17
+ const artifacts = [];
18
+ const changeRequests: ChangeRequest[] = [];
19
+
20
+ try {
21
+ // 1. Generate fresh snapshot
22
+ const currentSnapshot = await generateRepoSnapshot(projectDir);
23
+ const snapshotEntry = createSnapshotArtifact(currentSnapshot, artifactManager, 'REVIEW');
24
+ artifacts.push(snapshotEntry);
25
+ pipeline.latestRepoSnapshot = artifactManager.toArtifactRef(snapshotEntry);
26
+
27
+ // 2. Find role-plan-approval snapshot for drift detection
28
+ const rolePlanSnapshots = pipeline.artifacts.filter(
29
+ (a) => a.type === 'repo_snapshot' && a.phase === 'CONSENSUS_ROLE_PLANS',
30
+ );
31
+ const baselineSnapshot = rolePlanSnapshots[rolePlanSnapshots.length - 1];
32
+
33
+ let driftReport = 'No baseline snapshot found for drift detection.';
34
+ let hasDrift = false;
35
+
36
+ if (baselineSnapshot) {
37
+ const baselinePath = join(projectDir, baselineSnapshot.path);
38
+ if (existsSync(baselinePath)) {
39
+ try {
40
+ const baselineData = JSON.parse(readFileSync(baselinePath, 'utf-8')) as RepoSnapshot;
41
+ const diff = diffSnapshots(baselineData, currentSnapshot);
42
+
43
+ if (diff.has_changes) {
44
+ hasDrift = true;
45
+ driftReport = [
46
+ '## Implementation Drift Detected',
47
+ '',
48
+ `Files delta: ${diff.files_delta > 0 ? '+' : ''}${diff.files_delta}`,
49
+ `Lines delta: ${diff.lines_delta > 0 ? '+' : ''}${diff.lines_delta}`,
50
+ diff.added_configs.length > 0 ? `Added configs: ${diff.added_configs.join(', ')}` : '',
51
+ diff.removed_configs.length > 0 ? `Removed configs: ${diff.removed_configs.join(', ')}` : '',
52
+ diff.changed_configs.length > 0 ? `Changed configs: ${diff.changed_configs.join(', ')}` : '',
53
+ ].filter(Boolean).join('\n');
54
+
55
+ // v1.1: Create change requests for detected drift
56
+ if (diff.changed_configs.length > 0) {
57
+ const cr = buildChangeRequest({
58
+ originPhase: 'REVIEW',
59
+ requestedBy: 'REVIEWER',
60
+ changeType: 'config',
61
+ description: `Config files changed during implementation: ${diff.changed_configs.join(', ')}`,
62
+ justification: 'Detected by snapshot diff during review phase',
63
+ affectedArtifacts: [artifactManager.toArtifactRef(snapshotEntry)],
64
+ affectedPhases: ['IMPLEMENTATION', 'QA_VALIDATION'],
65
+ riskLevel: diff.changed_configs.length > 3 ? 'high' : 'medium',
66
+ });
67
+ changeRequests.push(cr);
68
+ }
69
+
70
+ if (Math.abs(diff.lines_delta) > 1000) {
71
+ const cr = buildChangeRequest({
72
+ originPhase: 'REVIEW',
73
+ requestedBy: 'REVIEWER',
74
+ changeType: 'scope',
75
+ description: `Significant scope drift detected: ${diff.lines_delta > 0 ? '+' : ''}${diff.lines_delta} lines`,
76
+ justification: 'Large line delta suggests scope changes beyond approved plans',
77
+ affectedArtifacts: [artifactManager.toArtifactRef(snapshotEntry)],
78
+ affectedPhases: ['CONSENSUS_MASTER_PLAN', 'IMPLEMENTATION'],
79
+ riskLevel: 'high',
80
+ });
81
+ changeRequests.push(cr);
82
+ }
83
+ } else {
84
+ driftReport = 'No drift detected between approved plans and implementation.';
85
+ }
86
+ } catch {
87
+ driftReport = 'Failed to parse baseline snapshot for drift detection.';
88
+ }
89
+ }
90
+ }
91
+
92
+ // 3. Store change requests as artifacts and register in pipeline state
93
+ for (const cr of changeRequests) {
94
+ const crEntry = artifactManager.createAndStoreText(
95
+ 'change_request',
96
+ formatChangeRequest(cr),
97
+ 'REVIEW',
98
+ );
99
+ artifacts.push(crEntry);
100
+
101
+ // Register CR in pipeline state for orchestrator routing
102
+ if (!pipeline.pendingChangeRequests) {
103
+ pipeline.pendingChangeRequests = [];
104
+ }
105
+ pipeline.pendingChangeRequests.push({
106
+ cr_id: cr.cr_id,
107
+ change_type: cr.change_type,
108
+ target_phase: routeChangeRequest(cr),
109
+ status: 'proposed',
110
+ });
111
+ }
112
+
113
+ // 4. Create review decision artifact
114
+ const reviewDoc = [
115
+ '# Review Decision',
116
+ '',
117
+ `**Timestamp:** ${new Date().toISOString()}`,
118
+ `**Phase:** REVIEW`,
119
+ `**Drift Detected:** ${hasDrift ? 'Yes' : 'No'}`,
120
+ `**Change Requests:** ${changeRequests.length}`,
121
+ '',
122
+ '## Drift Analysis',
123
+ driftReport,
124
+ '',
125
+ changeRequests.length > 0 ? '## Change Requests\n' + changeRequests.map((cr) => `- ${cr.cr_id}: ${cr.description}`).join('\n') : '',
126
+ '',
127
+ '## Plan Alignment',
128
+ 'Implementation reviewed against approved role plans.',
129
+ '',
130
+ '## Decision',
131
+ hasDrift && changeRequests.length > 0
132
+ ? 'Review flagged drift — change requests created for consensus review.'
133
+ : 'Review completed. See drift analysis above.',
134
+ ].join('\n');
135
+
136
+ const reviewEntry = artifactManager.createAndStoreText(
137
+ 'review_decision',
138
+ reviewDoc,
139
+ 'REVIEW',
140
+ );
141
+ artifacts.push(reviewEntry);
142
+
143
+ pipeline.artifacts.push(...artifacts);
144
+ return successResult('REVIEW', artifacts, `Review complete. ${changeRequests.length} change requests.`);
145
+ } catch (err) {
146
+ const message = err instanceof Error ? err.message : 'Unknown error';
147
+ return failureResult('REVIEW', 'Review failed', message);
148
+ }
149
+ }