@kici-dev/sdk 0.1.21 → 0.1.23

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,56 @@ 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
+ }
77
+ export interface BootstrapApi {
78
+ /**
79
+ * Bring up a temporary privileged init-runner on a declared-but-un-agented
80
+ * host over SSH, so it auto-enrolls as a short-lived `kici:init` agent. The
81
+ * step calling this must run on an agent holding the
82
+ * `kici:capability:ssh-transport` capability (the orchestrator refuses
83
+ * otherwise). No-op (`broughtUp: false`) when the target already has a live
84
+ * agent. Each bring-up is access-logged.
85
+ *
86
+ * The target's reach metadata + the bring-up SSH key (a scoped secret) are
87
+ * resolved server-side from the host roster — the workflow author supplies
88
+ * only the target agent id.
89
+ */
90
+ ensureInitRunner(targetAgentId: string): Promise<{
91
+ broughtUp: boolean;
92
+ }>;
93
+ /**
94
+ * Ship an input to a host's pre-boot SSH channel (e.g. a LUKS passphrase to
95
+ * a dropbear/initramfs `cryptroot-unlock` prompt on port 2222). Generic
96
+ * "pipe stdin to a forced-command endpoint"; the unlock recipe is
97
+ * per-host-passphrase → `preBootSend` → `waitForHostAlive`. Same
98
+ * `kici:capability:ssh-transport` gate + access-log as `ensureInitRunner`.
99
+ *
100
+ * `inputSecret` is a scoped-secret ref (`scope/key`) the orchestrator
101
+ * resolves server-side; the plaintext never passes through the workflow.
102
+ * Success is the send completing (the session drops as the box boots) —
103
+ * compose `restartHost`/host-alive waits to confirm the boot.
104
+ */
105
+ preBootSend(targetAgentId: string, opts: {
106
+ inputSecret: string;
107
+ port?: number;
108
+ command?: string;
109
+ }): Promise<void>;
110
+ }
61
111
  export interface KiciApi {
62
112
  /** Query orchestrator infrastructure (scalers, agents). */
63
113
  infrastructure: InfrastructureApi;
@@ -65,6 +115,10 @@ export interface KiciApi {
65
115
  inventory: InventoryApi;
66
116
  /** Request short-lived OIDC ID tokens for the current job (build provenance). */
67
117
  oidc: OidcApi;
118
+ /** Host-lifecycle operations on the agent's own host (e.g. reboot). */
119
+ host: HostApi;
120
+ /** Fresh-box bootstrap bring-up (init-runner over SSH, pre-boot unlock). */
121
+ bootstrap: BootstrapApi;
68
122
  }
69
123
  /**
70
124
  * Low-level transport function used to implement KiciApi.
package/dist/api-types.js CHANGED
@@ -36,7 +36,15 @@ 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 } : {} }) },
41
+ bootstrap: {
42
+ ensureInitRunner: (targetAgentId) => transport("kici.ensureInitRunner", { targetAgentId }),
43
+ preBootSend: (targetAgentId, opts) => transport("kici.preBootSend", {
44
+ targetAgentId,
45
+ ...opts
46
+ })
47
+ }
40
48
  };
41
49
  }
42
50
  //#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
@@ -3,6 +3,7 @@ import type { MatrixValues } from './matrix/types.js';
3
3
  import type { EventEmitOptions } from './events/types.js';
4
4
  import type { StepSecrets } from './secrets.js';
5
5
  import type { KiciApi } from './api-types.js';
6
+ import type { FanoutPosition } from './fanout-context.js';
6
7
  /** Logger interface for step execution */
7
8
  export interface Logger {
8
9
  info(message: string, ...args: unknown[]): void;
@@ -115,6 +116,12 @@ export interface StepContext<TInputs = Record<string, unknown>> {
115
116
  addPath(dir: string): void;
116
117
  /** Typed inputs from dependencies */
117
118
  inputs: TInputs;
119
+ /**
120
+ * Operator-supplied, validated + coerced workflow-dispatch inputs (from `dispatch({ inputs })`).
121
+ * Distinct from `inputs` (typed outputs from `needs` dependencies). Empty when none declared.
122
+ * Prefer the typed `defineDispatchInputs(...).from(ctx)` accessor for per-key types.
123
+ */
124
+ dispatchInputs: Readonly<Record<string, string | number | boolean | null>>;
118
125
  /** Current workflow metadata */
119
126
  workflow: WorkflowInfo;
120
127
  /** Current job metadata */
@@ -137,6 +144,12 @@ export interface StepContext<TInputs = Record<string, unknown>> {
137
144
  * platform, arch). Set only for jobs that use `runsOnAll`. Undefined otherwise.
138
145
  */
139
146
  agent?: AgentInfo;
147
+ /**
148
+ * Position of this child within its fan-out (a `runsOnAll` host or a matrix
149
+ * combination), deterministically ordered (host: by `agentId`; matrix: by
150
+ * variant label). Undefined on a non-fan-out job.
151
+ */
152
+ fanout?: FanoutPosition;
140
153
  /**
141
154
  * Raw webhook payload from the git provider.
142
155
  * Contains the full, unmodified payload as received from the webhook.
@@ -261,6 +274,15 @@ export interface StepContext<TInputs = Record<string, unknown>> {
261
274
  * the agent digests with SHA-256.
262
275
  */
263
276
  attestProvenance(opts: import('./provenance-types.js').AttestProvenanceOptions): Promise<import('./provenance-types.js').AttestProvenanceResult>;
277
+ /**
278
+ * Upstream needs resolved for this job, keyed by upstream job or group name.
279
+ * `ctx.needs.<job>.result` is the upstream's outputs proxy and
280
+ * `ctx.needs.<job>.status` its terminal status (`success | failed | skipped |
281
+ * …`). A group / matrix / `runsOnAll` fan-out upstream is an ordered array of
282
+ * `{ name, result, status }`, one entry per child. Undefined for a job with no
283
+ * declared `needs`.
284
+ */
285
+ needs?: import('./needs-context.js').NeedsContext;
264
286
  }
265
287
  export {};
266
288
  //# 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,21 @@
1
+ /**
2
+ * Deterministic position of a fan-out child within its fan-out.
3
+ *
4
+ * A fan-out child is one of:
5
+ * - a `runsOnAll` host execution (one pinned execution per matching roster host), or
6
+ * - a matrix combination (one execution per expanded combination).
7
+ *
8
+ * The order is deterministic: host fan-out is sorted by `agentId`, matrix fan-out by
9
+ * its variant label, so `first` is always reproducible across re-runs.
10
+ */
11
+ export interface FanoutPosition {
12
+ /** 0-based position in the deterministically-ordered fan-out. */
13
+ index: number;
14
+ /** Number of children in this fan-out. */
15
+ total: number;
16
+ /** Whether this is the first child (`index === 0`). */
17
+ first: boolean;
18
+ /** Whether this is the last child (`index === total - 1`). */
19
+ last: boolean;
20
+ }
21
+ //# sourceMappingURL=fanout-context.d.ts.map
@@ -0,0 +1,2 @@
1
+ import "./chunk-BTugEXQM.js";
2
+ export {};
@@ -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
@@ -21,7 +21,8 @@
21
21
  * whose run function executes `idempotent(...)` and propagates ctx.log
22
22
  * into the runner's status sink.
23
23
  */
24
- import type { Step } from './types.js';
24
+ import type { Step, StepOptionsBase } from './types.js';
25
+ import type { StepContext } from './context.js';
25
26
  export interface IdempotentOptions<TDrift, TInSync = void, TApplied = void> {
26
27
  /** Optional name surfaced in status lines and error messages. */
27
28
  name?: string;
@@ -68,4 +69,34 @@ export declare function idempotent<TDrift, TInSync = void, TApplied = void>(opts
68
69
  * The step's typed return value is the IdempotentResult union.
69
70
  */
70
71
  export declare function idempotentStep<TDrift, TInSync = void, TApplied = void>(name: string, opts: Omit<IdempotentOptions<TDrift, TInSync, TApplied>, 'name' | 'log'>): Step<IdempotentResult<TDrift, TInSync, TApplied>>;
72
+ /**
73
+ * Options for {@link checkStep}. The same shape as `idempotentStep`'s options,
74
+ * except `apply` and `whenInSync` receive `ctx` first (matching the `step()`
75
+ * check facet's `run(ctx, drift)` form) so the apply logic has access to
76
+ * `ctx.$` / `ctx.log` / `ctx.secrets`. The remaining `StepOptionsBase`
77
+ * passthroughs (`continueOnError`, `timeout`, `rules`, `outputs`, `retry`, …)
78
+ * are forwarded to the underlying step.
79
+ */
80
+ export interface CheckStepOptions<TDrift, TInSync = void, TApplied = void> extends Omit<StepOptionsBase, 'onCancel' | 'cleanup' | 'approval'> {
81
+ /** Read-only inspection: drift if apply would change state, or null if in sync. */
82
+ check: (ctx: StepContext) => Promise<TDrift | null>;
83
+ /** Brings the system to the desired state. Runs only in apply mode (skipped under `kici run --check`). */
84
+ apply: (ctx: StepContext, drift: TDrift) => Promise<TApplied>;
85
+ /** Required: human-readable summary of what apply() would do; shown in check-mode drift output. */
86
+ summarize: (drift: TDrift) => string;
87
+ /** Runs when check() returns null (already in sync). */
88
+ whenInSync?: (ctx: StepContext) => Promise<TInSync>;
89
+ }
90
+ /**
91
+ * Factory returning a check-facet SDK Step — the check-mode-aware sibling of
92
+ * {@link idempotentStep}. Unlike `idempotentStep` (which always applies on
93
+ * drift), a `checkStep` respects the run-level check mode: `kici run --check`
94
+ * reports the drift and skips `apply`, while apply mode applies it.
95
+ *
96
+ * It desugars to the `step()` check facet
97
+ * (`run: (ctx, drift) => apply(ctx, drift)`), so it inherits the agent
98
+ * step-loop and local-executor check-mode drive for free — no engine, agent,
99
+ * orchestrator, or lockfile change.
100
+ */
101
+ export declare function checkStep<TDrift, TInSync = void, TApplied = void>(name: string, options: CheckStepOptions<TDrift, TInSync, TApplied>): Step<TApplied | TInSync>;
71
102
  //# sourceMappingURL=idempotent.d.ts.map
@@ -71,7 +71,32 @@ function idempotentStep(name, opts) {
71
71
  log: (line) => ctx.log.info(line)
72
72
  }) });
73
73
  }
74
+ /**
75
+ * Factory returning a check-facet SDK Step — the check-mode-aware sibling of
76
+ * {@link idempotentStep}. Unlike `idempotentStep` (which always applies on
77
+ * drift), a `checkStep` respects the run-level check mode: `kici run --check`
78
+ * reports the drift and skips `apply`, while apply mode applies it.
79
+ *
80
+ * It desugars to the `step()` check facet
81
+ * (`run: (ctx, drift) => apply(ctx, drift)`), so it inherits the agent
82
+ * step-loop and local-executor check-mode drive for free — no engine, agent,
83
+ * orchestrator, or lockfile change.
84
+ */
85
+ function checkStep(name, options) {
86
+ return step(name, {
87
+ check: options.check,
88
+ summarize: options.summarize,
89
+ run: (ctx, drift) => options.apply(ctx, drift),
90
+ ...options.whenInSync && { whenInSync: options.whenInSync },
91
+ ...options.outputs !== void 0 && { outputs: options.outputs },
92
+ ...options.continueOnError !== void 0 && { continueOnError: options.continueOnError },
93
+ ...options.timeout !== void 0 && { timeout: options.timeout },
94
+ ...options.retry !== void 0 && { retry: options.retry },
95
+ ...options.cache !== void 0 && { cache: options.cache },
96
+ ...options.rules !== void 0 && { rules: options.rules }
97
+ });
98
+ }
74
99
  //#endregion
75
- export { idempotent, idempotentStep };
100
+ export { checkStep, idempotent, idempotentStep };
76
101
 
77
102
  //# sourceMappingURL=idempotent.js.map
package/dist/index.d.ts CHANGED
@@ -1,21 +1,21 @@
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';
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
- 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';
4
+ export { normalizeApproval } from './approval.js';
5
+ export type { ApprovalConfig, ApprovalWhen, ApproverClause, NormalizedApproval, } from './approval.js';
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, defineDispatchInputs, } from './triggers/index.js';
7
+ export type { DefinedDispatchInputs, InferDispatchInputs, DispatchInputsMap, 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';
9
9
  export type { HookConfig, HookFn, HookInput, HookContext, OutcomeMetadata } from './hooks/index.js';
10
- export { rule, skip } from './rules/index.js';
10
+ export { rule, skip, onlyOnFirstHost, onlyOnLastHost, onlyOnFanoutIndex } from './rules/index.js';
11
11
  export { evaluateRules } from './rules/index.js';
12
12
  export { isEventType } from './rules/index.js';
13
13
  export type { Rule, RuleContext, RuleCheckFn, RuleResult, EventPayload, RuleEvaluationResult, EventBase, PullRequestEventPayload, PushEventPayload, TagEventPayload, CommentEventPayload, ReviewEventPayload, ReviewCommentEventPayload, ReleaseEventPayload, DispatchEventPayload, CreateEventPayload, DeleteEventPayload, StatusEventPayload, WorkflowRunEventPayload, ForkEventPayload, StarEventPayload, WatchEventPayload, WebhookEventPayload, KiciEventPayload, WorkflowCompleteEventPayload, JobCompleteEventPayload, GenericWebhookEventPayload, ScheduleEventPayload, LifecycleEventPayload, GitHubRepository, GitHubUser, GitHubPullRequest, GitHubCommit, GitHubComment, GitHubReview, GitHubRelease, } from './rules/index.js';
14
14
  export { validateDag } from './validation/index.js';
15
15
  export type { DagNode, DagValidationResult } from './validation/index.js';
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';
16
+ export type { SourceLocation, OutputProxy, Step, StepOptions, StepOptionsBase, StepOptionsPlain, StepOptionsWithCheck, StepRunFn, RetryConfig, NormalizedRetry, BareStepFn, StepInput, OutputSchema, InferOutputs, Job, JobOptions, GenericInitConfig, MiseInitConfig, InitPreset, InitItem, InitConfig, ContainerConfig, RunsOnSelector, RunsOn, RunsOnPick, 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';
@@ -27,8 +27,9 @@ export { dynamicGroup, isDynamicGroupRef, DYNAMIC_GROUP_TAG } from './dynamic-gr
27
27
  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
+ export type { FanoutPosition } from './fanout-context.js';
30
31
  export { buildKiciApi } from './api-types.js';
31
- export type { KiciApi, KiciApiTransport, InfrastructureApi, InfrastructureListResult, InventoryApi, HostInventoryEntry, InventorySelector, } from './api-types.js';
32
+ export type { KiciApi, KiciApiTransport, InfrastructureApi, InfrastructureListResult, InventoryApi, HostApi, HostInventoryEntry, InventorySelector, } from './api-types.js';
32
33
  export { SecretNotFoundError } from './errors.js';
33
34
  export { createStepSecrets } from './secrets.js';
34
35
  export type { StepSecrets, TrackedStepSecrets, SecretMeta, SecretFileOptions, MountedFile, StepSecretsFileHost, StepSecretsFileWiring, StepSecretsHandle, StepSecretMountKind, StepSecretMountRecord, } from './secrets.js';
@@ -42,9 +43,11 @@ export type { EventDefinition } from './events/index.js';
42
43
  export type { EventEmitOptions } from './events/index.js';
43
44
  export { fixture } from './fixture.js';
44
45
  export type { Fixture, FixtureOptions } from './fixture.js';
45
- export { idempotent, idempotentStep } from './idempotent.js';
46
- export type { IdempotentOptions, IdempotentResult } from './idempotent.js';
46
+ export { idempotent, idempotentStep, checkStep } from './idempotent.js';
47
+ export type { IdempotentOptions, IdempotentResult, CheckStepOptions } from './idempotent.js';
47
48
  export { waitFor, waitForStep, WaitForTimeoutError } from './wait-for.js';
48
49
  export type { WaitForOptions, WaitForResult } from './wait-for.js';
50
+ export { waitForHostAlive, restartHost } from './host-restart.js';
51
+ export type { WaitForHostAliveOptions, RestartHostOptions } from './host-restart.js';
49
52
  export { z } from 'zod';
50
53
  //# 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,7 +8,9 @@ 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 { idempotent, idempotentStep } from "./idempotent.js";
11
+ import { WaitForTimeoutError, waitFor, waitForStep } from "./wait-for.js";
12
+ import { restartHost, waitForHostAlive } from "./host-restart.js";
13
+ import { checkStep, idempotent, idempotentStep } from "./idempotent.js";
12
14
  import { job } from "./job.js";
13
15
  import { workflow } from "./workflow.js";
14
16
  import { pr } from "./triggers/pr.js";
@@ -33,9 +35,10 @@ import { jobComplete } from "./triggers/job-complete.js";
33
35
  import { genericWebhook } from "./triggers/generic-webhook.js";
34
36
  import { schedule } from "./triggers/schedule.js";
35
37
  import { lifecycle } from "./triggers/lifecycle.js";
38
+ import { defineDispatchInputs } from "./triggers/dispatch-inputs.js";
36
39
  import "./triggers/index.js";
37
40
  import { afterStep, beforeStep, cleanup, onCancel, onFailure, onSuccess } from "./hooks/index.js";
38
- import { rule, skip } from "./rules/rule.js";
41
+ import { onlyOnFanoutIndex, onlyOnFirstHost, onlyOnLastHost, rule, skip } from "./rules/rule.js";
39
42
  import { evaluateRules } from "./rules/evaluator.js";
40
43
  import { isEventType } from "./events/event-payloads.js";
41
44
  import "./rules/index.js";
@@ -50,6 +53,5 @@ import { applyIncludeExclude, expandMatrix } from "./matrix/expand.js";
50
53
  import "./matrix/index.js";
51
54
  import { defineEvent } from "./events/define-event.js";
52
55
  import "./events/index.js";
53
- import { WaitForTimeoutError, waitFor, waitForStep } from "./wait-for.js";
54
56
  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 };
57
+ export { CacheSpecSchema, DYNAMIC_GROUP_TAG, DYNAMIC_JOB_GROUP_TAG, DYNAMIC_JOB_NEEDS_TAG, SecretNotFoundError, WaitForTimeoutError, afterStep, applyIncludeExclude, beforeStep, buildKiciApi, buildNeedsContext, checkStep, cleanup, comment, create, createJobOutputProxy, createSnapshotOutputProxy, createStepOutputProxy, createStepSecrets, defineDispatchInputs, 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, onlyOnFanoutIndex, onlyOnFirstHost, onlyOnLastHost, 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 };