@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.
Files changed (81) hide show
  1. package/dist/audit/access-log-policy.js +1 -0
  2. package/dist/audit/retention-policy.js +2 -0
  3. package/dist/context/held-run-job-id.d.ts +26 -10
  4. package/dist/context/held-run-job-id.js +30 -11
  5. package/dist/context/host-match.js +2 -1
  6. package/dist/context/index.d.ts +1 -1
  7. package/dist/context/index.js +3 -3
  8. package/dist/context/types.d.ts +10 -1
  9. package/dist/context/types.js +10 -1
  10. package/dist/index.d.ts +6 -2
  11. package/dist/index.js +17 -12
  12. package/dist/labels/compile.d.ts +2 -7
  13. package/dist/labels/compile.js +1 -10
  14. package/dist/labels.d.ts +74 -12
  15. package/dist/labels.js +82 -17
  16. package/dist/mcp/held-run-resolve.d.ts +40 -0
  17. package/dist/mcp/held-run-resolve.js +68 -15
  18. package/dist/mcp/tool-schemas.d.ts +4 -0
  19. package/dist/mcp/tool-schemas.js +13 -1
  20. package/dist/metrics/catalog-policy.d.ts +17 -3
  21. package/dist/metrics/catalog-policy.js +44 -13
  22. package/dist/metrics/metric-catalog.generated.d.ts +140 -0
  23. package/dist/metrics/metric-catalog.generated.js +168 -0
  24. package/dist/protocol/dashboard-global-workflows.js +2 -2
  25. package/dist/protocol/event-log-payload.js +1 -1
  26. package/dist/protocol/messages/access-log.d.ts +5 -0
  27. package/dist/protocol/messages/access-log.js +1 -0
  28. package/dist/protocol/messages/actor.d.ts +13 -2
  29. package/dist/protocol/messages/actor.js +16 -5
  30. package/dist/protocol/messages/common.js +1 -1
  31. package/dist/protocol/messages/dashboard-global-workflows.d.ts +29 -3
  32. package/dist/protocol/messages/dashboard-global-workflows.js +48 -4
  33. package/dist/protocol/messages/dashboard.d.ts +48 -7
  34. package/dist/protocol/messages/dashboard.js +62 -6
  35. package/dist/protocol/messages/execution-status.d.ts +44 -0
  36. package/dist/protocol/messages/execution-status.js +69 -2
  37. package/dist/protocol/messages/git-credential-relay.d.ts +78 -0
  38. package/dist/protocol/messages/git-credential-relay.js +86 -0
  39. package/dist/protocol/messages/orchestrator-agent.d.ts +138 -0
  40. package/dist/protocol/messages/orchestrator-agent.js +131 -3
  41. package/dist/protocol/messages/peer.d.ts +7 -0
  42. package/dist/protocol/messages/peer.js +18 -1
  43. package/dist/protocol/messages/platform-orchestrator.d.ts +155 -2
  44. package/dist/protocol/messages/platform-orchestrator.js +178 -19
  45. package/dist/protocol/version.d.ts +19 -2
  46. package/dist/protocol/version.js +20 -3
  47. package/dist/provenance/verify.js +11 -10
  48. package/dist/provider/check-status-poster.d.ts +37 -2
  49. package/dist/provider/contributor-resolver.d.ts +11 -3
  50. package/dist/provider/file-contents-fetcher.d.ts +39 -0
  51. package/dist/provider/file-contents-fetcher.js +2 -0
  52. package/dist/provider/git-credential.d.ts +77 -0
  53. package/dist/provider/git-credential.js +10 -0
  54. package/dist/provider/index.d.ts +4 -0
  55. package/dist/provider/index.js +2 -1
  56. package/dist/provider/webhook-normalizer.d.ts +12 -12
  57. package/dist/repo/pattern-negation.d.ts +73 -0
  58. package/dist/repo/pattern-negation.js +86 -0
  59. package/dist/safe-regex.d.ts +16 -0
  60. package/dist/safe-regex.js +24 -0
  61. package/dist/scaler/registry-auth.d.ts +18 -0
  62. package/dist/scaler/registry-auth.js +28 -0
  63. package/dist/scaler/scaler-backend-type.d.ts +35 -0
  64. package/dist/scaler/scaler-backend-type.js +39 -2
  65. package/dist/scaler/scaler-events.d.ts +79 -0
  66. package/dist/scaler/scaler-events.js +87 -0
  67. package/dist/trigger/compiled-matchers.d.ts +21 -1
  68. package/dist/trigger/compiled-matchers.js +30 -3
  69. package/dist/trigger/content-requirements.d.ts +31 -0
  70. package/dist/trigger/content-requirements.js +125 -0
  71. package/dist/trigger/decision-trace.d.ts +168 -0
  72. package/dist/trigger/decision-trace.js +207 -4
  73. package/dist/trigger/jsonpath-matcher.js +5 -1
  74. package/dist/trigger/matcher.js +61 -10
  75. package/dist/trigger/text-match.d.ts +27 -0
  76. package/dist/trigger/text-match.js +86 -0
  77. package/dist/trigger/types.d.ts +265 -23
  78. package/dist/trigger/types.js +37 -5
  79. package/dist/ws/rate-limiter.js +3 -3
  80. package/package.json +20 -3
  81. package/sbom.spdx.json +40 -15
@@ -0,0 +1,73 @@
1
+ /**
2
+ * The one classifier for "picomatch would read this repo pattern as a
3
+ * negation".
4
+ *
5
+ * Repo patterns are written on lists whose direction is already fixed by the
6
+ * list itself — a role's allowed repositories, a global-workflow allow list, a
7
+ * global-workflow deny list. A pattern picomatch reads as a negation inverts
8
+ * that direction inside a single entry, so an entry that reads as a restriction
9
+ * matches as its complement. On an allow list that grants almost everything; on
10
+ * a deny list it admits the one repository the entry named.
11
+ *
12
+ * This lives in the engine, and not beside either consumer, because two
13
+ * hand-maintained ban lists for one pattern language cannot be kept in step.
14
+ * The two ways they drift apart are both live hazards: a list that misses the
15
+ * regular-expression assertions accepts a real inversion, and a list that
16
+ * refuses `[!…]` turns away a genuine restriction. Every surface that stores a
17
+ * repo pattern reads its verdict from here, so neither can happen on one
18
+ * surface alone.
19
+ */
20
+ /**
21
+ * The regular-expression negations picomatch passes through into the compiled
22
+ * matcher: the negative lookahead `(?!…)` and the negative lookbehind `(?<!…)`.
23
+ * The optional `<` is what makes one pattern cover both; the positive `(?=…)`,
24
+ * `(?<=…)`, `(?:…)` and a plain capture group are deliberately not matched.
25
+ */
26
+ export declare const REGEX_NEGATIVE_ASSERTION: RegExp;
27
+ /**
28
+ * Why picomatch would read `pattern` as a negation, or null when it would not.
29
+ *
30
+ * Four arms, because picomatch reads four negation forms, each of which turns a
31
+ * pattern that reads as a restriction into a grant.
32
+ *
33
+ * A leading `!` negates the whole pattern. The extglob complement `!(…)`
34
+ * negates wherever it appears, so `org/!(secret)` covers every repository under
35
+ * `org/` except that one — the same defect in a prefix-scoped shape. The
36
+ * negated character class `[^…]` does it one character at a time: `org/[^s]*`
37
+ * covers every repository under `org/` whose name does not begin with `s`. The
38
+ * negative assertions are the widest of the four, because they can spell a
39
+ * whole repository identifier rather than one character: picomatch compiles a
40
+ * pattern to a regular expression and passes a group it does not recognise
41
+ * through verbatim, so `(?!org/secret)**` reaches the matcher as a real
42
+ * lookahead and matches every repository in every organization except the one
43
+ * it names.
44
+ *
45
+ * The extglob arm matches the two-character sequence `!(` and nothing wider:
46
+ * `*(`, `+(`, `@(` and `?(` are the non-complementing extglob heads and do not
47
+ * invert, so rejecting a bare `(` would refuse four harmless forms for no gain.
48
+ * A `(` cannot appear in a repository identifier, so no legitimate pattern
49
+ * contains `!(`. The assertion arm is narrow for the same reason: `(?=…)`,
50
+ * `(?<=…)`, `(?:…)` and a plain capture group match strictly what they name, so
51
+ * only the two negative forms are refused.
52
+ *
53
+ * The character-class arm matches `[^` and nothing wider: a `[` cannot appear
54
+ * in a repository identifier either, and a bracket that is not a negation —
55
+ * `org/[abc]*` — is a legitimate restriction. It matches `[^` and NOT `[!`:
56
+ * picomatch does not read `[!…]` as the POSIX negation. It reads it as a
57
+ * literal class containing `!` and the listed characters, so `org/[!s]*`
58
+ * matches exactly the repositories whose name begins with `!` or `s` — the
59
+ * exact inverse of `org/[^s]*`, and a genuine restriction. Rejecting it would
60
+ * refuse a pattern that grants strictly less than it names while leaving the
61
+ * real inversion open.
62
+ *
63
+ * A bare `!` is different — it *can* appear in a repository name — so the first
64
+ * arm stays anchored: `org/we!rd` is a legitimate literal, and an
65
+ * `includes('!')` check would silently reject a valid repository name.
66
+ */
67
+ export declare function negatedPatternReason(pattern: string): string | null;
68
+ /**
69
+ * True when `pattern` is a picomatch negation — whole-pattern `!…`, extglob
70
+ * `!(…)`, negated character class `[^…]`, or a negative lookahead / lookbehind.
71
+ */
72
+ export declare function isNegatedPattern(pattern: string): boolean;
73
+ //# sourceMappingURL=pattern-negation.d.ts.map
@@ -0,0 +1,86 @@
1
+ import "../rolldown-runtime-ClRpJifh.js";
2
+ //#region src/repo/pattern-negation.ts
3
+ /**
4
+ * The one classifier for "picomatch would read this repo pattern as a
5
+ * negation".
6
+ *
7
+ * Repo patterns are written on lists whose direction is already fixed by the
8
+ * list itself — a role's allowed repositories, a global-workflow allow list, a
9
+ * global-workflow deny list. A pattern picomatch reads as a negation inverts
10
+ * that direction inside a single entry, so an entry that reads as a restriction
11
+ * matches as its complement. On an allow list that grants almost everything; on
12
+ * a deny list it admits the one repository the entry named.
13
+ *
14
+ * This lives in the engine, and not beside either consumer, because two
15
+ * hand-maintained ban lists for one pattern language cannot be kept in step.
16
+ * The two ways they drift apart are both live hazards: a list that misses the
17
+ * regular-expression assertions accepts a real inversion, and a list that
18
+ * refuses `[!…]` turns away a genuine restriction. Every surface that stores a
19
+ * repo pattern reads its verdict from here, so neither can happen on one
20
+ * surface alone.
21
+ */
22
+ /**
23
+ * The regular-expression negations picomatch passes through into the compiled
24
+ * matcher: the negative lookahead `(?!…)` and the negative lookbehind `(?<!…)`.
25
+ * The optional `<` is what makes one pattern cover both; the positive `(?=…)`,
26
+ * `(?<=…)`, `(?:…)` and a plain capture group are deliberately not matched.
27
+ */
28
+ const REGEX_NEGATIVE_ASSERTION = /\(\?<?!/;
29
+ /**
30
+ * Why picomatch would read `pattern` as a negation, or null when it would not.
31
+ *
32
+ * Four arms, because picomatch reads four negation forms, each of which turns a
33
+ * pattern that reads as a restriction into a grant.
34
+ *
35
+ * A leading `!` negates the whole pattern. The extglob complement `!(…)`
36
+ * negates wherever it appears, so `org/!(secret)` covers every repository under
37
+ * `org/` except that one — the same defect in a prefix-scoped shape. The
38
+ * negated character class `[^…]` does it one character at a time: `org/[^s]*`
39
+ * covers every repository under `org/` whose name does not begin with `s`. The
40
+ * negative assertions are the widest of the four, because they can spell a
41
+ * whole repository identifier rather than one character: picomatch compiles a
42
+ * pattern to a regular expression and passes a group it does not recognise
43
+ * through verbatim, so `(?!org/secret)**` reaches the matcher as a real
44
+ * lookahead and matches every repository in every organization except the one
45
+ * it names.
46
+ *
47
+ * The extglob arm matches the two-character sequence `!(` and nothing wider:
48
+ * `*(`, `+(`, `@(` and `?(` are the non-complementing extglob heads and do not
49
+ * invert, so rejecting a bare `(` would refuse four harmless forms for no gain.
50
+ * A `(` cannot appear in a repository identifier, so no legitimate pattern
51
+ * contains `!(`. The assertion arm is narrow for the same reason: `(?=…)`,
52
+ * `(?<=…)`, `(?:…)` and a plain capture group match strictly what they name, so
53
+ * only the two negative forms are refused.
54
+ *
55
+ * The character-class arm matches `[^` and nothing wider: a `[` cannot appear
56
+ * in a repository identifier either, and a bracket that is not a negation —
57
+ * `org/[abc]*` — is a legitimate restriction. It matches `[^` and NOT `[!`:
58
+ * picomatch does not read `[!…]` as the POSIX negation. It reads it as a
59
+ * literal class containing `!` and the listed characters, so `org/[!s]*`
60
+ * matches exactly the repositories whose name begins with `!` or `s` — the
61
+ * exact inverse of `org/[^s]*`, and a genuine restriction. Rejecting it would
62
+ * refuse a pattern that grants strictly less than it names while leaving the
63
+ * real inversion open.
64
+ *
65
+ * A bare `!` is different — it *can* appear in a repository name — so the first
66
+ * arm stays anchored: `org/we!rd` is a legitimate literal, and an
67
+ * `includes('!')` check would silently reject a valid repository name.
68
+ */
69
+ function negatedPatternReason(pattern) {
70
+ if (pattern.startsWith("!")) return "negation ('!' prefix)";
71
+ if (pattern.includes("!(")) return "extglob negation ('!(…)')";
72
+ if (pattern.includes("[^")) return "character-class negation ('[^…]')";
73
+ if (REGEX_NEGATIVE_ASSERTION.test(pattern)) return "negative assertion ('(?!…)' / '(?<!…)')";
74
+ return null;
75
+ }
76
+ /**
77
+ * True when `pattern` is a picomatch negation — whole-pattern `!…`, extglob
78
+ * `!(…)`, negated character class `[^…]`, or a negative lookahead / lookbehind.
79
+ */
80
+ function isNegatedPattern(pattern) {
81
+ return negatedPatternReason(pattern) !== null;
82
+ }
83
+ //#endregion
84
+ export { REGEX_NEGATIVE_ASSERTION, isNegatedPattern, negatedPatternReason };
85
+
86
+ //# sourceMappingURL=pattern-negation.js.map
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Reject a ReDoS-prone author-supplied regex before it is compiled.
3
+ *
4
+ * `safe-regex` is a star-height heuristic. The orchestrator is single-tenant, so
5
+ * a slipped-through pattern only stalls the author's own orchestrator — but every
6
+ * author regex the orchestrator compiles from lock-file data on the webhook path
7
+ * (label selectors, branch/tag/repo patterns, embedded JSONPath `/re/flags`,
8
+ * comment `bodyMatch`) must be checked so a catastrophic pattern is rejected at
9
+ * compile/registration time rather than silently compiled. Globs are linear by
10
+ * construction but pass through here for uniformity.
11
+ *
12
+ * `ctx` is a human label (e.g. "branch pattern", "job 'web' runsOn") woven into
13
+ * the thrown error so an operator can identify the offending pattern.
14
+ */
15
+ export declare function assertSafeRegex(source: string, flags: string, ctx: string): void;
16
+ //# sourceMappingURL=safe-regex.d.ts.map
@@ -0,0 +1,24 @@
1
+ import "./rolldown-runtime-ClRpJifh.js";
2
+ import safeRegex from "safe-regex";
3
+ //#region src/safe-regex.ts
4
+ /**
5
+ * Reject a ReDoS-prone author-supplied regex before it is compiled.
6
+ *
7
+ * `safe-regex` is a star-height heuristic. The orchestrator is single-tenant, so
8
+ * a slipped-through pattern only stalls the author's own orchestrator — but every
9
+ * author regex the orchestrator compiles from lock-file data on the webhook path
10
+ * (label selectors, branch/tag/repo patterns, embedded JSONPath `/re/flags`,
11
+ * comment `bodyMatch`) must be checked so a catastrophic pattern is rejected at
12
+ * compile/registration time rather than silently compiled. Globs are linear by
13
+ * construction but pass through here for uniformity.
14
+ *
15
+ * `ctx` is a human label (e.g. "branch pattern", "job 'web' runsOn") woven into
16
+ * the thrown error so an operator can identify the offending pattern.
17
+ */
18
+ function assertSafeRegex(source, flags, ctx) {
19
+ if (!safeRegex(new RegExp(source, flags))) throw new Error(`${ctx}: regex /${source}/${flags} is ReDoS-prone — rejected`);
20
+ }
21
+ //#endregion
22
+ export { assertSafeRegex };
23
+
24
+ //# sourceMappingURL=safe-regex.js.map
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Registry-host extraction for container image references.
3
+ *
4
+ * Lives in the engine because three sites need the same answer: the agent's
5
+ * container sandbox, the container scaler backend, and the bare-metal backend
6
+ * in container mode. A private pull authenticates against the registry HOST,
7
+ * which is not a field of the image ref — it has to be derived from it.
8
+ */
9
+ /**
10
+ * Registry host (a container runtime's `authconfig.serveraddress`) for an image ref.
11
+ *
12
+ * Docker's own rule: the first path segment is the registry only when it looks
13
+ * like a host — it contains a dot or a colon, or it is exactly `localhost`.
14
+ * Otherwise the ref is a Docker Hub short name (`nginx`, `acme/ci`) and the
15
+ * registry is `docker.io`.
16
+ */
17
+ export declare function registryHostFromImageRef(image: string): string;
18
+ //# sourceMappingURL=registry-auth.d.ts.map
@@ -0,0 +1,28 @@
1
+ import "../rolldown-runtime-ClRpJifh.js";
2
+ //#region src/scaler/registry-auth.ts
3
+ /**
4
+ * Registry-host extraction for container image references.
5
+ *
6
+ * Lives in the engine because three sites need the same answer: the agent's
7
+ * container sandbox, the container scaler backend, and the bare-metal backend
8
+ * in container mode. A private pull authenticates against the registry HOST,
9
+ * which is not a field of the image ref — it has to be derived from it.
10
+ */
11
+ /**
12
+ * Registry host (a container runtime's `authconfig.serveraddress`) for an image ref.
13
+ *
14
+ * Docker's own rule: the first path segment is the registry only when it looks
15
+ * like a host — it contains a dot or a colon, or it is exactly `localhost`.
16
+ * Otherwise the ref is a Docker Hub short name (`nginx`, `acme/ci`) and the
17
+ * registry is `docker.io`.
18
+ */
19
+ function registryHostFromImageRef(image) {
20
+ const firstSlash = image.indexOf("/");
21
+ if (firstSlash === -1) return "docker.io";
22
+ const candidate = image.slice(0, firstSlash);
23
+ return candidate.includes(".") || candidate.includes(":") || candidate === "localhost" ? candidate : "docker.io";
24
+ }
25
+ //#endregion
26
+ export { registryHostFromImageRef };
27
+
28
+ //# sourceMappingURL=registry-auth.js.map
@@ -9,8 +9,43 @@ import { z } from 'zod';
9
9
  export declare const ScalerBackendType: z.ZodEnum<{
10
10
  "bare-metal": "bare-metal";
11
11
  container: "container";
12
+ event: "event";
12
13
  firecracker: "firecracker";
13
14
  kubernetes: "kubernetes";
14
15
  }>;
15
16
  export type ScalerBackendType = z.infer<typeof ScalerBackendType>;
17
+ /**
18
+ * Reserved event-name prefix for KiCI-internal system events (today: the event
19
+ * scaler's scale-up / scale-down events). Custom events emitted from user
20
+ * workflow steps (`ctx.emit(...)`) MUST NOT use this prefix — both the SDK
21
+ * (client-side) and the orchestrator (authoritative) reject a name that starts
22
+ * with it, so a user step cannot forge a system event. The rate limiter also
23
+ * exempts it. Defined in `@kici-dev/engine` so the SDK and the orchestrator
24
+ * share one source of truth without the SDK importing the orchestrator.
25
+ */
26
+ export declare const KICI_EVENT_NAME_PREFIX = "kici.";
27
+ /**
28
+ * Reserved event-name prefix for the events the ORCHESTRATOR mints for itself
29
+ * (`__schedule_fire`, `__workflow_complete`, `__job_complete`,
30
+ * `__workflows_failed_batch`).
31
+ *
32
+ * Reserved for the same reason as {@link KICI_EVENT_NAME_PREFIX}, and more
33
+ * sharply: every name under this prefix is exempt from the event-storm rate
34
+ * limiter, and `__schedule_fire` is additionally classified as a TRUSTED ref —
35
+ * no run causes it, so nothing external shaped it. The other three ARE caused
36
+ * by runs and inherit the tier of the run (or, for the failure batch, the most
37
+ * restrictive tier across the runs) behind them, so they forge no privilege on
38
+ * their own. A user step that could emit any of them would forge the
39
+ * rate-limiter exemption, and `__schedule_fire` the trusted classification on
40
+ * top of it — so the same two-sided reservation applies to the whole prefix,
41
+ * SDK first and orchestrator authoritatively.
42
+ */
43
+ export declare const INTERNAL_EVENT_NAME_PREFIX = "__";
44
+ /**
45
+ * The reserved prefix `eventName` uses, or `undefined` when a user step may
46
+ * emit it. One definition of "reserved", so the SDK-side check and the
47
+ * orchestrator's authoritative backstop can never disagree about which names a
48
+ * workflow may emit.
49
+ */
50
+ export declare function reservedEventNamePrefix(eventName: string): string | undefined;
16
51
  //# sourceMappingURL=scaler-backend-type.d.ts.map
@@ -12,9 +12,46 @@ const ScalerBackendType = z.enum([
12
12
  "container",
13
13
  "bare-metal",
14
14
  "firecracker",
15
- "kubernetes"
15
+ "kubernetes",
16
+ "event"
16
17
  ]);
18
+ /**
19
+ * Reserved event-name prefix for KiCI-internal system events (today: the event
20
+ * scaler's scale-up / scale-down events). Custom events emitted from user
21
+ * workflow steps (`ctx.emit(...)`) MUST NOT use this prefix — both the SDK
22
+ * (client-side) and the orchestrator (authoritative) reject a name that starts
23
+ * with it, so a user step cannot forge a system event. The rate limiter also
24
+ * exempts it. Defined in `@kici-dev/engine` so the SDK and the orchestrator
25
+ * share one source of truth without the SDK importing the orchestrator.
26
+ */
27
+ const KICI_EVENT_NAME_PREFIX = "kici.";
28
+ /**
29
+ * Reserved event-name prefix for the events the ORCHESTRATOR mints for itself
30
+ * (`__schedule_fire`, `__workflow_complete`, `__job_complete`,
31
+ * `__workflows_failed_batch`).
32
+ *
33
+ * Reserved for the same reason as {@link KICI_EVENT_NAME_PREFIX}, and more
34
+ * sharply: every name under this prefix is exempt from the event-storm rate
35
+ * limiter, and `__schedule_fire` is additionally classified as a TRUSTED ref —
36
+ * no run causes it, so nothing external shaped it. The other three ARE caused
37
+ * by runs and inherit the tier of the run (or, for the failure batch, the most
38
+ * restrictive tier across the runs) behind them, so they forge no privilege on
39
+ * their own. A user step that could emit any of them would forge the
40
+ * rate-limiter exemption, and `__schedule_fire` the trusted classification on
41
+ * top of it — so the same two-sided reservation applies to the whole prefix,
42
+ * SDK first and orchestrator authoritatively.
43
+ */
44
+ const INTERNAL_EVENT_NAME_PREFIX = "__";
45
+ /**
46
+ * The reserved prefix `eventName` uses, or `undefined` when a user step may
47
+ * emit it. One definition of "reserved", so the SDK-side check and the
48
+ * orchestrator's authoritative backstop can never disagree about which names a
49
+ * workflow may emit.
50
+ */
51
+ function reservedEventNamePrefix(eventName) {
52
+ for (const prefix of [KICI_EVENT_NAME_PREFIX, "__"]) if (eventName.startsWith(prefix)) return prefix;
53
+ }
17
54
  //#endregion
18
- export { ScalerBackendType };
55
+ export { INTERNAL_EVENT_NAME_PREFIX, KICI_EVENT_NAME_PREFIX, ScalerBackendType, reservedEventNamePrefix };
19
56
 
20
57
  //# sourceMappingURL=scaler-backend-type.js.map
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Shared schemas and constants for the event scaler backend.
3
+ *
4
+ * The event scaler performs no local compute: its `spawn()` / `destroy()` emit
5
+ * reserved `kici.`-prefixed custom events (`kici.scaler.scale-up` /
6
+ * `kici.scaler.scale-down`) that a customer-authored provisioning / teardown
7
+ * workflow consumes via the `kiciEvent()` trigger. These schemas define the
8
+ * event payloads and the single source of truth for the reserved event names.
9
+ *
10
+ * They live here, not in the orchestrator, because both sides of the contract
11
+ * need them: the orchestrator emits, and a workflow file — which may import
12
+ * `@kici-dev/sdk` and nothing else — consumes. Engine is the only package both
13
+ * the SDK and the orchestrator depend on, so it is the shared floor. The SDK
14
+ * re-exports all four symbols; the orchestrator's `scaler/scaler-events.ts`
15
+ * re-exports them for its own call sites.
16
+ */
17
+ import { z } from 'zod';
18
+ /**
19
+ * Reserved event names the event scaler emits. Both start with
20
+ * `KICI_EVENT_NAME_PREFIX` (`./scaler-backend-type.ts`), so the rate limiter
21
+ * exempts them and user steps cannot forge them — `scaler-events.test.ts`
22
+ * asserts that relationship holds for both names.
23
+ */
24
+ export declare const SCALER_EVENT_NAMES: {
25
+ readonly scaleUp: 'kici.scaler.scale-up';
26
+ readonly scaleDown: 'kici.scaler.scale-down';
27
+ };
28
+ /**
29
+ * Why the scaler asked for an agent to be torn down. Carried on the
30
+ * `kici.scaler.scale-down` event so a teardown workflow (and the timeline) can
31
+ * distinguish an idle reap from a job-complete teardown or a spawn timeout.
32
+ */
33
+ export declare const ScaleDownReason: z.ZodEnum<{
34
+ drain: "drain";
35
+ "heartbeat-timeout": "heartbeat-timeout";
36
+ idle: "idle";
37
+ "job-complete": "job-complete";
38
+ shutdown: "shutdown";
39
+ "spawn-timeout": "spawn-timeout";
40
+ }>;
41
+ export type ScaleDownReason = z.infer<typeof ScaleDownReason>;
42
+ /**
43
+ * Payload of a `kici.scaler.scale-up` event. Everything a provisioning workflow
44
+ * needs to boot an instance whose agent registers back with `agentId` and claim
45
+ * its ephemeral credentials with `claimCode`. The ephemeral token itself is
46
+ * NEVER in this payload — it is delivered only via the
47
+ * `scaler.claim-credentials` RPC response.
48
+ */
49
+ export declare const ScalerScaleUpPayload: z.ZodObject<{
50
+ scalerName: z.ZodString;
51
+ agentId: z.ZodString;
52
+ labels: z.ZodArray<z.ZodString>;
53
+ mandatoryLabels: z.ZodDefault<z.ZodArray<z.ZodString>>;
54
+ resources: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
55
+ orchestratorUrl: z.ZodString;
56
+ claimCode: z.ZodString;
57
+ jobId: z.ZodOptional<z.ZodString>;
58
+ requestId: z.ZodString;
59
+ }, z.core.$strip>;
60
+ export type ScalerScaleUpPayload = z.infer<typeof ScalerScaleUpPayload>;
61
+ /**
62
+ * Payload of a `kici.scaler.scale-down` event. A teardown workflow deletes the
63
+ * instance registered under `agentId`.
64
+ */
65
+ export declare const ScalerScaleDownPayload: z.ZodObject<{
66
+ scalerName: z.ZodString;
67
+ agentId: z.ZodString;
68
+ reason: z.ZodEnum<{
69
+ drain: "drain";
70
+ "heartbeat-timeout": "heartbeat-timeout";
71
+ idle: "idle";
72
+ "job-complete": "job-complete";
73
+ shutdown: "shutdown";
74
+ "spawn-timeout": "spawn-timeout";
75
+ }>;
76
+ requestId: z.ZodString;
77
+ }, z.core.$strip>;
78
+ export type ScalerScaleDownPayload = z.infer<typeof ScalerScaleDownPayload>;
79
+ //# sourceMappingURL=scaler-events.d.ts.map
@@ -0,0 +1,87 @@
1
+ import "../rolldown-runtime-ClRpJifh.js";
2
+ import { z } from "zod";
3
+ //#region src/scaler/scaler-events.ts
4
+ /**
5
+ * Shared schemas and constants for the event scaler backend.
6
+ *
7
+ * The event scaler performs no local compute: its `spawn()` / `destroy()` emit
8
+ * reserved `kici.`-prefixed custom events (`kici.scaler.scale-up` /
9
+ * `kici.scaler.scale-down`) that a customer-authored provisioning / teardown
10
+ * workflow consumes via the `kiciEvent()` trigger. These schemas define the
11
+ * event payloads and the single source of truth for the reserved event names.
12
+ *
13
+ * They live here, not in the orchestrator, because both sides of the contract
14
+ * need them: the orchestrator emits, and a workflow file — which may import
15
+ * `@kici-dev/sdk` and nothing else — consumes. Engine is the only package both
16
+ * the SDK and the orchestrator depend on, so it is the shared floor. The SDK
17
+ * re-exports all four symbols; the orchestrator's `scaler/scaler-events.ts`
18
+ * re-exports them for its own call sites.
19
+ */
20
+ /**
21
+ * Reserved event names the event scaler emits. Both start with
22
+ * `KICI_EVENT_NAME_PREFIX` (`./scaler-backend-type.ts`), so the rate limiter
23
+ * exempts them and user steps cannot forge them — `scaler-events.test.ts`
24
+ * asserts that relationship holds for both names.
25
+ */
26
+ const SCALER_EVENT_NAMES = {
27
+ scaleUp: "kici.scaler.scale-up",
28
+ scaleDown: "kici.scaler.scale-down"
29
+ };
30
+ /**
31
+ * Why the scaler asked for an agent to be torn down. Carried on the
32
+ * `kici.scaler.scale-down` event so a teardown workflow (and the timeline) can
33
+ * distinguish an idle reap from a job-complete teardown or a spawn timeout.
34
+ */
35
+ const ScaleDownReason = z.enum([
36
+ "idle",
37
+ "job-complete",
38
+ "heartbeat-timeout",
39
+ "spawn-timeout",
40
+ "drain",
41
+ "shutdown"
42
+ ]);
43
+ /**
44
+ * Payload of a `kici.scaler.scale-up` event. Everything a provisioning workflow
45
+ * needs to boot an instance whose agent registers back with `agentId` and claim
46
+ * its ephemeral credentials with `claimCode`. The ephemeral token itself is
47
+ * NEVER in this payload — it is delivered only via the
48
+ * `scaler.claim-credentials` RPC response.
49
+ */
50
+ const ScalerScaleUpPayload = z.object({
51
+ /** Name of the scaler entry that emitted the event. */
52
+ scalerName: z.string(),
53
+ /** Agent id the provisioned instance must register with (correlates the spawn). */
54
+ agentId: z.string(),
55
+ /** Exact label set the pending job needs. */
56
+ labels: z.array(z.string()),
57
+ /** Mandatory (taint) labels the pool gates on, if any. */
58
+ mandatoryLabels: z.array(z.string()).default([]),
59
+ /** Resolved resource hints for the provision (e.g. cpus / memBytes). */
60
+ resources: z.record(z.string(), z.unknown()).default({}),
61
+ /** Orchestrator WS URL the provisioned agent connects back to. */
62
+ orchestratorUrl: z.string(),
63
+ /** Single-use code the workflow exchanges for ephemeral agent credentials. */
64
+ claimCode: z.string(),
65
+ /** Execution job id the spawn is bound to (absent for unbound / warm spawns). */
66
+ jobId: z.string().optional(),
67
+ /** Correlation id for this scale-up request. */
68
+ requestId: z.string()
69
+ });
70
+ /**
71
+ * Payload of a `kici.scaler.scale-down` event. A teardown workflow deletes the
72
+ * instance registered under `agentId`.
73
+ */
74
+ const ScalerScaleDownPayload = z.object({
75
+ /** Name of the scaler entry that emitted the event. */
76
+ scalerName: z.string(),
77
+ /** Agent id whose instance should be torn down. */
78
+ agentId: z.string(),
79
+ /** Why the teardown was requested. */
80
+ reason: ScaleDownReason,
81
+ /** Correlation id for this scale-down request. */
82
+ requestId: z.string()
83
+ });
84
+ //#endregion
85
+ export { SCALER_EVENT_NAMES, ScaleDownReason, ScalerScaleDownPayload, ScalerScaleUpPayload };
86
+
87
+ //# sourceMappingURL=scaler-events.js.map
@@ -3,11 +3,31 @@
3
3
  * flags first with a space separator; regex flags are restricted to
4
4
  * `[gimsuydv]`, so the separator can never collide with a pattern that starts
5
5
  * with a space.
6
+ *
7
+ * Every pattern reaching here is author-supplied (branch/tag/repo patterns and
8
+ * comment `bodyMatch`), so it is ReDoS-checked before compiling. The guard runs
9
+ * inside the memo factory, so a benign pattern pays the check once (on cache
10
+ * miss) and a catastrophic one throws — and, being unsafe, is never cached, so
11
+ * it is rejected on every attempt. `ctx` names the dialect in the thrown error.
6
12
  */
7
- export declare function getCompiledRegex(pattern: string, flags?: string): RegExp;
13
+ export declare function getCompiledRegex(pattern: string, flags?: string, ctx?: string): RegExp;
8
14
  /**
9
15
  * Return a memoized picomatch matcher function for the given glob pattern.
10
16
  * `getGlobMatcher(pattern)(str)` is equivalent to `picomatch.isMatch(str, pattern)`.
11
17
  */
12
18
  export declare function getGlobMatcher(pattern: string): (s: string) => boolean;
19
+ /**
20
+ * Repo-identifier matcher. Identical to {@link getGlobMatcher} except it sets
21
+ * picomatch's `dot: true`, so a dot-prefixed identifier (`.hidden/repo`) is
22
+ * matched by `**` — `repos: ['**']` is documented as "every repo in the org",
23
+ * and silently excluding a whole class of identifier contradicts that.
24
+ *
25
+ * Deliberately NOT the shared matcher: `dot: true` on path globs would make
26
+ * `paths: ['**']` start matching `.github/**` for every existing workflow, a
27
+ * semantics change this does not intend.
28
+ *
29
+ * Note a bare `.` still does not match, in either mode — picomatch will not
30
+ * match a lone `.`. That is upstream behavior, not something this option fixes.
31
+ */
32
+ export declare function getRepoGlobMatcher(pattern: string): (s: string) => boolean;
13
33
  //# sourceMappingURL=compiled-matchers.d.ts.map
@@ -1,4 +1,5 @@
1
1
  import "../rolldown-runtime-ClRpJifh.js";
2
+ import { assertSafeRegex } from "../safe-regex.js";
2
3
  import picomatch from "picomatch";
3
4
  //#region src/trigger/compiled-matchers.ts
4
5
  /**
@@ -22,14 +23,24 @@ function boundedGet(cache, key, make) {
22
23
  }
23
24
  const regexCache = /* @__PURE__ */ new Map();
24
25
  const globCache = /* @__PURE__ */ new Map();
26
+ const repoGlobCache = /* @__PURE__ */ new Map();
25
27
  /**
26
28
  * Return a memoized RegExp for the given pattern + flags. The key encodes the
27
29
  * flags first with a space separator; regex flags are restricted to
28
30
  * `[gimsuydv]`, so the separator can never collide with a pattern that starts
29
31
  * with a space.
32
+ *
33
+ * Every pattern reaching here is author-supplied (branch/tag/repo patterns and
34
+ * comment `bodyMatch`), so it is ReDoS-checked before compiling. The guard runs
35
+ * inside the memo factory, so a benign pattern pays the check once (on cache
36
+ * miss) and a catastrophic one throws — and, being unsafe, is never cached, so
37
+ * it is rejected on every attempt. `ctx` names the dialect in the thrown error.
30
38
  */
31
- function getCompiledRegex(pattern, flags) {
32
- return boundedGet(regexCache, `${flags ?? ""} ${pattern}`, () => new RegExp(pattern, flags));
39
+ function getCompiledRegex(pattern, flags, ctx = "trigger pattern") {
40
+ return boundedGet(regexCache, `${flags ?? ""} ${pattern}`, () => {
41
+ assertSafeRegex(pattern, flags ?? "", ctx);
42
+ return new RegExp(pattern, flags);
43
+ });
33
44
  }
34
45
  /**
35
46
  * Return a memoized picomatch matcher function for the given glob pattern.
@@ -38,7 +49,23 @@ function getCompiledRegex(pattern, flags) {
38
49
  function getGlobMatcher(pattern) {
39
50
  return boundedGet(globCache, pattern, () => picomatch(pattern));
40
51
  }
52
+ /**
53
+ * Repo-identifier matcher. Identical to {@link getGlobMatcher} except it sets
54
+ * picomatch's `dot: true`, so a dot-prefixed identifier (`.hidden/repo`) is
55
+ * matched by `**` — `repos: ['**']` is documented as "every repo in the org",
56
+ * and silently excluding a whole class of identifier contradicts that.
57
+ *
58
+ * Deliberately NOT the shared matcher: `dot: true` on path globs would make
59
+ * `paths: ['**']` start matching `.github/**` for every existing workflow, a
60
+ * semantics change this does not intend.
61
+ *
62
+ * Note a bare `.` still does not match, in either mode — picomatch will not
63
+ * match a lone `.`. That is upstream behavior, not something this option fixes.
64
+ */
65
+ function getRepoGlobMatcher(pattern) {
66
+ return boundedGet(repoGlobCache, pattern, () => picomatch(pattern, { dot: true }));
67
+ }
41
68
  //#endregion
42
- export { getCompiledRegex, getGlobMatcher };
69
+ export { getCompiledRegex, getGlobMatcher, getRepoGlobMatcher };
43
70
 
44
71
  //# sourceMappingURL=compiled-matchers.js.map
@@ -0,0 +1,31 @@
1
+ import type { LockContentRequirement } from './types.js';
2
+ export type { ContentFormat, ContentRequirement, LockContentRequirement } from './types.js';
3
+ /** Result of evaluating a `requires` list: a definite verdict, or fail-visible indeterminate. */
4
+ export interface ContentRequirementResult {
5
+ readonly pass: boolean;
6
+ /** Set (with `pass:false`) when a file could not be evaluated — never a silent pass. */
7
+ readonly indeterminate?: string;
8
+ }
9
+ /**
10
+ * Parse `bytes` for the given concrete format. `text` returns the raw string;
11
+ * `json` uses `JSON.parse`; `yaml` uses a hardened `yaml.parse` with an explicit
12
+ * anchor/alias cap. Throws on a malformed document (the caller treats a throw as
13
+ * indeterminate).
14
+ */
15
+ export declare function parseForFormat(bytes: string, format: 'json' | 'yaml' | 'text'): unknown;
16
+ /**
17
+ * Evaluate an AND-ed list of content requirements against a resolved file map.
18
+ *
19
+ * Every entry must pass for the overall result to pass; an empty list passes.
20
+ * The first indeterminate entry short-circuits and is surfaced (fail-visible):
21
+ * an unevaluable file NEVER passes silently.
22
+ *
23
+ * @param reqs The lock `requires` list (each entry AND-ed).
24
+ * @param files Resolved file contents keyed by repo-relative path. A missing key
25
+ * or `{ present: false }` means the file does not exist at the ref.
26
+ */
27
+ export declare function evaluateContentRequirements(reqs: readonly LockContentRequirement[], files: Map<string, {
28
+ present: boolean;
29
+ bytes?: string;
30
+ }>): ContentRequirementResult;
31
+ //# sourceMappingURL=content-requirements.d.ts.map