@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.
- package/README.md +14 -2
- package/defaults/pipeline.yaml +23 -5
- package/defaults/profiles.yaml +104 -21
- package/dist/argo-graph.js +90 -88
- package/dist/argo-submit.d.ts +110 -138
- package/dist/argo-submit.js +363 -378
- package/dist/argo-workflow.d.ts +156 -177
- package/dist/argo-workflow.js +96 -138
- package/dist/backlog.js +5 -4
- package/dist/bench/eval-report.js +21 -12
- package/dist/claude-settings-config.js +23 -31
- package/dist/claude-user-config.js +6 -16
- package/dist/cli/bootstrap-commands.js +3 -3
- package/dist/cli/doctor.d.ts +1 -1
- package/dist/cli/doctor.js +176 -171
- package/dist/cli/factory-commands.js +13 -13
- package/dist/cli/format.js +92 -86
- package/dist/cli/loop-commands.js +21 -21
- package/dist/cli/mcp-gateway-commands.js +12 -12
- package/dist/cli/plan-commands.js +85 -116
- package/dist/cli/program.d.ts +3 -3
- package/dist/cli/program.js +41 -43
- package/dist/cli/run-command.d.ts +1 -1
- package/dist/cli/run-command.js +25 -25
- package/dist/cli/run-commands.js +31 -29
- package/dist/cli/run-resolver.d.ts +1 -1
- package/dist/cli/run-resolver.js +30 -32
- package/dist/cli/run-service.d.ts +2 -3
- package/dist/cli/run-service.js +229 -239
- package/dist/cli/submit-options.js +85 -83
- package/dist/cluster-doctor.js +147 -175
- package/dist/codex-config.js +24 -30
- package/dist/commands/bench-command.js +9 -7
- package/dist/commands/coordinator-command.js +35 -0
- package/dist/commands/pipeline-command.js +13 -7
- package/dist/commands/runner-command-command.js +39 -24
- package/dist/commands/runner-node-command.js +31 -0
- package/dist/commands/ticket/complete.js +29 -33
- package/dist/commands/ticket/create.js +84 -82
- package/dist/commands/ticket/graph-check.js +11 -11
- package/dist/commands/ticket/next.js +36 -36
- package/dist/commands/ticket/sequence.js +11 -12
- package/dist/commands/ticket/shared.d.ts +5 -2
- package/dist/commands/ticket/shared.js +63 -66
- package/dist/commands/ticket/start.js +58 -67
- package/dist/commands/ticket-command.js +2 -2
- package/dist/config/defaults.d.ts +139 -140
- package/dist/config/defaults.js +81 -80
- package/dist/config/lint.js +52 -64
- package/dist/config/load.d.ts +4 -5
- package/dist/config/load.js +64 -74
- package/dist/config/schema/catalog.d.ts +2 -1
- package/dist/config/schema/catalog.js +3 -2
- package/dist/config/schema/mcp.js +46 -52
- package/dist/config/schemas.d.ts +382 -528
- package/dist/config/schemas.js +400 -398
- package/dist/config/validate.d.ts +1 -2
- package/dist/config/validate.js +236 -201
- package/dist/config.d.ts +2 -2
- package/dist/context/repo-map.js +105 -119
- package/dist/coordinator/composition.js +169 -0
- package/dist/coordinator/config.js +71 -0
- package/dist/coordinator/run-owner.js +64 -0
- package/dist/coordinator/wave-advance.js +148 -0
- package/dist/coordinator/wave-scheduler.js +50 -0
- package/dist/credentials/broker.d.ts +6 -8
- package/dist/credentials/broker.js +17 -16
- package/dist/credentials/codex-config.js +15 -19
- package/dist/credentials/file-targets.js +9 -15
- package/dist/credentials/local-codex-auth-sync.js +55 -58
- package/dist/credentials/opencode-config.js +28 -32
- package/dist/credentials/runner.js +13 -13
- package/dist/effect-sync-errors.js +28 -0
- package/dist/factory/create-experiment.js +285 -121
- package/dist/factory/exec.js +10 -12
- package/dist/factory/git-credentials.js +4 -4
- package/dist/factory/stamp-answers.js +10 -11
- package/dist/factory/template-update.js +65 -44
- package/dist/factory-lane.d.ts +26 -40
- package/dist/factory-lane.js +26 -25
- package/dist/gates.js +3 -3
- package/dist/git-remote-url.js +17 -19
- package/dist/hooks.d.ts +26 -26
- package/dist/hooks.js +20 -22
- package/dist/index.d.ts +4 -3
- package/dist/index.js +27 -36
- package/dist/install-commands/claude-code.js +100 -92
- package/dist/install-commands/host-selection.js +3 -6
- package/dist/install-commands/opencode.js +264 -259
- package/dist/install-commands/planner.js +163 -181
- package/dist/install-commands/result-format.js +1 -3
- package/dist/install-commands/shared.js +25 -42
- package/dist/install-commands/writer.js +22 -25
- package/dist/install-commands.js +8 -8
- package/dist/jscpd-output.js +29 -0
- package/dist/json-config-merge.js +14 -20
- package/dist/json-line-values.js +17 -6
- package/dist/loop/argo-poll.d.ts +0 -1
- package/dist/loop/argo-poll.js +15 -95
- package/dist/loop/backlog-records.js +1 -3
- package/dist/loop/controller-deps.js +150 -161
- package/dist/loop/controller.js +164 -186
- package/dist/loop/gh-checks.js +62 -61
- package/dist/loop/gh-runner.js +22 -25
- package/dist/loop/loop-command.js +66 -58
- package/dist/loop/loop-controller-entrypoint.js +29 -30
- package/dist/loop/merge.js +36 -40
- package/dist/loop/run-terminal-poll.js +69 -0
- package/dist/mcp/gateway-config.js +25 -29
- package/dist/mcp/gateway-doctor.js +77 -119
- package/dist/mcp/gateway-reconcile.js +17 -22
- package/dist/mcp/gateway-runtime.js +1 -3
- package/dist/mcp/host-config.js +37 -40
- package/dist/mcp/host-renderers.js +10 -18
- package/dist/mcp/repo-local-backends.js +51 -54
- package/dist/mcp/toolhive-vmcp.js +39 -39
- package/dist/model-resolver.js +29 -33
- package/dist/moka-global-config.d.ts +78 -55
- package/dist/moka-global-config.js +93 -92
- package/dist/moka-submit.d.ts +2179 -866
- package/dist/moka-submit.js +97 -99
- package/dist/opencode-project-config.js +34 -40
- package/dist/package-assets.js +1 -3
- package/dist/path-refs.js +2 -2
- package/dist/pipeline-init.js +25 -25
- package/dist/pipeline-runtime.d.ts +15 -14
- package/dist/pipeline-runtime.js +51 -50
- package/dist/planned-node.js +6 -3
- package/dist/planning/compile.d.ts +5 -5
- package/dist/planning/compile.js +140 -139
- package/dist/planning/dependency-refs.js +5 -5
- package/dist/planning/generate.d.ts +1296 -1296
- package/dist/planning/generate.js +307 -314
- package/dist/planning/graph.d.ts +0 -1
- package/dist/planning/graph.js +131 -149
- package/dist/remote/argo/model.d.ts +104 -122
- package/dist/remote/argo/model.js +205 -197
- package/dist/remote/argo/policy.js +39 -47
- package/dist/remote/argo/storage.js +81 -85
- package/dist/remote/jobs/execution-identity.js +70 -0
- package/dist/remote/jobs/job-outcome.js +108 -0
- package/dist/remote/jobs/manifest.js +96 -0
- package/dist/remote/jobs/model.d.ts +158 -0
- package/dist/remote/jobs/model.js +162 -0
- package/dist/remote/jobs/node-bootstrap.js +213 -0
- package/dist/remote/jobs/policy.js +123 -0
- package/dist/remote/jobs/reconcile.js +100 -0
- package/dist/remote/jobs/run-spec-client.js +64 -0
- package/dist/remote/jobs/run-spec-path.js +31 -0
- package/dist/remote/jobs/run-spec-server.d.ts +34 -0
- package/dist/remote/jobs/run-spec-server.js +116 -0
- package/dist/remote/jobs/submit.d.ts +23 -0
- package/dist/remote/jobs/submit.js +116 -0
- package/dist/remote/jobs/watch.js +59 -0
- package/dist/remote/submit/argo-submission.d.ts +3 -1
- package/dist/remote/submit/argo-submission.js +53 -58
- package/dist/remote/submit/compilation.d.ts +2 -0
- package/dist/remote/submit/compilation.js +46 -49
- package/dist/remote/submit/event-boundary.js +62 -76
- package/dist/remote/submit/hook-events.d.ts +6 -0
- package/dist/remote/submit/io.d.ts +7 -1
- package/dist/remote/submit/io.js +40 -43
- package/dist/remote/submit/jobs-submission.d.ts +59 -0
- package/dist/remote/submit/jobs-submission.js +97 -0
- package/dist/remote/submit/jobs-submit-result.d.ts +25 -0
- package/dist/remote/submit/jobs-submit-result.js +34 -0
- package/dist/remote/submit/options.d.ts +49 -0
- package/dist/remote/submit/options.js +27 -0
- package/dist/remote/submit/service.d.ts +40 -1
- package/dist/remote/submit/service.js +67 -49
- package/dist/run-control/command-context.js +6 -8
- package/dist/run-control/commands.js +10 -10
- package/dist/run-control/contracts.d.ts +52 -101
- package/dist/run-control/contracts.js +83 -69
- package/dist/run-control/detach.js +66 -72
- package/dist/run-control/execution-store.js +0 -0
- package/dist/run-control/file-errors.js +1 -3
- package/dist/run-control/logical-segment.js +3 -3
- package/dist/run-control/next-node.js +67 -78
- package/dist/run-control/postgres/postgres-run-control-store.js +196 -225
- package/dist/run-control/resume-command.js +34 -41
- package/dist/run-control/run-artifacts-command.js +84 -105
- package/dist/run-control/run-command-domain.js +7 -11
- package/dist/run-control/run-control-store.js +9 -9
- package/dist/run-control/run-query-command.js +73 -100
- package/dist/run-control/run-record.js +5 -3
- package/dist/run-control/run-state-lock.js +5 -5
- package/dist/run-control/runtime-event-projection.js +38 -50
- package/dist/run-control/runtime-reporter.js +86 -102
- package/dist/run-control/stop-command.js +42 -53
- package/dist/run-control/store-fs-effects.js +3 -1
- package/dist/run-control/store-manifest.js +38 -13
- package/dist/run-control/store-paths.js +3 -3
- package/dist/run-control/store.js +1 -1
- package/dist/run-control/submit-result.js +21 -21
- package/dist/run-control/supervisor.js +78 -68
- package/dist/run-control/workspace.js +2 -2
- package/dist/run-state/git-refs.js +258 -307
- package/dist/runner/opencode-excludes.js +4 -4
- package/dist/runner/subprocess-result.js +28 -37
- package/dist/runner/subprocess.js +41 -41
- package/dist/runner/timeouts.js +14 -13
- package/dist/runner-command/dynamic-command.js +46 -39
- package/dist/runner-command/environment-commands.js +91 -0
- package/dist/runner-command/finalize.js +174 -153
- package/dist/runner-command/lifecycle-context.js +115 -130
- package/dist/runner-command/lifecycle.js +78 -72
- package/dist/runner-command/pre-schedule.js +203 -223
- package/dist/runner-command/run.js +450 -448
- package/dist/runner-command/schedule-source-options.js +8 -10
- package/dist/runner-command/select-ready-wave.js +39 -30
- package/dist/runner-command/task-descriptor.js +11 -17
- package/dist/runner-command-contract.d.ts +147 -157
- package/dist/runner-command-contract.js +403 -411
- package/dist/runner-event-schema.d.ts +364 -505
- package/dist/runner-event-schema.js +187 -175
- package/dist/runner-event-sink.js +37 -43
- package/dist/runner-output.js +6 -6
- package/dist/runner.d.ts +57 -37
- package/dist/runner.js +176 -127
- package/dist/runtime/actor-ids.d.ts +1 -0
- package/dist/runtime/actor-ids.js +2 -2
- package/dist/runtime/agent-node/agent-node.js +99 -110
- package/dist/runtime/agent-node/handoff-finalization.js +23 -24
- package/dist/runtime/agent-node/model-selection.js +19 -22
- package/dist/runtime/agent-node/output-finalization.js +174 -204
- package/dist/runtime/agent-node/prompt-rendering.js +208 -251
- package/dist/runtime/agent-node/session-execution.js +43 -39
- package/dist/runtime/builtins/builtins.js +218 -284
- package/dist/runtime/changed-files/changed-files.js +29 -34
- package/dist/runtime/command-executor/command-executor.js +31 -23
- package/dist/runtime/config-error.js +1 -3
- package/dist/runtime/context/context.js +35 -37
- package/dist/runtime/contracts/contracts.d.ts +3 -0
- package/dist/runtime/contracts/index.d.ts +1 -1
- package/dist/runtime/detached-race.js +11 -14
- package/dist/runtime/drain-merge/drain-merge.js +139 -164
- package/dist/runtime/durable-store/acquisition.js +5 -3
- package/dist/runtime/durable-store/durable-store.d.ts +3 -1
- package/dist/runtime/durable-store/postgres/client.js +29 -0
- package/dist/runtime/durable-store/postgres/migrate-substrate.js +34 -29
- package/dist/runtime/durable-store/postgres/postgres-store.js +18 -20
- package/dist/runtime/events/events.js +273 -331
- package/dist/runtime/events/index.js +2 -2
- package/dist/runtime/execution-envelope.js +44 -0
- package/dist/runtime/gates/adjudication/llm-judge.js +21 -24
- package/dist/runtime/gates/adjudication/structured-claim.js +15 -16
- package/dist/runtime/gates/adjudicator/adjudicator.js +27 -27
- package/dist/runtime/gates/adjudicator/index.js +2 -2
- package/dist/runtime/gates/contract.js +5 -9
- package/dist/runtime/gates/gates.js +9 -8
- package/dist/runtime/gates/kinds/acceptance/acceptance.js +68 -71
- package/dist/runtime/gates/kinds/acceptance/index.js +2 -2
- package/dist/runtime/gates/kinds/artifact/artifact.js +4 -4
- package/dist/runtime/gates/kinds/artifact/index.js +2 -2
- package/dist/runtime/gates/kinds/builtin/builtin.js +4 -4
- package/dist/runtime/gates/kinds/builtin/index.js +2 -2
- package/dist/runtime/gates/kinds/changed-files/changed-files.js +31 -35
- package/dist/runtime/gates/kinds/changed-files/index.js +2 -2
- package/dist/runtime/gates/kinds/command/command.js +3 -3
- package/dist/runtime/gates/kinds/command/index.js +2 -2
- package/dist/runtime/gates/kinds/json-schema/index.js +2 -2
- package/dist/runtime/gates/kinds/json-schema/json-schema.js +7 -6
- package/dist/runtime/gates/kinds/verdict/index.js +2 -2
- package/dist/runtime/gates/kinds/verdict/verdict.js +3 -3
- package/dist/runtime/gates/orchestrator.js +72 -86
- package/dist/runtime/gates/registry.js +1 -3
- package/dist/runtime/handoff.d.ts +2 -1
- package/dist/runtime/handoff.js +43 -46
- package/dist/runtime/hooks/command-hook.js +57 -71
- package/dist/runtime/hooks/context.js +21 -25
- package/dist/runtime/hooks/events.js +84 -100
- package/dist/runtime/hooks/execution.js +6 -12
- package/dist/runtime/hooks/hooks.js +34 -23
- package/dist/runtime/hooks/invocation.js +23 -29
- package/dist/runtime/hooks/module-hook.js +36 -35
- package/dist/runtime/hooks/policy.js +32 -29
- package/dist/runtime/hooks/results.js +56 -66
- package/dist/runtime/journal-acquisition.d.ts +3 -2
- package/dist/runtime/journal-acquisition.js +14 -14
- package/dist/runtime/json-validation/json-validation.js +51 -72
- package/dist/runtime/launch-plan-args.js +39 -0
- package/dist/runtime/local-scheduler.js +46 -48
- package/dist/runtime/node-execution.js +376 -445
- package/dist/runtime/node-protocol/node-protocol.js +36 -79
- package/dist/runtime/node-state-store.d.ts +4 -1
- package/dist/runtime/node-state-store.js +13 -57
- package/dist/runtime/node-state-tracker.js +46 -54
- package/dist/runtime/open-pull-request/open-pull-request.js +201 -187
- package/dist/runtime/opencode-adapter.js +23 -24
- package/dist/runtime/opencode-agent-name.js +6 -6
- package/dist/runtime/opencode-runtime.js +115 -93
- package/dist/runtime/opencode-server.js +39 -53
- package/dist/runtime/opencode-session-executor.js +312 -344
- package/dist/runtime/parallel-node/parallel-node.js +123 -134
- package/dist/runtime/parallel-worktrees/parallel-worktrees.js +90 -73
- package/dist/runtime/protected-paths/protected-paths.js +70 -71
- package/dist/runtime/remediation/remediation.js +202 -231
- package/dist/runtime/retry.js +8 -10
- package/dist/runtime/run-journal.d.ts +2 -0
- package/dist/runtime/run-journal.js +7 -7
- package/dist/runtime/runtime-results.js +54 -69
- package/dist/runtime/scheduled-dependencies.d.ts +2 -1
- package/dist/runtime/scheduled-dependencies.js +61 -75
- package/dist/runtime/scheduler.js +179 -202
- package/dist/runtime/services/agent-node-runtime-service.js +3 -3
- package/dist/runtime/services/backlog-service.d.ts +1 -2
- package/dist/runtime/services/backlog-service.js +8 -14
- package/dist/runtime/services/command-executor-service.js +1 -1
- package/dist/runtime/services/config-io-service.js +24 -21
- package/dist/runtime/services/drain-merge-git-service.js +1 -1
- package/dist/runtime/services/file-system-service.js +9 -7
- package/dist/runtime/services/git-porcelain-service.js +6 -6
- package/dist/runtime/services/kubernetes-argo-service.d.ts +10 -3
- package/dist/runtime/services/kubernetes-argo-service.js +90 -84
- package/dist/runtime/services/kubernetes-jobs-read-service.js +115 -0
- package/dist/runtime/services/kubernetes-jobs-service.d.ts +37 -0
- package/dist/runtime/services/kubernetes-jobs-service.js +45 -0
- package/dist/runtime/services/kubernetes-jobs-watch-service.js +61 -0
- package/dist/runtime/services/kubernetes-lease-service.js +21 -0
- package/dist/runtime/services/mcp-gateway-service.js +143 -94
- package/dist/runtime/services/open-pull-request-git-service.js +1 -3
- package/dist/runtime/services/opencode-runtime-server-service.js +10 -12
- package/dist/runtime/services/opencode-sdk-service.js +7 -7
- package/dist/runtime/services/repo-io-service.js +10 -12
- package/dist/runtime/services/run-journal-file-service.js +2 -2
- package/dist/runtime/services/runner-command-io-service.js +48 -52
- package/dist/runtime/services/runner-event-sink-http-service.js +32 -39
- package/dist/runtime/step/step-node.js +15 -15
- package/dist/runtime/workflow-execution.js +56 -57
- package/dist/runtime/workflow-lifecycle.js +82 -101
- package/dist/runtime/yeet-event-record.js +104 -0
- package/dist/runtime/yeet-executor.js +184 -0
- package/dist/safe-json.js +16 -16
- package/dist/schedule/backlog-context.js +122 -116
- package/dist/schedule/baseline.js +249 -255
- package/dist/schedule/passes/coverage.js +63 -68
- package/dist/schedule/passes/drain-merge.js +34 -40
- package/dist/schedule/passes/ids.js +15 -17
- package/dist/schedule/passes/models.js +40 -37
- package/dist/schedule/passes/open-pull-request.js +16 -20
- package/dist/schedule/passes/references.js +18 -22
- package/dist/schedule/prompts.js +135 -141
- package/dist/schedule/scheduling-roles.js +8 -14
- package/dist/schema-boundary.d.ts +4 -0
- package/dist/schema-boundary.js +145 -0
- package/dist/serialized-write-queue.js +2 -2
- package/dist/standard-output-schemas.js +61 -59
- package/dist/strings.js +12 -12
- package/dist/task-ref.js +5 -5
- package/dist/tickets/apply-ticket-plan.js +52 -61
- package/dist/tickets/backlog-task-store.d.ts +15 -23
- package/dist/tickets/backlog-task-store.js +82 -94
- package/dist/tickets/completion/complete-ticket.js +53 -59
- package/dist/tickets/ticket-graph-dto.d.ts +24 -48
- package/dist/tickets/ticket-graph-dto.js +40 -40
- package/dist/tickets/ticket-graph.d.ts +7 -2
- package/dist/tickets/ticket-graph.js +36 -50
- package/dist/tickets/ticket-plan-command-args.js +6 -10
- package/dist/tickets/ticket-plan-render.js +10 -16
- package/dist/tickets/ticket-plan.d.ts +32 -41
- package/dist/tickets/ticket-plan.js +97 -77
- package/dist/tickets/ticket-selection.d.ts +3 -1
- package/dist/tickets/ticket-selection.js +37 -52
- package/dist/tickets/ticket-task-index.js +13 -17
- package/dist/tickets/validation-error-format.js +3 -10
- package/dist/token-estimator.js +12 -7
- package/dist/unknown-fields.js +21 -0
- package/dist/workflow-submit-contract.d.ts +9 -10
- package/dist/workflow-submit-contract.js +10 -9
- package/docs/adr-moka-postgres-schema-isolation.md +48 -0
- package/docs/adr-opencode-first-goal-loop-runtime.md +11 -11
- package/docs/config-architecture.md +13 -13
- package/docs/mcp-host-isolation.md +1 -0
- package/docs/moka-orchestrator-design.md +3 -3
- package/docs/operator-guide.md +1 -1
- package/docs/pipeline-console-runner-contract.md +10 -6
- package/docs/runtime-actor-model.md +18 -18
- package/docs/runtime-test-subsystems.md +200 -0
- package/docs/slash-command-adapter-contract.md +3 -3
- package/package.json +49 -85
- 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
|
|
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 =
|
|
5
|
-
const STRING_ARRAY_SCHEMA =
|
|
6
|
-
const CHANGE_SCHEMA =
|
|
7
|
-
files:
|
|
8
|
-
summary:
|
|
9
|
-
why:
|
|
10
|
-
})
|
|
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:
|
|
13
|
-
acceptance:
|
|
16
|
+
acceptance: struct({
|
|
17
|
+
acceptance: mutableArray(struct({
|
|
14
18
|
evidence: STRING_ARRAY_SCHEMA,
|
|
15
|
-
id:
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
})
|
|
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:
|
|
22
|
-
})
|
|
23
|
-
implementation:
|
|
24
|
-
changes:
|
|
25
|
-
followups:
|
|
26
|
-
lessons:
|
|
27
|
-
risks:
|
|
28
|
-
summary:
|
|
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
|
-
})
|
|
31
|
-
learn:
|
|
34
|
+
}),
|
|
35
|
+
learn: struct({
|
|
32
36
|
evidence: STRING_ARRAY_SCHEMA,
|
|
33
|
-
qdrant:
|
|
34
|
-
attempted:
|
|
35
|
-
succeeded:
|
|
36
|
-
})
|
|
37
|
-
})
|
|
38
|
-
research:
|
|
37
|
+
qdrant: struct({
|
|
38
|
+
attempted: Schema.Boolean,
|
|
39
|
+
succeeded: Schema.Boolean
|
|
40
|
+
})
|
|
41
|
+
}),
|
|
42
|
+
research: struct({
|
|
39
43
|
ac: STRING_ARRAY_SCHEMA,
|
|
40
|
-
files:
|
|
44
|
+
files: Schema.optional(STRING_ARRAY_SCHEMA),
|
|
41
45
|
findings: STRING_ARRAY_SCHEMA,
|
|
42
|
-
risks:
|
|
43
|
-
target:
|
|
44
|
-
})
|
|
45
|
-
review:
|
|
46
|
-
findings:
|
|
47
|
-
file:
|
|
48
|
-
line:
|
|
49
|
-
message:
|
|
50
|
-
rule:
|
|
51
|
-
severity:
|
|
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
|
-
})
|
|
58
|
-
summary:
|
|
61
|
+
})),
|
|
62
|
+
summary: Schema.optional(Schema.String),
|
|
59
63
|
verdict: VERDICT_SCHEMA
|
|
60
|
-
})
|
|
64
|
+
}),
|
|
61
65
|
"ticket-plan": ticketPlanSchema,
|
|
62
|
-
verify:
|
|
66
|
+
verify: struct({
|
|
63
67
|
evidence: STRING_ARRAY_SCHEMA,
|
|
64
68
|
verdict: VERDICT_SCHEMA,
|
|
65
|
-
violations:
|
|
66
|
-
})
|
|
69
|
+
violations: Schema.optional(STRING_ARRAY_SCHEMA)
|
|
70
|
+
})
|
|
67
71
|
};
|
|
68
|
-
const standardOutputSchemaNames =
|
|
69
|
-
|
|
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
|
-
|
|
72
|
-
|
|
73
|
-
}
|
|
74
|
-
|
|
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
|
-
|
|
80
|
-
|
|
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
|
-
|
|
3
|
-
const input = options.filterEmpty ? values.filter(
|
|
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.
|
|
6
|
-
}
|
|
7
|
-
const GENERATED_ID_INVALID_CHARS_RE = /[^a-z0-9]+/
|
|
8
|
-
const GENERATED_ID_TRIM_HYPHENS_RE = /^-+|-+$/
|
|
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
|
-
|
|
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
|
-
|
|
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*(.*)$`, "
|
|
4
|
-
const TICKET_ID_RE = new RegExp(`\\b(${TICKET_ID_SOURCE})\\b`, "
|
|
5
|
-
|
|
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 (
|
|
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
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
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
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
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:
|
|
57
|
-
stdout
|
|
41
|
+
message: "Cannot apply ticket plan because local dependency keys contain a cycle or unresolved prerequisite."
|
|
58
42
|
}));
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
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
|
-
|
|
68
|
-
|
|
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
|
|
2
|
-
import
|
|
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:
|
|
6
|
-
dependencies:
|
|
7
|
-
id:
|
|
8
|
-
modified_files:
|
|
9
|
-
ordinal:
|
|
10
|
-
parent_task_id:
|
|
11
|
-
priority:
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
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 {
|
|
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
|
|
5
|
-
import
|
|
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 =
|
|
20
|
-
const taskFrontmatterSchema =
|
|
21
|
-
dependencies:
|
|
21
|
+
const nonEmptyStringSchema = trimmedRequiredString;
|
|
22
|
+
const taskFrontmatterSchema = struct({
|
|
23
|
+
dependencies: withDefault(mutableArray(nonEmptyStringSchema), []),
|
|
22
24
|
id: nonEmptyStringSchema,
|
|
23
|
-
modified_files:
|
|
24
|
-
ordinal:
|
|
25
|
-
parent_task_id:
|
|
26
|
-
priority:
|
|
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
|
-
])
|
|
31
|
-
references:
|
|
32
|
-
status:
|
|
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
|
-
})
|
|
40
|
+
});
|
|
39
41
|
var BacklogTaskStoreError = class extends Data.TaggedError("BacklogTaskStoreError") {};
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
return
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
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
|
-
|
|
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
|
-
|
|
91
|
+
};
|
|
92
|
+
const buildBacklogTaskStoreEffect = (tasks) => Effect.gen(function* effectBody() {
|
|
93
|
+
const tasksById = yield* indexTasksByIdEffect(tasks);
|
|
91
94
|
return {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
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
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
function
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
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 };
|