@kici-dev/sdk 0.1.14 → 0.1.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1 +1,19 @@
1
- TBD
1
+ # @kici-dev/sdk
2
+
3
+ TypeScript SDK for defining KiCI workflows. Import it in `.kici/workflows/*.ts` to declare workflows, jobs, steps, triggers, rules, and matrix configurations — with full type safety and editor autocomplete.
4
+
5
+ Part of [KiCI](https://kici.dev) — CI/CD workflows as TypeScript code: author them with full language power, dry-run them locally, and run them on your own infrastructure.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ npm install --save-dev @kici-dev/sdk
11
+ ```
12
+
13
+ Usually installed for you by `kici init`.
14
+
15
+ ## Links
16
+
17
+ - Documentation: <https://docs.kici.dev/user/sdk/core/>
18
+ - Source: <https://github.com/kici-dev/kici-public/tree/main/packages/sdk>
19
+ - License: Apache-2.0
@@ -0,0 +1,34 @@
1
+ /**
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.
6
+ */
7
+ /** A single approver clause: any member of a team, or a specific user. */
8
+ export type ApproverClause = {
9
+ team: string;
10
+ } | {
11
+ user: string;
12
+ };
13
+ /**
14
+ * Declarative approval requirement.
15
+ *
16
+ * - `true` — pause for ANY org member with the approval permission.
17
+ * - `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.
20
+ */
21
+ export type RequireApproval = true | ApproverClause[] | {
22
+ approvers: ApproverClause[];
23
+ reason?: string;
24
+ timeout?: number;
25
+ };
26
+ /** The normalized shape written into the lock file. */
27
+ export interface NormalizedRequireApproval {
28
+ clauses: ApproverClause[];
29
+ reason?: string;
30
+ timeoutSeconds?: number;
31
+ }
32
+ /** Normalize any `RequireApproval` form into `{ clauses, reason?, timeoutSeconds? }`. */
33
+ export declare function normalizeRequireApproval(r: RequireApproval): NormalizedRequireApproval;
34
+ //# sourceMappingURL=approval.d.ts.map
@@ -0,0 +1,16 @@
1
+ import "./chunk-gOLHoazu.js";
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 };
7
+ return {
8
+ clauses: r.approvers,
9
+ reason: r.reason,
10
+ timeoutSeconds: r.timeout
11
+ };
12
+ }
13
+ //#endregion
14
+ export { normalizeRequireApproval };
15
+
16
+ //# sourceMappingURL=approval.js.map
@@ -0,0 +1,47 @@
1
+ import { z } from 'zod';
2
+ /**
3
+ * Declarative + imperative cache specification.
4
+ *
5
+ * `key` is the immutable cache key — the first save under an exact key wins;
6
+ * re-saving the same exact key is a no-op. `paths` are the files/dirs to
7
+ * archive (repo-root-relative or `~`-prefixed). `restoreKeys` are ordered
8
+ * prefix fallbacks tried (newest matching entry wins) when the exact key
9
+ * misses on restore.
10
+ */
11
+ export interface CacheSpec {
12
+ /** Exact cache key. First save wins; re-saving an existing key is a no-op. */
13
+ key: string;
14
+ /** Files/directories to cache. Repo-root-relative or `~`-prefixed. */
15
+ paths: string[];
16
+ /** Ordered prefix fallbacks for partial restore; newest matching entry wins. */
17
+ restoreKeys?: string[];
18
+ }
19
+ /** Zod schema validating a CacheSpec at compile/serialize time. */
20
+ export declare const CacheSpecSchema: z.ZodObject<{
21
+ key: z.ZodString;
22
+ paths: z.ZodArray<z.ZodString>;
23
+ restoreKeys: z.ZodOptional<z.ZodArray<z.ZodString>>;
24
+ }, z.core.$strip>;
25
+ /** Declarative cache field shape: one spec or many. */
26
+ export type CacheInput = CacheSpec | CacheSpec[];
27
+ /** Coerce the declarative `cache` field into an array (empty when unset). */
28
+ export declare function normalizeCacheSpecs(input: CacheInput | undefined): CacheSpec[];
29
+ /** Result of an imperative cache restore. */
30
+ export interface CacheRestoreResult {
31
+ /** Whether any entry (exact key or a restoreKeys prefix match) was restored. */
32
+ hit: boolean;
33
+ /** The key that actually matched (exact key or the matched prefix entry's full key). */
34
+ matchedKey?: string;
35
+ }
36
+ /**
37
+ * Imperative cache API exposed on `StepContext` as `ctx.cache`.
38
+ *
39
+ * `restore` tries the exact `key`, then each `restoreKeys` prefix in order
40
+ * (newest matching entry wins). `save` is immutable — the first save under an
41
+ * exact key wins and re-saving an existing key is a no-op.
42
+ */
43
+ export interface CacheApi {
44
+ restore(spec: CacheSpec): Promise<CacheRestoreResult>;
45
+ save(spec: CacheSpec): Promise<void>;
46
+ }
47
+ //# sourceMappingURL=cache-types.d.ts.map
@@ -0,0 +1,18 @@
1
+ import "./chunk-gOLHoazu.js";
2
+ import { z } from "zod";
3
+ //#region src/cache-types.ts
4
+ /** Zod schema validating a CacheSpec at compile/serialize time. */
5
+ const CacheSpecSchema = z.object({
6
+ key: z.string().min(1, "cache key must be non-empty"),
7
+ paths: z.array(z.string().min(1)).min(1, "cache paths must be non-empty"),
8
+ restoreKeys: z.array(z.string().min(1)).optional()
9
+ });
10
+ /** Coerce the declarative `cache` field into an array (empty when unset). */
11
+ function normalizeCacheSpecs(input) {
12
+ if (input === void 0) return [];
13
+ return Array.isArray(input) ? input : [input];
14
+ }
15
+ //#endregion
16
+ export { CacheSpecSchema, normalizeCacheSpecs };
17
+
18
+ //# sourceMappingURL=cache-types.js.map
package/dist/context.d.ts CHANGED
@@ -180,6 +180,14 @@ export interface StepContext<TInputs = Record<string, unknown>> {
180
180
  setSecretOutput(key: string, value: string): void;
181
181
  /** Typed KiCI API — orchestrator queries over WS (e.g., kici.infrastructure.list()) */
182
182
  kici: KiciApi;
183
+ /**
184
+ * Imperative cache API for fine-grained control.
185
+ *
186
+ * `ctx.cache.restore(spec)` restores from object storage (exact key, then
187
+ * restoreKeys prefix fallback). `ctx.cache.save(spec)` archives `spec.paths`
188
+ * under `spec.key` (immutable — first save wins). Scoped per org + ref.
189
+ */
190
+ cache: import('./cache-types.js').CacheApi;
183
191
  }
184
192
  export {};
185
193
  //# sourceMappingURL=context.d.ts.map
@@ -364,9 +364,20 @@ export interface RerunEventPayload extends EventBase {
364
364
  export interface ManualScheduleEventPayload extends EventBase {
365
365
  type: 'manual_schedule';
366
366
  }
367
- /** Fallback for unknown/future event types. */
367
+ /**
368
+ * Compile-time fallback member of the {@link EventPayload} union for event
369
+ * types not yet modeled here.
370
+ *
371
+ * Its `type` is the literal `'unknown'` (not `string`) so that the union stays
372
+ * a *proper* discriminated union — a non-literal discriminant would collapse
373
+ * narrowing on `event.type` for every other member. At runtime, an event of an
374
+ * unmodeled kind still carries its real type string in `event.type`; this
375
+ * interface only governs how TypeScript narrows it. Code that must handle
376
+ * arbitrary future types can compare the raw value via `String(event.type) ===
377
+ * '...'`, or use the {@link isEventType} guard for the known types.
378
+ */
368
379
  export interface UnknownEventPayload extends EventBase {
369
- type: string;
380
+ type: 'unknown';
370
381
  }
371
382
  /**
372
383
  * Typed event payload — discriminated union over the `type` field.
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=event-payloads.test-d.d.ts.map
@@ -0,0 +1,32 @@
1
+ import "../chunk-gOLHoazu.js";
2
+ import { describe, expectTypeOf, it } from "vitest";
3
+ //#region src/events/event-payloads.test-d.ts
4
+ describe("EventPayload narrowing", () => {
5
+ it("narrows to the per-type payload shape on event.type", () => {
6
+ const handle = (event) => {
7
+ if (event.type === "pull_request") {
8
+ expectTypeOf(event).toEqualTypeOf();
9
+ expectTypeOf(event.payload.pull_request.number).toBeNumber();
10
+ }
11
+ };
12
+ expectTypeOf(handle).toBeFunction();
13
+ });
14
+ it("exposes a literal-union discriminant (not string)", () => {
15
+ expectTypeOf().toEqualTypeOf();
16
+ });
17
+ it("job dynamic functions accept EventPayload-param functions", () => {
18
+ expectTypeOf().toMatchTypeOf();
19
+ expectTypeOf().toMatchTypeOf();
20
+ expectTypeOf().toMatchTypeOf();
21
+ });
22
+ it("workflow concurrency.group ctx carries the EventPayload envelope", () => {
23
+ expectTypeOf().toEqualTypeOf();
24
+ });
25
+ it("DynamicJobContext.ctx.event is the EventPayload envelope (optional)", () => {
26
+ expectTypeOf().toEqualTypeOf();
27
+ });
28
+ });
29
+ //#endregion
30
+ export {};
31
+
32
+ //# sourceMappingURL=event-payloads.test-d.js.map
package/dist/index.d.ts CHANGED
@@ -1,6 +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
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';
5
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';
6
8
  export { onCancel, cleanup, onSuccess, onFailure, beforeStep, afterStep } from './hooks/index.js';
@@ -11,9 +13,12 @@ export { isEventType } from './rules/index.js';
11
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';
12
14
  export { validateDag } from './validation/index.js';
13
15
  export type { DagNode, DagValidationResult } from './validation/index.js';
14
- export type { SourceLocation, OutputProxy, Step, StepOptions, StepRunFn, BareStepFn, StepInput, OutputSchema, InferOutputs, Job, JobOptions, ContainerConfig, RunsOnSelector, RunsOn, Workflow, WorkflowOptions, Registry, Trigger, DynamicJobFn, DynamicJobContext, JobOrFactory, } from './types.js';
16
+ export type { SourceLocation, OutputProxy, Step, StepOptions, StepRunFn, BareStepFn, StepInput, OutputSchema, InferOutputs, Job, JobOptions, GenericInitConfig, ContainerConfig, RunsOnSelector, RunsOn, Workflow, WorkflowOptions, Registry, Trigger, DynamicJobFn, DynamicJobContext, JobOrFactory, } from './types.js';
15
17
  export { isDynamicJobFn, dynamicJob, getDynamicJobGroup, DYNAMIC_JOB_GROUP_TAG } from './types.js';
16
18
  export type { TaggedDynamicJobFn } from './types.js';
19
+ export { CacheSpecSchema, normalizeCacheSpecs } from './cache-types.js';
20
+ export type { CacheSpec, CacheInput } from './cache-types.js';
21
+ export type { CacheRestoreResult, CacheApi } from './cache-types.js';
17
22
  export { dynamicGroup, isDynamicGroupRef, DYNAMIC_GROUP_TAG } from './dynamic-group.js';
18
23
  export type { DynamicGroupRef } from './dynamic-group.js';
19
24
  export type { StepContext, Logger, WorkflowInfo, JobInfo, RepoInfo, StepSecretsTyped, KnownSecretKeys, } from './context.js';
package/dist/index.js CHANGED
@@ -1,5 +1,7 @@
1
1
  import "./chunk-gOLHoazu.js";
2
2
  import { buildKiciApi } from "./api-types.js";
3
+ import { normalizeRequireApproval } from "./approval.js";
4
+ import { CacheSpecSchema, normalizeCacheSpecs } from "./cache-types.js";
3
5
  import { DYNAMIC_GROUP_TAG, dynamicGroup, isDynamicGroupRef } from "./dynamic-group.js";
4
6
  import { SecretNotFoundError } from "./errors.js";
5
7
  import { fixture } from "./fixture.js";
@@ -47,4 +49,4 @@ import { defineEvent } from "./events/define-event.js";
47
49
  import "./events/index.js";
48
50
  import { WaitForTimeoutError, waitFor, waitForStep } from "./wait-for.js";
49
51
  import { z } from "zod";
50
- export { DYNAMIC_GROUP_TAG, DYNAMIC_JOB_GROUP_TAG, SecretNotFoundError, WaitForTimeoutError, afterStep, applyIncludeExclude, beforeStep, buildKiciApi, cleanup, comment, create, createJobOutputProxy, createStepOutputProxy, createStepSecrets, defineEvent, del as delete, dispatch, dynamicGroup, dynamicJob, evaluateRules, expandMatrix, fixture, fork, genericWebhook, getDynamicJobGroup, getJobOutputsMap, getStepOutputsMap, getStepRefMap, idempotent, idempotentStep, isDynamicFunction, isDynamicGroupRef, isDynamicJobFn, isEventType, isStaticArray, isStaticObject, job, jobComplete, kiciEvent, lifecycle, onCancel, onFailure, onSuccess, pr, 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 };
52
+ export { CacheSpecSchema, DYNAMIC_GROUP_TAG, DYNAMIC_JOB_GROUP_TAG, SecretNotFoundError, WaitForTimeoutError, afterStep, applyIncludeExclude, beforeStep, buildKiciApi, cleanup, comment, create, createJobOutputProxy, createStepOutputProxy, createStepSecrets, defineEvent, del as delete, dispatch, dynamicGroup, dynamicJob, evaluateRules, expandMatrix, fixture, fork, genericWebhook, getDynamicJobGroup, getJobOutputsMap, getStepOutputsMap, getStepRefMap, idempotent, idempotentStep, isDynamicFunction, isDynamicGroupRef, isDynamicJobFn, isEventType, isStaticArray, isStaticObject, job, jobComplete, kiciEvent, lifecycle, normalizeCacheSpecs, normalizeRequireApproval, onCancel, onFailure, onSuccess, pr, 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 };
package/dist/job.js CHANGED
@@ -3,6 +3,17 @@ import { createJobOutputProxy } from "./outputs.js";
3
3
  import { randomUUID } from "node:crypto";
4
4
  //#region src/job.ts
5
5
  /**
6
+ * Validate a job's `init` config. `undefined` / `false` are no-ops; every
7
+ * remaining spec (one, or each element of an array) must carry a non-empty
8
+ * `run` command. Throws with the offending index when validation fails.
9
+ */
10
+ function validateInit(init, jobName) {
11
+ if (init === void 0 || init === false) return;
12
+ (Array.isArray(init) ? init : [init]).forEach((spec, i) => {
13
+ if (typeof spec.run !== "string" || spec.run.trim().length === 0) throw new Error(`job('${jobName}'): init[${i}].run must be a non-empty command`);
14
+ });
15
+ }
16
+ /**
6
17
  * Implementation of job() factory.
7
18
  */
8
19
  function job(nameOrOptions, maybeOptions) {
@@ -13,6 +24,7 @@ function job(nameOrOptions, maybeOptions) {
13
24
  if (options.steps && options.steps.length > 0) throw new Error("job() cannot have both \"run\" and \"steps\" -- use one or the other");
14
25
  steps = [options.run];
15
26
  }
27
+ validateInit(options.init, name);
16
28
  return {
17
29
  _tag: "Job",
18
30
  name,
@@ -36,7 +48,11 @@ function job(nameOrOptions, maybeOptions) {
36
48
  beforeStep: options.beforeStep,
37
49
  afterStep: options.afterStep,
38
50
  gracePeriod: options.gracePeriod,
51
+ timeout: options.timeout,
39
52
  resources: options.resources,
53
+ init: options.init,
54
+ ...options.cache !== void 0 && { cache: options.cache },
55
+ ...options.requireApproval !== void 0 && { requireApproval: options.requireApproval },
40
56
  result: createJobOutputProxy(name)
41
57
  };
42
58
  }
package/dist/step.js CHANGED
@@ -65,9 +65,11 @@ function step(nameOrRunOrOptions, runOrOptions) {
65
65
  run: options.run,
66
66
  continueOnError: options.continueOnError,
67
67
  timeout: options.timeout,
68
+ ...options.cache !== void 0 && { cache: options.cache },
68
69
  rules: options.rules,
69
70
  onCancel: options.onCancel,
70
71
  cleanup: options.cleanup,
72
+ ...options.requireApproval !== void 0 && { requireApproval: options.requireApproval },
71
73
  _sourceLocation,
72
74
  result: createStepOutputProxy(name)
73
75
  };
package/dist/types.d.ts CHANGED
@@ -8,6 +8,8 @@ import type { Matrix, MatrixInclude, MatrixExclude } from './matrix/types.js';
8
8
  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
+ import type { EventPayload } from './events/event-payloads.js';
12
+ import type { RequireApproval } from './approval.js';
11
13
  export type { ResourceRequest, ResourceSpec } from '@kici-dev/engine';
12
14
  /** Source location captured at a step() call site. */
13
15
  export interface SourceLocation {
@@ -44,12 +46,16 @@ export interface Step<TResult = void> {
44
46
  readonly continueOnError?: boolean;
45
47
  /** Step-level timeout in milliseconds. Overrides the agent's default (30 minutes). */
46
48
  readonly timeout?: number;
49
+ /** Declarative cache: restored before this step, saved after on key miss. */
50
+ readonly cache?: import('./cache-types.js').CacheInput;
47
51
  /** Step-level conditional rules (evaluated agent-side). */
48
52
  readonly rules?: Rule[];
49
53
  /** Runs on cancellation. */
50
54
  readonly onCancel?: HookInput;
51
55
  /** Always runs after step (success, failure, or cancel). */
52
56
  readonly cleanup?: HookInput;
57
+ /** Pause for a manual human approval before this step runs. */
58
+ readonly requireApproval?: RequireApproval;
53
59
  /** Internal: source location captured at step() call site. Not part of public API. */
54
60
  readonly _sourceLocation?: SourceLocation;
55
61
  /**
@@ -80,12 +86,16 @@ export interface StepOptions<TResult = void> {
80
86
  continueOnError?: boolean;
81
87
  /** Step-level timeout in milliseconds. Overrides the agent's default (30 minutes). */
82
88
  timeout?: number;
89
+ /** Declarative cache: restored before this step, saved after on key miss. */
90
+ cache?: import('./cache-types.js').CacheInput;
83
91
  /** Step-level conditional rules (evaluated agent-side). */
84
92
  rules?: Rule[];
85
93
  /** Runs on cancellation. */
86
94
  onCancel?: HookInput;
87
95
  /** Always runs after step (success, failure, or cancel). */
88
96
  cleanup?: HookInput;
97
+ /** Pause for a manual human approval before this step runs. */
98
+ requireApproval?: RequireApproval;
89
99
  }
90
100
  /** Trigger type (config objects returned by pr()/push() factory functions) */
91
101
  export type Trigger = TriggerConfig;
@@ -114,7 +124,8 @@ export interface DynamicJobContext {
114
124
  workflow: {
115
125
  name: string;
116
126
  };
117
- event?: Record<string, unknown>;
127
+ /** Normalized event envelope that triggered this run. */
128
+ event?: EventPayload;
118
129
  };
119
130
  /** Structured logger */
120
131
  log: Logger;
@@ -176,6 +187,29 @@ export interface ContainerConfig {
176
187
  /** Additional environment variables for the container */
177
188
  env?: Record<string, string>;
178
189
  }
190
+ /**
191
+ * Generic per-job initialization config. Runs a hand-written command after the
192
+ * repo is cloned and before the job's steps execute, so a repo-declared
193
+ * toolchain (mise, a custom setup script, …) is provisioned and put on the
194
+ * step environment's PATH.
195
+ *
196
+ * The command writes env it wants visible to later steps to the file at
197
+ * `$KICI_ENV` (one `KEY=value` line each) and PATH additions to `$KICI_PATH`
198
+ * (one directory per line) — the agent reads both after the command and applies
199
+ * the delta to every subsequent step.
200
+ */
201
+ export interface GenericInitConfig {
202
+ /** Command run after clone, before steps. Runs in the job's sandbox at the clone root. */
203
+ run: string;
204
+ /** Shell used to run `run`. Defaults to 'bash'. */
205
+ shell?: string;
206
+ /** Cache spec for binaries the command fetches/installs (restored before, saved after on key miss). */
207
+ cache?: import('./cache-types.js').CacheSpec;
208
+ /** Max wall-clock for this init command in ms. Reuses the step/job timeout semantics. */
209
+ timeout?: number;
210
+ /** Static environment variables available to the command. */
211
+ env?: Record<string, string>;
212
+ }
179
213
  /**
180
214
  * Structured runsOn selector with required and excluded labels.
181
215
  * Used when jobs need to target specific agents while excluding others.
@@ -226,12 +260,12 @@ export interface Job {
226
260
  readonly checkout?: boolean;
227
261
  /** Docker image for job execution. All steps run inside the container. */
228
262
  readonly container?: string | ContainerConfig;
229
- /** Deployment environment for this job. String for static, async function for dynamic (resolved at orchestrator two-phase eval). */
230
- readonly environment?: string | ((event: Record<string, unknown>) => string | Promise<string>);
231
- /** Environment variables. Static object or async function (resolved at orchestrator two-phase eval). */
232
- readonly env?: Record<string, string> | ((event: Record<string, unknown>) => Record<string, string> | Promise<Record<string, string>>);
233
- /** Concurrency group name. Defaults to environment name if not set. String or async function. */
234
- readonly concurrencyGroup?: string | ((event: Record<string, unknown>) => string | Promise<string>);
263
+ /** Deployment environment for this job. String for static, or a function of the normalized event envelope for dynamic (resolved at orchestrator two-phase eval). */
264
+ readonly environment?: string | ((event: EventPayload) => string | Promise<string>);
265
+ /** Environment variables. Static object or a function of the normalized event envelope (resolved at orchestrator two-phase eval). */
266
+ readonly env?: Record<string, string> | ((event: EventPayload) => Record<string, string> | Promise<Record<string, string>>);
267
+ /** Concurrency group name. Defaults to environment name if not set. String or a function of the normalized event envelope. */
268
+ readonly concurrencyGroup?: string | ((event: EventPayload) => string | Promise<string>);
235
269
  /** Runs on cancellation. */
236
270
  readonly onCancel?: HookInput;
237
271
  /** Always runs after job (success, failure, or cancel). */
@@ -246,6 +280,8 @@ export interface Job {
246
280
  readonly afterStep?: HookInput;
247
281
  /** Seconds before SIGKILL after SIGTERM during cancellation. */
248
282
  readonly gracePeriod?: number;
283
+ /** Total job wall-clock timeout in milliseconds (init + all steps + hooks). On breach the job is aborted and reported timed out. Agent-enforced. Independent of step-level timeout. */
284
+ readonly timeout?: number;
249
285
  /**
250
286
  * Resource request and limit for this job. Used by the scaler to enforce
251
287
  * per-scaler / per-orchestrator / per-machine caps and the kernel-side limits
@@ -260,6 +296,16 @@ export interface Job {
260
296
  * toward the agent-count cap.
261
297
  */
262
298
  readonly resources?: ResourceRequest;
299
+ /**
300
+ * Per-job initialization. Runs after clone, before steps.
301
+ * - A `GenericInitConfig` (or array, run in order) provisions a toolchain.
302
+ * - `false` is an explicit opt-out (reserved for the future auto-detect layer).
303
+ */
304
+ readonly init?: GenericInitConfig | GenericInitConfig[] | false;
305
+ /** Declarative cache: restored before steps, saved after the job on key miss. */
306
+ readonly cache?: import('./cache-types.js').CacheInput;
307
+ /** Pause for a manual human approval before this job dispatches. */
308
+ readonly requireApproval?: RequireApproval;
263
309
  /**
264
310
  * Type-safe proxy for accessing this job's outputs.
265
311
  * For multi-step jobs: jobRef.result.stepName.field
@@ -317,12 +363,12 @@ export interface JobOptions {
317
363
  * When set, all steps run inside the container.
318
364
  */
319
365
  container?: string | ContainerConfig;
320
- /** Deployment environment for this job. String for static, async function for dynamic (resolved at orchestrator two-phase eval). */
321
- environment?: string | ((event: Record<string, unknown>) => string | Promise<string>);
322
- /** Environment variables. Static object or async function (resolved at orchestrator two-phase eval). */
323
- env?: Record<string, string> | ((event: Record<string, unknown>) => Record<string, string> | Promise<Record<string, string>>);
324
- /** Concurrency group name. Defaults to environment name if not set. String or async function. */
325
- concurrencyGroup?: string | ((event: Record<string, unknown>) => string | Promise<string>);
366
+ /** Deployment environment for this job. String for static, or a function of the normalized event envelope for dynamic (resolved at orchestrator two-phase eval). */
367
+ environment?: string | ((event: EventPayload) => string | Promise<string>);
368
+ /** Environment variables. Static object or a function of the normalized event envelope (resolved at orchestrator two-phase eval). */
369
+ env?: Record<string, string> | ((event: EventPayload) => Record<string, string> | Promise<Record<string, string>>);
370
+ /** Concurrency group name. Defaults to environment name if not set. String or a function of the normalized event envelope. */
371
+ concurrencyGroup?: string | ((event: EventPayload) => string | Promise<string>);
326
372
  /** Runs on cancellation. */
327
373
  onCancel?: HookInput;
328
374
  /** Always runs after job (success, failure, or cancel). */
@@ -337,6 +383,8 @@ export interface JobOptions {
337
383
  afterStep?: HookInput;
338
384
  /** Seconds before SIGKILL after SIGTERM during cancellation. */
339
385
  gracePeriod?: number;
386
+ /** Total job wall-clock timeout in milliseconds (init + all steps + hooks). On breach the job is aborted and reported timed out. Agent-enforced. Independent of step-level timeout. */
387
+ timeout?: number;
340
388
  /**
341
389
  * Resource request and limit for this job. Used by the scaler to enforce
342
390
  * per-scaler / per-orchestrator / per-machine caps and the kernel-side limits
@@ -351,6 +399,16 @@ export interface JobOptions {
351
399
  * toward the agent-count cap.
352
400
  */
353
401
  resources?: ResourceRequest;
402
+ /**
403
+ * Per-job initialization. Runs after clone, before steps.
404
+ * - A `GenericInitConfig` (or array, run in order) provisions a toolchain.
405
+ * - `false` is an explicit opt-out (reserved for the future auto-detect layer).
406
+ */
407
+ init?: GenericInitConfig | GenericInitConfig[] | false;
408
+ /** Declarative cache: restored before steps, saved after the job on key miss. */
409
+ cache?: import('./cache-types.js').CacheInput;
410
+ /** Pause for a manual human approval before this job dispatches. */
411
+ requireApproval?: RequireApproval;
354
412
  }
355
413
  /**
356
414
  * Private npm registry declaration. Tells the agent to authenticate against
@@ -409,6 +467,8 @@ export interface Workflow {
409
467
  * prefix is stripped for the env-var name).
410
468
  */
411
469
  readonly installEnv?: readonly string[];
470
+ /** Whole-run wall-clock timeout in milliseconds across all jobs. On breach the orchestrator cancels outstanding/queued jobs and marks the run timed out. Orchestrator-enforced. Independent of job-level timeout. */
471
+ readonly timeout?: number;
412
472
  /** Runs on cancellation. */
413
473
  readonly onCancel?: HookInput;
414
474
  /** Always runs after workflow (success, failure, or cancel). */
@@ -421,11 +481,13 @@ export interface Workflow {
421
481
  readonly concurrency?: {
422
482
  readonly group: (ctx: {
423
483
  branch: string;
424
- event: Record<string, unknown>;
484
+ event: EventPayload;
425
485
  }) => string;
426
486
  readonly cancelInProgress?: boolean;
427
487
  readonly max?: number;
428
488
  };
489
+ /** Pause for a manual human approval before the whole workflow dispatches. */
490
+ readonly requireApproval?: RequireApproval;
429
491
  }
430
492
  /** Options for workflow() factory */
431
493
  export interface WorkflowOptions {
@@ -458,6 +520,8 @@ export interface WorkflowOptions {
458
520
  * exposed to the install subprocess under the `<secret-name>` key.
459
521
  */
460
522
  installEnv?: string[];
523
+ /** Whole-run wall-clock timeout in milliseconds across all jobs. On breach the orchestrator cancels outstanding/queued jobs and marks the run timed out. Orchestrator-enforced. Independent of job-level timeout. */
524
+ timeout?: number;
461
525
  /** Runs on cancellation. */
462
526
  onCancel?: HookInput;
463
527
  /** Always runs after workflow (success, failure, or cancel). */
@@ -470,11 +534,13 @@ export interface WorkflowOptions {
470
534
  concurrency?: {
471
535
  group: (ctx: {
472
536
  branch: string;
473
- event: Record<string, unknown>;
537
+ event: EventPayload;
474
538
  }) => string;
475
539
  cancelInProgress?: boolean;
476
540
  max?: number;
477
541
  };
542
+ /** Pause for a manual human approval before the whole workflow dispatches. */
543
+ requireApproval?: RequireApproval;
478
544
  }
479
545
  export type { TriggerConfig, PrTriggerConfig, PushTriggerConfig } from './triggers/types.js';
480
546
  export type { Rule, RuleContext, RuleCheckFn, RuleResult } from './rules/types.js';
package/dist/workflow.js CHANGED
@@ -70,11 +70,13 @@ function workflow(name, options) {
70
70
  hashFiles: options.hashFiles,
71
71
  registries: options.registries,
72
72
  installEnv: options.installEnv,
73
+ timeout: options.timeout,
73
74
  onCancel: options.onCancel,
74
75
  cleanup: options.cleanup,
75
76
  onSuccess: options.onSuccess,
76
77
  onFailure: options.onFailure,
77
- concurrency: options.concurrency
78
+ concurrency: options.concurrency,
79
+ requireApproval: options.requireApproval
78
80
  };
79
81
  }
80
82
  //#endregion
package/package.json CHANGED
@@ -1,18 +1,22 @@
1
1
  {
2
2
  "name": "@kici-dev/sdk",
3
- "version": "0.1.14",
3
+ "version": "0.1.16",
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
- "kici",
7
6
  "ci",
8
- "cd",
9
- "ci-cd",
7
+ "cicd",
8
+ "continuous-integration",
10
9
  "typescript",
11
- "workflows",
12
- "devops",
10
+ "workflow",
13
11
  "sdk",
14
- "dsl"
12
+ "pipeline"
15
13
  ],
14
+ "repository": {
15
+ "type": "git",
16
+ "url": "git+https://github.com/kici-dev/kici-public.git",
17
+ "directory": "packages/sdk"
18
+ },
19
+ "bugs": "https://github.com/kici-dev/kici-public/issues",
16
20
  "homepage": "https://kici.dev",
17
21
  "author": {
18
22
  "name": "KiCI",
@@ -46,8 +50,8 @@
46
50
  "micromatch": "^4.0.8",
47
51
  "zod": "^4.3.6",
48
52
  "zx": "^8.8.5",
49
- "@kici-dev/core": "0.1.14",
50
- "@kici-dev/engine": "0.1.14"
53
+ "@kici-dev/core": "0.1.16",
54
+ "@kici-dev/engine": "0.1.16"
51
55
  },
52
56
  "devDependencies": {
53
57
  "@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.14",
6
- "documentNamespace": "https://kici.dev/sbom/%40kici-dev%2Fsdk/0.1.14/89096b19-0fba-4f00-884f-26dadf7c8045",
5
+ "name": "@kici-dev/sdk@0.1.16",
6
+ "documentNamespace": "https://kici.dev/sbom/%40kici-dev%2Fsdk/0.1.16/49f54029-d7dc-48b9-ad51-af6b845b321f",
7
7
  "creationInfo": {
8
- "created": "2026-05-30T03:06:03Z",
8
+ "created": "2026-06-12T09:41:41Z",
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.14",
149
+ "SPDXID": "SPDXRef-Package--kici-dev-core-0.1.16",
150
150
  "name": "@kici-dev/core",
151
- "versionInfo": "0.1.14",
151
+ "versionInfo": "0.1.16",
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.14"
162
+ "referenceLocator": "pkg:npm/%40kici-dev/core@0.1.16"
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.14",
169
+ "SPDXID": "SPDXRef-Package--kici-dev-engine-0.1.16",
170
170
  "name": "@kici-dev/engine",
171
- "versionInfo": "0.1.14",
171
+ "versionInfo": "0.1.16",
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.14"
182
+ "referenceLocator": "pkg:npm/%40kici-dev/engine@0.1.16"
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.14",
191
+ "versionInfo": "0.1.16",
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.14"
202
+ "referenceLocator": "pkg:npm/%40kici-dev/sdk@0.1.16"
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.",
@@ -1544,58 +1544,58 @@
1544
1544
  "relationshipType": "DEPENDS_ON"
1545
1545
  },
1546
1546
  {
1547
- "spdxElementId": "SPDXRef-Package--kici-dev-core-0.1.14",
1547
+ "spdxElementId": "SPDXRef-Package--kici-dev-core-0.1.16",
1548
1548
  "relatedSpdxElement": "SPDXRef-Package-oxc-transform-0.128.0",
1549
1549
  "relationshipType": "DEPENDS_ON"
1550
1550
  },
1551
1551
  {
1552
- "spdxElementId": "SPDXRef-Package--kici-dev-core-0.1.14",
1552
+ "spdxElementId": "SPDXRef-Package--kici-dev-core-0.1.16",
1553
1553
  "relatedSpdxElement": "SPDXRef-Package-picocolors-1.1.1",
1554
1554
  "relationshipType": "DEPENDS_ON"
1555
1555
  },
1556
1556
  {
1557
- "spdxElementId": "SPDXRef-Package--kici-dev-core-0.1.14",
1557
+ "spdxElementId": "SPDXRef-Package--kici-dev-core-0.1.16",
1558
1558
  "relatedSpdxElement": "SPDXRef-Package-winston-daily-rotate-file-5.0.0",
1559
1559
  "relationshipType": "DEPENDS_ON"
1560
1560
  },
1561
1561
  {
1562
- "spdxElementId": "SPDXRef-Package--kici-dev-core-0.1.14",
1562
+ "spdxElementId": "SPDXRef-Package--kici-dev-core-0.1.16",
1563
1563
  "relatedSpdxElement": "SPDXRef-Package-winston-3.19.0",
1564
1564
  "relationshipType": "DEPENDS_ON"
1565
1565
  },
1566
1566
  {
1567
- "spdxElementId": "SPDXRef-Package--kici-dev-core-0.1.14",
1567
+ "spdxElementId": "SPDXRef-Package--kici-dev-core-0.1.16",
1568
1568
  "relatedSpdxElement": "SPDXRef-Package-zod-4.3.6",
1569
1569
  "relationshipType": "DEPENDS_ON"
1570
1570
  },
1571
1571
  {
1572
- "spdxElementId": "SPDXRef-Package--kici-dev-core-0.1.14",
1572
+ "spdxElementId": "SPDXRef-Package--kici-dev-core-0.1.16",
1573
1573
  "relatedSpdxElement": "SPDXRef-Package-zx-8.8.5",
1574
1574
  "relationshipType": "DEPENDS_ON"
1575
1575
  },
1576
1576
  {
1577
- "spdxElementId": "SPDXRef-Package--kici-dev-engine-0.1.14",
1577
+ "spdxElementId": "SPDXRef-Package--kici-dev-engine-0.1.16",
1578
1578
  "relatedSpdxElement": "SPDXRef-Package-jsonpath-plus-10.4.0",
1579
1579
  "relationshipType": "DEPENDS_ON"
1580
1580
  },
1581
1581
  {
1582
- "spdxElementId": "SPDXRef-Package--kici-dev-engine-0.1.14",
1582
+ "spdxElementId": "SPDXRef-Package--kici-dev-engine-0.1.16",
1583
1583
  "relatedSpdxElement": "SPDXRef-Package-picomatch-4.0.4",
1584
1584
  "relationshipType": "DEPENDS_ON"
1585
1585
  },
1586
1586
  {
1587
- "spdxElementId": "SPDXRef-Package--kici-dev-engine-0.1.14",
1587
+ "spdxElementId": "SPDXRef-Package--kici-dev-engine-0.1.16",
1588
1588
  "relatedSpdxElement": "SPDXRef-Package-zod-4.3.6",
1589
1589
  "relationshipType": "DEPENDS_ON"
1590
1590
  },
1591
1591
  {
1592
1592
  "spdxElementId": "SPDXRef-RootPackage",
1593
- "relatedSpdxElement": "SPDXRef-Package--kici-dev-core-0.1.14",
1593
+ "relatedSpdxElement": "SPDXRef-Package--kici-dev-core-0.1.16",
1594
1594
  "relationshipType": "DEPENDS_ON"
1595
1595
  },
1596
1596
  {
1597
1597
  "spdxElementId": "SPDXRef-RootPackage",
1598
- "relatedSpdxElement": "SPDXRef-Package--kici-dev-engine-0.1.14",
1598
+ "relatedSpdxElement": "SPDXRef-Package--kici-dev-engine-0.1.16",
1599
1599
  "relationshipType": "DEPENDS_ON"
1600
1600
  },
1601
1601
  {