adispatchd 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +195 -2
- package/dist/api/errors.d.ts +27 -0
- package/dist/api/errors.js +80 -0
- package/dist/api/errors.js.map +1 -0
- package/dist/api/index.d.ts +10 -0
- package/dist/api/index.js +11 -0
- package/dist/api/index.js.map +1 -0
- package/dist/api/logs.d.ts +30 -0
- package/dist/api/logs.js +88 -0
- package/dist/api/logs.js.map +1 -0
- package/dist/api/serialize.d.ts +65 -0
- package/dist/api/serialize.js +135 -0
- package/dist/api/serialize.js.map +1 -0
- package/dist/api/server.d.ts +89 -0
- package/dist/api/server.js +751 -0
- package/dist/api/server.js.map +1 -0
- package/dist/api/sse.d.ts +90 -0
- package/dist/api/sse.js +225 -0
- package/dist/api/sse.js.map +1 -0
- package/dist/app.d.ts +173 -0
- package/dist/app.js +488 -0
- package/dist/app.js.map +1 -0
- package/dist/cli/config-validate.d.ts +6 -0
- package/dist/cli/config-validate.js +39 -0
- package/dist/cli/config-validate.js.map +1 -0
- package/dist/cli/control.d.ts +31 -0
- package/dist/cli/control.js +186 -0
- package/dist/cli/control.js.map +1 -0
- package/dist/cli/http-client.d.ts +57 -0
- package/dist/cli/http-client.js +174 -0
- package/dist/cli/http-client.js.map +1 -0
- package/dist/cli/index.d.ts +14 -0
- package/dist/cli/index.js +14 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/init-templates.d.ts +20 -0
- package/dist/cli/init-templates.js +275 -0
- package/dist/cli/init-templates.js.map +1 -0
- package/dist/cli/init.d.ts +16 -0
- package/dist/cli/init.js +107 -0
- package/dist/cli/init.js.map +1 -0
- package/dist/cli/main.d.ts +2 -0
- package/dist/cli/main.js +25 -0
- package/dist/cli/main.js.map +1 -0
- package/dist/cli/program.d.ts +102 -0
- package/dist/cli/program.js +133 -0
- package/dist/cli/program.js.map +1 -0
- package/dist/cli/service.d.ts +27 -0
- package/dist/cli/service.js +252 -0
- package/dist/cli/service.js.map +1 -0
- package/dist/cli/start.d.ts +22 -0
- package/dist/cli/start.js +133 -0
- package/dist/cli/start.js.map +1 -0
- package/dist/cli/workflow-dry-run.d.ts +13 -0
- package/dist/cli/workflow-dry-run.js +144 -0
- package/dist/cli/workflow-dry-run.js.map +1 -0
- package/dist/config/field-catalog.d.ts +33 -0
- package/dist/config/field-catalog.js +172 -0
- package/dist/config/field-catalog.js.map +1 -0
- package/dist/config/filter-schema.d.ts +15 -0
- package/dist/config/filter-schema.js +110 -0
- package/dist/config/filter-schema.js.map +1 -0
- package/dist/config/index.d.ts +15 -0
- package/dist/config/index.js +16 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/issues.d.ts +27 -0
- package/dist/config/issues.js +37 -0
- package/dist/config/issues.js.map +1 -0
- package/dist/config/loader.d.ts +32 -0
- package/dist/config/loader.js +250 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/config/manager.d.ts +153 -0
- package/dist/config/manager.js +276 -0
- package/dist/config/manager.js.map +1 -0
- package/dist/config/model.d.ts +334 -0
- package/dist/config/model.js +2 -0
- package/dist/config/model.js.map +1 -0
- package/dist/config/normalize.d.ts +20 -0
- package/dist/config/normalize.js +200 -0
- package/dist/config/normalize.js.map +1 -0
- package/dist/config/parameters.d.ts +37 -0
- package/dist/config/parameters.js +71 -0
- package/dist/config/parameters.js.map +1 -0
- package/dist/config/public.d.ts +6 -0
- package/dist/config/public.js +18 -0
- package/dist/config/public.js.map +1 -0
- package/dist/config/schemas.d.ts +538 -0
- package/dist/config/schemas.js +321 -0
- package/dist/config/schemas.js.map +1 -0
- package/dist/config/snapshot.d.ts +38 -0
- package/dist/config/snapshot.js +57 -0
- package/dist/config/snapshot.js.map +1 -0
- package/dist/config/validate.d.ts +33 -0
- package/dist/config/validate.js +346 -0
- package/dist/config/validate.js.map +1 -0
- package/dist/core/clock.d.ts +59 -0
- package/dist/core/clock.js +133 -0
- package/dist/core/clock.js.map +1 -0
- package/dist/core/duration.d.ts +19 -0
- package/dist/core/duration.js +93 -0
- package/dist/core/duration.js.map +1 -0
- package/dist/core/errors.d.ts +62 -0
- package/dist/core/errors.js +72 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/ids.d.ts +57 -0
- package/dist/core/ids.js +88 -0
- package/dist/core/ids.js.map +1 -0
- package/dist/core/index.d.ts +13 -0
- package/dist/core/index.js +14 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/logger.d.ts +100 -0
- package/dist/core/logger.js +207 -0
- package/dist/core/logger.js.map +1 -0
- package/dist/core/paths.d.ts +84 -0
- package/dist/core/paths.js +138 -0
- package/dist/core/paths.js.map +1 -0
- package/dist/core/template.d.ts +136 -0
- package/dist/core/template.js +261 -0
- package/dist/core/template.js.map +1 -0
- package/dist/core/types.d.ts +544 -0
- package/dist/core/types.js +172 -0
- package/dist/core/types.js.map +1 -0
- package/dist/core/worker-protocol.d.ts +102 -0
- package/dist/core/worker-protocol.js +75 -0
- package/dist/core/worker-protocol.js.map +1 -0
- package/dist/executors/classify.d.ts +25 -0
- package/dist/executors/classify.js +54 -0
- package/dist/executors/classify.js.map +1 -0
- package/dist/executors/dispatcher.d.ts +35 -0
- package/dist/executors/dispatcher.js +68 -0
- package/dist/executors/dispatcher.js.map +1 -0
- package/dist/executors/env.d.ts +43 -0
- package/dist/executors/env.js +66 -0
- package/dist/executors/env.js.map +1 -0
- package/dist/executors/event-parser.d.ts +41 -0
- package/dist/executors/event-parser.js +106 -0
- package/dist/executors/event-parser.js.map +1 -0
- package/dist/executors/index.d.ts +12 -0
- package/dist/executors/index.js +13 -0
- package/dist/executors/index.js.map +1 -0
- package/dist/executors/log-capture.d.ts +57 -0
- package/dist/executors/log-capture.js +155 -0
- package/dist/executors/log-capture.js.map +1 -0
- package/dist/executors/process-identity.d.ts +124 -0
- package/dist/executors/process-identity.js +283 -0
- package/dist/executors/process-identity.js.map +1 -0
- package/dist/executors/shell-executor.d.ts +35 -0
- package/dist/executors/shell-executor.js +478 -0
- package/dist/executors/shell-executor.js.map +1 -0
- package/dist/executors/stream-redactor.d.ts +40 -0
- package/dist/executors/stream-redactor.js +89 -0
- package/dist/executors/stream-redactor.js.map +1 -0
- package/dist/executors/workspace.d.ts +10 -0
- package/dist/executors/workspace.js +47 -0
- package/dist/executors/workspace.js.map +1 -0
- package/dist/filters/evaluate.d.ts +77 -0
- package/dist/filters/evaluate.js +187 -0
- package/dist/filters/evaluate.js.map +1 -0
- package/dist/filters/fields.d.ts +35 -0
- package/dist/filters/fields.js +75 -0
- package/dist/filters/fields.js.map +1 -0
- package/dist/filters/index.d.ts +11 -0
- package/dist/filters/index.js +12 -0
- package/dist/filters/index.js.map +1 -0
- package/dist/filters/iso-date.d.ts +10 -0
- package/dist/filters/iso-date.js +42 -0
- package/dist/filters/iso-date.js.map +1 -0
- package/dist/filters/predicate.d.ts +24 -0
- package/dist/filters/predicate.js +178 -0
- package/dist/filters/predicate.js.map +1 -0
- package/dist/filters/priority.d.ts +51 -0
- package/dist/filters/priority.js +91 -0
- package/dist/filters/priority.js.map +1 -0
- package/dist/filters/pushdown.d.ts +12 -0
- package/dist/filters/pushdown.js +52 -0
- package/dist/filters/pushdown.js.map +1 -0
- package/dist/filters/shell-check.d.ts +110 -0
- package/dist/filters/shell-check.js +304 -0
- package/dist/filters/shell-check.js.map +1 -0
- package/dist/identities/github-app.d.ts +55 -0
- package/dist/identities/github-app.js +160 -0
- package/dist/identities/github-app.js.map +1 -0
- package/dist/identities/index.d.ts +6 -0
- package/dist/identities/index.js +7 -0
- package/dist/identities/index.js.map +1 -0
- package/dist/identities/jwt.d.ts +24 -0
- package/dist/identities/jwt.js +56 -0
- package/dist/identities/jwt.js.map +1 -0
- package/dist/lifecycle/context.d.ts +106 -0
- package/dist/lifecycle/context.js +170 -0
- package/dist/lifecycle/context.js.map +1 -0
- package/dist/lifecycle/engine.d.ts +185 -0
- package/dist/lifecycle/engine.js +551 -0
- package/dist/lifecycle/engine.js.map +1 -0
- package/dist/lifecycle/errors.d.ts +48 -0
- package/dist/lifecycle/errors.js +71 -0
- package/dist/lifecycle/errors.js.map +1 -0
- package/dist/lifecycle/index.d.ts +9 -0
- package/dist/lifecycle/index.js +9 -0
- package/dist/lifecycle/index.js.map +1 -0
- package/dist/lifecycle/performers.d.ts +66 -0
- package/dist/lifecycle/performers.js +179 -0
- package/dist/lifecycle/performers.js.map +1 -0
- package/dist/notifications/index.d.ts +6 -0
- package/dist/notifications/index.js +7 -0
- package/dist/notifications/index.js.map +1 -0
- package/dist/notifications/service.d.ts +115 -0
- package/dist/notifications/service.js +364 -0
- package/dist/notifications/service.js.map +1 -0
- package/dist/persistence/actions.d.ts +101 -0
- package/dist/persistence/actions.js +196 -0
- package/dist/persistence/actions.js.map +1 -0
- package/dist/persistence/blocks.d.ts +85 -0
- package/dist/persistence/blocks.js +140 -0
- package/dist/persistence/blocks.js.map +1 -0
- package/dist/persistence/cron-firings.d.ts +55 -0
- package/dist/persistence/cron-firings.js +70 -0
- package/dist/persistence/cron-firings.js.map +1 -0
- package/dist/persistence/database.d.ts +60 -0
- package/dist/persistence/database.js +124 -0
- package/dist/persistence/database.js.map +1 -0
- package/dist/persistence/errors.d.ts +39 -0
- package/dist/persistence/errors.js +67 -0
- package/dist/persistence/errors.js.map +1 -0
- package/dist/persistence/events.d.ts +72 -0
- package/dist/persistence/events.js +83 -0
- package/dist/persistence/events.js.map +1 -0
- package/dist/persistence/index.d.ts +18 -0
- package/dist/persistence/index.js +19 -0
- package/dist/persistence/index.js.map +1 -0
- package/dist/persistence/instance-lock.d.ts +26 -0
- package/dist/persistence/instance-lock.js +117 -0
- package/dist/persistence/instance-lock.js.map +1 -0
- package/dist/persistence/lock-keys.d.ts +16 -0
- package/dist/persistence/lock-keys.js +41 -0
- package/dist/persistence/lock-keys.js.map +1 -0
- package/dist/persistence/notifications.d.ts +113 -0
- package/dist/persistence/notifications.js +213 -0
- package/dist/persistence/notifications.js.map +1 -0
- package/dist/persistence/persistence.d.ts +46 -0
- package/dist/persistence/persistence.js +42 -0
- package/dist/persistence/persistence.js.map +1 -0
- package/dist/persistence/retention.d.ts +46 -0
- package/dist/persistence/retention.js +68 -0
- package/dist/persistence/retention.js.map +1 -0
- package/dist/persistence/runs.d.ts +215 -0
- package/dist/persistence/runs.js +417 -0
- package/dist/persistence/runs.js.map +1 -0
- package/dist/persistence/schema.d.ts +16 -0
- package/dist/persistence/schema.js +183 -0
- package/dist/persistence/schema.js.map +1 -0
- package/dist/persistence/sqlite.d.ts +49 -0
- package/dist/persistence/sqlite.js +131 -0
- package/dist/persistence/sqlite.js.map +1 -0
- package/dist/runs/controller.d.ts +307 -0
- package/dist/runs/controller.js +1078 -0
- package/dist/runs/controller.js.map +1 -0
- package/dist/runs/errors.d.ts +20 -0
- package/dist/runs/errors.js +26 -0
- package/dist/runs/errors.js.map +1 -0
- package/dist/runs/event-bus.d.ts +106 -0
- package/dist/runs/event-bus.js +105 -0
- package/dist/runs/event-bus.js.map +1 -0
- package/dist/runs/execution.d.ts +39 -0
- package/dist/runs/execution.js +146 -0
- package/dist/runs/execution.js.map +1 -0
- package/dist/runs/index.d.ts +12 -0
- package/dist/runs/index.js +13 -0
- package/dist/runs/index.js.map +1 -0
- package/dist/runs/retention.d.ts +64 -0
- package/dist/runs/retention.js +232 -0
- package/dist/runs/retention.js.map +1 -0
- package/dist/runs/workspace.d.ts +20 -0
- package/dist/runs/workspace.js +51 -0
- package/dist/runs/workspace.js.map +1 -0
- package/dist/scheduler/checks.d.ts +41 -0
- package/dist/scheduler/checks.js +111 -0
- package/dist/scheduler/checks.js.map +1 -0
- package/dist/scheduler/cron.d.ts +32 -0
- package/dist/scheduler/cron.js +83 -0
- package/dist/scheduler/cron.js.map +1 -0
- package/dist/scheduler/dry-run.d.ts +42 -0
- package/dist/scheduler/dry-run.js +167 -0
- package/dist/scheduler/dry-run.js.map +1 -0
- package/dist/scheduler/errors.d.ts +22 -0
- package/dist/scheduler/errors.js +22 -0
- package/dist/scheduler/errors.js.map +1 -0
- package/dist/scheduler/format.d.ts +3 -0
- package/dist/scheduler/format.js +73 -0
- package/dist/scheduler/format.js.map +1 -0
- package/dist/scheduler/index.d.ts +13 -0
- package/dist/scheduler/index.js +14 -0
- package/dist/scheduler/index.js.map +1 -0
- package/dist/scheduler/planner.d.ts +88 -0
- package/dist/scheduler/planner.js +255 -0
- package/dist/scheduler/planner.js.map +1 -0
- package/dist/scheduler/scheduler.d.ts +160 -0
- package/dist/scheduler/scheduler.js +680 -0
- package/dist/scheduler/scheduler.js.map +1 -0
- package/dist/scheduler/state.d.ts +26 -0
- package/dist/scheduler/state.js +25 -0
- package/dist/scheduler/state.js.map +1 -0
- package/dist/scheduler/types.d.ts +197 -0
- package/dist/scheduler/types.js +3 -0
- package/dist/scheduler/types.js.map +1 -0
- package/dist/service/index.d.ts +6 -0
- package/dist/service/index.js +7 -0
- package/dist/service/index.js.map +1 -0
- package/dist/service/install.d.ts +93 -0
- package/dist/service/install.js +250 -0
- package/dist/service/install.js.map +1 -0
- package/dist/service/unit.d.ts +50 -0
- package/dist/service/unit.js +171 -0
- package/dist/service/unit.js.map +1 -0
- package/dist/sources/github/adapter.d.ts +99 -0
- package/dist/sources/github/adapter.js +336 -0
- package/dist/sources/github/adapter.js.map +1 -0
- package/dist/sources/github/fields.d.ts +8 -0
- package/dist/sources/github/fields.js +72 -0
- package/dist/sources/github/fields.js.map +1 -0
- package/dist/sources/github/http.d.ts +100 -0
- package/dist/sources/github/http.js +288 -0
- package/dist/sources/github/http.js.map +1 -0
- package/dist/sources/github/index.d.ts +6 -0
- package/dist/sources/github/index.js +7 -0
- package/dist/sources/github/index.js.map +1 -0
- package/dist/sources/github/pushdown.d.ts +14 -0
- package/dist/sources/github/pushdown.js +47 -0
- package/dist/sources/github/pushdown.js.map +1 -0
- package/dist/sources/github/refs.d.ts +17 -0
- package/dist/sources/github/refs.js +61 -0
- package/dist/sources/github/refs.js.map +1 -0
- package/dist/sources/index.d.ts +6 -0
- package/dist/sources/index.js +7 -0
- package/dist/sources/index.js.map +1 -0
- package/dist/ui/index.d.ts +12 -0
- package/dist/ui/index.js +28 -0
- package/dist/ui/index.js.map +1 -0
- package/dist/ui/public/app.css +239 -0
- package/dist/ui/public/favicon.svg +1 -0
- package/dist/ui/public/index.html +27 -0
- package/dist/ui/public/js/client/api.js +68 -0
- package/dist/ui/public/js/client/app.js +146 -0
- package/dist/ui/public/js/client/dom.js +34 -0
- package/dist/ui/public/js/client/page.js +9 -0
- package/dist/ui/public/js/client/pages/actions.js +35 -0
- package/dist/ui/public/js/client/pages/blocked.js +58 -0
- package/dist/ui/public/js/client/pages/config.js +126 -0
- package/dist/ui/public/js/client/pages/dashboard.js +175 -0
- package/dist/ui/public/js/client/pages/run.js +367 -0
- package/dist/ui/public/js/client/pages/runs.js +72 -0
- package/dist/ui/public/js/client/pages/views.js +80 -0
- package/dist/ui/public/js/client/pages/workflows.js +291 -0
- package/dist/ui/public/js/client/types.js +1 -0
- package/dist/ui/public/js/client/ui.js +152 -0
- package/dist/ui/public/js/shared/dom.js +77 -0
- package/dist/ui/public/js/shared/events.js +88 -0
- package/dist/ui/public/js/shared/format.js +213 -0
- package/dist/ui/public/js/shared/logs.js +136 -0
- package/dist/ui/public/js/shared/params.js +90 -0
- package/dist/ui/public/js/shared/route.js +36 -0
- package/dist/ui/public/js/shared/sort.js +70 -0
- package/dist/ui/public/js/shared/sse.js +193 -0
- package/dist/ui/public/js/shared/throttle.js +65 -0
- package/dist/views/index.d.ts +6 -0
- package/dist/views/index.js +7 -0
- package/dist/views/index.js.map +1 -0
- package/dist/views/service.d.ts +131 -0
- package/dist/views/service.js +264 -0
- package/dist/views/service.js.map +1 -0
- package/docs/api.md +239 -0
- package/docs/configuration-reference.md +1785 -0
- package/docs/cron-semantics.md +96 -0
- package/docs/manual-tests/github-fixture/config.yaml +30 -0
- package/docs/manual-tests/github-fixture/helpers.sh +93 -0
- package/docs/manual-tests/github-fixture/identities.yaml +18 -0
- package/docs/manual-tests/github-fixture/scripts/test-worker.sh +100 -0
- package/docs/manual-tests/github-fixture/sources.yaml +13 -0
- package/docs/manual-tests/github-fixture/views/dependencies.yaml +17 -0
- package/docs/manual-tests/github-fixture/views/needs-maintainer.yaml +17 -0
- package/docs/manual-tests/github-fixture/workflows/coder-test.yaml +76 -0
- package/docs/manual-tests/github-fixture/workflows/commenter-test.yaml +63 -0
- package/docs/manual-tests/github-fixture/workflows/reviewer-test.yaml +60 -0
- package/docs/manual-tests/github.md +1308 -0
- package/docs/manual-tests/process-supervision.md +64 -0
- package/docs/manual-tests/systemd.md +68 -0
- package/docs/operations.md +271 -0
- package/docs/worker-protocol.md +145 -0
- package/examples/config/config.yaml +35 -0
- package/examples/config/identities.yaml +18 -0
- package/examples/config/sources.yaml +13 -0
- package/examples/config/views/needs-maintainer.yaml +15 -0
- package/examples/config/workflows/coder-project-a.yaml +86 -0
- package/examples/config/workflows/deploy.yaml +15 -0
- package/examples/config/workflows/nightly-maintenance.yaml +13 -0
- package/package.json +75 -4
|
@@ -0,0 +1,544 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared domain types and component contracts (Spec §3, §6, §8, §9, §10, §13).
|
|
3
|
+
*
|
|
4
|
+
* Only types and tiny pure helpers live here. Implementations belong to the
|
|
5
|
+
* owning components (sources, executors, identities, persistence, ...).
|
|
6
|
+
*/
|
|
7
|
+
import type { Clock } from './clock.js';
|
|
8
|
+
import type { Logger } from './logger.js';
|
|
9
|
+
import type { WorkerContext, WorkerResult } from './worker-protocol.js';
|
|
10
|
+
/** Function that removes a previously registered listener. */
|
|
11
|
+
export type Unsubscribe = () => void;
|
|
12
|
+
/** Injectable HTTP client with the signature of the global `fetch`. */
|
|
13
|
+
export type FetchLike = (input: string | URL | Request, init?: RequestInit) => Promise<Response>;
|
|
14
|
+
/** All technical run states, including the technical extension `recovery_pending`. */
|
|
15
|
+
export declare const TECHNICAL_STATUSES: readonly ['reserved', 'starting', 'running', 'cancelling', 'finalizing', 'completed', 'crashed', 'start_error', 'timed_out', 'cancelled', 'recovery_pending'];
|
|
16
|
+
/** Technical run state (Spec §8.1). Independent of the {@link BusinessResult}. */
|
|
17
|
+
export type TechnicalStatus = (typeof TECHNICAL_STATUSES)[number];
|
|
18
|
+
/** Final technical states; a run in one of these never changes state again. */
|
|
19
|
+
export declare const TERMINAL_STATUSES: readonly ['completed', 'crashed', 'start_error', 'timed_out', 'cancelled'];
|
|
20
|
+
/** A final technical state. */
|
|
21
|
+
export type TerminalStatus = (typeof TERMINAL_STATUSES)[number];
|
|
22
|
+
/**
|
|
23
|
+
* Non-terminal states. A run in one of these holds its lock and counts
|
|
24
|
+
* towards concurrency. `recovery_pending` keeps the lock to prevent double starts (Spec §14).
|
|
25
|
+
*/
|
|
26
|
+
export declare const ACTIVE_STATUSES: readonly ['reserved', 'starting', 'running', 'cancelling', 'finalizing', 'recovery_pending'];
|
|
27
|
+
/** A non-terminal state. */
|
|
28
|
+
export type ActiveStatus = (typeof ACTIVE_STATUSES)[number];
|
|
29
|
+
/**
|
|
30
|
+
* Terminal states that count as technical failures for retry blocks
|
|
31
|
+
* (Spec §8.1, §11). `cancelled` and business `failure` do not count.
|
|
32
|
+
*/
|
|
33
|
+
export declare const TECHNICAL_FAILURE_STATUSES: readonly ['crashed', 'start_error', 'timed_out'];
|
|
34
|
+
/** True if `status` is terminal. */
|
|
35
|
+
export declare function isTerminalStatus(status: TechnicalStatus): status is TerminalStatus;
|
|
36
|
+
/** True if `status` counts as a technical failure (Spec §11). */
|
|
37
|
+
export declare function isTechnicalFailure(status: TechnicalStatus): boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Reference state machine for run transitions. Persistence (WI-03) enforces
|
|
40
|
+
* it; any transition not listed is invalid.
|
|
41
|
+
*
|
|
42
|
+
* **Every terminal status is reached only via `finalizing` — no exceptions.**
|
|
43
|
+
*
|
|
44
|
+
* Normal path: `reserved → starting → running → finalizing → <terminal>`.
|
|
45
|
+
*
|
|
46
|
+
* Finalization protocol (WI-03/WI-08):
|
|
47
|
+
* 1. `X → finalizing` persists the {@link FinalizationTarget} (columns
|
|
48
|
+
* `runs.final_status`, `runs.business_result`, `runs.final_reason`) and, for
|
|
49
|
+
* technical failures that reach the limit, the retry block — all in ONE
|
|
50
|
+
* transaction (Spec §11 "important order").
|
|
51
|
+
* 2. The completion hook ({@link hookForOutcome}) runs while `finalizing`.
|
|
52
|
+
* After a controller crash, recovery resumes the hook chain of runs still
|
|
53
|
+
* in `finalizing` from the persisted target.
|
|
54
|
+
* 3. `finalizing → target.status` (must equal the persisted target, see
|
|
55
|
+
* {@link canTransition}); the lock is released in the same transaction.
|
|
56
|
+
*
|
|
57
|
+
* Special cases (also via `finalizing`):
|
|
58
|
+
* - Cancel before the worker started (`reserved`/`starting` → `cancelling`
|
|
59
|
+
* or directly → `finalizing` with target `cancelled`): a uniform path keeps
|
|
60
|
+
* the journal and recovery logic simple; WI-08 decides whether `on_cancel`
|
|
61
|
+
* runs when `on_start` never ran.
|
|
62
|
+
* - `on_start` chain failed: `starting → finalizing` with target `start_error`.
|
|
63
|
+
* - Recovery: `recovery_pending → finalizing` with target `crashed` (or
|
|
64
|
+
* `cancelled`) once the process is confirmed gone.
|
|
65
|
+
*
|
|
66
|
+
* `cancelling` is entered on a cancel request; `recovery_pending` marks runs
|
|
67
|
+
* whose process could not be identified or stopped during recovery (keeps the lock).
|
|
68
|
+
*/
|
|
69
|
+
export declare const RUN_STATUS_TRANSITIONS: Readonly<Record<TechnicalStatus, readonly TechnicalStatus[]>>;
|
|
70
|
+
/**
|
|
71
|
+
* True if the reference state machine allows `from → to`. For
|
|
72
|
+
* `finalizing → <terminal>`, pass the persisted `target`; the transition is
|
|
73
|
+
* then only valid if `to === target.status`.
|
|
74
|
+
*/
|
|
75
|
+
export declare function canTransition(from: TechnicalStatus, to: TechnicalStatus, target?: FinalizationTarget): boolean;
|
|
76
|
+
/**
|
|
77
|
+
* Business result reported by the worker via the result file (Spec §8.2).
|
|
78
|
+
* `null` for every technically failed or cancelled run.
|
|
79
|
+
*/
|
|
80
|
+
export type BusinessResult = 'success' | 'failure' | null;
|
|
81
|
+
/**
|
|
82
|
+
* Final outcome decided when a run enters `finalizing`. Persisted with that
|
|
83
|
+
* transition (`runs.final_status`, `runs.business_result`, `runs.final_reason`)
|
|
84
|
+
* so that hooks and recovery work from it; the run later moves to exactly
|
|
85
|
+
* `status`. `businessResult` is non-null only for `completed`.
|
|
86
|
+
*/
|
|
87
|
+
export interface FinalizationTarget {
|
|
88
|
+
status: TerminalStatus;
|
|
89
|
+
businessResult: BusinessResult;
|
|
90
|
+
/** Short explanation, e.g. `exit code 1`, `cancelled by user`, `on_start failed`. */
|
|
91
|
+
reason: string;
|
|
92
|
+
}
|
|
93
|
+
/** How a run was triggered. */
|
|
94
|
+
export type TriggerType = 'source' | 'schedule' | 'manual';
|
|
95
|
+
/** Lifecycle hooks in declaration order (Spec §10). */
|
|
96
|
+
export declare const HOOK_NAMES: readonly ['on_start', 'on_success', 'on_failure', 'on_crash', 'on_start_error', 'on_cancel', 'on_timeout'];
|
|
97
|
+
/** Name of a lifecycle hook. */
|
|
98
|
+
export type HookName = (typeof HOOK_NAMES)[number];
|
|
99
|
+
/**
|
|
100
|
+
* The completion hook to run for a final outcome (Spec §8.2 rule 7):
|
|
101
|
+
* `completed`+`success` → `on_success`, `completed`+`failure` → `on_failure`,
|
|
102
|
+
* `crashed` → `on_crash`, `start_error` → `on_start_error`,
|
|
103
|
+
* `timed_out` → `on_timeout`, `cancelled` → `on_cancel`.
|
|
104
|
+
*/
|
|
105
|
+
export declare function hookForOutcome(status: TerminalStatus, businessResult: BusinessResult): HookName;
|
|
106
|
+
/** Lifecycle action types available in V1 (Spec §10). */
|
|
107
|
+
export declare const ACTION_TYPES: readonly ['source.update', 'source.comment', 'shell'];
|
|
108
|
+
/** A lifecycle action type. */
|
|
109
|
+
export type ActionType = (typeof ACTION_TYPES)[number];
|
|
110
|
+
/** Persisted state of one journaled lifecycle action (Spec §10). */
|
|
111
|
+
export type ActionStatus = 'pending' | 'running' | 'succeeded' | 'failed' | 'skipped';
|
|
112
|
+
/**
|
|
113
|
+
* Aggregate lifecycle state of a run (`runs.lifecycle_status`):
|
|
114
|
+
* `failed` when a hook chain stopped at a failed action (Spec §21: "lifecycle failed").
|
|
115
|
+
*/
|
|
116
|
+
export type LifecycleStatus = 'pending' | 'running' | 'succeeded' | 'failed';
|
|
117
|
+
/** Orchestrator events that can trigger central notifications (Spec §18). */
|
|
118
|
+
export declare const NOTIFICATION_EVENT_TYPES: readonly ['retry_block_created', 'lifecycle_action_failed', 'recovery_failed'];
|
|
119
|
+
/** A notification event type. */
|
|
120
|
+
export type NotificationEventType = (typeof NOTIFICATION_EVENT_TYPES)[number];
|
|
121
|
+
/**
|
|
122
|
+
* Sink for critical orchestrator events. Implementations persist and deliver
|
|
123
|
+
* asynchronously; `notify` must never block or throw into orchestration.
|
|
124
|
+
*/
|
|
125
|
+
export interface Notifier {
|
|
126
|
+
notify(type: NotificationEventType, payload: Record<string, unknown>): void;
|
|
127
|
+
}
|
|
128
|
+
/** Three-valued logic result (Spec §6). `unknown` is never startable. */
|
|
129
|
+
export type TriValue = true | false | 'unknown';
|
|
130
|
+
/** Declarative filter operators (Spec §6). */
|
|
131
|
+
export declare const FILTER_OPERATORS: readonly ['equals', 'not_equals', 'contains', 'in', 'greater_than', 'less_than'];
|
|
132
|
+
/** A declarative filter operator. */
|
|
133
|
+
export type FilterOperator = (typeof FILTER_OPERATORS)[number];
|
|
134
|
+
/** Literal value in a filter predicate. */
|
|
135
|
+
export type FilterValue = string | number | boolean | null | readonly (string | number | boolean)[];
|
|
136
|
+
/** Leaf of the filter AST: `{ field, operator, value }`. */
|
|
137
|
+
export interface FilterPredicate {
|
|
138
|
+
field: string;
|
|
139
|
+
operator: FilterOperator;
|
|
140
|
+
value: FilterValue;
|
|
141
|
+
}
|
|
142
|
+
/** Conjunction: true iff all children are true (Kleene logic with `unknown`). */
|
|
143
|
+
export interface FilterAll {
|
|
144
|
+
all: FilterNode[];
|
|
145
|
+
}
|
|
146
|
+
/** Disjunction: true iff any child is true (Kleene logic with `unknown`). */
|
|
147
|
+
export interface FilterAny {
|
|
148
|
+
any: FilterNode[];
|
|
149
|
+
}
|
|
150
|
+
/** Negation; `not unknown` is `unknown`. */
|
|
151
|
+
export interface FilterNot {
|
|
152
|
+
not: FilterNode;
|
|
153
|
+
}
|
|
154
|
+
/** Declarative filter AST shared by workflows, item priorities and views (Spec §6). */
|
|
155
|
+
export type FilterNode = FilterAll | FilterAny | FilterNot | FilterPredicate;
|
|
156
|
+
/** Type guard for {@link FilterAll}. */
|
|
157
|
+
export declare function isFilterAll(node: FilterNode): node is FilterAll;
|
|
158
|
+
/** Type guard for {@link FilterAny}. */
|
|
159
|
+
export declare function isFilterAny(node: FilterNode): node is FilterAny;
|
|
160
|
+
/** Type guard for {@link FilterNot}. */
|
|
161
|
+
export declare function isFilterNot(node: FilterNode): node is FilterNot;
|
|
162
|
+
/** Type guard for {@link FilterPredicate}. */
|
|
163
|
+
export declare function isFilterPredicate(node: FilterNode): node is FilterPredicate;
|
|
164
|
+
/** Field value types. `date` values are ISO-8601 strings. */
|
|
165
|
+
export type FieldType = 'string' | 'number' | 'boolean' | 'date' | 'string[]';
|
|
166
|
+
/** Runtime value of a field. `date` fields carry ISO-8601 strings; absent values are `null`. */
|
|
167
|
+
export type FieldValue = string | number | boolean | null | readonly string[];
|
|
168
|
+
/** Field declared by a source adapter (Spec §17). */
|
|
169
|
+
export interface FieldDefinition {
|
|
170
|
+
/** Full field name, possibly dotted, e.g. `labels`, `dependencies.blocked_by_open`. */
|
|
171
|
+
name: string;
|
|
172
|
+
type: FieldType;
|
|
173
|
+
/** Short human-readable description (for docs / config validation messages). */
|
|
174
|
+
description?: string;
|
|
175
|
+
/** Name of another field holding a URL to link this field to in views (e.g. `url`). */
|
|
176
|
+
link?: string;
|
|
177
|
+
/** Operators that are meaningful for this field. */
|
|
178
|
+
operators: readonly FilterOperator[];
|
|
179
|
+
/**
|
|
180
|
+
* Expensive field: not contained in {@link SourceItem.fields} from
|
|
181
|
+
* `listCandidates`, must be resolved lazily via {@link SourceAdapter.resolveFields}
|
|
182
|
+
* (e.g. GitHub dependencies; Spec §7 step 5).
|
|
183
|
+
*/
|
|
184
|
+
expensive?: boolean;
|
|
185
|
+
/**
|
|
186
|
+
* Operators the adapter can push down into the external query
|
|
187
|
+
* (`listCandidates({ filter })`). Must be a subset of `operators`.
|
|
188
|
+
*/
|
|
189
|
+
pushdown?: readonly FilterOperator[];
|
|
190
|
+
/**
|
|
191
|
+
* String values compare without regard to case (e.g. GitHub label names,
|
|
192
|
+
* which GitHub itself treats case-insensitively).
|
|
193
|
+
*/
|
|
194
|
+
caseInsensitive?: boolean;
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Operators that are meaningful per field type; config validation accepts
|
|
198
|
+
* exactly these. (`equals` on lists is not expressible: list values are only
|
|
199
|
+
* allowed for `in`.)
|
|
200
|
+
*/
|
|
201
|
+
export declare const OPERATORS_BY_TYPE: Readonly<Record<FieldType, readonly FilterOperator[]>>;
|
|
202
|
+
/**
|
|
203
|
+
* Internal run fields available to views (per global item key, latest run by
|
|
204
|
+
* creation). Not available in workflow filters.
|
|
205
|
+
*/
|
|
206
|
+
export declare const VIEW_RUN_FIELDS: readonly FieldDefinition[];
|
|
207
|
+
/**
|
|
208
|
+
* Result of resolving a field. `known: false` means the value could not be
|
|
209
|
+
* determined (e.g. missing API permission) and MUST evaluate to `unknown` —
|
|
210
|
+
* never to 0/empty (Spec §6, §20.7).
|
|
211
|
+
*/
|
|
212
|
+
export type FieldResolution = {
|
|
213
|
+
known: true;
|
|
214
|
+
value: FieldValue;
|
|
215
|
+
} | {
|
|
216
|
+
known: false;
|
|
217
|
+
reason: string;
|
|
218
|
+
};
|
|
219
|
+
/** One external work item (e.g. GitHub issue/PR) as seen by the orchestrator. */
|
|
220
|
+
export interface SourceItem {
|
|
221
|
+
/** Configured source ID (e.g. `project_a`). */
|
|
222
|
+
sourceId: string;
|
|
223
|
+
/** Adapter-defined item ID, stable within the source (GitHub: issue/PR number as string). */
|
|
224
|
+
itemId: string;
|
|
225
|
+
/** Global key `sourceItemKey(sourceId, itemId)`, used for locks/blocks/history. */
|
|
226
|
+
key: string;
|
|
227
|
+
/** Canonical web URL of the item. */
|
|
228
|
+
url: string;
|
|
229
|
+
/** Adapter-defined item kind, e.g. `issue` or `pull_request`. */
|
|
230
|
+
type: string;
|
|
231
|
+
/** Creation time (ISO-8601), used as deterministic scheduling tie-breaker (Spec §7). */
|
|
232
|
+
createdAt?: string;
|
|
233
|
+
/**
|
|
234
|
+
* Cheap field values keyed by the full field name (see {@link FieldDefinition.name}).
|
|
235
|
+
* Expensive fields are absent; they are resolved via {@link SourceAdapter.resolveFields}
|
|
236
|
+
* and callers never write resolved values back into this record.
|
|
237
|
+
*/
|
|
238
|
+
fields: Record<string, FieldValue>;
|
|
239
|
+
}
|
|
240
|
+
/** Identity ID as declared in `identities.yaml` (e.g. `coder`). */
|
|
241
|
+
export type IdentityRef = string;
|
|
242
|
+
/** Short-lived credential. Never persist or log `token`. */
|
|
243
|
+
export interface AccessToken {
|
|
244
|
+
token: string;
|
|
245
|
+
expiresAt: Date;
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Provides short-lived credentials per identity (Spec §5.3), e.g. GitHub App
|
|
249
|
+
* installation tokens. Implementations cache and refresh internally and
|
|
250
|
+
* register issued tokens with the secret redactor.
|
|
251
|
+
*/
|
|
252
|
+
export interface CredentialProvider {
|
|
253
|
+
/**
|
|
254
|
+
* Return a valid token for `identity`. Throws `SourceError`: kind `auth`
|
|
255
|
+
* for configuration/credential problems (not retryable), but also
|
|
256
|
+
* `transient` / `rate_limited` for temporary failures of the token
|
|
257
|
+
* exchange — consumers decide on retries via `SourceError.retryable`.
|
|
258
|
+
*/
|
|
259
|
+
getToken(identity: IdentityRef, options?: {
|
|
260
|
+
signal?: AbortSignal;
|
|
261
|
+
}): Promise<AccessToken>;
|
|
262
|
+
/** Drop a cached token (e.g. after a 401) so the next call fetches a fresh one. */
|
|
263
|
+
invalidate?(identity: IdentityRef): void;
|
|
264
|
+
/**
|
|
265
|
+
* Non-secret public facts about an identity (e.g. the GitHub App ID), used
|
|
266
|
+
* by adapters to recognise their own writes (comment authorship for
|
|
267
|
+
* idempotency markers). `undefined` for unknown identities.
|
|
268
|
+
*/
|
|
269
|
+
describe?(identity: IdentityRef): IdentityDescription | undefined;
|
|
270
|
+
}
|
|
271
|
+
/** Public, non-secret description of an identity (see {@link CredentialProvider.describe}). */
|
|
272
|
+
export interface IdentityDescription {
|
|
273
|
+
/** GitHub App ID for `github_app` identities. */
|
|
274
|
+
appId?: string;
|
|
275
|
+
}
|
|
276
|
+
/** Declarative change to an item (`source.update`, Spec §10). */
|
|
277
|
+
export interface SourceUpdate {
|
|
278
|
+
labels?: {
|
|
279
|
+
add?: readonly string[];
|
|
280
|
+
remove?: readonly string[];
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
/** Outcome of {@link SourceAdapter.applyUpdate}. */
|
|
284
|
+
export interface SourceUpdateResult {
|
|
285
|
+
/** False if the item already was in the desired state (idempotent no-op). */
|
|
286
|
+
changed: boolean;
|
|
287
|
+
/** What was actually changed, for the action journal. */
|
|
288
|
+
applied?: {
|
|
289
|
+
labelsAdded?: string[];
|
|
290
|
+
labelsRemoved?: string[];
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
/** Reference to a posted comment. */
|
|
294
|
+
export interface CommentRef {
|
|
295
|
+
/** Adapter-specific comment ID (persisted as action `external_key`). */
|
|
296
|
+
id: string;
|
|
297
|
+
url?: string;
|
|
298
|
+
}
|
|
299
|
+
/** Options for {@link SourceAdapter.listCandidates}. */
|
|
300
|
+
export interface ListCandidatesOptions {
|
|
301
|
+
/**
|
|
302
|
+
* Filter the adapter MAY push into the external query. Adapters may ignore
|
|
303
|
+
* any part of it; the result may therefore be a superset and callers always
|
|
304
|
+
* re-evaluate the full filter locally.
|
|
305
|
+
*/
|
|
306
|
+
filter?: FilterNode;
|
|
307
|
+
signal?: AbortSignal;
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* Adapter for one configured source instance (Spec §1.4, §5.2). Created per
|
|
311
|
+
* entry in `sources.yaml` by a {@link SourceAdapterFactory}.
|
|
312
|
+
*
|
|
313
|
+
* Reads use the source's default identity; writes take an explicit identity
|
|
314
|
+
* (action → workflow → source fallback is resolved by the caller).
|
|
315
|
+
* Failures are reported as `SourceError`.
|
|
316
|
+
*/
|
|
317
|
+
export interface SourceAdapter {
|
|
318
|
+
/** Adapter type, e.g. `github`. */
|
|
319
|
+
readonly type: string;
|
|
320
|
+
/** Configured source ID, e.g. `project_a`. */
|
|
321
|
+
readonly sourceId: string;
|
|
322
|
+
/** Human-readable location for `{source.repository}` (GitHub: `owner/name`). */
|
|
323
|
+
readonly repository?: string;
|
|
324
|
+
/** Fields this adapter can provide, including expensive ones. */
|
|
325
|
+
fieldDefinitions(): readonly FieldDefinition[];
|
|
326
|
+
/** List candidate items (default: open items) with cheap fields populated. */
|
|
327
|
+
listCandidates(options?: ListCandidatesOptions): Promise<SourceItem[]>;
|
|
328
|
+
/** Fetch a single item freshly; `null` if it does not exist / is not visible. */
|
|
329
|
+
getItem(itemId: string, options?: {
|
|
330
|
+
signal?: AbortSignal;
|
|
331
|
+
}): Promise<SourceItem | null>;
|
|
332
|
+
/**
|
|
333
|
+
* Parse a user-supplied reference (URL like `https://github.com/o/r/issues/1`
|
|
334
|
+
* or a bare ID like `1`) into an `itemId` of THIS source; `null` if the
|
|
335
|
+
* reference is malformed or belongs to another source.
|
|
336
|
+
*/
|
|
337
|
+
parseItemRef(ref: string): string | null;
|
|
338
|
+
/**
|
|
339
|
+
* Resolve (typically expensive) fields of one item lazily, as a batch.
|
|
340
|
+
*
|
|
341
|
+
* Contract:
|
|
342
|
+
* - Returns an entry for EVERY requested name; unknown field names and
|
|
343
|
+
* permission/availability problems yield `{ known: false }` instead of
|
|
344
|
+
* throwing, so filters evaluate to `unknown` (fail-closed, Spec §20.7).
|
|
345
|
+
* Only unexpected failures (e.g. aborted signal) may reject.
|
|
346
|
+
* - Adapters keep NO cache across calls: every call reflects the external
|
|
347
|
+
* state at call time. Related fields (e.g. all `dependencies.*`) should be
|
|
348
|
+
* computed from one API round trip within a call.
|
|
349
|
+
* - Callers request all expensive fields they need for an item in one call
|
|
350
|
+
* (once the first one is needed), hold the result only for the current
|
|
351
|
+
* planning step / view request, and never write it back into
|
|
352
|
+
* {@link SourceItem.fields}.
|
|
353
|
+
*/
|
|
354
|
+
resolveFields(item: SourceItem, fields: readonly string[], options?: {
|
|
355
|
+
signal?: AbortSignal;
|
|
356
|
+
}): Promise<Record<string, FieldResolution>>;
|
|
357
|
+
/**
|
|
358
|
+
* Apply a declarative update idempotently: re-read the item first, change
|
|
359
|
+
* only what differs, preserve unrelated manual changes (Spec §10).
|
|
360
|
+
*/
|
|
361
|
+
applyUpdate(item: SourceItem, update: SourceUpdate, identity: IdentityRef): Promise<SourceUpdateResult>;
|
|
362
|
+
/**
|
|
363
|
+
* Post a conversation comment (not a review) containing `marker` in an
|
|
364
|
+
* unobtrusive, adapter-specific way (GitHub: `<!-- marker -->`).
|
|
365
|
+
*/
|
|
366
|
+
postComment(item: SourceItem, body: string, marker: string, identity: IdentityRef): Promise<CommentRef>;
|
|
367
|
+
/** Find a previously posted comment carrying `marker` (idempotency before retry). */
|
|
368
|
+
findCommentByMarker(item: SourceItem, marker: string, identity: IdentityRef): Promise<CommentRef | null>;
|
|
369
|
+
}
|
|
370
|
+
/** Dependencies handed to adapter factories. */
|
|
371
|
+
export interface SourceAdapterDeps {
|
|
372
|
+
credentials: CredentialProvider;
|
|
373
|
+
logger: Logger;
|
|
374
|
+
clock: Clock;
|
|
375
|
+
fetch?: FetchLike;
|
|
376
|
+
}
|
|
377
|
+
/** Creates {@link SourceAdapter} instances for one adapter type. */
|
|
378
|
+
export interface SourceAdapterFactory<TConfig = unknown> {
|
|
379
|
+
readonly type: string;
|
|
380
|
+
/** Build an adapter for one source; `config` is the validated source entry. */
|
|
381
|
+
create(sourceId: string, config: TConfig, deps: SourceAdapterDeps): SourceAdapter;
|
|
382
|
+
}
|
|
383
|
+
/**
|
|
384
|
+
* Platform-specific identity of a started process (Spec §13). PID alone is
|
|
385
|
+
* not sufficient: `token` captures e.g. Linux boot-id + start time or the
|
|
386
|
+
* macOS `lstart`. Persisted as JSON in `runs.process_start_identity`.
|
|
387
|
+
*/
|
|
388
|
+
export interface ProcessStartIdentity {
|
|
389
|
+
pid: number;
|
|
390
|
+
/** Process group ID signalled on cancel/timeout (usually equals `pid`). */
|
|
391
|
+
pgid: number;
|
|
392
|
+
/** Opaque, platform-prefixed start identity, e.g. `linux:<boot-id>:<starttime>`. */
|
|
393
|
+
token: string;
|
|
394
|
+
}
|
|
395
|
+
/** Files used by one execution (see `dataPaths().run()`). */
|
|
396
|
+
export interface ExecutionFiles {
|
|
397
|
+
contextFile: string;
|
|
398
|
+
resultFile: string;
|
|
399
|
+
stdoutLog: string;
|
|
400
|
+
stderrLog: string;
|
|
401
|
+
}
|
|
402
|
+
/** Everything an executor needs to start the main worker of a run. */
|
|
403
|
+
export interface ExecutionSpec {
|
|
404
|
+
runId: string;
|
|
405
|
+
workflowId: string;
|
|
406
|
+
/** Executable (absolute path or resolvable via PATH of the minimal env). */
|
|
407
|
+
command: string;
|
|
408
|
+
/** Arguments passed as a list (no shell interpolation, Spec §20.6). */
|
|
409
|
+
args: readonly string[];
|
|
410
|
+
/** Absolute workspace directory (already rendered and checked with `resolveWithin`). */
|
|
411
|
+
workingDirectory: string;
|
|
412
|
+
/** Create `workingDirectory` if missing. */
|
|
413
|
+
createDirectory: boolean;
|
|
414
|
+
/** Explicitly declared environment variables (not secrets). */
|
|
415
|
+
env: Readonly<Record<string, string>>;
|
|
416
|
+
/** Resolved secret values by env var name; never persisted, redacted from logs. */
|
|
417
|
+
secrets: Readonly<Record<string, string>>;
|
|
418
|
+
/**
|
|
419
|
+
* Context written to `files.contextFile` (contains no secrets). The main
|
|
420
|
+
* worker gets a {@link WorkerContext}; other executions (e.g. lifecycle
|
|
421
|
+
* `shell` actions, WI-07) may pass their own JSON object (e.g. run + result).
|
|
422
|
+
* `ADISPATCH_SOURCE_*` variables are derived from a `source` block shaped like
|
|
423
|
+
* {@link WorkerContext.source} if present.
|
|
424
|
+
*/
|
|
425
|
+
context: WorkerContext | Readonly<Record<string, unknown>>;
|
|
426
|
+
files: ExecutionFiles;
|
|
427
|
+
timeouts: {
|
|
428
|
+
/** Total runtime limit; `undefined` = off. */
|
|
429
|
+
maxDurationMs?: number;
|
|
430
|
+
/** Limit since last stdout/stderr output or event; `undefined` = off. */
|
|
431
|
+
idleTimeoutMs?: number;
|
|
432
|
+
};
|
|
433
|
+
/** Grace period between SIGTERM and SIGKILL. */
|
|
434
|
+
cancelGraceMs: number;
|
|
435
|
+
/**
|
|
436
|
+
* Max bytes persisted per run, shared by stdout and stderr (Spec §5.1
|
|
437
|
+
* `max_log_size_per_run`); beyond that a truncation diagnostic naming the stream is emitted.
|
|
438
|
+
*/
|
|
439
|
+
maxLogBytes?: number;
|
|
440
|
+
}
|
|
441
|
+
/** A chunk of raw worker output. */
|
|
442
|
+
export interface OutputChunk {
|
|
443
|
+
stream: 'stdout' | 'stderr';
|
|
444
|
+
/** UTF-8 decoded text as received (may contain partial lines). */
|
|
445
|
+
data: string;
|
|
446
|
+
at: Date;
|
|
447
|
+
}
|
|
448
|
+
/** Structured worker event from a `@@ADISPATCH_EVENT {...}` line (Spec §9.3). Informative only. */
|
|
449
|
+
export interface WorkerEvent {
|
|
450
|
+
/** Event type, e.g. `status`, `progress`, `question`. */
|
|
451
|
+
type: string;
|
|
452
|
+
at: Date;
|
|
453
|
+
stream: 'stdout' | 'stderr';
|
|
454
|
+
/** Full parsed JSON object, including `type`. */
|
|
455
|
+
data: Record<string, unknown>;
|
|
456
|
+
}
|
|
457
|
+
/**
|
|
458
|
+
* Orchestrator-side diagnostics of an execution that must be persisted as
|
|
459
|
+
* events (Spec §9.3, §12): log truncation, log write errors, unparsable
|
|
460
|
+
* event lines.
|
|
461
|
+
*/
|
|
462
|
+
export interface ExecutorDiagnostic {
|
|
463
|
+
type: 'log_truncated' | 'log_write_error' | 'event_parse_warning' | 'kill_failed';
|
|
464
|
+
at: Date;
|
|
465
|
+
stream?: 'stdout' | 'stderr';
|
|
466
|
+
message: string;
|
|
467
|
+
details?: Record<string, unknown>;
|
|
468
|
+
}
|
|
469
|
+
/** State of the result file after the worker exited (Spec §8.2). */
|
|
470
|
+
export type ResultFileStatus = {
|
|
471
|
+
state: 'missing';
|
|
472
|
+
} | {
|
|
473
|
+
state: 'valid';
|
|
474
|
+
result: WorkerResult;
|
|
475
|
+
} | {
|
|
476
|
+
state: 'invalid';
|
|
477
|
+
error: string;
|
|
478
|
+
};
|
|
479
|
+
/** Raw facts about how an execution ended; classified by `classifyOutcome` (WI-05). */
|
|
480
|
+
export interface ExecutionOutcome {
|
|
481
|
+
/** Exit code, or `null` if killed by a signal or never started. */
|
|
482
|
+
exitCode: number | null;
|
|
483
|
+
/** Terminating signal name, or `null`. */
|
|
484
|
+
signal: NodeJS.Signals | null;
|
|
485
|
+
/** Set when the process (or its workspace/context) could not be started. */
|
|
486
|
+
spawnError?: {
|
|
487
|
+
code?: string;
|
|
488
|
+
message: string;
|
|
489
|
+
};
|
|
490
|
+
/** Which timeout fired, if any. */
|
|
491
|
+
timedOut: false | 'max_duration' | 'idle';
|
|
492
|
+
/** True if the process was stopped through {@link RunningProcess.cancel}. */
|
|
493
|
+
cancelled: boolean;
|
|
494
|
+
resultFile: ResultFileStatus;
|
|
495
|
+
startedAt: Date;
|
|
496
|
+
finishedAt: Date;
|
|
497
|
+
/** Bytes persisted per stream and whether limits truncated them. */
|
|
498
|
+
logs: {
|
|
499
|
+
stdoutBytes: number;
|
|
500
|
+
stderrBytes: number;
|
|
501
|
+
truncated: boolean;
|
|
502
|
+
};
|
|
503
|
+
}
|
|
504
|
+
/** Classified final outcome of a run (Spec §8.2 table). */
|
|
505
|
+
export interface OutcomeClassification extends FinalizationTarget {
|
|
506
|
+
/** The valid worker result, only when `status === 'completed'` and a file was present. */
|
|
507
|
+
result: WorkerResult | null;
|
|
508
|
+
}
|
|
509
|
+
/** Handle of a started worker process. */
|
|
510
|
+
export interface RunningProcess {
|
|
511
|
+
/** OS process ID; `undefined` if spawning failed. */
|
|
512
|
+
readonly pid: number | undefined;
|
|
513
|
+
/** Start identity captured right after spawn; `undefined` if unavailable. */
|
|
514
|
+
readonly startIdentity: ProcessStartIdentity | undefined;
|
|
515
|
+
/**
|
|
516
|
+
* Subscribe to raw output. Listeners are called asynchronously and must not
|
|
517
|
+
* block log capture. Register before yielding to the event loop to avoid
|
|
518
|
+
* missing early output.
|
|
519
|
+
*/
|
|
520
|
+
onOutput(listener: (chunk: OutputChunk) => void): Unsubscribe;
|
|
521
|
+
/** Subscribe to valid structured worker events. */
|
|
522
|
+
onEvent(listener: (event: WorkerEvent) => void): Unsubscribe;
|
|
523
|
+
/** Subscribe to orchestrator-side diagnostics (truncation, write errors, parse warnings). */
|
|
524
|
+
onDiagnostic(listener: (diagnostic: ExecutorDiagnostic) => void): Unsubscribe;
|
|
525
|
+
/** Resolves once the process (group) has ended and the result file was inspected. Never rejects. */
|
|
526
|
+
wait(): Promise<ExecutionOutcome>;
|
|
527
|
+
/**
|
|
528
|
+
* Controlled stop: SIGTERM to the process group, SIGKILL after `graceMs`
|
|
529
|
+
* (default: spec's `cancelGraceMs`). Resolves once termination is
|
|
530
|
+
* confirmed; rejects if the group could not be terminated — the run must
|
|
531
|
+
* then NOT be marked finished (Spec §13).
|
|
532
|
+
*/
|
|
533
|
+
cancel(graceMs?: number): Promise<void>;
|
|
534
|
+
}
|
|
535
|
+
/** Starts worker processes (V1: shell executor). */
|
|
536
|
+
export interface Executor {
|
|
537
|
+
readonly type: string;
|
|
538
|
+
/**
|
|
539
|
+
* Prepare workspace/context and spawn the worker. Never rejects for runtime
|
|
540
|
+
* failures (spawn error, unwritable workspace): those surface as
|
|
541
|
+
* `ExecutionOutcome.spawnError` from `wait()`.
|
|
542
|
+
*/
|
|
543
|
+
start(spec: ExecutionSpec): Promise<RunningProcess>;
|
|
544
|
+
}
|