@kici-dev/engine 0.15.0 → 0.16.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 (54) hide show
  1. package/dist/approval/expiry-duration.d.ts +11 -0
  2. package/dist/approval/expiry-duration.js +29 -0
  3. package/dist/audit/access-log-policy.js +2 -0
  4. package/dist/audit/retention-policy.d.ts +1 -1
  5. package/dist/audit/retention-policy.js +5 -1
  6. package/dist/auth/permissions.d.ts +69 -0
  7. package/dist/auth/permissions.js +51 -0
  8. package/dist/context/hold-type.d.ts +0 -19
  9. package/dist/context/hold-type.js +1 -37
  10. package/dist/context/index.d.ts +1 -1
  11. package/dist/context/index.js +2 -2
  12. package/dist/index.d.ts +7 -2
  13. package/dist/index.js +18 -13
  14. package/dist/labels.d.ts +2 -17
  15. package/dist/labels.js +3 -33
  16. package/dist/mcp/held-run-resolve.d.ts +2 -5
  17. package/dist/mcp/held-run-resolve.js +3 -4
  18. package/dist/metrics/metric-catalog.generated.d.ts +0 -5
  19. package/dist/metrics/metric-catalog.generated.js +0 -6
  20. package/dist/protocol/messages/access-log.d.ts +10 -0
  21. package/dist/protocol/messages/access-log.js +2 -0
  22. package/dist/protocol/messages/auth.d.ts +7 -10
  23. package/dist/protocol/messages/auth.js +8 -22
  24. package/dist/protocol/messages/browser.js +1 -1
  25. package/dist/protocol/messages/capabilities.d.ts +21 -106
  26. package/dist/protocol/messages/capabilities.js +23 -133
  27. package/dist/protocol/messages/dashboard.d.ts +24 -28
  28. package/dist/protocol/messages/dashboard.js +19 -38
  29. package/dist/protocol/messages/execution-status.d.ts +3 -3
  30. package/dist/protocol/messages/execution-status.js +7 -12
  31. package/dist/protocol/messages/orchestrator-agent.d.ts +35 -40
  32. package/dist/protocol/messages/orchestrator-agent.js +63 -96
  33. package/dist/protocol/messages/peer.d.ts +223 -18
  34. package/dist/protocol/messages/peer.js +90 -55
  35. package/dist/protocol/messages/platform-orchestrator.d.ts +36 -145
  36. package/dist/protocol/messages/platform-orchestrator.js +24 -86
  37. package/dist/protocol/messages/source-registration.d.ts +0 -13
  38. package/dist/protocol/messages/source-registration.js +9 -10
  39. package/dist/protocol/version.d.ts +9 -15
  40. package/dist/protocol/version.js +9 -15
  41. package/dist/provenance/id-token-claim-names.d.ts +3 -5
  42. package/dist/provenance/id-token-claim-names.js +3 -5
  43. package/dist/status/presentation.d.ts +2 -14
  44. package/dist/status/presentation.js +3 -23
  45. package/dist/trigger/types.d.ts +125 -34
  46. package/dist/trigger/types.js +9 -24
  47. package/dist/util/date.d.ts +7 -0
  48. package/dist/util/date.js +14 -0
  49. package/dist/util/parse-duration.d.ts +6 -0
  50. package/dist/util/parse-duration.js +21 -0
  51. package/dist/util/sleep.d.ts +3 -0
  52. package/dist/util/sleep.js +10 -0
  53. package/package.json +1 -1
  54. package/sbom.spdx.json +5 -5
@@ -1,21 +1,15 @@
1
1
  /**
2
2
  * Protocol version. Sent during WebSocket handshake.
3
3
  *
4
- * Increment when a message schema gains something an older peer cannot parse,
5
- * and pair the bump with a named floor so a sender can gate on the version a
6
- * peer negotiated instead of guessing.
4
+ * Increment when a message schema gains something an older peer cannot parse.
5
+ * The minimum equals the current version, so every bump is a breaking change:
6
+ * every tier upgrades in the same window.
7
7
  *
8
- * Version 3 records that a version-2 peer (every 0.8.x build) cannot parse the
9
- * 0.9.0 `trust_policy.update` policy, the peer heartbeat, or the
10
- * `artifacts.upload.complete` frame: the fields it requires were removed and
11
- * the schemas are strict, so a version-2 peer that was let through the
12
- * handshake would drop or refuse those frames silently.
8
+ * Version 4: fields every sender already set are required, and the capability
9
+ * flags every build advertised are gone. A version-3 peer (every release
10
+ * before it) may omit those fields, so it is refused at connect.
13
11
  */
14
- export declare const PROTOCOL_VERSION = 3;
15
- /**
16
- * Minimum protocol version accepted.
17
- * Connections below this are rejected.
18
- * Capabilities handle per-feature negotiation above this baseline.
19
- */
20
- export declare const MIN_PROTOCOL_VERSION = 3;
12
+ export declare const PROTOCOL_VERSION = 4;
13
+ /** Minimum protocol version accepted. Connections below this are rejected. */
14
+ export declare const MIN_PROTOCOL_VERSION = 4;
21
15
  //# sourceMappingURL=version.d.ts.map
@@ -3,23 +3,17 @@ import "../rolldown-runtime-ClRpJifh.js";
3
3
  /**
4
4
  * Protocol version. Sent during WebSocket handshake.
5
5
  *
6
- * Increment when a message schema gains something an older peer cannot parse,
7
- * and pair the bump with a named floor so a sender can gate on the version a
8
- * peer negotiated instead of guessing.
6
+ * Increment when a message schema gains something an older peer cannot parse.
7
+ * The minimum equals the current version, so every bump is a breaking change:
8
+ * every tier upgrades in the same window.
9
9
  *
10
- * Version 3 records that a version-2 peer (every 0.8.x build) cannot parse the
11
- * 0.9.0 `trust_policy.update` policy, the peer heartbeat, or the
12
- * `artifacts.upload.complete` frame: the fields it requires were removed and
13
- * the schemas are strict, so a version-2 peer that was let through the
14
- * handshake would drop or refuse those frames silently.
10
+ * Version 4: fields every sender already set are required, and the capability
11
+ * flags every build advertised are gone. A version-3 peer (every release
12
+ * before it) may omit those fields, so it is refused at connect.
15
13
  */
16
- const PROTOCOL_VERSION = 3;
17
- /**
18
- * Minimum protocol version accepted.
19
- * Connections below this are rejected.
20
- * Capabilities handle per-feature negotiation above this baseline.
21
- */
22
- const MIN_PROTOCOL_VERSION = 3;
14
+ const PROTOCOL_VERSION = 4;
15
+ /** Minimum protocol version accepted. Connections below this are rejected. */
16
+ const MIN_PROTOCOL_VERSION = 4;
23
17
  //#endregion
24
18
  export { MIN_PROTOCOL_VERSION, PROTOCOL_VERSION };
25
19
 
@@ -1,11 +1,9 @@
1
1
  /**
2
2
  * Every claim a KiCI provenance ID token carries, in a stable order.
3
3
  *
4
- * Both OIDC discovery documents render `claims_supported` from this list — the
5
- * orchestrator issuer that mints tokens today and the legacy Platform issuer
6
- * whose already-issued tokens carried the same shape — so a relying party
7
- * configuring a trust policy reads the same names under either `iss`. The
8
- * orchestrator binds the list to its `IdTokenClaims` type at compile time and
4
+ * The orchestrator's OIDC discovery document renders `claims_supported` from
5
+ * this list, so a relying party configuring a trust policy reads the names the
6
+ * tokens carry. The orchestrator binds the list to its `IdTokenClaims` type at compile time and
9
7
  * a drift test checks it against the claims its builder actually emits.
10
8
  */
11
9
  export declare const ID_TOKEN_CLAIM_NAMES: readonly ['iss', 'sub', 'aud', 'iat', 'nbf', 'exp', 'jti', 'kici_run_id', 'kici_job_id', 'repository', 'workflow_repository', 'ref', 'base_ref', 'head_ref', 'head_repository', 'is_fork', 'event_name', 'trust_tier', 'actor', 'sha', 'workflow_ref', 'orchestrator_id', 'org_id', 'source_origin', 'provider', 'statement_hash', 'attestation_origin'];
@@ -3,11 +3,9 @@ import "../rolldown-runtime-ClRpJifh.js";
3
3
  /**
4
4
  * Every claim a KiCI provenance ID token carries, in a stable order.
5
5
  *
6
- * Both OIDC discovery documents render `claims_supported` from this list — the
7
- * orchestrator issuer that mints tokens today and the legacy Platform issuer
8
- * whose already-issued tokens carried the same shape — so a relying party
9
- * configuring a trust policy reads the same names under either `iss`. The
10
- * orchestrator binds the list to its `IdTokenClaims` type at compile time and
6
+ * The orchestrator's OIDC discovery document renders `claims_supported` from
7
+ * this list, so a relying party configuring a trust policy reads the names the
8
+ * tokens carry. The orchestrator binds the list to its `IdTokenClaims` type at compile time and
11
9
  * a drift test checks it against the claims its builder actually emits.
12
10
  */
13
11
  const ID_TOKEN_CLAIM_NAMES = [
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Shared execution-status presentation vocabulary: the canonical status union,
3
- * a total precedence order for roll-up aggregates, legacy-spelling resolution,
3
+ * a total precedence order for roll-up aggregates, canonical-status resolution,
4
4
  * and a per-status failure classification.
5
5
  *
6
6
  * Pure Zod (browser-safe): the engine barrel re-exports this module and the
@@ -23,21 +23,9 @@ export type CanonicalStatus = ExecutionRunStatus | ExecutionJobStatus;
23
23
  export declare const CANONICAL_STATUSES: readonly CanonicalStatus[];
24
24
  /** Canonical statuses ordered worst-first. Derived from `STATUS_RANK`. */
25
25
  export declare const STATUS_PRECEDENCE: readonly CanonicalStatus[];
26
- /**
27
- * Legacy status spellings that map onto a canonical status. An alias always
28
- * resolves like the status it aliases, so a consumer never needs a second
29
- * hand-written copy of the mapping.
30
- */
31
- export declare const LEGACY_STATUS_ALIASES: Readonly<Record<string, CanonicalStatus>>;
32
26
  /**
33
27
  * Resolve a status string onto its canonical status, or `undefined` when it is
34
- * neither canonical nor a known legacy alias. Callers that accept mixed case
35
- * lowercase their input first.
36
- *
37
- * `Object.hasOwn`, not a bare index: an object literal inherits
38
- * `Object.prototype`, so indexing it with `toString` / `constructor` /
39
- * `valueOf` would yield a function rather than `undefined` and the caller's
40
- * fallback would never fire.
28
+ * not canonical. Callers that accept mixed case lowercase their input first.
41
29
  */
42
30
  export declare function toCanonicalStatus(status: string): CanonicalStatus | undefined;
43
31
  /**
@@ -4,7 +4,7 @@ import { z } from "zod";
4
4
  //#region src/status/presentation.ts
5
5
  /**
6
6
  * Shared execution-status presentation vocabulary: the canonical status union,
7
- * a total precedence order for roll-up aggregates, legacy-spelling resolution,
7
+ * a total precedence order for roll-up aggregates, canonical-status resolution,
8
8
  * and a per-status failure classification.
9
9
  *
10
10
  * Pure Zod (browser-safe): the engine barrel re-exports this module and the
@@ -61,30 +61,10 @@ const STATUS_RANK = Object.freeze({
61
61
  /** Canonical statuses ordered worst-first. Derived from `STATUS_RANK`. */
62
62
  const STATUS_PRECEDENCE = Object.freeze([...CANONICAL_STATUSES].sort((a, b) => STATUS_RANK[a] - STATUS_RANK[b]));
63
63
  /**
64
- * Legacy status spellings that map onto a canonical status. An alias always
65
- * resolves like the status it aliases, so a consumer never needs a second
66
- * hand-written copy of the mapping.
67
- */
68
- const LEGACY_STATUS_ALIASES = Object.freeze({
69
- passed: ExecutionRunStatus.enum.success,
70
- completed: ExecutionRunStatus.enum.success,
71
- in_progress: ExecutionRunStatus.enum.running,
72
- error: ExecutionRunStatus.enum.failed,
73
- canceled: ExecutionRunStatus.enum.cancelled,
74
- waiting: ExecutionRunStatus.enum.pending
75
- });
76
- /**
77
64
  * Resolve a status string onto its canonical status, or `undefined` when it is
78
- * neither canonical nor a known legacy alias. Callers that accept mixed case
79
- * lowercase their input first.
80
- *
81
- * `Object.hasOwn`, not a bare index: an object literal inherits
82
- * `Object.prototype`, so indexing it with `toString` / `constructor` /
83
- * `valueOf` would yield a function rather than `undefined` and the caller's
84
- * fallback would never fire.
65
+ * not canonical. Callers that accept mixed case lowercase their input first.
85
66
  */
86
67
  function toCanonicalStatus(status) {
87
- if (Object.hasOwn(LEGACY_STATUS_ALIASES, status)) return LEGACY_STATUS_ALIASES[status];
88
68
  return CANONICAL_SET.has(status) ? status : void 0;
89
69
  }
90
70
  /**
@@ -158,6 +138,6 @@ function isFailureStatus(status) {
158
138
  return canonical !== void 0 && STATUS_FAILURE_CLASS[canonical] === StatusFailureClass.enum.failure;
159
139
  }
160
140
  //#endregion
161
- export { CANONICAL_STATUSES, LEGACY_STATUS_ALIASES, STATUS_FAILURE_CLASS, STATUS_PRECEDENCE, StatusFailureClass, isFailureStatus, toCanonicalStatus, worstStatus };
141
+ export { CANONICAL_STATUSES, STATUS_FAILURE_CLASS, STATUS_PRECEDENCE, StatusFailureClass, isFailureStatus, toCanonicalStatus, worstStatus };
162
142
 
163
143
  //# sourceMappingURL=presentation.js.map
@@ -42,11 +42,9 @@
42
42
  * sibling closure the deps tarball carries, which no package-manager lock file moves).
43
43
  * Schema version 41 (additive): adds LockDynamicJobFn.gitCredentials (named git credential
44
44
  * refs declared by a dynamicJob generator and inherited by every job it generates).
45
- * Schema version 42 (additive, conditional reader floor): approval enforced on
46
- * organization-wide workflows. The lock shape is unchanged, but a v41 reader dispatches a
47
- * global workflow without consulting its `approval`, so a lock whose global workflow (or
48
- * one of its static jobs) declares `approval` stamps `minReaderVersion` =
49
- * `GLOBAL_APPROVAL_MIN_READER`. Every other lock keeps `minReaderVersion` = `BREAKING_FLOOR`.
45
+ * Schema version 42 (BREAKING): approval enforced on organization-wide workflows (a v41
46
+ * reader dispatches a global workflow without consulting its `approval`), and
47
+ * `minReaderVersion` is required. The floor moves to 42.
50
48
  */
51
49
  import { z } from 'zod';
52
50
  import type { ProviderType } from '../provider/types.js';
@@ -66,26 +64,13 @@ export declare const SCHEMA_VERSION: 42;
66
64
  *
67
65
  * A lock at `schemaVersion >= BREAKING_FLOOR` parses correctly here even if it
68
66
  * is newer than `SCHEMA_VERSION` (additive bumps add fields this reader ignores).
69
- * A lock below the floor was produced by an SDK whose breaking change this
70
- * reader predates and must be rejected (it would mis-parse silently otherwise).
67
+ * A lock below the floor must be recompiled with a current SDK and is rejected.
71
68
  *
72
- * Bump rule: move this to the current `SCHEMA_VERSION` ONLY in the commit that
73
- * lands a `BREAKING` schema change (see the bump-history convention above). It
74
- * currently sits at 30 because v30 (`environments`→`contexts`) was the most
75
- * recent breaking bump; v31 through v35 were additive, so a v30 lock still
76
- * reads correctly.
69
+ * Bump rule: move this to the current `SCHEMA_VERSION` in the commit that lands
70
+ * a `BREAKING` schema change (see the bump-history convention above). An
71
+ * additive bump leaves it in place, so locks compiled at the floor stay readable.
77
72
  */
78
- export declare const BREAKING_FLOOR: 30;
79
- /**
80
- * Reader version a lock must require when an organization-wide workflow in it
81
- * (a workflow with a trigger carrying `repos:`), or one of that workflow's
82
- * static jobs, declares `approval`. Readers below this version run a global
83
- * workflow's jobs without holding them for approval, so they must refuse such a
84
- * lock rather than dispatch it ungated. Not a `BREAKING_FLOOR` move: the lock
85
- * shape is unchanged, and locks without a gated global workflow stay readable by
86
- * every orchestrator down to the floor.
87
- */
88
- export declare const GLOBAL_APPROVAL_MIN_READER: 42;
73
+ export declare const BREAKING_FLOOR: 42;
89
74
  /**
90
75
  * Normalized approval config carried in the lock file. Produced by the compiler
91
76
  * from an SDK `approval` at any of the three levels; consumed by the
@@ -533,6 +518,39 @@ export interface LockRule {
533
518
  readonly index: number;
534
519
  };
535
520
  }
521
+ /**
522
+ * A declarative cache spec as serialized into the lock file. Mirrors the SDK
523
+ * `CacheSpec`; the engine cannot import the SDK, so the shape is inlined here.
524
+ */
525
+ export interface LockCacheSpec {
526
+ readonly key: string;
527
+ readonly paths: readonly string[];
528
+ readonly restoreKeys?: readonly string[];
529
+ }
530
+ /** Lock-file form of the SDK `GenericInitConfig`. */
531
+ interface LockGenericInitConfig {
532
+ readonly run: string;
533
+ readonly shell?: string;
534
+ readonly cache?: LockCacheSpec;
535
+ readonly timeout?: number;
536
+ readonly env?: Record<string, string>;
537
+ }
538
+ /** Lock-file form of the SDK `MiseInitConfig`. */
539
+ interface LockMiseInitConfig {
540
+ readonly cache?: LockCacheSpec | false;
541
+ readonly timeout?: number;
542
+ readonly env?: Record<string, string>;
543
+ readonly shell?: string;
544
+ }
545
+ type LockInitItem = LockGenericInitConfig | 'mise' | {
546
+ readonly mise: LockMiseInitConfig;
547
+ };
548
+ /**
549
+ * Per-job init config as serialized into the lock file. Mirrors the SDK
550
+ * `InitConfig` (a generic config, a typed preset, an ordered array, `'auto'`,
551
+ * or `false`); the engine cannot import the SDK, so the shape is inlined here.
552
+ */
553
+ export type LockInitConfig = LockInitItem | readonly LockInitItem[] | 'auto' | false;
536
554
  /**
537
555
  * Step in lock file.
538
556
  * Minimal representation - agents load full step functions from source.
@@ -553,12 +571,31 @@ export interface LockStep {
553
571
  readonly backoff: 'fixed' | 'exponential';
554
572
  readonly maxDelayMs: number;
555
573
  };
574
+ /** Declarative cache specs (normalized to an array). Restored before / saved after the step. */
575
+ readonly cache?: readonly LockCacheSpec[];
556
576
  /** Source location of the step() call in the original TypeScript file (for annotations). */
557
577
  readonly sourceLocation?: {
558
578
  readonly file: string;
559
579
  readonly line: number;
560
580
  readonly column: number;
561
581
  };
582
+ /** Whether this step has conditional rules (evaluated agent-side). */
583
+ readonly hasRules?: boolean;
584
+ /** Step-level rules (same format as job rules). */
585
+ readonly rules?: readonly LockRule[];
586
+ /** Whether this step has an onCancel hook. */
587
+ readonly hasOnCancel?: boolean;
588
+ /** Whether this step has a cleanup hook. */
589
+ readonly hasCleanup?: boolean;
590
+ /**
591
+ * Whether this step declares an idempotent `check` facet. When true the
592
+ * orchestrator knows the step is check-capable and a run can be dispatched in
593
+ * check mode. The check/apply closures themselves are never serialized — the
594
+ * agent re-evaluates the real workflow TypeScript.
595
+ */
596
+ readonly hasCheck?: boolean;
597
+ /** Whether this step declares a `whenInSync` facet (produces outputs when in sync). */
598
+ readonly hasWhenInSync?: boolean;
562
599
  /** Normalized approval gate; when set the step pauses for a human approval. */
563
600
  readonly approval?: LockApproval;
564
601
  }
@@ -670,9 +707,19 @@ export declare const NeedsGroupEntrySchema: z.ZodObject<{
670
707
  }, z.core.$strip>;
671
708
  export type NeedsGroupEntry = z.infer<typeof NeedsGroupEntrySchema>;
672
709
  /**
673
- * Static job in lock file.
674
- * Contains all orchestrator-readable information for scheduling.
710
+ * A `needs` entry as the compiler writes it into the lock file. `runOn` is the
711
+ * resolved status-set; it is a plain array because a raw status-set an author
712
+ * passes is copied through as is, so a reader must not assume it is non-empty.
675
713
  */
714
+ export interface LockNeedsEntry {
715
+ readonly name: string;
716
+ readonly runOn: ExecutionJobStatus[];
717
+ }
718
+ /** A dynamic-group `needs` entry as the compiler writes it into the lock file. */
719
+ export interface LockNeedsGroupEntry {
720
+ readonly group: string;
721
+ readonly runOn: ExecutionJobStatus[];
722
+ }
676
723
  /** Normalized runsOnAll predicate: OR of AND-groups (include), minus exclude matchers. */
677
724
  export interface RunsOnAllPredicate {
678
725
  /** OR across groups; AND within a group. */
@@ -761,6 +808,14 @@ export interface LockInvoke {
761
808
  */
762
809
  readonly optional?: boolean;
763
810
  }
811
+ /**
812
+ * Static job in lock file.
813
+ * Contains all orchestrator-readable information for scheduling.
814
+ *
815
+ * `runsOn` contains user-supplied labels only. The `kici:role:*` labels
816
+ * (e.g., `kici:role:builder`, `kici:role:init-runner`) are injected by the
817
+ * orchestrator for internal job types (build/init) and are not user-settable.
818
+ */
764
819
  export interface LockJob {
765
820
  readonly _type: 'static';
766
821
  readonly name: string;
@@ -818,7 +873,7 @@ export interface LockJob {
818
873
  readonly maxParallel?: number;
819
874
  /** Halt the fan-out on first child failure, skipping the held remainder. Default `false`. */
820
875
  readonly failFast?: boolean;
821
- readonly needs: readonly (string | NeedsEntry | NeedsGroupEntry)[];
876
+ readonly needs: readonly (string | LockNeedsEntry | LockNeedsGroupEntry)[];
822
877
  /** Group names this job depends on (populated by compiler from dynamicGroup refs). */
823
878
  readonly dependsOnGroups?: readonly string[];
824
879
  readonly steps: readonly LockStepEntry[];
@@ -827,6 +882,10 @@ export interface LockJob {
827
882
  readonly exclude?: readonly Record<string, string>[];
828
883
  readonly rules?: readonly LockRule[];
829
884
  readonly description?: string;
885
+ /** When false, agent skips git clone (default: true). */
886
+ readonly checkout?: boolean;
887
+ /** Declarative cache specs (normalized to an array). Restored before steps / saved after the job. */
888
+ readonly cache?: readonly LockCacheSpec[];
830
889
  /**
831
890
  * Bound contexts in merge order. Each entry is a static name; `dynamic` is set
832
891
  * when it is a function resolved on the eval agent's init-runner. Later entries
@@ -844,6 +903,20 @@ export interface LockJob {
844
903
  readonly concurrencyGroup?: string;
845
904
  /** When true, concurrencyGroup is dynamic (function) -- resolved on the eval agent's init-runner. */
846
905
  readonly dynamicConcurrencyGroup?: boolean;
906
+ /** Whether this job has an onCancel hook. */
907
+ readonly hasOnCancel?: boolean;
908
+ /** Whether this job has a cleanup hook. */
909
+ readonly hasCleanup?: boolean;
910
+ /** Whether this job has an onSuccess hook. */
911
+ readonly hasOnSuccess?: boolean;
912
+ /** Whether this job has an onFailure hook. */
913
+ readonly hasOnFailure?: boolean;
914
+ /** Whether this job has a beforeStep hook. */
915
+ readonly hasBeforeStep?: boolean;
916
+ /** Whether this job has an afterStep hook. */
917
+ readonly hasAfterStep?: boolean;
918
+ /** Seconds before SIGKILL after SIGTERM during cancellation. */
919
+ readonly gracePeriod?: number;
847
920
  /** Total job wall-clock timeout in milliseconds (init + all steps + hooks). Threaded to the agent via jobConfig. */
848
921
  readonly timeout?: number;
849
922
  /**
@@ -852,6 +925,12 @@ export interface LockJob {
852
925
  * (`requests`) and kernel-side enforcement (`limits`) on the spawned agent.
853
926
  */
854
927
  readonly resources?: import('../scaler/resource-types.js').ResourceRequest;
928
+ /**
929
+ * Per-job init config(s) run after clone, before steps. Threaded verbatim from
930
+ * the SDK `Job.init`. The agent reads it from the loaded module; the lock copy
931
+ * is for orchestrator/dashboard visibility.
932
+ */
933
+ readonly init?: LockInitConfig;
855
934
  /**
856
935
  * Container image selecting the container execution backend on the agent. A
857
936
  * bare image string, or an object naming exactly one image source: a
@@ -936,7 +1015,7 @@ export interface LockDynamicJobFn {
936
1015
  * with their frozen outputs available as ctx.needs. Same normalized shape as
937
1016
  * a static job's `needs`.
938
1017
  */
939
- readonly needs?: readonly (string | NeedsEntry | NeedsGroupEntry)[];
1018
+ readonly needs?: readonly (string | LockNeedsEntry | LockNeedsGroupEntry)[];
940
1019
  /** True when this dynamic entry was authored as dynamicJob(group, { needs, generate }). */
941
1020
  readonly resultAware?: boolean;
942
1021
  /**
@@ -1003,6 +1082,14 @@ export interface LockWorkflow {
1003
1082
  * env vars on the install subprocess for use with a customer-committed `.kici/.npmrc`.
1004
1083
  */
1005
1084
  readonly installEnv?: readonly string[];
1085
+ /** Whether this workflow has an onCancel hook. */
1086
+ readonly hasOnCancel?: boolean;
1087
+ /** Whether this workflow has a cleanup hook. */
1088
+ readonly hasCleanup?: boolean;
1089
+ /** Whether this workflow has an onSuccess hook. */
1090
+ readonly hasOnSuccess?: boolean;
1091
+ /** Whether this workflow has an onFailure hook. */
1092
+ readonly hasOnFailure?: boolean;
1006
1093
  /** Workflow-level concurrency configuration. */
1007
1094
  readonly concurrency?: {
1008
1095
  readonly hasGroup: boolean;
@@ -1044,18 +1131,21 @@ export interface LockFile {
1044
1131
  readonly schemaVersion: typeof SCHEMA_VERSION;
1045
1132
  /**
1046
1133
  * The oldest reader schema version that handles this lock correctly. The
1047
- * compiler stamps `BREAKING_FLOOR`, or `GLOBAL_APPROVAL_MIN_READER` when an
1048
- * organization-wide workflow in the lock declares `approval`. A reader whose
1134
+ * compiler stamps `BREAKING_FLOOR`. A reader whose
1049
1135
  * own `SCHEMA_VERSION` is below this value would mis-handle the lock and must
1050
- * reject it. Absent on
1051
- * pre-window locks, in which case the reader falls back to exact-match
1052
- * strictness (see `assertLockFileSchemaCompatible`).
1136
+ * reject it. Required: a lock without it fails the reader's compatibility check.
1053
1137
  */
1054
- readonly minReaderVersion?: number;
1138
+ readonly minReaderVersion: number;
1055
1139
  readonly source: LockSource;
1056
1140
  /** SHA-256 hash of the serialized lock file content (excluding this field). Changes only when workflows, triggers, jobs, or bundle hashes change. */
1057
1141
  readonly contentHash: string;
1058
- /** SHA-256 hash of .kici/ lockfile (pnpm-lock.yaml or package-lock.json). Used for dependency cache keying. */
1142
+ /**
1143
+ * SHA-256 hash of the repo's lockfile, used as the dependency cache key. The
1144
+ * lockfile is the one the detected package manager produces — `.kici/`'s
1145
+ * `package-lock.json` for npm, or the repo-root `pnpm-lock.yaml` /
1146
+ * `yarn.lock` for a pnpm/yarn workspace. The hash input is prefixed with the
1147
+ * manager name so a manager change is a guaranteed cache miss.
1148
+ */
1059
1149
  readonly lockfileHash?: string;
1060
1150
  /**
1061
1151
  * SHA-256 over the git-tracked source of every in-repo `workspace:` /
@@ -1169,4 +1259,5 @@ export interface SimulatedEvent {
1169
1259
  */
1170
1260
  headRepo?: string;
1171
1261
  }
1262
+ export {};
1172
1263
  //# sourceMappingURL=types.d.ts.map
@@ -47,11 +47,9 @@ import { z } from "zod";
47
47
  * sibling closure the deps tarball carries, which no package-manager lock file moves).
48
48
  * Schema version 41 (additive): adds LockDynamicJobFn.gitCredentials (named git credential
49
49
  * refs declared by a dynamicJob generator and inherited by every job it generates).
50
- * Schema version 42 (additive, conditional reader floor): approval enforced on
51
- * organization-wide workflows. The lock shape is unchanged, but a v41 reader dispatches a
52
- * global workflow without consulting its `approval`, so a lock whose global workflow (or
53
- * one of its static jobs) declares `approval` stamps `minReaderVersion` =
54
- * `GLOBAL_APPROVAL_MIN_READER`. Every other lock keeps `minReaderVersion` = `BREAKING_FLOOR`.
50
+ * Schema version 42 (BREAKING): approval enforced on organization-wide workflows (a v41
51
+ * reader dispatches a global workflow without consulting its `approval`), and
52
+ * `minReaderVersion` is required. The floor moves to 42.
55
53
  */
56
54
  /**
57
55
  * Schema version the compiler emits into every lock file. Incremented on ANY
@@ -65,26 +63,13 @@ const SCHEMA_VERSION = 42;
65
63
  *
66
64
  * A lock at `schemaVersion >= BREAKING_FLOOR` parses correctly here even if it
67
65
  * is newer than `SCHEMA_VERSION` (additive bumps add fields this reader ignores).
68
- * A lock below the floor was produced by an SDK whose breaking change this
69
- * reader predates and must be rejected (it would mis-parse silently otherwise).
66
+ * A lock below the floor must be recompiled with a current SDK and is rejected.
70
67
  *
71
- * Bump rule: move this to the current `SCHEMA_VERSION` ONLY in the commit that
72
- * lands a `BREAKING` schema change (see the bump-history convention above). It
73
- * currently sits at 30 because v30 (`environments`→`contexts`) was the most
74
- * recent breaking bump; v31 through v35 were additive, so a v30 lock still
75
- * reads correctly.
68
+ * Bump rule: move this to the current `SCHEMA_VERSION` in the commit that lands
69
+ * a `BREAKING` schema change (see the bump-history convention above). An
70
+ * additive bump leaves it in place, so locks compiled at the floor stay readable.
76
71
  */
77
- const BREAKING_FLOOR = 30;
78
- /**
79
- * Reader version a lock must require when an organization-wide workflow in it
80
- * (a workflow with a trigger carrying `repos:`), or one of that workflow's
81
- * static jobs, declares `approval`. Readers below this version run a global
82
- * workflow's jobs without holding them for approval, so they must refuse such a
83
- * lock rather than dispatch it ungated. Not a `BREAKING_FLOOR` move: the lock
84
- * shape is unchanged, and locks without a gated global workflow stay readable by
85
- * every orchestrator down to the floor.
86
- */
87
- const GLOBAL_APPROVAL_MIN_READER = 42;
72
+ const BREAKING_FLOOR = 42;
88
73
  /**
89
74
  * Resolve a content requirement's parse format to a concrete value. An explicit
90
75
  * non-`auto` format is returned as-is; `auto` (or unset) is resolved by the file
@@ -219,6 +204,6 @@ const changedFilesStatusSchema = z.enum([
219
204
  "skipped"
220
205
  ]);
221
206
  //#endregion
222
- export { BREAKING_FLOOR, GLOBAL_APPROVAL_MIN_READER, NeedsEntrySchema, NeedsGroupEntrySchema, NeedsRunOn, NeedsWhen, OnUnreachableMode, RunsOnPick, SANDBOX_NETWORK_MODES, SCHEMA_VERSION, changedFilesStatusSchema, isLockDynamicJobFn, isLockParallelStep, isLockStaticJob, resolveContentFormat, resolveWhenToRunOn };
207
+ export { BREAKING_FLOOR, NeedsEntrySchema, NeedsGroupEntrySchema, NeedsRunOn, NeedsWhen, OnUnreachableMode, RunsOnPick, SANDBOX_NETWORK_MODES, SCHEMA_VERSION, changedFilesStatusSchema, isLockDynamicJobFn, isLockParallelStep, isLockStaticJob, resolveContentFormat, resolveWhenToRunOn };
223
208
 
224
209
  //# sourceMappingURL=types.js.map
@@ -0,0 +1,7 @@
1
+ /**
2
+ * ISO-8601 for a timestamp column that a Postgres driver returns as a `Date`
3
+ * and a JSON round-trip or a mock returns as a string. A string passes through
4
+ * unchanged (never re-parsed).
5
+ */
6
+ export declare function toIsoString(value: Date | string): string;
7
+ //# sourceMappingURL=date.d.ts.map
@@ -0,0 +1,14 @@
1
+ import "../rolldown-runtime-ClRpJifh.js";
2
+ //#region src/util/date.ts
3
+ /**
4
+ * ISO-8601 for a timestamp column that a Postgres driver returns as a `Date`
5
+ * and a JSON round-trip or a mock returns as a string. A string passes through
6
+ * unchanged (never re-parsed).
7
+ */
8
+ function toIsoString(value) {
9
+ return value instanceof Date ? value.toISOString() : String(value);
10
+ }
11
+ //#endregion
12
+ export { toIsoString };
13
+
14
+ //# sourceMappingURL=date.js.map
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Parse a duration string like "30d", "7d", "24h" or "15m" into milliseconds.
3
+ * Returns null if the string is not a valid duration.
4
+ */
5
+ export declare function parseDuration(duration: string): number | null;
6
+ //# sourceMappingURL=parse-duration.d.ts.map
@@ -0,0 +1,21 @@
1
+ import "../rolldown-runtime-ClRpJifh.js";
2
+ //#region src/util/parse-duration.ts
3
+ /**
4
+ * Parse a duration string like "30d", "7d", "24h" or "15m" into milliseconds.
5
+ * Returns null if the string is not a valid duration.
6
+ */
7
+ function parseDuration(duration) {
8
+ const match = duration.match(/^(\d+)(d|h|m)$/);
9
+ if (!match) return null;
10
+ const value = parseInt(match[1], 10);
11
+ switch (match[2]) {
12
+ case "d": return value * 24 * 60 * 60 * 1e3;
13
+ case "h": return value * 60 * 60 * 1e3;
14
+ case "m": return value * 60 * 1e3;
15
+ default: return null;
16
+ }
17
+ }
18
+ //#endregion
19
+ export { parseDuration };
20
+
21
+ //# sourceMappingURL=parse-duration.js.map
@@ -0,0 +1,3 @@
1
+ /** Resolve after `ms` milliseconds. */
2
+ export declare function sleep(ms: number): Promise<void>;
3
+ //# sourceMappingURL=sleep.d.ts.map
@@ -0,0 +1,10 @@
1
+ import "../rolldown-runtime-ClRpJifh.js";
2
+ //#region src/util/sleep.ts
3
+ /** Resolve after `ms` milliseconds. */
4
+ function sleep(ms) {
5
+ return new Promise((resolve) => setTimeout(resolve, ms));
6
+ }
7
+ //#endregion
8
+ export { sleep };
9
+
10
+ //# sourceMappingURL=sleep.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kici-dev/engine",
3
- "version": "0.15.0",
3
+ "version": "0.16.0",
4
4
  "description": "Shared business logic for the KiCI CI/CD stack: protocol, triggers, state machine, and provider interfaces used by the Platform relay, orchestrator, and compiler.",
5
5
  "keywords": [
6
6
  "ci",
package/sbom.spdx.json CHANGED
@@ -2,10 +2,10 @@
2
2
  "spdxVersion": "SPDX-2.3",
3
3
  "dataLicense": "CC0-1.0",
4
4
  "SPDXID": "SPDXRef-DOCUMENT",
5
- "name": "@kici-dev/engine@0.15.0",
6
- "documentNamespace": "https://kici.dev/sbom/%40kici-dev%2Fengine/0.15.0/24481e55-dbc5-4970-be42-91b11ccfadb8",
5
+ "name": "@kici-dev/engine@0.16.0",
6
+ "documentNamespace": "https://kici.dev/sbom/%40kici-dev%2Fengine/0.16.0/daa1848d-44b4-4f16-8dc1-fb88a1f680f4",
7
7
  "creationInfo": {
8
- "created": "2026-10-04T12:25:10Z",
8
+ "created": "2026-10-07T15:58:42Z",
9
9
  "creators": [
10
10
  "Tool: kici-sbom-generator"
11
11
  ]
@@ -54,7 +54,7 @@
54
54
  {
55
55
  "SPDXID": "SPDXRef-RootPackage",
56
56
  "name": "@kici-dev/engine",
57
- "versionInfo": "0.15.0",
57
+ "versionInfo": "0.16.0",
58
58
  "downloadLocation": "NOASSERTION",
59
59
  "filesAnalyzed": false,
60
60
  "licenseConcluded": "NOASSERTION",
@@ -65,7 +65,7 @@
65
65
  {
66
66
  "referenceCategory": "PACKAGE-MANAGER",
67
67
  "referenceType": "purl",
68
- "referenceLocator": "pkg:npm/%40kici-dev/engine@0.15.0"
68
+ "referenceLocator": "pkg:npm/%40kici-dev/engine@0.16.0"
69
69
  }
70
70
  ],
71
71
  "description": "Shared business logic for the KiCI CI/CD stack: protocol, triggers, state machine, and provider interfaces used by the Platform relay, orchestrator, and compiler.",