@oisincoveney/pipeline 3.24.2 → 4.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 (382) hide show
  1. package/README.md +14 -2
  2. package/defaults/pipeline.yaml +23 -5
  3. package/defaults/profiles.yaml +104 -21
  4. package/dist/argo-graph.js +90 -88
  5. package/dist/argo-submit.d.ts +110 -138
  6. package/dist/argo-submit.js +363 -378
  7. package/dist/argo-workflow.d.ts +156 -177
  8. package/dist/argo-workflow.js +96 -138
  9. package/dist/backlog.js +5 -4
  10. package/dist/bench/eval-report.js +21 -12
  11. package/dist/claude-settings-config.js +23 -31
  12. package/dist/claude-user-config.js +6 -16
  13. package/dist/cli/bootstrap-commands.js +3 -3
  14. package/dist/cli/doctor.d.ts +1 -1
  15. package/dist/cli/doctor.js +176 -171
  16. package/dist/cli/factory-commands.js +13 -13
  17. package/dist/cli/format.js +92 -86
  18. package/dist/cli/loop-commands.js +21 -21
  19. package/dist/cli/mcp-gateway-commands.js +12 -12
  20. package/dist/cli/plan-commands.js +85 -116
  21. package/dist/cli/program.d.ts +3 -3
  22. package/dist/cli/program.js +41 -43
  23. package/dist/cli/run-command.d.ts +1 -1
  24. package/dist/cli/run-command.js +25 -25
  25. package/dist/cli/run-commands.js +31 -29
  26. package/dist/cli/run-resolver.d.ts +1 -1
  27. package/dist/cli/run-resolver.js +30 -32
  28. package/dist/cli/run-service.d.ts +2 -3
  29. package/dist/cli/run-service.js +229 -239
  30. package/dist/cli/submit-options.js +85 -83
  31. package/dist/cluster-doctor.js +147 -175
  32. package/dist/codex-config.js +24 -30
  33. package/dist/commands/bench-command.js +9 -7
  34. package/dist/commands/coordinator-command.js +35 -0
  35. package/dist/commands/pipeline-command.js +13 -7
  36. package/dist/commands/runner-command-command.js +39 -24
  37. package/dist/commands/runner-node-command.js +31 -0
  38. package/dist/commands/ticket/complete.js +29 -33
  39. package/dist/commands/ticket/create.js +84 -82
  40. package/dist/commands/ticket/graph-check.js +11 -11
  41. package/dist/commands/ticket/next.js +36 -36
  42. package/dist/commands/ticket/sequence.js +11 -12
  43. package/dist/commands/ticket/shared.d.ts +5 -2
  44. package/dist/commands/ticket/shared.js +63 -66
  45. package/dist/commands/ticket/start.js +58 -67
  46. package/dist/commands/ticket-command.js +2 -2
  47. package/dist/config/defaults.d.ts +139 -140
  48. package/dist/config/defaults.js +81 -80
  49. package/dist/config/lint.js +52 -64
  50. package/dist/config/load.d.ts +4 -5
  51. package/dist/config/load.js +64 -74
  52. package/dist/config/schema/catalog.d.ts +2 -1
  53. package/dist/config/schema/catalog.js +3 -2
  54. package/dist/config/schema/mcp.js +46 -52
  55. package/dist/config/schemas.d.ts +382 -528
  56. package/dist/config/schemas.js +400 -398
  57. package/dist/config/validate.d.ts +1 -2
  58. package/dist/config/validate.js +236 -201
  59. package/dist/config.d.ts +2 -2
  60. package/dist/context/repo-map.js +105 -119
  61. package/dist/coordinator/composition.js +169 -0
  62. package/dist/coordinator/config.js +71 -0
  63. package/dist/coordinator/run-owner.js +64 -0
  64. package/dist/coordinator/wave-advance.js +148 -0
  65. package/dist/coordinator/wave-scheduler.js +50 -0
  66. package/dist/credentials/broker.d.ts +6 -8
  67. package/dist/credentials/broker.js +17 -16
  68. package/dist/credentials/codex-config.js +15 -19
  69. package/dist/credentials/file-targets.js +9 -15
  70. package/dist/credentials/local-codex-auth-sync.js +55 -58
  71. package/dist/credentials/opencode-config.js +28 -32
  72. package/dist/credentials/runner.js +13 -13
  73. package/dist/effect-sync-errors.js +28 -0
  74. package/dist/factory/create-experiment.js +285 -121
  75. package/dist/factory/exec.js +10 -12
  76. package/dist/factory/git-credentials.js +4 -4
  77. package/dist/factory/stamp-answers.js +10 -11
  78. package/dist/factory/template-update.js +65 -44
  79. package/dist/factory-lane.d.ts +26 -40
  80. package/dist/factory-lane.js +26 -25
  81. package/dist/gates.js +3 -3
  82. package/dist/git-remote-url.js +17 -19
  83. package/dist/hooks.d.ts +26 -26
  84. package/dist/hooks.js +20 -22
  85. package/dist/index.d.ts +4 -3
  86. package/dist/index.js +27 -36
  87. package/dist/install-commands/claude-code.js +100 -92
  88. package/dist/install-commands/host-selection.js +3 -6
  89. package/dist/install-commands/opencode.js +264 -259
  90. package/dist/install-commands/planner.js +163 -181
  91. package/dist/install-commands/result-format.js +1 -3
  92. package/dist/install-commands/shared.js +25 -42
  93. package/dist/install-commands/writer.js +22 -25
  94. package/dist/install-commands.js +8 -8
  95. package/dist/jscpd-output.js +29 -0
  96. package/dist/json-config-merge.js +14 -20
  97. package/dist/json-line-values.js +17 -6
  98. package/dist/loop/argo-poll.d.ts +0 -1
  99. package/dist/loop/argo-poll.js +15 -95
  100. package/dist/loop/backlog-records.js +1 -3
  101. package/dist/loop/controller-deps.js +150 -161
  102. package/dist/loop/controller.js +164 -186
  103. package/dist/loop/gh-checks.js +62 -61
  104. package/dist/loop/gh-runner.js +22 -25
  105. package/dist/loop/loop-command.js +66 -58
  106. package/dist/loop/loop-controller-entrypoint.js +29 -30
  107. package/dist/loop/merge.js +36 -40
  108. package/dist/loop/run-terminal-poll.js +69 -0
  109. package/dist/mcp/gateway-config.js +25 -29
  110. package/dist/mcp/gateway-doctor.js +77 -119
  111. package/dist/mcp/gateway-reconcile.js +17 -22
  112. package/dist/mcp/gateway-runtime.js +1 -3
  113. package/dist/mcp/host-config.js +37 -40
  114. package/dist/mcp/host-renderers.js +10 -18
  115. package/dist/mcp/repo-local-backends.js +51 -54
  116. package/dist/mcp/toolhive-vmcp.js +39 -39
  117. package/dist/model-resolver.js +29 -33
  118. package/dist/moka-global-config.d.ts +78 -55
  119. package/dist/moka-global-config.js +93 -92
  120. package/dist/moka-submit.d.ts +2179 -866
  121. package/dist/moka-submit.js +97 -99
  122. package/dist/opencode-project-config.js +34 -40
  123. package/dist/package-assets.js +1 -3
  124. package/dist/path-refs.js +2 -2
  125. package/dist/pipeline-init.js +25 -25
  126. package/dist/pipeline-runtime.d.ts +15 -14
  127. package/dist/pipeline-runtime.js +51 -50
  128. package/dist/planned-node.js +6 -3
  129. package/dist/planning/compile.d.ts +5 -5
  130. package/dist/planning/compile.js +140 -139
  131. package/dist/planning/dependency-refs.js +5 -5
  132. package/dist/planning/generate.d.ts +1296 -1296
  133. package/dist/planning/generate.js +307 -314
  134. package/dist/planning/graph.d.ts +0 -1
  135. package/dist/planning/graph.js +131 -149
  136. package/dist/remote/argo/model.d.ts +104 -122
  137. package/dist/remote/argo/model.js +205 -197
  138. package/dist/remote/argo/policy.js +39 -47
  139. package/dist/remote/argo/storage.js +81 -85
  140. package/dist/remote/jobs/execution-identity.js +70 -0
  141. package/dist/remote/jobs/job-outcome.js +108 -0
  142. package/dist/remote/jobs/manifest.js +96 -0
  143. package/dist/remote/jobs/model.d.ts +158 -0
  144. package/dist/remote/jobs/model.js +162 -0
  145. package/dist/remote/jobs/node-bootstrap.js +213 -0
  146. package/dist/remote/jobs/policy.js +123 -0
  147. package/dist/remote/jobs/reconcile.js +100 -0
  148. package/dist/remote/jobs/run-spec-client.js +64 -0
  149. package/dist/remote/jobs/run-spec-path.js +31 -0
  150. package/dist/remote/jobs/run-spec-server.d.ts +34 -0
  151. package/dist/remote/jobs/run-spec-server.js +116 -0
  152. package/dist/remote/jobs/submit.d.ts +23 -0
  153. package/dist/remote/jobs/submit.js +116 -0
  154. package/dist/remote/jobs/watch.js +59 -0
  155. package/dist/remote/submit/argo-submission.d.ts +3 -1
  156. package/dist/remote/submit/argo-submission.js +53 -58
  157. package/dist/remote/submit/compilation.d.ts +2 -0
  158. package/dist/remote/submit/compilation.js +46 -49
  159. package/dist/remote/submit/event-boundary.js +62 -76
  160. package/dist/remote/submit/hook-events.d.ts +6 -0
  161. package/dist/remote/submit/io.d.ts +7 -1
  162. package/dist/remote/submit/io.js +40 -43
  163. package/dist/remote/submit/jobs-submission.d.ts +59 -0
  164. package/dist/remote/submit/jobs-submission.js +97 -0
  165. package/dist/remote/submit/jobs-submit-result.d.ts +25 -0
  166. package/dist/remote/submit/jobs-submit-result.js +34 -0
  167. package/dist/remote/submit/options.d.ts +49 -0
  168. package/dist/remote/submit/options.js +27 -0
  169. package/dist/remote/submit/service.d.ts +40 -1
  170. package/dist/remote/submit/service.js +67 -49
  171. package/dist/run-control/command-context.js +6 -8
  172. package/dist/run-control/commands.js +10 -10
  173. package/dist/run-control/contracts.d.ts +52 -101
  174. package/dist/run-control/contracts.js +83 -69
  175. package/dist/run-control/detach.js +66 -72
  176. package/dist/run-control/execution-store.js +0 -0
  177. package/dist/run-control/file-errors.js +1 -3
  178. package/dist/run-control/logical-segment.js +3 -3
  179. package/dist/run-control/next-node.js +67 -78
  180. package/dist/run-control/postgres/postgres-run-control-store.js +196 -225
  181. package/dist/run-control/resume-command.js +34 -41
  182. package/dist/run-control/run-artifacts-command.js +84 -105
  183. package/dist/run-control/run-command-domain.js +7 -11
  184. package/dist/run-control/run-control-store.js +9 -9
  185. package/dist/run-control/run-query-command.js +73 -100
  186. package/dist/run-control/run-record.js +5 -3
  187. package/dist/run-control/run-state-lock.js +5 -5
  188. package/dist/run-control/runtime-event-projection.js +38 -50
  189. package/dist/run-control/runtime-reporter.js +86 -102
  190. package/dist/run-control/stop-command.js +42 -53
  191. package/dist/run-control/store-fs-effects.js +3 -1
  192. package/dist/run-control/store-manifest.js +38 -13
  193. package/dist/run-control/store-paths.js +3 -3
  194. package/dist/run-control/store.js +1 -1
  195. package/dist/run-control/submit-result.js +21 -21
  196. package/dist/run-control/supervisor.js +78 -68
  197. package/dist/run-control/workspace.js +2 -2
  198. package/dist/run-state/git-refs.js +258 -307
  199. package/dist/runner/opencode-excludes.js +4 -4
  200. package/dist/runner/subprocess-result.js +28 -37
  201. package/dist/runner/subprocess.js +41 -41
  202. package/dist/runner/timeouts.js +14 -13
  203. package/dist/runner-command/dynamic-command.js +46 -39
  204. package/dist/runner-command/environment-commands.js +91 -0
  205. package/dist/runner-command/finalize.js +174 -153
  206. package/dist/runner-command/lifecycle-context.js +115 -130
  207. package/dist/runner-command/lifecycle.js +78 -72
  208. package/dist/runner-command/pre-schedule.js +203 -223
  209. package/dist/runner-command/run.js +450 -448
  210. package/dist/runner-command/schedule-source-options.js +8 -10
  211. package/dist/runner-command/select-ready-wave.js +39 -30
  212. package/dist/runner-command/task-descriptor.js +11 -17
  213. package/dist/runner-command-contract.d.ts +147 -157
  214. package/dist/runner-command-contract.js +403 -411
  215. package/dist/runner-event-schema.d.ts +364 -505
  216. package/dist/runner-event-schema.js +187 -175
  217. package/dist/runner-event-sink.js +37 -43
  218. package/dist/runner-output.js +6 -6
  219. package/dist/runner.d.ts +57 -37
  220. package/dist/runner.js +176 -127
  221. package/dist/runtime/actor-ids.d.ts +1 -0
  222. package/dist/runtime/actor-ids.js +2 -2
  223. package/dist/runtime/agent-node/agent-node.js +99 -110
  224. package/dist/runtime/agent-node/handoff-finalization.js +23 -24
  225. package/dist/runtime/agent-node/model-selection.js +19 -22
  226. package/dist/runtime/agent-node/output-finalization.js +174 -204
  227. package/dist/runtime/agent-node/prompt-rendering.js +208 -251
  228. package/dist/runtime/agent-node/session-execution.js +43 -39
  229. package/dist/runtime/builtins/builtins.js +218 -284
  230. package/dist/runtime/changed-files/changed-files.js +29 -34
  231. package/dist/runtime/command-executor/command-executor.js +31 -23
  232. package/dist/runtime/config-error.js +1 -3
  233. package/dist/runtime/context/context.js +35 -37
  234. package/dist/runtime/contracts/contracts.d.ts +3 -0
  235. package/dist/runtime/contracts/index.d.ts +1 -1
  236. package/dist/runtime/detached-race.js +11 -14
  237. package/dist/runtime/drain-merge/drain-merge.js +139 -164
  238. package/dist/runtime/durable-store/acquisition.js +5 -3
  239. package/dist/runtime/durable-store/durable-store.d.ts +3 -1
  240. package/dist/runtime/durable-store/postgres/client.js +29 -0
  241. package/dist/runtime/durable-store/postgres/migrate-substrate.js +34 -29
  242. package/dist/runtime/durable-store/postgres/postgres-store.js +18 -20
  243. package/dist/runtime/events/events.js +273 -331
  244. package/dist/runtime/events/index.js +2 -2
  245. package/dist/runtime/execution-envelope.js +44 -0
  246. package/dist/runtime/gates/adjudication/llm-judge.js +21 -24
  247. package/dist/runtime/gates/adjudication/structured-claim.js +15 -16
  248. package/dist/runtime/gates/adjudicator/adjudicator.js +27 -27
  249. package/dist/runtime/gates/adjudicator/index.js +2 -2
  250. package/dist/runtime/gates/contract.js +5 -9
  251. package/dist/runtime/gates/gates.js +9 -8
  252. package/dist/runtime/gates/kinds/acceptance/acceptance.js +68 -71
  253. package/dist/runtime/gates/kinds/acceptance/index.js +2 -2
  254. package/dist/runtime/gates/kinds/artifact/artifact.js +4 -4
  255. package/dist/runtime/gates/kinds/artifact/index.js +2 -2
  256. package/dist/runtime/gates/kinds/builtin/builtin.js +4 -4
  257. package/dist/runtime/gates/kinds/builtin/index.js +2 -2
  258. package/dist/runtime/gates/kinds/changed-files/changed-files.js +31 -35
  259. package/dist/runtime/gates/kinds/changed-files/index.js +2 -2
  260. package/dist/runtime/gates/kinds/command/command.js +3 -3
  261. package/dist/runtime/gates/kinds/command/index.js +2 -2
  262. package/dist/runtime/gates/kinds/json-schema/index.js +2 -2
  263. package/dist/runtime/gates/kinds/json-schema/json-schema.js +7 -6
  264. package/dist/runtime/gates/kinds/verdict/index.js +2 -2
  265. package/dist/runtime/gates/kinds/verdict/verdict.js +3 -3
  266. package/dist/runtime/gates/orchestrator.js +72 -86
  267. package/dist/runtime/gates/registry.js +1 -3
  268. package/dist/runtime/handoff.d.ts +2 -1
  269. package/dist/runtime/handoff.js +43 -46
  270. package/dist/runtime/hooks/command-hook.js +57 -71
  271. package/dist/runtime/hooks/context.js +21 -25
  272. package/dist/runtime/hooks/events.js +84 -100
  273. package/dist/runtime/hooks/execution.js +6 -12
  274. package/dist/runtime/hooks/hooks.js +34 -23
  275. package/dist/runtime/hooks/invocation.js +23 -29
  276. package/dist/runtime/hooks/module-hook.js +36 -35
  277. package/dist/runtime/hooks/policy.js +32 -29
  278. package/dist/runtime/hooks/results.js +56 -66
  279. package/dist/runtime/journal-acquisition.d.ts +3 -2
  280. package/dist/runtime/journal-acquisition.js +14 -14
  281. package/dist/runtime/json-validation/json-validation.js +51 -72
  282. package/dist/runtime/launch-plan-args.js +39 -0
  283. package/dist/runtime/local-scheduler.js +46 -48
  284. package/dist/runtime/node-execution.js +376 -445
  285. package/dist/runtime/node-protocol/node-protocol.js +36 -79
  286. package/dist/runtime/node-state-store.d.ts +4 -1
  287. package/dist/runtime/node-state-store.js +13 -57
  288. package/dist/runtime/node-state-tracker.js +46 -54
  289. package/dist/runtime/open-pull-request/open-pull-request.js +201 -187
  290. package/dist/runtime/opencode-adapter.js +23 -24
  291. package/dist/runtime/opencode-agent-name.js +6 -6
  292. package/dist/runtime/opencode-runtime.js +115 -93
  293. package/dist/runtime/opencode-server.js +39 -53
  294. package/dist/runtime/opencode-session-executor.js +312 -344
  295. package/dist/runtime/parallel-node/parallel-node.js +123 -134
  296. package/dist/runtime/parallel-worktrees/parallel-worktrees.js +90 -73
  297. package/dist/runtime/protected-paths/protected-paths.js +70 -71
  298. package/dist/runtime/remediation/remediation.js +202 -231
  299. package/dist/runtime/retry.js +8 -10
  300. package/dist/runtime/run-journal.d.ts +2 -0
  301. package/dist/runtime/run-journal.js +7 -7
  302. package/dist/runtime/runtime-results.js +54 -69
  303. package/dist/runtime/scheduled-dependencies.d.ts +2 -1
  304. package/dist/runtime/scheduled-dependencies.js +61 -75
  305. package/dist/runtime/scheduler.js +179 -202
  306. package/dist/runtime/services/agent-node-runtime-service.js +3 -3
  307. package/dist/runtime/services/backlog-service.d.ts +1 -2
  308. package/dist/runtime/services/backlog-service.js +8 -14
  309. package/dist/runtime/services/command-executor-service.js +1 -1
  310. package/dist/runtime/services/config-io-service.js +24 -21
  311. package/dist/runtime/services/drain-merge-git-service.js +1 -1
  312. package/dist/runtime/services/file-system-service.js +9 -7
  313. package/dist/runtime/services/git-porcelain-service.js +6 -6
  314. package/dist/runtime/services/kubernetes-argo-service.d.ts +10 -3
  315. package/dist/runtime/services/kubernetes-argo-service.js +90 -84
  316. package/dist/runtime/services/kubernetes-jobs-read-service.js +115 -0
  317. package/dist/runtime/services/kubernetes-jobs-service.d.ts +37 -0
  318. package/dist/runtime/services/kubernetes-jobs-service.js +45 -0
  319. package/dist/runtime/services/kubernetes-jobs-watch-service.js +61 -0
  320. package/dist/runtime/services/kubernetes-lease-service.js +21 -0
  321. package/dist/runtime/services/mcp-gateway-service.js +143 -94
  322. package/dist/runtime/services/open-pull-request-git-service.js +1 -3
  323. package/dist/runtime/services/opencode-runtime-server-service.js +10 -12
  324. package/dist/runtime/services/opencode-sdk-service.js +7 -7
  325. package/dist/runtime/services/repo-io-service.js +10 -12
  326. package/dist/runtime/services/run-journal-file-service.js +2 -2
  327. package/dist/runtime/services/runner-command-io-service.js +48 -52
  328. package/dist/runtime/services/runner-event-sink-http-service.js +32 -39
  329. package/dist/runtime/step/step-node.js +15 -15
  330. package/dist/runtime/workflow-execution.js +56 -57
  331. package/dist/runtime/workflow-lifecycle.js +82 -101
  332. package/dist/runtime/yeet-event-record.js +104 -0
  333. package/dist/runtime/yeet-executor.js +184 -0
  334. package/dist/safe-json.js +16 -16
  335. package/dist/schedule/backlog-context.js +122 -116
  336. package/dist/schedule/baseline.js +249 -255
  337. package/dist/schedule/passes/coverage.js +63 -68
  338. package/dist/schedule/passes/drain-merge.js +34 -40
  339. package/dist/schedule/passes/ids.js +15 -17
  340. package/dist/schedule/passes/models.js +40 -37
  341. package/dist/schedule/passes/open-pull-request.js +16 -20
  342. package/dist/schedule/passes/references.js +18 -22
  343. package/dist/schedule/prompts.js +135 -141
  344. package/dist/schedule/scheduling-roles.js +8 -14
  345. package/dist/schema-boundary.d.ts +4 -0
  346. package/dist/schema-boundary.js +145 -0
  347. package/dist/serialized-write-queue.js +2 -2
  348. package/dist/standard-output-schemas.js +61 -59
  349. package/dist/strings.js +12 -12
  350. package/dist/task-ref.js +5 -5
  351. package/dist/tickets/apply-ticket-plan.js +52 -61
  352. package/dist/tickets/backlog-task-store.d.ts +15 -23
  353. package/dist/tickets/backlog-task-store.js +82 -94
  354. package/dist/tickets/completion/complete-ticket.js +53 -59
  355. package/dist/tickets/ticket-graph-dto.d.ts +24 -48
  356. package/dist/tickets/ticket-graph-dto.js +40 -40
  357. package/dist/tickets/ticket-graph.d.ts +7 -2
  358. package/dist/tickets/ticket-graph.js +36 -50
  359. package/dist/tickets/ticket-plan-command-args.js +6 -10
  360. package/dist/tickets/ticket-plan-render.js +10 -16
  361. package/dist/tickets/ticket-plan.d.ts +32 -41
  362. package/dist/tickets/ticket-plan.js +97 -77
  363. package/dist/tickets/ticket-selection.d.ts +3 -1
  364. package/dist/tickets/ticket-selection.js +37 -52
  365. package/dist/tickets/ticket-task-index.js +13 -17
  366. package/dist/tickets/validation-error-format.js +3 -10
  367. package/dist/token-estimator.js +12 -7
  368. package/dist/unknown-fields.js +21 -0
  369. package/dist/workflow-submit-contract.d.ts +9 -10
  370. package/dist/workflow-submit-contract.js +10 -9
  371. package/docs/adr-moka-postgres-schema-isolation.md +48 -0
  372. package/docs/adr-opencode-first-goal-loop-runtime.md +11 -11
  373. package/docs/config-architecture.md +13 -13
  374. package/docs/mcp-host-isolation.md +1 -0
  375. package/docs/moka-orchestrator-design.md +3 -3
  376. package/docs/operator-guide.md +1 -1
  377. package/docs/pipeline-console-runner-contract.md +10 -6
  378. package/docs/runtime-actor-model.md +18 -18
  379. package/docs/runtime-test-subsystems.md +200 -0
  380. package/docs/slash-command-adapter-contract.md +3 -3
  381. package/package.json +49 -85
  382. package/dist/config/schema/reference-validation.js +0 -83
@@ -1,83 +1,85 @@
1
+ import { effectSchemaDocumentDraft07, mutableArray, nonEmptyMutableArray, positiveInteger, requiredString, stringArray, struct } from "./schema-boundary.js";
1
2
  import { ticketPlanSchema } from "./tickets/ticket-plan.js";
2
- import { z } from "zod";
3
+ import * as Option$1 from "effect/Option";
4
+ import * as R from "effect/Record";
5
+ import * as Schema from "effect/Schema";
6
+ import * as Arr from "effect/Array";
3
7
  //#region src/standard-output-schemas.ts
4
- const VERDICT_SCHEMA = z.enum(["PASS", "FAIL"]);
5
- const STRING_ARRAY_SCHEMA = z.array(z.string());
6
- const CHANGE_SCHEMA = z.object({
7
- files: z.array(z.string().min(1)).min(1),
8
- summary: z.string().min(1),
9
- why: z.string().min(1)
10
- }).strict();
8
+ const VERDICT_SCHEMA = Schema.Literals(["PASS", "FAIL"]);
9
+ const STRING_ARRAY_SCHEMA = stringArray;
10
+ const CHANGE_SCHEMA = struct({
11
+ files: nonEmptyMutableArray(requiredString),
12
+ summary: requiredString,
13
+ why: requiredString
14
+ });
11
15
  const STANDARD_OUTPUT_SCHEMAS = {
12
- acceptance: z.object({
13
- acceptance: z.array(z.object({
16
+ acceptance: struct({
17
+ acceptance: mutableArray(struct({
14
18
  evidence: STRING_ARRAY_SCHEMA,
15
- id: z.string(),
16
- violations: STRING_ARRAY_SCHEMA.optional(),
17
- verdict: VERDICT_SCHEMA
18
- }).strict()),
19
+ id: Schema.String,
20
+ verdict: VERDICT_SCHEMA,
21
+ violations: Schema.optional(STRING_ARRAY_SCHEMA)
22
+ })),
19
23
  evidence: STRING_ARRAY_SCHEMA,
20
24
  verdict: VERDICT_SCHEMA,
21
- violations: STRING_ARRAY_SCHEMA.optional()
22
- }).strict(),
23
- implementation: z.object({
24
- changes: z.array(CHANGE_SCHEMA).min(1),
25
- followups: STRING_ARRAY_SCHEMA.optional(),
26
- lessons: STRING_ARRAY_SCHEMA.optional(),
27
- risks: STRING_ARRAY_SCHEMA.optional(),
28
- summary: z.string().optional(),
25
+ violations: Schema.optional(STRING_ARRAY_SCHEMA)
26
+ }),
27
+ implementation: struct({
28
+ changes: nonEmptyMutableArray(CHANGE_SCHEMA),
29
+ followups: Schema.optional(STRING_ARRAY_SCHEMA),
30
+ lessons: Schema.optional(STRING_ARRAY_SCHEMA),
31
+ risks: Schema.optional(STRING_ARRAY_SCHEMA),
32
+ summary: Schema.optional(Schema.String),
29
33
  verification: STRING_ARRAY_SCHEMA
30
- }).strict(),
31
- learn: z.object({
34
+ }),
35
+ learn: struct({
32
36
  evidence: STRING_ARRAY_SCHEMA,
33
- qdrant: z.object({
34
- attempted: z.boolean(),
35
- succeeded: z.boolean()
36
- }).strict()
37
- }).strict(),
38
- research: z.object({
37
+ qdrant: struct({
38
+ attempted: Schema.Boolean,
39
+ succeeded: Schema.Boolean
40
+ })
41
+ }),
42
+ research: struct({
39
43
  ac: STRING_ARRAY_SCHEMA,
40
- files: STRING_ARRAY_SCHEMA.optional(),
44
+ files: Schema.optional(STRING_ARRAY_SCHEMA),
41
45
  findings: STRING_ARRAY_SCHEMA,
42
- risks: STRING_ARRAY_SCHEMA.optional(),
43
- target: z.string().optional()
44
- }).strict(),
45
- review: z.object({
46
- findings: z.array(z.object({
47
- file: z.string().optional(),
48
- line: z.number().int().min(1).optional(),
49
- message: z.string(),
50
- rule: z.string().optional(),
51
- severity: z.enum([
46
+ risks: Schema.optional(STRING_ARRAY_SCHEMA),
47
+ target: Schema.optional(Schema.String)
48
+ }),
49
+ review: struct({
50
+ findings: mutableArray(struct({
51
+ file: Schema.optional(Schema.String),
52
+ line: Schema.optional(positiveInteger),
53
+ message: Schema.String,
54
+ rule: Schema.optional(Schema.String),
55
+ severity: Schema.Literals([
52
56
  "info",
53
57
  "warn",
54
58
  "error",
55
59
  "critical"
56
60
  ])
57
- }).strict()),
58
- summary: z.string().optional(),
61
+ })),
62
+ summary: Schema.optional(Schema.String),
59
63
  verdict: VERDICT_SCHEMA
60
- }).strict(),
64
+ }),
61
65
  "ticket-plan": ticketPlanSchema,
62
- verify: z.object({
66
+ verify: struct({
63
67
  evidence: STRING_ARRAY_SCHEMA,
64
68
  verdict: VERDICT_SCHEMA,
65
- violations: STRING_ARRAY_SCHEMA.optional()
66
- }).strict()
69
+ violations: Schema.optional(STRING_ARRAY_SCHEMA)
70
+ })
67
71
  };
68
- const standardOutputSchemaNames = Object.freeze(Object.keys(STANDARD_OUTPUT_SCHEMAS).sort());
69
- function standardOutputSchemaJson(name) {
72
+ const standardOutputSchemaNames = R.keys(STANDARD_OUTPUT_SCHEMAS).toSorted();
73
+ const NO_STANDARD_OUTPUT_SCHEMA = null;
74
+ const encodeUnknownJson = Schema.encodeUnknownSync(Schema.fromJsonString(Schema.Unknown));
75
+ const standardOutputSchemaJson = (name) => {
70
76
  const schema = STANDARD_OUTPUT_SCHEMAS[name];
71
- if (!schema) throw new Error(`Missing standard output schema registry entry '${name}'`);
72
- return JSON.stringify(z.toJSONSchema(schema, { target: "draft-07" }), null, 2);
73
- }
74
- function standardOutputSchemaPath(name) {
75
- return `.pipeline/schemas/${name}.schema.json`;
76
- }
77
- function standardOutputSchemaNameFromPath(schemaPath) {
77
+ return encodeUnknownJson(effectSchemaDocumentDraft07(schema));
78
+ };
79
+ const standardOutputSchemaPath = (name) => `.pipeline/schemas/${name}.schema.json`;
80
+ const standardOutputSchemaNameFromPath = (schemaPath) => {
78
81
  const normalized = schemaPath.replaceAll("\\", "/");
79
- for (const name of standardOutputSchemaNames) if (normalized === standardOutputSchemaPath(name)) return name;
80
- return null;
81
- }
82
+ return Option$1.getOrElse(Arr.findFirst(standardOutputSchemaNames, (name) => normalized === standardOutputSchemaPath(name)), () => NO_STANDARD_OUTPUT_SCHEMA);
83
+ };
82
84
  //#endregion
83
85
  export { standardOutputSchemaJson, standardOutputSchemaNameFromPath };
package/dist/strings.js CHANGED
@@ -1,28 +1,28 @@
1
1
  //#region src/strings.ts
2
- function uniqueStrings(values, options = {}) {
3
- const input = options.filterEmpty ? values.filter(Boolean) : values;
2
+ const uniqueStrings = (values, options = {}) => {
3
+ const input = options.filterEmpty === true ? values.filter((value) => value.length > 0) : values;
4
4
  const unique = [...new Set(input)];
5
- return options.sort ? unique.sort() : unique;
6
- }
7
- const GENERATED_ID_INVALID_CHARS_RE = /[^a-z0-9]+/g;
8
- const GENERATED_ID_TRIM_HYPHENS_RE = /^-+|-+$/g;
9
- const STARTS_WITH_ALPHA_RE = /^[a-z]/;
5
+ return options.sort === true ? unique.toSorted() : unique;
6
+ };
7
+ const GENERATED_ID_INVALID_CHARS_RE = /[^a-z0-9]+/gu;
8
+ const GENERATED_ID_TRIM_HYPHENS_RE = /^-+|-+$/gu;
9
+ const STARTS_WITH_ALPHA_RE = /^[a-z]/u;
10
10
  /**
11
11
  * Slugify an arbitrary string into a workflow-safe id (lowercase, hyphenated).
12
12
  * When the slug does not begin with a letter it is prefixed with
13
13
  * `fallbackPrefix` so the result is always a valid node/workflow id.
14
14
  */
15
- function generatedId(value, fallbackPrefix) {
15
+ const generatedId = (value, fallbackPrefix) => {
16
16
  const slug = value.trim().toLowerCase().replaceAll(GENERATED_ID_INVALID_CHARS_RE, "-").replaceAll(GENERATED_ID_TRIM_HYPHENS_RE, "");
17
17
  if (STARTS_WITH_ALPHA_RE.test(slug)) return slug;
18
- return slug ? `${fallbackPrefix}-${slug}` : fallbackPrefix;
19
- }
18
+ return slug.length > 0 ? `${fallbackPrefix}-${slug}` : fallbackPrefix;
19
+ };
20
20
  /**
21
21
  * Slugify `value` to a generated id (see {@link generatedId}) and disambiguate
22
22
  * against `usedIds` by appending an incrementing numeric suffix. Mutates
23
23
  * `usedIds` to reserve the chosen id.
24
24
  */
25
- function uniqueGeneratedId(value, usedIds, fallbackPrefix) {
25
+ const uniqueGeneratedId = (value, usedIds, fallbackPrefix) => {
26
26
  const base = generatedId(value, fallbackPrefix);
27
27
  let candidate = base;
28
28
  let suffix = 2;
@@ -32,6 +32,6 @@ function uniqueGeneratedId(value, usedIds, fallbackPrefix) {
32
32
  }
33
33
  usedIds.add(candidate);
34
34
  return candidate;
35
- }
35
+ };
36
36
  //#endregion
37
37
  export { uniqueGeneratedId, uniqueStrings };
package/dist/task-ref.js CHANGED
@@ -1,17 +1,17 @@
1
1
  //#region src/task-ref.ts
2
2
  const TICKET_ID_SOURCE = String.raw`(?=[A-Za-z0-9.-]*\d)[A-Za-z][A-Za-z0-9]*(?:-[A-Za-z0-9]+)+(?:\.[A-Za-z0-9]+)*`;
3
- new RegExp(`^(${TICKET_ID_SOURCE})\\b\\s*(.*)$`, "s");
4
- const TICKET_ID_RE = new RegExp(`\\b(${TICKET_ID_SOURCE})\\b`, "g");
5
- function extractTicketIds(input) {
3
+ new RegExp(`^(${TICKET_ID_SOURCE})\\b\\s*(.*)$`, "su");
4
+ const TICKET_ID_RE = new RegExp(`\\b(${TICKET_ID_SOURCE})\\b`, "gu");
5
+ const extractTicketIds = (input) => {
6
6
  const ids = [];
7
7
  const seen = /* @__PURE__ */ new Set();
8
8
  for (const match of input.matchAll(TICKET_ID_RE)) {
9
9
  const id = match[1];
10
- if (!id || seen.has(id)) continue;
10
+ if (id.length === 0 || seen.has(id)) continue;
11
11
  seen.add(id);
12
12
  ids.push(id);
13
13
  }
14
14
  return ids;
15
- }
15
+ };
16
16
  //#endregion
17
17
  export { extractTicketIds };
@@ -1,75 +1,66 @@
1
1
  import { BacklogService } from "../runtime/services/backlog-service.js";
2
2
  import { parseBacklogTaskId } from "../backlog.js";
3
3
  import { formatBacklogCommand, ticketCreateArgs } from "./ticket-plan-command-args.js";
4
- import { Data, Effect } from "effect";
4
+ import { Data, Effect, Option } from "effect";
5
5
  //#region src/tickets/apply-ticket-plan.ts
6
6
  var ApplyTicketPlanError = class extends Data.TaggedError("ApplyTicketPlanError") {};
7
- function applyTicketPlanEffect(plan, worktreePath, options) {
8
- return Effect.gen(function* () {
9
- const backlog = yield* BacklogService;
10
- const createdIds = [];
11
- const parentId = yield* resolveParentId(plan, options, worktreePath, backlog, createdIds);
12
- return {
13
- createdIds,
14
- parentId,
15
- taskIdsByKey: yield* createChildTickets(plan, parentId, worktreePath, backlog, createdIds)
16
- };
17
- });
18
- }
19
- function resolveParentId(plan, options, worktreePath, backlog, createdIds) {
20
- if (options.parentId) return Effect.succeed(options.parentId);
21
- if (!plan.epic) return Effect.fail(new ApplyTicketPlanError({
7
+ const formatCreatedIds = (createdIds) => createdIds.length > 0 ? createdIds.join(", ") : "none";
8
+ const commandFailure = (args, createdIds, error) => new ApplyTicketPlanError({
9
+ command: formatBacklogCommand(args),
10
+ createdIds,
11
+ message: `backlog command failed after created ids: ${formatCreatedIds(createdIds)}; failed command: ${formatBacklogCommand(args)}; ${error.message}`,
12
+ stdout: error.stdout
13
+ });
14
+ const runCreateAndParseId = (args, worktreePath, backlog, createdIds) => Effect.gen(function* effectBody() {
15
+ const stdout = yield* backlog.run(args, worktreePath).pipe(Effect.mapError((error) => commandFailure(args, createdIds, error)));
16
+ const taskId = parseBacklogTaskId(stdout);
17
+ if (Option.isNone(taskId)) return yield* Effect.fail(new ApplyTicketPlanError({
18
+ command: formatBacklogCommand(args),
19
+ createdIds,
20
+ message: `could not parse created task id from Backlog output; created ids: ${formatCreatedIds(createdIds)}; failed command: ${formatBacklogCommand(args)}`,
21
+ stdout
22
+ }));
23
+ createdIds.push(taskId.value);
24
+ return taskId.value;
25
+ });
26
+ const resolveParentId = (plan, options, worktreePath, backlog, createdIds) => {
27
+ if (options.parentId !== void 0 && options.parentId.length > 0) return Effect.succeed(options.parentId);
28
+ if (plan.epic === void 0) return Effect.fail(new ApplyTicketPlanError({
22
29
  createdIds,
23
30
  message: "Cannot apply ticket plan without --parent because the plan does not include an epic."
24
31
  }));
25
32
  return runCreateAndParseId(ticketCreateArgs(plan.epic), worktreePath, backlog, createdIds);
26
- }
27
- function createChildTickets(plan, parentId, worktreePath, backlog, createdIds) {
28
- return Effect.gen(function* () {
29
- const remaining = new Map(plan.tickets.map((ticket) => [ticket.key, ticket]));
30
- const taskIdsByKey = {};
31
- while (remaining.size > 0) {
32
- const ready = [...remaining.values()].filter((ticket) => ticket.depends_on.every((key) => taskIdsByKey[key]));
33
- if (ready.length === 0) return yield* Effect.fail(new ApplyTicketPlanError({
34
- createdIds,
35
- message: "Cannot apply ticket plan because local dependency keys contain a cycle or unresolved prerequisite."
36
- }));
37
- for (const ticket of ready) {
38
- const taskId = yield* runCreateAndParseId(ticketCreateArgs(ticket, {
39
- dependencyIds: ticket.depends_on.map((key) => taskIdsByKey[key]),
40
- parentId
41
- }), worktreePath, backlog, createdIds);
42
- taskIdsByKey[ticket.key] = taskId;
43
- remaining.delete(ticket.key);
44
- }
45
- }
46
- return taskIdsByKey;
47
- });
48
- }
49
- function runCreateAndParseId(args, worktreePath, backlog, createdIds) {
50
- return Effect.gen(function* () {
51
- const stdout = yield* backlog.run(args, worktreePath).pipe(Effect.mapError((error) => commandFailure(args, createdIds, error)));
52
- const taskId = parseBacklogTaskId(stdout);
53
- if (!taskId) return yield* Effect.fail(new ApplyTicketPlanError({
54
- command: formatBacklogCommand(args),
33
+ };
34
+ const createChildTickets = (plan, parentId, worktreePath, backlog, createdIds) => Effect.gen(function* effectBody() {
35
+ const remaining = new Map(plan.tickets.map((ticket) => [ticket.key, ticket]));
36
+ const taskIdsByKey = {};
37
+ while (remaining.size > 0) {
38
+ const ready = [...remaining.values()].filter((ticket) => ticket.depends_on.every((key) => taskIdsByKey[key]));
39
+ if (ready.length === 0) return yield* Effect.fail(new ApplyTicketPlanError({
55
40
  createdIds,
56
- message: `could not parse created task id from Backlog output; created ids: ${formatCreatedIds(createdIds)}; failed command: ${formatBacklogCommand(args)}`,
57
- stdout
41
+ message: "Cannot apply ticket plan because local dependency keys contain a cycle or unresolved prerequisite."
58
42
  }));
59
- createdIds.push(taskId);
60
- return taskId;
61
- });
62
- }
63
- function commandFailure(args, createdIds, error) {
64
- return new ApplyTicketPlanError({
65
- command: formatBacklogCommand(args),
43
+ for (const ticket of ready) {
44
+ const dependencyIds = ticket.depends_on.map((key) => taskIdsByKey[key]);
45
+ const taskId = yield* runCreateAndParseId(ticketCreateArgs(ticket, {
46
+ dependencyIds,
47
+ parentId
48
+ }), worktreePath, backlog, createdIds);
49
+ taskIdsByKey[ticket.key] = taskId;
50
+ remaining.delete(ticket.key);
51
+ }
52
+ }
53
+ return taskIdsByKey;
54
+ });
55
+ const applyTicketPlanEffect = (plan, worktreePath, options) => Effect.gen(function* effectBody() {
56
+ const backlog = yield* BacklogService;
57
+ const createdIds = [];
58
+ const parentId = yield* resolveParentId(plan, options, worktreePath, backlog, createdIds);
59
+ return {
66
60
  createdIds,
67
- message: `backlog command failed after created ids: ${formatCreatedIds(createdIds)}; failed command: ${formatBacklogCommand(args)}; ${error.message}`,
68
- stdout: error.stdout
69
- });
70
- }
71
- function formatCreatedIds(createdIds) {
72
- return createdIds.length > 0 ? createdIds.join(", ") : "none";
73
- }
61
+ parentId,
62
+ taskIdsByKey: yield* createChildTickets(plan, parentId, worktreePath, backlog, createdIds)
63
+ };
64
+ });
74
65
  //#endregion
75
66
  export { applyTicketPlanEffect };
@@ -1,27 +1,19 @@
1
- import { Effect } from "effect";
2
- import { z } from "zod";
3
-
1
+ import "../runtime/services/repo-io-service.js";
2
+ import "effect/Effect";
3
+ import * as Schema from "effect/Schema";
4
4
  //#region src/tickets/backlog-task-store.d.ts
5
- declare const taskFrontmatterSchema: z.ZodObject<{
6
- dependencies: z.ZodDefault<z.ZodArray<z.ZodString>>;
7
- id: z.ZodString;
8
- modified_files: z.ZodDefault<z.ZodArray<z.ZodString>>;
9
- ordinal: z.ZodOptional<z.ZodNumber>;
10
- parent_task_id: z.ZodOptional<z.ZodString>;
11
- priority: z.ZodOptional<z.ZodEnum<{
12
- high: "high";
13
- low: "low";
14
- medium: "medium";
15
- }>>;
16
- references: z.ZodDefault<z.ZodArray<z.ZodString>>;
17
- status: z.ZodEnum<{
18
- Done: "Done";
19
- "In Progress": "In Progress";
20
- "To Do": "To Do";
21
- }>;
22
- title: z.ZodString;
23
- }, z.core.$loose>;
24
- type TaskFrontmatter = z.infer<typeof taskFrontmatterSchema>;
5
+ declare const taskFrontmatterSchema: Schema.Struct<{
6
+ readonly dependencies: Schema.withDecodingDefault<Schema.mutable<Schema.$Array<Schema.Trim>>, never>;
7
+ readonly id: Schema.Trim;
8
+ readonly modified_files: Schema.withDecodingDefault<Schema.mutable<Schema.$Array<Schema.Trim>>, never>;
9
+ readonly ordinal: Schema.optional<Schema.Number>;
10
+ readonly parent_task_id: Schema.optional<Schema.Trim>;
11
+ readonly priority: Schema.optional<Schema.Literals<readonly ["high", "medium", "low"]>>;
12
+ readonly references: Schema.withDecodingDefault<Schema.mutable<Schema.$Array<Schema.Trim>>, never>;
13
+ readonly status: Schema.Literals<readonly ["To Do", "In Progress", "Done"]>;
14
+ readonly title: Schema.Trim;
15
+ }>;
16
+ type TaskFrontmatter = typeof taskFrontmatterSchema.Type;
25
17
  type BacklogTaskPriority = NonNullable<TaskFrontmatter["priority"]>;
26
18
  type BacklogTaskStatus = TaskFrontmatter["status"];
27
19
  interface BacklogTaskRecord {
@@ -1,13 +1,15 @@
1
- import { errorMessage, formatZodIssues } from "./validation-error-format.js";
1
+ import { formatSchemaIssueList, mutableArray, parseResultWithSchema, struct, trimmedRequiredString, withDefault } from "../schema-boundary.js";
2
+ import { errorMessage } from "./validation-error-format.js";
2
3
  import { RepoIoService } from "../runtime/services/repo-io-service.js";
3
4
  import { indexChildrenByParentId } from "./ticket-task-index.js";
4
- import { Data, Effect } from "effect";
5
- import { z } from "zod";
5
+ import * as Effect from "effect/Effect";
6
+ import * as Schema from "effect/Schema";
6
7
  import { join } from "node:path";
8
+ import * as Data from "effect/Data";
7
9
  import matter from "gray-matter";
8
10
  //#region src/tickets/backlog-task-store.ts
9
- const LINE_RE = /\r?\n/;
10
- const ACCEPTANCE_ITEM_RE = /^\s*-\s*\[[ xX]\]\s*(?:#?[\w.-]+\s+)?(.+)$/;
11
+ const LINE_RE = /\r?\n/u;
12
+ const ACCEPTANCE_ITEM_RE = /^\s*-\s*\[[ xX]\]\s*(?:#?[\w.-]+\s+)?(.+)$/u;
11
13
  const DESCRIPTION_MARKERS = {
12
14
  end: "<!-- SECTION:DESCRIPTION:END -->",
13
15
  start: "<!-- SECTION:DESCRIPTION:BEGIN -->"
@@ -16,69 +18,69 @@ const ACCEPTANCE_MARKERS = {
16
18
  end: "<!-- AC:END -->",
17
19
  start: "<!-- AC:BEGIN -->"
18
20
  };
19
- const nonEmptyStringSchema = z.string().trim().min(1);
20
- const taskFrontmatterSchema = z.object({
21
- dependencies: z.array(nonEmptyStringSchema).default([]),
21
+ const nonEmptyStringSchema = trimmedRequiredString;
22
+ const taskFrontmatterSchema = struct({
23
+ dependencies: withDefault(mutableArray(nonEmptyStringSchema), []),
22
24
  id: nonEmptyStringSchema,
23
- modified_files: z.array(nonEmptyStringSchema).default([]),
24
- ordinal: z.number().finite().optional(),
25
- parent_task_id: nonEmptyStringSchema.optional(),
26
- priority: z.enum([
25
+ modified_files: withDefault(mutableArray(nonEmptyStringSchema), []),
26
+ ordinal: Schema.optional(Schema.Number),
27
+ parent_task_id: Schema.optional(nonEmptyStringSchema),
28
+ priority: Schema.optional(Schema.Literals([
27
29
  "high",
28
30
  "medium",
29
31
  "low"
30
- ]).optional(),
31
- references: z.array(nonEmptyStringSchema).default([]),
32
- status: z.enum([
32
+ ])),
33
+ references: withDefault(mutableArray(nonEmptyStringSchema), []),
34
+ status: Schema.Literals([
33
35
  "To Do",
34
36
  "In Progress",
35
37
  "Done"
36
38
  ]),
37
39
  title: nonEmptyStringSchema
38
- }).passthrough();
40
+ });
39
41
  var BacklogTaskStoreError = class extends Data.TaggedError("BacklogTaskStoreError") {};
40
- function loadBacklogTaskStoreEffect(worktreePath) {
41
- return Effect.gen(function* () {
42
- return yield* buildBacklogTaskStoreEffect(yield* readBacklogTasksEffect(worktreePath));
43
- });
44
- }
45
- function parseBacklogTaskMarkdownEffect(source, filePath) {
46
- return Effect.gen(function* () {
47
- const parsed = yield* Effect.try({
48
- catch: (error) => storeError(filePath, `Could not parse Backlog task frontmatter: ${errorMessage(error)}`),
49
- try: () => matter(source)
50
- });
51
- return taskRecordFromDocument(yield* decodeFrontmatterEffect(parsed.data, filePath), parsed.content, filePath);
52
- });
53
- }
54
- function readBacklogTasksEffect(worktreePath) {
55
- const tasksDir = join(worktreePath, "backlog", "tasks");
56
- return Effect.gen(function* () {
57
- const repoIo = yield* RepoIoService;
58
- if (!(yield* repoIo.exists(tasksDir).pipe(Effect.mapError((error) => ioStoreError(tasksDir, error))))) return [];
59
- const entries = yield* repoIo.readDir(tasksDir).pipe(Effect.mapError((error) => ioStoreError(tasksDir, error)));
60
- return yield* Effect.all(entries.filter((entry) => entry.isFile() && entry.name.endsWith(".md")).map((entry) => {
61
- const filePath = join(tasksDir, entry.name);
62
- return repoIo.readText(filePath).pipe(Effect.mapError((error) => ioStoreError(filePath, error)), Effect.flatMap((source) => parseBacklogTaskMarkdownEffect(source, filePath)));
63
- }));
64
- });
65
- }
66
- function decodeFrontmatterEffect(frontmatter, filePath) {
67
- const decoded = taskFrontmatterSchema.safeParse(frontmatter);
68
- if (decoded.success) return Effect.succeed(decoded.data);
69
- return Effect.fail(storeError(filePath, `Invalid Backlog task frontmatter in ${filePath}: ${formatZodIssues(decoded.error.issues)}`));
70
- }
71
- function buildBacklogTaskStoreEffect(tasks) {
72
- return Effect.gen(function* () {
73
- const tasksById = yield* indexTasksByIdEffect(tasks);
74
- return {
75
- childrenByParentId: indexChildrenByParentId(tasks),
76
- tasks,
77
- tasksById
78
- };
42
+ const extractMarkedBlock = (content, markers) => {
43
+ const start = content.indexOf(markers.start);
44
+ if (start === -1) return "";
45
+ const bodyStart = start + markers.start.length;
46
+ const end = content.indexOf(markers.end, bodyStart);
47
+ if (end === -1) return "";
48
+ return content.slice(bodyStart, end).trim();
49
+ };
50
+ const extractDescription = (content) => extractMarkedBlock(content, DESCRIPTION_MARKERS);
51
+ const extractAcceptanceCriteria = (content) => extractMarkedBlock(content, ACCEPTANCE_MARKERS).split(LINE_RE).map((line) => ACCEPTANCE_ITEM_RE.exec(line)?.[1]?.trim()).filter((criterion) => criterion !== void 0 && criterion.length > 0);
52
+ const taskRecordFromDocument = (frontmatter, content, filePath) => ({
53
+ acceptanceCriteria: extractAcceptanceCriteria(content),
54
+ dependencies: frontmatter.dependencies,
55
+ description: extractDescription(content),
56
+ filePath,
57
+ id: frontmatter.id,
58
+ modifiedFiles: frontmatter.modified_files,
59
+ ordinal: frontmatter.ordinal,
60
+ parentTaskId: frontmatter.parent_task_id,
61
+ priority: frontmatter.priority,
62
+ references: frontmatter.references,
63
+ status: frontmatter.status,
64
+ title: frontmatter.title
65
+ });
66
+ const storeError = (path, message) => new BacklogTaskStoreError({
67
+ message,
68
+ path
69
+ });
70
+ const decodeFrontmatterEffect = (frontmatter, filePath) => {
71
+ const decoded = parseResultWithSchema(taskFrontmatterSchema, frontmatter, { onExcessProperty: "preserve" });
72
+ if (decoded.ok) return Effect.succeed(decoded.value);
73
+ return Effect.fail(storeError(filePath, `Invalid Backlog task frontmatter in ${filePath}: ${formatSchemaIssueList(decoded.issues)}`));
74
+ };
75
+ const parseBacklogTaskMarkdownEffect = (source, filePath) => Effect.gen(function* effectBody() {
76
+ const parsed = yield* Effect.try({
77
+ catch: (error) => storeError(filePath, `Could not parse Backlog task frontmatter: ${errorMessage(error)}`),
78
+ try: () => matter(source)
79
79
  });
80
- }
81
- function indexTasksByIdEffect(tasks) {
80
+ const frontmatter = yield* decodeFrontmatterEffect(parsed.data, filePath);
81
+ return taskRecordFromDocument(frontmatter, parsed.content, filePath);
82
+ });
83
+ const indexTasksByIdEffect = (tasks) => {
82
84
  const tasksById = /* @__PURE__ */ new Map();
83
85
  for (const task of tasks) {
84
86
  const existing = tasksById.get(task.id);
@@ -86,45 +88,31 @@ function indexTasksByIdEffect(tasks) {
86
88
  tasksById.set(task.id, task);
87
89
  }
88
90
  return Effect.succeed(tasksById);
89
- }
90
- function taskRecordFromDocument(frontmatter, content, filePath) {
91
+ };
92
+ const buildBacklogTaskStoreEffect = (tasks) => Effect.gen(function* effectBody() {
93
+ const tasksById = yield* indexTasksByIdEffect(tasks);
91
94
  return {
92
- acceptanceCriteria: extractAcceptanceCriteria(content),
93
- dependencies: frontmatter.dependencies,
94
- description: extractDescription(content),
95
- filePath,
96
- id: frontmatter.id,
97
- modifiedFiles: frontmatter.modified_files,
98
- ordinal: frontmatter.ordinal,
99
- parentTaskId: frontmatter.parent_task_id,
100
- priority: frontmatter.priority,
101
- references: frontmatter.references,
102
- status: frontmatter.status,
103
- title: frontmatter.title
95
+ childrenByParentId: indexChildrenByParentId(tasks),
96
+ tasks,
97
+ tasksById
104
98
  };
105
- }
106
- function extractDescription(content) {
107
- return extractMarkedBlock(content, DESCRIPTION_MARKERS);
108
- }
109
- function extractAcceptanceCriteria(content) {
110
- return extractMarkedBlock(content, ACCEPTANCE_MARKERS).split(LINE_RE).map((line) => ACCEPTANCE_ITEM_RE.exec(line)?.[1]?.trim()).filter((criterion) => Boolean(criterion));
111
- }
112
- function extractMarkedBlock(content, markers) {
113
- const start = content.indexOf(markers.start);
114
- if (start < 0) return "";
115
- const bodyStart = start + markers.start.length;
116
- const end = content.indexOf(markers.end, bodyStart);
117
- if (end < 0) return "";
118
- return content.slice(bodyStart, end).trim();
119
- }
120
- function ioStoreError(path, error) {
121
- return storeError(path, `Could not read Backlog task data: ${errorMessage(error)}`);
122
- }
123
- function storeError(path, message) {
124
- return new BacklogTaskStoreError({
125
- message,
126
- path
99
+ });
100
+ const ioStoreError = (path, error) => storeError(path, `Could not read Backlog task data: ${errorMessage(error)}`);
101
+ const readBacklogTasksEffect = (worktreePath) => {
102
+ const tasksDir = join(worktreePath, "backlog", "tasks");
103
+ return Effect.gen(function* effectBody() {
104
+ const repoIo = yield* RepoIoService;
105
+ if (!(yield* repoIo.exists(tasksDir).pipe(Effect.mapError((error) => ioStoreError(tasksDir, error))))) return [];
106
+ const entries = yield* repoIo.readDir(tasksDir).pipe(Effect.mapError((error) => ioStoreError(tasksDir, error)));
107
+ return yield* Effect.all(entries.filter((entry) => entry.isFile() && entry.name.endsWith(".md")).map((entry) => {
108
+ const filePath = join(tasksDir, entry.name);
109
+ return repoIo.readText(filePath).pipe(Effect.mapError((error) => ioStoreError(filePath, error)), Effect.flatMap((source) => parseBacklogTaskMarkdownEffect(source, filePath)));
110
+ }));
127
111
  });
128
- }
112
+ };
113
+ const loadBacklogTaskStoreEffect = (worktreePath) => Effect.gen(function* effectBody() {
114
+ const tasks = yield* readBacklogTasksEffect(worktreePath);
115
+ return yield* buildBacklogTaskStoreEffect(tasks);
116
+ });
129
117
  //#endregion
130
118
  export { BacklogTaskStoreError, loadBacklogTaskStoreEffect };