popeye-cli 1.10.0 → 2.0.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 (253) hide show
  1. package/CHANGELOG.md +59 -0
  2. package/CONTRIBUTING.md +15 -1
  3. package/README.md +57 -0
  4. package/dist/pipeline/artifact-manager.d.ts +47 -0
  5. package/dist/pipeline/artifact-manager.d.ts.map +1 -0
  6. package/dist/pipeline/artifact-manager.js +251 -0
  7. package/dist/pipeline/artifact-manager.js.map +1 -0
  8. package/dist/pipeline/artifact-validators.d.ts +29 -0
  9. package/dist/pipeline/artifact-validators.d.ts.map +1 -0
  10. package/dist/pipeline/artifact-validators.js +173 -0
  11. package/dist/pipeline/artifact-validators.js.map +1 -0
  12. package/dist/pipeline/change-request.d.ts +47 -0
  13. package/dist/pipeline/change-request.d.ts.map +1 -0
  14. package/dist/pipeline/change-request.js +91 -0
  15. package/dist/pipeline/change-request.js.map +1 -0
  16. package/dist/pipeline/check-runner.d.ts +47 -0
  17. package/dist/pipeline/check-runner.d.ts.map +1 -0
  18. package/dist/pipeline/check-runner.js +417 -0
  19. package/dist/pipeline/check-runner.js.map +1 -0
  20. package/dist/pipeline/command-resolver.d.ts +9 -0
  21. package/dist/pipeline/command-resolver.d.ts.map +1 -0
  22. package/dist/pipeline/command-resolver.js +140 -0
  23. package/dist/pipeline/command-resolver.js.map +1 -0
  24. package/dist/pipeline/consensus/consensus-runner.d.ts +44 -0
  25. package/dist/pipeline/consensus/consensus-runner.d.ts.map +1 -0
  26. package/dist/pipeline/consensus/consensus-runner.js +212 -0
  27. package/dist/pipeline/consensus/consensus-runner.js.map +1 -0
  28. package/dist/pipeline/constitution.d.ts +45 -0
  29. package/dist/pipeline/constitution.d.ts.map +1 -0
  30. package/dist/pipeline/constitution.js +82 -0
  31. package/dist/pipeline/constitution.js.map +1 -0
  32. package/dist/pipeline/gate-engine.d.ts +55 -0
  33. package/dist/pipeline/gate-engine.d.ts.map +1 -0
  34. package/dist/pipeline/gate-engine.js +270 -0
  35. package/dist/pipeline/gate-engine.js.map +1 -0
  36. package/dist/pipeline/index.d.ts +26 -0
  37. package/dist/pipeline/index.d.ts.map +1 -0
  38. package/dist/pipeline/index.js +35 -0
  39. package/dist/pipeline/index.js.map +1 -0
  40. package/dist/pipeline/migration.d.ts +15 -0
  41. package/dist/pipeline/migration.d.ts.map +1 -0
  42. package/dist/pipeline/migration.js +76 -0
  43. package/dist/pipeline/migration.js.map +1 -0
  44. package/dist/pipeline/orchestrator.d.ts +28 -0
  45. package/dist/pipeline/orchestrator.d.ts.map +1 -0
  46. package/dist/pipeline/orchestrator.js +238 -0
  47. package/dist/pipeline/orchestrator.js.map +1 -0
  48. package/dist/pipeline/packets/audit-report-builder.d.ts +11 -0
  49. package/dist/pipeline/packets/audit-report-builder.d.ts.map +1 -0
  50. package/dist/pipeline/packets/audit-report-builder.js +32 -0
  51. package/dist/pipeline/packets/audit-report-builder.js.map +1 -0
  52. package/dist/pipeline/packets/consensus-packet-builder.d.ts +35 -0
  53. package/dist/pipeline/packets/consensus-packet-builder.d.ts.map +1 -0
  54. package/dist/pipeline/packets/consensus-packet-builder.js +80 -0
  55. package/dist/pipeline/packets/consensus-packet-builder.js.map +1 -0
  56. package/dist/pipeline/packets/index.d.ts +12 -0
  57. package/dist/pipeline/packets/index.d.ts.map +1 -0
  58. package/dist/pipeline/packets/index.js +8 -0
  59. package/dist/pipeline/packets/index.js.map +1 -0
  60. package/dist/pipeline/packets/plan-packet-builder.d.ts +21 -0
  61. package/dist/pipeline/packets/plan-packet-builder.d.ts.map +1 -0
  62. package/dist/pipeline/packets/plan-packet-builder.js +27 -0
  63. package/dist/pipeline/packets/plan-packet-builder.js.map +1 -0
  64. package/dist/pipeline/packets/rca-packet-builder.d.ts +19 -0
  65. package/dist/pipeline/packets/rca-packet-builder.d.ts.map +1 -0
  66. package/dist/pipeline/packets/rca-packet-builder.js +22 -0
  67. package/dist/pipeline/packets/rca-packet-builder.js.map +1 -0
  68. package/dist/pipeline/phases/architecture.d.ts +7 -0
  69. package/dist/pipeline/phases/architecture.d.ts.map +1 -0
  70. package/dist/pipeline/phases/architecture.js +60 -0
  71. package/dist/pipeline/phases/architecture.js.map +1 -0
  72. package/dist/pipeline/phases/audit.d.ts +8 -0
  73. package/dist/pipeline/phases/audit.d.ts.map +1 -0
  74. package/dist/pipeline/phases/audit.js +144 -0
  75. package/dist/pipeline/phases/audit.js.map +1 -0
  76. package/dist/pipeline/phases/consensus-architecture.d.ts +7 -0
  77. package/dist/pipeline/phases/consensus-architecture.d.ts.map +1 -0
  78. package/dist/pipeline/phases/consensus-architecture.js +84 -0
  79. package/dist/pipeline/phases/consensus-architecture.js.map +1 -0
  80. package/dist/pipeline/phases/consensus-master-plan.d.ts +7 -0
  81. package/dist/pipeline/phases/consensus-master-plan.d.ts.map +1 -0
  82. package/dist/pipeline/phases/consensus-master-plan.js +81 -0
  83. package/dist/pipeline/phases/consensus-master-plan.js.map +1 -0
  84. package/dist/pipeline/phases/consensus-role-plans.d.ts +7 -0
  85. package/dist/pipeline/phases/consensus-role-plans.d.ts.map +1 -0
  86. package/dist/pipeline/phases/consensus-role-plans.js +85 -0
  87. package/dist/pipeline/phases/consensus-role-plans.js.map +1 -0
  88. package/dist/pipeline/phases/done.d.ts +7 -0
  89. package/dist/pipeline/phases/done.d.ts.map +1 -0
  90. package/dist/pipeline/phases/done.js +45 -0
  91. package/dist/pipeline/phases/done.js.map +1 -0
  92. package/dist/pipeline/phases/implementation.d.ts +8 -0
  93. package/dist/pipeline/phases/implementation.d.ts.map +1 -0
  94. package/dist/pipeline/phases/implementation.js +42 -0
  95. package/dist/pipeline/phases/implementation.js.map +1 -0
  96. package/dist/pipeline/phases/index.d.ts +20 -0
  97. package/dist/pipeline/phases/index.d.ts.map +1 -0
  98. package/dist/pipeline/phases/index.js +19 -0
  99. package/dist/pipeline/phases/index.js.map +1 -0
  100. package/dist/pipeline/phases/intake.d.ts +8 -0
  101. package/dist/pipeline/phases/intake.d.ts.map +1 -0
  102. package/dist/pipeline/phases/intake.js +40 -0
  103. package/dist/pipeline/phases/intake.js.map +1 -0
  104. package/dist/pipeline/phases/phase-context.d.ts +30 -0
  105. package/dist/pipeline/phases/phase-context.d.ts.map +1 -0
  106. package/dist/pipeline/phases/phase-context.js +33 -0
  107. package/dist/pipeline/phases/phase-context.js.map +1 -0
  108. package/dist/pipeline/phases/production-gate.d.ts +8 -0
  109. package/dist/pipeline/phases/production-gate.d.ts.map +1 -0
  110. package/dist/pipeline/phases/production-gate.js +84 -0
  111. package/dist/pipeline/phases/production-gate.js.map +1 -0
  112. package/dist/pipeline/phases/qa-validation.d.ts +7 -0
  113. package/dist/pipeline/phases/qa-validation.d.ts.map +1 -0
  114. package/dist/pipeline/phases/qa-validation.js +50 -0
  115. package/dist/pipeline/phases/qa-validation.js.map +1 -0
  116. package/dist/pipeline/phases/recovery-loop.d.ts +7 -0
  117. package/dist/pipeline/phases/recovery-loop.d.ts.map +1 -0
  118. package/dist/pipeline/phases/recovery-loop.js +91 -0
  119. package/dist/pipeline/phases/recovery-loop.js.map +1 -0
  120. package/dist/pipeline/phases/review.d.ts +8 -0
  121. package/dist/pipeline/phases/review.d.ts.map +1 -0
  122. package/dist/pipeline/phases/review.js +127 -0
  123. package/dist/pipeline/phases/review.js.map +1 -0
  124. package/dist/pipeline/phases/role-planning.d.ts +7 -0
  125. package/dist/pipeline/phases/role-planning.d.ts.map +1 -0
  126. package/dist/pipeline/phases/role-planning.js +75 -0
  127. package/dist/pipeline/phases/role-planning.js.map +1 -0
  128. package/dist/pipeline/phases/stuck.d.ts +7 -0
  129. package/dist/pipeline/phases/stuck.d.ts.map +1 -0
  130. package/dist/pipeline/phases/stuck.js +51 -0
  131. package/dist/pipeline/phases/stuck.js.map +1 -0
  132. package/dist/pipeline/repo-snapshot.d.ts +24 -0
  133. package/dist/pipeline/repo-snapshot.d.ts.map +1 -0
  134. package/dist/pipeline/repo-snapshot.js +343 -0
  135. package/dist/pipeline/repo-snapshot.js.map +1 -0
  136. package/dist/pipeline/role-execution-adapter.d.ts +59 -0
  137. package/dist/pipeline/role-execution-adapter.d.ts.map +1 -0
  138. package/dist/pipeline/role-execution-adapter.js +159 -0
  139. package/dist/pipeline/role-execution-adapter.js.map +1 -0
  140. package/dist/pipeline/skill-loader.d.ts +34 -0
  141. package/dist/pipeline/skill-loader.d.ts.map +1 -0
  142. package/dist/pipeline/skill-loader.js +156 -0
  143. package/dist/pipeline/skill-loader.js.map +1 -0
  144. package/dist/pipeline/skills/defaults.d.ts +16 -0
  145. package/dist/pipeline/skills/defaults.d.ts.map +1 -0
  146. package/dist/pipeline/skills/defaults.js +189 -0
  147. package/dist/pipeline/skills/defaults.js.map +1 -0
  148. package/dist/pipeline/type-defs/artifacts.d.ts +202 -0
  149. package/dist/pipeline/type-defs/artifacts.d.ts.map +1 -0
  150. package/dist/pipeline/type-defs/artifacts.js +66 -0
  151. package/dist/pipeline/type-defs/artifacts.js.map +1 -0
  152. package/dist/pipeline/type-defs/audit.d.ts +256 -0
  153. package/dist/pipeline/type-defs/audit.d.ts.map +1 -0
  154. package/dist/pipeline/type-defs/audit.js +54 -0
  155. package/dist/pipeline/type-defs/audit.js.map +1 -0
  156. package/dist/pipeline/type-defs/checks.d.ts +81 -0
  157. package/dist/pipeline/type-defs/checks.d.ts.map +1 -0
  158. package/dist/pipeline/type-defs/checks.js +38 -0
  159. package/dist/pipeline/type-defs/checks.js.map +1 -0
  160. package/dist/pipeline/type-defs/enums.d.ts +43 -0
  161. package/dist/pipeline/type-defs/enums.d.ts.map +1 -0
  162. package/dist/pipeline/type-defs/enums.js +55 -0
  163. package/dist/pipeline/type-defs/enums.js.map +1 -0
  164. package/dist/pipeline/type-defs/index.d.ts +12 -0
  165. package/dist/pipeline/type-defs/index.d.ts.map +1 -0
  166. package/dist/pipeline/type-defs/index.js +12 -0
  167. package/dist/pipeline/type-defs/index.js.map +1 -0
  168. package/dist/pipeline/type-defs/packets.d.ts +806 -0
  169. package/dist/pipeline/type-defs/packets.d.ts.map +1 -0
  170. package/dist/pipeline/type-defs/packets.js +109 -0
  171. package/dist/pipeline/type-defs/packets.js.map +1 -0
  172. package/dist/pipeline/type-defs/snapshot.d.ts +52 -0
  173. package/dist/pipeline/type-defs/snapshot.d.ts.map +1 -0
  174. package/dist/pipeline/type-defs/snapshot.js +35 -0
  175. package/dist/pipeline/type-defs/snapshot.js.map +1 -0
  176. package/dist/pipeline/type-defs/state.d.ts +449 -0
  177. package/dist/pipeline/type-defs/state.d.ts.map +1 -0
  178. package/dist/pipeline/type-defs/state.js +88 -0
  179. package/dist/pipeline/type-defs/state.js.map +1 -0
  180. package/dist/pipeline/types.d.ts +16 -0
  181. package/dist/pipeline/types.d.ts.map +1 -0
  182. package/dist/pipeline/types.js +16 -0
  183. package/dist/pipeline/types.js.map +1 -0
  184. package/dist/types/audit.d.ts +6 -6
  185. package/dist/workflow/index.d.ts.map +1 -1
  186. package/dist/workflow/index.js +48 -0
  187. package/dist/workflow/index.js.map +1 -1
  188. package/package.json +1 -1
  189. package/skills/PHASE_GATE_ENGINE_SPEC.md +113 -20
  190. package/skills/POPEYE_FULL_AUTONOMY_PIPELINE.md +66 -13
  191. package/src/pipeline/artifact-manager.ts +339 -0
  192. package/src/pipeline/artifact-validators.ts +224 -0
  193. package/src/pipeline/change-request.ts +119 -0
  194. package/src/pipeline/check-runner.ts +504 -0
  195. package/src/pipeline/command-resolver.ts +168 -0
  196. package/src/pipeline/consensus/consensus-runner.ts +317 -0
  197. package/src/pipeline/constitution.ts +109 -0
  198. package/src/pipeline/gate-engine.ts +347 -0
  199. package/src/pipeline/index.ts +82 -0
  200. package/src/pipeline/migration.ts +91 -0
  201. package/src/pipeline/orchestrator.ts +314 -0
  202. package/src/pipeline/packets/audit-report-builder.ts +47 -0
  203. package/src/pipeline/packets/consensus-packet-builder.ts +112 -0
  204. package/src/pipeline/packets/index.ts +15 -0
  205. package/src/pipeline/packets/plan-packet-builder.ts +52 -0
  206. package/src/pipeline/packets/rca-packet-builder.ts +38 -0
  207. package/src/pipeline/phases/architecture.ts +73 -0
  208. package/src/pipeline/phases/audit.ts +193 -0
  209. package/src/pipeline/phases/consensus-architecture.ts +104 -0
  210. package/src/pipeline/phases/consensus-master-plan.ts +100 -0
  211. package/src/pipeline/phases/consensus-role-plans.ts +105 -0
  212. package/src/pipeline/phases/done.ts +68 -0
  213. package/src/pipeline/phases/implementation.ts +48 -0
  214. package/src/pipeline/phases/index.ts +21 -0
  215. package/src/pipeline/phases/intake.ts +54 -0
  216. package/src/pipeline/phases/phase-context.ts +86 -0
  217. package/src/pipeline/phases/production-gate.ts +113 -0
  218. package/src/pipeline/phases/qa-validation.ts +63 -0
  219. package/src/pipeline/phases/recovery-loop.ts +118 -0
  220. package/src/pipeline/phases/review.ts +149 -0
  221. package/src/pipeline/phases/role-planning.ts +92 -0
  222. package/src/pipeline/phases/stuck.ts +62 -0
  223. package/src/pipeline/repo-snapshot.ts +395 -0
  224. package/src/pipeline/role-execution-adapter.ts +238 -0
  225. package/src/pipeline/skill-loader.ts +192 -0
  226. package/src/pipeline/skills/defaults.ts +215 -0
  227. package/src/pipeline/type-defs/artifacts.ts +81 -0
  228. package/src/pipeline/type-defs/audit.ts +67 -0
  229. package/src/pipeline/type-defs/checks.ts +47 -0
  230. package/src/pipeline/type-defs/enums.ts +62 -0
  231. package/src/pipeline/type-defs/index.ts +12 -0
  232. package/src/pipeline/type-defs/packets.ts +131 -0
  233. package/src/pipeline/type-defs/snapshot.ts +55 -0
  234. package/src/pipeline/type-defs/state.ts +165 -0
  235. package/src/pipeline/types.ts +16 -0
  236. package/src/workflow/index.ts +48 -0
  237. package/tests/pipeline/artifact-manager.test.ts +183 -0
  238. package/tests/pipeline/artifact-validators.test.ts +207 -0
  239. package/tests/pipeline/change-request.test.ts +180 -0
  240. package/tests/pipeline/check-runner.test.ts +157 -0
  241. package/tests/pipeline/command-resolver.test.ts +159 -0
  242. package/tests/pipeline/consensus-runner.test.ts +206 -0
  243. package/tests/pipeline/consensus-scoring.test.ts +163 -0
  244. package/tests/pipeline/constitution.test.ts +122 -0
  245. package/tests/pipeline/gate-engine.test.ts +195 -0
  246. package/tests/pipeline/migration.test.ts +133 -0
  247. package/tests/pipeline/orchestrator.test.ts +614 -0
  248. package/tests/pipeline/packets/builders.test.ts +347 -0
  249. package/tests/pipeline/repo-snapshot.test.ts +189 -0
  250. package/tests/pipeline/role-execution-adapter.test.ts +299 -0
  251. package/tests/pipeline/skill-loader.test.ts +186 -0
  252. package/tests/pipeline/start-env-checks.test.ts +123 -0
  253. package/tests/pipeline/types.test.ts +156 -0
@@ -0,0 +1,54 @@
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. Expand idea using existing workflow
31
+ const { expandIdea, createPlan } = await import('../../workflow/plan-mode.js');
32
+ const expandedIdea = await expandIdea(
33
+ context.state.specification ?? context.state.idea ?? '',
34
+ context.state.language,
35
+ );
36
+
37
+ // 4. Create master plan using existing workflow
38
+ const plan = await createPlan(expandedIdea, '', context.state.language);
39
+
40
+ // 5. Store master plan as artifact
41
+ const planEntry = artifactManager.createAndStoreText(
42
+ 'master_plan',
43
+ plan,
44
+ 'INTAKE',
45
+ );
46
+ artifacts.push(planEntry);
47
+ pipeline.artifacts.push(...artifacts);
48
+
49
+ return successResult('INTAKE', artifacts, 'Master Plan v1 created');
50
+ } catch (err) {
51
+ const message = err instanceof Error ? err.message : 'Unknown error during intake';
52
+ return failureResult('INTAKE', 'Failed to create master plan', message);
53
+ }
54
+ }
@@ -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,118 @@
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 rcaPrompt = [
37
+ debuggerSkill.systemPrompt,
38
+ '',
39
+ '## Failure Evidence',
40
+ failureEvidence,
41
+ '',
42
+ '## Instructions',
43
+ 'Produce a Root Cause Analysis:',
44
+ '1. Precise root cause',
45
+ '2. Origin phase',
46
+ '3. Responsible role',
47
+ '4. Corrective actions',
48
+ '5. Whether phase rewind is needed (and to which phase)',
49
+ '6. Prevention recommendation',
50
+ ].join('\n');
51
+
52
+ const rcaResult = await executePrompt(rcaPrompt);
53
+ const rcaResponse = rcaResult.response;
54
+
55
+ // 4. Build RCA packet
56
+ const rcaPacket = buildRCAPacket({
57
+ incidentSummary: `Gate failure at ${failedPhase ?? 'unknown'} (recovery iteration ${pipeline.recoveryCount})`,
58
+ symptoms: failedGateResult?.blockers ?? ['Gate failed'],
59
+ rootCause: rcaResponse.slice(0, 500),
60
+ responsibleLayer: failedPhase ?? 'IMPLEMENTATION',
61
+ originPhase: failedPhase ?? 'IMPLEMENTATION',
62
+ governanceGap: 'Detected during gate evaluation',
63
+ correctiveActions: ['See RCA report for details'],
64
+ prevention: 'See RCA report for details',
65
+ rewindTo: determineRewindTarget(rcaResponse, failedPhase),
66
+ });
67
+
68
+ // 5. Store RCA as artifacts
69
+ const rcaJsonEntry = artifactManager.createAndStoreJson(
70
+ 'rca_report',
71
+ rcaPacket,
72
+ 'RECOVERY_LOOP',
73
+ );
74
+ artifacts.push(rcaJsonEntry);
75
+
76
+ const rcaTextEntry = artifactManager.createAndStoreText(
77
+ 'rca_report',
78
+ `# RCA Report\n\n${rcaResponse}`,
79
+ 'RECOVERY_LOOP',
80
+ );
81
+ artifacts.push(rcaTextEntry);
82
+
83
+ pipeline.artifacts.push(...artifacts);
84
+
85
+ // 6. Journalist trigger
86
+ await triggerJournalist('RECOVERY_LOOP', artifacts, context);
87
+
88
+ return successResult(
89
+ 'RECOVERY_LOOP',
90
+ artifacts,
91
+ `RCA complete: recovery iteration ${pipeline.recoveryCount}`,
92
+ );
93
+ } catch (err) {
94
+ const message = err instanceof Error ? err.message : 'Unknown error';
95
+ return failureResult('RECOVERY_LOOP', 'Recovery loop failed', message);
96
+ }
97
+ }
98
+
99
+ /** Determine rewind target from RCA response */
100
+ function determineRewindTarget(
101
+ _rcaResponse: string,
102
+ failedPhase: PipelinePhase | undefined,
103
+ ): PipelinePhase | undefined {
104
+ // If the failure was in production gate or audit, rewind to implementation
105
+ if (failedPhase === 'PRODUCTION_GATE' || failedPhase === 'AUDIT') {
106
+ return 'IMPLEMENTATION';
107
+ }
108
+ // If in QA, rewind to implementation
109
+ if (failedPhase === 'QA_VALIDATION') {
110
+ return 'IMPLEMENTATION';
111
+ }
112
+ // For consensus failures, rewind to the phase being validated
113
+ if (failedPhase === 'CONSENSUS_MASTER_PLAN') return 'INTAKE';
114
+ if (failedPhase === 'CONSENSUS_ARCHITECTURE') return 'ARCHITECTURE';
115
+ if (failedPhase === 'CONSENSUS_ROLE_PLANS') return 'ROLE_PLANNING';
116
+
117
+ return undefined;
118
+ }
@@ -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
+ }
@@ -0,0 +1,92 @@
1
+ /**
2
+ * ROLE_PLANNING phase — produce deterministic implementation plans by role.
3
+ * Runs per-role: DB, BE, FE, Website, QA. Creates role_plan artifacts.
4
+ */
5
+
6
+ import { existsSync, readFileSync } from 'node:fs';
7
+ import { join } from 'node:path';
8
+
9
+ import type { PipelineRole } from '../types.js';
10
+ import type { PhaseContext, PhaseResult } from './phase-context.js';
11
+ import { successResult, failureResult } from './phase-context.js';
12
+
13
+ /** Roles that produce implementation plans */
14
+ const PLANNING_ROLES: PipelineRole[] = [
15
+ 'DB_EXPERT',
16
+ 'BACKEND_PROGRAMMER',
17
+ 'FRONTEND_PROGRAMMER',
18
+ 'WEBSITE_PROGRAMMER',
19
+ 'QA_TESTER',
20
+ ];
21
+
22
+ export async function runRolePlanning(context: PhaseContext): Promise<PhaseResult> {
23
+ const { pipeline, artifactManager, skillLoader, projectDir } = context;
24
+ const artifacts = [];
25
+
26
+ try {
27
+ // Read architecture doc for context
28
+ const archArtifact = pipeline.artifacts.find((a) => a.type === 'architecture');
29
+ let architectureContent = '';
30
+ if (archArtifact) {
31
+ const fullPath = join(projectDir, archArtifact.path);
32
+ if (existsSync(fullPath)) {
33
+ architectureContent = readFileSync(fullPath, 'utf-8');
34
+ }
35
+ }
36
+
37
+ // Read master plan for context
38
+ const masterPlanArtifact = pipeline.artifacts.find((a) => a.type === 'master_plan');
39
+ let masterPlanContent = '';
40
+ if (masterPlanArtifact) {
41
+ const fullPath = join(projectDir, masterPlanArtifact.path);
42
+ if (existsSync(fullPath)) {
43
+ masterPlanContent = readFileSync(fullPath, 'utf-8');
44
+ }
45
+ }
46
+
47
+ const { executePrompt } = await import('../../adapters/claude.js');
48
+
49
+ // Generate plan for each role
50
+ for (const role of PLANNING_ROLES) {
51
+ // Skip website if not in active roles
52
+ if (role === 'WEBSITE_PROGRAMMER' && !pipeline.activeRoles.includes('WEBSITE_PROGRAMMER')) {
53
+ continue;
54
+ }
55
+
56
+ const skill = skillLoader.loadSkill(role);
57
+
58
+ const planPrompt = [
59
+ skill.systemPrompt,
60
+ '',
61
+ '## Master Plan',
62
+ masterPlanContent.slice(0, 5000),
63
+ '',
64
+ '## Architecture',
65
+ architectureContent.slice(0, 5000),
66
+ '',
67
+ '## Instructions',
68
+ `Create your ${role} implementation plan. Include:`,
69
+ '- Deterministic file-level outputs',
70
+ '- Specific tasks with acceptance criteria',
71
+ '- Dependencies on other roles',
72
+ '- Test requirements',
73
+ ].join('\n');
74
+
75
+ const planResult = await executePrompt(planPrompt);
76
+ const plan = planResult.response;
77
+
78
+ const entry = artifactManager.createAndStoreText(
79
+ 'role_plan',
80
+ `# ${role} Plan\n\n${plan}`,
81
+ 'ROLE_PLANNING',
82
+ );
83
+ artifacts.push(entry);
84
+ }
85
+
86
+ pipeline.artifacts.push(...artifacts);
87
+ return successResult('ROLE_PLANNING', artifacts, `Created ${artifacts.length} role plans`);
88
+ } catch (err) {
89
+ const message = err instanceof Error ? err.message : 'Unknown error';
90
+ return failureResult('ROLE_PLANNING', 'Role planning failed', message);
91
+ }
92
+ }