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,123 @@
1
+ /**
2
+ * Start & Env Checks tests — application start check,
3
+ * environment variable validation from .env.example.
4
+ */
5
+
6
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
7
+ import { mkdirSync, writeFileSync, rmSync, existsSync } from 'node:fs';
8
+ import { join } from 'node:path';
9
+ import { runStartCheck, runEnvCheck } from '../../src/pipeline/check-runner.js';
10
+
11
+ const TEST_DIR = join(process.cwd(), 'tmp-start-env-test');
12
+
13
+ beforeEach(() => {
14
+ mkdirSync(TEST_DIR, { recursive: true });
15
+ });
16
+
17
+ afterEach(() => {
18
+ if (existsSync(TEST_DIR)) {
19
+ rmSync(TEST_DIR, { recursive: true, force: true });
20
+ }
21
+ });
22
+
23
+ describe('runStartCheck', () => {
24
+ it('should pass when process stays alive past timeout', async () => {
25
+ // 'sleep 10' will stay alive for 10s, well past our 1s timeout
26
+ const result = await runStartCheck('sleep 10', TEST_DIR, { timeoutMs: 1000 });
27
+ expect(result.check_type).toBe('start');
28
+ expect(result.status).toBe('pass');
29
+ expect(result.exit_code).toBe(0);
30
+ }, 10000);
31
+
32
+ it('should fail when process crashes immediately', async () => {
33
+ const result = await runStartCheck('exit 1', TEST_DIR, { timeoutMs: 3000 });
34
+ expect(result.check_type).toBe('start');
35
+ expect(result.status).toBe('fail');
36
+ }, 10000);
37
+
38
+ it('should fail for dangerous commands', async () => {
39
+ const result = await runStartCheck('sudo rm -rf /', TEST_DIR);
40
+ expect(result.status).toBe('fail');
41
+ expect(result.stderr_summary).toContain('rejected');
42
+ });
43
+
44
+ it('should return start check type', async () => {
45
+ const result = await runStartCheck('echo hello', TEST_DIR, { timeoutMs: 1000 });
46
+ expect(result.check_type).toBe('start');
47
+ }, 5000);
48
+ });
49
+
50
+ describe('runEnvCheck', () => {
51
+ it('should pass when no .env.example exists', () => {
52
+ const result = runEnvCheck(TEST_DIR);
53
+ expect(result.check_type).toBe('env_check');
54
+ expect(result.status).toBe('pass');
55
+ expect(result.stderr_summary).toContain('No .env.example');
56
+ });
57
+
58
+ it('should fail when .env.example exists but .env is missing', () => {
59
+ writeFileSync(join(TEST_DIR, '.env.example'), 'API_KEY=\nDB_URL=');
60
+
61
+ const result = runEnvCheck(TEST_DIR);
62
+ expect(result.status).toBe('fail');
63
+ expect(result.stderr_summary).toContain('.env file not found');
64
+ expect(result.stderr_summary).toContain('API_KEY');
65
+ expect(result.stderr_summary).toContain('DB_URL');
66
+ });
67
+
68
+ it('should pass when all required vars are present', () => {
69
+ writeFileSync(join(TEST_DIR, '.env.example'), 'API_KEY=your-key\nDB_URL=postgres://');
70
+ writeFileSync(join(TEST_DIR, '.env'), 'API_KEY=real-key\nDB_URL=postgres://localhost/db');
71
+
72
+ const result = runEnvCheck(TEST_DIR);
73
+ expect(result.status).toBe('pass');
74
+ });
75
+
76
+ it('should fail when required vars are missing from .env', () => {
77
+ writeFileSync(join(TEST_DIR, '.env.example'), 'API_KEY=\nDB_URL=\nSECRET=');
78
+ writeFileSync(join(TEST_DIR, '.env'), 'API_KEY=real-key');
79
+
80
+ const result = runEnvCheck(TEST_DIR);
81
+ expect(result.status).toBe('fail');
82
+ expect(result.stderr_summary).toContain('Missing vars');
83
+ expect(result.stderr_summary).toContain('DB_URL');
84
+ expect(result.stderr_summary).toContain('SECRET');
85
+ });
86
+
87
+ it('should warn about empty vars but still pass', () => {
88
+ writeFileSync(join(TEST_DIR, '.env.example'), 'API_KEY=\nOPTIONAL_VAR=');
89
+ writeFileSync(join(TEST_DIR, '.env'), 'API_KEY=real-key\nOPTIONAL_VAR=');
90
+
91
+ const result = runEnvCheck(TEST_DIR);
92
+ expect(result.status).toBe('pass');
93
+ expect(result.stderr_summary).toContain('Empty vars');
94
+ expect(result.stderr_summary).toContain('OPTIONAL_VAR');
95
+ });
96
+
97
+ it('should skip comments in .env.example', () => {
98
+ writeFileSync(
99
+ join(TEST_DIR, '.env.example'),
100
+ '# Database config\nDB_URL=postgres://\n# API keys\nAPI_KEY=',
101
+ );
102
+ writeFileSync(join(TEST_DIR, '.env'), 'DB_URL=postgres://localhost\nAPI_KEY=key123');
103
+
104
+ const result = runEnvCheck(TEST_DIR);
105
+ expect(result.status).toBe('pass');
106
+ });
107
+
108
+ it('should handle quoted values in .env', () => {
109
+ writeFileSync(join(TEST_DIR, '.env.example'), 'SECRET=');
110
+ writeFileSync(join(TEST_DIR, '.env'), 'SECRET="my-secret-value"');
111
+
112
+ const result = runEnvCheck(TEST_DIR);
113
+ expect(result.status).toBe('pass');
114
+ });
115
+
116
+ it('should skip empty lines in .env.example', () => {
117
+ writeFileSync(join(TEST_DIR, '.env.example'), '\nAPI_KEY=\n\nDB_URL=\n\n');
118
+ writeFileSync(join(TEST_DIR, '.env'), 'API_KEY=key\nDB_URL=url');
119
+
120
+ const result = runEnvCheck(TEST_DIR);
121
+ expect(result.status).toBe('pass');
122
+ });
123
+ });
@@ -0,0 +1,156 @@
1
+ /**
2
+ * Pipeline Types tests — Zod schema validation for all types.
3
+ */
4
+
5
+ import { describe, it, expect } from 'vitest';
6
+ import {
7
+ PipelinePhaseSchema,
8
+ PipelineRoleSchema,
9
+ ArtifactTypeSchema,
10
+ GateCheckTypeSchema,
11
+ createDefaultPipelineState,
12
+ } from '../../src/pipeline/types.js';
13
+
14
+ describe('PipelineTypes', () => {
15
+ describe('PipelinePhaseSchema', () => {
16
+ it('should accept valid phases', () => {
17
+ const phases = [
18
+ 'INTAKE', 'CONSENSUS_MASTER_PLAN', 'ARCHITECTURE',
19
+ 'CONSENSUS_ARCHITECTURE', 'ROLE_PLANNING', 'CONSENSUS_ROLE_PLANS',
20
+ 'IMPLEMENTATION', 'QA_VALIDATION', 'REVIEW', 'AUDIT',
21
+ 'PRODUCTION_GATE', 'RECOVERY_LOOP', 'DONE', 'STUCK',
22
+ ];
23
+
24
+ for (const phase of phases) {
25
+ const result = PipelinePhaseSchema.safeParse(phase);
26
+ expect(result.success).toBe(true);
27
+ }
28
+ });
29
+
30
+ it('should reject invalid phases', () => {
31
+ const result = PipelinePhaseSchema.safeParse('INVALID_PHASE');
32
+ expect(result.success).toBe(false);
33
+ });
34
+
35
+ it('should reject non-string values', () => {
36
+ expect(PipelinePhaseSchema.safeParse(42).success).toBe(false);
37
+ expect(PipelinePhaseSchema.safeParse(null).success).toBe(false);
38
+ });
39
+ });
40
+
41
+ describe('PipelineRoleSchema', () => {
42
+ it('should accept all valid roles', () => {
43
+ const roles = [
44
+ 'DISPATCHER', 'ARCHITECT', 'DB_EXPERT',
45
+ 'BACKEND_PROGRAMMER', 'FRONTEND_PROGRAMMER',
46
+ 'WEBSITE_PROGRAMMER', 'QA_TESTER',
47
+ 'REVIEWER', 'ARBITRATOR', 'DEBUGGER',
48
+ 'AUDITOR', 'JOURNALIST', 'RELEASE_MANAGER',
49
+ 'MARKETING_EXPERT', 'SOCIAL_EXPERT', 'UI_UX_SPECIALIST',
50
+ ];
51
+
52
+ for (const role of roles) {
53
+ const result = PipelineRoleSchema.safeParse(role);
54
+ expect(result.success).toBe(true);
55
+ }
56
+ });
57
+
58
+ it('should reject invalid roles', () => {
59
+ expect(PipelineRoleSchema.safeParse('INVALID_ROLE').success).toBe(false);
60
+ });
61
+
62
+ it('should have exactly 16 roles', () => {
63
+ expect(PipelineRoleSchema.options.length).toBe(16);
64
+ });
65
+ });
66
+
67
+ describe('createDefaultPipelineState', () => {
68
+ it('should create state with INTAKE phase', () => {
69
+ const state = createDefaultPipelineState();
70
+ expect(state.pipelinePhase).toBe('INTAKE');
71
+ });
72
+
73
+ it('should create state with empty artifacts', () => {
74
+ const state = createDefaultPipelineState();
75
+ expect(state.artifacts).toEqual([]);
76
+ });
77
+
78
+ it('should create state with zero recovery count', () => {
79
+ const state = createDefaultPipelineState();
80
+ expect(state.recoveryCount).toBe(0);
81
+ });
82
+
83
+ it('should create state with max recovery of 5', () => {
84
+ const state = createDefaultPipelineState();
85
+ expect(state.maxRecoveryIterations).toBe(5);
86
+ });
87
+
88
+ it('should create state with empty gate results', () => {
89
+ const state = createDefaultPipelineState();
90
+ expect(state.gateResults).toEqual({});
91
+ expect(state.gateChecks).toEqual({});
92
+ });
93
+
94
+ it('should create state with empty active roles', () => {
95
+ const state = createDefaultPipelineState();
96
+ expect(state.activeRoles).toEqual([]);
97
+ });
98
+
99
+ it('should create state with empty constitution hash', () => {
100
+ const state = createDefaultPipelineState();
101
+ expect(state.constitutionHash).toBe('');
102
+ });
103
+
104
+ it('should return independent instances', () => {
105
+ const s1 = createDefaultPipelineState();
106
+ const s2 = createDefaultPipelineState();
107
+ s1.artifacts.push({} as any);
108
+ expect(s2.artifacts).toHaveLength(0);
109
+ });
110
+ });
111
+
112
+ describe('ArtifactTypeSchema (v1.1)', () => {
113
+ it('should accept constitution artifact type', () => {
114
+ expect(ArtifactTypeSchema.safeParse('constitution').success).toBe(true);
115
+ });
116
+
117
+ it('should accept change_request artifact type', () => {
118
+ expect(ArtifactTypeSchema.safeParse('change_request').success).toBe(true);
119
+ });
120
+
121
+ it('should still accept all original artifact types', () => {
122
+ const originals = [
123
+ 'master_plan', 'architecture', 'role_plan', 'consensus',
124
+ 'audit_report', 'repo_snapshot', 'build_check', 'qa_validation',
125
+ ];
126
+ for (const t of originals) {
127
+ expect(ArtifactTypeSchema.safeParse(t).success).toBe(true);
128
+ }
129
+ });
130
+
131
+ it('should reject unknown artifact types', () => {
132
+ expect(ArtifactTypeSchema.safeParse('unknown_type').success).toBe(false);
133
+ });
134
+ });
135
+
136
+ describe('GateCheckTypeSchema (v1.1)', () => {
137
+ it('should accept start check type', () => {
138
+ expect(GateCheckTypeSchema.safeParse('start').success).toBe(true);
139
+ });
140
+
141
+ it('should accept env_check type', () => {
142
+ expect(GateCheckTypeSchema.safeParse('env_check').success).toBe(true);
143
+ });
144
+
145
+ it('should still accept all original check types', () => {
146
+ const originals = ['build', 'test', 'lint', 'typecheck', 'migration', 'placeholder_scan'];
147
+ for (const t of originals) {
148
+ expect(GateCheckTypeSchema.safeParse(t).success).toBe(true);
149
+ }
150
+ });
151
+
152
+ it('should reject unknown check types', () => {
153
+ expect(GateCheckTypeSchema.safeParse('unknown_check').success).toBe(false);
154
+ });
155
+ });
156
+ });
@@ -141,7 +141,7 @@ describe('DEFAULT_CONSENSUS_CONFIG', () => {
141
141
  it('should have valid default values', () => {
142
142
  expect(DEFAULT_CONSENSUS_CONFIG.threshold).toBe(95);
143
143
  expect(DEFAULT_CONSENSUS_CONFIG.maxIterations).toBe(10);
144
- expect(DEFAULT_CONSENSUS_CONFIG.openaiModel).toBe('gpt-4o');
144
+ expect(DEFAULT_CONSENSUS_CONFIG.openaiModel).toBe('gpt-4.1');
145
145
  expect(DEFAULT_CONSENSUS_CONFIG.temperature).toBe(0.3);
146
146
  expect(DEFAULT_CONSENSUS_CONFIG.maxTokens).toBe(4096);
147
147
  });
@@ -0,0 +1,162 @@
1
+ /**
2
+ * Fix B tests — new projects use pipeline from start.
3
+ * Verifies that runWorkflow() bootstraps state before pipeline.
4
+ */
5
+
6
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
7
+
8
+ // Mock the modules before importing
9
+ vi.mock('../../src/state/index.js', () => ({
10
+ loadProject: vi.fn(),
11
+ projectExists: vi.fn(),
12
+ getProgress: vi.fn(),
13
+ resetToPhase: vi.fn(),
14
+ deleteProject: vi.fn(),
15
+ verifyProjectCompletion: vi.fn(),
16
+ resetIncompleteProject: vi.fn(),
17
+ createProject: vi.fn(),
18
+ }));
19
+
20
+ vi.mock('../../src/pipeline/orchestrator.js', () => ({
21
+ runPipeline: vi.fn(),
22
+ resumePipeline: vi.fn(),
23
+ }));
24
+
25
+ vi.mock('../../src/workflow/plan-mode.js', () => ({
26
+ runPlanMode: vi.fn(),
27
+ resumePlanMode: vi.fn(),
28
+ }));
29
+
30
+ vi.mock('../../src/workflow/execution-mode.js', () => ({
31
+ runExecutionMode: vi.fn(),
32
+ resumeExecutionMode: vi.fn(),
33
+ executeSingleTask: vi.fn(),
34
+ }));
35
+
36
+ vi.mock('../../src/workflow/workflow-logger.js', () => ({
37
+ getWorkflowLogger: () => ({
38
+ stageStart: vi.fn(),
39
+ stageComplete: vi.fn(),
40
+ stageFailed: vi.fn(),
41
+ info: vi.fn(),
42
+ }),
43
+ }));
44
+
45
+ describe('Fix B: New projects use pipeline from start', () => {
46
+ beforeEach(() => {
47
+ vi.resetAllMocks();
48
+ // Default: pipeline mode enabled
49
+ delete process.env.POPEYE_LEGACY_WORKFLOW;
50
+ });
51
+
52
+ it('should create state and run pipeline when state does not exist', async () => {
53
+ const { loadProject, createProject } = await import('../../src/state/index.js');
54
+ const { runPipeline } = await import('../../src/pipeline/orchestrator.js');
55
+
56
+ const mockState = {
57
+ id: 'test-id',
58
+ name: 'test-project',
59
+ idea: 'Build something',
60
+ language: 'python' as const,
61
+ phase: 'plan' as const,
62
+ status: 'pending' as const,
63
+ milestones: [],
64
+ currentMilestone: null,
65
+ currentTask: null,
66
+ consensusHistory: [],
67
+ createdAt: new Date().toISOString(),
68
+ updatedAt: new Date().toISOString(),
69
+ };
70
+
71
+ // loadProject fails (no state.json) on first call, succeeds after create
72
+ vi.mocked(loadProject)
73
+ .mockRejectedValueOnce(new Error('No project found'))
74
+ .mockResolvedValue(mockState as any);
75
+
76
+ vi.mocked(createProject).mockResolvedValue(mockState as any);
77
+ vi.mocked(runPipeline).mockResolvedValue({
78
+ success: true,
79
+ finalPhase: 'DONE',
80
+ artifacts: [],
81
+ recoveryIterations: 0,
82
+ });
83
+
84
+ const { runWorkflow } = await import('../../src/workflow/index.js');
85
+
86
+ const result = await runWorkflow(
87
+ { idea: 'Build something', name: 'test-project', language: 'python', openaiModel: 'gpt-4o' },
88
+ { projectDir: '/tmp/test-project' },
89
+ );
90
+
91
+ expect(createProject).toHaveBeenCalledWith(
92
+ expect.objectContaining({ idea: 'Build something' }),
93
+ '/tmp/test-project',
94
+ );
95
+ expect(runPipeline).toHaveBeenCalledWith(
96
+ expect.objectContaining({
97
+ projectDir: '/tmp/test-project',
98
+ state: mockState,
99
+ }),
100
+ );
101
+ expect(result.success).toBe(true);
102
+ });
103
+
104
+ it('should use existing state when state already exists', async () => {
105
+ const { loadProject, createProject } = await import('../../src/state/index.js');
106
+ const { runPipeline } = await import('../../src/pipeline/orchestrator.js');
107
+
108
+ const existingState = {
109
+ id: 'existing-id',
110
+ name: 'existing-project',
111
+ phase: 'execution' as const,
112
+ };
113
+
114
+ vi.mocked(loadProject).mockResolvedValue(existingState as any);
115
+ vi.mocked(runPipeline).mockResolvedValue({
116
+ success: true,
117
+ finalPhase: 'DONE',
118
+ artifacts: [],
119
+ recoveryIterations: 0,
120
+ });
121
+
122
+ const { runWorkflow } = await import('../../src/workflow/index.js');
123
+
124
+ await runWorkflow(
125
+ { idea: 'Build something', name: 'existing-project', language: 'python', openaiModel: 'gpt-4o' },
126
+ { projectDir: '/tmp/existing-project' },
127
+ );
128
+
129
+ // Should NOT call createProject since state exists
130
+ expect(createProject).not.toHaveBeenCalled();
131
+ expect(runPipeline).toHaveBeenCalled();
132
+ });
133
+
134
+ it('should fall through to legacy workflow when POPEYE_LEGACY_WORKFLOW=1', async () => {
135
+ process.env.POPEYE_LEGACY_WORKFLOW = '1';
136
+
137
+ const { runPipeline } = await import('../../src/pipeline/orchestrator.js');
138
+ const { runPlanMode } = await import('../../src/workflow/plan-mode.js');
139
+ const { runExecutionMode } = await import('../../src/workflow/execution-mode.js');
140
+
141
+ vi.mocked(runPlanMode).mockResolvedValue({
142
+ success: true,
143
+ state: { phase: 'execution' } as any,
144
+ });
145
+ vi.mocked(runExecutionMode).mockResolvedValue({
146
+ success: true,
147
+ state: { phase: 'complete' } as any,
148
+ completedTasks: 5,
149
+ failedTasks: 0,
150
+ });
151
+
152
+ const { runWorkflow } = await import('../../src/workflow/index.js');
153
+
154
+ await runWorkflow(
155
+ { idea: 'Build something', name: 'test', language: 'python', openaiModel: 'gpt-4o' },
156
+ { projectDir: '/tmp/test' },
157
+ );
158
+
159
+ // Pipeline should NOT be called in legacy mode
160
+ expect(runPipeline).not.toHaveBeenCalled();
161
+ });
162
+ });