@kici-dev/engine 0.1.26 → 0.2.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 (157) hide show
  1. package/dist/approval/types.d.ts +11 -4
  2. package/dist/approval/types.js +11 -4
  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 +20 -11
  7. package/dist/audit/activity.d.ts +12 -12
  8. package/dist/audit/retention-policy.js +40 -22
  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/{environment → context}/host-match.js +1 -1
  26. package/dist/context/index.d.ts +14 -0
  27. package/dist/context/index.js +12 -0
  28. package/dist/context/multi-context.d.ts +30 -0
  29. package/dist/context/multi-context.js +38 -0
  30. package/dist/context/scope-name.d.ts +29 -0
  31. package/dist/context/scope-name.js +49 -0
  32. package/dist/context/scope-resolver.d.ts +79 -0
  33. package/dist/{environment → context}/scope-resolver.js +47 -17
  34. package/dist/{environment → context}/scope-template.js +1 -1
  35. package/dist/{environment → context}/types.d.ts +25 -22
  36. package/dist/{environment → context}/types.js +3 -3
  37. package/dist/dev-ops/operations.d.ts +9 -1
  38. package/dist/dev-ops/operations.js +37 -20
  39. package/dist/diagnostics/infra-alert.d.ts +71 -0
  40. package/dist/diagnostics/infra-alert.js +60 -0
  41. package/dist/env/environment-allowlist.d.ts +26 -3
  42. package/dist/env/environment-allowlist.js +35 -1
  43. package/dist/fanout/materialize.d.ts +16 -0
  44. package/dist/fanout/materialize.js +34 -5
  45. package/dist/index.d.ts +16 -7
  46. package/dist/index.js +38 -23
  47. package/dist/inputs/descriptor.d.ts +9 -9
  48. package/dist/inventory.d.ts +4 -4
  49. package/dist/labels.d.ts +82 -2
  50. package/dist/labels.js +119 -1
  51. package/dist/matrix/expand.d.ts +49 -2
  52. package/dist/matrix/expand.js +102 -13
  53. package/dist/matrix/format.d.ts +6 -1
  54. package/dist/matrix/format.js +6 -1
  55. package/dist/mcp/held-run-resolve.d.ts +7 -10
  56. package/dist/mcp/held-run-resolve.js +33 -7
  57. package/dist/metrics/catalog-policy.js +4 -4
  58. package/dist/metrics/metric-catalog.generated.d.ts +954 -734
  59. package/dist/metrics/metric-catalog.generated.js +296 -32
  60. package/dist/metrics/metric-kind-compat.d.ts +26 -0
  61. package/dist/metrics/metric-kind-compat.js +33 -0
  62. package/dist/protocol/analytics-events.d.ts +6 -6
  63. package/dist/protocol/dashboard-api-errors.d.ts +13 -0
  64. package/dist/protocol/dashboard-api-errors.js +17 -0
  65. package/dist/protocol/dashboard-write-operations.d.ts +143 -86
  66. package/dist/protocol/dashboard-write-operations.js +143 -69
  67. package/dist/protocol/messages/access-log.d.ts +438 -388
  68. package/dist/protocol/messages/access-log.js +24 -14
  69. package/dist/protocol/messages/actor.d.ts +2 -2
  70. package/dist/protocol/messages/agent-dev-ops.d.ts +4 -2
  71. package/dist/protocol/messages/agent-dev-ops.js +2 -5
  72. package/dist/protocol/messages/agent-run-result.d.ts +74 -64
  73. package/dist/protocol/messages/agent-run-result.js +1 -1
  74. package/dist/protocol/messages/auth.d.ts +35 -23
  75. package/dist/protocol/messages/browser.d.ts +81 -5
  76. package/dist/protocol/messages/browser.js +53 -2
  77. package/dist/protocol/messages/capabilities.d.ts +106 -31
  78. package/dist/protocol/messages/capabilities.js +94 -10
  79. package/dist/protocol/messages/common.d.ts +45 -2
  80. package/dist/protocol/messages/common.js +64 -3
  81. package/dist/protocol/messages/dashboard-sealed-write.d.ts +52 -0
  82. package/dist/protocol/messages/dashboard-sealed-write.js +57 -0
  83. package/dist/protocol/messages/dashboard.d.ts +1232 -706
  84. package/dist/protocol/messages/dashboard.js +387 -220
  85. package/dist/protocol/messages/deployment-identity.d.ts +37 -10
  86. package/dist/protocol/messages/deployment-identity.js +30 -3
  87. package/dist/protocol/messages/event-log.d.ts +5 -5
  88. package/dist/protocol/messages/execution-status.d.ts +198 -62
  89. package/dist/protocol/messages/execution-status.js +114 -46
  90. package/dist/protocol/messages/heartbeat-health.d.ts +83 -0
  91. package/dist/protocol/messages/heartbeat-health.js +87 -0
  92. package/dist/protocol/messages/log-stream.d.ts +18 -0
  93. package/dist/protocol/messages/log-stream.js +19 -0
  94. package/dist/protocol/messages/oidc-mint.d.ts +7 -0
  95. package/dist/protocol/messages/oidc-mint.js +7 -0
  96. package/dist/protocol/messages/orchestrator-agent.d.ts +264 -67
  97. package/dist/protocol/messages/orchestrator-agent.js +170 -5
  98. package/dist/protocol/messages/pat-kind.d.ts +1 -1
  99. package/dist/protocol/messages/peer.d.ts +122 -58
  100. package/dist/protocol/messages/peer.js +37 -2
  101. package/dist/protocol/messages/platform-orchestrator.d.ts +603 -258
  102. package/dist/protocol/messages/platform-orchestrator.js +131 -21
  103. package/dist/protocol/messages/run-events.d.ts +5 -5
  104. package/dist/protocol/messages/scaler-event.d.ts +3 -3
  105. package/dist/protocol/messages/source-registration.d.ts +56 -13
  106. package/dist/protocol/messages/source-registration.js +49 -6
  107. package/dist/protocol/session-policy.d.ts +20 -0
  108. package/dist/protocol/session-policy.js +25 -0
  109. package/dist/protocol/source-origin.d.ts +1 -1
  110. package/dist/provenance/attestation-origin.d.ts +1 -1
  111. package/dist/provenance/schema.d.ts +11 -11
  112. package/dist/provenance/verify.js +2 -1
  113. package/dist/provider/changed-files-fetcher.d.ts +21 -2
  114. package/dist/provider/check-run-conclusion.d.ts +2 -2
  115. package/dist/provider/check-status-poster.d.ts +23 -0
  116. package/dist/provider/index.d.ts +2 -2
  117. package/dist/registration/registerable-trigger-type.d.ts +14 -13
  118. package/dist/registration/registerable-trigger-type.js +1 -0
  119. package/dist/sandbox/capabilities.d.ts +6 -0
  120. package/dist/sandbox/capabilities.js +57 -0
  121. package/dist/scaler/scaler-backend-type.d.ts +1 -1
  122. package/dist/status/presentation.d.ts +89 -0
  123. package/dist/status/presentation.js +163 -0
  124. package/dist/trigger/compiled-matchers.d.ts +13 -0
  125. package/dist/trigger/compiled-matchers.js +44 -0
  126. package/dist/trigger/event-buckets.d.ts +44 -0
  127. package/dist/trigger/event-buckets.js +93 -0
  128. package/dist/trigger/matcher.d.ts +7 -3
  129. package/dist/trigger/matcher.js +53 -15
  130. package/dist/trigger/schedule-key.d.ts +14 -0
  131. package/dist/trigger/schedule-key.js +21 -0
  132. package/dist/trigger/trigger-event-type.d.ts +1 -1
  133. package/dist/trigger/trigger-event-type.js +2 -0
  134. package/dist/trigger/types.d.ts +178 -47
  135. package/dist/trigger/types.js +82 -24
  136. package/dist/webhook/event-types.d.ts +56 -0
  137. package/dist/webhook/event-types.js +59 -0
  138. package/dist/ws/ws-like.d.ts +13 -0
  139. package/package.json +26 -10
  140. package/sbom.spdx.json +10 -10
  141. package/dist/environment/index.d.ts +0 -6
  142. package/dist/environment/index.js +0 -5
  143. package/dist/environment/multi-env.d.ts +0 -30
  144. package/dist/environment/multi-env.js +0 -38
  145. package/dist/environment/scope-resolver.d.ts +0 -46
  146. package/dist/package-manager.d.ts +0 -20
  147. package/dist/protocol/messages/observe.d.ts +0 -76
  148. package/dist/protocol/messages/saas-orchestrator.d.ts +0 -2179
  149. package/dist/protocol/messages/test-run.d.ts +0 -59
  150. package/dist/state-machine/index.d.ts +0 -2
  151. package/dist/state-machine/index.js +0 -3
  152. package/dist/state-machine/machine.d.ts +0 -34
  153. package/dist/state-machine/machine.js +0 -103
  154. package/dist/state-machine/types.d.ts +0 -34
  155. package/dist/state-machine/types.js +0 -15
  156. /package/dist/{environment → context}/host-match.d.ts +0 -0
  157. /package/dist/{environment → context}/scope-template.d.ts +0 -0
@@ -1,5 +1,5 @@
1
- import type { LockWorkflow, LockBranchPattern, SimulatedEvent } from './types.js';
2
- import { type WorkflowDecision } from './decision-trace.js';
1
+ import type { LockTrigger, LockWorkflow, LockBranchPattern, SimulatedEvent, ChangedFilesStatus } from './types.js';
2
+ import { type TraceEntry, type WorkflowDecision } from './decision-trace.js';
3
3
  /**
4
4
  * Match a branch pattern against a branch name.
5
5
  */
@@ -9,7 +9,7 @@ export declare function matchBranchPattern(pattern: LockBranchPattern, branch: s
9
9
  * Patterns prefixed with ! are exclusions. Remaining patterns are inclusions.
10
10
  * An all-negation array has implicit match-all semantics for non-excluded files.
11
11
  */
12
- export declare function matchPathPatterns(paths: readonly string[], changedFiles: string[]): boolean;
12
+ export declare function matchPathPatterns(paths: readonly string[], changedFiles: string[], status?: ChangedFilesStatus): boolean;
13
13
  /**
14
14
  * Match repo patterns against a source repository identifier.
15
15
  * Patterns with ! prefix in the pattern string are exclusions.
@@ -17,6 +17,10 @@ export declare function matchPathPatterns(paths: readonly string[], changedFiles
17
17
  * Empty array = no filtering (matches all repos).
18
18
  */
19
19
  export declare function matchRepoPatterns(repos: readonly LockBranchPattern[], sourceRepo: string): boolean;
20
+ /**
21
+ * Match a trigger against a simulated event.
22
+ */
23
+ export declare function matchTrigger(trigger: LockTrigger, event: SimulatedEvent, traces: TraceEntry[]): boolean;
20
24
  /**
21
25
  * Match all triggers for a workflow against an event.
22
26
  * Returns WorkflowDecision with full trace.
@@ -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,25 +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).
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).
23
32
  */
24
33
  import { z } from 'zod';
25
34
  import type { ProviderType } from '../provider/types.js';
@@ -27,8 +36,28 @@ import type { ApproverClause } from '../approval/types.js';
27
36
  import type { InputsDescriptorMap } from '../inputs/descriptor.js';
28
37
  import { LabelMatcher } from '../labels-match.js';
29
38
  import { ExecutionJobStatus } from '../protocol/messages/execution-status.js';
30
- /** Schema version - increment on breaking changes */
31
- export declare const SCHEMA_VERSION: 29;
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;
32
61
  /**
33
62
  * Normalized approval config carried in the lock file. Produced by the compiler
34
63
  * from an SDK `approval` at any of the three levels; consumed by the
@@ -247,6 +276,21 @@ export interface LockWorkflowCompleteTrigger {
247
276
  readonly status?: readonly string[];
248
277
  readonly source?: string;
249
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
+ }
250
294
  /**
251
295
  * Job completion trigger in lock file.
252
296
  * Matches when a specific job within a workflow finishes execution.
@@ -307,7 +351,7 @@ export interface LockLifecycleTrigger {
307
351
  readonly description?: string;
308
352
  }
309
353
  /** Union of all trigger types */
310
- 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;
311
355
  /**
312
356
  * Matrix configuration in lock file.
313
357
  * Static matrices are expanded at orchestrator, dynamic at agent runtime.
@@ -402,9 +446,9 @@ export declare function isLockInlineValue(value: unknown): value is LockInlineVa
402
446
  */
403
447
  export declare const NeedsWhen: z.ZodEnum<{
404
448
  always: "always";
405
- "on-success": "on-success";
406
- "on-skip": "on-skip";
407
449
  "on-failure": "on-failure";
450
+ "on-skip": "on-skip";
451
+ "on-success": "on-success";
408
452
  }>;
409
453
  export type NeedsWhen = z.infer<typeof NeedsWhen>;
410
454
  /**
@@ -414,23 +458,29 @@ export type NeedsWhen = z.infer<typeof NeedsWhen>;
414
458
  * gating stays a pure status-set membership test.
415
459
  */
416
460
  export declare const NeedsRunOn: z.ZodArray<z.ZodEnum<{
417
- skipped: "skipped";
418
- success: "success";
419
- pending: "pending";
420
- running: "running";
421
- failed: "failed";
422
461
  cancelled: "cancelled";
423
462
  cancelling: "cancelling";
463
+ drift_dropped: "drift_dropped";
464
+ failed: "failed";
465
+ pending: "pending";
424
466
  queued: "queued";
425
467
  recovering: "recovering";
468
+ running: "running";
469
+ skipped: "skipped";
470
+ success: "success";
426
471
  timed_out_stale: "timed_out_stale";
427
- drift_dropped: "drift_dropped";
472
+ unroutable: "unroutable";
428
473
  }>>;
429
474
  export type NeedsRunOn = z.infer<typeof NeedsRunOn>;
430
475
  /**
431
476
  * Resolve the author-facing `when` (keyword sugar | raw status-set | unset) to
432
477
  * the normalized status-set. An unset `when` defaults to success-only — the
433
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.
434
484
  */
435
485
  export declare function resolveWhenToRunOn(when: NeedsWhen | ExecutionJobStatus[] | undefined): ExecutionJobStatus[];
436
486
  /**
@@ -440,17 +490,18 @@ export declare function resolveWhenToRunOn(when: NeedsWhen | ExecutionJobStatus[
440
490
  export declare const NeedsEntrySchema: z.ZodObject<{
441
491
  name: z.ZodString;
442
492
  runOn: z.ZodDefault<z.ZodArray<z.ZodEnum<{
443
- skipped: "skipped";
444
- success: "success";
445
- pending: "pending";
446
- running: "running";
447
- failed: "failed";
448
493
  cancelled: "cancelled";
449
494
  cancelling: "cancelling";
495
+ drift_dropped: "drift_dropped";
496
+ failed: "failed";
497
+ pending: "pending";
450
498
  queued: "queued";
451
499
  recovering: "recovering";
500
+ running: "running";
501
+ skipped: "skipped";
502
+ success: "success";
452
503
  timed_out_stale: "timed_out_stale";
453
- drift_dropped: "drift_dropped";
504
+ unroutable: "unroutable";
454
505
  }>>>;
455
506
  }, z.core.$strip>;
456
507
  export type NeedsEntry = z.infer<typeof NeedsEntrySchema>;
@@ -461,17 +512,18 @@ export type NeedsEntry = z.infer<typeof NeedsEntrySchema>;
461
512
  export declare const NeedsGroupEntrySchema: z.ZodObject<{
462
513
  group: z.ZodString;
463
514
  runOn: z.ZodDefault<z.ZodArray<z.ZodEnum<{
464
- skipped: "skipped";
465
- success: "success";
466
- pending: "pending";
467
- running: "running";
468
- failed: "failed";
469
515
  cancelled: "cancelled";
470
516
  cancelling: "cancelling";
517
+ drift_dropped: "drift_dropped";
518
+ failed: "failed";
519
+ pending: "pending";
471
520
  queued: "queued";
472
521
  recovering: "recovering";
522
+ running: "running";
523
+ skipped: "skipped";
524
+ success: "success";
473
525
  timed_out_stale: "timed_out_stale";
474
- drift_dropped: "drift_dropped";
526
+ unroutable: "unroutable";
475
527
  }>>>;
476
528
  }, z.core.$strip>;
477
529
  export type NeedsGroupEntry = z.infer<typeof NeedsGroupEntrySchema>;
@@ -506,9 +558,9 @@ export type RunsOnAllInput = string | RegExp | readonly (string | RegExp)[] | {
506
558
  * never return), independent of this policy.
507
559
  */
508
560
  export declare const OnUnreachableMode: z.ZodEnum<{
561
+ fail: "fail";
509
562
  hold: "hold";
510
563
  skip: "skip";
511
- fail: "fail";
512
564
  }>;
513
565
  export type OnUnreachableMode = z.infer<typeof OnUnreachableMode>;
514
566
  /**
@@ -523,6 +575,26 @@ export declare const RunsOnPick: z.ZodEnum<{
523
575
  deterministic: "deterministic";
524
576
  }>;
525
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
+ }
526
598
  export interface LockJob {
527
599
  readonly _type: 'static';
528
600
  readonly name: string;
@@ -568,11 +640,11 @@ export interface LockJob {
568
640
  readonly rules?: readonly LockRule[];
569
641
  readonly description?: string;
570
642
  /**
571
- * Deployment environments in merge order. Each entry is a static name or inline
643
+ * Bound contexts in merge order. Each entry is a static name or inline
572
644
  * expression (pure function); `dynamic` is set when it is a function resolved at
573
645
  * two-phase eval. Later entries override earlier ones on name collisions.
574
646
  */
575
- readonly environments?: ReadonlyArray<{
647
+ readonly contexts?: ReadonlyArray<{
576
648
  value: string | LockInlineValue;
577
649
  dynamic: boolean;
578
650
  }>;
@@ -592,6 +664,29 @@ export interface LockJob {
592
664
  * (`requests`) and kernel-side enforcement (`limits`) on the spawned agent.
593
665
  */
594
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
+ };
595
690
  /** Normalized approval gate; when set the job is held before dispatch. */
596
691
  readonly approval?: LockApproval;
597
692
  }
@@ -622,13 +717,13 @@ export type LockJobOrFactory = LockJob | LockDynamicJobFn;
622
717
  /**
623
718
  * Private npm registry declaration in the lock file.
624
719
  * Carries the URL/scope/secret-reference but NOT the resolved token —
625
- * the orchestrator resolves the token at dispatch time via the per-environment
720
+ * the orchestrator resolves the token at dispatch time via the per-context
626
721
  * secretResolver.resolveForJob path.
627
722
  */
628
723
  export interface LockRegistry {
629
724
  readonly url: string;
630
725
  readonly scope?: string;
631
- /** Qualified secret reference: `<environment>:<secret-name>`. */
726
+ /** Qualified secret reference: `<context>:<secret-name>`. */
632
727
  readonly tokenSecret: string;
633
728
  readonly alwaysAuth?: boolean;
634
729
  }
@@ -660,7 +755,7 @@ export interface LockWorkflow {
660
755
  */
661
756
  readonly registries?: readonly LockRegistry[];
662
757
  /**
663
- * Extra qualified secret refs (`<environment>:<secret-name>`) to project as
758
+ * Extra qualified secret refs (`<context>:<secret-name>`) to project as
664
759
  * env vars on the install subprocess for use with a customer-committed `.kici/.npmrc`.
665
760
  */
666
761
  readonly installEnv?: readonly string[];
@@ -694,6 +789,14 @@ export interface LockWorkflow {
694
789
  */
695
790
  export interface LockFile {
696
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;
697
800
  readonly source: LockSource;
698
801
  /** SHA-256 hash of the serialized lock file content (excluding this field). Changes only when workflows, triggers, jobs, or bundle hashes change. */
699
802
  readonly contentHash: string;
@@ -705,6 +808,24 @@ export interface LockFile {
705
808
  export declare function isLockStaticJob(job: LockJobOrFactory): job is LockJob;
706
809
  /** Type guard for dynamic job generators */
707
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>;
708
829
  /**
709
830
  * Simulated event payload structure for trigger matching.
710
831
  *
@@ -720,8 +841,18 @@ export interface SimulatedEvent {
720
841
  targetBranch: string;
721
842
  /** PR source branch (only for PRs) */
722
843
  sourceBranch?: string;
844
+ /** Pull-request number for PR-family events (pull_request / review / review_comment); undefined otherwise. */
845
+ prNumber?: number;
723
846
  /** Changed files (for path filtering) */
724
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;
725
856
  /** Which provider originated this event. Optional for backward compatibility with compiler/test CLI. */
726
857
  provider?: ProviderType;
727
858
  /** Whether this PR comes from a fork (head repo != base repo). Only set for PR events. */