@kici-dev/orchestrator 0.11.0 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (158) hide show
  1. package/dist/__test-helpers__/mock-db-query.d.ts +4 -5
  2. package/dist/agent/agent-version.d.ts +5 -5
  3. package/dist/agent/dispatcher.d.ts +48 -0
  4. package/dist/agent/registry.d.ts +38 -9
  5. package/dist/agent-packaging/node-runtime-members.d.ts +14 -0
  6. package/dist/app.d.ts +9 -3
  7. package/dist/approvals/apply-decision.d.ts +1 -1
  8. package/dist/audit/access-log.d.ts +2 -3
  9. package/dist/cache/cache-upload-settle.d.ts +75 -0
  10. package/dist/cache/pending-inits.d.ts +9 -0
  11. package/dist/cancel/cancel-run.d.ts +22 -4
  12. package/dist/cancel/peer-job-cancel.d.ts +50 -0
  13. package/dist/cancel/sweep-stuck-cancelling.d.ts +3 -1
  14. package/dist/cli/commands/access-log.d.ts +3 -3
  15. package/dist/cli/commands/agent-service/agent-env.d.ts +20 -0
  16. package/dist/cli/commands/agent-service/status.d.ts +3 -3
  17. package/dist/cli/commands/attestations.d.ts +1 -1
  18. package/dist/cli/commands/context.d.ts +2 -2
  19. package/dist/cli/commands/event-dlq.d.ts +5 -6
  20. package/dist/cli/commands/event-log.d.ts +2 -3
  21. package/dist/cli/commands/execution.d.ts +1 -3
  22. package/dist/cli/commands/local-hook.d.ts +3 -2
  23. package/dist/cli/commands/local-trigger.d.ts +7 -0
  24. package/dist/cli/commands/orchestrator-service/status.d.ts +10 -3
  25. package/dist/cli/commands/queue.d.ts +1 -2
  26. package/dist/cli/commands/runs.d.ts +2 -3
  27. package/dist/cli/commands/service-health.d.ts +68 -0
  28. package/dist/cli/commands/shared/env-file-mode.d.ts +3 -2
  29. package/dist/cli/commands/shared/upgrade-safety.d.ts +11 -5
  30. package/dist/cli/commands/shared/versioned-upgrade.d.ts +119 -7
  31. package/dist/cli/commands/workflow.d.ts +3 -4
  32. package/dist/cli/open-browser.d.ts +1 -1
  33. package/dist/cli/service/entrypoint.d.ts +18 -0
  34. package/dist/cli/service/image-digests.d.ts +10 -0
  35. package/dist/cli/service/index.d.ts +4 -2
  36. package/dist/cli/service/instance/manifest.d.ts +39 -0
  37. package/dist/cli/service/launchd.d.ts +45 -10
  38. package/dist/cli/service/shutdown-grace.d.ts +35 -0
  39. package/dist/cli/service/types.d.ts +9 -0
  40. package/dist/cli/service/windows-acl.d.ts +40 -0
  41. package/dist/cli/service/windows-env-file.d.ts +45 -0
  42. package/dist/cli/service/windows.d.ts +13 -0
  43. package/dist/cli.js +2601 -1232
  44. package/dist/cluster/cluster-identity.d.ts +4 -4
  45. package/dist/cluster/coordinator-credential.d.ts +45 -0
  46. package/dist/cluster/coordinator.d.ts +18 -2
  47. package/dist/cluster/index.d.ts +1 -0
  48. package/dist/cluster/instance-heartbeat.d.ts +6 -1
  49. package/dist/cluster/join-token.d.ts +4 -2
  50. package/dist/cluster/leader-gated-scheduler.d.ts +7 -1
  51. package/dist/cluster/peer-auth-coordinator.d.ts +13 -0
  52. package/dist/cluster/peer-client.d.ts +4 -0
  53. package/dist/cluster/peer-credentials.d.ts +32 -1
  54. package/dist/cluster/raft-state.d.ts +6 -0
  55. package/dist/cluster/raft.d.ts +16 -2
  56. package/dist/cold-store/load-access-log-range.d.ts +3 -3
  57. package/dist/cold-store/load-event-log-range.d.ts +1 -1
  58. package/dist/cold-store/load-secret-audit-log-range.d.ts +2 -2
  59. package/dist/cold-store/orchestrator-cold-store.d.ts +9 -11
  60. package/dist/cold-store/tables/access-log.d.ts +2 -2
  61. package/dist/cold-store/tables/event-log.d.ts +4 -10
  62. package/dist/cold-store/tables/execution-jobs.d.ts +1 -1
  63. package/dist/cold-store/tables/execution-runs.d.ts +4 -4
  64. package/dist/cold-store/tables/execution-steps.d.ts +1 -1
  65. package/dist/cold-store/tables/secret-audit-log.d.ts +3 -3
  66. package/dist/config.d.ts +6 -1
  67. package/dist/contexts/held-runs.d.ts +2 -2
  68. package/dist/dashboard/attestation-filters.d.ts +1 -1
  69. package/dist/dashboard/handler.d.ts +8 -8
  70. package/dist/db/deferred-indexes.d.ts +2 -2
  71. package/dist/db/migrations/005_cold_store_chunk_counter.d.ts +2 -4
  72. package/dist/db/migrations/006_runs_jobs_steps_archived_at.d.ts +4 -4
  73. package/dist/db/migrations/007_audit_logs_archived_at.d.ts +6 -9
  74. package/dist/db/migrations/008_event_log_archived_at.d.ts +4 -6
  75. package/dist/db/migrations/010_cold_store_chunks.d.ts +2 -2
  76. package/dist/db/migrations/012_peer_credentials_active_uniq.d.ts +2 -4
  77. package/dist/db/migrations/016_org_settings_allow_http_npm.d.ts +2 -2
  78. package/dist/db/migrations/045_host_properties.d.ts +1 -1
  79. package/dist/db/migrations/046_join_token_consumed_by_instance.d.ts +1 -1
  80. package/dist/db/migrations/048_host_reboot_pending.d.ts +1 -1
  81. package/dist/db/migrations/049_held_runs_payload.d.ts +1 -1
  82. package/dist/db/migrations/050_sources_slug.d.ts +1 -1
  83. package/dist/db/migrations/051_binding_host_pattern.d.ts +1 -1
  84. package/dist/db/migrations/052_host_reach_metadata.d.ts +1 -1
  85. package/dist/db/migrations/053_agent_token_single_use.d.ts +1 -1
  86. package/dist/db/migrations/054_local_working_tree.d.ts +1 -1
  87. package/dist/db/migrations/055_agent_token_mandatory_labels.d.ts +1 -1
  88. package/dist/db/migrations/056_execution_jobs_environments.d.ts +1 -1
  89. package/dist/db/migrations/064_execution_jobs_skipped_environments.d.ts +1 -1
  90. package/dist/db/migrations/152_org_settings_cache_upload_settle_timeout.d.ts +15 -0
  91. package/dist/db/migrations/153_execution_runs_cancel_force.d.ts +16 -0
  92. package/dist/db/types.d.ts +27 -13
  93. package/dist/events/types.d.ts +1 -1
  94. package/dist/fault-injection-types.d.ts +2 -2
  95. package/dist/firecracker/host-network.d.ts +21 -3
  96. package/dist/firecracker/net-interfaces.d.ts +1 -1
  97. package/dist/helpers/run-detached.d.ts +12 -0
  98. package/dist/index.js +242 -67
  99. package/dist/oidc/db-signer.d.ts +1 -1
  100. package/dist/pipeline/changed-files.d.ts +51 -0
  101. package/dist/pipeline/cross-source-tally.d.ts +21 -0
  102. package/dist/pipeline/degraded-reason.d.ts +8 -0
  103. package/dist/pipeline/dispatch-matched-workflow.d.ts +10 -0
  104. package/dist/pipeline/global-eval-round.d.ts +5 -4
  105. package/dist/pipeline/processor.d.ts +11 -3
  106. package/dist/pipeline/rerun-inputs.d.ts +16 -7
  107. package/dist/provenance/retrier-mint.d.ts +1 -1
  108. package/dist/provenance/trust-root.d.ts +3 -3
  109. package/dist/providers/github/changed-files.d.ts +14 -4
  110. package/dist/providers/universal-git/changed-files.d.ts +6 -0
  111. package/dist/providers/universal-git/clone-token.d.ts +9 -13
  112. package/dist/providers/universal-git/config.d.ts +4 -0
  113. package/dist/providers/universal-git/index.d.ts +1 -2
  114. package/dist/providers/universal-git/normalizer.d.ts +2 -3
  115. package/dist/providers/universal-git/ssh-auth.d.ts +4 -4
  116. package/dist/queue/cleanup.d.ts +2 -2
  117. package/dist/queue/job-queue.d.ts +6 -6
  118. package/dist/queue/scheduled-job.d.ts +5 -7
  119. package/dist/registration/extractor.d.ts +1 -1
  120. package/dist/registration/registration-index.d.ts +1 -1
  121. package/dist/reporting/execution-tracker.d.ts +3 -3
  122. package/dist/routes/admin-access-log.d.ts +1 -1
  123. package/dist/routes/admin-auth.d.ts +2 -2
  124. package/dist/routes/admin-event-log.d.ts +2 -2
  125. package/dist/routes/admin-runs.d.ts +3 -3
  126. package/dist/routes/admin-scheduled-jobs.d.ts +2 -3
  127. package/dist/routes/health.d.ts +9 -0
  128. package/dist/scaler/container-backend.d.ts +3 -1
  129. package/dist/scaler/container-runtime.d.ts +9 -0
  130. package/dist/scaler/firecracker-backend.d.ts +15 -10
  131. package/dist/scaler/firecracker-extra-hosts.d.ts +20 -0
  132. package/dist/scaler/machine-ledger.d.ts +3 -4
  133. package/dist/scaler/manager.d.ts +26 -2
  134. package/dist/scaler/scaler-state-store.d.ts +1 -1
  135. package/dist/scaler/types.d.ts +4 -1
  136. package/dist/secrets/audit-logger.d.ts +2 -2
  137. package/dist/security/reduced-privilege-note.d.ts +2 -3
  138. package/dist/security/trust-policy-store.d.ts +3 -3
  139. package/dist/server.d.ts +2 -1
  140. package/dist/server.js +4955 -3206
  141. package/dist/stale-detector/stale-run-detector.d.ts +1 -1
  142. package/dist/stale-detector/workflow-deadline-detector.d.ts +7 -1
  143. package/dist/standalone.d.ts +1 -1
  144. package/dist/standalone.js +12944 -11243
  145. package/dist/storage/filesystem.d.ts +1 -1
  146. package/dist/storage/index.d.ts +1 -1
  147. package/dist/storage/s3.d.ts +36 -0
  148. package/dist/storage/sign-url.d.ts +2 -1
  149. package/dist/storage/types.d.ts +2 -2
  150. package/dist/ws/agent-handler.d.ts +58 -6
  151. package/dist/ws/agent-heartbeat.d.ts +4 -5
  152. package/dist/ws/dashboard-context-handler.d.ts +1 -1
  153. package/dist/ws/platform-client.d.ts +44 -32
  154. package/dist/ws/server-options.d.ts +1 -1
  155. package/dist/ws/test-relay-handlers.d.ts +1 -1
  156. package/installer-image-digests.json +3 -3
  157. package/package.json +5 -5
  158. package/sbom.spdx.json +53 -53
@@ -6,7 +6,7 @@
6
6
  * are replaced by HMAC-signed `http://<orchUrl>/api/v1/cache/blob/...` URLs
7
7
  * — see `sign-url.ts` for the token mechanics and `app.ts` for the route.
8
8
  *
9
- * Intended for single-host deployments and E2E sandboxes where standing up
9
+ * Intended for single-host deployments and test sandboxes where standing up
10
10
  * an S3-compatible service is overkill. Production should still use S3.
11
11
  *
12
12
  * Metadata is co-located as a sibling JSON file (`<key>.meta.json`) so the
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * Pluggable storage backends:
5
5
  * - S3CacheStorage — production / multi-host
6
- * - FilesystemCacheStorage — single-host / E2E sandbox
6
+ * - FilesystemCacheStorage — single-host / test sandbox
7
7
  *
8
8
  * Use createCacheStorage() to instantiate from a discriminated config.
9
9
  */
@@ -47,6 +47,11 @@ export declare class S3CacheStorage implements CacheStorage {
47
47
  private readonly bucket;
48
48
  private readonly prefix;
49
49
  private readonly ttlMs;
50
+ /**
51
+ * False once the backend answered a conditional self-copy with
52
+ * `501 NotImplemented`. From then on `updateMeta` copies unconditionally.
53
+ */
54
+ private conditionalCopySupported;
50
55
  constructor(options: S3CacheStorageOptions);
51
56
  /** Build the full S3 object key from a cache key. */
52
57
  private objectKey;
@@ -57,11 +62,42 @@ export declare class S3CacheStorage implements CacheStorage {
57
62
  * Returns null if the object doesn't exist (NoSuchKey/NotFound).
58
63
  */
59
64
  private readMeta;
65
+ /**
66
+ * Read an object's TTL metadata together with the ETag of the version it
67
+ * belongs to. Returns null if the object doesn't exist (NoSuchKey/NotFound).
68
+ */
69
+ private readHead;
60
70
  /**
61
71
  * Update metadata on an S3 object by copying it to itself.
62
72
  * This is the standard S3 pattern for updating metadata without re-uploading data.
73
+ *
74
+ * The copy is conditional on `etag`, the version whose metadata the caller
75
+ * read. A self-copy is a whole-object write: without the condition, one that
76
+ * races a `put()` of the same key can land after it and write the older body
77
+ * back. Cache pointers are rewritten in place while builds publish them, so a
78
+ * touch-on-read racing a publish reverted the pointer to a tarball that no
79
+ * longer exists. `CopySourceIfMatch` pins the bytes copied to that version and
80
+ * `IfMatch` refuses the write unless the key still holds it.
81
+ *
82
+ * Returns false when the object was replaced since the read (`412`), or is
83
+ * being replaced right now (`409 ConditionalRequestConflict`): the newer
84
+ * write stamps metadata of its own, so there is nothing left to refresh.
85
+ *
86
+ * An S3-compatible backend that does not implement conditional copies
87
+ * answers `501 NotImplemented`. The copy then runs again without the
88
+ * condition, and later copies skip it, as on a backend that ignores the
89
+ * headers.
63
90
  */
64
91
  private updateMeta;
92
+ /** Copy an object onto itself with new TTL metadata, conditional on `etag` when given. */
93
+ private copyOntoItself;
94
+ /** Check if an error is a failed conditional request (PreconditionFailed, 412). */
95
+ private isPreconditionFailedError;
96
+ /** Check if an error is a conditional write that raced another write (ConditionalRequestConflict, 409). */
97
+ private isConditionalConflictError;
98
+ /** Check if an error is a request the backend does not implement (NotImplemented, 501). */
99
+ private isNotImplementedError;
100
+ private hasErrorShape;
65
101
  /** Check if an error is a "not found" error (NoSuchKey, NotFound, 404). */
66
102
  private isNotFoundError;
67
103
  put(key: string, data: Buffer | string): Promise<void>;
@@ -10,7 +10,8 @@
10
10
  * Signature input: `${method}:${key}:${expiresUnixMs}` with HMAC-SHA256 keyed
11
11
  * by a per-orchestrator-process secret (random 32-byte hex at boot, persists
12
12
  * for the lifetime of the process). Tokens become invalid on orchestrator
13
- * restart — fine for the filesystem backend's E2E / single-host use case.
13
+ * restart — fine for the filesystem backend's single-host / test-sandbox use
14
+ * case.
14
15
  */
15
16
  /** Default URL lifetime: 1 hour (matches S3 backend's PUT-URL lifetime). */
16
17
  export declare const DEFAULT_SIGN_URL_TTL_MS: number;
@@ -7,7 +7,7 @@
7
7
  *
8
8
  * Backends:
9
9
  * - `S3CacheStorage` for production / multi-host deployments
10
- * - `FilesystemCacheStorage` for single-host / E2E sandboxes
10
+ * - `FilesystemCacheStorage` for single-host / test sandboxes
11
11
  */
12
12
  /**
13
13
  * Metadata tracked alongside each cached item.
@@ -119,7 +119,7 @@ export type S3CacheStorageConfig = SharedS3Config & {
119
119
  * mints HMAC-signed `http://baseUrl<routePrefix>...` URLs that the
120
120
  * orchestrator's `/api/v1/cache/blob/*` route verifies before serving.
121
121
  *
122
- * Intended for single-host / E2E sandboxes where standing up an
122
+ * Intended for single-host / test sandboxes where standing up an
123
123
  * S3-compatible service is overkill.
124
124
  */
125
125
  export interface FilesystemCacheStorageConfig {
@@ -19,8 +19,8 @@
19
19
  * frame is accepted there and answered with auth.success without reading the
20
20
  * token, and the agent then registers as normal.
21
21
  */
22
- import type { WSEvents } from 'hono/ws';
23
- import { LogStream } from '@kici-dev/engine';
22
+ import type { WSContext, WSEvents, WSMessageReceive } from 'hono/ws';
23
+ import { LogStream, ScaleDownReason } from '@kici-dev/engine';
24
24
  import type { RateLimiterConfig, AttestationVerifyStatus } from '@kici-dev/engine';
25
25
  import type { ProvenanceTrustRoot } from '../provenance/trust-root.js';
26
26
  import type { AgentRegistry } from '../agent/registry.js';
@@ -36,6 +36,7 @@ import type { PendingBuildTracker } from '../cache/pending-builds.js';
36
36
  import type { PendingInitTracker } from '../cache/pending-inits.js';
37
37
  import type { PendingDynamicTracker } from '../cache/pending-dynamics.js';
38
38
  import type { PendingGlobalEvalTracker } from '../cache/pending-global-evals.js';
39
+ import { type CacheUploadSettle } from '../cache/cache-upload-settle.js';
39
40
  import type { CacheStorage } from '../storage/types.js';
40
41
  import type { AgentMetricsAggregator } from '../metrics/agent-metrics-aggregator.js';
41
42
  import { type AgentApiRegistry } from './agent-api-registry.js';
@@ -74,6 +75,28 @@ import type { FleetAgentCollector } from './fleet-agent-collector.js';
74
75
  * trailing partial multi-byte char.
75
76
  */
76
77
  export declare function truncateCloseReason(reason: string): string;
78
+ /** What a failed frame is about, for the failure log. */
79
+ export interface FrameIdentity {
80
+ messageType?: string;
81
+ agentId?: string;
82
+ runId?: string;
83
+ jobId?: string;
84
+ }
85
+ /**
86
+ * Read the type and ids from a raw agent frame, for logging a failure. Only
87
+ * string fields are copied, each capped at 128 characters; anything that is
88
+ * not a JSON object yields nothing. Runs on the failure path only.
89
+ */
90
+ export declare function frameIdentity(data: unknown): FrameIdentity;
91
+ /**
92
+ * The agent WebSocket handler. `onMessage` resolves once the frame is handled
93
+ * and never rejects: the WebSocket server does not await it.
94
+ */
95
+ export interface AgentWsEvents extends Omit<WSEvents, 'onMessage'> {
96
+ onMessage(evt: MessageEvent<WSMessageReceive>, ws: WSContext): Promise<void>;
97
+ }
98
+ /** `error` frame code sent when a registration is refused because another agent token holds the id. */
99
+ export declare const AGENT_ID_IN_USE = "AGENT_ID_IN_USE";
77
100
  export interface AgentWsHandlerDeps {
78
101
  registry: AgentRegistry;
79
102
  dispatcher: Dispatcher;
@@ -141,8 +164,11 @@ export interface AgentWsHandlerDeps {
141
164
  boundJobId?: string;
142
165
  mandatoryLabels: string[];
143
166
  } | null>;
144
- /** Optional callback when an agent disconnects (for scaler lifecycle). */
145
- onScalerAgentDisconnected?: (agentId: string) => void;
167
+ /**
168
+ * Optional callback when an agent disconnects (for scaler lifecycle). `reason`
169
+ * is the scale-down reason an event scaler emits for it.
170
+ */
171
+ onScalerAgentDisconnected?: (agentId: string, reason?: ScaleDownReason) => void;
146
172
  /** Optional callback when an agent completes a job (for scaler lifecycle). */
147
173
  onScalerJobComplete?: (agentId: string) => void;
148
174
  /** Optional callback when agent sends per-job heartbeats. */
@@ -236,6 +262,13 @@ export interface AgentWsHandlerDeps {
236
262
  artifactStore?: ArtifactStore;
237
263
  /** Cache storage for setting metadata after upload completion. */
238
264
  cacheStorage?: CacheStorage;
265
+ /**
266
+ * In-flight build-cache publishes and the per-org bound a build's success
267
+ * waits for them. Built once per orchestrator, not per connection, so a
268
+ * success replayed on a reconnected socket still sees a publish started on
269
+ * the old one. Absent: no registration and no wait.
270
+ */
271
+ cacheUploadSettle?: CacheUploadSettle;
239
272
  /**
240
273
  * Storage used to mint presigned PUT URLs for provenance bundles. Distinct
241
274
  * dep so a deployment can decide whether attestations share the cache bucket.
@@ -383,7 +416,6 @@ export interface AgentWsHandlerDeps {
383
416
  * SYNC INVARIANT: This manual validator MUST match the Zod schema
384
417
  * `agentLogChunkSchema` in packages/engine/src/protocol/messages/orchestrator-agent.ts.
385
418
  * If you change the schema, update this validator in the same commit.
386
- * See CLAUDE.md rule: "Zod fast-path sync invariant".
387
419
  */
388
420
  export declare function isValidLogChunk(raw: unknown): raw is {
389
421
  type: 'log.chunk';
@@ -405,5 +437,25 @@ export interface AgentLogChunkInput {
405
437
  /** Absent when the agent does not report a stream; read as `stdout`. */
406
438
  stream?: LogStream;
407
439
  }
408
- export declare function createAgentWsHandler(deps: AgentWsHandlerDeps): WSEvents;
440
+ /**
441
+ * Release the in-memory waiters of jobs a disconnect triage failed: pending
442
+ * builds, inits, dynamic evaluations and global eval rounds, and the user-cache
443
+ * refs of the dispatch. The dispatcher runs it inside `onAgentDisconnect`, so
444
+ * every path that drops an agent reaches it, whether or not it waits for the
445
+ * socket to close.
446
+ */
447
+ export declare function releaseFailedJobWaiters(deps: Pick<AgentWsHandlerDeps, 'pendingBuilds' | 'pendingInits' | 'pendingDynamics' | 'pendingGlobalEvals' | 'dispatchCacheRefs'>, failedJobIds: string[]): void;
448
+ /**
449
+ * Create a Hono WS event handler for agent connections.
450
+ *
451
+ * Flow:
452
+ * 1. onOpen: start 10-second register timer
453
+ * 2. First onMessage: must be agent.register with labels and capacity
454
+ * 3. Subsequent onMessage: validated against protocol schemas, routed by type
455
+ * 4. onClose: cleanup from pending registration or dispatcher
456
+ *
457
+ * A frame whose handling fails is logged with its type and ids; the
458
+ * connection stays open.
459
+ */
460
+ export declare function createAgentWsHandler(deps: AgentWsHandlerDeps): AgentWsEvents;
409
461
  //# sourceMappingURL=agent-handler.d.ts.map
@@ -5,9 +5,8 @@
5
5
  * - Logs warnings for agents past the unhealthy threshold (90s).
6
6
  * - Forcibly disconnects agents past the disconnect threshold (180s).
7
7
  *
8
- * Follows the same pattern as the Platform HeartbeatMonitor
9
- * (packages/platform/src/ws/heartbeat.ts) for consistency across
10
- * the three-tier architecture.
8
+ * Follows the same pattern as the Platform's heartbeat monitor, for
9
+ * consistency across the three-tier architecture.
11
10
  */
12
11
  import type { AgentRegistry } from '../agent/registry.js';
13
12
  import type { Dispatcher } from '../agent/dispatcher.js';
@@ -24,8 +23,8 @@ interface AgentHeartbeatMonitorDeps {
24
23
  /**
25
24
  * Periodically inspects all registered agent connections and:
26
25
  * - Marks agents as unhealthy after 90s of silence (log only).
27
- * - Closes and unregisters agents after 180s of silence.
28
- * - Triggers dispatcher.onAgentDisconnect for stale agents.
26
+ * - Triggers dispatcher.onAgentDisconnect for an agent silent for 180s, then
27
+ * unregisters it and closes its socket.
29
28
  */
30
29
  export declare class AgentHeartbeatMonitor {
31
30
  private readonly registry;
@@ -67,7 +67,7 @@ export interface DashboardContextHandlerDeps {
67
67
  /** Dependencies enabling the resolver-backed approve/reject + resume path. */
68
68
  export interface ApprovalHandlerDeps {
69
69
  store: HeldRunStore;
70
- /** Team name → member user ids (Plan-1 trust-policy cache). */
70
+ /** Team name → member user ids (trust-policy cache). */
71
71
  teamMembershipLookup: TeamMembershipLookup;
72
72
  /** Re-dispatch a released job hold (consumes its pending context). */
73
73
  resumeJob: (signal: ReleaseSignal) => Promise<void>;
@@ -51,6 +51,12 @@ import type { ProviderSource } from '../entry-helpers.js';
51
51
  * is exactly the pair that drifts.
52
52
  */
53
53
  export declare const ADMITTED_PIPELINE_LIFETIME_MS: number;
54
+ /**
55
+ * A handler for one Platform frame. It may be async: the client runs it
56
+ * through {@link PlatformClient.runFrameHandler}, which logs a failure and
57
+ * keeps the connection.
58
+ */
59
+ export type FrameHandler<M> = (msg: M) => void | Promise<void>;
54
60
  export interface PlatformClientOptions {
55
61
  /** WebSocket URL of the Platform relay. */
56
62
  url: string;
@@ -99,14 +105,14 @@ export interface PlatformClientOptions {
99
105
  /** Maximum event buffer size. Default: 10000. */
100
106
  maxBufferSize?: number;
101
107
  /** Optional callback for log pull requests from Platform. */
102
- onLogPullRequest?: (msg: {
108
+ onLogPullRequest?: FrameHandler<{
103
109
  messageId: string;
104
110
  executionId: string;
105
111
  jobName?: string;
106
112
  stepIndex?: number;
107
113
  cursor?: number;
108
114
  limit?: number;
109
- }) => void;
115
+ }>;
110
116
  /** Optional callback for peer discovery (from Platform matchmaker). */
111
117
  onPeerDiscover?: (peer: {
112
118
  connectionId: string;
@@ -116,7 +122,7 @@ export interface PlatformClientOptions {
116
122
  orchRole?: OrchRole;
117
123
  }) => void;
118
124
  /** Optional callback invoked after successful authentication and source registration. */
119
- onAuthenticated?: () => void;
125
+ onAuthenticated?: () => void | Promise<void>;
120
126
  /**
121
127
  * Returns this coordinator's currently-connected worker peers for the
122
128
  * `cluster.membership` snapshot. Undefined on a non-coordinator (or when
@@ -156,66 +162,66 @@ export interface PlatformClientOptions {
156
162
  */
157
163
  onProvenanceIssuer?: (issuer: string | null) => void;
158
164
  /** Optional callback for dashboard run detail requests from Platform. */
159
- onDashboardRunDetail?: (msg: DashboardRunDetailRequest) => void;
165
+ onDashboardRunDetail?: FrameHandler<DashboardRunDetailRequest>;
160
166
  /** Optional callback for dashboard structured run-result requests from Platform. */
161
- onDashboardRunStructured?: (msg: DashboardRunStructuredRequest) => void;
167
+ onDashboardRunStructured?: FrameHandler<DashboardRunStructuredRequest>;
162
168
  /** Optional callback for the run-state system reconciliation read from Platform. */
163
- onDashboardRunState?: (msg: DashboardRunStateRequest) => void;
169
+ onDashboardRunState?: FrameHandler<DashboardRunStateRequest>;
164
170
  /** Optional callback for dashboard runs.list (operator console) requests from Platform. */
165
- onDashboardRunsList?: (msg: DashboardRunsListRequest) => void;
171
+ onDashboardRunsList?: FrameHandler<DashboardRunsListRequest>;
166
172
  /** Optional callback for dashboard runs.filters (operator console) requests from Platform. */
167
- onDashboardRunsFilters?: (msg: DashboardRunsFiltersRequest) => void;
173
+ onDashboardRunsFilters?: FrameHandler<DashboardRunsFiltersRequest>;
168
174
  /** Optional callback for dashboard sources.list (operator console) requests from Platform. */
169
- onDashboardSourcesList?: (msg: DashboardSourcesListRequest) => void;
175
+ onDashboardSourcesList?: FrameHandler<DashboardSourcesListRequest>;
170
176
  /** Optional callback for dashboard admin-tokens.list (RBAC drift report) requests from Platform. */
171
- onDashboardAdminTokensList?: (msg: DashboardAdminTokensListRequest) => void;
177
+ onDashboardAdminTokensList?: FrameHandler<DashboardAdminTokensListRequest>;
172
178
  /** Optional callback for dashboard step logs requests from Platform. */
173
- onDashboardStepLogs?: (msg: DashboardStepLogsRequest) => void;
179
+ onDashboardStepLogs?: FrameHandler<DashboardStepLogsRequest>;
174
180
  /** Optional callback for dashboard attestations-list requests from Platform. */
175
- onDashboardAttestationsList?: (msg: DashboardAttestationsListRequest) => void;
181
+ onDashboardAttestationsList?: FrameHandler<DashboardAttestationsListRequest>;
176
182
  /** Optional callback for org-wide attestations list (browser) requests from Platform. */
177
- onDashboardAttestationsListAll?: (msg: DashboardAttestationsListAllRequest) => void;
183
+ onDashboardAttestationsListAll?: FrameHandler<DashboardAttestationsListAllRequest>;
178
184
  /** Optional callback for single-attestation detail requests from Platform. */
179
- onDashboardAttestationGet?: (msg: DashboardAttestationGetRequest) => void;
180
- onDashboardAttestationRetry?: (msg: DashboardAttestationRetryRequest) => void;
185
+ onDashboardAttestationGet?: FrameHandler<DashboardAttestationGetRequest>;
186
+ onDashboardAttestationRetry?: FrameHandler<DashboardAttestationRetryRequest>;
181
187
  /** Optional callback for dashboard artifacts-list requests from Platform. */
182
- onDashboardArtifactsList?: (msg: DashboardArtifactsListRequest) => void;
188
+ onDashboardArtifactsList?: FrameHandler<DashboardArtifactsListRequest>;
183
189
  /** Optional callback for run re-run requests from Platform (dashboard action). */
184
- onRunRerun?: (msg: RunRerunRequest) => void;
190
+ onRunRerun?: FrameHandler<RunRerunRequest>;
185
191
  /** Optional callback for manual schedule trigger requests from Platform (dashboard action). */
186
- onManualSchedule?: (msg: ManualScheduleRequest) => void;
192
+ onManualSchedule?: FrameHandler<ManualScheduleRequest>;
187
193
  /** Optional callback for run cancel requests from Platform (dashboard action). */
188
- onRunCancel?: (msg: RunCancelRequest) => void;
194
+ onRunCancel?: FrameHandler<RunCancelRequest>;
189
195
  /** Optional callback for dashboard payload requests from Platform. */
190
- onDashboardPayload?: (msg: DashboardPayloadRequest) => void;
196
+ onDashboardPayload?: FrameHandler<DashboardPayloadRequest>;
191
197
  /** Optional callback for dashboard orchestration logs requests from Platform. */
192
- onDashboardOrchLogs?: (msg: DashboardOrchLogsRequest) => void;
198
+ onDashboardOrchLogs?: FrameHandler<DashboardOrchLogsRequest>;
193
199
  /** Optional callback for dashboard environment/held-run messages from Platform. */
194
- onDashboardEnvMessage?: (msg: DashboardPlatformToOrchMessage) => void;
200
+ onDashboardEnvMessage?: FrameHandler<DashboardPlatformToOrchMessage>;
195
201
  /**
196
202
  * Optional callback for Platform-first `kici run remote` control-plane relay
197
203
  * requests (upload-init, trigger, status, logs, cancel). The handler performs
198
204
  * the action and replies over the WS keyed by `requestId`.
199
205
  */
200
- onTestRelay?: (msg: TestRelayRequest) => void;
206
+ onTestRelay?: FrameHandler<TestRelayRequest>;
201
207
  /** Optional callback for dashboard diagnostics requests from Platform. */
202
- onDashboardDiagnostics?: (msg: DashboardDiagnosticsRequest) => void;
208
+ onDashboardDiagnostics?: FrameHandler<DashboardDiagnosticsRequest>;
203
209
  /** Optional callback for dashboard scaler capacity requests from Platform. */
204
- onDashboardScalerCapacity?: (msg: DashboardScalerCapacityRequest) => void;
210
+ onDashboardScalerCapacity?: FrameHandler<DashboardScalerCapacityRequest>;
205
211
  /** Optional callback for dashboard scaler agents requests from Platform. */
206
- onDashboardScalerAgents?: (msg: DashboardScalerAgentsRequest) => void;
212
+ onDashboardScalerAgents?: FrameHandler<DashboardScalerAgentsRequest>;
207
213
  /** Optional callback for fleet roster requests from Platform. */
208
- onFleetHosts?: (msg: DashboardFleetHostsRequest) => void;
214
+ onFleetHosts?: FrameHandler<DashboardFleetHostsRequest>;
209
215
  /** Optional callback for fleet host-detail requests from Platform. */
210
- onFleetHost?: (msg: DashboardFleetHostRequest) => void;
216
+ onFleetHost?: FrameHandler<DashboardFleetHostRequest>;
211
217
  /** Optional callback for fleet runsOnAll-preview requests from Platform. */
212
- onFleetPreview?: (msg: DashboardFleetPreviewRequest) => void;
218
+ onFleetPreview?: FrameHandler<DashboardFleetPreviewRequest>;
213
219
  /** Optional callback for fleet workflows-for-host requests from Platform. */
214
- onFleetWorkflowsForHost?: (msg: DashboardFleetWorkflowsForHostRequest) => void;
220
+ onFleetWorkflowsForHost?: FrameHandler<DashboardFleetWorkflowsForHostRequest>;
215
221
  /** Optional callback for trust policy updates pushed from Platform. */
216
- onTrustPolicyUpdate?: (msg: TrustPolicyUpdate) => void;
222
+ onTrustPolicyUpdate?: FrameHandler<TrustPolicyUpdate>;
217
223
  /** Optional callback for stale check run cleanup requests from Platform. */
218
- onStaleCheckrunCleanup?: (msg: StaleCheckrunCleanup) => void;
224
+ onStaleCheckrunCleanup?: FrameHandler<StaleCheckrunCleanup>;
219
225
  /** Optional callback for join requests relayed via Platform. */
220
226
  onJoinRequest?: (msg: JoinRequest) => Promise<JoinResponse>;
221
227
  /** Custom orchestrator capabilities to merge with ORCH_CAPABILITIES in auth.request. */
@@ -540,6 +546,12 @@ export declare class PlatformClient {
540
546
  * not a recognisable dashboard request (let the caller log a warning).
541
547
  */
542
548
  private respondToInvalidDashboardRequest;
549
+ /**
550
+ * Run the handler for one Platform frame. Nothing awaits a frame, so a throw
551
+ * or a rejection is logged with the frame's type and request id and the
552
+ * connection carries on; left unhandled it would stop the orchestrator.
553
+ */
554
+ private runFrameHandler;
543
555
  /**
544
556
  * Dispatch a parsed platform message to the appropriate per-area
545
557
  * handler. Each `case` either inlines a tiny dispatch (for one-line
@@ -6,7 +6,7 @@ import type { WebSocketServer } from 'ws';
6
6
  * here so it is unit-testable independently of the heavy `createApp` dependency
7
7
  * graph.
8
8
  *
9
- * The (`permessage-deflate` compression bombs) invariant lives here: any
9
+ * The `permessage-deflate` compression-bomb invariant lives here: any
10
10
  * field added to defend against compression-bomb DoS — `maxPayload`,
11
11
  * `serverNoContextTakeover`, etc. — MUST be set inside this helper so the
12
12
  * neighbouring test file can assert it.
@@ -118,7 +118,7 @@ export interface TestRunLogsPayload {
118
118
  }
119
119
  /**
120
120
  * Return the next chunk of a run's logs from a monotonic line-offset cursor
121
- * (spec §13a). The orchestrator concatenates every log line in a deterministic
121
+ * The orchestrator concatenates every log line in a deterministic
122
122
  * `(jobName ASC, stepIndex ASC, lineIndex ASC)` order; `cursor` is the count of
123
123
  * lines already delivered. `done` is true only when the run is terminal AND the
124
124
  * cursor has reached the end (the final tail-draining poll). A poll mid-step
@@ -1,7 +1,7 @@
1
1
  {
2
- "version": "0.11.0",
2
+ "version": "0.13.0",
3
3
  "images": {
4
- "kici-agent": "sha256:3a7a387964836acf6f89bdd31a4ee285383349926db21ef90d43905a5bce1dd4",
5
- "kici-orchestrator": "sha256:8ee2909b622f813348506589c25b8b7d4ef2333604e1bc919e15016304822a27"
4
+ "kici-agent": "sha256:301bc573b855f582a43aaf1813ed6d5fc1b1f72ecbbe6e98d7176227bb4f7d81",
5
+ "kici-orchestrator": "sha256:6dc6f9aa82b30b6f194873816cebc37a8d8eb4600ed00ce72f3ea8dbdfa91501"
6
6
  }
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kici-dev/orchestrator",
3
- "version": "0.11.0",
3
+ "version": "0.13.0",
4
4
  "description": "Customer-deployable orchestrator for the KiCI CI/CD stack. Receives webhook events (direct or via Platform relay), matches triggers against the lock file, and dispatches jobs to connected agents.",
5
5
  "keywords": [
6
6
  "ci",
@@ -24,7 +24,7 @@
24
24
  },
25
25
  "license": "AGPL-3.0-only",
26
26
  "engines": {
27
- "node": ">=24"
27
+ "node": ">=24.5.0"
28
28
  },
29
29
  "type": "module",
30
30
  "files": [
@@ -90,8 +90,8 @@
90
90
  "ws": "^8.21.3",
91
91
  "yaml": "^2.9.1",
92
92
  "zod": "^4.6.5",
93
- "@kici-dev/engine": "0.11.0",
94
- "@kici-dev/shared": "0.11.0"
93
+ "@kici-dev/shared": "0.13.0",
94
+ "@kici-dev/engine": "0.13.0"
95
95
  },
96
96
  "kici": {
97
97
  "metrics": {
@@ -106,7 +106,7 @@
106
106
  "@types/dockerode": "^4.0.1",
107
107
  "@types/ws": "^8.18.1",
108
108
  "kysely-ctl": "^0.21.0",
109
- "@kici-dev/agent": "0.11.0"
109
+ "@kici-dev/agent": "0.13.0"
110
110
  },
111
111
  "scripts": {
112
112
  "build": "node ../../scripts/build-service.mjs && tsc --emitDeclarationOnly",