@kici-dev/sdk 0.1.26 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/dist/api-types.d.ts +28 -0
  2. package/dist/api-types.js +3 -1
  3. package/dist/approval.d.ts +3 -8
  4. package/dist/approval.js +9 -0
  5. package/dist/artifacts-types.d.ts +45 -0
  6. package/dist/artifacts-types.js +3 -0
  7. package/dist/context.d.ts +73 -23
  8. package/dist/events/define-event.d.ts +11 -3
  9. package/dist/events/define-event.js +14 -4
  10. package/dist/events/emit-typing.test-d.d.ts +2 -0
  11. package/dist/events/emit-typing.test-d.js +36 -0
  12. package/dist/events/event-payloads.d.ts +4 -0
  13. package/dist/events/index.d.ts +1 -1
  14. package/dist/events/index.js +2 -2
  15. package/dist/fleet/agent-version-converge.d.ts +23 -0
  16. package/dist/fleet/agent-version-converge.js +58 -0
  17. package/dist/idempotent.d.ts +2 -2
  18. package/dist/idempotent.js +2 -2
  19. package/dist/index.d.ts +9 -3
  20. package/dist/index.js +6 -2
  21. package/dist/job-outputs.test-d.d.ts +2 -0
  22. package/dist/job-outputs.test-d.js +164 -0
  23. package/dist/job.d.ts +71 -9
  24. package/dist/job.js +19 -5
  25. package/dist/matrix/expand.d.ts +1 -1
  26. package/dist/matrix/expand.js +2 -2
  27. package/dist/needs-context.d.ts +13 -6
  28. package/dist/outputs.d.ts +19 -4
  29. package/dist/outputs.js +21 -7
  30. package/dist/parallel.d.ts +1 -1
  31. package/dist/parallel.js +1 -1
  32. package/dist/provenance-types.d.ts +3 -3
  33. package/dist/rules/context.d.ts +33 -0
  34. package/dist/rules/context.js +51 -0
  35. package/dist/rules/evaluator.d.ts +10 -0
  36. package/dist/rules/evaluator.js +9 -1
  37. package/dist/rules/index.d.ts +2 -0
  38. package/dist/rules/index.js +2 -1
  39. package/dist/rules/types.d.ts +11 -1
  40. package/dist/secrets.d.ts +1 -1
  41. package/dist/step.d.ts +6 -6
  42. package/dist/step.js +6 -3
  43. package/dist/testing/index.d.ts +2 -0
  44. package/dist/testing/index.js +3 -0
  45. package/dist/testing/step-context.d.ts +56 -0
  46. package/dist/testing/step-context.js +259 -0
  47. package/dist/triggers/index.d.ts +2 -1
  48. package/dist/triggers/index.js +2 -1
  49. package/dist/triggers/types.d.ts +23 -1
  50. package/dist/triggers/workflows-failed-batch.d.ts +20 -0
  51. package/dist/triggers/workflows-failed-batch.js +25 -0
  52. package/dist/types.d.ts +163 -30
  53. package/dist/validation/dag.js +11 -3
  54. package/dist/workflow.js +3 -3
  55. package/package.json +10 -5
  56. package/sbom.spdx.json +192 -192
@@ -74,6 +74,15 @@ export interface HostApi {
74
74
  deadlineMs?: number;
75
75
  }): Promise<void>;
76
76
  }
77
+ /** Version-convergence status for a fleet host (the availability-gate probe). */
78
+ export interface AgentVersionStatus {
79
+ /** The orchestrator's own version — the convergence target. */
80
+ targetVersion: string;
81
+ /** The version last staged onto the host, or null when never staged. */
82
+ stagedVersion: string | null;
83
+ /** True only when the target's payload objects exist for the host's platform. */
84
+ available: boolean;
85
+ }
77
86
  export interface BootstrapApi {
78
87
  /**
79
88
  * Bring up a temporary privileged init-runner on a declared-but-un-agented
@@ -107,6 +116,25 @@ export interface BootstrapApi {
107
116
  port?: number;
108
117
  command?: string;
109
118
  }): Promise<void>;
119
+ /**
120
+ * Read a fleet host's agent-version convergence status: the orchestrator's
121
+ * target version, the version last staged on the host, and whether the
122
+ * target's self-contained payloads are available for the host's platform. The
123
+ * availability-gate probe the `agentVersionConverge()` check-step calls; a
124
+ * `false` `available` means the convergence HOLDS the host (never a skew).
125
+ */
126
+ agentVersionStatus(targetAgentId: string): Promise<AgentVersionStatus>;
127
+ /**
128
+ * Re-stage a fleet host onto the orchestrator's version and restart its agent,
129
+ * driven by THIS (ops) agent as an external actor over SSH — no
130
+ * self-update-handoff. Availability-gated server-side: refuses when the target
131
+ * version's payloads are unavailable. Returns `{ restaged: false }` when the
132
+ * host is already on the target version. The step calling this must run on an
133
+ * agent holding `kici:capability:ssh-transport`.
134
+ */
135
+ restageAgent(targetAgentId: string): Promise<{
136
+ restaged: boolean;
137
+ }>;
110
138
  }
111
139
  export interface KiciApi {
112
140
  /** Query orchestrator infrastructure (scalers, agents). */
package/dist/api-types.js CHANGED
@@ -43,7 +43,9 @@ function buildKiciApi(transport, jobCtx) {
43
43
  preBootSend: (targetAgentId, opts) => transport("kici.preBootSend", {
44
44
  targetAgentId,
45
45
  ...opts
46
- })
46
+ }),
47
+ agentVersionStatus: (targetAgentId) => transport("kici.agentVersionStatus", { targetAgentId }),
48
+ restageAgent: (targetAgentId) => transport("kici.restageAgent", { targetAgentId })
47
49
  }
48
50
  };
49
51
  }
@@ -1,10 +1,3 @@
1
- /**
2
- * Workflow-author API for declaring a manual approval gate at step, job, or
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'`).
7
- */
8
1
  /** A single approver clause: any member of a team, or a specific user. */
9
2
  export type ApproverClause = {
10
3
  team: string;
@@ -26,7 +19,9 @@ export type ApprovalWhen = 'always' | 'drift';
26
19
  * - `true` — pause for ANY org member with the approval permission.
27
20
  * - `ApproverClause[]` — a flat AND list (all clauses must be satisfied).
28
21
  * - object form — clauses plus an optional `when`, a human `reason`, and a
29
- * per-gate `timeout` (seconds) that overrides the org-default expiry.
22
+ * per-gate `timeout` that overrides the org-default expiry. The `timeout`
23
+ * must be a positive integer number of seconds; a non-positive or non-finite
24
+ * value is rejected at compile time.
30
25
  */
31
26
  export type ApprovalConfig = true | ApproverClause[] | {
32
27
  when?: ApprovalWhen;
package/dist/approval.js CHANGED
@@ -1,6 +1,14 @@
1
1
  import "./rolldown-runtime-ClRpJifh.js";
2
+ import { approvalTimeoutSecondsSchema } from "@kici-dev/engine";
2
3
  //#region src/approval.ts
3
4
  /**
5
+ * Workflow-author API for declaring a manual approval gate at step, job, or
6
+ * workflow level. The author writes `approval`; the compiler normalizes it
7
+ * into the lock file's `approval` block, and the orchestrator turns it into a
8
+ * held element at dispatch time (for `when: 'always'`) or the agent turns it
9
+ * into a mid-step drift gate (for `when: 'drift'`).
10
+ */
11
+ /**
4
12
  * Normalize any `ApprovalConfig` form into
5
13
  * `{ clauses, reason?, timeoutSeconds?, when }`. `when` defaults to `'always'`.
6
14
  */
@@ -13,6 +21,7 @@ function normalizeApproval(c) {
13
21
  clauses: c,
14
22
  when: "always"
15
23
  };
24
+ if (c.timeout !== void 0 && !approvalTimeoutSecondsSchema.safeParse(c.timeout).success) throw new Error(`approval.timeout must be a positive integer number of seconds, got ${c.timeout}`);
16
25
  return {
17
26
  clauses: c.approvers ?? [],
18
27
  ...c.reason !== void 0 && { reason: c.reason },
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Artifact name constraints: a filesystem/URL-safe token. The schema is hosted
3
+ * in `@kici-dev/engine` because it is a trust-boundary contract the orchestrator
4
+ * enforces on every inbound upload, not only an SDK-side call check. Re-exported
5
+ * here unchanged, so the public SDK surface is stable and a name the SDK accepts
6
+ * is exactly a name the orchestrator accepts.
7
+ */
8
+ export { ArtifactNameSchema, ARTIFACT_NAME_MAX_LENGTH } from '@kici-dev/engine';
9
+ /** Result of an artifact upload or download: the packed size and content hash. */
10
+ export interface ArtifactResult {
11
+ /** Size of the packed tarball in bytes. */
12
+ size: number;
13
+ /** SHA-256 (hex) of the packed tarball bytes. */
14
+ sha256: string;
15
+ }
16
+ /**
17
+ * Imperative artifacts API exposed on `StepContext` as `ctx.artifacts`.
18
+ *
19
+ * Artifacts are named, durable build deliverables shared between jobs of the
20
+ * same run and surfaced in the dashboard run detail. Unlike the cache
21
+ * (content-keyed, eviction-tolerant speedup) and job outputs (small JSON passed
22
+ * via `needs`), an artifact is a first-class deliverable:
23
+ *
24
+ * - **Immutable per run:** the first upload of a name within a run wins; a
25
+ * duplicate name fails loudly (parallel writers become a deterministic error,
26
+ * never a silent clobber).
27
+ * - **Downloadable by any later job** of the same run, and by a human from the
28
+ * run detail page.
29
+ */
30
+ export interface ArtifactsApi {
31
+ /**
32
+ * Pack the given paths (repo-root-relative or `~`-prefixed) into a tarball
33
+ * and upload it as a named artifact. The first upload of a name in a run
34
+ * wins; a duplicate name, an over-cap size, or an exhausted quota throws with
35
+ * the rejection reason. Returns the packed size + sha256.
36
+ */
37
+ upload(name: string, paths: string[]): Promise<ArtifactResult>;
38
+ /**
39
+ * Download a named artifact uploaded earlier in this run and extract it into
40
+ * `destDir` (default: the step's working directory). Throws when the name was
41
+ * never uploaded in this run. Returns the artifact's size + sha256.
42
+ */
43
+ download(name: string, destDir?: string): Promise<ArtifactResult>;
44
+ }
45
+ //# sourceMappingURL=artifacts-types.d.ts.map
@@ -0,0 +1,3 @@
1
+ import "./rolldown-runtime-ClRpJifh.js";
2
+ import { ARTIFACT_NAME_MAX_LENGTH, ArtifactNameSchema } from "@kici-dev/engine";
3
+ export { ARTIFACT_NAME_MAX_LENGTH, ArtifactNameSchema };
package/dist/context.d.ts CHANGED
@@ -1,6 +1,10 @@
1
1
  import type { $ as Shell } from 'zx';
2
+ import type { z } from 'zod';
3
+ import type { TempHandle } from '@kici-dev/core/tmp';
4
+ import type { Job } from './types.js';
2
5
  import type { MatrixValues } from './matrix/types.js';
3
6
  import type { EventEmitOptions } from './events/types.js';
7
+ import type { EventDefinition } from './events/define-event.js';
4
8
  import type { StepSecrets } from './secrets.js';
5
9
  import type { KiciApi } from './api-types.js';
6
10
  import type { FanoutPosition } from './fanout-context.js';
@@ -37,7 +41,7 @@ export interface AgentInfo {
37
41
  /**
38
42
  * Outputs of a matrix job as seen by a downstream `needs:` consumer.
39
43
  * A downstream that consumes a matrix upstream receives this envelope instead of
40
- * a flat outputs object, identically under `kici run local` and the remote path.
44
+ * a flat outputs object, identically under `kici run --local` and the remote path.
41
45
  */
42
46
  export interface MatrixJobOutputs<T = Record<string, unknown>> {
43
47
  /** Keyed by the combination suffix (the text inside `(...)` of the child name). */
@@ -46,7 +50,7 @@ export interface MatrixJobOutputs<T = Record<string, unknown>> {
46
50
  merged: T;
47
51
  }
48
52
  /** Runtime discriminator: true when `ctx.jobOutputs(ref)` returned a matrix envelope. */
49
- export declare function isMatrixJobOutputs(value: Record<string, unknown> | MatrixJobOutputs | HostJobOutputs): value is MatrixJobOutputs;
53
+ export declare function isMatrixJobOutputs<T = Record<string, unknown>>(value: T | MatrixJobOutputs<T> | HostJobOutputs<T>): value is MatrixJobOutputs<T>;
50
54
  /**
51
55
  * Outputs of a `runsOnAll` host-fanout job as seen by a downstream `needs:`
52
56
  * consumer. Keyed by hostname. Unlike {@link MatrixJobOutputs}, the summary does
@@ -65,7 +69,7 @@ export interface HostJobOutputs<T = Record<string, unknown>> {
65
69
  };
66
70
  }
67
71
  /** Runtime discriminator: true when `ctx.jobOutputs(ref)` returned a host envelope. */
68
- export declare function isHostJobOutputs(value: Record<string, unknown> | MatrixJobOutputs | HostJobOutputs): value is HostJobOutputs;
72
+ export declare function isHostJobOutputs<T = Record<string, unknown>>(value: T | MatrixJobOutputs<T> | HostJobOutputs<T>): value is HostJobOutputs<T>;
69
73
  /**
70
74
  * Augmentable interface for known secret keys.
71
75
  * When augmented via `kici types` (.d.ts generation), narrows get/expose key parameter.
@@ -82,15 +86,24 @@ type IsAugmented<T> = [keyof T] extends [never] ? false : true;
82
86
  * Step secrets with async get/expose accessors.
83
87
  * Use ctx.secrets.get('KEY') to retrieve a value, ctx.secrets.expose('KEY') to inject into env.
84
88
  *
85
- * When KnownSecretKeys is augmented (via .d.ts generation), narrows get/expose key parameter.
86
- * When empty (no augmentation), falls back to StepSecrets with string keys.
89
+ * When KnownSecretKeys is augmented (via .d.ts generation), only the `get`/`expose`
90
+ * key parameter is narrowed to the known keys — every other accessor
91
+ * (`has`, `getMeta`, `list`, `mountFile`, `exposeFile`) is preserved verbatim
92
+ * from StepSecrets. When empty (no augmentation), the whole StepSecrets surface
93
+ * accepts any string key.
87
94
  */
88
- export type StepSecretsTyped = IsAugmented<KnownSecretKeys> extends true ? {
89
- get(key: keyof KnownSecretKeys): Promise<string>;
90
- expose(key: keyof KnownSecretKeys): Promise<void>;
91
- has(key: string): boolean;
92
- getMeta(key: string): import('./secrets.js').SecretMeta | undefined;
93
- } : StepSecrets;
95
+ /**
96
+ * The augmented secrets surface: narrows `get`/`expose` to the provided key set
97
+ * while preserving every other StepSecrets accessor (`has`, `getMeta`, `list`,
98
+ * `mountFile`, `exposeFile`) verbatim. Deriving from StepSecrets via `Omit`
99
+ * keeps the file-mount accessors from silently dropping off whenever the
100
+ * StepSecrets surface grows a new method.
101
+ */
102
+ export type AugmentedStepSecrets<TKeys> = Omit<StepSecrets, 'get' | 'expose'> & {
103
+ get(key: keyof TKeys): Promise<string>;
104
+ expose(key: keyof TKeys): Promise<void>;
105
+ };
106
+ export type StepSecretsTyped = IsAugmented<KnownSecretKeys> extends true ? AugmentedStepSecrets<KnownSecretKeys> : StepSecrets;
94
107
  /** Repository metadata for global workflow context */
95
108
  export interface RepoInfo {
96
109
  /** Repository identifier (e.g., "owner/repo") */
@@ -160,7 +173,7 @@ export interface StepContext<TInputs = Record<string, unknown>> {
160
173
  /**
161
174
  * Raw webhook payload from the git provider.
162
175
  * Contains the full, unmodified payload as received from the webhook.
163
- * In local preview/run mode (`kici preview` / `kici run local`), contains the simulated payload.
176
+ * In local preview/run mode (`kici preview` / `kici run --local`), contains the simulated payload.
164
177
  * Use this for provider-specific data not covered by normalized fields.
165
178
  */
166
179
  rawPayload?: Record<string, unknown>;
@@ -189,13 +202,13 @@ export interface StepContext<TInputs = Record<string, unknown>> {
189
202
  */
190
203
  sourceRepo?: RepoInfo;
191
204
  /**
192
- * The resolved deployment environment name for this job.
193
- * Set when the job declares an `environment` property.
194
- * Undefined for jobs without an environment.
205
+ * The resolved context name for this job.
206
+ * Set when the job declares a `context` property.
207
+ * Undefined for jobs without a context.
195
208
  */
196
- environment?: string;
209
+ context?: string;
197
210
  /**
198
- * Secrets resolved for this job's environment.
211
+ * Secrets resolved for this job's context.
199
212
  * Use ctx.secrets.get('KEY') to retrieve a value asynchronously.
200
213
  * Use ctx.secrets.expose('KEY') to inject into process.env explicitly.
201
214
  * Use ctx.secrets.has('KEY') to check existence synchronously.
@@ -208,12 +221,18 @@ export interface StepContext<TInputs = Record<string, unknown>> {
208
221
  * Events are delivered immediately (mid-workflow, not queued until completion).
209
222
  *
210
223
  * @example
211
- * // Emit a simple event
224
+ * // Typed via a defineEvent() definition — payload is schema-checked
225
+ * await ctx.emit(deployComplete, { env: 'prod', version: '1.2.3' });
226
+ *
227
+ * // Or by ad-hoc name (payload typed as Record<string, unknown>)
212
228
  * await ctx.emit('deploy-complete', { env: 'prod', version: '1.2.3' });
213
229
  *
214
230
  * // Emit with cross-repo targeting
215
231
  * await ctx.emit('deploy-complete', { env: 'prod' }, { target: { repos: ['org/other-repo'] } });
216
232
  */
233
+ emit<T extends z.ZodTypeAny>(definition: EventDefinition<T>, payload: z.infer<T>, options?: EventEmitOptions): Promise<{
234
+ deliveryId: string;
235
+ }>;
217
236
  emit(eventName: string, payload?: Record<string, unknown>, options?: EventEmitOptions): Promise<{
218
237
  deliveryId: string;
219
238
  }>;
@@ -239,7 +258,7 @@ export interface StepContext<TInputs = Record<string, unknown>> {
239
258
  * For a plain upstream this returns the job's collected outputs (step-keyed
240
259
  * for multi-step, flat for run shorthand). For a **matrix** upstream it returns
241
260
  * a {@link MatrixJobOutputs} envelope `{ byMatrix, merged }` keyed by the
242
- * combination suffix — identical under `kici run local` and the remote path.
261
+ * combination suffix — identical under `kici run --local` and the remote path.
243
262
  * Use {@link isMatrixJobOutputs} (or `'byMatrix' in result`) to discriminate.
244
263
  *
245
264
  * @example
@@ -248,6 +267,7 @@ export interface StepContext<TInputs = Record<string, unknown>> {
248
267
  * const m = ctx.jobOutputs(buildMatrixJob);
249
268
  * if (isMatrixJobOutputs(m)) console.log(m.byMatrix['linux, arm64']);
250
269
  */
270
+ jobOutputs<T>(ref: Job<T>): T | MatrixJobOutputs<T> | HostJobOutputs<T>;
251
271
  jobOutputs(ref: {
252
272
  name: string;
253
273
  }): Record<string, unknown> | MatrixJobOutputs | HostJobOutputs;
@@ -273,14 +293,44 @@ export interface StepContext<TInputs = Record<string, unknown>> {
273
293
  * under `spec.key` (immutable — first save wins). Scoped per org + ref.
274
294
  */
275
295
  cache: import('./cache-types.js').CacheApi;
296
+ /**
297
+ * Imperative artifacts API for named, durable build deliverables.
298
+ *
299
+ * `ctx.artifacts.upload(name, paths)` packs the paths and uploads them under
300
+ * `name` (immutable per run — first upload wins, a duplicate name fails).
301
+ * `ctx.artifacts.download(name, destDir?)` retrieves an artifact uploaded by
302
+ * an earlier job of the same run. Artifacts are surfaced in the dashboard run
303
+ * detail and downloadable from there. Distinct from `cache` (content-keyed
304
+ * speedup) and job outputs (small JSON via `needs`).
305
+ */
306
+ artifacts: import('./artifacts-types.js').ArtifactsApi;
276
307
  /**
277
308
  * Build, sign, and persist a KiCI build-provenance attestation for a produced
278
- * artifact. The in-toto statement's identity is derived from a Platform-minted
279
- * identity token (unforgeable); the bundle is signed with an ephemeral key and
280
- * is offline-verifiable. Pass the artifact via a precomputed digest or a path
281
- * the agent digests with SHA-256.
309
+ * artifact. The in-toto statement's identity is derived from an
310
+ * orchestrator-minted identity token (unforgeable); the bundle is signed with
311
+ * an ephemeral key and is offline-verifiable. Pass the artifact via a
312
+ * precomputed digest or a path the agent digests with SHA-256.
282
313
  */
283
314
  attestProvenance(opts: import('./provenance-types.js').AttestProvenanceOptions): Promise<import('./provenance-types.js').AttestProvenanceResult>;
315
+ /**
316
+ * Allocate a scratch directory for this job. The directory is removed
317
+ * automatically when the job ends (success, failure, or cancel); the returned
318
+ * `cleanup()` may also be called manually at any time and is idempotent.
319
+ *
320
+ * When `label` is omitted it defaults to a sanitized step id. Use the returned
321
+ * handle's `path` for scratch work, or `await using h = await ctx.mktemp()` to
322
+ * tie the directory's lifetime to the enclosing scope.
323
+ */
324
+ mktemp(label?: string): Promise<TempHandle>;
325
+ /**
326
+ * Allocate a scratch file for this job. Like {@link mktemp}, the file (and its
327
+ * holder) is removed automatically when the job ends, and the returned
328
+ * `cleanup()` is idempotent and manually callable. `opts.suffix` appends a file
329
+ * extension to the generated name.
330
+ */
331
+ mktempFile(label?: string, opts?: {
332
+ suffix?: string;
333
+ }): Promise<TempHandle>;
284
334
  /**
285
335
  * Upstream needs resolved for this job, keyed by upstream job or group name.
286
336
  * `ctx.needs.<job>.result` is the upstream's outputs proxy and
@@ -3,12 +3,14 @@
3
3
  * Uses Zod for schema validation, re-exported from @kici-dev/sdk.
4
4
  */
5
5
  import type { z } from 'zod';
6
+ /** Discriminant tag stamped on every value produced by {@link defineEvent}. */
7
+ export declare const EVENT_DEFINITION_TAG: 'EventDefinition';
6
8
  /**
7
9
  * A typed event definition with a name and Zod validation schema.
8
10
  * Used to define custom events that can be emitted from steps via ctx.emit().
9
11
  */
10
12
  export interface EventDefinition<T extends z.ZodTypeAny = z.ZodTypeAny> {
11
- readonly _tag: 'EventDefinition';
13
+ readonly _tag: typeof EVENT_DEFINITION_TAG;
12
14
  readonly name: string;
13
15
  readonly schema: T;
14
16
  }
@@ -25,8 +27,14 @@ export interface EventDefinition<T extends z.ZodTypeAny = z.ZodTypeAny> {
25
27
  * services: z.array(z.string()),
26
28
  * }));
27
29
  *
28
- * // In a step:
29
- * await ctx.emit(deployComplete.name, { env: 'prod', version: '1.2.3', services: ['api'] });
30
+ * // In a step (the definition drives payload type-checking):
31
+ * await ctx.emit(deployComplete, { env: 'prod', version: '1.2.3', services: ['api'] });
30
32
  */
31
33
  export declare function defineEvent<T extends z.ZodTypeAny>(name: string, schema: T): EventDefinition<T>;
34
+ /**
35
+ * Runtime type guard: true when `value` is an event definition produced by
36
+ * `defineEvent()`. Lets `ctx.emit(definition, payload)` accept either an event
37
+ * name string or a definition object, resolving the name from the object.
38
+ */
39
+ export declare function isEventDefinition(value: unknown): value is EventDefinition;
32
40
  //# sourceMappingURL=define-event.d.ts.map
@@ -1,5 +1,7 @@
1
1
  import "../rolldown-runtime-ClRpJifh.js";
2
2
  //#region src/events/define-event.ts
3
+ /** Discriminant tag stamped on every value produced by {@link defineEvent}. */
4
+ const EVENT_DEFINITION_TAG = "EventDefinition";
3
5
  /**
4
6
  * Create a typed event definition with a Zod schema.
5
7
  * Event definitions serve as the contract for custom event payloads.
@@ -13,17 +15,25 @@ import "../rolldown-runtime-ClRpJifh.js";
13
15
  * services: z.array(z.string()),
14
16
  * }));
15
17
  *
16
- * // In a step:
17
- * await ctx.emit(deployComplete.name, { env: 'prod', version: '1.2.3', services: ['api'] });
18
+ * // In a step (the definition drives payload type-checking):
19
+ * await ctx.emit(deployComplete, { env: 'prod', version: '1.2.3', services: ['api'] });
18
20
  */
19
21
  function defineEvent(name, schema) {
20
22
  return Object.freeze({
21
- _tag: "EventDefinition",
23
+ _tag: EVENT_DEFINITION_TAG,
22
24
  name,
23
25
  schema
24
26
  });
25
27
  }
28
+ /**
29
+ * Runtime type guard: true when `value` is an event definition produced by
30
+ * `defineEvent()`. Lets `ctx.emit(definition, payload)` accept either an event
31
+ * name string or a definition object, resolving the name from the object.
32
+ */
33
+ function isEventDefinition(value) {
34
+ return typeof value === "object" && value !== null && value._tag === "EventDefinition" && typeof value.name === "string";
35
+ }
26
36
  //#endregion
27
- export { defineEvent };
37
+ export { EVENT_DEFINITION_TAG, defineEvent, isEventDefinition };
28
38
 
29
39
  //# sourceMappingURL=define-event.js.map
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=emit-typing.test-d.d.ts.map
@@ -0,0 +1,36 @@
1
+ import "../rolldown-runtime-ClRpJifh.js";
2
+ import { defineEvent } from "./define-event.js";
3
+ import { z } from "zod";
4
+ import { describe, expectTypeOf, it } from "vitest";
5
+ //#region src/events/emit-typing.test-d.ts
6
+ const deployComplete = defineEvent("deploy-complete", z.object({
7
+ env: z.string(),
8
+ version: z.string()
9
+ }));
10
+ describe("ctx.emit typed overload", () => {
11
+ it("accepts a matching payload when called with a definition", () => {
12
+ const emit = null.emit;
13
+ expectTypeOf(emit).toBeCallableWith(deployComplete, {
14
+ env: "prod",
15
+ version: "1.2.3"
16
+ });
17
+ });
18
+ it("rejects a payload missing a schema field (definition form)", () => {
19
+ null.emit(deployComplete, { env: "prod" });
20
+ });
21
+ it("rejects a payload with a wrong field type (definition form)", () => {
22
+ null.emit(deployComplete, {
23
+ env: 1,
24
+ version: "1.2.3"
25
+ });
26
+ });
27
+ it("still accepts the string-name signature with a loose payload", () => {
28
+ const ctx = null;
29
+ expectTypeOf(ctx.emit).toBeCallableWith("ad-hoc-event", { anything: true });
30
+ expectTypeOf(ctx.emit("ad-hoc-event")).resolves.toEqualTypeOf();
31
+ });
32
+ });
33
+ //#endregion
34
+ export {};
35
+
36
+ //# sourceMappingURL=emit-typing.test-d.js.map
@@ -124,6 +124,10 @@ export interface EventBase {
124
124
  sourceRepo?: string;
125
125
  /** Files changed in this event (for path filtering). */
126
126
  changedFiles?: string[];
127
+ /**
128
+ * Availability of `changedFiles` — `fetched` (real diff), `unavailable` (no diff / could not compute), or `skipped` (orchestrator did not fetch; the agent recomputes from its clone).
129
+ */
130
+ changedFilesStatus?: import('@kici-dev/engine').ChangedFilesStatus;
127
131
  /** Raw webhook payload from the provider. May be absent in flattened event forms. */
128
132
  payload?: Record<string, unknown>;
129
133
  /** Index signature for backward compatibility — untyped fields resolve to unknown. */
@@ -1,4 +1,4 @@
1
- export { defineEvent } from './define-event.js';
1
+ export { defineEvent, isEventDefinition } from './define-event.js';
2
2
  export type { EventDefinition } from './define-event.js';
3
3
  export type { EventEmitOptions } from './types.js';
4
4
  export { isEventType } from './event-payloads.js';
@@ -1,4 +1,4 @@
1
1
  import "../rolldown-runtime-ClRpJifh.js";
2
2
  import { isEventType } from "./event-payloads.js";
3
- import { defineEvent } from "./define-event.js";
4
- export { defineEvent, isEventType };
3
+ import { defineEvent, isEventDefinition } from "./define-event.js";
4
+ export { defineEvent, isEventDefinition, isEventType };
@@ -0,0 +1,23 @@
1
+ import type { Step } from '../types.js';
2
+ /** Drift the convergence check reports; `blocked` is never applied. */
3
+ export interface AgentVersionDrift {
4
+ /** True when the target payloads are unavailable — hold, never apply. */
5
+ blocked: boolean;
6
+ /** The host's current staged version (null when never staged). */
7
+ from: string | null;
8
+ /** The orchestrator target version to converge onto. */
9
+ to: string;
10
+ }
11
+ export interface AgentVersionConvergeOptions {
12
+ /** Step name surfaced in logs / the dashboard. Defaults to `agent-version-converge`. */
13
+ name?: string;
14
+ }
15
+ /**
16
+ * Build a check-step that converges `targetAgentId` onto the orchestrator's
17
+ * version, availability-gated (a missing payload holds the host, never a skew).
18
+ * MUST run on an agent holding `kici:capability:ssh-transport`.
19
+ */
20
+ export declare function agentVersionConverge(targetAgentId: string, opts?: AgentVersionConvergeOptions): Step<{
21
+ restaged: boolean;
22
+ }, string>;
23
+ //# sourceMappingURL=agent-version-converge.d.ts.map
@@ -0,0 +1,58 @@
1
+ import "../rolldown-runtime-ClRpJifh.js";
2
+ import { step } from "../step.js";
3
+ //#region src/fleet/agent-version-converge.ts
4
+ /**
5
+ * Availability-gated fleet agent auto-upgrade — the `agentVersionConverge()`
6
+ * check-step.
7
+ *
8
+ * Placed in a workflow job that runs on an ops agent (one holding
9
+ * `kici:capability:ssh-transport`), it converges a target fleet host onto the
10
+ * orchestrator's own version:
11
+ *
12
+ * - **check** compares the host's staged version against the orchestrator target.
13
+ * Equal ⇒ in-sync (skip). Different ⇒ drift. If the target's self-contained
14
+ * payloads are UNAVAILABLE for the host's platform, the drift is `blocked`:
15
+ * the runner surfaces it (held + alarmed) and the apply refuses it, so a
16
+ * version skew can never be applied.
17
+ * - **apply** (run) re-stages the target payload onto the host and restarts its
18
+ * agent, driven by THIS ops agent as an external actor over SSH — no
19
+ * self-update-handoff. It THROWS on a `blocked` drift (belt-and-suspenders on
20
+ * top of the check + the orchestrator-side availability gate).
21
+ *
22
+ * The re-stage is external-actor driven because the host's own agent cannot
23
+ * swap its running binary underneath itself; the ops agent holds the SSH
24
+ * transport and the host reconnects on its own persistent credential.
25
+ *
26
+ * Rolling + drift-approval gating comes from the shipped check-facet machinery:
27
+ * combine with the run-level check mode and `approval: { when: 'drift' }` for a
28
+ * controlled, health-gated roll.
29
+ */
30
+ /**
31
+ * Build a check-step that converges `targetAgentId` onto the orchestrator's
32
+ * version, availability-gated (a missing payload holds the host, never a skew).
33
+ * MUST run on an agent holding `kici:capability:ssh-transport`.
34
+ */
35
+ function agentVersionConverge(targetAgentId, opts = {}) {
36
+ return step(opts.name ?? "agent-version-converge", {
37
+ check: async (ctx) => {
38
+ const status = await ctx.kici.bootstrap.agentVersionStatus(targetAgentId);
39
+ if (status.stagedVersion === status.targetVersion) return null;
40
+ return {
41
+ blocked: !status.available,
42
+ from: status.stagedVersion,
43
+ to: status.targetVersion
44
+ };
45
+ },
46
+ summarize: (drift) => drift.blocked ? `blocked: payload for ${drift.to} unavailable — holding ${targetAgentId} at ${drift.from ?? "(none)"}` : `agent ${targetAgentId}: ${drift.from ?? "(none)"} → ${drift.to}`,
47
+ run: async (ctx, drift) => {
48
+ if (drift.blocked) throw new Error(`refusing to converge ${targetAgentId} to ${drift.to}: payload unavailable (held to avoid a version skew)`);
49
+ ctx.log.info(`Re-staging ${targetAgentId}: ${drift.from ?? "(none)"} → ${drift.to}`);
50
+ return ctx.kici.bootstrap.restageAgent(targetAgentId);
51
+ },
52
+ whenInSync: async () => ({ restaged: false })
53
+ });
54
+ }
55
+ //#endregion
56
+ export { agentVersionConverge };
57
+
58
+ //# sourceMappingURL=agent-version-converge.js.map
@@ -95,8 +95,8 @@ export interface CheckStepOptions<TDrift, TInSync = void, TApplied = void> exten
95
95
  *
96
96
  * It desugars to the `step()` check facet
97
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.
98
+ * step-loop check-mode drive for free — no engine, agent, orchestrator, or
99
+ * lockfile change.
100
100
  */
101
101
  export declare function checkStep<TDrift, TInSync = void, TApplied = void>(name: string, options: CheckStepOptions<TDrift, TInSync, TApplied>): Step<TApplied | TInSync>;
102
102
  //# sourceMappingURL=idempotent.d.ts.map
@@ -79,8 +79,8 @@ function idempotentStep(name, opts) {
79
79
  *
80
80
  * It desugars to the `step()` check facet
81
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.
82
+ * step-loop check-mode drive for free — no engine, agent, orchestrator, or
83
+ * lockfile change.
84
84
  */
85
85
  function checkStep(name, options) {
86
86
  return step(name, {
package/dist/index.d.ts CHANGED
@@ -5,12 +5,14 @@ export { parallel, isParallelGroup, flattenStepInputs } from './parallel.js';
5
5
  export type { ParallelGroup, ParallelOptions } from './parallel.js';
6
6
  export { normalizeApproval } from './approval.js';
7
7
  export type { ApprovalConfig, ApprovalWhen, ApproverClause, NormalizedApproval, } from './approval.js';
8
- 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';
9
- 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
+ export { pr, push, tag, comment, review, reviewComment, release, dispatch, create, delete as delete, status, workflowRun, fork, star, watch, webhook, kiciEvent, workflowComplete, workflowsFailedBatch, jobComplete, genericWebhook, schedule, lifecycle, defineDispatchInputs, } from './triggers/index.js';
9
+ 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, WorkflowsFailedBatchConfigInput, WorkflowsFailedBatchTriggerConfig, JobCompleteConfigInput, JobCompleteTriggerConfig, JobCompleteStatus, GenericWebhookConfigInput, GenericWebhookTriggerConfig, GenericWebhookAuthMethod, GenericWebhookHmacAuth, GenericWebhookApiKeyAuth, GenericWebhookAuth, ScheduleConfigInput, ScheduleTriggerConfig, LifecycleEvent, LifecycleConfigInput, LifecycleTriggerConfig, } from './triggers/index.js';
10
10
  export { onCancel, cleanup, onSuccess, onFailure, beforeStep, afterStep } from './hooks/index.js';
11
11
  export type { HookConfig, HookFn, HookInput, HookContext, OutcomeMetadata } from './hooks/index.js';
12
12
  export { rule, skip, onlyOnFirstHost, onlyOnLastHost, onlyOnFanoutIndex } from './rules/index.js';
13
13
  export { evaluateRules } from './rules/index.js';
14
+ export { createRuleContext, ChangedFilesUnavailableError } from './rules/index.js';
15
+ export type { CreateRuleContextInput } from './rules/index.js';
14
16
  export { isEventType } from './rules/index.js';
15
17
  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';
16
18
  export { validateDag } from './validation/index.js';
@@ -23,6 +25,8 @@ export type { UpstreamSnapshot, NeedsContext, NeedEntry, GroupNeedEntry } from '
23
25
  export { CacheSpecSchema, normalizeCacheSpecs } from './cache-types.js';
24
26
  export type { CacheSpec, CacheInput } from './cache-types.js';
25
27
  export type { CacheRestoreResult, CacheApi } from './cache-types.js';
28
+ export { ArtifactNameSchema, ARTIFACT_NAME_MAX_LENGTH } from './artifacts-types.js';
29
+ export type { ArtifactsApi, ArtifactResult } from './artifacts-types.js';
26
30
  export { provenanceSubjectIsPath } from './provenance-types.js';
27
31
  export type { AttestProvenanceOptions, AttestProvenanceResult, ProvenanceSubjectInput, } from './provenance-types.js';
28
32
  export { dynamicGroup, isDynamicGroupRef, DYNAMIC_GROUP_TAG } from './dynamic-group.js';
@@ -40,7 +44,7 @@ export type { OutputsMap, StepRefMap } from './outputs.js';
40
44
  export type { StaticMatrixArray, StaticMatrixObject, DynamicMatrixFn, DynamicMatrixContext, Matrix, MatrixInclude, MatrixExclude, MatrixValues, } from './matrix/index.js';
41
45
  export { isStaticArray, isStaticObject, isDynamicFunction } from './matrix/index.js';
42
46
  export { expandMatrix, applyIncludeExclude } from './matrix/index.js';
43
- export { defineEvent } from './events/index.js';
47
+ export { defineEvent, isEventDefinition } from './events/index.js';
44
48
  export type { EventDefinition } from './events/index.js';
45
49
  export type { EventEmitOptions } from './events/index.js';
46
50
  export { fixture } from './fixture.js';
@@ -51,5 +55,7 @@ export { waitFor, waitForStep, WaitForTimeoutError } from './wait-for.js';
51
55
  export type { WaitForOptions, WaitForResult } from './wait-for.js';
52
56
  export { waitForHostAlive, restartHost } from './host-restart.js';
53
57
  export type { WaitForHostAliveOptions, RestartHostOptions } from './host-restart.js';
58
+ export { agentVersionConverge } from './fleet/agent-version-converge.js';
59
+ export type { AgentVersionConvergeOptions, AgentVersionDrift, } from './fleet/agent-version-converge.js';
54
60
  export { z } from 'zod';
55
61
  //# sourceMappingURL=index.d.ts.map