@kici-dev/sdk 0.1.21 → 0.1.22

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.
@@ -58,6 +58,22 @@ export interface InventoryApi {
58
58
  /** Look up one host by agent id; null when the host is not in the roster. */
59
59
  get(agentId: string): Promise<HostInventoryEntry | null>;
60
60
  }
61
+ export interface HostApi {
62
+ /**
63
+ * Signal the orchestrator that the host this job runs on is about to reboot,
64
+ * and resolve once the orchestrator acks (which sets a persisted
65
+ * reboot-pending flag holding the pinned post-restart job). After this
66
+ * resolves, the agent issues the OS reboot once the current step completes.
67
+ *
68
+ * Used by the SDK `restartHost()` step. `deadlineMs` overrides the
69
+ * orchestrator's default host-reboot deadline. Only meaningful inside a
70
+ * running job step on an agent; a local `kici run` rejects (no orchestrator
71
+ * to ack, and a local run cannot reboot a remote host).
72
+ */
73
+ requestReboot(opts?: {
74
+ deadlineMs?: number;
75
+ }): Promise<void>;
76
+ }
61
77
  export interface KiciApi {
62
78
  /** Query orchestrator infrastructure (scalers, agents). */
63
79
  infrastructure: InfrastructureApi;
@@ -65,6 +81,8 @@ export interface KiciApi {
65
81
  inventory: InventoryApi;
66
82
  /** Request short-lived OIDC ID tokens for the current job (build provenance). */
67
83
  oidc: OidcApi;
84
+ /** Host-lifecycle operations on the agent's own host (e.g. reboot). */
85
+ host: HostApi;
68
86
  }
69
87
  /**
70
88
  * Low-level transport function used to implement KiciApi.
package/dist/api-types.js CHANGED
@@ -36,7 +36,8 @@ function buildKiciApi(transport, jobCtx) {
36
36
  jobId: jobCtx.jobId,
37
37
  audience: opts.audience
38
38
  });
39
- } }
39
+ } },
40
+ host: { requestReboot: (opts) => transport("host.requestReboot", { ...opts?.deadlineMs !== void 0 ? { deadlineMs: opts.deadlineMs } : {} }) }
40
41
  };
41
42
  }
42
43
  //#endregion
@@ -1,8 +1,9 @@
1
1
  /**
2
2
  * Workflow-author API for declaring a manual approval gate at step, job, or
3
- * workflow level. The author writes `requireApproval`; the compiler normalizes
4
- * it into the lock file's `approval` block, and the orchestrator turns it into
5
- * a held element at dispatch time.
3
+ * workflow level. The author writes `approval`; the compiler normalizes it
4
+ * into the lock file's `approval` block, and the orchestrator turns it into a
5
+ * held element at dispatch time (for `when: 'always'`) or the agent turns it
6
+ * into a mid-step drift gate (for `when: 'drift'`).
6
7
  */
7
8
  /** A single approver clause: any member of a team, or a specific user. */
8
9
  export type ApproverClause = {
@@ -10,25 +11,39 @@ export type ApproverClause = {
10
11
  } | {
11
12
  user: string;
12
13
  };
14
+ /**
15
+ * When the gate fires.
16
+ *
17
+ * - `always` (default) — gate BEFORE the element runs, with a static reason.
18
+ * Valid at step / job / workflow scope.
19
+ * - `drift` — gate BETWEEN a step's `check` and `run`, only when `check`
20
+ * returns drift in apply mode. Step-scope only; requires a `check` facet.
21
+ */
22
+ export type ApprovalWhen = 'always' | 'drift';
13
23
  /**
14
24
  * Declarative approval requirement.
15
25
  *
16
26
  * - `true` — pause for ANY org member with the approval permission.
17
27
  * - `ApproverClause[]` — a flat AND list (all clauses must be satisfied).
18
- * - object form — clauses plus an optional human `reason` and a per-gate
19
- * `timeout` (seconds) that overrides the org-default expiry.
28
+ * - object form — clauses plus an optional `when`, a human `reason`, and a
29
+ * per-gate `timeout` (seconds) that overrides the org-default expiry.
20
30
  */
21
- export type RequireApproval = true | ApproverClause[] | {
22
- approvers: ApproverClause[];
31
+ export type ApprovalConfig = true | ApproverClause[] | {
32
+ when?: ApprovalWhen;
33
+ approvers?: ApproverClause[];
23
34
  reason?: string;
24
35
  timeout?: number;
25
36
  };
26
37
  /** The normalized shape written into the lock file. */
27
- export interface NormalizedRequireApproval {
38
+ export interface NormalizedApproval {
28
39
  clauses: ApproverClause[];
29
40
  reason?: string;
30
41
  timeoutSeconds?: number;
42
+ when: ApprovalWhen;
31
43
  }
32
- /** Normalize any `RequireApproval` form into `{ clauses, reason?, timeoutSeconds? }`. */
33
- export declare function normalizeRequireApproval(r: RequireApproval): NormalizedRequireApproval;
44
+ /**
45
+ * Normalize any `ApprovalConfig` form into
46
+ * `{ clauses, reason?, timeoutSeconds?, when }`. `when` defaults to `'always'`.
47
+ */
48
+ export declare function normalizeApproval(c: ApprovalConfig): NormalizedApproval;
34
49
  //# sourceMappingURL=approval.d.ts.map
package/dist/approval.js CHANGED
@@ -1,16 +1,26 @@
1
1
  import "./chunk-BTugEXQM.js";
2
2
  //#region src/approval.ts
3
- /** Normalize any `RequireApproval` form into `{ clauses, reason?, timeoutSeconds? }`. */
4
- function normalizeRequireApproval(r) {
5
- if (r === true) return { clauses: [] };
6
- if (Array.isArray(r)) return { clauses: r };
3
+ /**
4
+ * Normalize any `ApprovalConfig` form into
5
+ * `{ clauses, reason?, timeoutSeconds?, when }`. `when` defaults to `'always'`.
6
+ */
7
+ function normalizeApproval(c) {
8
+ if (c === true) return {
9
+ clauses: [],
10
+ when: "always"
11
+ };
12
+ if (Array.isArray(c)) return {
13
+ clauses: c,
14
+ when: "always"
15
+ };
7
16
  return {
8
- clauses: r.approvers,
9
- reason: r.reason,
10
- timeoutSeconds: r.timeout
17
+ clauses: c.approvers ?? [],
18
+ ...c.reason !== void 0 && { reason: c.reason },
19
+ ...c.timeout !== void 0 && { timeoutSeconds: c.timeout },
20
+ when: c.when ?? "always"
11
21
  };
12
22
  }
13
23
  //#endregion
14
- export { normalizeRequireApproval };
24
+ export { normalizeApproval };
15
25
 
16
26
  //# sourceMappingURL=approval.js.map
package/dist/context.d.ts CHANGED
@@ -261,6 +261,15 @@ export interface StepContext<TInputs = Record<string, unknown>> {
261
261
  * the agent digests with SHA-256.
262
262
  */
263
263
  attestProvenance(opts: import('./provenance-types.js').AttestProvenanceOptions): Promise<import('./provenance-types.js').AttestProvenanceResult>;
264
+ /**
265
+ * Upstream needs resolved for this job, keyed by upstream job or group name.
266
+ * `ctx.needs.<job>.result` is the upstream's outputs proxy and
267
+ * `ctx.needs.<job>.status` its terminal status (`success | failed | skipped |
268
+ * …`). A group / matrix / `runsOnAll` fan-out upstream is an ordered array of
269
+ * `{ name, result, status }`, one entry per child. Undefined for a job with no
270
+ * declared `needs`.
271
+ */
272
+ needs?: import('./needs-context.js').NeedsContext;
264
273
  }
265
274
  export {};
266
275
  //# sourceMappingURL=context.d.ts.map
@@ -6,22 +6,24 @@
6
6
  *
7
7
  * Usage in workflow definition:
8
8
  * needs: [dynamicGroup('test-shards')]
9
- * needs: [dynamicGroup('test-shards', { ifFailed: 'run' })]
9
+ * needs: [dynamicGroup('test-shards', { when: 'always' })]
10
10
  */
11
+ import type { NeedsWhenInput } from './types.js';
11
12
  declare const DYNAMIC_GROUP_TAG: unique symbol;
12
13
  export interface DynamicGroupRef {
13
14
  readonly [DYNAMIC_GROUP_TAG]: true;
14
15
  readonly group: string;
15
- readonly ifFailed?: 'skip' | 'run';
16
+ /** Run condition for the edge: keyword sugar or a raw upstream-status set. */
17
+ readonly when?: NeedsWhenInput;
16
18
  }
17
19
  /**
18
20
  * Create a reference to a dynamic job group for use in a static job's `needs` array.
19
21
  *
20
22
  * @param name - The group name (must match the name used in `dynamicJob(name, fn)`)
21
- * @param opts - Optional failure policy override
23
+ * @param opts - Optional run condition for the edge
22
24
  */
23
25
  export declare function dynamicGroup(name: string, opts?: {
24
- ifFailed?: 'skip' | 'run';
26
+ when?: NeedsWhenInput;
25
27
  }): DynamicGroupRef;
26
28
  /** Type guard to check if a value is a DynamicGroupRef. */
27
29
  export declare function isDynamicGroupRef(value: unknown): value is DynamicGroupRef;
@@ -1,27 +1,17 @@
1
1
  import "./chunk-BTugEXQM.js";
2
2
  //#region src/dynamic-group.ts
3
- /**
4
- * Dynamic group helpers for cross-domain needs.
5
- *
6
- * A DynamicGroupRef allows static jobs to declare a dependency on a dynamic
7
- * job group by name, without knowing the concrete generated job names.
8
- *
9
- * Usage in workflow definition:
10
- * needs: [dynamicGroup('test-shards')]
11
- * needs: [dynamicGroup('test-shards', { ifFailed: 'run' })]
12
- */
13
3
  const DYNAMIC_GROUP_TAG = Symbol.for("kici:dynamicGroup");
14
4
  /**
15
5
  * Create a reference to a dynamic job group for use in a static job's `needs` array.
16
6
  *
17
7
  * @param name - The group name (must match the name used in `dynamicJob(name, fn)`)
18
- * @param opts - Optional failure policy override
8
+ * @param opts - Optional run condition for the edge
19
9
  */
20
10
  function dynamicGroup(name, opts) {
21
11
  return {
22
12
  [DYNAMIC_GROUP_TAG]: true,
23
13
  group: name,
24
- ...opts?.ifFailed && { ifFailed: opts.ifFailed }
14
+ ...opts?.when !== void 0 && { when: opts.when }
25
15
  };
26
16
  }
27
17
  /** Type guard to check if a value is a DynamicGroupRef. */
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Workflow-level host restart + wait-for-host-alive steps.
3
+ *
4
+ * KiCI agents run ON each host while executing a job, so a workflow can reboot
5
+ * the machine it runs on (the Ansible `reboot` + `wait_for_connection` pattern,
6
+ * adapted to KiCI's no-remote-exec model). The flow is job-boundary:
7
+ *
8
+ * - `restartHost()` is the LAST step of a "restart" job. It signals the
9
+ * orchestrator that this host is about to reboot (which holds the pinned
10
+ * post-restart job and treats the imminent disconnect as expected), reports
11
+ * success, and the agent issues the OS reboot once the step completes.
12
+ * - The post-restart work is a SEPARATE job pinned to the same host
13
+ * (`runsOn: [hostId]`) that `needs` the restart job. The orchestrator holds
14
+ * it until the host completes a reboot cycle, then dispatches it.
15
+ * - `waitForHostAlive(probe)` is the optional first step of that post-restart
16
+ * job: the "host is back" guarantee comes free from the pinned-hold (the job
17
+ * only dispatches after the agent reconnects); this step adds a
18
+ * service-readiness gate for hosts where "agent connected" ≠ "services ready".
19
+ */
20
+ import type { Step } from './types.js';
21
+ export interface WaitForHostAliveOptions {
22
+ /** Step name surfaced in logs. Defaults to 'wait-for-host-alive'. */
23
+ name?: string;
24
+ /** Time between successive probe invocations, ms. Defaults to 3000. */
25
+ intervalMs?: number;
26
+ /** Total time budget for readiness, ms. Defaults to 300000 (5 min). */
27
+ timeoutMs?: number;
28
+ }
29
+ /**
30
+ * Optional first step of a post-restart job. Polls a readiness probe until it
31
+ * resolves (services back up after a reboot). The host being reconnected is
32
+ * already guaranteed by the pinned-hold; this gates on service readiness.
33
+ *
34
+ * A probe that throws/rejects keeps polling (the `waitFor` swallow-errors
35
+ * default — the "poll until healthy" pattern). Any non-null resolution means
36
+ * "ready". Exceeding `timeoutMs` fails the step ("services did not come up").
37
+ */
38
+ export declare function waitForHostAlive(probe: () => Promise<unknown> | unknown, opts?: WaitForHostAliveOptions): Step<unknown>;
39
+ export interface RestartHostOptions {
40
+ /**
41
+ * Max time the orchestrator waits for the host to return after the reboot,
42
+ * ms. Defaults to the orchestrator's `KICI_HOST_REBOOT_DEADLINE_MS`.
43
+ */
44
+ deadlineMs?: number;
45
+ }
46
+ /**
47
+ * Reboot the host this job runs on. MUST be the last step of a "restart" job;
48
+ * the post-restart work goes in a separate job that `needs` this one and is
49
+ * pinned to the same host (`runsOn: [hostId]`). The orchestrator holds that job
50
+ * until the host completes a reboot cycle, then dispatches it.
51
+ *
52
+ * The step signals the orchestrator (reboot-pending) and reports success; the
53
+ * agent issues the actual OS reboot after the step completes. Rebooting needs
54
+ * host privilege: if the OS reboot primitive is denied, the step fails with a
55
+ * clear privilege error and the orchestrator clears the reboot-pending flag.
56
+ */
57
+ export declare function restartHost(opts?: RestartHostOptions): Step<void>;
58
+ //# sourceMappingURL=host-restart.d.ts.map
@@ -0,0 +1,63 @@
1
+ import "./chunk-BTugEXQM.js";
2
+ import { step } from "./step.js";
3
+ import { waitForStep } from "./wait-for.js";
4
+ //#region src/host-restart.ts
5
+ /**
6
+ * Workflow-level host restart + wait-for-host-alive steps.
7
+ *
8
+ * KiCI agents run ON each host while executing a job, so a workflow can reboot
9
+ * the machine it runs on (the Ansible `reboot` + `wait_for_connection` pattern,
10
+ * adapted to KiCI's no-remote-exec model). The flow is job-boundary:
11
+ *
12
+ * - `restartHost()` is the LAST step of a "restart" job. It signals the
13
+ * orchestrator that this host is about to reboot (which holds the pinned
14
+ * post-restart job and treats the imminent disconnect as expected), reports
15
+ * success, and the agent issues the OS reboot once the step completes.
16
+ * - The post-restart work is a SEPARATE job pinned to the same host
17
+ * (`runsOn: [hostId]`) that `needs` the restart job. The orchestrator holds
18
+ * it until the host completes a reboot cycle, then dispatches it.
19
+ * - `waitForHostAlive(probe)` is the optional first step of that post-restart
20
+ * job: the "host is back" guarantee comes free from the pinned-hold (the job
21
+ * only dispatches after the agent reconnects); this step adds a
22
+ * service-readiness gate for hosts where "agent connected" ≠ "services ready".
23
+ */
24
+ /**
25
+ * Optional first step of a post-restart job. Polls a readiness probe until it
26
+ * resolves (services back up after a reboot). The host being reconnected is
27
+ * already guaranteed by the pinned-hold; this gates on service readiness.
28
+ *
29
+ * A probe that throws/rejects keeps polling (the `waitFor` swallow-errors
30
+ * default — the "poll until healthy" pattern). Any non-null resolution means
31
+ * "ready". Exceeding `timeoutMs` fails the step ("services did not come up").
32
+ */
33
+ function waitForHostAlive(probe, opts = {}) {
34
+ return waitForStep(opts.name ?? "wait-for-host-alive", {
35
+ check: async () => {
36
+ return await probe() ?? true;
37
+ },
38
+ intervalMs: opts.intervalMs ?? 3e3,
39
+ timeoutMs: opts.timeoutMs ?? 3e5
40
+ });
41
+ }
42
+ /**
43
+ * Reboot the host this job runs on. MUST be the last step of a "restart" job;
44
+ * the post-restart work goes in a separate job that `needs` this one and is
45
+ * pinned to the same host (`runsOn: [hostId]`). The orchestrator holds that job
46
+ * until the host completes a reboot cycle, then dispatches it.
47
+ *
48
+ * The step signals the orchestrator (reboot-pending) and reports success; the
49
+ * agent issues the actual OS reboot after the step completes. Rebooting needs
50
+ * host privilege: if the OS reboot primitive is denied, the step fails with a
51
+ * clear privilege error and the orchestrator clears the reboot-pending flag.
52
+ */
53
+ function restartHost(opts = {}) {
54
+ return step("restart-host", { run: async (ctx) => {
55
+ ctx.log.info("Requesting host reboot…");
56
+ await ctx.kici.host.requestReboot({ deadlineMs: opts.deadlineMs });
57
+ ctx.log.info("Reboot acknowledged; host will reboot after this step completes.");
58
+ } });
59
+ }
60
+ //#endregion
61
+ export { restartHost, waitForHostAlive };
62
+
63
+ //# sourceMappingURL=host-restart.js.map
package/dist/index.d.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  export { step } from './step.js';
2
2
  export { job } from './job.js';
3
3
  export { workflow } from './workflow.js';
4
- export { normalizeRequireApproval } from './approval.js';
5
- export type { RequireApproval, ApproverClause, NormalizedRequireApproval } from './approval.js';
4
+ export { normalizeApproval } from './approval.js';
5
+ export type { ApprovalConfig, ApprovalWhen, ApproverClause, NormalizedApproval, } from './approval.js';
6
6
  export { pr, push, tag, comment, review, reviewComment, release, dispatch, create, delete as delete, status, workflowRun, fork, star, watch, webhook, kiciEvent, workflowComplete, jobComplete, genericWebhook, schedule, lifecycle, } from './triggers/index.js';
7
7
  export type { TriggerConfig, PrTriggerConfig, PushTriggerConfig, TagTriggerConfig, CommentTriggerConfig, ReviewTriggerConfig, ReviewCommentTriggerConfig, ReleaseTriggerConfig, DispatchTriggerConfig, CreateTriggerConfig, DeleteTriggerConfig, StatusTriggerConfig, WorkflowRunTriggerConfig, ForkTriggerConfig, StarTriggerConfig, WatchTriggerConfig, WebhookTriggerConfig, BranchPattern, BodyMatchPattern, PrEvent, PushEvent, PrConfigInput, PushConfigInput, TagConfigInput, CommentConfigInput, CommentAction, CommentSource, ReviewConfigInput, ReviewAction, ReviewState, ReviewCommentConfigInput, ReviewCommentAction, ReleaseConfigInput, ReleaseAction, DispatchConfigInput, CreateConfigInput, DeleteConfigInput, RefType, StatusConfigInput, StatusState, WorkflowRunConfigInput, WorkflowRunAction, ForkConfigInput, StarConfigInput, StarAction, WatchConfigInput, WatchAction, WebhookConfigInput, KiciEventConfigInput, KiciEventTriggerConfig, WorkflowCompleteConfigInput, WorkflowCompleteTriggerConfig, WorkflowCompleteStatus, JobCompleteConfigInput, JobCompleteTriggerConfig, JobCompleteStatus, GenericWebhookConfigInput, GenericWebhookTriggerConfig, GenericWebhookAuthMethod, GenericWebhookHmacAuth, GenericWebhookApiKeyAuth, GenericWebhookAuth, ScheduleConfigInput, ScheduleTriggerConfig, LifecycleEvent, LifecycleConfigInput, LifecycleTriggerConfig, } from './triggers/index.js';
8
8
  export { onCancel, cleanup, onSuccess, onFailure, beforeStep, afterStep } from './hooks/index.js';
@@ -15,7 +15,7 @@ export { validateDag } from './validation/index.js';
15
15
  export type { DagNode, DagValidationResult } from './validation/index.js';
16
16
  export type { SourceLocation, OutputProxy, Step, StepOptions, StepOptionsBase, StepOptionsPlain, StepOptionsWithCheck, StepRunFn, BareStepFn, StepInput, OutputSchema, InferOutputs, Job, JobOptions, GenericInitConfig, MiseInitConfig, InitPreset, InitItem, InitConfig, ContainerConfig, RunsOnSelector, RunsOn, Workflow, WorkflowOptions, Registry, Trigger, DynamicJobFn, DynamicJobContext, JobOrFactory, } from './types.js';
17
17
  export { isDynamicJobFn, dynamicJob, getDynamicJobGroup, getDynamicJobNeeds, DYNAMIC_JOB_GROUP_TAG, DYNAMIC_JOB_NEEDS_TAG, } from './types.js';
18
- export type { TaggedDynamicJobFn, ResultAwareDynamicJobConfig, ResultAwareDynamicJobFn, DynamicJobNeed, } from './types.js';
18
+ export type { TaggedDynamicJobFn, ResultAwareDynamicJobConfig, ResultAwareDynamicJobFn, DynamicJobNeed, NeedsWhen, NeedsWhenInput, } from './types.js';
19
19
  export { buildNeedsContext } from './needs-context.js';
20
20
  export type { UpstreamSnapshot, NeedsContext, NeedEntry, GroupNeedEntry } from './needs-context.js';
21
21
  export { CacheSpecSchema, normalizeCacheSpecs } from './cache-types.js';
@@ -28,7 +28,7 @@ export type { DynamicGroupRef } from './dynamic-group.js';
28
28
  export type { StepContext, Logger, WorkflowInfo, JobInfo, AgentInfo, MatrixJobOutputs, HostJobOutputs, RepoInfo, StepSecretsTyped, KnownSecretKeys, } from './context.js';
29
29
  export { isMatrixJobOutputs, isHostJobOutputs } from './context.js';
30
30
  export { buildKiciApi } from './api-types.js';
31
- export type { KiciApi, KiciApiTransport, InfrastructureApi, InfrastructureListResult, InventoryApi, HostInventoryEntry, InventorySelector, } from './api-types.js';
31
+ export type { KiciApi, KiciApiTransport, InfrastructureApi, InfrastructureListResult, InventoryApi, HostApi, HostInventoryEntry, InventorySelector, } from './api-types.js';
32
32
  export { SecretNotFoundError } from './errors.js';
33
33
  export { createStepSecrets } from './secrets.js';
34
34
  export type { StepSecrets, TrackedStepSecrets, SecretMeta, SecretFileOptions, MountedFile, StepSecretsFileHost, StepSecretsFileWiring, StepSecretsHandle, StepSecretMountKind, StepSecretMountRecord, } from './secrets.js';
@@ -46,5 +46,7 @@ export { idempotent, idempotentStep } from './idempotent.js';
46
46
  export type { IdempotentOptions, IdempotentResult } from './idempotent.js';
47
47
  export { waitFor, waitForStep, WaitForTimeoutError } from './wait-for.js';
48
48
  export type { WaitForOptions, WaitForResult } from './wait-for.js';
49
+ export { waitForHostAlive, restartHost } from './host-restart.js';
50
+ export type { WaitForHostAliveOptions, RestartHostOptions } from './host-restart.js';
49
51
  export { z } from 'zod';
50
52
  //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import "./chunk-BTugEXQM.js";
2
2
  import { buildKiciApi } from "./api-types.js";
3
- import { normalizeRequireApproval } from "./approval.js";
3
+ import { normalizeApproval } from "./approval.js";
4
4
  import { CacheSpecSchema, normalizeCacheSpecs } from "./cache-types.js";
5
5
  import { isHostJobOutputs, isMatrixJobOutputs } from "./context.js";
6
6
  import { DYNAMIC_GROUP_TAG, dynamicGroup, isDynamicGroupRef } from "./dynamic-group.js";
@@ -8,6 +8,8 @@ import { SecretNotFoundError } from "./errors.js";
8
8
  import { fixture } from "./fixture.js";
9
9
  import { createJobOutputProxy, createSnapshotOutputProxy, createStepOutputProxy, getJobOutputsMap, getStepOutputsMap, getStepRefMap, resolveJobOutputs, resolveStepOutputs, setJobOutputsMap, setStepOutputsMap, setStepRefMap } from "./outputs.js";
10
10
  import { step } from "./step.js";
11
+ import { WaitForTimeoutError, waitFor, waitForStep } from "./wait-for.js";
12
+ import { restartHost, waitForHostAlive } from "./host-restart.js";
11
13
  import { idempotent, idempotentStep } from "./idempotent.js";
12
14
  import { job } from "./job.js";
13
15
  import { workflow } from "./workflow.js";
@@ -50,6 +52,5 @@ import { applyIncludeExclude, expandMatrix } from "./matrix/expand.js";
50
52
  import "./matrix/index.js";
51
53
  import { defineEvent } from "./events/define-event.js";
52
54
  import "./events/index.js";
53
- import { WaitForTimeoutError, waitFor, waitForStep } from "./wait-for.js";
54
55
  import { z } from "zod";
55
- export { CacheSpecSchema, DYNAMIC_GROUP_TAG, DYNAMIC_JOB_GROUP_TAG, DYNAMIC_JOB_NEEDS_TAG, SecretNotFoundError, WaitForTimeoutError, afterStep, applyIncludeExclude, beforeStep, buildKiciApi, buildNeedsContext, cleanup, comment, create, createJobOutputProxy, createSnapshotOutputProxy, createStepOutputProxy, createStepSecrets, defineEvent, del as delete, dispatch, dynamicGroup, dynamicJob, evaluateRules, expandMatrix, fixture, fork, genericWebhook, getDynamicJobGroup, getDynamicJobNeeds, getJobOutputsMap, getStepOutputsMap, getStepRefMap, idempotent, idempotentStep, isDynamicFunction, isDynamicGroupRef, isDynamicJobFn, isEventType, isHostJobOutputs, isMatrixJobOutputs, isStaticArray, isStaticObject, job, jobComplete, kiciEvent, lifecycle, normalizeCacheSpecs, normalizeRequireApproval, onCancel, onFailure, onSuccess, pr, provenanceSubjectIsPath, push, release, resolveJobOutputs, resolveStepOutputs, review, reviewComment, rule, schedule, setJobOutputsMap, setStepOutputsMap, setStepRefMap, skip, star, status, step, tag, validateDag, waitFor, waitForStep, watch, webhook, workflow, workflowComplete, workflowRun, z };
56
+ export { CacheSpecSchema, DYNAMIC_GROUP_TAG, DYNAMIC_JOB_GROUP_TAG, DYNAMIC_JOB_NEEDS_TAG, SecretNotFoundError, WaitForTimeoutError, afterStep, applyIncludeExclude, beforeStep, buildKiciApi, buildNeedsContext, cleanup, comment, create, createJobOutputProxy, createSnapshotOutputProxy, createStepOutputProxy, createStepSecrets, defineEvent, del as delete, dispatch, dynamicGroup, dynamicJob, evaluateRules, expandMatrix, fixture, fork, genericWebhook, getDynamicJobGroup, getDynamicJobNeeds, getJobOutputsMap, getStepOutputsMap, getStepRefMap, idempotent, idempotentStep, isDynamicFunction, isDynamicGroupRef, isDynamicJobFn, isEventType, isHostJobOutputs, isMatrixJobOutputs, isStaticArray, isStaticObject, job, jobComplete, kiciEvent, lifecycle, normalizeApproval, normalizeCacheSpecs, onCancel, onFailure, onSuccess, pr, provenanceSubjectIsPath, push, release, resolveJobOutputs, resolveStepOutputs, restartHost, review, reviewComment, rule, schedule, setJobOutputsMap, setStepOutputsMap, setStepRefMap, skip, star, status, step, tag, validateDag, waitFor, waitForHostAlive, waitForStep, watch, webhook, workflow, workflowComplete, workflowRun, z };
package/dist/job.js CHANGED
@@ -66,7 +66,7 @@ function job(nameOrOptions, maybeOptions) {
66
66
  resources: options.resources,
67
67
  init: options.init,
68
68
  ...options.cache !== void 0 && { cache: options.cache },
69
- ...options.requireApproval !== void 0 && { requireApproval: options.requireApproval },
69
+ ...options.approval !== void 0 && { approval: options.approval },
70
70
  result: createJobOutputProxy(name)
71
71
  };
72
72
  }
@@ -1,31 +1,38 @@
1
1
  import type { OutputProxy, DynamicJobNeed } from './types.js';
2
+ import type { ExecutionJobStatus } from '@kici-dev/engine';
2
3
  /**
3
- * Frozen snapshot of upstream outputs, captured once at first eval of a
4
- * result-aware dynamic generator and replayed unchanged on re-eval.
4
+ * Frozen snapshot of upstream outputs + statuses, captured once at first eval of
5
+ * a result-aware dynamic generator and replayed unchanged on re-eval.
5
6
  *
6
7
  * - `jobs` maps an upstream job name to its outputs record.
7
8
  * - `groups` maps a dynamic group name to its ordered member job names.
9
+ * - `statuses` maps an upstream job name to its terminal status. Absent entries
10
+ * default to `success` (the only status that satisfies a default needs edge,
11
+ * so an upstream resolved into the snapshot is success unless told otherwise).
8
12
  */
9
13
  export interface UpstreamSnapshot {
10
14
  jobs: Record<string, Record<string, unknown>>;
11
15
  groups: Record<string, string[]>;
16
+ statuses?: Record<string, ExecutionJobStatus>;
12
17
  }
13
18
  /** One entry in the array exposed for a `dynamicGroup(...)` need. */
14
19
  export interface GroupNeedEntry {
15
20
  name: string;
16
21
  result: OutputProxy<any>;
22
+ status: ExecutionJobStatus;
17
23
  }
18
- /** A single-job need exposes `{ result }`; a group need exposes an ordered array. */
24
+ /** A single-job need exposes `{ result, status }`; a group need exposes an ordered array. */
19
25
  export type NeedEntry = {
20
26
  result: OutputProxy<any>;
27
+ status: ExecutionJobStatus;
21
28
  } | GroupNeedEntry[];
22
29
  /** The resolved `ctx.needs` map keyed by job name or group name. */
23
30
  export type NeedsContext = Record<string, NeedEntry>;
24
31
  /**
25
32
  * Resolve declared needs against a frozen snapshot into the `ctx.needs` map.
26
33
  *
27
- * - A single static/named-job need resolves to `{ result: <proxy over jobs[name]> }`.
28
- * - A `dynamicGroup(...)` need resolves to an ordered array of `{ name, result }`,
34
+ * - A single static/named-job need resolves to `{ result: <proxy over jobs[name]>, status }`.
35
+ * - A `dynamicGroup(...)` need resolves to an ordered array of `{ name, result, status }`,
29
36
  * one entry per group member in the snapshot's deterministic eval order.
30
37
  */
31
38
  export declare function buildNeedsContext(snapshot: UpstreamSnapshot, declaredNeeds: ReadonlyArray<DynamicJobNeed>): NeedsContext;
@@ -19,11 +19,15 @@ function needKey(need) {
19
19
  key: need.name
20
20
  };
21
21
  }
22
+ /** Read an upstream's terminal status from the snapshot, defaulting to success. */
23
+ function statusFor(snapshot, name) {
24
+ return snapshot.statuses?.[name] ?? "success";
25
+ }
22
26
  /**
23
27
  * Resolve declared needs against a frozen snapshot into the `ctx.needs` map.
24
28
  *
25
- * - A single static/named-job need resolves to `{ result: <proxy over jobs[name]> }`.
26
- * - A `dynamicGroup(...)` need resolves to an ordered array of `{ name, result }`,
29
+ * - A single static/named-job need resolves to `{ result: <proxy over jobs[name]>, status }`.
30
+ * - A `dynamicGroup(...)` need resolves to an ordered array of `{ name, result, status }`,
27
31
  * one entry per group member in the snapshot's deterministic eval order.
28
32
  */
29
33
  function buildNeedsContext(snapshot, declaredNeeds) {
@@ -32,9 +36,13 @@ function buildNeedsContext(snapshot, declaredNeeds) {
32
36
  const { kind, key } = needKey(need);
33
37
  if (kind === "group") out[key] = (snapshot.groups[key] ?? []).map((name) => ({
34
38
  name,
35
- result: createSnapshotOutputProxy(name, snapshot.jobs[name])
39
+ result: createSnapshotOutputProxy(name, snapshot.jobs[name]),
40
+ status: statusFor(snapshot, name)
36
41
  }));
37
- else out[key] = { result: createSnapshotOutputProxy(key, snapshot.jobs[key]) };
42
+ else out[key] = {
43
+ result: createSnapshotOutputProxy(key, snapshot.jobs[key]),
44
+ status: statusFor(snapshot, key)
45
+ };
38
46
  }
39
47
  return out;
40
48
  }
package/dist/step.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import "./chunk-BTugEXQM.js";
2
+ import { normalizeApproval } from "./approval.js";
2
3
  import { createStepOutputProxy } from "./outputs.js";
3
4
  //#region src/step.ts
4
5
  /**
@@ -59,6 +60,7 @@ function step(nameOrRunOrOptions, runOrOptions) {
59
60
  options = nameOrRunOrOptions;
60
61
  }
61
62
  if (options.check && !options.summarize) throw new Error("summarize is required when check is set");
63
+ if (options.approval !== void 0 && normalizeApproval(options.approval).when === "drift" && !options.check) throw new Error("approval.when \"drift\" requires a check facet");
62
64
  return {
63
65
  _tag: "Step",
64
66
  name,
@@ -74,7 +76,7 @@ function step(nameOrRunOrOptions, runOrOptions) {
74
76
  rules: options.rules,
75
77
  onCancel: options.onCancel,
76
78
  cleanup: options.cleanup,
77
- ...options.requireApproval !== void 0 && { requireApproval: options.requireApproval },
79
+ ...options.approval !== void 0 && { approval: options.approval },
78
80
  _sourceLocation,
79
81
  result: createStepOutputProxy(name)
80
82
  };
package/dist/types.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import type { z } from 'zod';
2
2
  import type { $ as Shell } from 'zx';
3
- import type { ResourceRequest, RunsOnAllInput, OnUnreachableMode } from '@kici-dev/engine';
3
+ import type { ResourceRequest, RunsOnAllInput, OnUnreachableMode, NeedsWhen, ExecutionJobStatus } from '@kici-dev/engine';
4
4
  import type { StepContext, Logger } from './context.js';
5
5
  import type { TriggerConfig } from './triggers/types.js';
6
6
  import type { Rule } from './rules/types.js';
@@ -9,8 +9,15 @@ import type { HookInput } from './hooks/types.js';
9
9
  import type { KiciApi } from './api-types.js';
10
10
  import type { DynamicGroupRef } from './dynamic-group.js';
11
11
  import type { EventPayload } from './events/event-payloads.js';
12
- import type { RequireApproval } from './approval.js';
13
- export type { ResourceRequest, ResourceSpec, RunsOnAllInput, OnUnreachableMode, } from '@kici-dev/engine';
12
+ import type { ApprovalConfig } from './approval.js';
13
+ export type { ResourceRequest, ResourceSpec, RunsOnAllInput, OnUnreachableMode, NeedsWhen, } from '@kici-dev/engine';
14
+ /**
15
+ * Author-facing run condition for a `needs` edge: keyword sugar
16
+ * (`'on-success'` | `'always'` | `'on-skip'` | `'on-failure'`) or a raw set of
17
+ * upstream terminal statuses. Resolved to a normalized status-set at compile
18
+ * time; the downstream runs when the upstream's terminal status is a member.
19
+ */
20
+ export type NeedsWhenInput = NeedsWhen | ExecutionJobStatus[];
14
21
  /** Source location captured at a step() call site. */
15
22
  export interface SourceLocation {
16
23
  readonly file: string;
@@ -65,8 +72,8 @@ export interface Step<TResult = void> {
65
72
  readonly onCancel?: HookInput;
66
73
  /** Always runs after step (success, failure, or cancel). */
67
74
  readonly cleanup?: HookInput;
68
- /** Pause for a manual human approval before this step runs. */
69
- readonly requireApproval?: RequireApproval;
75
+ /** Pause for a manual human approval (before this step, or on drift). */
76
+ readonly approval?: ApprovalConfig;
70
77
  /** Internal: source location captured at step() call site. Not part of public API. */
71
78
  readonly _sourceLocation?: SourceLocation;
72
79
  /**
@@ -107,8 +114,8 @@ export interface StepOptionsBase {
107
114
  onCancel?: HookInput;
108
115
  /** Always runs after step (success, failure, or cancel). */
109
116
  cleanup?: HookInput;
110
- /** Pause for a manual human approval before this step runs. */
111
- requireApproval?: RequireApproval;
117
+ /** Pause for a manual human approval (before this step, or on drift). */
118
+ approval?: ApprovalConfig;
112
119
  }
113
120
  /**
114
121
  * Plain step options: `run` takes only the context — the existing, fully
@@ -249,10 +256,10 @@ declare const DYNAMIC_JOB_NEEDS_TAG: unique symbol;
249
256
  */
250
257
  export type DynamicJobNeed = Job | string | DynamicGroupRef | {
251
258
  name: string;
252
- ifFailed?: 'skip' | 'run';
259
+ when?: NeedsWhenInput;
253
260
  } | {
254
261
  group: string;
255
- ifFailed?: 'skip' | 'run';
262
+ when?: NeedsWhenInput;
256
263
  };
257
264
  /**
258
265
  * Options-object form of {@link dynamicJob}: a result-aware generator that is
@@ -391,10 +398,10 @@ export interface Job {
391
398
  readonly steps: readonly StepInput[];
392
399
  readonly needs?: ReadonlyArray<Job | string | DynamicGroupRef | {
393
400
  name: string;
394
- ifFailed: 'skip' | 'run';
401
+ when?: NeedsWhenInput;
395
402
  } | {
396
403
  group: string;
397
- ifFailed: 'skip' | 'run';
404
+ when?: NeedsWhenInput;
398
405
  }>;
399
406
  /** Rules for conditional execution */
400
407
  readonly rules?: Rule[];
@@ -457,7 +464,7 @@ export interface Job {
457
464
  /** Declarative cache: restored before steps, saved after the job on key miss. */
458
465
  readonly cache?: import('./cache-types.js').CacheInput;
459
466
  /** Pause for a manual human approval before this job dispatches. */
460
- readonly requireApproval?: RequireApproval;
467
+ readonly approval?: ApprovalConfig;
461
468
  /**
462
469
  * Type-safe proxy for accessing this job's outputs.
463
470
  * For multi-step jobs: jobRef.result.stepName.field
@@ -510,10 +517,10 @@ export interface JobOptions {
510
517
  run?: (ctx: StepContext) => Promise<any>;
511
518
  needs?: Array<Job | string | DynamicGroupRef | {
512
519
  name: string;
513
- ifFailed: 'skip' | 'run';
520
+ when?: NeedsWhenInput;
514
521
  } | {
515
522
  group: string;
516
- ifFailed: 'skip' | 'run';
523
+ when?: NeedsWhenInput;
517
524
  }>;
518
525
  /** Rules that must pass for job to execute */
519
526
  rules?: Rule[];
@@ -591,7 +598,7 @@ export interface JobOptions {
591
598
  /** Declarative cache: restored before steps, saved after the job on key miss. */
592
599
  cache?: import('./cache-types.js').CacheInput;
593
600
  /** Pause for a manual human approval before this job dispatches. */
594
- requireApproval?: RequireApproval;
601
+ approval?: ApprovalConfig;
595
602
  }
596
603
  /**
597
604
  * Private npm registry declaration. Tells the agent to authenticate against
@@ -670,7 +677,7 @@ export interface Workflow {
670
677
  readonly max?: number;
671
678
  };
672
679
  /** Pause for a manual human approval before the whole workflow dispatches. */
673
- readonly requireApproval?: RequireApproval;
680
+ readonly approval?: ApprovalConfig;
674
681
  }
675
682
  /** Options for workflow() factory */
676
683
  export interface WorkflowOptions {
@@ -723,7 +730,7 @@ export interface WorkflowOptions {
723
730
  max?: number;
724
731
  };
725
732
  /** Pause for a manual human approval before the whole workflow dispatches. */
726
- requireApproval?: RequireApproval;
733
+ approval?: ApprovalConfig;
727
734
  }
728
735
  export type { TriggerConfig, PrTriggerConfig, PushTriggerConfig } from './triggers/types.js';
729
736
  export type { Rule, RuleContext, RuleCheckFn, RuleResult } from './rules/types.js';
package/dist/workflow.js CHANGED
@@ -76,7 +76,7 @@ function workflow(name, options) {
76
76
  onSuccess: options.onSuccess,
77
77
  onFailure: options.onFailure,
78
78
  concurrency: options.concurrency,
79
- requireApproval: options.requireApproval
79
+ approval: options.approval
80
80
  };
81
81
  }
82
82
  //#endregion
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kici-dev/sdk",
3
- "version": "0.1.21",
3
+ "version": "0.1.22",
4
4
  "description": "TypeScript SDK for defining KiCI workflows. Import into `.kici/workflows/*.ts` to declare workflows, jobs, steps, triggers, rules, and matrix configurations.",
5
5
  "keywords": [
6
6
  "ci",
@@ -49,8 +49,8 @@
49
49
  "micromatch": "^4.0.8",
50
50
  "zod": "^4.4.3",
51
51
  "zx": "^8.8.5",
52
- "@kici-dev/core": "0.1.21",
53
- "@kici-dev/engine": "0.1.21"
52
+ "@kici-dev/core": "0.1.22",
53
+ "@kici-dev/engine": "0.1.22"
54
54
  },
55
55
  "devDependencies": {
56
56
  "@types/micromatch": "^4.0.10"
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/sdk@0.1.21",
6
- "documentNamespace": "https://kici.dev/sbom/%40kici-dev%2Fsdk/0.1.21/1834e1a9-6047-4754-a53b-056d1a5e091c",
5
+ "name": "@kici-dev/sdk@0.1.22",
6
+ "documentNamespace": "https://kici.dev/sbom/%40kici-dev%2Fsdk/0.1.22/fea982d5-064e-481c-8436-fbd07a92a3c8",
7
7
  "creationInfo": {
8
- "created": "2026-06-23T05:10:13Z",
8
+ "created": "2026-06-24T06:03:05Z",
9
9
  "creators": [
10
10
  "Tool: kici-sbom-generator"
11
11
  ]
@@ -146,9 +146,9 @@
146
146
  "homepage": "https://ericsmekens.github.io/jsep/tree/master/packages/regex#readme"
147
147
  },
148
148
  {
149
- "SPDXID": "SPDXRef-Package--kici-dev-core-0.1.21",
149
+ "SPDXID": "SPDXRef-Package--kici-dev-core-0.1.22",
150
150
  "name": "@kici-dev/core",
151
- "versionInfo": "0.1.21",
151
+ "versionInfo": "0.1.22",
152
152
  "downloadLocation": "NOASSERTION",
153
153
  "filesAnalyzed": false,
154
154
  "licenseConcluded": "NOASSERTION",
@@ -159,16 +159,16 @@
159
159
  {
160
160
  "referenceCategory": "PACKAGE-MANAGER",
161
161
  "referenceType": "purl",
162
- "referenceLocator": "pkg:npm/%40kici-dev/core@0.1.21"
162
+ "referenceLocator": "pkg:npm/%40kici-dev/core@0.1.22"
163
163
  }
164
164
  ],
165
165
  "description": "Light shared utilities for the KiCI stack (logging, errors, formatting, crypto, zx init, the TypeScript ESM loader hook). No server-side dependencies.",
166
166
  "homepage": "https://kici.dev"
167
167
  },
168
168
  {
169
- "SPDXID": "SPDXRef-Package--kici-dev-engine-0.1.21",
169
+ "SPDXID": "SPDXRef-Package--kici-dev-engine-0.1.22",
170
170
  "name": "@kici-dev/engine",
171
- "versionInfo": "0.1.21",
171
+ "versionInfo": "0.1.22",
172
172
  "downloadLocation": "NOASSERTION",
173
173
  "filesAnalyzed": false,
174
174
  "licenseConcluded": "NOASSERTION",
@@ -179,7 +179,7 @@
179
179
  {
180
180
  "referenceCategory": "PACKAGE-MANAGER",
181
181
  "referenceType": "purl",
182
- "referenceLocator": "pkg:npm/%40kici-dev/engine@0.1.21"
182
+ "referenceLocator": "pkg:npm/%40kici-dev/engine@0.1.22"
183
183
  }
184
184
  ],
185
185
  "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.",
@@ -188,7 +188,7 @@
188
188
  {
189
189
  "SPDXID": "SPDXRef-RootPackage",
190
190
  "name": "@kici-dev/sdk",
191
- "versionInfo": "0.1.21",
191
+ "versionInfo": "0.1.22",
192
192
  "downloadLocation": "NOASSERTION",
193
193
  "filesAnalyzed": false,
194
194
  "licenseConcluded": "NOASSERTION",
@@ -199,7 +199,7 @@
199
199
  {
200
200
  "referenceCategory": "PACKAGE-MANAGER",
201
201
  "referenceType": "purl",
202
- "referenceLocator": "pkg:npm/%40kici-dev/sdk@0.1.21"
202
+ "referenceLocator": "pkg:npm/%40kici-dev/sdk@0.1.22"
203
203
  }
204
204
  ],
205
205
  "description": "TypeScript SDK for defining KiCI workflows. Import into `.kici/workflows/*.ts` to declare workflows, jobs, steps, triggers, rules, and matrix configurations.",
@@ -1584,68 +1584,68 @@
1584
1584
  "relationshipType": "DEPENDS_ON"
1585
1585
  },
1586
1586
  {
1587
- "spdxElementId": "SPDXRef-Package--kici-dev-core-0.1.21",
1587
+ "spdxElementId": "SPDXRef-Package--kici-dev-core-0.1.22",
1588
1588
  "relatedSpdxElement": "SPDXRef-Package-oxc-transform-0.135.0",
1589
1589
  "relationshipType": "DEPENDS_ON"
1590
1590
  },
1591
1591
  {
1592
- "spdxElementId": "SPDXRef-Package--kici-dev-core-0.1.21",
1592
+ "spdxElementId": "SPDXRef-Package--kici-dev-core-0.1.22",
1593
1593
  "relatedSpdxElement": "SPDXRef-Package-picocolors-1.1.1",
1594
1594
  "relationshipType": "DEPENDS_ON"
1595
1595
  },
1596
1596
  {
1597
- "spdxElementId": "SPDXRef-Package--kici-dev-core-0.1.21",
1597
+ "spdxElementId": "SPDXRef-Package--kici-dev-core-0.1.22",
1598
1598
  "relatedSpdxElement": "SPDXRef-Package-winston-daily-rotate-file-5.0.0",
1599
1599
  "relationshipType": "DEPENDS_ON"
1600
1600
  },
1601
1601
  {
1602
- "spdxElementId": "SPDXRef-Package--kici-dev-core-0.1.21",
1602
+ "spdxElementId": "SPDXRef-Package--kici-dev-core-0.1.22",
1603
1603
  "relatedSpdxElement": "SPDXRef-Package-winston-3.19.0",
1604
1604
  "relationshipType": "DEPENDS_ON"
1605
1605
  },
1606
1606
  {
1607
- "spdxElementId": "SPDXRef-Package--kici-dev-core-0.1.21",
1607
+ "spdxElementId": "SPDXRef-Package--kici-dev-core-0.1.22",
1608
1608
  "relatedSpdxElement": "SPDXRef-Package-zod-4.4.3",
1609
1609
  "relationshipType": "DEPENDS_ON"
1610
1610
  },
1611
1611
  {
1612
- "spdxElementId": "SPDXRef-Package--kici-dev-core-0.1.21",
1612
+ "spdxElementId": "SPDXRef-Package--kici-dev-core-0.1.22",
1613
1613
  "relatedSpdxElement": "SPDXRef-Package-zx-8.8.5",
1614
1614
  "relationshipType": "DEPENDS_ON"
1615
1615
  },
1616
1616
  {
1617
- "spdxElementId": "SPDXRef-Package--kici-dev-engine-0.1.21",
1617
+ "spdxElementId": "SPDXRef-Package--kici-dev-engine-0.1.22",
1618
1618
  "relatedSpdxElement": "SPDXRef-Package-jose-6.2.3",
1619
1619
  "relationshipType": "DEPENDS_ON"
1620
1620
  },
1621
1621
  {
1622
- "spdxElementId": "SPDXRef-Package--kici-dev-engine-0.1.21",
1622
+ "spdxElementId": "SPDXRef-Package--kici-dev-engine-0.1.22",
1623
1623
  "relatedSpdxElement": "SPDXRef-Package-jsonpath-plus-10.4.0",
1624
1624
  "relationshipType": "DEPENDS_ON"
1625
1625
  },
1626
1626
  {
1627
- "spdxElementId": "SPDXRef-Package--kici-dev-engine-0.1.21",
1627
+ "spdxElementId": "SPDXRef-Package--kici-dev-engine-0.1.22",
1628
1628
  "relatedSpdxElement": "SPDXRef-Package-picomatch-4.0.4",
1629
1629
  "relationshipType": "DEPENDS_ON"
1630
1630
  },
1631
1631
  {
1632
- "spdxElementId": "SPDXRef-Package--kici-dev-engine-0.1.21",
1632
+ "spdxElementId": "SPDXRef-Package--kici-dev-engine-0.1.22",
1633
1633
  "relatedSpdxElement": "SPDXRef-Package-safe-regex-2.1.1",
1634
1634
  "relationshipType": "DEPENDS_ON"
1635
1635
  },
1636
1636
  {
1637
- "spdxElementId": "SPDXRef-Package--kici-dev-engine-0.1.21",
1637
+ "spdxElementId": "SPDXRef-Package--kici-dev-engine-0.1.22",
1638
1638
  "relatedSpdxElement": "SPDXRef-Package-zod-4.4.3",
1639
1639
  "relationshipType": "DEPENDS_ON"
1640
1640
  },
1641
1641
  {
1642
1642
  "spdxElementId": "SPDXRef-RootPackage",
1643
- "relatedSpdxElement": "SPDXRef-Package--kici-dev-core-0.1.21",
1643
+ "relatedSpdxElement": "SPDXRef-Package--kici-dev-core-0.1.22",
1644
1644
  "relationshipType": "DEPENDS_ON"
1645
1645
  },
1646
1646
  {
1647
1647
  "spdxElementId": "SPDXRef-RootPackage",
1648
- "relatedSpdxElement": "SPDXRef-Package--kici-dev-engine-0.1.21",
1648
+ "relatedSpdxElement": "SPDXRef-Package--kici-dev-engine-0.1.22",
1649
1649
  "relationshipType": "DEPENDS_ON"
1650
1650
  },
1651
1651
  {