@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
|
@@ -1,56 +1,53 @@
|
|
|
1
1
|
import { createSerializedWriteQueue } from "../serialized-write-queue.js";
|
|
2
2
|
import { withRunStateLock } from "./run-state-lock.js";
|
|
3
3
|
import { createRuntimeEventProjectionState, projectRuntimeEvent } from "./runtime-event-projection.js";
|
|
4
|
-
import { Effect } from "effect";
|
|
5
4
|
import { isAbsolute, join } from "node:path";
|
|
5
|
+
import { Effect } from "effect";
|
|
6
6
|
import { appendFile, mkdir } from "node:fs/promises";
|
|
7
7
|
//#region src/run-control/runtime-reporter.ts
|
|
8
8
|
const RUNS_DIRECTORY = ".pipeline/runs";
|
|
9
9
|
const RUNTIME_EVENTS_FILE = "runtime-events.jsonl";
|
|
10
10
|
const NODES_DIRECTORY = "nodes";
|
|
11
11
|
const STDOUT_ARTIFACT = "stdout.jsonl";
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
});
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
return store.statusPaths({ runId }).manifest.startsWith(`${RUNS_DIRECTORY}/`);
|
|
52
|
-
}
|
|
53
|
-
function persistStoreWriteIntentEffect(input, store, writeIntent, now) {
|
|
12
|
+
const writesFilesystemRunState = (store, runId) => store.statusPaths({ runId }).manifest.startsWith(`${RUNS_DIRECTORY}/`);
|
|
13
|
+
const appendJsonlEffect = (path, value) => Effect.tryPromise({
|
|
14
|
+
catch: (error) => error,
|
|
15
|
+
try: async () => {
|
|
16
|
+
await appendFile(path, `${JSON.stringify(value)}\n`, "utf-8");
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
const mkdirEffect = (path, options) => Effect.tryPromise({
|
|
20
|
+
catch: (error) => error,
|
|
21
|
+
try: async () => await mkdir(path, options)
|
|
22
|
+
}).pipe(Effect.asVoid);
|
|
23
|
+
const logicalSegment = (label, value) => {
|
|
24
|
+
if (value.length === 0 || isAbsolute(value) || value.includes("/") || value.includes("\\") || value === "." || value === "..") throw new Error(`${label} must be a non-empty logical identifier.`);
|
|
25
|
+
return value;
|
|
26
|
+
};
|
|
27
|
+
const runDirectory = (workspaceRoot, runId) => join(workspaceRoot, RUNS_DIRECTORY, logicalSegment("runId", runId));
|
|
28
|
+
const runDirectoryEffect = (workspaceRoot, runId) => Effect.try({
|
|
29
|
+
catch: (error) => error,
|
|
30
|
+
try: () => runDirectory(workspaceRoot, runId)
|
|
31
|
+
});
|
|
32
|
+
const appendRuntimeEventEffect = (input, event) => Effect.gen(function* effectBody() {
|
|
33
|
+
const runRoot = yield* runDirectoryEffect(input.workspaceRoot, input.runId);
|
|
34
|
+
yield* mkdirEffect(runRoot, { recursive: true });
|
|
35
|
+
yield* appendJsonlEffect(join(runRoot, RUNTIME_EVENTS_FILE), event);
|
|
36
|
+
});
|
|
37
|
+
const logicalSegmentEffect = (label, value) => Effect.try({
|
|
38
|
+
catch: (error) => error,
|
|
39
|
+
try: () => logicalSegment(label, value)
|
|
40
|
+
});
|
|
41
|
+
const appendNodeStdoutEffect = (input, nodeId, event) => Effect.gen(function* effectBody() {
|
|
42
|
+
const nodeRoot = join(yield* runDirectoryEffect(input.workspaceRoot, input.runId), NODES_DIRECTORY, yield* logicalSegmentEffect("nodeId", nodeId));
|
|
43
|
+
yield* mkdirEffect(nodeRoot, { recursive: true });
|
|
44
|
+
yield* appendJsonlEffect(join(nodeRoot, STDOUT_ARTIFACT), event);
|
|
45
|
+
});
|
|
46
|
+
const timestamp = (now) => now().toISOString();
|
|
47
|
+
const assertNever = (value) => {
|
|
48
|
+
throw new Error(`Unhandled runtime reporter value: ${String(value)}`);
|
|
49
|
+
};
|
|
50
|
+
const persistStoreWriteIntentEffect = (input, store, writeIntent, now) => {
|
|
54
51
|
switch (writeIntent.type) {
|
|
55
52
|
case "node.session": return store.updateNodeSession({
|
|
56
53
|
nodeId: writeIntent.nodeId,
|
|
@@ -70,66 +67,51 @@ function persistStoreWriteIntentEffect(input, store, writeIntent, now) {
|
|
|
70
67
|
});
|
|
71
68
|
default: return assertNever(writeIntent);
|
|
72
69
|
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
return join(workspaceRoot, RUNS_DIRECTORY, logicalSegment("runId", runId));
|
|
102
|
-
}
|
|
103
|
-
function runDirectoryEffect(workspaceRoot, runId) {
|
|
104
|
-
return Effect.try({
|
|
105
|
-
catch: (error) => error,
|
|
106
|
-
try: () => runDirectory(workspaceRoot, runId)
|
|
107
|
-
});
|
|
108
|
-
}
|
|
109
|
-
function logicalSegment(label, value) {
|
|
110
|
-
if (value.length === 0 || isAbsolute(value) || value.includes("/") || value.includes("\\") || value === "." || value === "..") throw new Error(`${label} must be a non-empty logical identifier.`);
|
|
111
|
-
return value;
|
|
112
|
-
}
|
|
113
|
-
function logicalSegmentEffect(label, value) {
|
|
114
|
-
return Effect.try({
|
|
70
|
+
};
|
|
71
|
+
const persistRuntimeEventEffect = (input, store, event, writeIntents, now) => Effect.gen(function* effectBody() {
|
|
72
|
+
const writesFilesystemObservability = writesFilesystemRunState(store, input.runId);
|
|
73
|
+
if (writesFilesystemObservability) yield* appendRuntimeEventEffect(input, event);
|
|
74
|
+
for (const writeIntent of writeIntents) yield* persistStoreWriteIntentEffect(input, store, writeIntent, now);
|
|
75
|
+
if (writesFilesystemObservability && event.type === "node.output.recorded") yield* appendNodeStdoutEffect(input, event.nodeId, event);
|
|
76
|
+
});
|
|
77
|
+
const errorMessage = (error) => error instanceof Error ? error.message : String(error);
|
|
78
|
+
const warnPersistSkipped = (input, event, error) => Effect.sync(() => {
|
|
79
|
+
const nodeId = "nodeId" in event && typeof event.nodeId === "string" ? ` node=${event.nodeId}` : "";
|
|
80
|
+
process.stderr.write(`run-control: skipped persisting ${event.type}${nodeId} for run ${input.runId}: ${errorMessage(error)}\n`);
|
|
81
|
+
});
|
|
82
|
+
const createRunStoreRuntimeReporterRuntime = (input) => {
|
|
83
|
+
const now = input.now ?? (() => /* @__PURE__ */ new Date());
|
|
84
|
+
const { store } = input;
|
|
85
|
+
let projectionState = createRuntimeEventProjectionState();
|
|
86
|
+
const writes = createSerializedWriteQueue();
|
|
87
|
+
const enqueue = (event) => {
|
|
88
|
+
const projection = projectRuntimeEvent(event, projectionState);
|
|
89
|
+
projectionState = projection.state;
|
|
90
|
+
const persisted = persistRuntimeEventEffect(input, store, event, projection.writes, now).pipe(Effect.catch((error) => warnPersistSkipped(input, event, error)));
|
|
91
|
+
writes.enqueue(async () => {
|
|
92
|
+
await withRunStateLock(async () => {
|
|
93
|
+
await Effect.runPromise(persisted);
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
};
|
|
97
|
+
const flushEffect = () => Effect.tryPromise({
|
|
115
98
|
catch: (error) => error,
|
|
116
|
-
try: () =>
|
|
117
|
-
|
|
118
|
-
}
|
|
119
|
-
function timestamp(now) {
|
|
120
|
-
return now().toISOString();
|
|
121
|
-
}
|
|
122
|
-
function assertNever(value) {
|
|
123
|
-
throw new Error(`Unhandled runtime reporter value: ${String(value)}`);
|
|
124
|
-
}
|
|
125
|
-
function warnPersistSkipped(input, event, error) {
|
|
126
|
-
return Effect.sync(() => {
|
|
127
|
-
const nodeId = "nodeId" in event && typeof event.nodeId === "string" ? ` node=${event.nodeId}` : "";
|
|
128
|
-
process.stderr.write(`run-control: skipped persisting ${event.type}${nodeId} for run ${input.runId}: ${errorMessage(error)}\n`);
|
|
99
|
+
try: async () => {
|
|
100
|
+
await writes.flush();
|
|
101
|
+
}
|
|
129
102
|
});
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
}
|
|
103
|
+
return {
|
|
104
|
+
flush: async () => {
|
|
105
|
+
await Effect.runPromise(flushEffect());
|
|
106
|
+
},
|
|
107
|
+
flushEffect,
|
|
108
|
+
reporter(event) {
|
|
109
|
+
enqueue(event);
|
|
110
|
+
input.reporter?.(event);
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
};
|
|
114
|
+
const createRunStoreRuntimeReporterEffect = (input) => Effect.sync(() => createRunStoreRuntimeReporterRuntime(input));
|
|
115
|
+
const createRunStoreRuntimeReporter = (input) => Effect.runSync(createRunStoreRuntimeReporterEffect(input));
|
|
134
116
|
//#endregion
|
|
135
117
|
export { createRunStoreRuntimeReporter, createRunStoreRuntimeReporterEffect };
|
|
@@ -1,60 +1,49 @@
|
|
|
1
1
|
import { ACTIVE_NODE_STATUSES, requireKnownNodeEffect } from "./run-command-domain.js";
|
|
2
2
|
import { requireRunEffect } from "./run-query-command.js";
|
|
3
|
-
import { Effect } from "effect";
|
|
3
|
+
import { Effect, Option } from "effect";
|
|
4
4
|
//#region src/run-control/stop-command.ts
|
|
5
|
-
function
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
5
|
+
const stopNodeEffect = (store, run, requestedNodeId, at) => Effect.gen(function* effectBody() {
|
|
6
|
+
const nodeId = yield* requireKnownNodeEffect(run, requestedNodeId);
|
|
7
|
+
yield* store.updateNodeStatus({
|
|
8
|
+
at,
|
|
9
|
+
nodeId,
|
|
10
|
+
runId: run.runId,
|
|
11
|
+
status: "aborted"
|
|
11
12
|
});
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
13
|
+
return `Run ${run.runId} node ${nodeId} aborted.`;
|
|
14
|
+
});
|
|
15
|
+
const activeNodeIds = (run) => Object.entries(run.nodes).filter(([, status]) => ACTIVE_NODE_STATUSES.has(status)).map(([nodeId]) => nodeId);
|
|
16
|
+
const isNoSuchProcess = (error) => typeof error === "object" && error !== null && "code" in error && error.code === "ESRCH";
|
|
17
|
+
const stopControllerProcessEffect = (pid) => Effect.sync(() => {
|
|
18
|
+
if (Option.isNone(pid) || pid.value === 0) return;
|
|
19
|
+
try {
|
|
20
|
+
process.kill(-pid.value, "SIGTERM");
|
|
21
|
+
} catch (error) {
|
|
22
|
+
if (isNoSuchProcess(error)) return;
|
|
23
|
+
process.kill(pid.value, "SIGTERM");
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
const stopRunEffect = (store, run, at) => Effect.gen(function* effectBody() {
|
|
27
|
+
yield* stopControllerProcessEffect(Option.fromNullishOr(run.controller?.pid));
|
|
28
|
+
yield* store.updateRunStatus({
|
|
29
|
+
at,
|
|
30
|
+
runId: run.runId,
|
|
31
|
+
status: "aborted"
|
|
23
32
|
});
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
return `Run ${run.runId} aborted.`;
|
|
40
|
-
});
|
|
41
|
-
}
|
|
42
|
-
function activeNodeIds(run) {
|
|
43
|
-
return Object.entries(run.nodes).filter(([, status]) => ACTIVE_NODE_STATUSES.has(status)).map(([nodeId]) => nodeId);
|
|
44
|
-
}
|
|
45
|
-
function stopControllerProcessEffect(pid) {
|
|
46
|
-
return Effect.sync(() => {
|
|
47
|
-
if (!pid) return;
|
|
48
|
-
try {
|
|
49
|
-
process.kill(-pid, "SIGTERM");
|
|
50
|
-
} catch (error) {
|
|
51
|
-
if (isNoSuchProcess(error)) return;
|
|
52
|
-
process.kill(pid, "SIGTERM");
|
|
53
|
-
}
|
|
54
|
-
});
|
|
55
|
-
}
|
|
56
|
-
function isNoSuchProcess(error) {
|
|
57
|
-
return typeof error === "object" && error !== null && "code" in error && error.code === "ESRCH";
|
|
58
|
-
}
|
|
33
|
+
yield* Effect.forEach(activeNodeIds(run), (nodeId) => store.updateNodeStatus({
|
|
34
|
+
at,
|
|
35
|
+
nodeId,
|
|
36
|
+
runId: run.runId,
|
|
37
|
+
status: "aborted"
|
|
38
|
+
}));
|
|
39
|
+
return `Run ${run.runId} aborted.`;
|
|
40
|
+
});
|
|
41
|
+
const stopRunOrNodeEffect = (input) => Effect.gen(function* effectBody() {
|
|
42
|
+
const run = yield* requireRunEffect(input.store, input.runId);
|
|
43
|
+
const at = (/* @__PURE__ */ new Date()).toISOString();
|
|
44
|
+
const nodeId = Option.fromNullishOr(input.nodeId).pipe(Option.filter((value) => value.length > 0));
|
|
45
|
+
if (Option.isSome(nodeId)) return yield* stopNodeEffect(input.store, run, nodeId.value, at);
|
|
46
|
+
return yield* stopRunEffect(input.store, run, at);
|
|
47
|
+
});
|
|
59
48
|
//#endregion
|
|
60
49
|
export { stopRunOrNodeEffect };
|
|
@@ -1,28 +1,53 @@
|
|
|
1
|
+
import { requiredString, struct } from "../schema-boundary.js";
|
|
1
2
|
import { mokaNodeStatusSchema, mokaRunStatusSchema, parseMokaRunManifest } from "./contracts.js";
|
|
2
3
|
import { parseLogicalSegment } from "./logical-segment.js";
|
|
3
|
-
import
|
|
4
|
+
import "effect/Option";
|
|
5
|
+
import * as R from "effect/Record";
|
|
6
|
+
import * as Schema from "effect/Schema";
|
|
7
|
+
import * as Arr from "effect/Array";
|
|
8
|
+
import "effect/Match";
|
|
9
|
+
import * as Str from "effect/String";
|
|
4
10
|
//#region src/run-control/store-manifest.ts
|
|
5
|
-
const
|
|
6
|
-
sessionId:
|
|
11
|
+
const runStatusNode = Schema.Union([mokaNodeStatusSchema, struct({
|
|
12
|
+
sessionId: Schema.optional(requiredString),
|
|
7
13
|
status: mokaNodeStatusSchema
|
|
8
|
-
})
|
|
9
|
-
|
|
10
|
-
nodes:
|
|
14
|
+
})]);
|
|
15
|
+
struct({
|
|
16
|
+
nodes: Schema.Record(requiredString, runStatusNode),
|
|
11
17
|
status: mokaRunStatusSchema
|
|
12
|
-
})
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
18
|
+
});
|
|
19
|
+
struct({ sessionId: requiredString });
|
|
20
|
+
var EmptyPublishedScheduleError = class extends Schema.TaggedErrorClass()("EmptyPublishedScheduleError", { message: Schema.String }) {
|
|
21
|
+
constructor() {
|
|
22
|
+
super({ message: "schedule must be a non-empty string." });
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
var PublishedScheduleConflictError = class extends Schema.TaggedErrorClass()("PublishedScheduleConflictError", {
|
|
26
|
+
message: Schema.String,
|
|
27
|
+
runId: requiredString
|
|
28
|
+
}) {
|
|
29
|
+
constructor(runId) {
|
|
30
|
+
super({
|
|
31
|
+
message: `Run ${runId} already has a different published schedule.`,
|
|
32
|
+
runId
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
const queuedNodeEntry = (nodeId) => [nodeId, "queued"];
|
|
37
|
+
const queuedNodeRecord = (nodeIds) => R.fromEntries(Arr.map(nodeIds, queuedNodeEntry));
|
|
38
|
+
const publishScheduleManifest = (input) => {
|
|
39
|
+
if (Str.isEmpty(input.schedule)) throw new EmptyPublishedScheduleError();
|
|
40
|
+
if (input.manifest.schedule !== void 0 && input.manifest.schedule !== input.schedule) throw new PublishedScheduleConflictError(input.manifest.runId);
|
|
17
41
|
const nodeIds = input.nodeIds.map((nodeId) => parseLogicalSegment("nodeId", nodeId));
|
|
42
|
+
const missingNodes = Arr.filter(nodeIds, (nodeId) => !R.has(input.manifest.nodes, nodeId));
|
|
18
43
|
return parseMokaRunManifest({
|
|
19
44
|
...input.manifest,
|
|
20
45
|
nodes: {
|
|
21
46
|
...input.manifest.nodes,
|
|
22
|
-
...
|
|
47
|
+
...queuedNodeRecord(missingNodes)
|
|
23
48
|
},
|
|
24
49
|
schedule: input.schedule
|
|
25
50
|
});
|
|
26
|
-
}
|
|
51
|
+
};
|
|
27
52
|
//#endregion
|
|
28
53
|
export { publishScheduleManifest };
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import "./logical-segment.js";
|
|
2
|
-
import "effect";
|
|
3
2
|
import { join } from "node:path";
|
|
3
|
+
import "effect";
|
|
4
4
|
//#region src/run-control/store-paths.ts
|
|
5
5
|
const RUNS_DIRECTORY = ".pipeline/runs";
|
|
6
6
|
const MANIFEST_FILE = "manifest.json";
|
|
7
7
|
const STATUS_FILE = "status.json";
|
|
8
8
|
const EVENTS_FILE = "events.jsonl";
|
|
9
9
|
const NODES_DIRECTORY = "nodes";
|
|
10
|
-
|
|
10
|
+
const runPaths = (workspaceRoot, runId) => {
|
|
11
11
|
const runsRoot = join(workspaceRoot, RUNS_DIRECTORY);
|
|
12
12
|
const runRoot = join(runsRoot, runId);
|
|
13
13
|
return {
|
|
@@ -18,6 +18,6 @@ function runPaths(workspaceRoot, runId) {
|
|
|
18
18
|
runsRoot,
|
|
19
19
|
status: join(runRoot, STATUS_FILE)
|
|
20
20
|
};
|
|
21
|
-
}
|
|
21
|
+
};
|
|
22
22
|
//#endregion
|
|
23
23
|
export { RUNS_DIRECTORY, runPaths };
|
|
@@ -2,11 +2,11 @@ import { loadMokaDbUrl } from "../moka-global-config.js";
|
|
|
2
2
|
import { recordNodeResult } from "../runtime/step/step-node.js";
|
|
3
3
|
import { resolveDurableStore } from "../runtime/durable-store/acquisition.js";
|
|
4
4
|
import { parseSubmitResult } from "../runtime/node-protocol/node-protocol.js";
|
|
5
|
-
import
|
|
5
|
+
import * as Effect from "effect/Effect";
|
|
6
6
|
//#region src/run-control/submit-result.ts
|
|
7
7
|
/**
|
|
8
8
|
* PIPE-91.7: validate and persist a node's terminal result into the durable
|
|
9
|
-
* store. Throws
|
|
9
|
+
* store. Throws an Effect Schema validation error on malformed payload or a
|
|
10
10
|
* `result.nodeId !== nodeId` mismatch; throws a {@link SyntaxError} on
|
|
11
11
|
* invalid JSON.
|
|
12
12
|
*
|
|
@@ -16,7 +16,7 @@ import { Effect } from "effect";
|
|
|
16
16
|
* gate evaluation must look up the schedule artifact, not this store entry.
|
|
17
17
|
* `inputs` are opaque and `undefined` until a future lane pins the schema.
|
|
18
18
|
*/
|
|
19
|
-
|
|
19
|
+
const recordSubmitResult = (input) => {
|
|
20
20
|
const raw = JSON.parse(input.resultJson);
|
|
21
21
|
const parsed = parseSubmitResult({
|
|
22
22
|
nodeId: input.nodeId,
|
|
@@ -28,7 +28,22 @@ function recordSubmitResult(input) {
|
|
|
28
28
|
runId: parsed.runId,
|
|
29
29
|
store: input.store
|
|
30
30
|
});
|
|
31
|
-
}
|
|
31
|
+
};
|
|
32
|
+
const submitResultEffect = (runId, nodeId, resultJson) => Effect.scoped(Effect.gen(function* effectBody() {
|
|
33
|
+
const store = yield* resolveDurableStore(loadMokaDbUrl(), runId);
|
|
34
|
+
yield* Effect.try({
|
|
35
|
+
catch: (error) => error,
|
|
36
|
+
try: () => {
|
|
37
|
+
recordSubmitResult({
|
|
38
|
+
nodeId,
|
|
39
|
+
resultJson,
|
|
40
|
+
runId,
|
|
41
|
+
store
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
process.stdout.write(`Recorded result for run ${runId} node ${nodeId}.\n`);
|
|
46
|
+
}));
|
|
32
47
|
/**
|
|
33
48
|
* PIPE-91.7: register `moka submit-result <run-id> <node-id> --json <payload>`.
|
|
34
49
|
* A distinct top-level command (NOT a `submit` group — `moka submit` already
|
|
@@ -36,25 +51,10 @@ function recordSubmitResult(input) {
|
|
|
36
51
|
* string; `(runId, nodeId)` are the positional routing keys — mirroring
|
|
37
52
|
* `moka next node <run-id>` (PIPE-91.6).
|
|
38
53
|
*/
|
|
39
|
-
|
|
54
|
+
const registerSubmitResultSubcommand = (program) => {
|
|
40
55
|
program.command("submit-result").description("Persist a node's terminal result into the durable run store").argument("<run-id>", "the run id to persist the result under").argument("<node-id>", "the node id whose result is being submitted").requiredOption("--json <payload>", "the RuntimeNodeResult as a JSON string").action(async (runId, nodeId, flags) => {
|
|
41
56
|
await Effect.runPromise(submitResultEffect(runId, nodeId, flags.json));
|
|
42
57
|
});
|
|
43
|
-
}
|
|
44
|
-
function submitResultEffect(runId, nodeId, resultJson) {
|
|
45
|
-
return Effect.scoped(Effect.gen(function* () {
|
|
46
|
-
const store = yield* resolveDurableStore(loadMokaDbUrl(), runId);
|
|
47
|
-
yield* Effect.try({
|
|
48
|
-
catch: (error) => error,
|
|
49
|
-
try: () => recordSubmitResult({
|
|
50
|
-
nodeId,
|
|
51
|
-
resultJson,
|
|
52
|
-
runId,
|
|
53
|
-
store
|
|
54
|
-
})
|
|
55
|
-
});
|
|
56
|
-
process.stdout.write(`Recorded result for run ${runId} node ${nodeId}.\n`);
|
|
57
|
-
}));
|
|
58
|
-
}
|
|
58
|
+
};
|
|
59
59
|
//#endregion
|
|
60
60
|
export { recordSubmitResult, registerSubmitResultSubcommand };
|