@kici-dev/orchestrator 0.1.17 → 0.1.18

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 (42) hide show
  1. package/dist/agent/dispatcher.d.ts +9 -0
  2. package/dist/agent/host-roster-reaper.d.ts +42 -0
  3. package/dist/agent/host-roster.d.ts +110 -0
  4. package/dist/agent/registry.d.ts +65 -2
  5. package/dist/app.d.ts +3 -0
  6. package/dist/cli/commands/host.d.ts +13 -0
  7. package/dist/cli/commands/shared/versioned-upgrade.d.ts +23 -0
  8. package/dist/cli/service/compose.d.ts +2 -1
  9. package/dist/cli/service/index.d.ts +2 -2
  10. package/dist/cli/service/instance/manifest.d.ts +12 -0
  11. package/dist/cli/service/instance/resolve.d.ts +12 -2
  12. package/dist/cli/service/launchd.d.ts +4 -1
  13. package/dist/cli/service/platform-detect.d.ts +5 -0
  14. package/dist/cli/service/systemd.d.ts +2 -1
  15. package/dist/cli/service/types.d.ts +37 -0
  16. package/dist/cli/service/windows.d.ts +2 -1
  17. package/dist/cli.js +794 -201
  18. package/dist/cluster/coordinator.d.ts +5 -1
  19. package/dist/config/schema.d.ts +4 -0
  20. package/dist/config/types.d.ts +9 -0
  21. package/dist/config.d.ts +6 -0
  22. package/dist/db/migrations/039_host_roster.d.ts +19 -0
  23. package/dist/db/migrations/040_runsonall_pin.d.ts +4 -0
  24. package/dist/db/migrations/041_wave_gated.d.ts +4 -0
  25. package/dist/db/migrations/042_dispatch_queue_patterns.d.ts +4 -0
  26. package/dist/db/types.d.ts +61 -0
  27. package/dist/diagnostics/fleet-collector.d.ts +1 -1
  28. package/dist/environments/held-runs.d.ts +9 -0
  29. package/dist/lockfile-redos-guard.d.ts +19 -0
  30. package/dist/metrics/prometheus.d.ts +13 -0
  31. package/dist/metrics/scheduled-jobs.d.ts +2 -2
  32. package/dist/orchestrator-core.d.ts +46 -1
  33. package/dist/pipeline/dispatch-matched-workflow.d.ts +42 -1
  34. package/dist/pipeline/processor.d.ts +25 -0
  35. package/dist/pipeline/wave-scheduler.d.ts +60 -0
  36. package/dist/queue/job-queue.d.ts +61 -2
  37. package/dist/reporting/execution-tracker.d.ts +28 -0
  38. package/dist/server.js +52720 -51280
  39. package/dist/standalone.js +1908 -488
  40. package/installer-image-digests.json +3 -3
  41. package/package.json +22 -22
  42. package/sbom.spdx.json +3227 -6682
@@ -1,5 +1,5 @@
1
1
  import { type Kysely } from 'kysely';
2
- import type { ResourceRequest } from '@kici-dev/engine';
2
+ import { type LabelMatcher, type ResourceRequest } from '@kici-dev/engine';
3
3
  import type { Database } from '../db/types.js';
4
4
  /** Info about an expired dispatch_queue entry, returned by markExpired(). */
5
5
  export interface ExpiredJobInfo {
@@ -92,12 +92,26 @@ export interface QueuedJobInput {
92
92
  requestId?: string;
93
93
  /** Labels that the dispatched agent must NOT have. */
94
94
  excludeLabels?: string[];
95
+ /** Regex matchers the agent's labels must satisfy (JS post-filter on the exact @> prefilter). */
96
+ runsOnPatterns?: LabelMatcher[];
97
+ /** Regex matchers that disqualify an agent (JS post-filter). */
98
+ excludePatterns?: LabelMatcher[];
95
99
  /**
96
100
  * Per-job resource request and limit (K8s-style). Drives scaler cap accounting
97
101
  * (`requests`) and kernel-side enforcement on the spawned agent (`limits`).
98
102
  * Stored inside `jobConfig` JSON; this typed field is a convenience for callers.
99
103
  */
100
104
  resources?: ResourceRequest;
105
+ /**
106
+ * For a runsOnAll host-fanout child: the agent this job is pinned to. The
107
+ * dispatcher routes it only to that agent; the drain never hands it to another.
108
+ */
109
+ pinnedAgentId?: string;
110
+ /**
111
+ * For a pinned child: which orchestrator instance owns the pinned agent's live
112
+ * WS (null = not currently connected). Used by the cross-cluster pin reroute.
113
+ */
114
+ connectedInstanceId?: string | null;
101
115
  }
102
116
  /**
103
117
  * Full queued job as stored in the database.
@@ -135,11 +149,17 @@ export interface QueuedJob {
135
149
  requestId?: string;
136
150
  /** Labels that the dispatched agent must NOT have. */
137
151
  excludeLabels: string[];
152
+ /** Regex matchers the agent's labels must satisfy (JS post-filter on the exact @> prefilter). */
153
+ runsOnPatterns: LabelMatcher[];
154
+ /** Regex matchers that disqualify an agent (JS post-filter). */
155
+ excludePatterns: LabelMatcher[];
138
156
  /**
139
157
  * Per-job resource request and limit (K8s-style). Materialized from `jobConfig.resources`
140
158
  * by `rowToQueuedJob` so callers can read it without re-parsing the JSON column.
141
159
  */
142
160
  resources?: ResourceRequest;
161
+ /** For a runsOnAll host-fanout child: the agent this job is pinned to. */
162
+ pinnedAgentId?: string;
143
163
  }
144
164
  /**
145
165
  * DB-backed FIFO job dispatch queue using Kysely (PostgreSQL only).
@@ -188,7 +208,46 @@ export declare class JobQueue {
188
208
  * (empty for static / non-scaler agents).
189
209
  * @returns The matching job, or null if none found.
190
210
  */
191
- dequeueForLabels(agentLabels: string[], agentMandatoryLabels?: string[]): Promise<QueuedJob | null>;
211
+ dequeueForLabels(agentLabels: string[], agentMandatoryLabels?: string[], agentId?: string): Promise<QueuedJob | null>;
212
+ /**
213
+ * Build the shared drain WHERE chain (status / expiry / exact-label @> /
214
+ * exclude-label / pin / mandatory-label gate) common to both drain passes.
215
+ * The pattern columns are NOT filtered here — each pass adds its own
216
+ * pattern-free / pattern-bearing guard on top.
217
+ */
218
+ private drainBaseQuery;
219
+ /**
220
+ * Fast path: claim the oldest pending pattern-free row. The
221
+ * `runs_on_patterns = '[]' AND exclude_patterns = '[]'` guard restricts this
222
+ * pass to rows that need no JS post-filter, so the single-row atomic claim
223
+ * (FOR UPDATE SKIP LOCKED) keeps the original hot-path semantics intact.
224
+ */
225
+ private claimPatternFree;
226
+ /**
227
+ * Pattern path: load a small batch of pattern-bearing candidate rows, apply
228
+ * the JS regex post-filter (matcherSatisfiedBy), and atomically claim the
229
+ * first match by id with a conditional `status = Pending` guard. The claim is
230
+ * a conditional UPDATE rather than relying on the SELECT lock alone because
231
+ * the JS filter runs after the per-statement lock window has closed, so two
232
+ * agents could both pass the filter for the same row; the `where status =
233
+ * Pending` makes exactly one of them win. The claim transitions the row to
234
+ * Dispatched, matching the value the caller-side markDispatched would set
235
+ * (which then re-sets it idempotently).
236
+ */
237
+ private claimWithPatterns;
238
+ /**
239
+ * Atomically claim the oldest pending job pinned to a specific agent. Used by
240
+ * the eager pin drain when the pinned agent (re)registers or frees a slot —
241
+ * the host-fanout analog of `dispatchBoundJob`'s eager path. Ignores the exact
242
+ * label gate: the pin was resolved against the roster at materialize time.
243
+ *
244
+ * Still applies the JS regex post-filter (`jobPatternsSatisfiedBy`) when
245
+ * `agentLabels` is supplied, mirroring `dequeueById`: a pinned child whose
246
+ * `runsOn`/`exclude` patterns no longer match the agent's current labels must
247
+ * not be claimed. The single matching authority is the engine's
248
+ * `matcherSatisfiedBy` (never a Postgres `~`).
249
+ */
250
+ dequeueByPinnedAgent(agentId: string, agentLabels?: string[]): Promise<QueuedJob | null>;
192
251
  /**
193
252
  * Atomically claim a specific pending job by ID, validating it still
194
253
  * matches the agent's labels and isn't expired.
@@ -202,6 +202,12 @@ export declare class ExecutionTracker {
202
202
  jobName: string;
203
203
  matrixValues?: Record<string, unknown>;
204
204
  runsOnLabels?: string[];
205
+ baseJobName?: string;
206
+ variantKind?: string;
207
+ variantLabel?: string;
208
+ waveGated?: boolean;
209
+ waveMaxParallel?: number;
210
+ waveFailFast?: boolean;
205
211
  }>, routingKey?: string,
206
212
  /** Secret context names dispatched with jobs (for context-disable job lookup). */
207
213
  dispatchedContexts?: string[],
@@ -237,6 +243,13 @@ export declare class ExecutionTracker {
237
243
  * which peer owns the downstream dispatch.
238
244
  */
239
245
  findSyntheticJobId(runId: string, jobName: string): Promise<string | undefined>;
246
+ /**
247
+ * Find the synthetic deferred-eval placeholder job ID for a result-aware
248
+ * dynamic generator's eval job. Mirrors {@link findSyntheticJobId} but keys on
249
+ * the `dynamic-eval-pending-<evalJobName>-` prefix that registerDeferredEvalJob
250
+ * uses, so dispatchEvalJob can swap it for the real eval job id.
251
+ */
252
+ findDynamicEvalSyntheticId(runId: string, evalJobName: string): Promise<string | undefined>;
240
253
  /**
241
254
  * Run `fn` while holding a per-run lock, serializing the run-mutating methods
242
255
  * (`onJobStatus`, `addJobsToRun`) so a status reply cannot interleave with the
@@ -258,6 +271,9 @@ export declare class ExecutionTracker {
258
271
  jobName: string;
259
272
  matrixValues?: Record<string, unknown>;
260
273
  runsOnLabels?: string[];
274
+ baseJobName?: string;
275
+ variantKind?: string;
276
+ variantLabel?: string;
261
277
  }>, dispatchedContexts?: string[],
262
278
  /** Synthetic job ID to replace (e.g. needs-pending-deploy-{uuid}). */
263
279
  replaceSyntheticId?: string): Promise<void>;
@@ -339,6 +355,18 @@ export declare class ExecutionTracker {
339
355
  * so recursive skip propagation terminates naturally.
340
356
  */
341
357
  private runSchedulerHook;
358
+ /**
359
+ * Rolling-wave hook: fires beside the needs-scheduler when a fan-out child of
360
+ * a bounded wave (`maxParallel` set) reaches terminal. Reads the completed
361
+ * child's row to recover the base + wave policy, asks {@link evaluateWave}
362
+ * what to do, then performs it:
363
+ *
364
+ * - `release`: clear the next held sibling's `wave_gated` flag and fire the
365
+ * onJobReady callback (the existing ready→dispatch path).
366
+ * - `skip-remaining`: mark every still-held sibling `skipped` (failFast).
367
+ * - `noop`: nothing — a later terminal will free the next slot.
368
+ */
369
+ private runWaveSchedulerHook;
342
370
  /**
343
371
  * Phase 9: stuck-jobs invariant check ( Layer 3).
344
372
  * Before declaring a run complete, verify no stuck jobs exist. If any are