@kici-dev/sdk 0.1.17 → 0.1.19
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/dist/context.d.ts +46 -2
- package/dist/context.js +5 -1
- package/dist/index.d.ts +7 -5
- package/dist/index.js +5 -4
- package/dist/job.js +8 -1
- package/dist/needs-context.d.ts +32 -0
- package/dist/needs-context.js +44 -0
- package/dist/outputs.d.ts +12 -0
- package/dist/outputs.js +36 -1
- package/dist/types.d.ts +106 -13
- package/dist/types.js +24 -4
- package/package.json +4 -4
- package/sbom.spdx.json +208 -183
package/dist/context.d.ts
CHANGED
|
@@ -19,6 +19,20 @@ export interface JobInfo {
|
|
|
19
19
|
name: string;
|
|
20
20
|
runsOn: string;
|
|
21
21
|
}
|
|
22
|
+
/**
|
|
23
|
+
* Facts about the agent a `runsOnAll` host-fanout child is pinned to, exposed
|
|
24
|
+
* as `ctx.agent`. Present only for jobs that use `runsOnAll`.
|
|
25
|
+
*/
|
|
26
|
+
export interface AgentInfo {
|
|
27
|
+
/** Hostname of the agent. */
|
|
28
|
+
host: string;
|
|
29
|
+
/** The agent's label set. */
|
|
30
|
+
labels: readonly string[];
|
|
31
|
+
/** Operating-system platform (os.platform()). */
|
|
32
|
+
platform?: string;
|
|
33
|
+
/** CPU architecture (os.arch()). */
|
|
34
|
+
arch?: string;
|
|
35
|
+
}
|
|
22
36
|
/**
|
|
23
37
|
* Outputs of a matrix job as seen by a downstream `needs:` consumer.
|
|
24
38
|
* A downstream that consumes a matrix upstream receives this envelope instead of
|
|
@@ -31,7 +45,26 @@ export interface MatrixJobOutputs<T = Record<string, unknown>> {
|
|
|
31
45
|
merged: T;
|
|
32
46
|
}
|
|
33
47
|
/** Runtime discriminator: true when `ctx.jobOutputs(ref)` returned a matrix envelope. */
|
|
34
|
-
export declare function isMatrixJobOutputs(value: Record<string, unknown> | MatrixJobOutputs): value is MatrixJobOutputs;
|
|
48
|
+
export declare function isMatrixJobOutputs(value: Record<string, unknown> | MatrixJobOutputs | HostJobOutputs): value is MatrixJobOutputs;
|
|
49
|
+
/**
|
|
50
|
+
* Outputs of a `runsOnAll` host-fanout job as seen by a downstream `needs:`
|
|
51
|
+
* consumer. Keyed by hostname. Unlike {@link MatrixJobOutputs}, the summary does
|
|
52
|
+
* NOT collapse to a last-write-wins scalar (a fleet footgun): `summary.outputs`
|
|
53
|
+
* is an array view across hosts, and `succeededHosts`/`failedHosts` name the
|
|
54
|
+
* per-host outcome.
|
|
55
|
+
*/
|
|
56
|
+
export interface HostJobOutputs<T = Record<string, unknown>> {
|
|
57
|
+
/** Keyed by hostname. */
|
|
58
|
+
byHost: Record<string, T>;
|
|
59
|
+
summary: {
|
|
60
|
+
succeededHosts: string[];
|
|
61
|
+
failedHosts: string[];
|
|
62
|
+
/** Per output key, every host's value (array view; never a collapsing scalar). */
|
|
63
|
+
outputs: Record<string, unknown[]>;
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
/** Runtime discriminator: true when `ctx.jobOutputs(ref)` returned a host envelope. */
|
|
67
|
+
export declare function isHostJobOutputs(value: Record<string, unknown> | MatrixJobOutputs | HostJobOutputs): value is HostJobOutputs;
|
|
35
68
|
/**
|
|
36
69
|
* Augmentable interface for known secret keys.
|
|
37
70
|
* When augmented via `kici types` (.d.ts generation), narrows get/expose key parameter.
|
|
@@ -93,6 +126,17 @@ export interface StepContext<TInputs = Record<string, unknown>> {
|
|
|
93
126
|
* - Undefined for jobs without matrix configuration
|
|
94
127
|
*/
|
|
95
128
|
matrix?: MatrixValues;
|
|
129
|
+
/**
|
|
130
|
+
* Hostname of the agent this job instance is running on.
|
|
131
|
+
* Set only for jobs that use `runsOnAll` (host fan-out — one pinned execution
|
|
132
|
+
* per matching host). Undefined for jobs without host fan-out.
|
|
133
|
+
*/
|
|
134
|
+
host?: string;
|
|
135
|
+
/**
|
|
136
|
+
* Facts about the agent this job instance is pinned to (hostname, labels,
|
|
137
|
+
* platform, arch). Set only for jobs that use `runsOnAll`. Undefined otherwise.
|
|
138
|
+
*/
|
|
139
|
+
agent?: AgentInfo;
|
|
96
140
|
/**
|
|
97
141
|
* Raw webhook payload from the git provider.
|
|
98
142
|
* Contains the full, unmodified payload as received from the webhook.
|
|
@@ -186,7 +230,7 @@ export interface StepContext<TInputs = Record<string, unknown>> {
|
|
|
186
230
|
*/
|
|
187
231
|
jobOutputs(ref: {
|
|
188
232
|
name: string;
|
|
189
|
-
}): Record<string, unknown> | MatrixJobOutputs;
|
|
233
|
+
}): Record<string, unknown> | MatrixJobOutputs | HostJobOutputs;
|
|
190
234
|
/**
|
|
191
235
|
* Publish a secret output value from this job.
|
|
192
236
|
* Secret outputs are encrypted before leaving the agent and can be consumed
|
package/dist/context.js
CHANGED
|
@@ -4,7 +4,11 @@ import "./chunk-BTugEXQM.js";
|
|
|
4
4
|
function isMatrixJobOutputs(value) {
|
|
5
5
|
return typeof value === "object" && value !== null && "byMatrix" in value && "merged" in value && typeof value.byMatrix === "object";
|
|
6
6
|
}
|
|
7
|
+
/** Runtime discriminator: true when `ctx.jobOutputs(ref)` returned a host envelope. */
|
|
8
|
+
function isHostJobOutputs(value) {
|
|
9
|
+
return typeof value === "object" && value !== null && "byHost" in value && "summary" in value && typeof value.byHost === "object";
|
|
10
|
+
}
|
|
7
11
|
//#endregion
|
|
8
|
-
export { isMatrixJobOutputs };
|
|
12
|
+
export { isHostJobOutputs, isMatrixJobOutputs };
|
|
9
13
|
|
|
10
14
|
//# sourceMappingURL=context.js.map
|
package/dist/index.d.ts
CHANGED
|
@@ -14,8 +14,10 @@ export type { Rule, RuleContext, RuleCheckFn, RuleResult, EventPayload, RuleEval
|
|
|
14
14
|
export { validateDag } from './validation/index.js';
|
|
15
15
|
export type { DagNode, DagValidationResult } from './validation/index.js';
|
|
16
16
|
export type { SourceLocation, OutputProxy, Step, StepOptions, StepRunFn, BareStepFn, StepInput, OutputSchema, InferOutputs, Job, JobOptions, GenericInitConfig, MiseInitConfig, InitPreset, InitItem, InitConfig, ContainerConfig, RunsOnSelector, RunsOn, Workflow, WorkflowOptions, Registry, Trigger, DynamicJobFn, DynamicJobContext, JobOrFactory, } from './types.js';
|
|
17
|
-
export { isDynamicJobFn, dynamicJob, getDynamicJobGroup, DYNAMIC_JOB_GROUP_TAG } from './types.js';
|
|
18
|
-
export type { TaggedDynamicJobFn } from './types.js';
|
|
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';
|
|
19
|
+
export { buildNeedsContext } from './needs-context.js';
|
|
20
|
+
export type { UpstreamSnapshot, NeedsContext, NeedEntry, GroupNeedEntry } from './needs-context.js';
|
|
19
21
|
export { CacheSpecSchema, normalizeCacheSpecs } from './cache-types.js';
|
|
20
22
|
export type { CacheSpec, CacheInput } from './cache-types.js';
|
|
21
23
|
export type { CacheRestoreResult, CacheApi } from './cache-types.js';
|
|
@@ -23,14 +25,14 @@ export { provenanceSubjectIsPath } from './provenance-types.js';
|
|
|
23
25
|
export type { AttestProvenanceOptions, AttestProvenanceResult, ProvenanceSubjectInput, } from './provenance-types.js';
|
|
24
26
|
export { dynamicGroup, isDynamicGroupRef, DYNAMIC_GROUP_TAG } from './dynamic-group.js';
|
|
25
27
|
export type { DynamicGroupRef } from './dynamic-group.js';
|
|
26
|
-
export type { StepContext, Logger, WorkflowInfo, JobInfo, MatrixJobOutputs, RepoInfo, StepSecretsTyped, KnownSecretKeys, } from './context.js';
|
|
27
|
-
export { isMatrixJobOutputs } from './context.js';
|
|
28
|
+
export type { StepContext, Logger, WorkflowInfo, JobInfo, AgentInfo, MatrixJobOutputs, HostJobOutputs, RepoInfo, StepSecretsTyped, KnownSecretKeys, } from './context.js';
|
|
29
|
+
export { isMatrixJobOutputs, isHostJobOutputs } from './context.js';
|
|
28
30
|
export { buildKiciApi } from './api-types.js';
|
|
29
31
|
export type { KiciApi, KiciApiTransport, InfrastructureApi, InfrastructureListResult, } from './api-types.js';
|
|
30
32
|
export { SecretNotFoundError } from './errors.js';
|
|
31
33
|
export { createStepSecrets } from './secrets.js';
|
|
32
34
|
export type { StepSecrets, TrackedStepSecrets, SecretMeta, SecretFileOptions, MountedFile, StepSecretsFileHost, StepSecretsFileWiring, StepSecretsHandle, StepSecretMountKind, StepSecretMountRecord, } from './secrets.js';
|
|
33
|
-
export { createStepOutputProxy, createJobOutputProxy, resolveStepOutputs, resolveJobOutputs, setStepOutputsMap, setJobOutputsMap, setStepRefMap, getStepOutputsMap, getJobOutputsMap, getStepRefMap, } from './outputs.js';
|
|
35
|
+
export { createStepOutputProxy, createJobOutputProxy, createSnapshotOutputProxy, resolveStepOutputs, resolveJobOutputs, setStepOutputsMap, setJobOutputsMap, setStepRefMap, getStepOutputsMap, getJobOutputsMap, getStepRefMap, } from './outputs.js';
|
|
34
36
|
export type { OutputsMap, StepRefMap } from './outputs.js';
|
|
35
37
|
export type { StaticMatrixArray, StaticMatrixObject, DynamicMatrixFn, DynamicMatrixContext, Matrix, MatrixInclude, MatrixExclude, MatrixValues, } from './matrix/index.js';
|
|
36
38
|
export { isStaticArray, isStaticObject, isDynamicFunction } from './matrix/index.js';
|
package/dist/index.js
CHANGED
|
@@ -2,11 +2,11 @@ import "./chunk-BTugEXQM.js";
|
|
|
2
2
|
import { buildKiciApi } from "./api-types.js";
|
|
3
3
|
import { normalizeRequireApproval } from "./approval.js";
|
|
4
4
|
import { CacheSpecSchema, normalizeCacheSpecs } from "./cache-types.js";
|
|
5
|
-
import { isMatrixJobOutputs } from "./context.js";
|
|
5
|
+
import { isHostJobOutputs, isMatrixJobOutputs } from "./context.js";
|
|
6
6
|
import { DYNAMIC_GROUP_TAG, dynamicGroup, isDynamicGroupRef } from "./dynamic-group.js";
|
|
7
7
|
import { SecretNotFoundError } from "./errors.js";
|
|
8
8
|
import { fixture } from "./fixture.js";
|
|
9
|
-
import { createJobOutputProxy, createStepOutputProxy, getJobOutputsMap, getStepOutputsMap, getStepRefMap, resolveJobOutputs, resolveStepOutputs, setJobOutputsMap, setStepOutputsMap, setStepRefMap } from "./outputs.js";
|
|
9
|
+
import { createJobOutputProxy, createSnapshotOutputProxy, createStepOutputProxy, getJobOutputsMap, getStepOutputsMap, getStepRefMap, resolveJobOutputs, resolveStepOutputs, setJobOutputsMap, setStepOutputsMap, setStepRefMap } from "./outputs.js";
|
|
10
10
|
import { step } from "./step.js";
|
|
11
11
|
import { idempotent, idempotentStep } from "./idempotent.js";
|
|
12
12
|
import { job } from "./job.js";
|
|
@@ -41,7 +41,8 @@ import { isEventType } from "./events/event-payloads.js";
|
|
|
41
41
|
import "./rules/index.js";
|
|
42
42
|
import { validateDag } from "./validation/dag.js";
|
|
43
43
|
import "./validation/index.js";
|
|
44
|
-
import { DYNAMIC_JOB_GROUP_TAG, dynamicJob, getDynamicJobGroup, isDynamicJobFn } from "./types.js";
|
|
44
|
+
import { DYNAMIC_JOB_GROUP_TAG, DYNAMIC_JOB_NEEDS_TAG, dynamicJob, getDynamicJobGroup, getDynamicJobNeeds, isDynamicJobFn } from "./types.js";
|
|
45
|
+
import { buildNeedsContext } from "./needs-context.js";
|
|
45
46
|
import { provenanceSubjectIsPath } from "./provenance-types.js";
|
|
46
47
|
import { createStepSecrets } from "./secrets.js";
|
|
47
48
|
import { isDynamicFunction, isStaticArray, isStaticObject } from "./matrix/types.js";
|
|
@@ -51,4 +52,4 @@ import { defineEvent } from "./events/define-event.js";
|
|
|
51
52
|
import "./events/index.js";
|
|
52
53
|
import { WaitForTimeoutError, waitFor, waitForStep } from "./wait-for.js";
|
|
53
54
|
import { z } from "zod";
|
|
54
|
-
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, 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 };
|
|
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 };
|
package/dist/job.js
CHANGED
|
@@ -32,10 +32,17 @@ function job(nameOrOptions, maybeOptions) {
|
|
|
32
32
|
steps = [options.run];
|
|
33
33
|
}
|
|
34
34
|
validateInit(options.init, name);
|
|
35
|
+
if (options.runsOn !== void 0 && options.runsOnAll !== void 0) throw new Error(`job('${name}'): runsOn and runsOnAll are mutually exclusive`);
|
|
36
|
+
if (options.runsOn === void 0 && options.runsOnAll === void 0) throw new Error(`job('${name}'): one of runsOn or runsOnAll is required`);
|
|
37
|
+
if (options.onUnreachable !== void 0 && options.runsOnAll === void 0) console.warn(`[kici] job('${name}'): onUnreachable is ignored without runsOnAll`);
|
|
35
38
|
return {
|
|
36
39
|
_tag: "Job",
|
|
37
40
|
name,
|
|
38
|
-
runsOn: options.runsOn,
|
|
41
|
+
...options.runsOn !== void 0 && { runsOn: options.runsOn },
|
|
42
|
+
...options.runsOnAll !== void 0 && { runsOnAll: options.runsOnAll },
|
|
43
|
+
...options.onUnreachable !== void 0 && { onUnreachable: options.onUnreachable },
|
|
44
|
+
...options.maxParallel !== void 0 && { maxParallel: options.maxParallel },
|
|
45
|
+
...options.failFast !== void 0 && { failFast: options.failFast },
|
|
39
46
|
steps,
|
|
40
47
|
needs: options.needs,
|
|
41
48
|
rules: options.rules,
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { OutputProxy, DynamicJobNeed } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Frozen snapshot of upstream outputs, captured once at first eval of a
|
|
4
|
+
* result-aware dynamic generator and replayed unchanged on re-eval.
|
|
5
|
+
*
|
|
6
|
+
* - `jobs` maps an upstream job name to its outputs record.
|
|
7
|
+
* - `groups` maps a dynamic group name to its ordered member job names.
|
|
8
|
+
*/
|
|
9
|
+
export interface UpstreamSnapshot {
|
|
10
|
+
jobs: Record<string, Record<string, unknown>>;
|
|
11
|
+
groups: Record<string, string[]>;
|
|
12
|
+
}
|
|
13
|
+
/** One entry in the array exposed for a `dynamicGroup(...)` need. */
|
|
14
|
+
export interface GroupNeedEntry {
|
|
15
|
+
name: string;
|
|
16
|
+
result: OutputProxy<any>;
|
|
17
|
+
}
|
|
18
|
+
/** A single-job need exposes `{ result }`; a group need exposes an ordered array. */
|
|
19
|
+
export type NeedEntry = {
|
|
20
|
+
result: OutputProxy<any>;
|
|
21
|
+
} | GroupNeedEntry[];
|
|
22
|
+
/** The resolved `ctx.needs` map keyed by job name or group name. */
|
|
23
|
+
export type NeedsContext = Record<string, NeedEntry>;
|
|
24
|
+
/**
|
|
25
|
+
* Resolve declared needs against a frozen snapshot into the `ctx.needs` map.
|
|
26
|
+
*
|
|
27
|
+
* - A single static/named-job need resolves to `{ result: <proxy over jobs[name]> }`.
|
|
28
|
+
* - A `dynamicGroup(...)` need resolves to an ordered array of `{ name, result }`,
|
|
29
|
+
* one entry per group member in the snapshot's deterministic eval order.
|
|
30
|
+
*/
|
|
31
|
+
export declare function buildNeedsContext(snapshot: UpstreamSnapshot, declaredNeeds: ReadonlyArray<DynamicJobNeed>): NeedsContext;
|
|
32
|
+
//# sourceMappingURL=needs-context.d.ts.map
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import "./chunk-BTugEXQM.js";
|
|
2
|
+
import { createSnapshotOutputProxy } from "./outputs.js";
|
|
3
|
+
//#region src/needs-context.ts
|
|
4
|
+
function needKey(need) {
|
|
5
|
+
if (typeof need === "string") return {
|
|
6
|
+
kind: "job",
|
|
7
|
+
key: need
|
|
8
|
+
};
|
|
9
|
+
if ("group" in need) return {
|
|
10
|
+
kind: "group",
|
|
11
|
+
key: need.group
|
|
12
|
+
};
|
|
13
|
+
if ("name" in need) return {
|
|
14
|
+
kind: "job",
|
|
15
|
+
key: need.name
|
|
16
|
+
};
|
|
17
|
+
return {
|
|
18
|
+
kind: "job",
|
|
19
|
+
key: need.name
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Resolve declared needs against a frozen snapshot into the `ctx.needs` map.
|
|
24
|
+
*
|
|
25
|
+
* - A single static/named-job need resolves to `{ result: <proxy over jobs[name]> }`.
|
|
26
|
+
* - A `dynamicGroup(...)` need resolves to an ordered array of `{ name, result }`,
|
|
27
|
+
* one entry per group member in the snapshot's deterministic eval order.
|
|
28
|
+
*/
|
|
29
|
+
function buildNeedsContext(snapshot, declaredNeeds) {
|
|
30
|
+
const out = {};
|
|
31
|
+
for (const need of declaredNeeds) {
|
|
32
|
+
const { kind, key } = needKey(need);
|
|
33
|
+
if (kind === "group") out[key] = (snapshot.groups[key] ?? []).map((name) => ({
|
|
34
|
+
name,
|
|
35
|
+
result: createSnapshotOutputProxy(name, snapshot.jobs[name])
|
|
36
|
+
}));
|
|
37
|
+
else out[key] = { result: createSnapshotOutputProxy(key, snapshot.jobs[key]) };
|
|
38
|
+
}
|
|
39
|
+
return out;
|
|
40
|
+
}
|
|
41
|
+
//#endregion
|
|
42
|
+
export { buildNeedsContext };
|
|
43
|
+
|
|
44
|
+
//# sourceMappingURL=needs-context.js.map
|
package/dist/outputs.d.ts
CHANGED
|
@@ -61,6 +61,18 @@ export declare function createStepOutputProxy<T>(stepName: string): OutputProxy<
|
|
|
61
61
|
* @returns A Proxy that resolves property access at runtime
|
|
62
62
|
*/
|
|
63
63
|
export declare function createJobOutputProxy(jobName: string): OutputProxy<any>;
|
|
64
|
+
/**
|
|
65
|
+
* Output proxy bound to a specific outputs object (not the module-global map).
|
|
66
|
+
*
|
|
67
|
+
* Used to expose a frozen upstream-job snapshot as `ctx.needs.<job>.result` for
|
|
68
|
+
* result-aware dynamic generators. The snapshot is captured once at eval and
|
|
69
|
+
* replayed unchanged on re-eval, so the proxy reads a fixed `outputs` object
|
|
70
|
+
* rather than the live module-global job-outputs map.
|
|
71
|
+
*
|
|
72
|
+
* @param jobName - The upstream job whose outputs to proxy (used in error text)
|
|
73
|
+
* @param outputs - The frozen outputs object, or undefined if the job produced none
|
|
74
|
+
*/
|
|
75
|
+
export declare function createSnapshotOutputProxy(jobName: string, outputs: Record<string, unknown> | undefined): OutputProxy<any>;
|
|
64
76
|
/**
|
|
65
77
|
* Resolve step outputs by step reference (Step object or bare function).
|
|
66
78
|
* Used by ctx.outputsOf() implementation.
|
package/dist/outputs.js
CHANGED
|
@@ -140,6 +140,41 @@ function createJobOutputProxy(jobName) {
|
|
|
140
140
|
});
|
|
141
141
|
}
|
|
142
142
|
/**
|
|
143
|
+
* Output proxy bound to a specific outputs object (not the module-global map).
|
|
144
|
+
*
|
|
145
|
+
* Used to expose a frozen upstream-job snapshot as `ctx.needs.<job>.result` for
|
|
146
|
+
* result-aware dynamic generators. The snapshot is captured once at eval and
|
|
147
|
+
* replayed unchanged on re-eval, so the proxy reads a fixed `outputs` object
|
|
148
|
+
* rather than the live module-global job-outputs map.
|
|
149
|
+
*
|
|
150
|
+
* @param jobName - The upstream job whose outputs to proxy (used in error text)
|
|
151
|
+
* @param outputs - The frozen outputs object, or undefined if the job produced none
|
|
152
|
+
*/
|
|
153
|
+
function createSnapshotOutputProxy(jobName, outputs) {
|
|
154
|
+
return new Proxy({}, {
|
|
155
|
+
get(_target, prop, receiver) {
|
|
156
|
+
if (typeof prop === "symbol") return Reflect.get(_target, prop, receiver);
|
|
157
|
+
if (WELL_KNOWN_STRING_PROPS.has(prop)) return Reflect.get(_target, prop, receiver);
|
|
158
|
+
if (!outputs) throw new Error(`Upstream job '${jobName}' has no frozen outputs in the generator snapshot`);
|
|
159
|
+
return outputs[prop];
|
|
160
|
+
},
|
|
161
|
+
ownKeys() {
|
|
162
|
+
return outputs ? Reflect.ownKeys(outputs) : [];
|
|
163
|
+
},
|
|
164
|
+
has(_target, prop) {
|
|
165
|
+
return outputs ? prop in outputs : false;
|
|
166
|
+
},
|
|
167
|
+
getOwnPropertyDescriptor(_target, prop) {
|
|
168
|
+
if (!outputs) return void 0;
|
|
169
|
+
if (prop in outputs) return {
|
|
170
|
+
configurable: true,
|
|
171
|
+
enumerable: true,
|
|
172
|
+
value: outputs[prop]
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
143
178
|
* Resolve step outputs by step reference (Step object or bare function).
|
|
144
179
|
* Used by ctx.outputsOf() implementation.
|
|
145
180
|
*
|
|
@@ -175,6 +210,6 @@ function resolveJobOutputs(ref, outputsMap) {
|
|
|
175
210
|
return outputs;
|
|
176
211
|
}
|
|
177
212
|
//#endregion
|
|
178
|
-
export { createJobOutputProxy, createStepOutputProxy, getJobOutputsMap, getStepOutputsMap, getStepRefMap, resolveJobOutputs, resolveStepOutputs, setJobOutputsMap, setStepOutputsMap, setStepRefMap };
|
|
213
|
+
export { createJobOutputProxy, createSnapshotOutputProxy, createStepOutputProxy, getJobOutputsMap, getStepOutputsMap, getStepRefMap, resolveJobOutputs, resolveStepOutputs, setJobOutputsMap, setStepOutputsMap, setStepRefMap };
|
|
179
214
|
|
|
180
215
|
//# sourceMappingURL=outputs.js.map
|
package/dist/types.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { z } from 'zod';
|
|
2
2
|
import type { $ as Shell } from 'zx';
|
|
3
|
-
import type { ResourceRequest } from '@kici-dev/engine';
|
|
3
|
+
import type { ResourceRequest, RunsOnAllInput, OnUnreachableMode } from '@kici-dev/engine';
|
|
4
4
|
import type { StepContext, Logger } from './context.js';
|
|
5
5
|
import type { TriggerConfig } from './triggers/types.js';
|
|
6
6
|
import type { Rule } from './rules/types.js';
|
|
@@ -10,7 +10,7 @@ import type { KiciApi } from './api-types.js';
|
|
|
10
10
|
import type { DynamicGroupRef } from './dynamic-group.js';
|
|
11
11
|
import type { EventPayload } from './events/event-payloads.js';
|
|
12
12
|
import type { RequireApproval } from './approval.js';
|
|
13
|
-
export type { ResourceRequest, ResourceSpec } from '@kici-dev/engine';
|
|
13
|
+
export type { ResourceRequest, ResourceSpec, RunsOnAllInput, OnUnreachableMode, } from '@kici-dev/engine';
|
|
14
14
|
/** Source location captured at a step() call site. */
|
|
15
15
|
export interface SourceLocation {
|
|
16
16
|
readonly file: string;
|
|
@@ -108,13 +108,16 @@ export type Trigger = TriggerConfig;
|
|
|
108
108
|
* the re-evaluation must produce a job with the same name and the same steps.
|
|
109
109
|
*
|
|
110
110
|
* - `ctx.event` is deterministic — frozen from the original webhook payload.
|
|
111
|
+
* - `ctx.needs` is deterministic — a snapshot of upstream outputs frozen at first
|
|
112
|
+
* eval and replayed unchanged on re-eval, like `ctx.event`. Present only on
|
|
113
|
+
* result-aware generators created via `dynamicJob(group, { needs, generate })`.
|
|
111
114
|
* - `$`, `env`, and `kici` can return different results between eval and re-eval
|
|
112
115
|
* (different agent, different time, different infrastructure state).
|
|
113
116
|
*
|
|
114
|
-
* **Guidance:** derive job names and structure from `ctx.event`
|
|
115
|
-
* possible. If you use `kici.infrastructure.list()` or shell
|
|
116
|
-
* determine job names, be aware that changes between eval and re-eval
|
|
117
|
-
* cause a non-determinism warning (or failure if a job disappears).
|
|
117
|
+
* **Guidance:** derive job names and structure from `ctx.event` / `ctx.needs`
|
|
118
|
+
* data whenever possible. If you use `kici.infrastructure.list()` or shell
|
|
119
|
+
* commands to determine job names, be aware that changes between eval and re-eval
|
|
120
|
+
* will cause a non-determinism warning (or failure if a job disappears).
|
|
118
121
|
*/
|
|
119
122
|
export interface DynamicJobContext {
|
|
120
123
|
/** zx shell executor for running commands */
|
|
@@ -126,6 +129,12 @@ export interface DynamicJobContext {
|
|
|
126
129
|
};
|
|
127
130
|
/** Normalized event envelope that triggered this run. */
|
|
128
131
|
event?: EventPayload;
|
|
132
|
+
/**
|
|
133
|
+
* Frozen outputs of declared upstream needs (result-aware generators only).
|
|
134
|
+
* Single-job needs expose `ctx.needs.<job>.result.<field>`; group needs
|
|
135
|
+
* expose an ordered array of `{ name, result }`.
|
|
136
|
+
*/
|
|
137
|
+
needs?: import('./needs-context.js').NeedsContext;
|
|
129
138
|
};
|
|
130
139
|
/** Structured logger */
|
|
131
140
|
log: Logger;
|
|
@@ -167,16 +176,56 @@ export interface TaggedDynamicJobFn extends DynamicJobFn {
|
|
|
167
176
|
* Tag a DynamicJobFn with a group name for cross-domain needs.
|
|
168
177
|
* Static jobs can then depend on this group via `needs: [dynamicGroup('name')]`.
|
|
169
178
|
*
|
|
179
|
+
* Two forms:
|
|
180
|
+
* - **Function form** (event-only): `dynamicJob('shards', async ({ ctx }) => [...])`.
|
|
181
|
+
* Dispatched at webhook time; deterministic from `ctx.event` alone.
|
|
182
|
+
* - **Options form** (result-aware): `dynamicJob('reports', { needs, generate })`.
|
|
183
|
+
* Deferred until every job/group in `needs` completes, then `generate` is
|
|
184
|
+
* evaluated with the upstreams' frozen outputs available as `ctx.needs`.
|
|
185
|
+
*
|
|
170
186
|
* @param groupName - The group name (must match what static jobs reference)
|
|
171
|
-
* @param
|
|
187
|
+
* @param fnOrConfig - The generator function, or a result-aware `{ needs, generate }` config
|
|
172
188
|
*/
|
|
173
|
-
export declare function dynamicJob(groupName: string,
|
|
189
|
+
export declare function dynamicJob(groupName: string, fnOrConfig: DynamicJobFn | ResultAwareDynamicJobConfig): TaggedDynamicJobFn;
|
|
174
190
|
/**
|
|
175
191
|
* Get the group name from a DynamicJobFn, if it was tagged with dynamicJob().
|
|
176
192
|
* Returns undefined for untagged functions.
|
|
177
193
|
*/
|
|
178
194
|
export declare function getDynamicJobGroup(fn: DynamicJobFn): string | undefined;
|
|
179
195
|
export { DYNAMIC_JOB_GROUP_TAG };
|
|
196
|
+
declare const DYNAMIC_JOB_NEEDS_TAG: unique symbol;
|
|
197
|
+
/**
|
|
198
|
+
* One declared upstream edge for a result-aware generator.
|
|
199
|
+
* Same shape as the elements of {@link JobOptions.needs}.
|
|
200
|
+
*/
|
|
201
|
+
export type DynamicJobNeed = Job | string | DynamicGroupRef | {
|
|
202
|
+
name: string;
|
|
203
|
+
ifFailed?: 'skip' | 'run';
|
|
204
|
+
} | {
|
|
205
|
+
group: string;
|
|
206
|
+
ifFailed?: 'skip' | 'run';
|
|
207
|
+
};
|
|
208
|
+
/**
|
|
209
|
+
* Options-object form of {@link dynamicJob}: a result-aware generator that is
|
|
210
|
+
* deferred until its declared `needs` complete, then evaluated with their frozen
|
|
211
|
+
* outputs available as `ctx.needs`.
|
|
212
|
+
*/
|
|
213
|
+
export interface ResultAwareDynamicJobConfig {
|
|
214
|
+
/** Upstream jobs/groups whose outputs the generator reads via `ctx.needs`. */
|
|
215
|
+
needs: ReadonlyArray<DynamicJobNeed>;
|
|
216
|
+
/** The generator. Receives `ctx.needs` resolved from the frozen upstream snapshot. */
|
|
217
|
+
generate: DynamicJobFn;
|
|
218
|
+
}
|
|
219
|
+
/** A {@link DynamicJobFn} tagged with declared needs (result-aware). */
|
|
220
|
+
export interface ResultAwareDynamicJobFn extends TaggedDynamicJobFn {
|
|
221
|
+
readonly [DYNAMIC_JOB_NEEDS_TAG]: ReadonlyArray<DynamicJobNeed>;
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Read the declared needs from a result-aware generator.
|
|
225
|
+
* Returns undefined for event-only generators (the function form of dynamicJob).
|
|
226
|
+
*/
|
|
227
|
+
export declare function getDynamicJobNeeds(fn: DynamicJobFn): ReadonlyArray<DynamicJobNeed> | undefined;
|
|
228
|
+
export { DYNAMIC_JOB_NEEDS_TAG };
|
|
180
229
|
/**
|
|
181
230
|
* Container configuration for job execution.
|
|
182
231
|
* When set, all steps run inside the specified container.
|
|
@@ -254,8 +303,8 @@ export type InitConfig = InitItem | InitItem[] | 'auto' | false;
|
|
|
254
303
|
* the agent's self-reported platform facts.
|
|
255
304
|
*/
|
|
256
305
|
export interface RunsOnSelector {
|
|
257
|
-
labels: string | string[];
|
|
258
|
-
exclude?: string | string[];
|
|
306
|
+
labels: string | RegExp | (string | RegExp)[];
|
|
307
|
+
exclude?: string | RegExp | (string | RegExp)[];
|
|
259
308
|
}
|
|
260
309
|
/**
|
|
261
310
|
* Polymorphic runsOn type: string shorthand, array shorthand, or full selector object.
|
|
@@ -263,18 +312,33 @@ export interface RunsOnSelector {
|
|
|
263
312
|
* - `['kici:os:linux', 'gpu']` — multi-label shorthand (all must match)
|
|
264
313
|
* - `{ labels: ['kici:os:linux'], exclude: ['kici:host:box-01'] }` — full selector
|
|
265
314
|
*
|
|
315
|
+
* A plain string is matched exactly; a string containing glob metachars (`*?[]{}`) is a
|
|
316
|
+
* glob; a `RegExp` is a regex. Patterns are validated for ReDoS at compile time.
|
|
317
|
+
*
|
|
266
318
|
* **Targeting `kici:` labels:** `runsOn` may target any agent label, including the
|
|
267
319
|
* `kici:`-namespaced auto-labels (`kici:os:`, `kici:arch:`, `kici:host:`, `kici:agent:`,
|
|
268
320
|
* `kici:scaler:`, `kici:role:`). Targeting is a requirement on candidate agents, never a
|
|
269
321
|
* grant. `kici:scaler:` / `kici:agent:` are deployment-specific, so prefer custom labels
|
|
270
322
|
* for portable pool targeting. Users still cannot *set* `kici:` labels on agents.
|
|
271
323
|
*/
|
|
272
|
-
export type RunsOn = string | string[] | RunsOnSelector;
|
|
324
|
+
export type RunsOn = string | RegExp | (string | RegExp)[] | RunsOnSelector;
|
|
273
325
|
/** Job definition returned by job() factory */
|
|
274
326
|
export interface Job {
|
|
275
327
|
readonly _tag: 'Job';
|
|
276
328
|
readonly name: string;
|
|
277
|
-
|
|
329
|
+
/** Single-agent targeting. Mutually exclusive with `runsOnAll`. */
|
|
330
|
+
readonly runsOn?: RunsOn;
|
|
331
|
+
/**
|
|
332
|
+
* Host fan-out: run one pinned execution per roster host matching the predicate.
|
|
333
|
+
* Mutually exclusive with `runsOn`.
|
|
334
|
+
*/
|
|
335
|
+
readonly runsOnAll?: RunsOnAllInput;
|
|
336
|
+
/** Failure policy for unreachable durable hosts when using `runsOnAll`. */
|
|
337
|
+
readonly onUnreachable?: OnUnreachableMode;
|
|
338
|
+
/** Fan-out concurrency width (sliding window; `1` = serial). Applies to matrix and `runsOnAll`. */
|
|
339
|
+
readonly maxParallel?: number;
|
|
340
|
+
/** Halt the fan-out on first child failure, skipping the remainder. Default `false`. */
|
|
341
|
+
readonly failFast?: boolean;
|
|
278
342
|
readonly steps: readonly StepInput[];
|
|
279
343
|
readonly needs?: ReadonlyArray<Job | string | DynamicGroupRef | {
|
|
280
344
|
name: string;
|
|
@@ -355,7 +419,36 @@ export interface Job {
|
|
|
355
419
|
}
|
|
356
420
|
/** Options for job() factory */
|
|
357
421
|
export interface JobOptions {
|
|
358
|
-
|
|
422
|
+
/** Single-agent targeting. Mutually exclusive with `runsOnAll`. */
|
|
423
|
+
runsOn?: RunsOn;
|
|
424
|
+
/**
|
|
425
|
+
* Host fan-out: run one pinned execution per roster host matching the predicate.
|
|
426
|
+
* The author writes a label string (`'role:web'`), an array with `!`-prefixed
|
|
427
|
+
* excludes (`['kici:os:linux', 'role:db', '!kici:host:db-01']`), or the
|
|
428
|
+
* structured `{ include: [{ all: [...] }], exclude?: [...] }` form.
|
|
429
|
+
* Mutually exclusive with `runsOn`.
|
|
430
|
+
*/
|
|
431
|
+
runsOnAll?: RunsOnAllInput;
|
|
432
|
+
/**
|
|
433
|
+
* Failure policy for unreachable durable hosts when using `runsOnAll`:
|
|
434
|
+
* `'skip'` omits them, `'fail'` fails the run, `'hold'` (default) queues a
|
|
435
|
+
* pinned child and waits. Only meaningful alongside `runsOnAll`.
|
|
436
|
+
*/
|
|
437
|
+
onUnreachable?: OnUnreachableMode;
|
|
438
|
+
/**
|
|
439
|
+
* Fan-out concurrency width: the maximum number of fan-out children (matrix
|
|
440
|
+
* combinations or `runsOnAll` hosts) that run at once. A sliding window —
|
|
441
|
+
* each child that reaches a terminal state releases the next held sibling.
|
|
442
|
+
* `1` = strictly serial (rolling). Applies to both matrix and `runsOnAll`
|
|
443
|
+
* fan-out; ignored on a non-fan-out job. Must be `>= 1`.
|
|
444
|
+
*/
|
|
445
|
+
maxParallel?: number;
|
|
446
|
+
/**
|
|
447
|
+
* Halt the fan-out on the first child failure: stop releasing new children
|
|
448
|
+
* and skip the ones still held. Default `false` (every child runs regardless
|
|
449
|
+
* of sibling outcomes). Applies to both matrix and `runsOnAll` fan-out.
|
|
450
|
+
*/
|
|
451
|
+
failFast?: boolean;
|
|
359
452
|
/**
|
|
360
453
|
* Steps to execute in this job. Accepts Step objects and bare async functions.
|
|
361
454
|
* Mutually exclusive with `run`.
|
package/dist/types.js
CHANGED
|
@@ -11,15 +11,27 @@ const DYNAMIC_JOB_GROUP_TAG = Symbol.for("kici:dynamicJobGroup");
|
|
|
11
11
|
* Tag a DynamicJobFn with a group name for cross-domain needs.
|
|
12
12
|
* Static jobs can then depend on this group via `needs: [dynamicGroup('name')]`.
|
|
13
13
|
*
|
|
14
|
+
* Two forms:
|
|
15
|
+
* - **Function form** (event-only): `dynamicJob('shards', async ({ ctx }) => [...])`.
|
|
16
|
+
* Dispatched at webhook time; deterministic from `ctx.event` alone.
|
|
17
|
+
* - **Options form** (result-aware): `dynamicJob('reports', { needs, generate })`.
|
|
18
|
+
* Deferred until every job/group in `needs` completes, then `generate` is
|
|
19
|
+
* evaluated with the upstreams' frozen outputs available as `ctx.needs`.
|
|
20
|
+
*
|
|
14
21
|
* @param groupName - The group name (must match what static jobs reference)
|
|
15
|
-
* @param
|
|
22
|
+
* @param fnOrConfig - The generator function, or a result-aware `{ needs, generate }` config
|
|
16
23
|
*/
|
|
17
|
-
function dynamicJob(groupName,
|
|
18
|
-
const
|
|
24
|
+
function dynamicJob(groupName, fnOrConfig) {
|
|
25
|
+
const isConfig = typeof fnOrConfig !== "function";
|
|
26
|
+
const tagged = isConfig ? fnOrConfig.generate : fnOrConfig;
|
|
19
27
|
Object.defineProperty(tagged, DYNAMIC_JOB_GROUP_TAG, {
|
|
20
28
|
value: groupName,
|
|
21
29
|
enumerable: false
|
|
22
30
|
});
|
|
31
|
+
if (isConfig) Object.defineProperty(tagged, DYNAMIC_JOB_NEEDS_TAG, {
|
|
32
|
+
value: fnOrConfig.needs,
|
|
33
|
+
enumerable: false
|
|
34
|
+
});
|
|
23
35
|
return tagged;
|
|
24
36
|
}
|
|
25
37
|
/**
|
|
@@ -29,7 +41,15 @@ function dynamicJob(groupName, fn) {
|
|
|
29
41
|
function getDynamicJobGroup(fn) {
|
|
30
42
|
return fn[DYNAMIC_JOB_GROUP_TAG];
|
|
31
43
|
}
|
|
44
|
+
const DYNAMIC_JOB_NEEDS_TAG = Symbol.for("kici:dynamicJobNeeds");
|
|
45
|
+
/**
|
|
46
|
+
* Read the declared needs from a result-aware generator.
|
|
47
|
+
* Returns undefined for event-only generators (the function form of dynamicJob).
|
|
48
|
+
*/
|
|
49
|
+
function getDynamicJobNeeds(fn) {
|
|
50
|
+
return fn[DYNAMIC_JOB_NEEDS_TAG];
|
|
51
|
+
}
|
|
32
52
|
//#endregion
|
|
33
|
-
export { DYNAMIC_JOB_GROUP_TAG, dynamicJob, getDynamicJobGroup, isDynamicJobFn };
|
|
53
|
+
export { DYNAMIC_JOB_GROUP_TAG, DYNAMIC_JOB_NEEDS_TAG, dynamicJob, getDynamicJobGroup, getDynamicJobNeeds, isDynamicJobFn };
|
|
34
54
|
|
|
35
55
|
//# sourceMappingURL=types.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kici-dev/sdk",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.19",
|
|
4
4
|
"description": "TypeScript SDK for defining KiCI workflows. Import into `.kici/workflows/*.ts` to declare workflows, jobs, steps, triggers, rules, and matrix configurations.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ci",
|
|
@@ -47,10 +47,10 @@
|
|
|
47
47
|
},
|
|
48
48
|
"dependencies": {
|
|
49
49
|
"micromatch": "^4.0.8",
|
|
50
|
-
"zod": "^4.3
|
|
50
|
+
"zod": "^4.4.3",
|
|
51
51
|
"zx": "^8.8.5",
|
|
52
|
-
"@kici-dev/core": "0.1.
|
|
53
|
-
"@kici-dev/engine": "0.1.
|
|
52
|
+
"@kici-dev/core": "0.1.19",
|
|
53
|
+
"@kici-dev/engine": "0.1.19"
|
|
54
54
|
},
|
|
55
55
|
"devDependencies": {
|
|
56
56
|
"@types/micromatch": "^4.0.10"
|