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,322 @@
1
+ /**
2
+ * Pipeline Orchestrator — top-level loop driving pipeline from any phase
3
+ * to completion. Implements deterministic transition logic (P0-A).
4
+ *
5
+ * Key rule: requires_phase_rewind_to ONLY takes effect after RECOVERY_LOOP
6
+ * completes successfully. Any failure from any non-recovery phase always
7
+ * goes to RECOVERY_LOOP first.
8
+ *
9
+ * v1.1: Constitution verification, CR-based phase routing, gateResult merge,
10
+ * and RCA rewind support.
11
+ */
12
+
13
+ import { readFileSync, existsSync } from 'node:fs';
14
+ import { join } from 'node:path';
15
+
16
+ import type {
17
+ PipelinePhase,
18
+ PipelineState,
19
+ PipelineResult,
20
+ RCAPacket,
21
+ } from './types.js';
22
+ import { createDefaultPipelineState } from './types.js';
23
+ import { createGateEngine } from './gate-engine.js';
24
+ import type { GateResult } from './gate-engine.js';
25
+ import { createArtifactManager } from './artifact-manager.js';
26
+ import { createSkillLoader } from './skill-loader.js';
27
+ import { createConsensusRunner } from './consensus/consensus-runner.js';
28
+ import { verifyConstitution } from './constitution.js';
29
+
30
+ import {
31
+ runIntake,
32
+ runConsensusMasterPlan,
33
+ runArchitecture,
34
+ runConsensusArchitecture,
35
+ runRolePlanning,
36
+ runConsensusRolePlans,
37
+ runImplementation,
38
+ runQaValidation,
39
+ runReview,
40
+ runAudit,
41
+ runProductionGate,
42
+ runRecoveryLoop,
43
+ runDone,
44
+ runStuck,
45
+ } from './phases/index.js';
46
+ import type { PhaseContext, PhaseResult } from './phases/index.js';
47
+ import type { ProjectState } from '../types/workflow.js';
48
+ import type { ConsensusConfig } from '../types/consensus.js';
49
+
50
+ // ─── Types ───────────────────────────────────────────────
51
+
52
+ export interface PipelineOptions {
53
+ projectDir: string;
54
+ state: ProjectState;
55
+ consensusConfig?: Partial<ConsensusConfig>;
56
+ /** User steering, upgrade context, or resume instructions */
57
+ additionalContext?: string;
58
+ onPhaseStart?: (phase: PipelinePhase) => void;
59
+ onPhaseComplete?: (phase: PipelinePhase, result: PhaseResult) => void;
60
+ onProgress?: (message: string) => void;
61
+ }
62
+
63
+ // ─── Phase Dispatch Map ──────────────────────────────────
64
+
65
+ const PHASE_HANDLERS: Record<PipelinePhase, (ctx: PhaseContext) => Promise<PhaseResult>> = {
66
+ INTAKE: runIntake,
67
+ CONSENSUS_MASTER_PLAN: runConsensusMasterPlan,
68
+ ARCHITECTURE: runArchitecture,
69
+ CONSENSUS_ARCHITECTURE: runConsensusArchitecture,
70
+ ROLE_PLANNING: runRolePlanning,
71
+ CONSENSUS_ROLE_PLANS: runConsensusRolePlans,
72
+ IMPLEMENTATION: runImplementation,
73
+ QA_VALIDATION: runQaValidation,
74
+ REVIEW: runReview,
75
+ AUDIT: runAudit,
76
+ PRODUCTION_GATE: runProductionGate,
77
+ RECOVERY_LOOP: runRecoveryLoop,
78
+ DONE: runDone,
79
+ STUCK: runStuck,
80
+ };
81
+
82
+ /** Phases after which we check for pending CRs */
83
+ const CR_CHECK_PHASES: Set<PipelinePhase> = new Set(['REVIEW', 'AUDIT']);
84
+
85
+ // ─── Orchestrator ────────────────────────────────────────
86
+
87
+ /** Run the full pipeline from current phase to completion */
88
+ export async function runPipeline(options: PipelineOptions): Promise<PipelineResult> {
89
+ const {
90
+ projectDir,
91
+ state,
92
+ consensusConfig,
93
+ additionalContext,
94
+ onPhaseStart,
95
+ onPhaseComplete,
96
+ onProgress,
97
+ } = options;
98
+
99
+ // Initialize pipeline state if needed
100
+ const pipeline: PipelineState = (state as unknown as { pipeline?: PipelineState }).pipeline
101
+ ?? createDefaultPipelineState();
102
+
103
+ // Persist user guidance in pipeline state so it survives resume
104
+ if (additionalContext && !pipeline.sessionGuidance) {
105
+ pipeline.sessionGuidance = additionalContext;
106
+ }
107
+
108
+ // Create context dependencies
109
+ const gateEngine = createGateEngine();
110
+ const artifactManager = createArtifactManager(projectDir);
111
+ const skillLoader = createSkillLoader(projectDir);
112
+ const consensusRunner = createConsensusRunner(projectDir, consensusConfig);
113
+
114
+ // Ensure docs structure
115
+ artifactManager.ensureDocsStructure();
116
+
117
+ const context: PhaseContext = {
118
+ state,
119
+ pipeline,
120
+ projectDir,
121
+ skillLoader,
122
+ artifactManager,
123
+ gateEngine,
124
+ consensusRunner,
125
+ };
126
+
127
+ let phase = pipeline.pipelinePhase;
128
+ let failedPhase: PipelinePhase | null = null;
129
+
130
+ // ─── Main Loop ───────────────────────────────────────
131
+ while (phase !== 'DONE' && phase !== 'STUCK') {
132
+ onPhaseStart?.(phase);
133
+ onProgress?.(`Pipeline phase: ${phase}`);
134
+
135
+ // Execute the current phase
136
+ const handler = PHASE_HANDLERS[phase];
137
+ if (!handler) {
138
+ return {
139
+ success: false,
140
+ finalPhase: phase,
141
+ artifacts: pipeline.artifacts,
142
+ recoveryIterations: pipeline.recoveryCount,
143
+ error: `No handler for phase: ${phase}`,
144
+ };
145
+ }
146
+
147
+ let result: PhaseResult;
148
+ try {
149
+ result = await handler(context);
150
+ } catch (err) {
151
+ result = {
152
+ phase,
153
+ success: false,
154
+ artifacts: [],
155
+ message: 'Phase handler threw an exception',
156
+ error: err instanceof Error ? err.message : String(err),
157
+ };
158
+ }
159
+
160
+ onPhaseComplete?.(phase, result);
161
+
162
+ // v1.1: Verify constitution integrity before evaluating gate
163
+ const constitutionCheck = verifyConstitution(pipeline, projectDir);
164
+
165
+ // Evaluate gate with constitution verification result
166
+ const gateResult = gateEngine.evaluateGate(phase, pipeline, {
167
+ constitutionValid: constitutionCheck.valid,
168
+ constitutionReason: constitutionCheck.reason,
169
+ });
170
+
171
+ // v1.1: Merge gate result with any pre-existing phase data (preserves consensus scores)
172
+ mergeGateResult(pipeline, phase, gateResult);
173
+
174
+ if (gateResult.pass) {
175
+ // ─── PASS ────────────────────────────────────────
176
+
177
+ // v1.1: Check for pending CRs after REVIEW/AUDIT — route to consensus before continuing
178
+ if (CR_CHECK_PHASES.has(phase)) {
179
+ const crRoute = getNextCRRoute(pipeline);
180
+ if (crRoute) {
181
+ onProgress?.(`CR ${crRoute.cr_id} routing to ${crRoute.target_phase}`);
182
+ phase = crRoute.target_phase;
183
+ pipeline.pipelinePhase = phase;
184
+ continue;
185
+ }
186
+ }
187
+
188
+ if (phase === 'RECOVERY_LOOP') {
189
+ // Recovery succeeded. RCA may specify rewind target.
190
+ const rca = getLatestRCA(pipeline, projectDir);
191
+ if (rca?.requires_phase_rewind_to) {
192
+ phase = rca.requires_phase_rewind_to;
193
+ } else {
194
+ // Retest the phase that failed
195
+ phase = failedPhase ?? 'QA_VALIDATION';
196
+ }
197
+ failedPhase = null;
198
+ } else {
199
+ // Normal progression
200
+ phase = gateEngine.getNextPhase(phase, gateResult);
201
+ }
202
+ } else {
203
+ // ─── FAIL ────────────────────────────────────────
204
+ if (pipeline.recoveryCount >= pipeline.maxRecoveryIterations) {
205
+ phase = 'STUCK';
206
+ } else {
207
+ failedPhase = phase;
208
+ pipeline.failedPhase = phase;
209
+ phase = 'RECOVERY_LOOP';
210
+ pipeline.recoveryCount++;
211
+ }
212
+ }
213
+
214
+ // Update pipeline phase in state
215
+ pipeline.pipelinePhase = phase;
216
+ onProgress?.(`Transitioning to: ${phase}`);
217
+ }
218
+
219
+ // ─── Terminal State ────────────────────────────────────
220
+ // Run the terminal phase handler (DONE or STUCK)
221
+ if (phase === 'DONE' || phase === 'STUCK') {
222
+ const terminalHandler = PHASE_HANDLERS[phase];
223
+ if (terminalHandler) {
224
+ try {
225
+ await terminalHandler(context);
226
+ } catch {
227
+ // Best-effort for terminal phases
228
+ }
229
+ }
230
+ }
231
+
232
+ return {
233
+ success: phase === 'DONE',
234
+ finalPhase: phase,
235
+ artifacts: pipeline.artifacts,
236
+ recoveryIterations: pipeline.recoveryCount,
237
+ error: phase !== 'DONE'
238
+ ? `Pipeline stuck after ${pipeline.recoveryCount} recovery iterations`
239
+ : undefined,
240
+ };
241
+ }
242
+
243
+ /** Resume pipeline from saved state */
244
+ export async function resumePipeline(options: PipelineOptions): Promise<PipelineResult> {
245
+ // Resume is the same as run — it picks up from pipeline.pipelinePhase
246
+ return runPipeline(options);
247
+ }
248
+
249
+ // ─── Helpers ─────────────────────────────────────────────
250
+
251
+ /**
252
+ * Merge gate engine result with existing phase data in gateResults.
253
+ * Preserves score/consensusScore stored by consensus phase handlers
254
+ * while updating pass/blockers from the gate engine.
255
+ */
256
+ function mergeGateResult(
257
+ pipeline: PipelineState,
258
+ phase: PipelinePhase,
259
+ gateResult: GateResult,
260
+ ): void {
261
+ const existing = pipeline.gateResults[phase];
262
+ if (existing?.score !== undefined || existing?.consensusScore !== undefined) {
263
+ // Preserve consensus scores from the phase handler
264
+ pipeline.gateResults[phase] = {
265
+ ...gateResult,
266
+ score: existing.score ?? gateResult.score,
267
+ consensusScore: existing.consensusScore ?? gateResult.consensusScore,
268
+ };
269
+ } else {
270
+ pipeline.gateResults[phase] = gateResult;
271
+ }
272
+ }
273
+
274
+ /**
275
+ * Find the next pending change request that needs routing.
276
+ * Returns the first 'proposed' CR and marks it as 'approved' (routed).
277
+ */
278
+ function getNextCRRoute(
279
+ pipeline: PipelineState,
280
+ ): { cr_id: string; target_phase: PipelinePhase } | undefined {
281
+ const pending = pipeline.pendingChangeRequests;
282
+ if (!pending) return undefined;
283
+
284
+ const nextCR = pending.find((cr) => cr.status === 'proposed');
285
+ if (!nextCR) return undefined;
286
+
287
+ // Mark as approved (it has been routed to the consensus phase)
288
+ nextCR.status = 'approved';
289
+
290
+ return {
291
+ cr_id: nextCR.cr_id,
292
+ target_phase: nextCR.target_phase,
293
+ };
294
+ }
295
+
296
+ /**
297
+ * Read the latest RCA packet from stored artifacts.
298
+ * Parses the JSON artifact file to extract rewind targets.
299
+ */
300
+ function getLatestRCA(
301
+ pipeline: PipelineState,
302
+ projectDir: string,
303
+ ): RCAPacket | undefined {
304
+ const rcaArtifacts = pipeline.artifacts
305
+ .filter((a) => a.type === 'rca_report' && a.content_type === 'json')
306
+ .sort((a, b) => b.timestamp.localeCompare(a.timestamp));
307
+
308
+ if (rcaArtifacts.length === 0) return undefined;
309
+
310
+ // Read the latest RCA artifact from disk
311
+ const latest = rcaArtifacts[0];
312
+ const rcaPath = join(projectDir, latest.path);
313
+ if (!existsSync(rcaPath)) return undefined;
314
+
315
+ try {
316
+ const content = readFileSync(rcaPath, 'utf-8');
317
+ const parsed = JSON.parse(content) as RCAPacket;
318
+ return parsed;
319
+ } catch {
320
+ return undefined;
321
+ }
322
+ }
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Audit Report Builder — constructs structured AuditReports
3
+ * with auto-computed status, risk score, and recovery flag (P2-1).
4
+ */
5
+
6
+ import { randomUUID } from 'node:crypto';
7
+
8
+ import type { ArtifactRef, AuditFinding, AuditReport } from '../types.js';
9
+
10
+ export interface BuildAuditReportArgs {
11
+ repoSnapshot: ArtifactRef;
12
+ findings: AuditFinding[];
13
+ }
14
+
15
+ /** Severity weights for risk score calculation */
16
+ const SEVERITY_WEIGHTS: Record<string, number> = {
17
+ P0: 40,
18
+ P1: 20,
19
+ P2: 8,
20
+ P3: 2,
21
+ };
22
+
23
+ export function buildAuditReport(args: BuildAuditReportArgs): AuditReport {
24
+ const { repoSnapshot, findings } = args;
25
+
26
+ const hasBlockingFindings = findings.some((f) => f.blocking);
27
+ const overallStatus = hasBlockingFindings ? 'FAIL' : 'PASS';
28
+
29
+ // Risk score: sum of severity weights, capped at 100
30
+ const rawScore = findings.reduce((sum, f) => sum + (SEVERITY_WEIGHTS[f.severity] ?? 0), 0);
31
+ const systemRiskScore = Math.min(100, rawScore);
32
+
33
+ // Recovery needed if any blocking P0/P1 findings
34
+ const recoveryRequired = findings.some(
35
+ (f) => f.blocking && (f.severity === 'P0' || f.severity === 'P1'),
36
+ );
37
+
38
+ return {
39
+ audit_id: randomUUID(),
40
+ timestamp: new Date().toISOString(),
41
+ repo_snapshot: repoSnapshot,
42
+ overall_status: overallStatus,
43
+ findings,
44
+ system_risk_score: systemRiskScore,
45
+ recovery_required: recoveryRequired,
46
+ };
47
+ }
@@ -0,0 +1,112 @@
1
+ /**
2
+ * Consensus Packet Builder — aggregates reviewer votes into a ConsensusPacket.
3
+ * Auto-computes consensus result (score, approval) and final status.
4
+ * v1.1: Added confidence-weighted scoring.
5
+ */
6
+
7
+ import { randomUUID } from 'node:crypto';
8
+
9
+ import type {
10
+ ArtifactRef,
11
+ ReviewerVote,
12
+ ConsensusPacket,
13
+ } from '../types.js';
14
+
15
+ export interface ConsensusRules {
16
+ threshold: number;
17
+ quorum: number;
18
+ min_reviewers: number;
19
+ }
20
+
21
+ export interface BuildConsensusPacketArgs {
22
+ planPacketRef: ArtifactRef;
23
+ votes: ReviewerVote[];
24
+ rules: ConsensusRules;
25
+ arbitratorResult?: {
26
+ decision: string;
27
+ merged_patch?: string;
28
+ artifact_ref?: ArtifactRef;
29
+ };
30
+ }
31
+
32
+ /** Vote weight mapping: APPROVE=1.0, CONDITIONAL=0.5, REJECT=0.0 */
33
+ const VOTE_WEIGHTS: Record<string, number> = {
34
+ 'APPROVE': 1.0,
35
+ 'CONDITIONAL': 0.5,
36
+ 'REJECT': 0.0,
37
+ };
38
+
39
+ /**
40
+ * Compute both simple and confidence-weighted consensus scores.
41
+ *
42
+ * Simple score: approve count / total votes (backward compat).
43
+ * Weighted score: each vote's weight (APPROVE=1, CONDITIONAL=0.5, REJECT=0)
44
+ * multiplied by voter confidence, then averaged by total confidence.
45
+ * If any vote has blocking_issues, weighted_score is forced to 0.
46
+ */
47
+ export function computeConsensusScore(
48
+ votes: ReviewerVote[],
49
+ ): { score: number; weighted_score: number } {
50
+ if (votes.length === 0) return { score: 0, weighted_score: 0 };
51
+
52
+ // Simple score (backward compat): approve ratio
53
+ const approvedCount = votes.filter((v) => v.vote === 'APPROVE').length;
54
+ const score = approvedCount / votes.length;
55
+
56
+ // Weighted score: confidence-weighted vote values
57
+ let totalWeight = 0;
58
+ let weightedSum = 0;
59
+ for (const v of votes) {
60
+ const w = v.confidence;
61
+ weightedSum += (VOTE_WEIGHTS[v.vote] ?? 0) * w;
62
+ totalWeight += w;
63
+ }
64
+ const rawWeighted = totalWeight > 0 ? weightedSum / totalWeight : 0;
65
+
66
+ // Override: any vote with blocking_issues forces weighted_score to 0
67
+ const hasBlockingIssues = votes.some((v) => v.blocking_issues.length > 0);
68
+
69
+ return {
70
+ score,
71
+ weighted_score: hasBlockingIssues ? 0 : rawWeighted,
72
+ };
73
+ }
74
+
75
+ export function buildConsensusPacket(args: BuildConsensusPacketArgs): ConsensusPacket {
76
+ const { planPacketRef, votes, rules, arbitratorResult } = args;
77
+
78
+ const { score, weighted_score } = computeConsensusScore(votes);
79
+ const approved = score >= rules.threshold && votes.length >= rules.quorum;
80
+
81
+ let finalStatus: 'APPROVED' | 'REJECTED' | 'ARBITRATED';
82
+ if (arbitratorResult) {
83
+ finalStatus = 'ARBITRATED';
84
+ } else if (approved) {
85
+ finalStatus = 'APPROVED';
86
+ } else {
87
+ finalStatus = 'REJECTED';
88
+ }
89
+
90
+ return {
91
+ metadata: {
92
+ packet_id: randomUUID(),
93
+ timestamp: new Date().toISOString(),
94
+ plan_packet_id: planPacketRef.artifact_id,
95
+ },
96
+ plan_packet_reference: planPacketRef,
97
+ reviewer_votes: votes,
98
+ consensus_rules: {
99
+ threshold: rules.threshold,
100
+ quorum: rules.quorum,
101
+ min_reviewers: rules.min_reviewers,
102
+ },
103
+ consensus_result: {
104
+ approved,
105
+ score,
106
+ weighted_score,
107
+ participating_reviewers: votes.length,
108
+ },
109
+ arbitrator_result: arbitratorResult,
110
+ final_status: finalStatus,
111
+ };
112
+ }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Re-exports all packet builders.
3
+ */
4
+
5
+ export { buildPlanPacket } from './plan-packet-builder.js';
6
+ export type { BuildPlanPacketArgs } from './plan-packet-builder.js';
7
+
8
+ export { buildConsensusPacket } from './consensus-packet-builder.js';
9
+ export type { BuildConsensusPacketArgs, ConsensusRules } from './consensus-packet-builder.js';
10
+
11
+ export { buildRCAPacket } from './rca-packet-builder.js';
12
+ export type { BuildRCAPacketArgs } from './rca-packet-builder.js';
13
+
14
+ export { buildAuditReport } from './audit-report-builder.js';
15
+ export type { BuildAuditReportArgs } from './audit-report-builder.js';
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Plan Packet Builder — deterministic construction of PlanPackets.
3
+ * Auto-generates packet_id, timestamp, auto-increments version.
4
+ */
5
+
6
+ import { randomUUID } from 'node:crypto';
7
+
8
+ import type {
9
+ PipelinePhase,
10
+ PipelineRole,
11
+ ArtifactRef,
12
+ DependencyEdge,
13
+ Constraint,
14
+ PlanPacket,
15
+ } from '../types.js';
16
+
17
+ export interface BuildPlanPacketArgs {
18
+ phase: PipelinePhase;
19
+ submittedBy: PipelineRole;
20
+ masterPlanRef: ArtifactRef;
21
+ constitutionRef: ArtifactRef;
22
+ repoSnapshotRef: ArtifactRef;
23
+ proposedArtifacts: ArtifactRef[];
24
+ acceptanceCriteria: string[];
25
+ dependencies: DependencyEdge[];
26
+ constraints: Constraint[];
27
+ openQuestions?: string[];
28
+ /** Override version (defaults to 1) */
29
+ version?: number;
30
+ }
31
+
32
+ export function buildPlanPacket(args: BuildPlanPacketArgs): PlanPacket {
33
+ return {
34
+ metadata: {
35
+ packet_id: randomUUID(),
36
+ timestamp: new Date().toISOString(),
37
+ phase: args.phase,
38
+ submitted_by: args.submittedBy,
39
+ version: args.version ?? 1,
40
+ },
41
+ references: {
42
+ master_plan: args.masterPlanRef,
43
+ constitution: args.constitutionRef,
44
+ repo_snapshot: args.repoSnapshotRef,
45
+ },
46
+ proposed_artifacts: args.proposedArtifacts,
47
+ acceptance_criteria: args.acceptanceCriteria,
48
+ artifact_dependencies: args.dependencies,
49
+ constraints: args.constraints,
50
+ open_questions: args.openQuestions,
51
+ };
52
+ }
@@ -0,0 +1,38 @@
1
+ /**
2
+ * RCA Packet Builder — constructs Root Cause Analysis packets
3
+ * with explicit phase rewind routing (P1-3).
4
+ */
5
+
6
+ import { randomUUID } from 'node:crypto';
7
+
8
+ import type { PipelinePhase, RCAPacket } from '../types.js';
9
+
10
+ export interface BuildRCAPacketArgs {
11
+ incidentSummary: string;
12
+ symptoms: string[];
13
+ rootCause: string;
14
+ responsibleLayer: string;
15
+ originPhase: PipelinePhase;
16
+ governanceGap: string;
17
+ correctiveActions: string[];
18
+ prevention: string;
19
+ rewindTo?: PipelinePhase;
20
+ requiresConsensusOn?: PipelinePhase[];
21
+ }
22
+
23
+ export function buildRCAPacket(args: BuildRCAPacketArgs): RCAPacket {
24
+ return {
25
+ rca_id: randomUUID(),
26
+ timestamp: new Date().toISOString(),
27
+ incident_summary: args.incidentSummary,
28
+ symptoms: args.symptoms,
29
+ root_cause: args.rootCause,
30
+ responsible_layer: args.responsibleLayer,
31
+ origin_phase: args.originPhase,
32
+ governance_gap: args.governanceGap,
33
+ corrective_actions: args.correctiveActions,
34
+ prevention: args.prevention,
35
+ requires_phase_rewind_to: args.rewindTo,
36
+ requires_consensus_on: args.requiresConsensusOn,
37
+ };
38
+ }
@@ -0,0 +1,73 @@
1
+ /**
2
+ * ARCHITECTURE phase — create system architecture + explicit contracts.
3
+ * Uses ARCHITECT skill via executePrompt().
4
+ */
5
+
6
+ import { existsSync, readFileSync } from 'node:fs';
7
+ import { join } from 'node:path';
8
+
9
+ import type { PhaseContext, PhaseResult } from './phase-context.js';
10
+ import { successResult, failureResult } from './phase-context.js';
11
+ import { generateRepoSnapshot, createSnapshotArtifact } from '../repo-snapshot.js';
12
+
13
+ export async function runArchitecture(context: PhaseContext): Promise<PhaseResult> {
14
+ const { pipeline, artifactManager, skillLoader, projectDir } = context;
15
+ const artifacts = [];
16
+
17
+ try {
18
+ // 1. Load architect skill
19
+ const architectSkill = skillLoader.loadSkill('ARCHITECT');
20
+
21
+ // 2. Read approved master plan
22
+ const masterPlanArtifact = pipeline.artifacts.find((a) => a.type === 'master_plan');
23
+ let masterPlanContent = '';
24
+ if (masterPlanArtifact) {
25
+ const fullPath = join(projectDir, masterPlanArtifact.path);
26
+ if (existsSync(fullPath)) {
27
+ masterPlanContent = readFileSync(fullPath, 'utf-8');
28
+ }
29
+ }
30
+
31
+ // 3. Generate architecture via Claude
32
+ const { executePrompt } = await import('../../adapters/claude.js');
33
+ const architecturePrompt = [
34
+ architectSkill.systemPrompt,
35
+ '',
36
+ '## Master Plan',
37
+ masterPlanContent,
38
+ '',
39
+ '## Instructions',
40
+ 'Create the system architecture document covering:',
41
+ '- System topology & boundaries',
42
+ '- API contracts (endpoints, methods, request/response)',
43
+ '- Auth model and security assumptions',
44
+ '- Data ownership boundaries',
45
+ '- Env var list',
46
+ '- Repo layout blueprint',
47
+ '- Error handling strategy',
48
+ ].join('\n');
49
+
50
+ const result = await executePrompt(architecturePrompt);
51
+ const architectureDoc = result.response;
52
+
53
+ // 4. Store architecture artifact
54
+ const archEntry = artifactManager.createAndStoreText(
55
+ 'architecture',
56
+ architectureDoc,
57
+ 'ARCHITECTURE',
58
+ );
59
+ artifacts.push(archEntry);
60
+
61
+ // 5. Generate fresh repo snapshot
62
+ const snapshot = await generateRepoSnapshot(projectDir);
63
+ const snapshotEntry = createSnapshotArtifact(snapshot, artifactManager, 'ARCHITECTURE');
64
+ artifacts.push(snapshotEntry);
65
+ pipeline.latestRepoSnapshot = artifactManager.toArtifactRef(snapshotEntry);
66
+
67
+ pipeline.artifacts.push(...artifacts);
68
+ return successResult('ARCHITECTURE', artifacts, 'Architecture document created');
69
+ } catch (err) {
70
+ const message = err instanceof Error ? err.message : 'Unknown error';
71
+ return failureResult('ARCHITECTURE', 'Architecture creation failed', message);
72
+ }
73
+ }