@kici-dev/engine 0.4.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/audit/access-log-policy.js +1 -0
- package/dist/audit/retention-policy.js +2 -0
- package/dist/context/held-run-job-id.d.ts +26 -10
- package/dist/context/held-run-job-id.js +30 -11
- package/dist/context/host-match.js +2 -1
- package/dist/context/index.d.ts +1 -1
- package/dist/context/index.js +3 -3
- package/dist/context/types.d.ts +10 -1
- package/dist/context/types.js +10 -1
- package/dist/index.d.ts +6 -2
- package/dist/index.js +17 -12
- package/dist/labels/compile.d.ts +2 -7
- package/dist/labels/compile.js +1 -10
- package/dist/labels.d.ts +74 -12
- package/dist/labels.js +82 -17
- package/dist/mcp/held-run-resolve.d.ts +40 -0
- package/dist/mcp/held-run-resolve.js +68 -15
- package/dist/mcp/tool-schemas.d.ts +4 -0
- package/dist/mcp/tool-schemas.js +13 -1
- package/dist/metrics/catalog-policy.d.ts +17 -3
- package/dist/metrics/catalog-policy.js +44 -13
- package/dist/metrics/metric-catalog.generated.d.ts +140 -0
- package/dist/metrics/metric-catalog.generated.js +168 -0
- package/dist/protocol/dashboard-global-workflows.js +2 -2
- package/dist/protocol/event-log-payload.js +1 -1
- package/dist/protocol/messages/access-log.d.ts +5 -0
- package/dist/protocol/messages/access-log.js +1 -0
- package/dist/protocol/messages/actor.d.ts +13 -2
- package/dist/protocol/messages/actor.js +16 -5
- package/dist/protocol/messages/common.js +1 -1
- package/dist/protocol/messages/dashboard-global-workflows.d.ts +29 -3
- package/dist/protocol/messages/dashboard-global-workflows.js +48 -4
- package/dist/protocol/messages/dashboard.d.ts +48 -7
- package/dist/protocol/messages/dashboard.js +62 -6
- package/dist/protocol/messages/execution-status.d.ts +44 -0
- package/dist/protocol/messages/execution-status.js +69 -2
- package/dist/protocol/messages/git-credential-relay.d.ts +78 -0
- package/dist/protocol/messages/git-credential-relay.js +86 -0
- package/dist/protocol/messages/orchestrator-agent.d.ts +138 -0
- package/dist/protocol/messages/orchestrator-agent.js +131 -3
- package/dist/protocol/messages/peer.d.ts +7 -0
- package/dist/protocol/messages/peer.js +18 -1
- package/dist/protocol/messages/platform-orchestrator.d.ts +155 -2
- package/dist/protocol/messages/platform-orchestrator.js +178 -19
- package/dist/protocol/version.d.ts +19 -2
- package/dist/protocol/version.js +20 -3
- package/dist/provenance/verify.js +11 -10
- package/dist/provider/check-status-poster.d.ts +37 -2
- package/dist/provider/contributor-resolver.d.ts +11 -3
- package/dist/provider/file-contents-fetcher.d.ts +39 -0
- package/dist/provider/file-contents-fetcher.js +2 -0
- package/dist/provider/git-credential.d.ts +77 -0
- package/dist/provider/git-credential.js +10 -0
- package/dist/provider/index.d.ts +4 -0
- package/dist/provider/index.js +2 -1
- package/dist/provider/webhook-normalizer.d.ts +12 -12
- package/dist/repo/pattern-negation.d.ts +73 -0
- package/dist/repo/pattern-negation.js +86 -0
- package/dist/safe-regex.d.ts +16 -0
- package/dist/safe-regex.js +24 -0
- package/dist/scaler/registry-auth.d.ts +18 -0
- package/dist/scaler/registry-auth.js +28 -0
- package/dist/scaler/scaler-backend-type.d.ts +35 -0
- package/dist/scaler/scaler-backend-type.js +39 -2
- package/dist/scaler/scaler-events.d.ts +79 -0
- package/dist/scaler/scaler-events.js +87 -0
- package/dist/trigger/compiled-matchers.d.ts +21 -1
- package/dist/trigger/compiled-matchers.js +30 -3
- package/dist/trigger/content-requirements.d.ts +31 -0
- package/dist/trigger/content-requirements.js +125 -0
- package/dist/trigger/decision-trace.d.ts +168 -0
- package/dist/trigger/decision-trace.js +207 -4
- package/dist/trigger/jsonpath-matcher.js +5 -1
- package/dist/trigger/matcher.js +61 -10
- package/dist/trigger/text-match.d.ts +27 -0
- package/dist/trigger/text-match.js +86 -0
- package/dist/trigger/types.d.ts +265 -23
- package/dist/trigger/types.js +37 -5
- package/dist/ws/rate-limiter.js +3 -3
- package/package.json +20 -3
- package/sbom.spdx.json +40 -15
package/dist/trigger/matcher.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import "../rolldown-runtime-ClRpJifh.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { evaluateTextMatch } from "./text-match.js";
|
|
3
|
+
import { TraceCheck, createCommitMessageTraceEntry, createTraceEntry, createWorkflowDecision } from "./decision-trace.js";
|
|
4
|
+
import { getCompiledRegex, getGlobMatcher, getRepoGlobMatcher } from "./compiled-matchers.js";
|
|
4
5
|
import { matchJsonPath, matchJsonPathNot } from "./jsonpath-matcher.js";
|
|
5
6
|
//#region src/trigger/matcher.ts
|
|
6
7
|
/**
|
|
@@ -35,7 +36,21 @@ function splitBranchPatterns(patterns) {
|
|
|
35
36
|
*/
|
|
36
37
|
function matchBranchPattern(pattern, branch) {
|
|
37
38
|
if (pattern.type === "glob") return getGlobMatcher(pattern.pattern)(branch);
|
|
38
|
-
else return getCompiledRegex(pattern.pattern, pattern.flags).test(branch);
|
|
39
|
+
else return getCompiledRegex(pattern.pattern, pattern.flags, "branch/tag/repo pattern").test(branch);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Match a repo pattern against a repository identifier.
|
|
43
|
+
*
|
|
44
|
+
* Same shape as {@link matchBranchPattern}, but glob patterns compile through
|
|
45
|
+
* {@link getRepoGlobMatcher} so a dot-prefixed identifier (`.hidden/repo`) is
|
|
46
|
+
* matched by `**`. Repo identifiers are org/name pairs, not paths, so there is
|
|
47
|
+
* no dotfile convention to respect — and `repos: ['**']` means every repo.
|
|
48
|
+
*
|
|
49
|
+
* Regex patterns are unaffected: `dot` is a glob option with no regex analogue.
|
|
50
|
+
*/
|
|
51
|
+
function matchRepoPattern(pattern, repo) {
|
|
52
|
+
if (pattern.type === "glob") return getRepoGlobMatcher(pattern.pattern)(repo);
|
|
53
|
+
return getCompiledRegex(pattern.pattern, pattern.flags, "branch/tag/repo pattern").test(repo);
|
|
39
54
|
}
|
|
40
55
|
/**
|
|
41
56
|
* Match any of the branch patterns.
|
|
@@ -73,10 +88,10 @@ function matchRepoPatterns(repos, sourceRepo) {
|
|
|
73
88
|
if (repos.length === 0) return true;
|
|
74
89
|
const { include, exclude } = splitBranchPatterns(repos);
|
|
75
90
|
if (exclude.length > 0) {
|
|
76
|
-
if (exclude.some((p) =>
|
|
91
|
+
if (exclude.some((p) => matchRepoPattern(p, sourceRepo))) return false;
|
|
77
92
|
}
|
|
78
93
|
if (include.length === 0) return true;
|
|
79
|
-
return include.some((p) =>
|
|
94
|
+
return include.some((p) => matchRepoPattern(p, sourceRepo));
|
|
80
95
|
}
|
|
81
96
|
/**
|
|
82
97
|
* Evaluate repo pattern filter for a trigger against an event.
|
|
@@ -86,17 +101,48 @@ function matchRepoPatterns(repos, sourceRepo) {
|
|
|
86
101
|
function evaluateRepoFilter(trigger, event, traces) {
|
|
87
102
|
if (trigger.repos?.length) {
|
|
88
103
|
if (!event.sourceRepo) {
|
|
89
|
-
traces.push(createTraceEntry(
|
|
104
|
+
traces.push(createTraceEntry(TraceCheck.RepoFilter, "required", "(missing)", false));
|
|
90
105
|
return false;
|
|
91
106
|
}
|
|
92
107
|
const { include, exclude } = splitBranchPatterns(trigger.repos);
|
|
93
108
|
const repoMatch = matchRepoPatterns(trigger.repos, event.sourceRepo);
|
|
94
|
-
traces.push(createTraceEntry(
|
|
109
|
+
traces.push(createTraceEntry(TraceCheck.RepoFilter, `include:[${include.map((p) => p.pattern).join(",")}] exclude:[${exclude.map((p) => p.pattern).join(",")}]`, event.sourceRepo, repoMatch));
|
|
95
110
|
if (!repoMatch) return false;
|
|
96
111
|
}
|
|
97
112
|
return true;
|
|
98
113
|
}
|
|
99
114
|
/**
|
|
115
|
+
* Evaluate a trigger's `commitMessage` filter. Returns true when the trigger
|
|
116
|
+
* declares none (the fast path).
|
|
117
|
+
*
|
|
118
|
+
* An event with no message is INDETERMINATE, not a clean exclusion: the filter
|
|
119
|
+
* is fail-visible, mirroring the Tier-1 `requires` gate, so a workflow whose
|
|
120
|
+
* declared gate was never evaluated does not run.
|
|
121
|
+
*/
|
|
122
|
+
function evaluateCommitMessageFilter(trigger, event, traces) {
|
|
123
|
+
const match = trigger.commitMessage;
|
|
124
|
+
if (!match) return true;
|
|
125
|
+
if (event.commitMessage === void 0) {
|
|
126
|
+
traces.push(createCommitMessageTraceEntry({
|
|
127
|
+
match,
|
|
128
|
+
text: void 0,
|
|
129
|
+
passed: false,
|
|
130
|
+
indeterminate: true,
|
|
131
|
+
reason: "no commit message in payload (provider carries none for this event)"
|
|
132
|
+
}));
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
const result = evaluateTextMatch(event.commitMessage, match);
|
|
136
|
+
traces.push(createCommitMessageTraceEntry({
|
|
137
|
+
match,
|
|
138
|
+
text: event.commitMessage,
|
|
139
|
+
passed: result.pass,
|
|
140
|
+
indeterminate: result.indeterminate !== void 0,
|
|
141
|
+
...result.indeterminate !== void 0 && { reason: result.indeterminate }
|
|
142
|
+
}));
|
|
143
|
+
return result.pass;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
100
146
|
* Match a PR trigger against a simulated event.
|
|
101
147
|
*/
|
|
102
148
|
function matchPrTrigger(trigger, event, traces) {
|
|
@@ -132,6 +178,7 @@ function matchPrTrigger(trigger, event, traces) {
|
|
|
132
178
|
traces.push(createTraceEntry("paths", `include: [${include.join(", ")}] exclude: [${exclude.join(", ")}]`, event.changedFilesStatus === "unavailable" ? "[unavailable — matched conservatively]" : `[${changedFiles.join(", ")}]`, matches));
|
|
133
179
|
if (!matches) return false;
|
|
134
180
|
}
|
|
181
|
+
if (!evaluateCommitMessageFilter(trigger, event, traces)) return false;
|
|
135
182
|
if (!evaluateRepoFilter(trigger, event, traces)) return false;
|
|
136
183
|
return true;
|
|
137
184
|
}
|
|
@@ -156,6 +203,7 @@ function matchPushTrigger(trigger, event, traces) {
|
|
|
156
203
|
traces.push(createTraceEntry("paths", `include: [${include.join(", ")}] exclude: [${exclude.join(", ")}]`, event.changedFilesStatus === "unavailable" ? "[unavailable — matched conservatively]" : `[${changedFiles.join(", ")}]`, matches));
|
|
157
204
|
if (!matches) return false;
|
|
158
205
|
}
|
|
206
|
+
if (!evaluateCommitMessageFilter(trigger, event, traces)) return false;
|
|
159
207
|
if (!evaluateRepoFilter(trigger, event, traces)) return false;
|
|
160
208
|
return true;
|
|
161
209
|
}
|
|
@@ -174,6 +222,7 @@ function matchTagTrigger(trigger, event, traces) {
|
|
|
174
222
|
traces.push(createTraceEntry("tag pattern", trigger.patterns.map((p) => p.pattern).join("|"), event.targetBranch, matches));
|
|
175
223
|
if (!matches) return false;
|
|
176
224
|
}
|
|
225
|
+
if (!evaluateCommitMessageFilter(trigger, event, traces)) return false;
|
|
177
226
|
if (!evaluateRepoFilter(trigger, event, traces)) return false;
|
|
178
227
|
return true;
|
|
179
228
|
}
|
|
@@ -213,7 +262,7 @@ function matchCommentTrigger(trigger, event, traces) {
|
|
|
213
262
|
traces.push(createTraceEntry("bodyMatch (glob)", trigger.bodyMatch.pattern, body, matches));
|
|
214
263
|
if (!matches) return false;
|
|
215
264
|
} else {
|
|
216
|
-
const matches = getCompiledRegex(trigger.bodyMatch.pattern, trigger.bodyMatch.flags).test(body);
|
|
265
|
+
const matches = getCompiledRegex(trigger.bodyMatch.pattern, trigger.bodyMatch.flags, "comment bodyMatch").test(body);
|
|
217
266
|
traces.push(createTraceEntry("bodyMatch (regex)", trigger.bodyMatch.pattern, body, matches));
|
|
218
267
|
if (!matches) return false;
|
|
219
268
|
}
|
|
@@ -493,12 +542,14 @@ function matchKiciEventTrigger(trigger, event, traces) {
|
|
|
493
542
|
traces.push(createTraceEntry("event name", trigger.eventName, eventName, nameMatches));
|
|
494
543
|
if (!nameMatches) return false;
|
|
495
544
|
if (trigger.match && Object.keys(trigger.match).length > 0) {
|
|
496
|
-
const
|
|
545
|
+
const eventPayload = event.payload.payload ?? {};
|
|
546
|
+
const matches = matchJsonPath(eventPayload, trigger.match);
|
|
497
547
|
traces.push(createTraceEntry("jsonpath match", JSON.stringify(trigger.match), "(payload)", matches));
|
|
498
548
|
if (!matches) return false;
|
|
499
549
|
}
|
|
500
550
|
if (trigger.not && Object.keys(trigger.not).length > 0) {
|
|
501
|
-
const
|
|
551
|
+
const eventPayload = event.payload.payload ?? {};
|
|
552
|
+
const passes = matchJsonPathNot(eventPayload, trigger.not);
|
|
502
553
|
traces.push(createTraceEntry("jsonpath not", JSON.stringify(trigger.not), "(payload)", passes));
|
|
503
554
|
if (!passes) return false;
|
|
504
555
|
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { LockTextMatch, TextMatch } from './types.js';
|
|
2
|
+
/** A definite verdict, or fail-visible indeterminate. Mirrors `ContentRequirementResult`. */
|
|
3
|
+
export interface TextMatchResult {
|
|
4
|
+
readonly pass: boolean;
|
|
5
|
+
/** Set (with `pass: false`) when the match could not be evaluated. */
|
|
6
|
+
readonly indeterminate?: string;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Compile a `/pattern/flags` (or bare-pattern) string, rejecting a ReDoS-prone
|
|
10
|
+
* pattern. Returns `null` when the pattern is syntactically invalid or fails the
|
|
11
|
+
* `safe-regex` star-height heuristic — callers treat `null` as indeterminate.
|
|
12
|
+
*
|
|
13
|
+
* Always compiles a FRESH RegExp. A `g`-flagged instance carries `lastIndex`
|
|
14
|
+
* across `.test()` calls, so a cached one would return alternating verdicts for
|
|
15
|
+
* the same input.
|
|
16
|
+
*/
|
|
17
|
+
export declare function compileSafeRegex(source: string): RegExp | null;
|
|
18
|
+
/** True when the matcher carries at least one populated query key. */
|
|
19
|
+
export declare function textMatchHasQuery(m: TextMatch | LockTextMatch): boolean;
|
|
20
|
+
/** Render the populated keys for a decision-trace `pattern` field. */
|
|
21
|
+
export declare function describeTextMatch(m: LockTextMatch): string;
|
|
22
|
+
/**
|
|
23
|
+
* Evaluate a text match. Every entry in every list is a conjunct, and every
|
|
24
|
+
* populated key ANDs with the others; an empty matcher passes.
|
|
25
|
+
*/
|
|
26
|
+
export declare function evaluateTextMatch(text: string, m: LockTextMatch): TextMatchResult;
|
|
27
|
+
//# sourceMappingURL=text-match.d.ts.map
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import "../rolldown-runtime-ClRpJifh.js";
|
|
2
|
+
import safeRegex from "safe-regex";
|
|
3
|
+
//#region src/trigger/text-match.ts
|
|
4
|
+
/**
|
|
5
|
+
* The single definition of what `contains` / `notContains` / `matches` /
|
|
6
|
+
* `notMatches` mean.
|
|
7
|
+
*
|
|
8
|
+
* Two sites consume it: the Tier-0 `commitMessage` trigger filter (in
|
|
9
|
+
* `matcher.ts`) and the Tier-1 `requires` content filter (in
|
|
10
|
+
* `content-requirements.ts`). Sharing one function is what keeps them from
|
|
11
|
+
* drifting into two dialects of the same vocabulary.
|
|
12
|
+
*
|
|
13
|
+
* Pure string logic — it imports only `safe-regex` and no Node built-in, so it
|
|
14
|
+
* belongs in the browser-safe barrel rather than a subpath export.
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Compile a `/pattern/flags` (or bare-pattern) string, rejecting a ReDoS-prone
|
|
18
|
+
* pattern. Returns `null` when the pattern is syntactically invalid or fails the
|
|
19
|
+
* `safe-regex` star-height heuristic — callers treat `null` as indeterminate.
|
|
20
|
+
*
|
|
21
|
+
* Always compiles a FRESH RegExp. A `g`-flagged instance carries `lastIndex`
|
|
22
|
+
* across `.test()` calls, so a cached one would return alternating verdicts for
|
|
23
|
+
* the same input.
|
|
24
|
+
*/
|
|
25
|
+
function compileSafeRegex(source) {
|
|
26
|
+
const wrapped = /^\/(.+)\/([gimsuy]*)$/.exec(source);
|
|
27
|
+
const pattern = wrapped ? wrapped[1] : source;
|
|
28
|
+
const flags = wrapped ? wrapped[2] : "";
|
|
29
|
+
let re;
|
|
30
|
+
try {
|
|
31
|
+
re = new RegExp(pattern, flags);
|
|
32
|
+
} catch {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
return safeRegex(re) ? re : null;
|
|
36
|
+
}
|
|
37
|
+
/** True when the matcher carries at least one populated query key. */
|
|
38
|
+
function textMatchHasQuery(m) {
|
|
39
|
+
const populated = (v) => Array.isArray(v) ? v.length > 0 : v !== void 0 && v !== null;
|
|
40
|
+
return populated(m.contains) || populated(m.notContains) || populated(m.matches) || populated(m.notMatches);
|
|
41
|
+
}
|
|
42
|
+
/** Render the populated keys for a decision-trace `pattern` field. */
|
|
43
|
+
function describeTextMatch(m) {
|
|
44
|
+
const parts = [];
|
|
45
|
+
if (m.contains?.length) parts.push(`contains: [${m.contains.join(", ")}]`);
|
|
46
|
+
if (m.notContains?.length) parts.push(`notContains: [${m.notContains.join(", ")}]`);
|
|
47
|
+
if (m.matches?.length) parts.push(`matches: [${m.matches.join(", ")}]`);
|
|
48
|
+
if (m.notMatches?.length) parts.push(`notMatches: [${m.notMatches.join(", ")}]`);
|
|
49
|
+
if (m.ignoreCase) parts.push("ignoreCase");
|
|
50
|
+
return parts.length > 0 ? parts.join("; ") : "(no query)";
|
|
51
|
+
}
|
|
52
|
+
/** Evaluate every regex in `sources`; `expectMatch` selects matches vs notMatches. */
|
|
53
|
+
function evaluateRegexes(text, sources, expectMatch) {
|
|
54
|
+
for (const source of sources) {
|
|
55
|
+
const re = compileSafeRegex(source);
|
|
56
|
+
if (!re) return {
|
|
57
|
+
pass: false,
|
|
58
|
+
indeterminate: `unsafe or invalid regex: ${source}`
|
|
59
|
+
};
|
|
60
|
+
if (re.test(text) !== expectMatch) return { pass: false };
|
|
61
|
+
}
|
|
62
|
+
return { pass: true };
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Evaluate a text match. Every entry in every list is a conjunct, and every
|
|
66
|
+
* populated key ANDs with the others; an empty matcher passes.
|
|
67
|
+
*/
|
|
68
|
+
function evaluateTextMatch(text, m) {
|
|
69
|
+
const fold = (s) => m.ignoreCase === true ? s.toLowerCase() : s;
|
|
70
|
+
const haystack = fold(text);
|
|
71
|
+
for (const needle of m.contains ?? []) if (!haystack.includes(fold(needle))) return { pass: false };
|
|
72
|
+
for (const needle of m.notContains ?? []) if (haystack.includes(fold(needle))) return { pass: false };
|
|
73
|
+
if (m.matches?.length) {
|
|
74
|
+
const result = evaluateRegexes(text, m.matches, true);
|
|
75
|
+
if (!result.pass) return result;
|
|
76
|
+
}
|
|
77
|
+
if (m.notMatches?.length) {
|
|
78
|
+
const result = evaluateRegexes(text, m.notMatches, false);
|
|
79
|
+
if (!result.pass) return result;
|
|
80
|
+
}
|
|
81
|
+
return { pass: true };
|
|
82
|
+
}
|
|
83
|
+
//#endregion
|
|
84
|
+
export { compileSafeRegex, describeTextMatch, evaluateTextMatch, textMatchHasQuery };
|
|
85
|
+
|
|
86
|
+
//# sourceMappingURL=text-match.js.map
|
package/dist/trigger/types.d.ts
CHANGED
|
@@ -29,6 +29,15 @@
|
|
|
29
29
|
* Schema version 30 (BREAKING): renames job-level `environments` to `contexts`.
|
|
30
30
|
* Schema version 31 (additive): adds the workflows_failed_batch lock trigger.
|
|
31
31
|
* Schema version 32 (additive): adds LockJob.sandbox (per-job escape-hatch request).
|
|
32
|
+
* Schema version 33 (additive): adds `requires` (declarative static content filter) to the push/pr/tag git-event triggers.
|
|
33
|
+
* Schema version 34 (additive): adds LockWorkflow.hasFilter (workflow-level pre-dispatch filter predicate).
|
|
34
|
+
* Schema version 35 (additive): adds `commitMessage` (LockTextMatch) to the push/pr/tag
|
|
35
|
+
* git-event triggers, and contains/notContains/notMatches to LockContentRequirement.
|
|
36
|
+
* Schema version 36 (additive): adds LockJob.invoke (invokeSource gate, incl. optional).
|
|
37
|
+
* Schema version 37 (additive): adds LockJob.gitCredentials (named git credential refs).
|
|
38
|
+
* Schema version 38 (additive): adds container.auth (private-registry credentials for the job image).
|
|
39
|
+
* Schema version 39 (additive): adds container.dockerfile/context/target/args (build the
|
|
40
|
+
* job's image from a Dockerfile in the repo) and container.auth.registry.
|
|
32
41
|
*/
|
|
33
42
|
import { z } from 'zod';
|
|
34
43
|
import type { ProviderType } from '../provider/types.js';
|
|
@@ -41,7 +50,7 @@ import { ExecutionJobStatus } from '../protocol/messages/execution-status.js';
|
|
|
41
50
|
* schema change (additive or breaking); the bump-history comment above records
|
|
42
51
|
* which. See `BREAKING_FLOOR` for the compatibility-window semantics.
|
|
43
52
|
*/
|
|
44
|
-
export declare const SCHEMA_VERSION:
|
|
53
|
+
export declare const SCHEMA_VERSION: 39;
|
|
45
54
|
/**
|
|
46
55
|
* Oldest lock schema version this codebase can still read correctly — the lower
|
|
47
56
|
* bound of the acceptance window.
|
|
@@ -54,8 +63,8 @@ export declare const SCHEMA_VERSION: 32;
|
|
|
54
63
|
* Bump rule: move this to the current `SCHEMA_VERSION` ONLY in the commit that
|
|
55
64
|
* lands a `BREAKING` schema change (see the bump-history convention above). It
|
|
56
65
|
* currently sits at 30 because v30 (`environments`→`contexts`) was the most
|
|
57
|
-
* recent breaking bump; v31
|
|
58
|
-
* correctly.
|
|
66
|
+
* recent breaking bump; v31 through v35 were additive, so a v30 lock still
|
|
67
|
+
* reads correctly.
|
|
59
68
|
*/
|
|
60
69
|
export declare const BREAKING_FLOOR: 30;
|
|
61
70
|
/**
|
|
@@ -92,6 +101,121 @@ export interface LockBranchPattern {
|
|
|
92
101
|
readonly pattern: string;
|
|
93
102
|
readonly flags?: string;
|
|
94
103
|
}
|
|
104
|
+
/**
|
|
105
|
+
* A declarative query over one piece of text: literal substrings and/or a
|
|
106
|
+
* regex, in either direction. Pure DATA the orchestrator interprets — never
|
|
107
|
+
* author code — so it is safe to evaluate inside the orchestrator under the
|
|
108
|
+
* execution-purity model.
|
|
109
|
+
*
|
|
110
|
+
* Every entry in a list is a CONJUNCT: `contains: [a, b]` means the text
|
|
111
|
+
* contains `a` AND contains `b`. OR is expressed by declaring two triggers,
|
|
112
|
+
* since a workflow's trigger list is already "first match wins".
|
|
113
|
+
*
|
|
114
|
+
* This is the SDK-facing shape a workflow author writes; the compiler
|
|
115
|
+
* normalizes it to {@link LockTextMatch}.
|
|
116
|
+
*/
|
|
117
|
+
export interface TextMatch {
|
|
118
|
+
/** Literal substring(s). Every entry must be present. */
|
|
119
|
+
readonly contains?: string | readonly string[];
|
|
120
|
+
/** Literal substring(s). No entry may be present. */
|
|
121
|
+
readonly notContains?: string | readonly string[];
|
|
122
|
+
/** Regex(es), as a RegExp or a `/pattern/flags` string. Every one must match. */
|
|
123
|
+
readonly matches?: string | RegExp | readonly (string | RegExp)[];
|
|
124
|
+
/** Regex(es). None may match. */
|
|
125
|
+
readonly notMatches?: string | RegExp | readonly (string | RegExp)[];
|
|
126
|
+
/**
|
|
127
|
+
* Case-insensitive comparison for `contains`/`notContains` ONLY. Default false.
|
|
128
|
+
* It deliberately does not touch the regex keys: a regex already carries its
|
|
129
|
+
* own flags, and injecting `i` into a pattern whose author omitted it would
|
|
130
|
+
* silently change its meaning.
|
|
131
|
+
*/
|
|
132
|
+
readonly ignoreCase?: boolean;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Lock-file form of {@link TextMatch}. The compiler normalizes every key to a
|
|
136
|
+
* flat array, and every regex to a `/pattern/flags` string, so the orchestrator
|
|
137
|
+
* matcher has exactly one shape to interpret.
|
|
138
|
+
*/
|
|
139
|
+
export interface LockTextMatch {
|
|
140
|
+
readonly contains?: readonly string[];
|
|
141
|
+
readonly notContains?: readonly string[];
|
|
142
|
+
/** Always in `/pattern/flags` form. */
|
|
143
|
+
readonly matches?: readonly string[];
|
|
144
|
+
/** Always in `/pattern/flags` form. */
|
|
145
|
+
readonly notMatches?: readonly string[];
|
|
146
|
+
readonly ignoreCase?: boolean;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* How a file's bytes are parsed before a content query runs.
|
|
150
|
+
* `auto` picks by extension: `.json` → json, `.yaml`/`.yml` → yaml, else text.
|
|
151
|
+
*/
|
|
152
|
+
export type ContentFormat = 'json' | 'yaml' | 'text' | 'auto';
|
|
153
|
+
/**
|
|
154
|
+
* Declarative static content filter: a query over the bytes of one source file
|
|
155
|
+
* at the event's ref. Pure DATA the orchestrator's own matcher interprets — never
|
|
156
|
+
* author code — so it is safe to evaluate in the orchestrator (Part B of the
|
|
157
|
+
* execution-purity model). Query keys
|
|
158
|
+
* (`exists`/`match`/`not`/`contains`/`notContains`/`matches`/`notMatches`) are
|
|
159
|
+
* AND-ed within an entry; `absent` is mutually exclusive with them and passes
|
|
160
|
+
* only when the file is missing.
|
|
161
|
+
*
|
|
162
|
+
* This is the SDK-facing shape a workflow author writes, which accepts a scalar
|
|
163
|
+
* or `RegExp` where the lock form ({@link LockContentRequirement}) carries a flat
|
|
164
|
+
* array of `/pattern/flags` strings — the compiler normalizes one to the other.
|
|
165
|
+
*/
|
|
166
|
+
export interface ContentRequirement {
|
|
167
|
+
/** Repo-relative path of the file to query. */
|
|
168
|
+
readonly file: string;
|
|
169
|
+
/** Parse format; defaults to `auto` when unset. */
|
|
170
|
+
readonly format?: ContentFormat;
|
|
171
|
+
/** JSONPath expressions that must each resolve to ≥1 node (json/yaml only). */
|
|
172
|
+
readonly exists?: readonly string[];
|
|
173
|
+
/** JSONPath → expected-value map; every expression must match (json/yaml only). */
|
|
174
|
+
readonly match?: Record<string, unknown>;
|
|
175
|
+
/** JSONPath → value map; passes only when NONE match (json/yaml only). */
|
|
176
|
+
readonly not?: Record<string, unknown>;
|
|
177
|
+
/** Literal substring(s) that must ALL be present in the raw file text. */
|
|
178
|
+
readonly contains?: string | readonly string[];
|
|
179
|
+
/** Literal substring(s) of which NONE may be present in the raw file text. */
|
|
180
|
+
readonly notContains?: string | readonly string[];
|
|
181
|
+
/** Regex(es) that must ALL match the raw file text (RegExp or `/pattern/flags`). */
|
|
182
|
+
readonly matches?: string | RegExp | readonly (string | RegExp)[];
|
|
183
|
+
/** Regex(es) of which NONE may match the raw file text. */
|
|
184
|
+
readonly notMatches?: string | RegExp | readonly (string | RegExp)[];
|
|
185
|
+
/** Case-insensitive `contains`/`notContains`. Default false. */
|
|
186
|
+
readonly ignoreCase?: boolean;
|
|
187
|
+
/** When true, the entry passes only if the file is absent. Excludes all query keys. */
|
|
188
|
+
readonly absent?: boolean;
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Lock-file form of {@link ContentRequirement}. The compiler normalizes each
|
|
192
|
+
* raw-text key to the flat {@link LockTextMatch} shape, so the orchestrator
|
|
193
|
+
* matcher has one shape to interpret.
|
|
194
|
+
*/
|
|
195
|
+
export interface LockContentRequirement {
|
|
196
|
+
readonly file: string;
|
|
197
|
+
readonly format?: ContentFormat;
|
|
198
|
+
readonly exists?: readonly string[];
|
|
199
|
+
readonly match?: Record<string, unknown>;
|
|
200
|
+
readonly not?: Record<string, unknown>;
|
|
201
|
+
readonly contains?: readonly string[];
|
|
202
|
+
readonly notContains?: readonly string[];
|
|
203
|
+
readonly matches?: readonly string[];
|
|
204
|
+
readonly notMatches?: readonly string[];
|
|
205
|
+
readonly ignoreCase?: boolean;
|
|
206
|
+
readonly absent?: boolean;
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Resolve a content requirement's parse format to a concrete value. An explicit
|
|
210
|
+
* non-`auto` format is returned as-is; `auto` (or unset) is resolved by the file
|
|
211
|
+
* extension: `.json` → json, `.yaml`/`.yml` → yaml, everything else text.
|
|
212
|
+
*
|
|
213
|
+
* Yaml-free (pure string logic) so it lives in the browser-safe barrel and is
|
|
214
|
+
* the single source of truth for both the compiler's compile-time serializer and
|
|
215
|
+
* the orchestrator's eval-time matcher — the two can never disagree about how a
|
|
216
|
+
* file's format is picked.
|
|
217
|
+
*/
|
|
218
|
+
export declare function resolveContentFormat(file: string, format: ContentFormat | undefined): 'json' | 'yaml' | 'text';
|
|
95
219
|
/**
|
|
96
220
|
* PR trigger in lock file.
|
|
97
221
|
* Optimized for orchestrator event matching - flat structure with all filters accessible.
|
|
@@ -103,6 +227,10 @@ export interface LockPrTrigger {
|
|
|
103
227
|
readonly sourceBranches: readonly LockBranchPattern[];
|
|
104
228
|
readonly paths: readonly string[];
|
|
105
229
|
readonly repos?: readonly LockBranchPattern[];
|
|
230
|
+
/** Declarative static content filter over source files at the event ref (AND-ed). */
|
|
231
|
+
readonly requires?: readonly LockContentRequirement[];
|
|
232
|
+
/** Declarative static filter over the event's commit message / PR title+body. */
|
|
233
|
+
readonly commitMessage?: LockTextMatch;
|
|
106
234
|
}
|
|
107
235
|
/**
|
|
108
236
|
* Push trigger in lock file.
|
|
@@ -113,6 +241,10 @@ export interface LockPushTrigger {
|
|
|
113
241
|
readonly branches: readonly LockBranchPattern[];
|
|
114
242
|
readonly paths: readonly string[];
|
|
115
243
|
readonly repos?: readonly LockBranchPattern[];
|
|
244
|
+
/** Declarative static content filter over source files at the event ref (AND-ed). */
|
|
245
|
+
readonly requires?: readonly LockContentRequirement[];
|
|
246
|
+
/** Declarative static filter over the event's commit message / PR title+body. */
|
|
247
|
+
readonly commitMessage?: LockTextMatch;
|
|
116
248
|
}
|
|
117
249
|
/**
|
|
118
250
|
* Tag trigger in lock file.
|
|
@@ -122,6 +254,10 @@ export interface LockTagTrigger {
|
|
|
122
254
|
readonly _type: 'tag';
|
|
123
255
|
readonly patterns: readonly LockBranchPattern[];
|
|
124
256
|
readonly repos?: readonly LockBranchPattern[];
|
|
257
|
+
/** Declarative static content filter over source files at the event ref (AND-ed). */
|
|
258
|
+
readonly requires?: readonly LockContentRequirement[];
|
|
259
|
+
/** Declarative static filter over the event's commit message / PR title+body. */
|
|
260
|
+
readonly commitMessage?: LockTextMatch;
|
|
125
261
|
}
|
|
126
262
|
/**
|
|
127
263
|
* Comment trigger in lock file.
|
|
@@ -426,17 +562,27 @@ export type LockStepEntry = LockStep | LockParallelStep;
|
|
|
426
562
|
/** Type guard distinguishing a parallel group from an ordinary lock step. */
|
|
427
563
|
export declare function isLockParallelStep(entry: LockStepEntry): entry is LockParallelStep;
|
|
428
564
|
/**
|
|
429
|
-
*
|
|
430
|
-
*
|
|
431
|
-
*
|
|
432
|
-
*
|
|
433
|
-
*
|
|
565
|
+
* Serialized inline expression for a dynamic env/context/concurrencyGroup
|
|
566
|
+
* field, shaped as `{ _type: 'inline', expression: '(event) => ...' }`
|
|
567
|
+
* alongside the existing 'static' and 'dynamic' discriminants.
|
|
568
|
+
*
|
|
569
|
+
* @deprecated Schema v11 inline expressions are no longer evaluated in the
|
|
570
|
+
* orchestrator. Dynamic env/context/concurrencyGroup fields are resolved on the
|
|
571
|
+
* eval agent's init-runner. The compiler no longer emits this type; readers keep
|
|
572
|
+
* recognizing it only to defer an old lock's field to the init round. Removed at
|
|
573
|
+
* the next major (v1.0.0).
|
|
434
574
|
*/
|
|
435
575
|
export interface LockInlineValue {
|
|
436
576
|
readonly _type: 'inline';
|
|
437
577
|
readonly expression: string;
|
|
438
578
|
}
|
|
439
|
-
/**
|
|
579
|
+
/**
|
|
580
|
+
* Type guard for inline expression values.
|
|
581
|
+
*
|
|
582
|
+
* @deprecated See {@link LockInlineValue}. Retained only so a reader can
|
|
583
|
+
* recognize an old lock's inline field and defer it to the eval agent's
|
|
584
|
+
* init-runner. Removed at the next major (v1.0.0).
|
|
585
|
+
*/
|
|
440
586
|
export declare function isLockInlineValue(value: unknown): value is LockInlineValue;
|
|
441
587
|
/**
|
|
442
588
|
* Author-facing keyword sugar for a `needs` edge's run condition. Each keyword
|
|
@@ -595,9 +741,34 @@ export interface ResolvedSandboxGrant {
|
|
|
595
741
|
/** Run the container as this user (operator-config path only in Phase 2). */
|
|
596
742
|
user?: string;
|
|
597
743
|
}
|
|
744
|
+
/**
|
|
745
|
+
* Invoke-gate action carried on a lock job (compiled from `invokeSource()`).
|
|
746
|
+
* A job carrying this never runs steps on an agent: the orchestrator emits the
|
|
747
|
+
* named kici event at the source repo and gates on the runs it triggers.
|
|
748
|
+
*/
|
|
749
|
+
export interface LockInvoke {
|
|
750
|
+
/** The kici event name to emit; source-repo workflows subscribe with `kiciEvent({ name })`. */
|
|
751
|
+
readonly event: string;
|
|
752
|
+
/** Target scope. `'source'` targets exactly the source repo (the only v1 scope). */
|
|
753
|
+
readonly scope: 'source';
|
|
754
|
+
/** Optional event payload delivered to subscribers. */
|
|
755
|
+
readonly payload?: Readonly<Record<string, unknown>>;
|
|
756
|
+
/**
|
|
757
|
+
* When true, a zero-subscriber emit succeeds immediately (the repo may opt
|
|
758
|
+
* out). Absent/false (the default) fails the gate on zero subscribers.
|
|
759
|
+
*/
|
|
760
|
+
readonly optional?: boolean;
|
|
761
|
+
}
|
|
598
762
|
export interface LockJob {
|
|
599
763
|
readonly _type: 'static';
|
|
600
764
|
readonly name: string;
|
|
765
|
+
/**
|
|
766
|
+
* Invoke-gate action. When set, the job is a gate: it never dispatches steps
|
|
767
|
+
* to an agent; the orchestrator emits `invoke.event` at the source repo and
|
|
768
|
+
* tracks each triggered run as a proxy child. Additive — an older
|
|
769
|
+
* orchestrator that does not understand it ignores it (the gate stays inert).
|
|
770
|
+
*/
|
|
771
|
+
readonly invoke?: LockInvoke;
|
|
601
772
|
/** Single-agent targeting matchers. Absent when the job uses `runsOnAll` instead. */
|
|
602
773
|
readonly runsOn?: readonly LabelMatcher[];
|
|
603
774
|
readonly excludeLabels?: readonly LabelMatcher[];
|
|
@@ -607,6 +778,16 @@ export interface LockJob {
|
|
|
607
778
|
* `any` picks any available agent. Absent on a `runsOnAll` fan-out job.
|
|
608
779
|
*/
|
|
609
780
|
readonly runsOnPick?: RunsOnPick;
|
|
781
|
+
/**
|
|
782
|
+
* Named git credentials for this job, as SECRET NAMES in qualified
|
|
783
|
+
* `<context>:<secret-name>` form — never credential material.
|
|
784
|
+
*
|
|
785
|
+
* `default` is used when a call names no credential; any other key is
|
|
786
|
+
* referenced by name. Additive: an older orchestrator that does not
|
|
787
|
+
* understand it simply passes it through in `jobConfig`, and an older agent
|
|
788
|
+
* ignores it (git falls back to its own mechanisms, exactly as before).
|
|
789
|
+
*/
|
|
790
|
+
readonly gitCredentials?: Readonly<Record<string, Readonly<Record<string, string>>>>;
|
|
610
791
|
/**
|
|
611
792
|
* Host fan-out predicate (mutually exclusive with `runsOn`). When set, the job
|
|
612
793
|
* fans out to every roster host matching the predicate, one pinned child per host.
|
|
@@ -640,21 +821,28 @@ export interface LockJob {
|
|
|
640
821
|
readonly rules?: readonly LockRule[];
|
|
641
822
|
readonly description?: string;
|
|
642
823
|
/**
|
|
643
|
-
* Bound contexts in merge order. Each entry is a static name
|
|
644
|
-
*
|
|
645
|
-
*
|
|
824
|
+
* Bound contexts in merge order. Each entry is a static name; `dynamic` is set
|
|
825
|
+
* when it is a function resolved on the eval agent's init-runner. Later entries
|
|
826
|
+
* override earlier ones on name collisions. The `LockInlineValue` shape is a
|
|
827
|
+
* deprecated form still accepted from old locks (see {@link LockInlineValue}).
|
|
646
828
|
*/
|
|
647
829
|
readonly contexts?: ReadonlyArray<{
|
|
648
830
|
value: string | LockInlineValue;
|
|
649
831
|
dynamic: boolean;
|
|
650
832
|
}>;
|
|
651
|
-
/**
|
|
833
|
+
/**
|
|
834
|
+
* Static environment variables. A deprecated `LockInlineValue` shape is still
|
|
835
|
+
* accepted from old locks (see {@link LockInlineValue}).
|
|
836
|
+
*/
|
|
652
837
|
readonly env?: Record<string, string> | LockInlineValue;
|
|
653
|
-
/** When true, env is dynamic (function) -- resolved
|
|
838
|
+
/** When true, env is dynamic (function) -- resolved on the eval agent's init-runner. */
|
|
654
839
|
readonly dynamicEnv?: boolean;
|
|
655
|
-
/**
|
|
840
|
+
/**
|
|
841
|
+
* Concurrency group name (static string). A deprecated `LockInlineValue` shape
|
|
842
|
+
* is still accepted from old locks (see {@link LockInlineValue}).
|
|
843
|
+
*/
|
|
656
844
|
readonly concurrencyGroup?: string | LockInlineValue;
|
|
657
|
-
/** When true, concurrencyGroup is dynamic (function) -- resolved
|
|
845
|
+
/** When true, concurrencyGroup is dynamic (function) -- resolved on the eval agent's init-runner. */
|
|
658
846
|
readonly dynamicConcurrencyGroup?: boolean;
|
|
659
847
|
/** Total job wall-clock timeout in milliseconds (init + all steps + hooks). Threaded to the agent via jobConfig. */
|
|
660
848
|
readonly timeout?: number;
|
|
@@ -666,15 +854,55 @@ export interface LockJob {
|
|
|
666
854
|
readonly resources?: import('../scaler/resource-types.js').ResourceRequest;
|
|
667
855
|
/**
|
|
668
856
|
* Container image selecting the container execution backend on the agent. A
|
|
669
|
-
* bare image string or an object
|
|
670
|
-
*
|
|
671
|
-
*
|
|
672
|
-
*
|
|
673
|
-
*
|
|
857
|
+
* bare image string, or an object naming exactly one image source: a
|
|
858
|
+
* finalized `image`, or a `dockerfile` the agent builds from the cloned tree
|
|
859
|
+
* before the job starts. When set, the agent's `determineExecutionMode`
|
|
860
|
+
* routes the job to the container sandbox (top priority), so the orchestrator
|
|
861
|
+
* threads it through dispatch as `jobConfig.container`. (Shape mirrors the SDK
|
|
862
|
+
* `string | ContainerConfig`, including `ContainerRegistryAuth`; the engine
|
|
863
|
+
* cannot import the SDK, so it is inlined here.)
|
|
674
864
|
*/
|
|
675
865
|
readonly container?: string | {
|
|
676
|
-
|
|
866
|
+
/** Finalized image to pull. Exactly one of `image` / `dockerfile` is set. */
|
|
867
|
+
readonly image?: string;
|
|
868
|
+
/**
|
|
869
|
+
* Repo-relative Dockerfile the agent builds before the job runs.
|
|
870
|
+
*
|
|
871
|
+
* The agent re-validates this path against the resolved workdir: a lock
|
|
872
|
+
* file is repo content, so a path that escapes the tree must be refused
|
|
873
|
+
* on the agent too, not only by the SDK that wrote it.
|
|
874
|
+
*/
|
|
875
|
+
readonly dockerfile?: string;
|
|
876
|
+
/** Repo-relative build context. Defaults to the repository root. */
|
|
877
|
+
readonly context?: string;
|
|
878
|
+
/** Build stage to stop at. */
|
|
879
|
+
readonly target?: string;
|
|
880
|
+
/**
|
|
881
|
+
* Build arguments. Plain strings — never secret references, because a
|
|
882
|
+
* build argument is recorded in the built image's history.
|
|
883
|
+
*/
|
|
884
|
+
readonly args?: Record<string, string>;
|
|
677
885
|
readonly env?: Record<string, string>;
|
|
886
|
+
/**
|
|
887
|
+
* Private-registry credentials for pulling `image`.
|
|
888
|
+
*
|
|
889
|
+
* Flattened `Sourced<Name>` pairs: exactly one half of each pair is
|
|
890
|
+
* set — `*Secret` names a `<context>:<secret-name>` entry to resolve,
|
|
891
|
+
* `*Value` carries material supplied at run time.
|
|
892
|
+
*/
|
|
893
|
+
readonly auth?: {
|
|
894
|
+
readonly username?: string;
|
|
895
|
+
readonly usernameSecret?: string;
|
|
896
|
+
readonly usernameValue?: string;
|
|
897
|
+
readonly tokenSecret?: string;
|
|
898
|
+
readonly tokenValue?: string;
|
|
899
|
+
/**
|
|
900
|
+
* Registry host the credentials belong to. Derived from `image` when
|
|
901
|
+
* one is set; REQUIRED with `dockerfile`, whose base image is named
|
|
902
|
+
* inside the Dockerfile and cannot be read back out reliably.
|
|
903
|
+
*/
|
|
904
|
+
readonly registry?: string;
|
|
905
|
+
};
|
|
678
906
|
};
|
|
679
907
|
/**
|
|
680
908
|
* Workflow-declared per-job sandbox escape-hatch request (container jobs
|
|
@@ -769,6 +997,13 @@ export interface LockWorkflow {
|
|
|
769
997
|
readonly timeout?: number;
|
|
770
998
|
/** Normalized approval gate; when set the whole run is held before any job dispatches. */
|
|
771
999
|
readonly approval?: LockApproval;
|
|
1000
|
+
/**
|
|
1001
|
+
* True when the workflow declares a `filter` predicate. A bare flag, not a
|
|
1002
|
+
* source reference: `LockWorkflow.source` already identifies the module and
|
|
1003
|
+
* export, so the eval agent loads it and reads `.filter` off the workflow
|
|
1004
|
+
* object. Mirrors the `dynamicEnv` / `dynamicConcurrencyGroup` convention.
|
|
1005
|
+
*/
|
|
1006
|
+
readonly hasFilter?: boolean;
|
|
772
1007
|
}
|
|
773
1008
|
/**
|
|
774
1009
|
* Complete lock file structure.
|
|
@@ -783,7 +1018,7 @@ export interface LockWorkflow {
|
|
|
783
1018
|
* v8 adds runsOn polymorphic type (string | string[] | selector) and excludeLabels.
|
|
784
1019
|
* v9 adds repos/notRepos repo pattern fields to git-event triggers for global workflow matching.
|
|
785
1020
|
* v10 removes notRepos/notPaths fields; negative patterns use ! prefix in repos/paths arrays.
|
|
786
|
-
* v11 adds LockInlineValue type
|
|
1021
|
+
* v11 adds the LockInlineValue type (deprecated; inline dynamic fields are resolved on the eval agent).
|
|
787
1022
|
* v12 adds workflow-level registries and installEnv for private npm registry auth.
|
|
788
1023
|
* v13 adds job-level and workflow-level timeout.
|
|
789
1024
|
*/
|
|
@@ -869,6 +1104,13 @@ export interface SimulatedEvent {
|
|
|
869
1104
|
* to the previous owner.
|
|
870
1105
|
*/
|
|
871
1106
|
senderUserId?: string;
|
|
1107
|
+
/**
|
|
1108
|
+
* Text a `commitMessage` trigger filter is tested against: the full head-commit
|
|
1109
|
+
* message for push/tag, or PR title + body for pull-request events. Absent when
|
|
1110
|
+
* the provider payload carries none — which a `commitMessage` filter treats as
|
|
1111
|
+
* INDETERMINATE (fail-visible), never as an empty string.
|
|
1112
|
+
*/
|
|
1113
|
+
commitMessage?: string;
|
|
872
1114
|
/** Repository identifier where the event occurred (e.g., "owner/repo").
|
|
873
1115
|
* Used by global workflow repo pattern matching. */
|
|
874
1116
|
sourceRepo?: string;
|