@kici-dev/engine 0.1.27 → 0.3.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 (148) hide show
  1. package/dist/approval/types.d.ts +8 -1
  2. package/dist/approval/types.js +8 -1
  3. package/dist/artifacts/name.d.ts +60 -0
  4. package/dist/artifacts/name.js +71 -0
  5. package/dist/audit/access-log-policy.d.ts +1 -1
  6. package/dist/audit/access-log-policy.js +8 -0
  7. package/dist/audit/activity.d.ts +12 -12
  8. package/dist/audit/retention-policy.js +16 -0
  9. package/dist/billing/plan-type.d.ts +53 -0
  10. package/dist/billing/plan-type.js +70 -0
  11. package/dist/bundler/rolldown-config.d.ts +3 -3
  12. package/dist/check-mode.d.ts +1 -1
  13. package/dist/context/concurrency-strategy.d.ts +34 -0
  14. package/dist/context/concurrency-strategy.js +35 -0
  15. package/dist/context/held-run-job-id.d.ts +45 -0
  16. package/dist/context/held-run-job-id.js +56 -0
  17. package/dist/context/held-run-status.d.ts +33 -0
  18. package/dist/context/held-run-status.js +37 -0
  19. package/dist/context/hold-expiry.d.ts +20 -0
  20. package/dist/context/hold-expiry.js +25 -0
  21. package/dist/context/hold-reason.d.ts +33 -0
  22. package/dist/context/hold-reason.js +23 -0
  23. package/dist/context/hold-type.d.ts +40 -0
  24. package/dist/context/hold-type.js +61 -0
  25. package/dist/context/index.d.ts +9 -1
  26. package/dist/context/index.js +9 -2
  27. package/dist/context/multi-context.d.ts +3 -3
  28. package/dist/context/scope-name.d.ts +29 -0
  29. package/dist/context/scope-name.js +49 -0
  30. package/dist/context/scope-resolver.d.ts +33 -0
  31. package/dist/context/scope-resolver.js +45 -15
  32. package/dist/context/types.d.ts +8 -5
  33. package/dist/dev-ops/operations.d.ts +8 -0
  34. package/dist/dev-ops/operations.js +36 -19
  35. package/dist/diagnostics/infra-alert.d.ts +71 -0
  36. package/dist/diagnostics/infra-alert.js +60 -0
  37. package/dist/env/environment-allowlist.d.ts +4 -4
  38. package/dist/fanout/materialize.d.ts +16 -0
  39. package/dist/fanout/materialize.js +32 -3
  40. package/dist/index.d.ts +15 -6
  41. package/dist/index.js +34 -19
  42. package/dist/inputs/descriptor.d.ts +9 -9
  43. package/dist/inventory.d.ts +4 -4
  44. package/dist/labels.d.ts +82 -2
  45. package/dist/labels.js +119 -1
  46. package/dist/matrix/expand.d.ts +49 -2
  47. package/dist/matrix/expand.js +102 -13
  48. package/dist/matrix/format.d.ts +6 -1
  49. package/dist/matrix/format.js +6 -1
  50. package/dist/mcp/held-run-resolve.d.ts +7 -10
  51. package/dist/mcp/held-run-resolve.js +33 -7
  52. package/dist/metrics/catalog-policy.js +4 -4
  53. package/dist/metrics/metric-catalog.generated.d.ts +959 -739
  54. package/dist/metrics/metric-catalog.generated.js +284 -20
  55. package/dist/metrics/metric-kind-compat.d.ts +26 -0
  56. package/dist/metrics/metric-kind-compat.js +33 -0
  57. package/dist/protocol/analytics-events.d.ts +6 -6
  58. package/dist/protocol/dashboard-api-errors.d.ts +1 -0
  59. package/dist/protocol/dashboard-api-errors.js +5 -1
  60. package/dist/protocol/dashboard-write-operations.d.ts +143 -86
  61. package/dist/protocol/dashboard-write-operations.js +91 -17
  62. package/dist/protocol/messages/access-log.d.ts +437 -392
  63. package/dist/protocol/messages/access-log.js +11 -2
  64. package/dist/protocol/messages/actor.d.ts +2 -2
  65. package/dist/protocol/messages/agent-dev-ops.d.ts +4 -2
  66. package/dist/protocol/messages/agent-dev-ops.js +2 -5
  67. package/dist/protocol/messages/agent-run-result.d.ts +72 -62
  68. package/dist/protocol/messages/auth.d.ts +35 -23
  69. package/dist/protocol/messages/browser.d.ts +81 -5
  70. package/dist/protocol/messages/browser.js +53 -2
  71. package/dist/protocol/messages/capabilities.d.ts +106 -31
  72. package/dist/protocol/messages/capabilities.js +94 -10
  73. package/dist/protocol/messages/common.d.ts +45 -2
  74. package/dist/protocol/messages/common.js +64 -3
  75. package/dist/protocol/messages/dashboard-sealed-write.d.ts +52 -0
  76. package/dist/protocol/messages/dashboard-sealed-write.js +57 -0
  77. package/dist/protocol/messages/dashboard.d.ts +1026 -498
  78. package/dist/protocol/messages/dashboard.js +208 -31
  79. package/dist/protocol/messages/deployment-identity.d.ts +37 -10
  80. package/dist/protocol/messages/deployment-identity.js +30 -3
  81. package/dist/protocol/messages/event-log.d.ts +5 -5
  82. package/dist/protocol/messages/execution-status.d.ts +189 -53
  83. package/dist/protocol/messages/execution-status.js +108 -40
  84. package/dist/protocol/messages/heartbeat-health.d.ts +83 -0
  85. package/dist/protocol/messages/heartbeat-health.js +87 -0
  86. package/dist/protocol/messages/log-stream.d.ts +18 -0
  87. package/dist/protocol/messages/log-stream.js +19 -0
  88. package/dist/protocol/messages/oidc-mint.d.ts +7 -0
  89. package/dist/protocol/messages/oidc-mint.js +7 -0
  90. package/dist/protocol/messages/orchestrator-agent.d.ts +264 -67
  91. package/dist/protocol/messages/orchestrator-agent.js +170 -5
  92. package/dist/protocol/messages/pat-kind.d.ts +1 -1
  93. package/dist/protocol/messages/peer.d.ts +122 -58
  94. package/dist/protocol/messages/peer.js +37 -2
  95. package/dist/protocol/messages/platform-orchestrator.d.ts +561 -217
  96. package/dist/protocol/messages/platform-orchestrator.js +131 -21
  97. package/dist/protocol/messages/run-events.d.ts +5 -5
  98. package/dist/protocol/messages/scaler-event.d.ts +3 -3
  99. package/dist/protocol/messages/source-registration.d.ts +56 -13
  100. package/dist/protocol/messages/source-registration.js +49 -6
  101. package/dist/protocol/source-origin.d.ts +1 -1
  102. package/dist/provenance/attestation-origin.d.ts +1 -1
  103. package/dist/provenance/schema.d.ts +11 -11
  104. package/dist/provenance/verify.js +2 -1
  105. package/dist/provider/changed-files-fetcher.d.ts +21 -2
  106. package/dist/provider/check-run-conclusion.d.ts +2 -2
  107. package/dist/provider/check-status-poster.d.ts +23 -0
  108. package/dist/provider/index.d.ts +2 -2
  109. package/dist/registration/registerable-trigger-type.d.ts +14 -13
  110. package/dist/registration/registerable-trigger-type.js +1 -0
  111. package/dist/sandbox/capabilities.d.ts +6 -0
  112. package/dist/sandbox/capabilities.js +57 -0
  113. package/dist/scaler/scaler-backend-type.d.ts +1 -1
  114. package/dist/status/presentation.d.ts +89 -0
  115. package/dist/status/presentation.js +163 -0
  116. package/dist/trigger/compiled-matchers.d.ts +13 -0
  117. package/dist/trigger/compiled-matchers.js +44 -0
  118. package/dist/trigger/event-buckets.d.ts +44 -0
  119. package/dist/trigger/event-buckets.js +93 -0
  120. package/dist/trigger/matcher.d.ts +7 -3
  121. package/dist/trigger/matcher.js +53 -15
  122. package/dist/trigger/schedule-key.d.ts +14 -0
  123. package/dist/trigger/schedule-key.js +21 -0
  124. package/dist/trigger/trigger-event-type.d.ts +1 -1
  125. package/dist/trigger/trigger-event-type.js +2 -0
  126. package/dist/trigger/types.d.ts +173 -43
  127. package/dist/trigger/types.js +82 -25
  128. package/dist/webhook/event-types.d.ts +56 -0
  129. package/dist/webhook/event-types.js +59 -0
  130. package/dist/ws/ws-like.d.ts +13 -0
  131. package/package.json +12 -4
  132. package/sbom.spdx.json +10 -10
  133. package/dist/environment/host-match.d.ts +0 -25
  134. package/dist/environment/index.d.ts +0 -6
  135. package/dist/environment/multi-env.d.ts +0 -30
  136. package/dist/environment/scope-resolver.d.ts +0 -46
  137. package/dist/environment/scope-template.d.ts +0 -18
  138. package/dist/environment/types.d.ts +0 -119
  139. package/dist/package-manager.d.ts +0 -20
  140. package/dist/protocol/messages/observe.d.ts +0 -76
  141. package/dist/protocol/messages/saas-orchestrator.d.ts +0 -2179
  142. package/dist/protocol/messages/test-run.d.ts +0 -59
  143. package/dist/state-machine/index.d.ts +0 -2
  144. package/dist/state-machine/index.js +0 -3
  145. package/dist/state-machine/machine.d.ts +0 -34
  146. package/dist/state-machine/machine.js +0 -103
  147. package/dist/state-machine/types.d.ts +0 -34
  148. package/dist/state-machine/types.js +0 -15
@@ -1,7 +1,7 @@
1
1
  import "../rolldown-runtime-ClRpJifh.js";
2
2
  import { createTraceEntry, createWorkflowDecision } from "./decision-trace.js";
3
+ import { getCompiledRegex, getGlobMatcher } from "./compiled-matchers.js";
3
4
  import { matchJsonPath, matchJsonPathNot } from "./jsonpath-matcher.js";
4
- import picomatch from "picomatch";
5
5
  //#region src/trigger/matcher.ts
6
6
  /**
7
7
  * Trigger matching engine for evaluating workflow triggers against webhook events.
@@ -34,8 +34,8 @@ function splitBranchPatterns(patterns) {
34
34
  * Match a branch pattern against a branch name.
35
35
  */
36
36
  function matchBranchPattern(pattern, branch) {
37
- if (pattern.type === "glob") return picomatch.isMatch(branch, pattern.pattern);
38
- else return new RegExp(pattern.pattern, pattern.flags).test(branch);
37
+ if (pattern.type === "glob") return getGlobMatcher(pattern.pattern)(branch);
38
+ else return getCompiledRegex(pattern.pattern, pattern.flags).test(branch);
39
39
  }
40
40
  /**
41
41
  * Match any of the branch patterns.
@@ -50,17 +50,18 @@ function matchAnyBranch(patterns, branch) {
50
50
  * Patterns prefixed with ! are exclusions. Remaining patterns are inclusions.
51
51
  * An all-negation array has implicit match-all semantics for non-excluded files.
52
52
  */
53
- function matchPathPatterns(paths, changedFiles) {
53
+ function matchPathPatterns(paths, changedFiles, status) {
54
54
  if (paths.length === 0) return true;
55
+ if (status === "unavailable") return true;
55
56
  if (changedFiles.length === 0) return false;
56
57
  const { include, exclude } = splitStringPatterns(paths);
57
58
  let relevantFiles = changedFiles;
58
59
  if (exclude.length > 0) {
59
- relevantFiles = changedFiles.filter((file) => !exclude.some((pattern) => picomatch.isMatch(file, pattern)));
60
+ relevantFiles = changedFiles.filter((file) => !exclude.some((pattern) => getGlobMatcher(pattern)(file)));
60
61
  if (relevantFiles.length === 0) return false;
61
62
  }
62
63
  if (include.length === 0) return true;
63
- return relevantFiles.some((file) => include.some((pattern) => picomatch.isMatch(file, pattern)));
64
+ return relevantFiles.some((file) => include.some((pattern) => getGlobMatcher(pattern)(file)));
64
65
  }
65
66
  /**
66
67
  * Match repo patterns against a source repository identifier.
@@ -127,8 +128,8 @@ function matchPrTrigger(trigger, event, traces) {
127
128
  if (trigger.paths.length > 0) {
128
129
  const changedFiles = event.changedFiles ?? [];
129
130
  const { include, exclude } = splitStringPatterns(trigger.paths);
130
- const matches = matchPathPatterns(trigger.paths, changedFiles);
131
- traces.push(createTraceEntry("paths", `include: [${include.join(", ")}] exclude: [${exclude.join(", ")}]`, `[${changedFiles.join(", ")}]`, matches));
131
+ const matches = matchPathPatterns(trigger.paths, changedFiles, event.changedFilesStatus);
132
+ traces.push(createTraceEntry("paths", `include: [${include.join(", ")}] exclude: [${exclude.join(", ")}]`, event.changedFilesStatus === "unavailable" ? "[unavailable — matched conservatively]" : `[${changedFiles.join(", ")}]`, matches));
132
133
  if (!matches) return false;
133
134
  }
134
135
  if (!evaluateRepoFilter(trigger, event, traces)) return false;
@@ -151,8 +152,8 @@ function matchPushTrigger(trigger, event, traces) {
151
152
  if (trigger.paths.length > 0) {
152
153
  const changedFiles = event.changedFiles ?? [];
153
154
  const { include, exclude } = splitStringPatterns(trigger.paths);
154
- const matches = matchPathPatterns(trigger.paths, changedFiles);
155
- traces.push(createTraceEntry("paths", `include: [${include.join(", ")}] exclude: [${exclude.join(", ")}]`, `[${changedFiles.join(", ")}]`, matches));
155
+ const matches = matchPathPatterns(trigger.paths, changedFiles, event.changedFilesStatus);
156
+ traces.push(createTraceEntry("paths", `include: [${include.join(", ")}] exclude: [${exclude.join(", ")}]`, event.changedFilesStatus === "unavailable" ? "[unavailable — matched conservatively]" : `[${changedFiles.join(", ")}]`, matches));
156
157
  if (!matches) return false;
157
158
  }
158
159
  if (!evaluateRepoFilter(trigger, event, traces)) return false;
@@ -208,11 +209,11 @@ function matchCommentTrigger(trigger, event, traces) {
208
209
  if (trigger.bodyMatch) {
209
210
  const body = event.payload.comment?.body ?? "";
210
211
  if (trigger.bodyMatch.type === "glob") {
211
- const matches = picomatch.isMatch(body, trigger.bodyMatch.pattern);
212
+ const matches = getGlobMatcher(trigger.bodyMatch.pattern)(body);
212
213
  traces.push(createTraceEntry("bodyMatch (glob)", trigger.bodyMatch.pattern, body, matches));
213
214
  if (!matches) return false;
214
215
  } else {
215
- const matches = new RegExp(trigger.bodyMatch.pattern, trigger.bodyMatch.flags).test(body);
216
+ const matches = getCompiledRegex(trigger.bodyMatch.pattern, trigger.bodyMatch.flags).test(body);
216
217
  traces.push(createTraceEntry("bodyMatch (regex)", trigger.bodyMatch.pattern, body, matches));
217
218
  if (!matches) return false;
218
219
  }
@@ -354,7 +355,7 @@ function matchDeleteTrigger(trigger, event, traces) {
354
355
  }
355
356
  /**
356
357
  * Match a status trigger against a simulated event.
357
- * Checks context via picomatch and state filter.
358
+ * Checks context via glob matching and state filter.
358
359
  */
359
360
  function matchStatusTrigger(trigger, event, traces) {
360
361
  if (event.type !== "status") {
@@ -364,7 +365,7 @@ function matchStatusTrigger(trigger, event, traces) {
364
365
  traces.push(createTraceEntry("event type", "status", event.type, true));
365
366
  if (trigger.contexts.length > 0) {
366
367
  const context = event.payload.context ?? "";
367
- const matches = trigger.contexts.some((pattern) => picomatch.isMatch(context, pattern));
368
+ const matches = trigger.contexts.some((pattern) => getGlobMatcher(pattern)(context));
368
369
  traces.push(createTraceEntry("context", trigger.contexts.join("|"), context, matches));
369
370
  if (!matches) return false;
370
371
  }
@@ -540,6 +541,42 @@ function matchWorkflowCompleteTrigger(trigger, event, traces) {
540
541
  return true;
541
542
  }
542
543
  /**
544
+ * Match a workflows_failed_batch trigger against a simulated event.
545
+ *
546
+ * The trigger participates in two phases:
547
+ * - A failed `workflow_complete` event is an accumulation input — it matches
548
+ * (respecting optional name/source filters) so the orchestrator buffers the
549
+ * run into the batch window instead of dispatching now.
550
+ * - A synthetic `workflows_failed_batch` event is the dispatch trigger — the
551
+ * orchestrator emits it once per window and it matches to dispatch the
552
+ * subscribing workflow a single time.
553
+ */
554
+ function matchWorkflowsFailedBatchTrigger(trigger, event, traces) {
555
+ if (event.type === "workflow_complete") {
556
+ const status = event.payload.status ?? "";
557
+ const isFailed = status === "failed";
558
+ traces.push(createTraceEntry("status", "failed", status, isFailed));
559
+ if (!isFailed) return false;
560
+ } else if (event.type !== "workflows_failed_batch") {
561
+ traces.push(createTraceEntry("event type", "workflow_complete|workflows_failed_batch", event.type, false));
562
+ return false;
563
+ }
564
+ traces.push(createTraceEntry("event type", "workflows_failed_batch", event.type, true));
565
+ if (trigger.name) {
566
+ const workflowName = event.payload.workflowName ?? "";
567
+ const matches = workflowName === trigger.name;
568
+ traces.push(createTraceEntry("workflow name", trigger.name, workflowName, matches));
569
+ if (!matches) return false;
570
+ }
571
+ if (trigger.source) {
572
+ const sourceRepo = event.payload.sourceRepo ?? "";
573
+ const matches = sourceRepo === trigger.source;
574
+ traces.push(createTraceEntry("source", trigger.source, sourceRepo, matches));
575
+ if (!matches) return false;
576
+ }
577
+ return true;
578
+ }
579
+ /**
543
580
  * Match a job_complete trigger against a simulated event.
544
581
  * Checks workflow name, job name, status array, and source filter.
545
582
  */
@@ -669,6 +706,7 @@ function matchTrigger(trigger, event, traces) {
669
706
  case "webhook": return matchWebhookTrigger(trigger, event, traces);
670
707
  case "kici_event": return matchKiciEventTrigger(trigger, event, traces);
671
708
  case "workflow_complete": return matchWorkflowCompleteTrigger(trigger, event, traces);
709
+ case "workflows_failed_batch": return matchWorkflowsFailedBatchTrigger(trigger, event, traces);
672
710
  case "job_complete": return matchJobCompleteTrigger(trigger, event, traces);
673
711
  case "generic_webhook": return matchGenericWebhookTrigger(trigger, event, traces);
674
712
  case "schedule": return matchScheduleTrigger(trigger, event, traces);
@@ -699,6 +737,6 @@ function matchAllWorkflows(workflows, event) {
699
737
  return workflows.map((w) => matchWorkflowTriggers(w, event));
700
738
  }
701
739
  //#endregion
702
- export { matchAllWorkflows, matchBranchPattern, matchPathPatterns, matchRepoPatterns, matchWorkflowTriggers };
740
+ export { matchAllWorkflows, matchBranchPattern, matchPathPatterns, matchRepoPatterns, matchTrigger, matchWorkflowTriggers };
703
741
 
704
742
  //# sourceMappingURL=matcher.js.map
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Stable identity of a schedule trigger for last-fired bookkeeping.
3
+ *
4
+ * Two schedule triggers are "the same schedule" iff they share a cron
5
+ * expression AND timezone — they fire at the same instants and dispatch
6
+ * identically (the trigger matcher keys on cronExpression). The orchestrator's
7
+ * `cron_last_fired` table is keyed by (registration_id, this key) so every
8
+ * distinct schedule of a workflow is fired and tracked independently.
9
+ *
10
+ * The format is intentionally trivial (newline-joined) so migration SQL can
11
+ * reproduce it byte-for-byte: `cronExpression || E'\n' || timezone`.
12
+ */
13
+ export declare function scheduleTriggerKey(cronExpression: string, timezone: string): string;
14
+ //# sourceMappingURL=schedule-key.d.ts.map
@@ -0,0 +1,21 @@
1
+ import "../rolldown-runtime-ClRpJifh.js";
2
+ //#region src/trigger/schedule-key.ts
3
+ /**
4
+ * Stable identity of a schedule trigger for last-fired bookkeeping.
5
+ *
6
+ * Two schedule triggers are "the same schedule" iff they share a cron
7
+ * expression AND timezone — they fire at the same instants and dispatch
8
+ * identically (the trigger matcher keys on cronExpression). The orchestrator's
9
+ * `cron_last_fired` table is keyed by (registration_id, this key) so every
10
+ * distinct schedule of a workflow is fired and tracked independently.
11
+ *
12
+ * The format is intentionally trivial (newline-joined) so migration SQL can
13
+ * reproduce it byte-for-byte: `cronExpression || E'\n' || timezone`.
14
+ */
15
+ function scheduleTriggerKey(cronExpression, timezone) {
16
+ return `${cronExpression}\n${timezone}`;
17
+ }
18
+ //#endregion
19
+ export { scheduleTriggerKey };
20
+
21
+ //# sourceMappingURL=schedule-key.js.map
@@ -6,7 +6,7 @@
6
6
  * compile-time failures in any exhaustive Record<TriggerEventType, ...>
7
7
  * (e.g., the dashboard icon map).
8
8
  */
9
- export declare const TRIGGER_EVENT_TYPES: readonly ["pull_request", "push", "tag", "comment", "review", "review_comment", "release", "dispatch", "create", "delete", "status", "workflow_run", "fork", "star", "watch", "webhook", "kici_event", "workflow_complete", "job_complete", "generic_webhook", "schedule", "lifecycle", "rerun", "manual_schedule"];
9
+ export declare const TRIGGER_EVENT_TYPES: readonly ['pull_request', 'push', 'tag', 'comment', 'review', 'review_comment', 'release', 'dispatch', 'create', 'delete', 'status', 'workflow_run', 'fork', 'star', 'watch', 'webhook', 'kici_event', 'workflow_complete', 'workflows_failed_batch', 'job_complete', 'generic_webhook', 'schedule', 'lifecycle', 'rerun', 'manual_schedule'];
10
10
  export type TriggerEventType = (typeof TRIGGER_EVENT_TYPES)[number];
11
11
  export declare const TRIGGER_EVENT_META: Record<TriggerEventType, {
12
12
  label: string;
@@ -27,6 +27,7 @@ const TRIGGER_EVENT_TYPES = [
27
27
  "webhook",
28
28
  "kici_event",
29
29
  "workflow_complete",
30
+ "workflows_failed_batch",
30
31
  "job_complete",
31
32
  "generic_webhook",
32
33
  "schedule",
@@ -53,6 +54,7 @@ const TRIGGER_EVENT_META = {
53
54
  webhook: { label: "Webhook" },
54
55
  kici_event: { label: "KiCI event" },
55
56
  workflow_complete: { label: "Workflow complete" },
57
+ workflows_failed_batch: { label: "Workflows failed batch" },
56
58
  job_complete: { label: "Job complete" },
57
59
  generic_webhook: { label: "Generic webhook" },
58
60
  schedule: { label: "Schedule" },
@@ -1,26 +1,34 @@
1
1
  /**
2
2
  * Lock file types for the trigger matching engine.
3
3
  * Single source of truth -- replaces local copies in @kici-dev/compiler and @kici-dev/orchestrator.
4
- * Schema version 4: adds 4 internal event routing trigger types (kici_event, workflow_complete,
4
+ *
5
+ * Bump-history convention: every entry is annotated `additive` (older readers
6
+ * tolerate the new lock because unknown fields are ignored) or `BREAKING` (an
7
+ * older reader would mis-parse the lock). Every `BREAKING` bump moves
8
+ * `BREAKING_FLOOR` (below) to that version in the SAME commit.
9
+ *
10
+ * Schema version 4 (additive): adds 4 internal event routing trigger types (kici_event, workflow_complete,
5
11
  * job_complete, generic_webhook).
6
- * Schema version 6: replaces job-level contexts with environment/env/concurrencyGroup.
7
- * Schema version 8: adds runsOn polymorphic type (string | string[] | selector) and excludeLabels.
8
- * Schema version 9: adds repos/notRepos repo pattern fields to git-event triggers for global workflow matching.
9
- * Schema version 10: removes notRepos/notPaths fields, negative patterns use ! prefix in repos/paths arrays.
10
- * Schema version 11: adds LockInlineValue type for pure function inline evaluation.
11
- * Schema version 14: adds declarative cache specs to LockJob and LockStep.
12
- * Schema version 15: adds per-job init config(s) to LockJob.
13
- * Schema version 16: adds normalized approval config to LockWorkflow/LockJob/LockStep.
14
- * Schema version 17: widens LockJob.init to typed presets ('mise' / { mise }) and 'auto' detection.
15
- * Schema version 18: adds LockJob.runsOnAll host fan-out predicate + onUnreachable policy.
16
- * Schema version 19: adds LockJob.maxParallel/failFast fan-out concurrency (rolling waves).
17
- * Schema version 20: runsOn/runsOnAll/excludeLabels carry LabelMatcher (exact|regex) for glob+regex selectors.
18
- * Schema version 23: adds LockDispatchTrigger.inputs (typed dispatch inputs descriptors).
19
- * Schema version 24: adds LockJob.runsOnPick (deterministic single-host selection).
20
- * Schema version 25: adds LockStep.retry (step retry policy data subset; retryIf is execution-only).
21
- * Schema version 26: adds LockJob.includeUninitialized (runsOnAll fans out to declared-but-un-agented hosts, bringing up a temporary init-runner per fresh box).
22
- * Schema version 27: adds LockScheduleTrigger.inputs (defaults-only schedule dispatch inputs).
23
- * Schema version 30: renames job-level `environments` to `contexts`.
12
+ * Schema version 6 (BREAKING): replaces job-level contexts with environment/env/concurrencyGroup.
13
+ * Schema version 8 (additive): adds runsOn polymorphic type (string | string[] | selector) and excludeLabels.
14
+ * Schema version 9 (additive): adds repos/notRepos repo pattern fields to git-event triggers for global workflow matching.
15
+ * Schema version 10 (BREAKING): removes notRepos/notPaths fields, negative patterns use ! prefix in repos/paths arrays.
16
+ * Schema version 11 (additive): adds LockInlineValue type for pure function inline evaluation.
17
+ * Schema version 14 (additive): adds declarative cache specs to LockJob and LockStep.
18
+ * Schema version 15 (additive): adds per-job init config(s) to LockJob.
19
+ * Schema version 16 (additive): adds normalized approval config to LockWorkflow/LockJob/LockStep.
20
+ * Schema version 17 (additive): widens LockJob.init to typed presets ('mise' / { mise }) and 'auto' detection.
21
+ * Schema version 18 (additive): adds LockJob.runsOnAll host fan-out predicate + onUnreachable policy.
22
+ * Schema version 19 (additive): adds LockJob.maxParallel/failFast fan-out concurrency (rolling waves).
23
+ * Schema version 20 (BREAKING): runsOn/runsOnAll/excludeLabels carry LabelMatcher (exact|regex) for glob+regex selectors.
24
+ * Schema version 23 (additive): adds LockDispatchTrigger.inputs (typed dispatch inputs descriptors).
25
+ * Schema version 24 (additive): adds LockJob.runsOnPick (deterministic single-host selection).
26
+ * Schema version 25 (additive): adds LockStep.retry (step retry policy data subset; retryIf is execution-only).
27
+ * Schema version 26 (additive): adds LockJob.includeUninitialized (runsOnAll fans out to declared-but-un-agented hosts, bringing up a temporary init-runner per fresh box).
28
+ * Schema version 27 (additive): adds LockScheduleTrigger.inputs (defaults-only schedule dispatch inputs).
29
+ * Schema version 30 (BREAKING): renames job-level `environments` to `contexts`.
30
+ * Schema version 31 (additive): adds the workflows_failed_batch lock trigger.
31
+ * Schema version 32 (additive): adds LockJob.sandbox (per-job escape-hatch request).
24
32
  */
25
33
  import { z } from 'zod';
26
34
  import type { ProviderType } from '../provider/types.js';
@@ -28,8 +36,28 @@ import type { ApproverClause } from '../approval/types.js';
28
36
  import type { InputsDescriptorMap } from '../inputs/descriptor.js';
29
37
  import { LabelMatcher } from '../labels-match.js';
30
38
  import { ExecutionJobStatus } from '../protocol/messages/execution-status.js';
31
- /** Schema version - increment on breaking changes */
32
- export declare const SCHEMA_VERSION: 30;
39
+ /**
40
+ * Schema version the compiler emits into every lock file. Incremented on ANY
41
+ * schema change (additive or breaking); the bump-history comment above records
42
+ * which. See `BREAKING_FLOOR` for the compatibility-window semantics.
43
+ */
44
+ export declare const SCHEMA_VERSION: 32;
45
+ /**
46
+ * Oldest lock schema version this codebase can still read correctly — the lower
47
+ * bound of the acceptance window.
48
+ *
49
+ * A lock at `schemaVersion >= BREAKING_FLOOR` parses correctly here even if it
50
+ * is newer than `SCHEMA_VERSION` (additive bumps add fields this reader ignores).
51
+ * A lock below the floor was produced by an SDK whose breaking change this
52
+ * reader predates and must be rejected (it would mis-parse silently otherwise).
53
+ *
54
+ * Bump rule: move this to the current `SCHEMA_VERSION` ONLY in the commit that
55
+ * lands a `BREAKING` schema change (see the bump-history convention above). It
56
+ * currently sits at 30 because v30 (`environments`→`contexts`) was the most
57
+ * recent breaking bump; v31 and v32 were additive, so a v30 lock still reads
58
+ * correctly.
59
+ */
60
+ export declare const BREAKING_FLOOR: 30;
33
61
  /**
34
62
  * Normalized approval config carried in the lock file. Produced by the compiler
35
63
  * from an SDK `approval` at any of the three levels; consumed by the
@@ -248,6 +276,21 @@ export interface LockWorkflowCompleteTrigger {
248
276
  readonly status?: readonly string[];
249
277
  readonly source?: string;
250
278
  }
279
+ /**
280
+ * Workflows-failed-batch trigger in lock file.
281
+ *
282
+ * Accumulates failed workflow completions over `accumulateFor` ms and fires the
283
+ * subscribing workflow once per window with the batched run list. The matcher
284
+ * treats a failed `workflow_complete` event as an accumulation input and a
285
+ * synthetic `workflows_failed_batch` event as the dispatch trigger.
286
+ */
287
+ export interface LockWorkflowsFailedBatchTrigger {
288
+ readonly _type: 'workflows_failed_batch';
289
+ /** Accumulation window in milliseconds; the window opens on the first failure. */
290
+ readonly accumulateFor: number;
291
+ readonly name?: string;
292
+ readonly source?: string;
293
+ }
251
294
  /**
252
295
  * Job completion trigger in lock file.
253
296
  * Matches when a specific job within a workflow finishes execution.
@@ -308,7 +351,7 @@ export interface LockLifecycleTrigger {
308
351
  readonly description?: string;
309
352
  }
310
353
  /** Union of all trigger types */
311
- export type LockTrigger = LockPrTrigger | LockPushTrigger | LockTagTrigger | LockCommentTrigger | LockReviewTrigger | LockReviewCommentTrigger | LockReleaseTrigger | LockDispatchTrigger | LockCreateTrigger | LockDeleteTrigger | LockStatusTrigger | LockWorkflowRunTrigger | LockForkTrigger | LockStarTrigger | LockWatchTrigger | LockWebhookTrigger | LockKiciEventTrigger | LockWorkflowCompleteTrigger | LockJobCompleteTrigger | LockGenericWebhookTrigger | LockScheduleTrigger | LockLifecycleTrigger;
354
+ export type LockTrigger = LockPrTrigger | LockPushTrigger | LockTagTrigger | LockCommentTrigger | LockReviewTrigger | LockReviewCommentTrigger | LockReleaseTrigger | LockDispatchTrigger | LockCreateTrigger | LockDeleteTrigger | LockStatusTrigger | LockWorkflowRunTrigger | LockForkTrigger | LockStarTrigger | LockWatchTrigger | LockWebhookTrigger | LockKiciEventTrigger | LockWorkflowCompleteTrigger | LockWorkflowsFailedBatchTrigger | LockJobCompleteTrigger | LockGenericWebhookTrigger | LockScheduleTrigger | LockLifecycleTrigger;
312
355
  /**
313
356
  * Matrix configuration in lock file.
314
357
  * Static matrices are expanded at orchestrator, dynamic at agent runtime.
@@ -403,9 +446,9 @@ export declare function isLockInlineValue(value: unknown): value is LockInlineVa
403
446
  */
404
447
  export declare const NeedsWhen: z.ZodEnum<{
405
448
  always: "always";
406
- "on-success": "on-success";
407
- "on-skip": "on-skip";
408
449
  "on-failure": "on-failure";
450
+ "on-skip": "on-skip";
451
+ "on-success": "on-success";
409
452
  }>;
410
453
  export type NeedsWhen = z.infer<typeof NeedsWhen>;
411
454
  /**
@@ -415,23 +458,29 @@ export type NeedsWhen = z.infer<typeof NeedsWhen>;
415
458
  * gating stays a pure status-set membership test.
416
459
  */
417
460
  export declare const NeedsRunOn: z.ZodArray<z.ZodEnum<{
418
- skipped: "skipped";
419
- success: "success";
420
- pending: "pending";
421
- running: "running";
422
- failed: "failed";
423
461
  cancelled: "cancelled";
424
462
  cancelling: "cancelling";
463
+ drift_dropped: "drift_dropped";
464
+ failed: "failed";
465
+ pending: "pending";
425
466
  queued: "queued";
426
467
  recovering: "recovering";
468
+ running: "running";
469
+ skipped: "skipped";
470
+ success: "success";
427
471
  timed_out_stale: "timed_out_stale";
428
- drift_dropped: "drift_dropped";
472
+ unroutable: "unroutable";
429
473
  }>>;
430
474
  export type NeedsRunOn = z.infer<typeof NeedsRunOn>;
431
475
  /**
432
476
  * Resolve the author-facing `when` (keyword sugar | raw status-set | unset) to
433
477
  * the normalized status-set. An unset `when` defaults to success-only — the
434
478
  * downstream runs only when the upstream succeeded.
479
+ *
480
+ * Always a fresh array. The keyword arm used to hand back the shared
481
+ * `WHEN_TO_RUN_ON` entry itself, so every lock-file edge compiled from the same
482
+ * keyword aliased one array and any caller that sorted or mutated its result
483
+ * silently reordered the keyword's expansion for every other edge.
435
484
  */
436
485
  export declare function resolveWhenToRunOn(when: NeedsWhen | ExecutionJobStatus[] | undefined): ExecutionJobStatus[];
437
486
  /**
@@ -441,17 +490,18 @@ export declare function resolveWhenToRunOn(when: NeedsWhen | ExecutionJobStatus[
441
490
  export declare const NeedsEntrySchema: z.ZodObject<{
442
491
  name: z.ZodString;
443
492
  runOn: z.ZodDefault<z.ZodArray<z.ZodEnum<{
444
- skipped: "skipped";
445
- success: "success";
446
- pending: "pending";
447
- running: "running";
448
- failed: "failed";
449
493
  cancelled: "cancelled";
450
494
  cancelling: "cancelling";
495
+ drift_dropped: "drift_dropped";
496
+ failed: "failed";
497
+ pending: "pending";
451
498
  queued: "queued";
452
499
  recovering: "recovering";
500
+ running: "running";
501
+ skipped: "skipped";
502
+ success: "success";
453
503
  timed_out_stale: "timed_out_stale";
454
- drift_dropped: "drift_dropped";
504
+ unroutable: "unroutable";
455
505
  }>>>;
456
506
  }, z.core.$strip>;
457
507
  export type NeedsEntry = z.infer<typeof NeedsEntrySchema>;
@@ -462,17 +512,18 @@ export type NeedsEntry = z.infer<typeof NeedsEntrySchema>;
462
512
  export declare const NeedsGroupEntrySchema: z.ZodObject<{
463
513
  group: z.ZodString;
464
514
  runOn: z.ZodDefault<z.ZodArray<z.ZodEnum<{
465
- skipped: "skipped";
466
- success: "success";
467
- pending: "pending";
468
- running: "running";
469
- failed: "failed";
470
515
  cancelled: "cancelled";
471
516
  cancelling: "cancelling";
517
+ drift_dropped: "drift_dropped";
518
+ failed: "failed";
519
+ pending: "pending";
472
520
  queued: "queued";
473
521
  recovering: "recovering";
522
+ running: "running";
523
+ skipped: "skipped";
524
+ success: "success";
474
525
  timed_out_stale: "timed_out_stale";
475
- drift_dropped: "drift_dropped";
526
+ unroutable: "unroutable";
476
527
  }>>>;
477
528
  }, z.core.$strip>;
478
529
  export type NeedsGroupEntry = z.infer<typeof NeedsGroupEntrySchema>;
@@ -507,9 +558,9 @@ export type RunsOnAllInput = string | RegExp | readonly (string | RegExp)[] | {
507
558
  * never return), independent of this policy.
508
559
  */
509
560
  export declare const OnUnreachableMode: z.ZodEnum<{
561
+ fail: "fail";
510
562
  hold: "hold";
511
563
  skip: "skip";
512
- fail: "fail";
513
564
  }>;
514
565
  export type OnUnreachableMode = z.infer<typeof OnUnreachableMode>;
515
566
  /**
@@ -524,6 +575,26 @@ export declare const RunsOnPick: z.ZodEnum<{
524
575
  deterministic: "deterministic";
525
576
  }>;
526
577
  export type RunsOnPick = z.infer<typeof RunsOnPick>;
578
+ /** Container network posture: 'default' (bridge), 'none' (loopback-only), 'host' (host netns; gated). */
579
+ export declare const SANDBOX_NETWORK_MODES: readonly ['default', 'none', 'host'];
580
+ export type SandboxNetworkMode = (typeof SANDBOX_NETWORK_MODES)[number];
581
+ /**
582
+ * The dispatch-resolved, allow-listed per-job sandbox escape hatch. Produced
583
+ * orchestrator-side at dispatch (the agent never resolves it) and applied
584
+ * additively over the hardened container baseline by the agent. The lock carries
585
+ * the workflow-declared request (`LockJob.sandbox`); this is the resolved grant
586
+ * the orchestrator authorized against the operator's `org_settings` allow-list.
587
+ */
588
+ export interface ResolvedSandboxGrant {
589
+ /** Extra Linux capabilities added back over CapDrop:['ALL'] (bare form, e.g. 'NET_ADMIN'). */
590
+ capabilities?: string[];
591
+ /** Network override; when set it wins over the config network mode. */
592
+ network?: SandboxNetworkMode;
593
+ /** Force a read-only rootfs (operator-config path only in Phase 2). */
594
+ readonlyRootfs?: boolean;
595
+ /** Run the container as this user (operator-config path only in Phase 2). */
596
+ user?: string;
597
+ }
527
598
  export interface LockJob {
528
599
  readonly _type: 'static';
529
600
  readonly name: string;
@@ -593,6 +664,29 @@ export interface LockJob {
593
664
  * (`requests`) and kernel-side enforcement (`limits`) on the spawned agent.
594
665
  */
595
666
  readonly resources?: import('../scaler/resource-types.js').ResourceRequest;
667
+ /**
668
+ * Container image selecting the container execution backend on the agent. A
669
+ * bare image string or an object with `image` + optional `env`. When set, the
670
+ * agent's `determineExecutionMode` routes the job to the container sandbox
671
+ * (top priority), so the orchestrator threads it through dispatch as
672
+ * `jobConfig.container`. (Shape mirrors the SDK `string | ContainerConfig`;
673
+ * the engine cannot import the SDK, so it is inlined here.)
674
+ */
675
+ readonly container?: string | {
676
+ readonly image: string;
677
+ readonly env?: Record<string, string>;
678
+ };
679
+ /**
680
+ * Workflow-declared per-job sandbox escape-hatch request (container jobs
681
+ * only). The orchestrator resolves it at dispatch against the operator's
682
+ * `org_settings` allow-list into a `ResolvedSandboxGrant` (a non-allow-listed
683
+ * request fails the run); the agent never reads this field. Additive — an
684
+ * older orchestrator that does not understand it ignores it.
685
+ */
686
+ readonly sandbox?: {
687
+ readonly capabilities?: string[];
688
+ readonly network?: SandboxNetworkMode;
689
+ };
596
690
  /** Normalized approval gate; when set the job is held before dispatch. */
597
691
  readonly approval?: LockApproval;
598
692
  }
@@ -695,6 +789,14 @@ export interface LockWorkflow {
695
789
  */
696
790
  export interface LockFile {
697
791
  readonly schemaVersion: typeof SCHEMA_VERSION;
792
+ /**
793
+ * The newest breaking schema version at emit time (the compiler stamps
794
+ * `BREAKING_FLOOR`). A reader whose own `SCHEMA_VERSION` is below this value
795
+ * predates a breaking change the lock relies on and must reject it. Absent on
796
+ * pre-window locks, in which case the reader falls back to exact-match
797
+ * strictness (see `assertLockFileSchemaCompatible`).
798
+ */
799
+ readonly minReaderVersion?: number;
698
800
  readonly source: LockSource;
699
801
  /** SHA-256 hash of the serialized lock file content (excluding this field). Changes only when workflows, triggers, jobs, or bundle hashes change. */
700
802
  readonly contentHash: string;
@@ -706,6 +808,24 @@ export interface LockFile {
706
808
  export declare function isLockStaticJob(job: LockJobOrFactory): job is LockJob;
707
809
  /** Type guard for dynamic job generators */
708
810
  export declare function isLockDynamicJobFn(job: LockJobOrFactory): job is LockDynamicJobFn;
811
+ /**
812
+ * Availability of the changed-files list for path-filter evaluation.
813
+ *
814
+ * Distinguishes three states that a bare `string[]` collapses into one:
815
+ * - `skipped` — no trigger has path patterns, so the fetch never ran. Path
816
+ * filters are not evaluated (today's no-fetch fast path).
817
+ * - `fetched` — the fetch succeeded and the list is authoritative; an empty
818
+ * list genuinely means "no files changed" and does NOT match a path filter.
819
+ * - `unavailable` — the diff could not be determined (a provider capability
820
+ * gap such as universal-git PR events, or upstream degradation). Path
821
+ * filters match conservatively so a real change is never silently dropped.
822
+ */
823
+ export declare const changedFilesStatusSchema: z.ZodEnum<{
824
+ fetched: "fetched";
825
+ skipped: "skipped";
826
+ unavailable: "unavailable";
827
+ }>;
828
+ export type ChangedFilesStatus = z.infer<typeof changedFilesStatusSchema>;
709
829
  /**
710
830
  * Simulated event payload structure for trigger matching.
711
831
  *
@@ -721,8 +841,18 @@ export interface SimulatedEvent {
721
841
  targetBranch: string;
722
842
  /** PR source branch (only for PRs) */
723
843
  sourceBranch?: string;
844
+ /** Pull-request number for PR-family events (pull_request / review / review_comment); undefined otherwise. */
845
+ prNumber?: number;
724
846
  /** Changed files (for path filtering) */
725
847
  changedFiles?: string[];
848
+ /**
849
+ * Availability of {@link changedFiles} for path-filter evaluation. When
850
+ * `unavailable`, path filters match conservatively instead of inferring a
851
+ * no-match from an empty list. Optional for backward compatibility with the
852
+ * compiler/test CLI, which never fetches a diff (treated as legacy `fetched`
853
+ * exact-match semantics).
854
+ */
855
+ changedFilesStatus?: ChangedFilesStatus;
726
856
  /** Which provider originated this event. Optional for backward compatibility with compiler/test CLI. */
727
857
  provider?: ProviderType;
728
858
  /** Whether this PR comes from a fork (head repo != base repo). Only set for PR events. */