@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.
- package/dist/api-types.d.ts +28 -0
- package/dist/api-types.js +3 -1
- package/dist/approval.d.ts +3 -8
- package/dist/approval.js +9 -0
- package/dist/artifacts-types.d.ts +45 -0
- package/dist/artifacts-types.js +3 -0
- package/dist/context.d.ts +73 -23
- package/dist/events/define-event.d.ts +11 -3
- package/dist/events/define-event.js +14 -4
- package/dist/events/emit-typing.test-d.d.ts +2 -0
- package/dist/events/emit-typing.test-d.js +36 -0
- package/dist/events/event-payloads.d.ts +4 -0
- package/dist/events/index.d.ts +1 -1
- package/dist/events/index.js +2 -2
- package/dist/fleet/agent-version-converge.d.ts +23 -0
- package/dist/fleet/agent-version-converge.js +58 -0
- package/dist/idempotent.d.ts +2 -2
- package/dist/idempotent.js +2 -2
- package/dist/index.d.ts +9 -3
- package/dist/index.js +6 -2
- package/dist/job-outputs.test-d.d.ts +2 -0
- package/dist/job-outputs.test-d.js +164 -0
- package/dist/job.d.ts +71 -9
- package/dist/job.js +19 -5
- package/dist/matrix/expand.d.ts +1 -1
- package/dist/matrix/expand.js +2 -2
- package/dist/needs-context.d.ts +13 -6
- package/dist/outputs.d.ts +19 -4
- package/dist/outputs.js +21 -7
- package/dist/parallel.d.ts +1 -1
- package/dist/parallel.js +1 -1
- package/dist/provenance-types.d.ts +3 -3
- package/dist/rules/context.d.ts +33 -0
- package/dist/rules/context.js +51 -0
- package/dist/rules/evaluator.d.ts +10 -0
- package/dist/rules/evaluator.js +9 -1
- package/dist/rules/index.d.ts +2 -0
- package/dist/rules/index.js +2 -1
- package/dist/rules/types.d.ts +11 -1
- package/dist/secrets.d.ts +1 -1
- package/dist/step.d.ts +6 -6
- package/dist/step.js +6 -3
- package/dist/testing/index.d.ts +2 -0
- package/dist/testing/index.js +3 -0
- package/dist/testing/step-context.d.ts +56 -0
- package/dist/testing/step-context.js +259 -0
- package/dist/triggers/index.d.ts +2 -1
- package/dist/triggers/index.js +2 -1
- package/dist/triggers/types.d.ts +23 -1
- package/dist/triggers/workflows-failed-batch.d.ts +20 -0
- package/dist/triggers/workflows-failed-batch.js +25 -0
- package/dist/types.d.ts +163 -30
- package/dist/validation/dag.js +11 -3
- package/dist/workflow.js +3 -3
- package/package.json +10 -5
- package/sbom.spdx.json +192 -192
package/dist/types.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ import type { $ as Shell } from 'zx';
|
|
|
3
3
|
import type { RetryBackoff } from '@kici-dev/core';
|
|
4
4
|
import type { ResourceRequest, RunsOnAllInput, OnUnreachableMode, NeedsWhen, ExecutionJobStatus } from '@kici-dev/engine';
|
|
5
5
|
import type { StepContext, Logger } from './context.js';
|
|
6
|
+
import type { SingleNeedEntry, NeedsContext } from './needs-context.js';
|
|
6
7
|
import type { TriggerConfig } from './triggers/types.js';
|
|
7
8
|
import type { Rule } from './rules/types.js';
|
|
8
9
|
import type { Matrix, MatrixInclude, MatrixExclude } from './matrix/types.js';
|
|
@@ -33,6 +34,78 @@ export interface SourceLocation {
|
|
|
33
34
|
export type OutputProxy<T> = {
|
|
34
35
|
readonly [K in keyof T]: T[K];
|
|
35
36
|
};
|
|
37
|
+
/** Collapse a union of object types into their intersection (`{a} | {b}` -> `{a} & {b}`). */
|
|
38
|
+
type UnionToIntersection<U> = (U extends unknown ? (k: U) => void : never) extends (k: infer I) => void ? I : never;
|
|
39
|
+
/**
|
|
40
|
+
* A single step's contribution to its job's merged output map. A named,
|
|
41
|
+
* non-void step contributes `{ [name]: result }`; an id-less step (empty name)
|
|
42
|
+
* or a void step contributes nothing; a bare function / parallel group in the
|
|
43
|
+
* steps array contributes nothing. Used by {@link InferJobOutputsFromSteps}.
|
|
44
|
+
*/
|
|
45
|
+
type StepOutputEntry<TStep> = TStep extends Step<infer TResult, infer TName> ? TName extends '' ? object : [TResult] extends [void] ? object : {
|
|
46
|
+
readonly [K in TName]: TResult;
|
|
47
|
+
} : object;
|
|
48
|
+
/**
|
|
49
|
+
* Merge every named, non-void step's outputs into the job's nested output map,
|
|
50
|
+
* keyed by step name — reproducing the runtime shape `jobRef.result.<step>.<field>`
|
|
51
|
+
* for a multi-step job. When no step contributes a name (all id-less or void),
|
|
52
|
+
* falls back to the loose `Record<string, unknown>` so untyped code keeps
|
|
53
|
+
* compiling. The `run:` shorthand does NOT go through this helper: it infers a
|
|
54
|
+
* flat shape from the run function's return type at the `job()` overload.
|
|
55
|
+
*/
|
|
56
|
+
export type InferJobOutputsFromSteps<TSteps extends readonly unknown[]> = UnionToIntersection<{
|
|
57
|
+
[I in keyof TSteps]: StepOutputEntry<TSteps[I]>;
|
|
58
|
+
}[number]> extends infer M ? keyof M extends never ? Record<string, unknown> : {
|
|
59
|
+
readonly [K in keyof M]: M[K];
|
|
60
|
+
} : never;
|
|
61
|
+
/**
|
|
62
|
+
* One `needs` tuple element's contribution to the typed `ctx.needs` map. A job
|
|
63
|
+
* reference with a literal name, or a `'name'` string / `{ name }` object,
|
|
64
|
+
* contributes `{ [name]: SingleNeedEntry<T> }` (outputs typed for a job ref,
|
|
65
|
+
* loose for a string/name); a name-less job, a group ref, or a `{ group }`
|
|
66
|
+
* entry contributes nothing typed (they fall back to the loose map).
|
|
67
|
+
*/
|
|
68
|
+
type NeedFromTupleEntry<E> = E extends Job<infer TOut, infer TName> ? string extends TName ? object : TName extends '' ? object : {
|
|
69
|
+
readonly [K in TName]: SingleNeedEntry<TOut>;
|
|
70
|
+
} : E extends string ? string extends E ? object : {
|
|
71
|
+
readonly [K in E]: SingleNeedEntry<Record<string, unknown>>;
|
|
72
|
+
} : E extends {
|
|
73
|
+
name: infer N;
|
|
74
|
+
} ? N extends string ? string extends N ? object : {
|
|
75
|
+
readonly [K in N]: SingleNeedEntry<Record<string, unknown>>;
|
|
76
|
+
} : object : object;
|
|
77
|
+
/**
|
|
78
|
+
* True when at least one `needs` tuple element cannot be keyed (a group ref, a
|
|
79
|
+
* `{ group }` entry, or a name-less job) — i.e. its {@link NeedFromTupleEntry}
|
|
80
|
+
* contributes no key. Such an element would be silently dropped from a strict
|
|
81
|
+
* closed map, so its presence forces the loose fallback.
|
|
82
|
+
*/
|
|
83
|
+
type HasUnkeyableNeed<TNeeds extends readonly unknown[]> = true extends {
|
|
84
|
+
[I in keyof TNeeds]: keyof NeedFromTupleEntry<TNeeds[I]> extends never ? true : false;
|
|
85
|
+
}[number] ? true : false;
|
|
86
|
+
/**
|
|
87
|
+
* Derive the typed `ctx.needs` map from a job's `needs` tuple. The strict, closed
|
|
88
|
+
* map (keyed by upstream name — job references carry their inferred outputs,
|
|
89
|
+
* string / `{ name }` entries key loose) is produced ONLY when every entry is
|
|
90
|
+
* keyable, so reading an undeclared need is a compile error. If any entry cannot
|
|
91
|
+
* be keyed (a group reference, a `{ group }` entry, or a name-less job), the whole
|
|
92
|
+
* map falls back to the loose {@link NeedsContext} — the group's key stays
|
|
93
|
+
* accessible and no valid read regresses to a type error.
|
|
94
|
+
*/
|
|
95
|
+
export type NeedsFromTuple<TNeeds extends readonly unknown[]> = HasUnkeyableNeed<TNeeds> extends true ? NeedsContext : UnionToIntersection<{
|
|
96
|
+
[I in keyof TNeeds]: NeedFromTupleEntry<TNeeds[I]>;
|
|
97
|
+
}[number]> extends infer M ? keyof M extends never ? NeedsContext : {
|
|
98
|
+
readonly [K in keyof M]: M[K];
|
|
99
|
+
} : never;
|
|
100
|
+
/**
|
|
101
|
+
* The step/run context with its `needs` narrowed to the typed map derived from
|
|
102
|
+
* the enclosing job's `needs` tuple. Used as the contextual type of the `run:`
|
|
103
|
+
* shorthand so `ctx.needs.<job>.result.<field>` is checked. `needs` is required
|
|
104
|
+
* here (a job with declared needs always has them at runtime).
|
|
105
|
+
*/
|
|
106
|
+
export type StepContextWithNeeds<TNeeds extends readonly unknown[]> = Omit<StepContext, 'needs'> & {
|
|
107
|
+
needs: NeedsFromTuple<TNeeds>;
|
|
108
|
+
};
|
|
36
109
|
/** Output schema type - record of Zod types */
|
|
37
110
|
export type OutputSchema = Record<string, z.ZodTypeAny>;
|
|
38
111
|
/** Infer the output type from an output schema */
|
|
@@ -43,10 +116,15 @@ export type InferOutputs<T extends OutputSchema> = z.infer<z.ZodObject<T>>;
|
|
|
43
116
|
* TResult is the inferred return type of the run function (defaults to void for backward compat).
|
|
44
117
|
* The optional `outputs` field holds a Zod schema for runtime validation but does NOT drive the generic.
|
|
45
118
|
*/
|
|
46
|
-
export interface Step<TResult = void> {
|
|
119
|
+
export interface Step<TResult = void, TName extends string = string> {
|
|
47
120
|
readonly _tag: 'Step';
|
|
48
|
-
/**
|
|
49
|
-
|
|
121
|
+
/**
|
|
122
|
+
* Step name, carried as a literal type. Empty string (`''`) for id-less steps
|
|
123
|
+
* (the compiler assigns counter IDs at lock generation). The literal name is
|
|
124
|
+
* what lets a named step contribute a typed key to its job's merged output map
|
|
125
|
+
* (see {@link InferJobOutputsFromSteps}).
|
|
126
|
+
*/
|
|
127
|
+
readonly name: TName;
|
|
50
128
|
/** Optional Zod schema for runtime output validation. */
|
|
51
129
|
readonly outputs?: OutputSchema;
|
|
52
130
|
readonly run: (ctx: StepContext, drift?: any) => Promise<TResult>;
|
|
@@ -324,6 +402,29 @@ export interface ContainerConfig {
|
|
|
324
402
|
/** Additional environment variables for the container */
|
|
325
403
|
env?: Record<string, string>;
|
|
326
404
|
}
|
|
405
|
+
/**
|
|
406
|
+
* Per-job sandbox escape hatch for container-sandbox jobs (a job with a
|
|
407
|
+
* `container:` image). Requests are granted only within the operator's
|
|
408
|
+
* allow-list (`sandboxAllowedCapabilities` / `sandboxAllowHostNetwork`); a
|
|
409
|
+
* request for anything not allow-listed FAILS the run at dispatch with a reason
|
|
410
|
+
* naming the offending capability or knob — never a silent downgrade.
|
|
411
|
+
*/
|
|
412
|
+
export interface SandboxOptions {
|
|
413
|
+
/**
|
|
414
|
+
* Extra Linux capabilities to add back over the hardened `CapDrop:['ALL']`
|
|
415
|
+
* baseline (e.g. `['NET_ADMIN']`). Each requested capability must be
|
|
416
|
+
* allow-listed by the operator via `sandboxAllowedCapabilities`. Unknown
|
|
417
|
+
* capability names are rejected at author time.
|
|
418
|
+
*/
|
|
419
|
+
capabilities?: string[];
|
|
420
|
+
/**
|
|
421
|
+
* Container network posture. `'host'` shares the host network namespace and
|
|
422
|
+
* is the escalation — it requires the operator to enable
|
|
423
|
+
* `sandboxAllowHostNetwork`. `'none'` (loopback-only) and `'default'` (bridge)
|
|
424
|
+
* are always allowed (they do not escalate).
|
|
425
|
+
*/
|
|
426
|
+
network?: 'default' | 'none' | 'host';
|
|
427
|
+
}
|
|
327
428
|
/**
|
|
328
429
|
* Generic per-job initialization config. Runs a hand-written command after the
|
|
329
430
|
* repo is cloned and before the job's steps execute, so a repo-declared
|
|
@@ -424,10 +525,25 @@ export type RunsOnPick = 'deterministic' | 'any';
|
|
|
424
525
|
* for portable pool targeting. Users still cannot *set* `kici:` labels on agents.
|
|
425
526
|
*/
|
|
426
527
|
export type RunsOn = string | RegExp | (string | RegExp)[] | RunsOnSelector;
|
|
427
|
-
/**
|
|
428
|
-
|
|
528
|
+
/**
|
|
529
|
+
* Job definition returned by job() factory.
|
|
530
|
+
*
|
|
531
|
+
* `TOutputs` is the job's inferred output shape, threaded onto `result` so
|
|
532
|
+
* cross-job reads (`jobRef.result.<step>.<field>`) are type-checked. It is
|
|
533
|
+
* inferred by {@link InferJobOutputsFromSteps} for a `steps:` job (nested by
|
|
534
|
+
* step name) or from the run function's return type for a `run:` shorthand job
|
|
535
|
+
* (flat), with an explicit override available (`job<T>(...)`). Defaults to the
|
|
536
|
+
* loose `Record<string, unknown>` so a bare `Job` and untyped code keep
|
|
537
|
+
* compiling.
|
|
538
|
+
*
|
|
539
|
+
* `TName` is the job's name carried as a literal (from the `job('name', …)`
|
|
540
|
+
* argument), which lets a typed `needs: [jobRef]` key the reference under its
|
|
541
|
+
* name in `ctx.needs`. Name-less jobs (auto-generated id) keep the loose
|
|
542
|
+
* `string` default.
|
|
543
|
+
*/
|
|
544
|
+
export interface Job<TOutputs = Record<string, unknown>, TName extends string = string> {
|
|
429
545
|
readonly _tag: 'Job';
|
|
430
|
-
readonly name:
|
|
546
|
+
readonly name: TName;
|
|
431
547
|
/** Single-agent targeting. Mutually exclusive with `runsOnAll`. */
|
|
432
548
|
readonly runsOn?: RunsOn;
|
|
433
549
|
/**
|
|
@@ -471,18 +587,20 @@ export interface Job {
|
|
|
471
587
|
readonly checkout?: boolean;
|
|
472
588
|
/** Docker image for job execution. All steps run inside the container. */
|
|
473
589
|
readonly container?: string | ContainerConfig;
|
|
474
|
-
/**
|
|
475
|
-
readonly
|
|
590
|
+
/** Per-job sandbox escape hatch (container jobs only); granted within the operator allow-list. */
|
|
591
|
+
readonly sandbox?: SandboxOptions;
|
|
592
|
+
/** Bound context for this job. String for static, or a function of the normalized event envelope for dynamic (resolved at orchestrator two-phase eval). */
|
|
593
|
+
readonly context?: string | ((event: EventPayload) => string | Promise<string>);
|
|
476
594
|
/**
|
|
477
|
-
*
|
|
478
|
-
* earlier on name collisions). Mutually exclusive with `
|
|
595
|
+
* Bound contexts for this job, in merge order (later entries override
|
|
596
|
+
* earlier on name collisions). Mutually exclusive with `context`. Each entry
|
|
479
597
|
* is a static name or a function of the event (dynamic, resolved per element at
|
|
480
598
|
* two-phase eval).
|
|
481
599
|
*/
|
|
482
|
-
readonly
|
|
600
|
+
readonly contexts?: readonly (string | ((event: EventPayload) => string | Promise<string>))[];
|
|
483
601
|
/** Environment variables. Static object or a function of the normalized event envelope (resolved at orchestrator two-phase eval). */
|
|
484
602
|
readonly env?: Record<string, string> | ((event: EventPayload) => Record<string, string> | Promise<Record<string, string>>);
|
|
485
|
-
/** Concurrency group name. Defaults to the first bound
|
|
603
|
+
/** Concurrency group name. Defaults to the first bound context's name if not set. String or a function of the normalized event envelope. */
|
|
486
604
|
readonly concurrencyGroup?: string | ((event: EventPayload) => string | Promise<string>);
|
|
487
605
|
/** Runs on cancellation. */
|
|
488
606
|
readonly onCancel?: HookInput;
|
|
@@ -530,9 +648,18 @@ export interface Job {
|
|
|
530
648
|
* Type-safe proxy for accessing this job's outputs.
|
|
531
649
|
* For multi-step jobs: jobRef.result.stepName.field
|
|
532
650
|
* For single-step (run shorthand) jobs: jobRef.result.field
|
|
533
|
-
* At runtime, resolves against the shared job outputs map populated by the
|
|
534
|
-
|
|
535
|
-
|
|
651
|
+
* At runtime, resolves against the shared job outputs map populated by the
|
|
652
|
+
* workflow runner.
|
|
653
|
+
*
|
|
654
|
+
* The `[TOutputs] extends [void]` guard mirrors `Step.result` so a void
|
|
655
|
+
* run-shorthand job resolves `result` to `never` — which keeps `Job<void>`
|
|
656
|
+
* assignable to `JobOrFactory` (`never` is assignable to
|
|
657
|
+
* `OutputProxy<Record<string, unknown>>`). The tuple wrap is deliberate and
|
|
658
|
+
* non-distributive: it must not distribute over a union output map. Do not
|
|
659
|
+
* "align" this with `Step.result`'s naked form — that would reintroduce
|
|
660
|
+
* distribution over unions.
|
|
661
|
+
*/
|
|
662
|
+
readonly result: [TOutputs] extends [void] ? never : OutputProxy<TOutputs>;
|
|
536
663
|
}
|
|
537
664
|
/** Options for job() factory */
|
|
538
665
|
export interface JobOptions {
|
|
@@ -619,18 +746,24 @@ export interface JobOptions {
|
|
|
619
746
|
* When set, all steps run inside the container.
|
|
620
747
|
*/
|
|
621
748
|
container?: string | ContainerConfig;
|
|
622
|
-
/** Deployment environment for this job. String for static, or a function of the normalized event envelope for dynamic (resolved at orchestrator two-phase eval). */
|
|
623
|
-
environment?: string | ((event: EventPayload) => string | Promise<string>);
|
|
624
749
|
/**
|
|
625
|
-
*
|
|
626
|
-
*
|
|
750
|
+
* Per-job sandbox escape hatch (container jobs only). Request extra Linux
|
|
751
|
+
* capabilities / host networking; granted only within the operator's
|
|
752
|
+
* `org_settings` allow-list, else the run fails loudly at dispatch.
|
|
753
|
+
*/
|
|
754
|
+
sandbox?: SandboxOptions;
|
|
755
|
+
/** Bound context for this job. String for static, or a function of the normalized event envelope for dynamic (resolved at orchestrator two-phase eval). */
|
|
756
|
+
context?: string | ((event: EventPayload) => string | Promise<string>);
|
|
757
|
+
/**
|
|
758
|
+
* Bound contexts for this job, in merge order (later entries override
|
|
759
|
+
* earlier on name collisions). Mutually exclusive with `context`. Each entry
|
|
627
760
|
* is a static name or a function of the event (dynamic, resolved per element at
|
|
628
761
|
* two-phase eval).
|
|
629
762
|
*/
|
|
630
|
-
|
|
763
|
+
contexts?: (string | ((event: EventPayload) => string | Promise<string>))[];
|
|
631
764
|
/** Environment variables. Static object or a function of the normalized event envelope (resolved at orchestrator two-phase eval). */
|
|
632
765
|
env?: Record<string, string> | ((event: EventPayload) => Record<string, string> | Promise<Record<string, string>>);
|
|
633
|
-
/** Concurrency group name. Defaults to the first bound
|
|
766
|
+
/** Concurrency group name. Defaults to the first bound context's name if not set. String or a function of the normalized event envelope. */
|
|
634
767
|
concurrencyGroup?: string | ((event: EventPayload) => string | Promise<string>);
|
|
635
768
|
/** Runs on cancellation. */
|
|
636
769
|
onCancel?: HookInput;
|
|
@@ -679,8 +812,8 @@ export interface JobOptions {
|
|
|
679
812
|
* Private npm registry declaration. Tells the agent to authenticate against
|
|
680
813
|
* a private package registry before running `npm install`.
|
|
681
814
|
*
|
|
682
|
-
* `tokenSecret` uses qualified `<
|
|
683
|
-
* orchestrator resolves the secret from the named
|
|
815
|
+
* `tokenSecret` uses qualified `<context>:<secret-name>` syntax — the
|
|
816
|
+
* orchestrator resolves the secret from the named context's scoped secret
|
|
684
817
|
* store at dispatch time. Example: `tokenSecret: 'production:NPM_TOKEN'`.
|
|
685
818
|
*/
|
|
686
819
|
export interface Registry {
|
|
@@ -692,8 +825,8 @@ export interface Registry {
|
|
|
692
825
|
*/
|
|
693
826
|
readonly scope?: string;
|
|
694
827
|
/**
|
|
695
|
-
* Qualified secret reference of the form `<
|
|
696
|
-
* The orchestrator resolves it at dispatch via `secretResolver.resolveForJob(orgId,
|
|
828
|
+
* Qualified secret reference of the form `<context>:<secret-name>`.
|
|
829
|
+
* The orchestrator resolves it at dispatch via `secretResolver.resolveForJob(orgId, context)`.
|
|
697
830
|
*/
|
|
698
831
|
readonly tokenSecret: string;
|
|
699
832
|
/** Whether to require auth on every request (rendered as `always-auth=true` in `.npmrc`). Defaults to `true`. */
|
|
@@ -721,14 +854,14 @@ export interface Workflow {
|
|
|
721
854
|
readonly hashFiles?: string[];
|
|
722
855
|
/**
|
|
723
856
|
* Private npm registries the agent should authenticate against before `npm install`.
|
|
724
|
-
* Each registry's `tokenSecret` uses qualified `<
|
|
857
|
+
* Each registry's `tokenSecret` uses qualified `<context>:<secret-name>` syntax.
|
|
725
858
|
*/
|
|
726
859
|
readonly registries?: readonly Registry[];
|
|
727
860
|
/**
|
|
728
861
|
* Extra secrets to project as environment variables on the install subprocess.
|
|
729
862
|
* Used together with a customer-committed `.kici/.npmrc` containing `${VAR}` placeholders.
|
|
730
|
-
* Each entry uses qualified `<
|
|
731
|
-
* exposed to the install subprocess under the `<secret-name>` key (the
|
|
863
|
+
* Each entry uses qualified `<context>:<secret-name>` syntax; the resolved value is
|
|
864
|
+
* exposed to the install subprocess under the `<secret-name>` key (the context
|
|
732
865
|
* prefix is stripped for the env-var name).
|
|
733
866
|
*/
|
|
734
867
|
readonly installEnv?: readonly string[];
|
|
@@ -775,13 +908,13 @@ export interface WorkflowOptions {
|
|
|
775
908
|
hashFiles?: string[];
|
|
776
909
|
/**
|
|
777
910
|
* Private npm registries the agent should authenticate against before `npm install`.
|
|
778
|
-
* Each registry's `tokenSecret` uses qualified `<
|
|
911
|
+
* Each registry's `tokenSecret` uses qualified `<context>:<secret-name>` syntax.
|
|
779
912
|
*/
|
|
780
913
|
registries?: Registry[];
|
|
781
914
|
/**
|
|
782
915
|
* Extra secrets to project as environment variables on the install subprocess.
|
|
783
916
|
* Used together with a customer-committed `.kici/.npmrc` containing `${VAR}` placeholders.
|
|
784
|
-
* Each entry uses qualified `<
|
|
917
|
+
* Each entry uses qualified `<context>:<secret-name>` syntax; the resolved value is
|
|
785
918
|
* exposed to the install subprocess under the `<secret-name>` key.
|
|
786
919
|
*/
|
|
787
920
|
installEnv?: string[];
|
package/dist/validation/dag.js
CHANGED
|
@@ -51,12 +51,20 @@ function validateDag(nodes) {
|
|
|
51
51
|
}
|
|
52
52
|
}
|
|
53
53
|
if (sortedOrder.length !== nodes.length) {
|
|
54
|
-
const
|
|
55
|
-
for (const [id, degree] of inDegree) if (degree > 0)
|
|
54
|
+
const residual = /* @__PURE__ */ new Set();
|
|
55
|
+
for (const [id, degree] of inDegree) if (degree > 0) residual.add(id);
|
|
56
|
+
let changed = true;
|
|
57
|
+
while (changed) {
|
|
58
|
+
changed = false;
|
|
59
|
+
for (const id of residual) if (!(adjacencyList.get(id) ?? []).some((target) => residual.has(target))) {
|
|
60
|
+
residual.delete(id);
|
|
61
|
+
changed = true;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
56
64
|
return {
|
|
57
65
|
valid: false,
|
|
58
66
|
error: "cycle",
|
|
59
|
-
nodesInCycle:
|
|
67
|
+
nodesInCycle: [...residual]
|
|
60
68
|
};
|
|
61
69
|
}
|
|
62
70
|
return {
|
package/dist/workflow.js
CHANGED
|
@@ -27,7 +27,7 @@ function normalizeTriggers(on) {
|
|
|
27
27
|
* });
|
|
28
28
|
*/
|
|
29
29
|
/**
|
|
30
|
-
* Validates a `<
|
|
30
|
+
* Validates a `<context>:<secret-name>` qualified secret reference.
|
|
31
31
|
* Both halves must be non-empty and free of additional colons.
|
|
32
32
|
*/
|
|
33
33
|
function isQualifiedSecretRef(value) {
|
|
@@ -47,7 +47,7 @@ function workflow(name, options) {
|
|
|
47
47
|
} catch {
|
|
48
48
|
throw new Error(`workflow('${name}'): registries[${i}].url is not a valid URL: ${reg.url}`);
|
|
49
49
|
}
|
|
50
|
-
if (!isQualifiedSecretRef(reg.tokenSecret)) throw new Error(`workflow('${name}'): registries[${i}].tokenSecret must use qualified <
|
|
50
|
+
if (!isQualifiedSecretRef(reg.tokenSecret)) throw new Error(`workflow('${name}'): registries[${i}].tokenSecret must use qualified <context>:<secret-name> syntax (got: ${reg.tokenSecret})`);
|
|
51
51
|
if (reg.scope === void 0) defaultCount += 1;
|
|
52
52
|
else {
|
|
53
53
|
if (!/^@[a-z0-9][a-z0-9-]*$/i.test(reg.scope)) throw new Error(`workflow('${name}'): registries[${i}].scope must match @<package-scope> (got: ${reg.scope})`);
|
|
@@ -58,7 +58,7 @@ function workflow(name, options) {
|
|
|
58
58
|
if (defaultCount > 1) throw new Error(`workflow('${name}'): at most one registries entry may omit \`scope\` (default registry); got ${defaultCount}`);
|
|
59
59
|
}
|
|
60
60
|
if (options.installEnv) {
|
|
61
|
-
for (const [i, ref] of options.installEnv.entries()) if (!isQualifiedSecretRef(ref)) throw new Error(`workflow('${name}'): installEnv[${i}] must use qualified <
|
|
61
|
+
for (const [i, ref] of options.installEnv.entries()) if (!isQualifiedSecretRef(ref)) throw new Error(`workflow('${name}'): installEnv[${i}] must use qualified <context>:<secret-name> syntax (got: ${ref})`);
|
|
62
62
|
}
|
|
63
63
|
return {
|
|
64
64
|
_tag: "Workflow",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kici-dev/sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
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",
|
|
@@ -43,21 +43,26 @@
|
|
|
43
43
|
"types": "./dist/index.d.ts",
|
|
44
44
|
"import": "./dist/index.js",
|
|
45
45
|
"default": "./dist/index.js"
|
|
46
|
+
},
|
|
47
|
+
"./testing": {
|
|
48
|
+
"types": "./dist/testing/index.d.ts",
|
|
49
|
+
"import": "./dist/testing/index.js",
|
|
50
|
+
"default": "./dist/testing/index.js"
|
|
46
51
|
}
|
|
47
52
|
},
|
|
48
53
|
"dependencies": {
|
|
49
54
|
"micromatch": "^4.0.8",
|
|
50
55
|
"zod": "^4.4.3",
|
|
51
56
|
"zx": "^8.8.5",
|
|
52
|
-
"@kici-dev/core": "0.
|
|
53
|
-
"@kici-dev/engine": "0.
|
|
57
|
+
"@kici-dev/core": "0.2.0",
|
|
58
|
+
"@kici-dev/engine": "0.2.0"
|
|
54
59
|
},
|
|
55
60
|
"devDependencies": {
|
|
56
61
|
"@types/micromatch": "^4.0.10"
|
|
57
62
|
},
|
|
58
63
|
"scripts": {
|
|
59
|
-
"build": "node ../../scripts/build-ts.mjs &&
|
|
60
|
-
"typecheck": "
|
|
64
|
+
"build": "node ../../scripts/build-ts.mjs && tsgo --emitDeclarationOnly",
|
|
65
|
+
"typecheck": "tsgo --noEmit",
|
|
61
66
|
"test": "vitest run",
|
|
62
67
|
"test:watch": "vitest"
|
|
63
68
|
}
|