@kici-dev/compiler 0.1.22 → 0.1.24
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/cli.js +34 -10
- package/dist/commands/compile.d.ts +6 -0
- package/dist/commands/compile.js +6 -3
- package/dist/commands/docs.d.ts +8 -8
- package/dist/commands/docs.js +35 -16
- package/dist/commands/index.d.ts +4 -2
- package/dist/commands/index.js +3 -2
- package/dist/commands/init.js +2 -2
- package/dist/commands/org.js +2 -2
- package/dist/commands/pat.d.ts +27 -0
- package/dist/commands/pat.js +76 -0
- package/dist/commands/preview.d.ts +88 -0
- package/dist/commands/{test.js → preview.js} +15 -14
- package/dist/commands/run.d.ts +27 -2
- package/dist/commands/run.js +117 -18
- package/dist/commands/test.d.ts +4 -0
- package/dist/commands/types.d.ts +2 -0
- package/dist/commands/types.js +1 -1
- package/dist/commands/verify-attestation.d.ts +4 -1
- package/dist/commands/verify-attestation.js +26 -10
- package/dist/fixtures/describe-event.d.ts +6 -0
- package/dist/fixtures/describe-event.js +18 -0
- package/dist/fixtures/picker.d.ts +19 -0
- package/dist/fixtures/picker.js +64 -0
- package/dist/generators/secrets-dts.js +2 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/llm-context/llms-architecture.txt +1440 -0
- package/dist/llm-context/llms-cli.txt +2509 -0
- package/dist/llm-context/llms-features.txt +2491 -0
- package/dist/llm-context/llms-full.txt +1364 -361
- package/dist/llm-context/llms-getting-started.txt +519 -0
- package/dist/llm-context/llms-patterns.txt +1324 -0
- package/dist/llm-context/llms-providers.txt +805 -0
- package/dist/llm-context/llms-sdk.txt +3844 -0
- package/dist/llm-context/llms.txt +16 -1
- package/dist/local-executor/index.js +42 -4
- package/dist/local-executor/job-runner.d.ts +2 -0
- package/dist/local-executor/job-runner.js +38 -6
- package/dist/local-executor/types.d.ts +2 -0
- package/dist/lockfile/generator.d.ts +10 -2
- package/dist/lockfile/generator.js +112 -49
- package/dist/remote/history.d.ts +1 -1
- package/dist/remote/history.js +1 -1
- package/dist/remote/local-repo-identity.d.ts +32 -0
- package/dist/remote/local-repo-identity.js +74 -0
- package/dist/remote/platform-client.d.ts +6 -0
- package/dist/remote/prod-defaults.d.ts +8 -0
- package/dist/remote/prod-defaults.js +9 -1
- package/dist/remote/uploader.js +1 -0
- package/dist/templates/agents-md.d.ts +1 -1
- package/dist/templates/agents-md.js +2 -2
- package/dist/templates/package-json.js +1 -1
- package/dist/test-runner/rule-evaluator.d.ts +1 -1
- package/dist/test-runner/rule-evaluator.js +2 -1
- package/dist/test-runner/step-context.d.ts +1 -1
- package/dist/test-runner/step-context.js +8 -2
- package/dist/types.d.ts +38 -7
- package/dist/types.js +5 -1
- package/package.json +4 -7
- package/sbom.spdx.json +35 -35
package/dist/commands/run.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type HostTargetSelector, type InputsDescriptorMap } from '@kici-dev/engine';
|
|
2
2
|
import type { RunLocalOptions } from '../local-executor/types.js';
|
|
3
|
-
import type { RemoteRunOptions } from './
|
|
3
|
+
import type { RemoteRunOptions } from './preview.js';
|
|
4
4
|
/**
|
|
5
5
|
* Compile `--target` selector strings into a {@link HostTargetSelector}. Each
|
|
6
6
|
* string becomes one AND value (its own include set); repeated values
|
|
@@ -8,6 +8,31 @@ import type { RemoteRunOptions } from './test.js';
|
|
|
8
8
|
* `--target-allow-empty` is set without at least one `--target`.
|
|
9
9
|
*/
|
|
10
10
|
export declare function buildTargetSelector(targets: string[] | undefined, allowEmpty: boolean): HostTargetSelector | undefined;
|
|
11
|
+
/**
|
|
12
|
+
* Look up the dispatch-trigger `inputs` descriptor for a workflow from a parsed
|
|
13
|
+
* inline lock file. When `workflowName` is given, only that workflow's dispatch
|
|
14
|
+
* triggers are considered; otherwise descriptors across all workflows are merged
|
|
15
|
+
* (best-effort fast-fail — the orchestrator re-validates against the matched
|
|
16
|
+
* workflow authoritatively). Returns undefined when no dispatch inputs declared.
|
|
17
|
+
*/
|
|
18
|
+
export declare function lookupDispatchInputsDescriptor(inlineLockFile: string | undefined, workflowName: string | undefined): InputsDescriptorMap | undefined;
|
|
19
|
+
/**
|
|
20
|
+
* Validate raw `--input KEY=VALUE` pairs against the (optional) lock descriptor
|
|
21
|
+
* and return the raw operator pairs verbatim. The CLI fast-fails on malformed /
|
|
22
|
+
* invalid input for UX, but forwards the **raw** strings — the orchestrator is
|
|
23
|
+
* authoritative and applies coercion + defaults exactly once.
|
|
24
|
+
*/
|
|
25
|
+
export declare function buildDispatchInputs(pairs: string[], descriptor: InputsDescriptorMap | undefined): Record<string, string>;
|
|
26
|
+
/**
|
|
27
|
+
* Run `fn` with everything written to `process.stdout` redirected to
|
|
28
|
+
* `process.stderr`, then restore the original writer. Compiling a repo
|
|
29
|
+
* evaluates every user workflow / fixture module, and a `console.log` at a
|
|
30
|
+
* module's top level writes straight to stdout. On a machine-readable
|
|
31
|
+
* (`--json`) run that stdout MUST carry only the final JSON result, so the
|
|
32
|
+
* compile phases run inside this guard — workflow log output belongs on
|
|
33
|
+
* stderr regardless.
|
|
34
|
+
*/
|
|
35
|
+
export declare function withStdoutOnStderr<T>(fn: () => Promise<T>): Promise<T>;
|
|
11
36
|
/**
|
|
12
37
|
* Run a workflow locally using the local executor.
|
|
13
38
|
* Thin wrapper that delegates to executeLocal from local-executor.
|
package/dist/commands/run.js
CHANGED
|
@@ -3,19 +3,24 @@ import { resolveKiciDir } from "../execution/executor.js";
|
|
|
3
3
|
import "../execution/index.js";
|
|
4
4
|
import { loadGlobalConfig } from "../remote/config.js";
|
|
5
5
|
import { RunHistory } from "../remote/history.js";
|
|
6
|
+
import { buildLocalRepoIdentity } from "../remote/local-repo-identity.js";
|
|
6
7
|
import { AccessDeniedError, AmbiguousClusterError, AuthenticationError, ConnectionError, NoClusterError, PlatformRunClient } from "../remote/platform-client.js";
|
|
7
8
|
import { buildEncryptedSecrets } from "../remote/secret-upload.js";
|
|
8
9
|
import { createOverlayTarball, getSizeWarning, uploadTarball } from "../remote/uploader.js";
|
|
9
10
|
import { formatJsonResult } from "../remote/output/json.js";
|
|
10
11
|
import { formatJunitResult } from "../remote/output/junit.js";
|
|
11
12
|
import { formatErrorHighlight, formatMultiFixtureSummary, formatSummary } from "../remote/output/summary.js";
|
|
13
|
+
import { compileCommand } from "./compile.js";
|
|
12
14
|
import { compileFixtures, filterFixtures } from "../fixtures/compiler.js";
|
|
15
|
+
import { describeEvent } from "../fixtures/describe-event.js";
|
|
16
|
+
import { FixturePickerCancelledError, runFixturePicker } from "../fixtures/picker.js";
|
|
13
17
|
import { listHeldRunsForRun, resolveHeldRunContext } from "./held-run-client.js";
|
|
14
18
|
import { handleNewHolds } from "./run-hold-watch.js";
|
|
15
19
|
import path from "node:path";
|
|
16
20
|
import pc from "picocolors";
|
|
17
21
|
import { readFile, writeFile } from "node:fs/promises";
|
|
18
22
|
import { formatBytes, logger, toErrorMessage } from "@kici-dev/core";
|
|
23
|
+
import { coerceDispatchInputs, parseInputPairs } from "@kici-dev/engine";
|
|
19
24
|
import { normalizeRunsOnToMatchers } from "@kici-dev/engine/labels/compile";
|
|
20
25
|
import { confirm } from "@inquirer/prompts";
|
|
21
26
|
//#region src/commands/run.ts
|
|
@@ -42,9 +47,85 @@ function buildTargetSelector(targets, allowEmpty) {
|
|
|
42
47
|
allowEmpty
|
|
43
48
|
};
|
|
44
49
|
}
|
|
50
|
+
/**
|
|
51
|
+
* Look up the dispatch-trigger `inputs` descriptor for a workflow from a parsed
|
|
52
|
+
* inline lock file. When `workflowName` is given, only that workflow's dispatch
|
|
53
|
+
* triggers are considered; otherwise descriptors across all workflows are merged
|
|
54
|
+
* (best-effort fast-fail — the orchestrator re-validates against the matched
|
|
55
|
+
* workflow authoritatively). Returns undefined when no dispatch inputs declared.
|
|
56
|
+
*/
|
|
57
|
+
function lookupDispatchInputsDescriptor(inlineLockFile, workflowName) {
|
|
58
|
+
if (!inlineLockFile) return void 0;
|
|
59
|
+
let lock;
|
|
60
|
+
try {
|
|
61
|
+
lock = JSON.parse(inlineLockFile);
|
|
62
|
+
} catch {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
const merged = {};
|
|
66
|
+
let found = false;
|
|
67
|
+
for (const wf of lock.workflows ?? []) {
|
|
68
|
+
if (workflowName && wf.name !== workflowName) continue;
|
|
69
|
+
for (const trigger of wf.triggers ?? []) if (trigger._type === "dispatch" && trigger.inputs) {
|
|
70
|
+
Object.assign(merged, trigger.inputs);
|
|
71
|
+
found = true;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return found ? merged : void 0;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Validate raw `--input KEY=VALUE` pairs against the (optional) lock descriptor
|
|
78
|
+
* and return the raw operator pairs verbatim. The CLI fast-fails on malformed /
|
|
79
|
+
* invalid input for UX, but forwards the **raw** strings — the orchestrator is
|
|
80
|
+
* authoritative and applies coercion + defaults exactly once.
|
|
81
|
+
*/
|
|
82
|
+
function buildDispatchInputs(pairs, descriptor) {
|
|
83
|
+
if (!pairs.length) return {};
|
|
84
|
+
const raw = parseInputPairs(pairs);
|
|
85
|
+
if (descriptor) {
|
|
86
|
+
const r = coerceDispatchInputs(raw, descriptor);
|
|
87
|
+
if ("error" in r) throw r.error;
|
|
88
|
+
}
|
|
89
|
+
return raw;
|
|
90
|
+
}
|
|
45
91
|
/** Interval between status/log polls while a run is active. */
|
|
46
92
|
const POLL_INTERVAL_MS = 750;
|
|
47
93
|
/**
|
|
94
|
+
* Run `fn` with everything written to `process.stdout` redirected to
|
|
95
|
+
* `process.stderr`, then restore the original writer. Compiling a repo
|
|
96
|
+
* evaluates every user workflow / fixture module, and a `console.log` at a
|
|
97
|
+
* module's top level writes straight to stdout. On a machine-readable
|
|
98
|
+
* (`--json`) run that stdout MUST carry only the final JSON result, so the
|
|
99
|
+
* compile phases run inside this guard — workflow log output belongs on
|
|
100
|
+
* stderr regardless.
|
|
101
|
+
*/
|
|
102
|
+
async function withStdoutOnStderr(fn) {
|
|
103
|
+
const realWrite = process.stdout.write.bind(process.stdout);
|
|
104
|
+
process.stdout.write = process.stderr.write.bind(process.stderr);
|
|
105
|
+
try {
|
|
106
|
+
return await fn();
|
|
107
|
+
} finally {
|
|
108
|
+
process.stdout.write = realWrite;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Recompile `.kici/workflows` → `kici.lock.json` before a remote run, mirroring
|
|
113
|
+
* `kici run local`. The orchestrator matches triggers and dispatches against the
|
|
114
|
+
* inline lock, so a stale lock would route an edited or newly-added workflow
|
|
115
|
+
* incorrectly. Returns false on a compile/validation error so the caller can
|
|
116
|
+
* abort before any upload or dispatch.
|
|
117
|
+
*/
|
|
118
|
+
async function compileBeforeRemoteRun(options) {
|
|
119
|
+
const pureStdout = Boolean(options.json || options.quiet);
|
|
120
|
+
const compile = () => compileCommand({
|
|
121
|
+
kiciDir: options.kiciDir ?? ".kici",
|
|
122
|
+
check: false,
|
|
123
|
+
verbose: options.debug ?? false,
|
|
124
|
+
quiet: pureStdout
|
|
125
|
+
});
|
|
126
|
+
return pureStdout ? withStdoutOnStderr(compile) : compile();
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
48
129
|
* Run a workflow locally using the local executor.
|
|
49
130
|
* Thin wrapper that delegates to executeLocal from local-executor.
|
|
50
131
|
*
|
|
@@ -88,10 +169,22 @@ async function runRemoteCommand(fixture, options) {
|
|
|
88
169
|
console.log(history.formatTable(entries));
|
|
89
170
|
return true;
|
|
90
171
|
}
|
|
91
|
-
const
|
|
92
|
-
|
|
172
|
+
const testsDir = path.join(kiciDir, "tests");
|
|
173
|
+
const fixtures = options.json ? await withStdoutOnStderr(() => compileFixtures(testsDir)) : await compileFixtures(testsDir);
|
|
93
174
|
let selected;
|
|
94
|
-
if (options.
|
|
175
|
+
if (options.pick) {
|
|
176
|
+
if (fixtures.length === 0) return listFixtures(fixtures);
|
|
177
|
+
try {
|
|
178
|
+
selected = await runFixturePicker(fixtures);
|
|
179
|
+
} catch (err) {
|
|
180
|
+
if (err instanceof FixturePickerCancelledError) {
|
|
181
|
+
logger.info(pc.gray(err.message));
|
|
182
|
+
return false;
|
|
183
|
+
}
|
|
184
|
+
throw err;
|
|
185
|
+
}
|
|
186
|
+
} else if (!fixture && !options.all) return listFixtures(fixtures);
|
|
187
|
+
else if (options.all) selected = fixtures;
|
|
95
188
|
else selected = filterFixtures(fixtures, fixture);
|
|
96
189
|
if (selected.length === 0) {
|
|
97
190
|
logger.info(pc.yellow(`No fixtures matched: ${fixture ?? "(none)"}`));
|
|
@@ -132,17 +225,6 @@ function listFixtures(fixtures) {
|
|
|
132
225
|
return true;
|
|
133
226
|
}
|
|
134
227
|
/**
|
|
135
|
-
* Describe the event type from a fixture's trigger config.
|
|
136
|
-
*/
|
|
137
|
-
function describeEvent(event) {
|
|
138
|
-
if (!event || typeof event !== "object") return "unknown";
|
|
139
|
-
const e = event;
|
|
140
|
-
if (e._type === "push") return "push";
|
|
141
|
-
if (e._type === "pr") return `pr:${e.action ?? "open"}`;
|
|
142
|
-
if (typeof e._type === "string") return String(e._type);
|
|
143
|
-
return "custom";
|
|
144
|
-
}
|
|
145
|
-
/**
|
|
146
228
|
* Resolve the authenticated Platform client and the run target (org + cluster).
|
|
147
229
|
*
|
|
148
230
|
* Org resolution: `--org` → `config.activeOrgId` → error.
|
|
@@ -182,6 +264,7 @@ function resolvePlatformContext(config, options) {
|
|
|
182
264
|
* Run fixtures remotely against the Platform.
|
|
183
265
|
*/
|
|
184
266
|
async function runFixturesRemotely(fixtures, options) {
|
|
267
|
+
if (!await compileBeforeRemoteRun(options)) return false;
|
|
185
268
|
const config = await loadGlobalConfig();
|
|
186
269
|
const ctx = resolvePlatformContext(config, options);
|
|
187
270
|
if (!ctx) return false;
|
|
@@ -294,11 +377,12 @@ async function runSingleFixture(fixture, ctx, options, config, history) {
|
|
|
294
377
|
const uploaded = await initAndUpload(ctx, overlay, options);
|
|
295
378
|
const event = buildEventFromFixture(opts);
|
|
296
379
|
{
|
|
297
|
-
const
|
|
380
|
+
const identity = buildLocalRepoIdentity(overlay.repoRoot);
|
|
298
381
|
const repo = event.payload.repository;
|
|
299
382
|
event.payload.repository = {
|
|
300
383
|
...repo ?? {},
|
|
301
|
-
full_name:
|
|
384
|
+
full_name: identity.repoIdentifier,
|
|
385
|
+
provider: identity.provider
|
|
302
386
|
};
|
|
303
387
|
}
|
|
304
388
|
if (!options.quiet) logger.info(pc.gray("Triggering test run..."));
|
|
@@ -320,6 +404,11 @@ async function runSingleFixture(fixture, ctx, options, config, history) {
|
|
|
320
404
|
...(() => {
|
|
321
405
|
const target = buildTargetSelector(options.targets, options.targetAllowEmpty ?? false);
|
|
322
406
|
return target ? { target } : {};
|
|
407
|
+
})(),
|
|
408
|
+
...(() => {
|
|
409
|
+
const descriptor = lookupDispatchInputsDescriptor(overlay.inlineLockFile, opts.workflowName);
|
|
410
|
+
const dispatchInputs = buildDispatchInputs(options.inputs ?? [], descriptor);
|
|
411
|
+
return Object.keys(dispatchInputs).length ? { dispatchInputs } : {};
|
|
323
412
|
})()
|
|
324
413
|
});
|
|
325
414
|
if (triggerResult.status === "rejected") {
|
|
@@ -513,6 +602,7 @@ function buildEventFromFixture(opts) {
|
|
|
513
602
|
* Platform.
|
|
514
603
|
*/
|
|
515
604
|
async function runDirectWorkflow(workflowName, options) {
|
|
605
|
+
if (!await compileBeforeRemoteRun(options)) return false;
|
|
516
606
|
const ctx = resolvePlatformContext(await loadGlobalConfig(), options);
|
|
517
607
|
if (!ctx) return false;
|
|
518
608
|
if (options.json) options.quiet = true;
|
|
@@ -522,7 +612,11 @@ async function runDirectWorkflow(workflowName, options) {
|
|
|
522
612
|
try {
|
|
523
613
|
const overlay = await prepareOverlay(options);
|
|
524
614
|
const uploaded = await initAndUpload(ctx, overlay, options);
|
|
525
|
-
const
|
|
615
|
+
const identity = buildLocalRepoIdentity(overlay.repoRoot);
|
|
616
|
+
const payload = { repository: {
|
|
617
|
+
full_name: identity.repoIdentifier,
|
|
618
|
+
provider: identity.provider
|
|
619
|
+
} };
|
|
526
620
|
const encrypted = await buildEncryptedSecrets(overlay.kiciDir, options.envFlags, options.context, uploaded.publicKey);
|
|
527
621
|
const triggerResult = await ctx.client.trigger(ctx.orgId, ctx.target, {
|
|
528
622
|
fixtureId,
|
|
@@ -544,6 +638,11 @@ async function runDirectWorkflow(workflowName, options) {
|
|
|
544
638
|
...(() => {
|
|
545
639
|
const target = buildTargetSelector(options.targets, options.targetAllowEmpty ?? false);
|
|
546
640
|
return target ? { target } : {};
|
|
641
|
+
})(),
|
|
642
|
+
...(() => {
|
|
643
|
+
const descriptor = lookupDispatchInputsDescriptor(overlay.inlineLockFile, workflowName);
|
|
644
|
+
const dispatchInputs = buildDispatchInputs(options.inputs ?? [], descriptor);
|
|
645
|
+
return Object.keys(dispatchInputs).length ? { dispatchInputs } : {};
|
|
547
646
|
})()
|
|
548
647
|
});
|
|
549
648
|
if (!options.quiet) logger.info(pc.green(`Run started: ${triggerResult.runId}`));
|
|
@@ -572,6 +671,6 @@ function displayRemoteResults(results) {
|
|
|
572
671
|
logger.info("");
|
|
573
672
|
}
|
|
574
673
|
//#endregion
|
|
575
|
-
export { buildTargetSelector, runLocalCommand, runRemoteCommand };
|
|
674
|
+
export { buildDispatchInputs, buildTargetSelector, lookupDispatchInputsDescriptor, runLocalCommand, runRemoteCommand, withStdoutOnStderr };
|
|
576
675
|
|
|
577
676
|
//# sourceMappingURL=run.js.map
|
package/dist/commands/test.d.ts
CHANGED
|
@@ -19,6 +19,8 @@ export interface TestOptions extends PayloadOptions {
|
|
|
19
19
|
export interface RemoteRunOptions extends TestOptions {
|
|
20
20
|
/** Run all available fixtures */
|
|
21
21
|
all?: boolean;
|
|
22
|
+
/** Interactively pick fixtures to run (multi-select checkbox). */
|
|
23
|
+
pick?: boolean;
|
|
22
24
|
/** Run matching fixtures concurrently */
|
|
23
25
|
parallel?: boolean;
|
|
24
26
|
/** Fire and forget (print runIds, don't stream) */
|
|
@@ -55,6 +57,8 @@ export interface RemoteRunOptions extends TestOptions {
|
|
|
55
57
|
* operator must still be clause-eligible per hold; an ineligible hold blocks.
|
|
56
58
|
*/
|
|
57
59
|
approveAll?: boolean;
|
|
60
|
+
/** `--input KEY=VALUE` values (repeatable): typed workflow-dispatch inputs. */
|
|
61
|
+
inputs?: string[];
|
|
58
62
|
}
|
|
59
63
|
/** Result of a single remote fixture run */
|
|
60
64
|
export interface RemoteRunResult {
|
package/dist/commands/types.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
export interface TypesOptions {
|
|
2
2
|
/** Path to .kici directory (defaults to .kici) */
|
|
3
3
|
kiciDir?: string;
|
|
4
|
+
/** Suppress the success line on stdout (so machine-readable output stays pure). */
|
|
5
|
+
quiet?: boolean;
|
|
4
6
|
}
|
|
5
7
|
/**
|
|
6
8
|
* Generate TypeScript declarations for environment secrets.
|
package/dist/commands/types.js
CHANGED
|
@@ -33,7 +33,7 @@ async function typesCommand(options = {}) {
|
|
|
33
33
|
await fs.mkdir(typesDir, { recursive: true });
|
|
34
34
|
const outputPath = path.join(typesDir, "secrets.d.ts");
|
|
35
35
|
await fs.writeFile(outputPath, dtsContent, "utf-8");
|
|
36
|
-
console.log(pc.green("Types generated") + pc.dim(` ${outputPath}`));
|
|
36
|
+
if (!options.quiet) console.log(pc.green("Types generated") + pc.dim(` ${outputPath}`));
|
|
37
37
|
return true;
|
|
38
38
|
} catch (err) {
|
|
39
39
|
if (err instanceof DashboardClientError) {
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
export interface VerifyAttestationOptions {
|
|
2
2
|
/** Path or `http(s)` URL to the attestation bundle JSON. Required. */
|
|
3
3
|
bundle?: string;
|
|
4
|
-
/**
|
|
4
|
+
/**
|
|
5
|
+
* Trusted issuer URL (online discovery) or a self-contained `{ issuer, jwks }`
|
|
6
|
+
* file. Optional — defaults to the hosted KiCI Platform's provenance issuer.
|
|
7
|
+
*/
|
|
5
8
|
trustRoot?: string;
|
|
6
9
|
/** Expected token audience (defaults to the KiCI provenance audience). */
|
|
7
10
|
audience?: string;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import "../chunk-BTugEXQM.js";
|
|
2
2
|
import { resolveTrustRoot } from "../provenance-trust-root.js";
|
|
3
|
+
import "../remote/prod-defaults.js";
|
|
3
4
|
import pc from "picocolors";
|
|
4
5
|
import { readFile } from "node:fs/promises";
|
|
5
6
|
import { logger, sha256File, toErrorMessage } from "@kici-dev/core";
|
|
@@ -7,13 +8,18 @@ import { KICI_PROVENANCE_AUDIENCE } from "@kici-dev/engine/provenance/bundle";
|
|
|
7
8
|
import { verifyKiciBundle } from "@kici-dev/engine/provenance/verify";
|
|
8
9
|
//#region src/commands/verify-attestation.ts
|
|
9
10
|
/**
|
|
10
|
-
* `kici verify-attestation [artifact] --bundle <path|url> --trust-root <url|file
|
|
11
|
+
* `kici verify-attestation [artifact] --bundle <path|url> [--trust-root <url|file>]`
|
|
11
12
|
*
|
|
12
13
|
* Offline verification of a KiCI-signed provenance bundle: read the bundle,
|
|
13
|
-
* resolve the trusted issuer + JWKS out-of-band
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
14
|
+
* resolve the trusted issuer + JWKS out-of-band, optionally digest the artifact,
|
|
15
|
+
* and hand everything to the shared browser-safe `verifyKiciBundle` core in
|
|
16
|
+
* `@kici-dev/engine`. The engine owns all crypto; this command is the thin Node
|
|
17
|
+
* wrapper (fs / fetch / artifact digest / output).
|
|
18
|
+
*
|
|
19
|
+
* `--trust-root` is optional: when omitted it defaults to the hosted KiCI
|
|
20
|
+
* Platform's provenance issuer, so the common case (verifying a bundle attested
|
|
21
|
+
* on the hosted platform) needs no flag. Pass `--trust-root` to verify against a
|
|
22
|
+
* different environment (e.g. staging) or an offline `{ issuer, jwks }` file.
|
|
17
23
|
*
|
|
18
24
|
* Returns a boolean (verified) so `cli.ts` can map it to an exit code (0/1).
|
|
19
25
|
*/
|
|
@@ -23,12 +29,22 @@ async function verifyAttestationCommand(artifact, options = {}) {
|
|
|
23
29
|
logger.error(pc.red("Error: --bundle <path|url> is required"));
|
|
24
30
|
return false;
|
|
25
31
|
}
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
}
|
|
32
|
+
const trustRoot = options.trustRoot ?? "https://api.kici.dev";
|
|
33
|
+
const usingDefault = !options.trustRoot;
|
|
34
|
+
if (usingDefault) logger.info(pc.gray(`Using default trust root ${trustRoot} (pass --trust-root to override)`));
|
|
30
35
|
const bundle = JSON.parse(await readBundle(options.bundle));
|
|
31
|
-
|
|
36
|
+
let resolved;
|
|
37
|
+
try {
|
|
38
|
+
resolved = await resolveTrustRoot(trustRoot);
|
|
39
|
+
} catch (error) {
|
|
40
|
+
const msg = toErrorMessage(error);
|
|
41
|
+
if (usingDefault && /\b503\b/.test(msg)) {
|
|
42
|
+
logger.error(pc.red(`Error: build provenance is not enabled on the hosted KiCI platform yet (${trustRoot} returned 503). Pass --trust-root to verify against another environment (e.g. staging) or an offline { issuer, jwks } file.`));
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
throw error;
|
|
46
|
+
}
|
|
47
|
+
const { issuer, jwks } = resolved;
|
|
32
48
|
const expectedDigest = artifact ? {
|
|
33
49
|
alg: "sha256",
|
|
34
50
|
hex: await sha256File(artifact)
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import "../chunk-BTugEXQM.js";
|
|
2
|
+
//#region src/fixtures/describe-event.ts
|
|
3
|
+
/**
|
|
4
|
+
* Describe the event type from a fixture's trigger config, for the fixtures
|
|
5
|
+
* table and the interactive picker.
|
|
6
|
+
*/
|
|
7
|
+
function describeEvent(event) {
|
|
8
|
+
if (!event || typeof event !== "object") return "unknown";
|
|
9
|
+
const e = event;
|
|
10
|
+
if (e._type === "push") return "push";
|
|
11
|
+
if (e._type === "pr") return `pr:${e.action ?? "open"}`;
|
|
12
|
+
if (typeof e._type === "string") return String(e._type);
|
|
13
|
+
return "custom";
|
|
14
|
+
}
|
|
15
|
+
//#endregion
|
|
16
|
+
export { describeEvent };
|
|
17
|
+
|
|
18
|
+
//# sourceMappingURL=describe-event.js.map
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interactive multi-select fixture picker for `kici run remote --pick`.
|
|
3
|
+
*
|
|
4
|
+
* Lists every available fixture with its source and event type, lets the user
|
|
5
|
+
* toggle one or more via a checkbox prompt, and returns the chosen fixtures.
|
|
6
|
+
* The caller feeds them into the standard remote-dispatch pipeline, so a picked
|
|
7
|
+
* run is identical to one selected by name / glob / --all.
|
|
8
|
+
*/
|
|
9
|
+
import type { CompiledFixture } from './compiler.js';
|
|
10
|
+
export declare class FixturePickerCancelledError extends Error {
|
|
11
|
+
constructor(message: string);
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Run the interactive multi-select fixture picker.
|
|
15
|
+
*
|
|
16
|
+
* @throws FixturePickerCancelledError when stdin is not a TTY or the user aborts.
|
|
17
|
+
*/
|
|
18
|
+
export declare function runFixturePicker(fixtures: CompiledFixture[]): Promise<CompiledFixture[]>;
|
|
19
|
+
//# sourceMappingURL=picker.d.ts.map
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import "../chunk-BTugEXQM.js";
|
|
2
|
+
import { describeEvent } from "./describe-event.js";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import pc from "picocolors";
|
|
5
|
+
import { logger } from "@kici-dev/core";
|
|
6
|
+
import { checkbox } from "@inquirer/prompts";
|
|
7
|
+
//#region src/fixtures/picker.ts
|
|
8
|
+
/**
|
|
9
|
+
* Interactive multi-select fixture picker for `kici run remote --pick`.
|
|
10
|
+
*
|
|
11
|
+
* Lists every available fixture with its source and event type, lets the user
|
|
12
|
+
* toggle one or more via a checkbox prompt, and returns the chosen fixtures.
|
|
13
|
+
* The caller feeds them into the standard remote-dispatch pipeline, so a picked
|
|
14
|
+
* run is identical to one selected by name / glob / --all.
|
|
15
|
+
*/
|
|
16
|
+
var FixturePickerCancelledError = class extends Error {
|
|
17
|
+
constructor(message) {
|
|
18
|
+
super(message);
|
|
19
|
+
this.name = "FixturePickerCancelledError";
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
function isStdinTty() {
|
|
23
|
+
return Boolean(process.stdin.isTTY);
|
|
24
|
+
}
|
|
25
|
+
/** Build a single fixture's display row: `id <source> <event type>`. */
|
|
26
|
+
function fixtureRow(f) {
|
|
27
|
+
const opts = typeof f.fixture.options === "function" ? null : f.fixture.options;
|
|
28
|
+
const eventType = opts?.event ? describeEvent(opts.event) : "(async)";
|
|
29
|
+
const source = path.relative(process.cwd(), f.sourceFile);
|
|
30
|
+
return `${f.id} ${pc.gray(source)} ${eventType}`;
|
|
31
|
+
}
|
|
32
|
+
function printFixtureList(fixtures) {
|
|
33
|
+
logger.info(pc.bold("Available fixtures:"));
|
|
34
|
+
for (const f of fixtures) logger.info(` ${pc.cyan(f.id)} — ${fixtureRow(f)}`);
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Run the interactive multi-select fixture picker.
|
|
38
|
+
*
|
|
39
|
+
* @throws FixturePickerCancelledError when stdin is not a TTY or the user aborts.
|
|
40
|
+
*/
|
|
41
|
+
async function runFixturePicker(fixtures) {
|
|
42
|
+
if (!isStdinTty()) {
|
|
43
|
+
printFixtureList(fixtures);
|
|
44
|
+
throw new FixturePickerCancelledError("--pick requires an interactive terminal. Pass a fixture name instead.");
|
|
45
|
+
}
|
|
46
|
+
let chosenIds;
|
|
47
|
+
try {
|
|
48
|
+
chosenIds = await checkbox({
|
|
49
|
+
message: "Select fixtures to run",
|
|
50
|
+
choices: fixtures.map((f) => ({
|
|
51
|
+
name: fixtureRow(f),
|
|
52
|
+
value: f.id
|
|
53
|
+
})),
|
|
54
|
+
required: true
|
|
55
|
+
});
|
|
56
|
+
} catch (err) {
|
|
57
|
+
throw new FixturePickerCancelledError(`Picker cancelled: ${err instanceof Error ? err.message : String(err)}`);
|
|
58
|
+
}
|
|
59
|
+
return fixtures.filter((f) => chosenIds.includes(f.id));
|
|
60
|
+
}
|
|
61
|
+
//#endregion
|
|
62
|
+
export { FixturePickerCancelledError, runFixturePicker };
|
|
63
|
+
|
|
64
|
+
//# sourceMappingURL=picker.js.map
|
package/dist/index.d.ts
CHANGED
|
@@ -3,8 +3,8 @@ export type { ExecutionResult } from './execution/index.js';
|
|
|
3
3
|
export { validateConfig } from './validation/index.js';
|
|
4
4
|
export type { ValidationResult } from './validation/index.js';
|
|
5
5
|
export { generateLockFile, serializeLockFile } from './lockfile/index.js';
|
|
6
|
-
export { SCHEMA_VERSION, isLockStaticJob } from './types.js';
|
|
7
|
-
export type { LockFile, LockWorkflow, LockJob, LockDynamicJobFn, LockJobOrFactory, LockTrigger, LockPrTrigger, LockPushTrigger, LockMatrix, LockRule, LockStep, LockApproval, LockSource, LockBranchPattern, } from './types.js';
|
|
6
|
+
export { SCHEMA_VERSION, isLockStaticJob, isLockParallelStep } from './types.js';
|
|
7
|
+
export type { LockFile, LockWorkflow, LockJob, LockDynamicJobFn, LockJobOrFactory, LockTrigger, LockPrTrigger, LockPushTrigger, LockMatrix, LockRule, LockStep, LockParallelStep, LockStepEntry, LockApproval, LockSource, LockBranchPattern, } from './types.js';
|
|
8
8
|
export { formatError, compilerError, isCompilerError } from './errors/index.js';
|
|
9
9
|
export type { SourceLocation, CompilerError } from './errors/index.js';
|
|
10
10
|
export { CapabilityGapError, formatCapabilityGapError } from './errors/index.js';
|
package/dist/index.js
CHANGED
|
@@ -6,7 +6,7 @@ import { executeConfig } from "./execution/executor.js";
|
|
|
6
6
|
import "./execution/index.js";
|
|
7
7
|
import { validateConfig } from "./validation/validator.js";
|
|
8
8
|
import "./validation/index.js";
|
|
9
|
-
import { SCHEMA_VERSION, isLockStaticJob } from "./types.js";
|
|
9
|
+
import { SCHEMA_VERSION, isLockParallelStep, isLockStaticJob } from "./types.js";
|
|
10
10
|
import { generateLockFile, serializeLockFile } from "./lockfile/generator.js";
|
|
11
11
|
import "./lockfile/index.js";
|
|
12
|
-
export { CapabilityGapError, SCHEMA_VERSION, compilerError, executeConfig, formatCapabilityGapError, formatError, generateLockFile, isCompilerError, isLockStaticJob, serializeLockFile, validateConfig };
|
|
12
|
+
export { CapabilityGapError, SCHEMA_VERSION, compilerError, executeConfig, formatCapabilityGapError, formatError, generateLockFile, isCompilerError, isLockParallelStep, isLockStaticJob, serializeLockFile, validateConfig };
|