@oisincoveney/pipeline 3.24.2 → 3.24.3
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 +2 -2
- package/defaults/pipeline.yaml +23 -5
- package/defaults/profiles.yaml +104 -21
- package/dist/argo-graph.js +88 -88
- package/dist/argo-submit.d.ts +109 -137
- package/dist/argo-submit.js +337 -360
- package/dist/argo-workflow.d.ts +156 -176
- 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 +172 -169
- package/dist/cli/factory-commands.js +12 -11
- 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 +2 -2
- package/dist/cli/program.js +35 -43
- package/dist/cli/run-command.js +25 -25
- package/dist/cli/run-commands.js +25 -25
- 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 -2
- package/dist/cli/run-service.js +226 -239
- package/dist/cli/submit-options.js +78 -82
- 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/pipeline-command.js +9 -5
- package/dist/commands/runner-command-command.js +28 -18
- package/dist/commands/ticket/complete.js +29 -33
- package/dist/commands/ticket/create.js +82 -82
- package/dist/commands/ticket/graph-check.js +11 -11
- package/dist/commands/ticket/next.js +36 -36
- package/dist/commands/ticket/sequence.js +10 -12
- package/dist/commands/ticket/shared.d.ts +1 -1
- 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 -139
- package/dist/config/defaults.js +81 -80
- package/dist/config/lint.js +52 -64
- package/dist/config/load.d.ts +4 -4
- package/dist/config/load.js +62 -74
- package/dist/config/schema/catalog.js +1 -1
- package/dist/config/schema/mcp.js +46 -52
- package/dist/config/schemas.d.ts +375 -525
- package/dist/config/schemas.js +397 -397
- package/dist/config/validate.d.ts +1 -1
- package/dist/config/validate.js +236 -201
- package/dist/context/repo-map.js +102 -119
- 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 +38 -42
- 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 -25
- package/dist/hooks.js +20 -22
- package/dist/index.d.ts +1 -1
- package/dist/index.js +21 -35
- package/dist/install-commands/claude-code.js +96 -92
- package/dist/install-commands/host-selection.js +3 -6
- package/dist/install-commands/opencode.js +263 -259
- package/dist/install-commands/planner.js +159 -180
- 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.js +52 -71
- package/dist/loop/backlog-records.js +1 -3
- package/dist/loop/controller-deps.js +146 -159
- package/dist/loop/controller.js +162 -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 +28 -30
- package/dist/loop/merge.js +36 -40
- package/dist/mcp/gateway-config.js +25 -29
- package/dist/mcp/gateway-doctor.js +104 -116
- 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 +50 -54
- package/dist/mcp/toolhive-vmcp.js +39 -39
- package/dist/model-resolver.js +29 -33
- package/dist/moka-global-config.d.ts +78 -54
- package/dist/moka-global-config.js +90 -92
- package/dist/moka-submit.d.ts +2163 -864
- 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 +11 -11
- package/dist/pipeline-runtime.js +49 -50
- package/dist/planned-node.js +6 -3
- package/dist/planning/compile.d.ts +3 -3
- package/dist/planning/compile.js +140 -139
- package/dist/planning/dependency-refs.js +5 -5
- package/dist/planning/generate.d.ts +1293 -1293
- package/dist/planning/generate.js +305 -314
- package/dist/planning/graph.js +131 -149
- package/dist/remote/argo/model.d.ts +103 -121
- 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/submit/argo-submission.js +53 -58
- 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 +5 -0
- package/dist/remote/submit/io.js +40 -43
- package/dist/remote/submit/options.d.ts +50 -0
- package/dist/remote/submit/options.js +27 -0
- package/dist/remote/submit/service.js +45 -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 +40 -100
- package/dist/run-control/contracts.js +56 -69
- package/dist/run-control/detach.js +66 -72
- 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 +66 -78
- package/dist/run-control/postgres/postgres-run-control-store.js +195 -224
- package/dist/run-control/resume-command.js +33 -41
- package/dist/run-control/run-artifacts-command.js +83 -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 +2 -2
- 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 +84 -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 +77 -68
- package/dist/run-control/workspace.js +2 -2
- package/dist/run-state/git-refs.js +257 -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/finalize.js +174 -153
- package/dist/runner-command/lifecycle-context.js +112 -130
- package/dist/runner-command/lifecycle.js +77 -71
- package/dist/runner-command/pre-schedule.js +201 -222
- package/dist/runner-command/run.js +432 -447
- package/dist/runner-command/schedule-source-options.js +8 -10
- package/dist/runner-command/select-ready-wave.js +38 -29
- package/dist/runner-command/task-descriptor.js +11 -17
- package/dist/runner-command-contract.d.ts +147 -156
- package/dist/runner-command-contract.js +401 -410
- package/dist/runner-event-schema.d.ts +364 -504
- 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 +56 -36
- package/dist/runner.js +175 -127
- package/dist/runtime/actor-ids.js +2 -2
- package/dist/runtime/agent-node/agent-node.js +99 -111
- 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 -205
- package/dist/runtime/agent-node/prompt-rendering.js +207 -251
- package/dist/runtime/agent-node/session-execution.js +34 -38
- package/dist/runtime/builtins/builtins.js +212 -284
- package/dist/runtime/changed-files/changed-files.js +26 -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/index.d.ts +1 -1
- package/dist/runtime/detached-race.js +11 -14
- package/dist/runtime/drain-merge/drain-merge.js +137 -163
- package/dist/runtime/durable-store/acquisition.js +5 -3
- package/dist/runtime/durable-store/durable-store.d.ts +1 -1
- package/dist/runtime/durable-store/postgres/migrate-substrate.js +36 -33
- package/dist/runtime/durable-store/postgres/postgres-store.js +17 -18
- package/dist/runtime/events/events.js +255 -323
- 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 +66 -70
- 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 +1 -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 +35 -35
- package/dist/runtime/hooks/policy.js +32 -29
- package/dist/runtime/hooks/results.js +56 -66
- package/dist/runtime/journal-acquisition.d.ts +1 -1
- package/dist/runtime/journal-acquisition.js +14 -14
- package/dist/runtime/json-validation/json-validation.js +50 -72
- package/dist/runtime/local-scheduler.js +46 -48
- package/dist/runtime/node-execution.js +375 -446
- package/dist/runtime/node-protocol/node-protocol.js +36 -79
- package/dist/runtime/node-state-store.d.ts +1 -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 +143 -187
- package/dist/runtime/opencode-adapter.js +23 -24
- package/dist/runtime/opencode-agent-name.js +6 -6
- package/dist/runtime/opencode-runtime.js +92 -92
- package/dist/runtime/opencode-server.js +39 -53
- package/dist/runtime/opencode-session-executor.js +315 -334
- package/dist/runtime/parallel-node/parallel-node.js +122 -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.js +7 -7
- package/dist/runtime/runtime-results.js +54 -69
- package/dist/runtime/scheduled-dependencies.d.ts +1 -1
- package/dist/runtime/scheduled-dependencies.js +59 -74
- package/dist/runtime/scheduler.js +177 -202
- package/dist/runtime/services/agent-node-runtime-service.js +3 -3
- 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 -2
- package/dist/runtime/services/kubernetes-argo-service.js +90 -84
- package/dist/runtime/services/mcp-gateway-service.js +82 -81
- 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 +31 -39
- package/dist/runtime/step/step-node.js +15 -15
- package/dist/runtime/workflow-execution.js +55 -57
- package/dist/runtime/workflow-lifecycle.js +81 -101
- package/dist/safe-json.js +16 -16
- package/dist/schedule/backlog-context.js +120 -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 +12 -18
- package/dist/schedule/passes/references.js +18 -22
- package/dist/schedule/prompts.js +134 -141
- package/dist/schedule/scheduling-roles.js +8 -14
- package/dist/schema-boundary.d.ts +1 -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 +51 -61
- package/dist/tickets/backlog-task-store.d.ts +13 -22
- package/dist/tickets/backlog-task-store.js +80 -94
- package/dist/tickets/completion/complete-ticket.js +53 -59
- package/dist/tickets/ticket-graph-dto.d.ts +24 -47
- package/dist/tickets/ticket-graph-dto.js +40 -40
- package/dist/tickets/ticket-graph.d.ts +7 -1
- 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 +31 -40
- package/dist/tickets/ticket-plan.js +97 -77
- package/dist/tickets/ticket-selection.d.ts +1 -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 -9
- package/dist/workflow-submit-contract.js +10 -9
- 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/runtime-actor-model.md +18 -18
- package/docs/slash-command-adapter-contract.md +3 -3
- package/package.json +73 -76
- package/dist/config/schema/reference-validation.js +0 -83
|
@@ -2,14 +2,8 @@ import { OpencodeServerStartupError, openOpencodeServer } from "../opencode-serv
|
|
|
2
2
|
import { Context, Effect, Layer } from "effect";
|
|
3
3
|
//#region src/runtime/services/opencode-runtime-server-service.ts
|
|
4
4
|
var OpencodeRuntimeServerService = class extends Context.Service()("OpencodeRuntimeServerService") {};
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
try: () => openRuntimeServer(input)
|
|
8
|
-
}) });
|
|
9
|
-
function openRuntimeServer(input) {
|
|
10
|
-
return (input.openServer ?? startServer)(input);
|
|
11
|
-
}
|
|
12
|
-
async function startServer(input) {
|
|
5
|
+
const startupMessage = (error) => `${error.message}. Confirm the opencode binary is installed and recent enough to expose 'opencode serve', or set OPENCODE_SERVER_URL to an already-running server.`;
|
|
6
|
+
const startServer = async (input) => {
|
|
13
7
|
try {
|
|
14
8
|
return await openOpencodeServer({
|
|
15
9
|
directory: input.worktreePath,
|
|
@@ -19,9 +13,13 @@ async function startServer(input) {
|
|
|
19
13
|
if (error instanceof OpencodeServerStartupError) throw new OpencodeServerStartupError(startupMessage(error), { cause: error });
|
|
20
14
|
throw error;
|
|
21
15
|
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
return
|
|
25
|
-
}
|
|
16
|
+
};
|
|
17
|
+
const openRuntimeServer = async (input) => {
|
|
18
|
+
return await (input.openServer ?? startServer)(input);
|
|
19
|
+
};
|
|
20
|
+
const OpencodeRuntimeServerServiceLive = Layer.succeed(OpencodeRuntimeServerService, { open: (input) => Effect.tryPromise({
|
|
21
|
+
catch: (error) => error,
|
|
22
|
+
try: async () => await openRuntimeServer(input)
|
|
23
|
+
}) });
|
|
26
24
|
//#endregion
|
|
27
25
|
export { OpencodeRuntimeServerService, OpencodeRuntimeServerServiceLive };
|
|
@@ -3,22 +3,22 @@ import { createOpencode, createOpencodeClient } from "@opencode-ai/sdk/v2";
|
|
|
3
3
|
//#region src/runtime/services/opencode-sdk-service.ts
|
|
4
4
|
var OpencodeSdkService = class extends Context.Service()("OpencodeSdkService") {};
|
|
5
5
|
const OpencodeSdkServiceLive = Layer.succeed(OpencodeSdkService, {
|
|
6
|
+
abortSession: (client, args) => Effect.tryPromise({
|
|
7
|
+
catch: (error) => error,
|
|
8
|
+
try: async () => await (client.session.abort?.(args) ?? Promise.resolve())
|
|
9
|
+
}),
|
|
6
10
|
createClient: (opts) => Effect.try(() => createOpencodeClient(opts)),
|
|
7
11
|
createSession: (client, args) => Effect.tryPromise({
|
|
8
12
|
catch: (error) => error,
|
|
9
|
-
try: () => client.session.create(args)
|
|
13
|
+
try: async () => await client.session.create(args)
|
|
10
14
|
}),
|
|
11
15
|
promptSession: (client, args) => Effect.tryPromise({
|
|
12
16
|
catch: (error) => error,
|
|
13
|
-
try: () => client.session.prompt(args)
|
|
17
|
+
try: async () => await client.session.prompt(args)
|
|
14
18
|
}),
|
|
15
19
|
spawnServer: (args, spawn = createOpencode) => Effect.tryPromise({
|
|
16
20
|
catch: (error) => error,
|
|
17
|
-
try: () => spawn(args)
|
|
18
|
-
}),
|
|
19
|
-
abortSession: (client, args) => Effect.tryPromise({
|
|
20
|
-
catch: (error) => error,
|
|
21
|
-
try: () => client.session.abort?.(args) ?? Promise.resolve(void 0)
|
|
21
|
+
try: async () => await spawn(args)
|
|
22
22
|
}),
|
|
23
23
|
subscribeEvents: (client) => Effect.tryPromise({
|
|
24
24
|
catch: (error) => error,
|
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import { Cause, Context, Effect, Layer, Option } from "effect";
|
|
2
1
|
import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
|
|
2
|
+
import { Cause, Context, Effect, Layer, Option } from "effect";
|
|
3
3
|
import { Language, Parser } from "web-tree-sitter";
|
|
4
4
|
//#region src/runtime/services/repo-io-service.ts
|
|
5
5
|
let parserInitPromise = null;
|
|
6
|
-
|
|
6
|
+
const initializeParser = async () => {
|
|
7
7
|
parserInitPromise ??= Parser.init();
|
|
8
|
-
|
|
9
|
-
}
|
|
8
|
+
await parserInitPromise;
|
|
9
|
+
};
|
|
10
10
|
var RepoIoService = class extends Context.Service()("RepoIoService") {};
|
|
11
|
+
const direntCompare = (a, b) => a.name.localeCompare(b.name);
|
|
11
12
|
const RepoIoServiceLive = Layer.succeed(RepoIoService, {
|
|
12
13
|
createParser: () => Effect.tryPromise({
|
|
13
14
|
catch: (error) => error,
|
|
@@ -23,7 +24,7 @@ const RepoIoServiceLive = Layer.succeed(RepoIoService, {
|
|
|
23
24
|
}),
|
|
24
25
|
loadLanguage: (path) => Effect.tryPromise({
|
|
25
26
|
catch: (error) => error,
|
|
26
|
-
try: () => Language.load(path)
|
|
27
|
+
try: async () => await Language.load(path)
|
|
27
28
|
}),
|
|
28
29
|
readDir: (path) => Effect.try({
|
|
29
30
|
catch: (error) => error,
|
|
@@ -31,18 +32,15 @@ const RepoIoServiceLive = Layer.succeed(RepoIoService, {
|
|
|
31
32
|
}),
|
|
32
33
|
readText: (path) => Effect.try({
|
|
33
34
|
catch: (error) => error,
|
|
34
|
-
try: () => readFileSync(path, "
|
|
35
|
+
try: () => readFileSync(path, "utf-8")
|
|
35
36
|
})
|
|
36
37
|
});
|
|
37
|
-
|
|
38
|
-
return a.name.localeCompare(b.name);
|
|
39
|
-
}
|
|
40
|
-
function runRepoIoSync(program) {
|
|
38
|
+
const runRepoIoSync = (program) => {
|
|
41
39
|
const exit = Effect.runSyncExit(Effect.provide(program, RepoIoServiceLive));
|
|
42
40
|
if (exit._tag === "Success") return exit.value;
|
|
43
41
|
const originalError = Option.getOrUndefined(Cause.findErrorOption(exit.cause));
|
|
44
|
-
if (originalError) throw originalError;
|
|
42
|
+
if (originalError !== void 0) throw originalError;
|
|
45
43
|
throw Cause.squash(exit.cause);
|
|
46
|
-
}
|
|
44
|
+
};
|
|
47
45
|
//#endregion
|
|
48
46
|
export { RepoIoService, RepoIoServiceLive, runRepoIoSync };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { Context, Effect, Layer } from "effect";
|
|
2
1
|
import { appendFileSync, existsSync, mkdirSync, readFileSync } from "node:fs";
|
|
3
2
|
import { dirname } from "node:path";
|
|
3
|
+
import { Context, Effect, Layer, Option } from "effect";
|
|
4
4
|
//#region src/runtime/services/run-journal-file-service.ts
|
|
5
5
|
var RunJournalFileService = class extends Context.Service()("RunJournalFileService") {};
|
|
6
6
|
Layer.succeed(RunJournalFileService, {
|
|
@@ -13,7 +13,7 @@ Layer.succeed(RunJournalFileService, {
|
|
|
13
13
|
}),
|
|
14
14
|
readTextIfExists: (path) => Effect.try({
|
|
15
15
|
catch: (error) => error,
|
|
16
|
-
try: () => existsSync(path) ? readFileSync(path, "
|
|
16
|
+
try: () => existsSync(path) ? Option.some(readFileSync(path, "utf-8")) : Option.none()
|
|
17
17
|
})
|
|
18
18
|
});
|
|
19
19
|
//#endregion
|
|
@@ -1,16 +1,20 @@
|
|
|
1
|
+
import { parseResultWithSchema } from "../../schema-boundary.js";
|
|
1
2
|
import { prepareOpencodeCredentials } from "../../credentials/runner.js";
|
|
2
3
|
import { commitAndPushNodeRef, mergeDependencyRefs, prepareRunnerGitWorkspace, promoteFinalRef } from "../../run-state/git-refs.js";
|
|
3
4
|
import { runScheduledWorkflowTask } from "../../pipeline-runtime.js";
|
|
4
5
|
import { resolveRunnerEventSinkAuthToken } from "../../runner-command-contract.js";
|
|
5
6
|
import { createRunnerEventSink } from "../../runner-event-sink.js";
|
|
6
|
-
import
|
|
7
|
+
import * as Effect from "effect/Effect";
|
|
7
8
|
import { existsSync, readFileSync } from "node:fs";
|
|
9
|
+
import * as Context from "effect/Context";
|
|
10
|
+
import * as Layer from "effect/Layer";
|
|
11
|
+
import * as Schedule from "effect/Schedule";
|
|
8
12
|
import { execa } from "execa";
|
|
9
13
|
//#region src/runtime/services/runner-command-io-service.ts
|
|
10
14
|
const TERMINAL_FLUSH_RETRY_LIMIT = 60;
|
|
11
15
|
const TERMINAL_FLUSH_RETRY_DELAY = "1 second";
|
|
12
16
|
const TERMINAL_FLUSH_TIMEOUT = "60 seconds";
|
|
13
|
-
|
|
17
|
+
const createRunnerCommandEventSink = ({ fetch, payload }) => {
|
|
14
18
|
const authToken = resolveRunnerEventSinkAuthToken({ authTokenFile: payload.events.authTokenFile });
|
|
15
19
|
return createRunnerEventSink({
|
|
16
20
|
authHeader: payload.events.authHeader,
|
|
@@ -19,84 +23,76 @@ function createRunnerCommandEventSink({ fetch, payload }) {
|
|
|
19
23
|
runId: payload.run.id,
|
|
20
24
|
url: payload.events.url
|
|
21
25
|
});
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
const result = yield* Effect.result(flushSinkWithTerminalRetry(io.flushSink, sink));
|
|
27
|
-
if (result._tag === "Success") return;
|
|
28
|
-
reportError(errorMessage(result.failure));
|
|
29
|
-
});
|
|
30
|
-
}
|
|
31
|
-
function flushSinkWithTerminalRetry(flushSink, sink) {
|
|
32
|
-
return flushSink(sink).pipe(Effect.retry(terminalFlushRetrySchedule()), Effect.timeout(TERMINAL_FLUSH_TIMEOUT));
|
|
33
|
-
}
|
|
34
|
-
function terminalFlushRetrySchedule() {
|
|
35
|
-
return Schedule.spaced(TERMINAL_FLUSH_RETRY_DELAY).pipe(Schedule.both(Schedule.recurs(TERMINAL_FLUSH_RETRY_LIMIT)));
|
|
36
|
-
}
|
|
37
|
-
function errorMessage(error) {
|
|
38
|
-
return error instanceof Error ? error.message : String(error);
|
|
39
|
-
}
|
|
26
|
+
};
|
|
27
|
+
const terminalFlushRetrySchedule = () => Schedule.spaced(TERMINAL_FLUSH_RETRY_DELAY).pipe(Schedule.both(Schedule.recurs(TERMINAL_FLUSH_RETRY_LIMIT)));
|
|
28
|
+
const flushSinkWithTerminalRetry = (flushSink, sink) => flushSink(sink).pipe(Effect.retry(terminalFlushRetrySchedule()), Effect.timeout(TERMINAL_FLUSH_TIMEOUT));
|
|
29
|
+
const errorMessage = (error) => error instanceof Error ? error.message : String(error);
|
|
40
30
|
var RunnerCommandIoService = class extends Context.Service()("RunnerCommandIoService") {};
|
|
31
|
+
const flushRunnerCommandSink = (sink, reportError) => Effect.gen(function* effectBody() {
|
|
32
|
+
const io = yield* RunnerCommandIoService;
|
|
33
|
+
const result = yield* Effect.result(flushSinkWithTerminalRetry(io.flushSink, sink));
|
|
34
|
+
if (result._tag === "Success") return;
|
|
35
|
+
reportError(errorMessage(result.failure));
|
|
36
|
+
});
|
|
41
37
|
const RunnerCommandIoServiceLive = Layer.succeed(RunnerCommandIoService, {
|
|
42
38
|
commitAndPushNodeRef: (options) => Effect.tryPromise({
|
|
43
|
-
|
|
44
|
-
|
|
39
|
+
catch: (error) => error,
|
|
40
|
+
try: async () => await commitAndPushNodeRef(options)
|
|
45
41
|
}),
|
|
46
42
|
exists: (path) => Effect.try({
|
|
47
|
-
|
|
48
|
-
|
|
43
|
+
catch: (error) => error,
|
|
44
|
+
try: () => existsSync(path)
|
|
49
45
|
}),
|
|
50
46
|
flushSink: (sink) => Effect.tryPromise({
|
|
51
|
-
|
|
52
|
-
|
|
47
|
+
catch: (error) => error,
|
|
48
|
+
try: async () => {
|
|
49
|
+
await sink.flush();
|
|
50
|
+
}
|
|
53
51
|
}),
|
|
54
52
|
mergeDependencyRefs: (options) => Effect.tryPromise({
|
|
55
|
-
|
|
56
|
-
|
|
53
|
+
catch: (error) => error,
|
|
54
|
+
try: async () => {
|
|
55
|
+
await mergeDependencyRefs(options);
|
|
56
|
+
}
|
|
57
57
|
}),
|
|
58
58
|
prepareOpencodeCredentials: () => Effect.try({
|
|
59
|
-
|
|
60
|
-
|
|
59
|
+
catch: (error) => error,
|
|
60
|
+
try: () => prepareOpencodeCredentials()
|
|
61
61
|
}),
|
|
62
62
|
prepareRunnerGitWorkspace: (payload, options) => Effect.tryPromise({
|
|
63
|
-
|
|
64
|
-
|
|
63
|
+
catch: (error) => error,
|
|
64
|
+
try: async () => await prepareRunnerGitWorkspace(payload, options)
|
|
65
65
|
}),
|
|
66
66
|
promoteFinalRef: (options) => Effect.tryPromise({
|
|
67
|
-
|
|
68
|
-
|
|
67
|
+
catch: (error) => error,
|
|
68
|
+
try: async () => await promoteFinalRef(options)
|
|
69
69
|
}),
|
|
70
70
|
readText: (path) => Effect.try({
|
|
71
|
-
|
|
72
|
-
|
|
71
|
+
catch: (error) => error,
|
|
72
|
+
try: () => readFileSync(path, "utf-8")
|
|
73
73
|
}),
|
|
74
74
|
runScheduledWorkflowTask: (options) => Effect.tryPromise({
|
|
75
|
-
|
|
76
|
-
|
|
75
|
+
catch: (error) => error,
|
|
76
|
+
try: async () => await runScheduledWorkflowTask(options)
|
|
77
77
|
}),
|
|
78
78
|
runSetupCommand: (command, args, options) => Effect.tryPromise({
|
|
79
|
-
|
|
79
|
+
catch: (error) => error,
|
|
80
|
+
try: async () => await execa(command, args, {
|
|
80
81
|
cwd: options.cwd,
|
|
81
82
|
env: options.env,
|
|
82
83
|
reject: false
|
|
83
|
-
})
|
|
84
|
-
catch: (error) => error
|
|
84
|
+
})
|
|
85
85
|
})
|
|
86
86
|
});
|
|
87
87
|
const EXIT_VALIDATION = 64;
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
return flushRunnerCommandSink(sink, (message) => stderr.write(`runner event flush failed: ${message}\n`));
|
|
93
|
-
}
|
|
94
|
-
function runValidatedRunnerCommand(schema, rawOptions, toEffect) {
|
|
95
|
-
const parsed = schema.safeParse(rawOptions);
|
|
88
|
+
const isOutputStream = (value) => typeof value === "object" && value !== null && "write" in value && typeof value.write === "function";
|
|
89
|
+
const flushAndReport = (sink, stderr) => flushRunnerCommandSink(sink, (message) => stderr.write(`runner event flush failed: ${message}\n`));
|
|
90
|
+
const runValidatedRunnerCommand = async (schema, rawOptions, toEffect) => {
|
|
91
|
+
const parsed = parseResultWithSchema(schema, rawOptions, { onExcessProperty: "error" });
|
|
96
92
|
const stderr = rawOptions.stderr ?? process.stderr;
|
|
97
|
-
if (parsed.
|
|
93
|
+
if (parsed.ok) return await Effect.runPromise(Effect.provide(toEffect(parsed.value, stderr), RunnerCommandIoServiceLive));
|
|
98
94
|
stderr.write(`${parsed.error.message}\n`);
|
|
99
|
-
return
|
|
100
|
-
}
|
|
95
|
+
return EXIT_VALIDATION;
|
|
96
|
+
};
|
|
101
97
|
//#endregion
|
|
102
98
|
export { RunnerCommandIoService, RunnerCommandIoServiceLive, createRunnerCommandEventSink, flushAndReport, isOutputStream, runValidatedRunnerCommand };
|
|
@@ -4,8 +4,8 @@ import ky, { isHTTPError } from "ky";
|
|
|
4
4
|
var EventSinkHttpError = class extends Data.TaggedError("EventSinkHttpError") {
|
|
5
5
|
constructor(status, message) {
|
|
6
6
|
super({
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
message,
|
|
8
|
+
status
|
|
9
9
|
});
|
|
10
10
|
}
|
|
11
11
|
};
|
|
@@ -26,42 +26,37 @@ const RETRYABLE_STATUS_CODES = [
|
|
|
26
26
|
511
|
|
27
27
|
];
|
|
28
28
|
const REQUEST_TIMEOUT_MS = 1e4;
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
}
|
|
32
|
-
function httpErrorData(error) {
|
|
33
|
-
return formatHttpErrorData(isHTTPError(error) ? error.data : void 0);
|
|
34
|
-
}
|
|
35
|
-
function formatHttpErrorData(data) {
|
|
29
|
+
const authHeaderName = (request) => request.authHeader ?? "Authorization";
|
|
30
|
+
const formatHttpErrorData = (data) => {
|
|
36
31
|
if (typeof data === "string") return data;
|
|
37
32
|
return data === void 0 ? "" : JSON.stringify(data);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
return error
|
|
41
|
-
}
|
|
42
|
-
|
|
33
|
+
};
|
|
34
|
+
const httpErrorData = (error) => {
|
|
35
|
+
return formatHttpErrorData(isHTTPError(error) ? error.data : void 0);
|
|
36
|
+
};
|
|
37
|
+
const toError = (error) => error instanceof Error ? error : new Error(String(error));
|
|
38
|
+
const toHttpError = (error) => {
|
|
43
39
|
const data = httpErrorData(error);
|
|
44
40
|
const status = isHTTPError(error) ? error.response.status : 0;
|
|
45
41
|
return new EventSinkHttpError(status, `Event sink responded with ${status}${data ? `: ${data}` : ""}`);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
try: () => ky.post(request.url, {
|
|
42
|
+
};
|
|
43
|
+
const mapPostError = (error) => isHTTPError(error) ? toHttpError(error) : toError(error);
|
|
44
|
+
const kyFetchAdapter = (fetchImpl) => async (input, init) => {
|
|
45
|
+
const request = new Request(input, init);
|
|
46
|
+
return await fetchImpl(request.url, {
|
|
47
|
+
body: await request.clone().text(),
|
|
48
|
+
headers: request.headers,
|
|
49
|
+
method: request.method,
|
|
50
|
+
signal: request.signal
|
|
51
|
+
});
|
|
52
|
+
};
|
|
53
|
+
const totalTimeoutMs = (request) => {
|
|
54
|
+
return (request.maxRetries + 1) * REQUEST_TIMEOUT_MS + request.maxRetries * request.retryDelayMs;
|
|
55
|
+
};
|
|
56
|
+
const postBatch = (request) => Effect.tryPromise({
|
|
57
|
+
catch: mapPostError,
|
|
58
|
+
try: async () => {
|
|
59
|
+
await ky.post(request.url, {
|
|
65
60
|
fetch: kyFetchAdapter(request.fetch),
|
|
66
61
|
headers: { [authHeaderName(request)]: `Bearer ${request.authToken}` },
|
|
67
62
|
json: { events: request.events },
|
|
@@ -74,12 +69,9 @@ function postBatch(request) {
|
|
|
74
69
|
},
|
|
75
70
|
timeout: REQUEST_TIMEOUT_MS,
|
|
76
71
|
totalTimeout: totalTimeoutMs(request)
|
|
77
|
-
}).then(() =>
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
function totalTimeoutMs(request) {
|
|
81
|
-
return (request.maxRetries + 1) * REQUEST_TIMEOUT_MS + request.maxRetries * request.retryDelayMs;
|
|
82
|
-
}
|
|
72
|
+
}).then(() => {});
|
|
73
|
+
}
|
|
74
|
+
});
|
|
83
75
|
var RunnerEventSinkHttpService = class extends Context.Service()("RunnerEventSinkHttpService") {};
|
|
84
76
|
const RunnerEventSinkHttpServiceLive = Layer.succeed(RunnerEventSinkHttpService, { postBatch });
|
|
85
77
|
//#endregion
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import "../scheduler.js";
|
|
2
|
+
import * as Option$2 from "effect/Option";
|
|
2
3
|
import "effect";
|
|
3
4
|
//#region src/runtime/step/step-node.ts
|
|
4
5
|
/**
|
|
@@ -7,12 +8,10 @@ import "effect";
|
|
|
7
8
|
* settled — a failed node is not re-emitted as ready, and a failed dependency
|
|
8
9
|
* blocks its dependents via {@link computeReadyNodeIds}'s default check.
|
|
9
10
|
*/
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
});
|
|
15
|
-
}
|
|
11
|
+
const collectStoredResults = (input) => input.nodes.flatMap((node) => {
|
|
12
|
+
const record = input.store.get(input.runId, node.id);
|
|
13
|
+
return Option$2.isSome(record) ? [record.value.result] : [];
|
|
14
|
+
});
|
|
16
15
|
/**
|
|
17
16
|
* Build the {@link NextNodeEnvelope} for a SPECIFIC node — everything that node
|
|
18
17
|
* needs to execute, made explicit and serializable. Returns `undefined` when the
|
|
@@ -20,34 +19,35 @@ function collectStoredResults(input) {
|
|
|
20
19
|
* outputs of the node's direct `needs` — a failed upstream has no meaningful
|
|
21
20
|
* output to hand the next executor. Pure: all store reads come from `input.store`.
|
|
22
21
|
*/
|
|
23
|
-
|
|
22
|
+
const buildEnvelopeForNodeOption = (input, nodeId) => {
|
|
24
23
|
const node = input.nodes.find((candidate) => candidate.id === nodeId);
|
|
25
|
-
if (node === void 0) return;
|
|
24
|
+
if (node === void 0) return Option$2.none();
|
|
26
25
|
const meta = input.nodeMetadata.get(nodeId);
|
|
27
26
|
const prompt = meta?.prompt ?? "";
|
|
28
27
|
const criteria = meta?.criteria ? [...meta.criteria] : [];
|
|
29
28
|
const passedByNodeId = new Map(collectStoredResults(input).filter((result) => result.status === "passed").map((result) => [result.nodeId, result]));
|
|
30
29
|
const upstreamOutputs = node.needs.flatMap((needId) => {
|
|
31
30
|
const result = passedByNodeId.get(needId);
|
|
32
|
-
return result ? [{
|
|
31
|
+
return result === void 0 ? [] : [{
|
|
33
32
|
nodeId: needId,
|
|
34
33
|
output: result.output
|
|
35
|
-
}]
|
|
34
|
+
}];
|
|
36
35
|
});
|
|
37
|
-
return {
|
|
36
|
+
return Option$2.some({
|
|
38
37
|
criteria,
|
|
39
38
|
nodeId,
|
|
40
39
|
prompt,
|
|
41
40
|
runId: input.runId,
|
|
42
41
|
upstreamOutputs
|
|
43
|
-
};
|
|
44
|
-
}
|
|
45
|
-
|
|
42
|
+
});
|
|
43
|
+
};
|
|
44
|
+
const buildEnvelopeForNode = (input, nodeId) => Option$2.getOrUndefined(buildEnvelopeForNodeOption(input, nodeId));
|
|
45
|
+
const recordNodeResult = (input) => {
|
|
46
46
|
input.store.record(input.runId, input.result.nodeId, {
|
|
47
47
|
criteria: [],
|
|
48
48
|
inputs: void 0,
|
|
49
49
|
result: input.result
|
|
50
50
|
});
|
|
51
|
-
}
|
|
51
|
+
};
|
|
52
52
|
//#endregion
|
|
53
53
|
export { buildEnvelopeForNode, collectStoredResults, recordNodeResult };
|
|
@@ -9,76 +9,74 @@ import { LocalScheduler } from "./local-scheduler.js";
|
|
|
9
9
|
import { workflowRuntimeResult } from "./runtime-results.js";
|
|
10
10
|
import { executePlannedNode, isCancelled, markNodeReady, recordSkippedNodeState } from "./node-execution.js";
|
|
11
11
|
import { hydrateDependencyOutputs, hydrateScheduledDependencyStates } from "./scheduled-dependencies.js";
|
|
12
|
-
import { Effect } from "effect";
|
|
12
|
+
import { Effect, Option } from "effect";
|
|
13
13
|
//#region src/runtime/workflow-execution.ts
|
|
14
|
-
|
|
15
|
-
return Effect.scoped(Effect.gen(function* () {
|
|
16
|
-
const scheduler = buildPipelineScheduler(context, yield* acquireRunJournal(context.runId, dbUrl));
|
|
17
|
-
return finishRuntime(context, yield* Effect.tryPromise(() => scheduler.runWorkflow(context.plan, context)));
|
|
18
|
-
}));
|
|
19
|
-
}
|
|
20
|
-
function resumeRunWithContext(context, dbUrl) {
|
|
21
|
-
return Effect.scoped(Effect.gen(function* () {
|
|
22
|
-
const journal = yield* acquireRunJournal(context.runId, dbUrl);
|
|
23
|
-
yield* requireResumableRun(context.runId, journal);
|
|
24
|
-
const scheduler = buildPipelineScheduler(context, journal);
|
|
25
|
-
return finishRuntime(context, yield* Effect.tryPromise(() => scheduler.runWorkflow(context.plan, context)));
|
|
26
|
-
}));
|
|
27
|
-
}
|
|
28
|
-
function executeScheduledWorkflowTaskWithContext(context, nodeId, dependencyOutputs) {
|
|
14
|
+
const executeScheduledWorkflowTaskWithContext = (context, nodeId, dependencyOutputs) => {
|
|
29
15
|
hydrateScheduledDependencyStates(context, nodeId);
|
|
30
16
|
hydrateDependencyOutputs(context, dependencyOutputs);
|
|
31
17
|
markNodeReady(context, nodeId);
|
|
32
18
|
return executePlannedNode(nodeId, context);
|
|
33
|
-
}
|
|
34
|
-
|
|
19
|
+
};
|
|
20
|
+
const requireResumableRun = (runId, journal) => {
|
|
35
21
|
if (journal === void 0) return Effect.fail(/* @__PURE__ */ new Error(`Cannot resume run '${runId ?? "<unknown>"}': no durable store is configured (set momokaya.db.url).`));
|
|
36
22
|
if (journal.resumeCompleted().length === 0) return Effect.fail(/* @__PURE__ */ new Error(`Cannot resume run '${runId}': no persisted node results were found in the durable store.`));
|
|
37
23
|
return Effect.void;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
buildResult: (outcome, nodes, failure) => workflowRuntimeResult(context, outcome, nodes, failure),
|
|
42
|
-
emitWorkflowPlanned: (nextContext) => emitWorkflowPlanned(nextContext),
|
|
43
|
-
emitWorkflowStarted: (nextContext) => emitWorkflowStarted(nextContext),
|
|
44
|
-
executeNode: (nodeId, nextContext) => Effect.runPromise(executePlannedNode(nodeId, nextContext)),
|
|
45
|
-
isCancelled: (nextContext) => isCancelled(nextContext),
|
|
46
|
-
markNodeReady: (nodeId, nextContext) => markNodeReady(nextContext, nodeId),
|
|
47
|
-
resolveJournal: () => journal,
|
|
48
|
-
runWorkflowHook: (event, failure, nextContext) => Effect.runPromise(dispatchHooksEffect(nextContext, event, failure)),
|
|
49
|
-
shouldContinueAfterNodeResult: (result, nextContext) => shouldContinueAfterNodeResult(result, nextContext),
|
|
50
|
-
skipNode: (nodeId, reason, nextContext) => recordSkippedNodeState(nextContext, nodeId, reason)
|
|
51
|
-
});
|
|
52
|
-
}
|
|
53
|
-
function shouldContinueAfterNodeResult(result, context) {
|
|
54
|
-
if (result.status !== "failed") return true;
|
|
55
|
-
return isRecoverableParallelFailure(context.plan.graph.node(result.nodeId), result.output, context);
|
|
56
|
-
}
|
|
57
|
-
function isRecoverableParallelFailure(node, output, context) {
|
|
58
|
-
if (!isParallelWithChildren(node, output)) return false;
|
|
59
|
-
return hasOnlyDrainMergeDependents(node, context);
|
|
60
|
-
}
|
|
61
|
-
function isParallelWithChildren(node, output) {
|
|
24
|
+
};
|
|
25
|
+
const parallelOutputHasChildren = (output) => Object.keys(parseJsonObject(parseJsonObject(output).children)).length > 0;
|
|
26
|
+
const isParallelWithChildren = (output, node) => {
|
|
62
27
|
if (!node) return false;
|
|
63
28
|
return node.kind === "parallel" ? parallelOutputHasChildren(output) : false;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
if (node.dependents.length === 0) return false;
|
|
67
|
-
return node.dependents.every((dependentId) => isDrainMergeNode(context.plan.graph.node(dependentId)));
|
|
68
|
-
}
|
|
69
|
-
function parallelOutputHasChildren(output) {
|
|
70
|
-
return Object.keys(parseJsonObject(parseJsonObject(output).children)).length > 0;
|
|
71
|
-
}
|
|
72
|
-
function isDrainMergeNode(node) {
|
|
29
|
+
};
|
|
30
|
+
const isDrainMergeNode = (node) => {
|
|
73
31
|
if (!node) return false;
|
|
74
32
|
return node.kind === "builtin" ? node.builtin === "drain-merge" : false;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
33
|
+
};
|
|
34
|
+
const hasOnlyDrainMergeDependents = (node, context) => {
|
|
35
|
+
if (node.dependents.length === 0) return false;
|
|
36
|
+
return node.dependents.every((dependentId) => isDrainMergeNode(context.plan.graph.node(dependentId)));
|
|
37
|
+
};
|
|
38
|
+
const isRecoverableParallelFailure = (output, context, node) => {
|
|
39
|
+
if (!isParallelWithChildren(output, node)) return false;
|
|
40
|
+
return hasOnlyDrainMergeDependents(node, context);
|
|
41
|
+
};
|
|
42
|
+
const shouldContinueAfterNodeResult = (result, context) => {
|
|
43
|
+
if (result.status !== "failed") return true;
|
|
44
|
+
const node = context.plan.graph.node(result.nodeId);
|
|
45
|
+
return isRecoverableParallelFailure(result.output, context, node);
|
|
46
|
+
};
|
|
47
|
+
const dispatchHooksEffect = (...args) => Effect.tryPromise(async () => await dispatchHooks(...args)).pipe(Effect.map(Option.fromNullishOr));
|
|
48
|
+
const buildPipelineScheduler = (context, journal) => new LocalScheduler({
|
|
49
|
+
buildResult: (outcome, nodes, failure) => workflowRuntimeResult(context, outcome, nodes, failure),
|
|
50
|
+
emitWorkflowPlanned: (nextContext) => {
|
|
51
|
+
emitWorkflowPlanned(nextContext);
|
|
52
|
+
},
|
|
53
|
+
emitWorkflowStarted: (nextContext) => {
|
|
54
|
+
emitWorkflowStarted(nextContext);
|
|
55
|
+
},
|
|
56
|
+
executeNode: async (nodeId, nextContext) => await Effect.runPromise(executePlannedNode(nodeId, nextContext)),
|
|
57
|
+
isCancelled: (nextContext) => isCancelled(nextContext),
|
|
58
|
+
markNodeReady: (nodeId, nextContext) => {
|
|
59
|
+
markNodeReady(nextContext, nodeId);
|
|
60
|
+
},
|
|
61
|
+
resolveJournal: () => Option.fromUndefinedOr(journal),
|
|
62
|
+
runWorkflowHook: async (event, nextContext, failure) => await Effect.runPromise(dispatchHooksEffect(nextContext, event, failure)),
|
|
63
|
+
shouldContinueAfterNodeResult: (result, nextContext) => shouldContinueAfterNodeResult(result, nextContext),
|
|
64
|
+
skipNode: (nodeId, reason, nextContext) => {
|
|
65
|
+
recordSkippedNodeState(nextContext, nodeId, reason);
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
const finishRuntime = (context, result) => {
|
|
80
69
|
emitWorkflowFinish(context, result.outcome);
|
|
81
70
|
return result;
|
|
82
|
-
}
|
|
71
|
+
};
|
|
72
|
+
const skipRunValidation = () => Effect.void;
|
|
73
|
+
const runWorkflowWithContext = (context, dbUrl, validateRun = skipRunValidation) => Effect.scoped(Effect.gen(function* effectBody() {
|
|
74
|
+
const journal = yield* acquireRunJournal(Option.fromUndefinedOr(context.runId), dbUrl);
|
|
75
|
+
yield* validateRun(journal);
|
|
76
|
+
const scheduler = buildPipelineScheduler(context, Option.getOrUndefined(journal));
|
|
77
|
+
return finishRuntime(context, yield* Effect.tryPromise(async () => await scheduler.runWorkflow(context.plan, context)));
|
|
78
|
+
}));
|
|
79
|
+
const runPipelineWithContext = (context, dbUrl) => runWorkflowWithContext(context, Option.fromUndefinedOr(dbUrl));
|
|
80
|
+
const resumeRunWithContext = (context, dbUrl) => runWorkflowWithContext(context, Option.fromUndefinedOr(dbUrl), (journal) => requireResumableRun(context.runId, Option.getOrUndefined(journal)));
|
|
83
81
|
//#endregion
|
|
84
82
|
export { executeScheduledWorkflowTaskWithContext, resumeRunWithContext, runPipelineWithContext };
|