@kici-dev/compiler 0.1.23 → 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 +15 -5
- 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/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 +11 -1
- package/dist/commands/run.js +34 -7
- package/dist/commands/verify-attestation.d.ts +4 -1
- package/dist/commands/verify-attestation.js +26 -10
- 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 +3 -3
- package/dist/llm-context/llms-cli.txt +149 -26
- package/dist/llm-context/llms-features.txt +107 -5
- package/dist/llm-context/llms-full.txt +390 -46
- package/dist/llm-context/llms-getting-started.txt +6 -6
- package/dist/llm-context/llms-sdk.txt +125 -6
- package/dist/llm-context/llms.txt +7 -5
- package/dist/local-executor/index.js +2 -1
- package/dist/local-executor/job-runner.js +3 -3
- package/dist/lockfile/generator.d.ts +10 -2
- package/dist/lockfile/generator.js +106 -52
- 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/prod-defaults.d.ts +8 -0
- package/dist/remote/prod-defaults.js +9 -1
- 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/step-context.d.ts +1 -1
- package/dist/test-runner/step-context.js +2 -1
- package/dist/types.d.ts +33 -6
- package/dist/types.js +5 -1
- package/package.json +4 -7
- package/sbom.spdx.json +35 -35
package/dist/cli.js
CHANGED
|
@@ -7,7 +7,7 @@ import { realpathSync } from "node:fs";
|
|
|
7
7
|
import { Argument, Command, Option } from "commander";
|
|
8
8
|
import pc from "picocolors";
|
|
9
9
|
//#region src/cli.ts
|
|
10
|
-
const version = "0.1.
|
|
10
|
+
const version = "0.1.24";
|
|
11
11
|
/**
|
|
12
12
|
* Build the kici Commander program with every command registered. Exported so
|
|
13
13
|
* the surface registry can walk the real command tree without parsing argv (no
|
|
@@ -126,9 +126,9 @@ function buildProgram() {
|
|
|
126
126
|
});
|
|
127
127
|
process.exit(success ? 0 : 1);
|
|
128
128
|
});
|
|
129
|
-
program.command("
|
|
130
|
-
const {
|
|
131
|
-
const success = await
|
|
129
|
+
program.command("preview").argument("[event]", "Event type to preview (e.g., push, pr:open, schedule)").description("Preview which workflows match a trigger event (no execution)").option("--branch <name>", "Override target branch for trigger matching (default: main)").option("--sha <hash>", "Override commit SHA").option("--workflow <name>", "Filter to specific workflow in display").option("--job <name>", "Filter to specific job in display").option("--debug", "Verbose internals", false).option("--kici-dir <path>", "Path to .kici directory", ".kici").option("--files <path>", "Simulate changed file path for trigger matching (repeatable)", (val, prev) => [...prev, val], []).option("--secret <key=value>", "Inject flat secret (repeatable)", (val, prev) => [...prev, val], []).option("--context <ctx.key=value>", "Inject context secret (repeatable)", (val, prev) => [...prev, val], []).action(async (event, options) => {
|
|
130
|
+
const { previewCommand } = await import("./commands/index.js");
|
|
131
|
+
const success = await previewCommand(event, options);
|
|
132
132
|
process.exit(success ? 0 : 1);
|
|
133
133
|
});
|
|
134
134
|
program.command("init").description("Initialize .kici/ directory with default workflows").option("--force", "Overwrite existing .kici/ directory", false).option("--skip-install", "Create files without installing dependencies", false).option("--package-manager <npm|pnpm|yarn>", "Force a package manager for the install step (default: auto-detect)").option("--mjs", "JavaScript-only mode (no TypeScript, no dependencies)", false).option("--no-agents-md", "Skip writing .kici/AGENTS.md (LLM authoring context)").option("--private-registry <url>", "Scaffold a workflow registries: entry pointing at <url>").option("--private-registry-scope <scope>", "Optional npm package scope (e.g. @my-org) for the private registry").option("--private-registry-secret <ref>", "Qualified secret reference (env:NAME) the private registry token comes from", "production:NPM_TOKEN").addOption(new Option("--use-verdaccio-local").default(false).hideHelp()).action(async (options) => {
|
|
@@ -199,6 +199,16 @@ Environment variables:
|
|
|
199
199
|
const success = await secretsListCommand();
|
|
200
200
|
process.exit(success ? 0 : 1);
|
|
201
201
|
});
|
|
202
|
+
program.command("pat").description("Manage personal access tokens").command("create").description("Mint a personal access token (use --agent for a coding-agent token)").option("--name <name>", "Token name (defaults to the agent label)").option("--agent", "Mint an agent-kind PAT for the KiCI MCP server", false).option("--expires-in-days <n>", "Custom expiry in days", (v) => parseInt(v, 10)).action(async (options) => {
|
|
203
|
+
const { patCreateCommand } = await import("./commands/index.js");
|
|
204
|
+
const success = await patCreateCommand({
|
|
205
|
+
name: options.name,
|
|
206
|
+
agent: options.agent,
|
|
207
|
+
label: options.name,
|
|
208
|
+
expiresInDays: options.expiresInDays
|
|
209
|
+
});
|
|
210
|
+
process.exit(success ? 0 : 1);
|
|
211
|
+
});
|
|
202
212
|
const runsCommand = program.command("runs").description("Inspect and manage execution runs");
|
|
203
213
|
runsCommand.command("list").description("List execution runs (mirrors the dashboard Runs page)").option("--status <s>", "Filter by status").option("--workflow <w>", "Filter by workflow name").option("--branch <b>", "Filter by branch/ref").option("--repo <r>", "Filter by repository").option("--trigger <t>", "Filter by trigger type").option("--source <routingKey>", "Filter by source routing key").option("--since <ts>", "Only runs since (ISO-8601 or epoch ms)").option("--page <n>", "Page number", (v) => parseInt(v, 10)).option("--json", "Output raw JSON", false).action(async (options) => {
|
|
204
214
|
const { runsListCommand } = await import("./commands/index.js");
|
|
@@ -295,7 +305,7 @@ Environment variables:
|
|
|
295
305
|
const success = await drainWorkerCommand({ url: options.url });
|
|
296
306
|
process.exit(success ? 0 : 1);
|
|
297
307
|
});
|
|
298
|
-
program.command("verify-attestation").argument("[artifact]", "Artifact path to digest-check against the attestation subject (optional)").description("Verify a KiCI provenance attestation bundle offline").option("--bundle <path>", "Path or URL to the attestation bundle JSON").option("--trust-root <url-or-file>", "Trusted issuer URL, or a self-contained { issuer, jwks } file").option("--audience <aud>", "Expected token audience").option("--json", "Output structured JSON result", false).action(async (artifact, options) => {
|
|
308
|
+
program.command("verify-attestation").argument("[artifact]", "Artifact path to digest-check against the attestation subject (optional)").description("Verify a KiCI provenance attestation bundle offline").option("--bundle <path>", "Path or URL to the attestation bundle JSON").option("--trust-root <url-or-file>", "Trusted issuer URL, or a self-contained { issuer, jwks } file (default: hosted KiCI platform)").option("--audience <aud>", "Expected token audience").option("--json", "Output structured JSON result", false).action(async (artifact, options) => {
|
|
299
309
|
const { verifyAttestationCommand } = await import("./commands/index.js");
|
|
300
310
|
const success = await verifyAttestationCommand(artifact, options);
|
|
301
311
|
process.exit(success ? 0 : 1);
|
package/dist/commands/index.d.ts
CHANGED
|
@@ -3,8 +3,8 @@ export type { CompileOptions } from './compile.js';
|
|
|
3
3
|
export { watchCommand } from './watch.js';
|
|
4
4
|
export { fixtureCommand } from './fixture.js';
|
|
5
5
|
export type { FixtureOptions } from './fixture.js';
|
|
6
|
-
export {
|
|
7
|
-
export type {
|
|
6
|
+
export { previewCommand, previewEvent } from './preview.js';
|
|
7
|
+
export type { PreviewOptions, RemoteRunOptions, RemoteRunResult } from './preview.js';
|
|
8
8
|
export { runLocalCommand, runRemoteCommand } from './run.js';
|
|
9
9
|
export { initCommand } from './init.js';
|
|
10
10
|
export type { InitOptions } from './init.js';
|
|
@@ -14,6 +14,8 @@ export { loginCommand } from './login.js';
|
|
|
14
14
|
export type { LoginOptions } from './login.js';
|
|
15
15
|
export { secretsListCommand } from './secrets-list.js';
|
|
16
16
|
export type { SecretsListOptions } from './secrets-list.js';
|
|
17
|
+
export { patCreateCommand } from './pat.js';
|
|
18
|
+
export type { PatCreateOptions } from './pat.js';
|
|
17
19
|
export { runsListCommand } from './runs/list.js';
|
|
18
20
|
export type { RunsListOptions } from './runs/list.js';
|
|
19
21
|
export { runsShowCommand } from './runs/show.js';
|
package/dist/commands/index.js
CHANGED
|
@@ -8,11 +8,12 @@ import { endpointsCommand } from "./endpoints.js";
|
|
|
8
8
|
import { fixtureCommand } from "./fixture.js";
|
|
9
9
|
import { hookInstallCommand } from "./hook.js";
|
|
10
10
|
import { watchCommand } from "./watch.js";
|
|
11
|
-
import {
|
|
11
|
+
import { previewCommand, previewEvent } from "./preview.js";
|
|
12
12
|
import { runLocalCommand, runRemoteCommand } from "./run.js";
|
|
13
13
|
import { initCommand } from "./init.js";
|
|
14
14
|
import { loginCommand } from "./login.js";
|
|
15
15
|
import { secretsListCommand } from "./secrets-list.js";
|
|
16
|
+
import { patCreateCommand } from "./pat.js";
|
|
16
17
|
import { runsListCommand } from "./runs/list.js";
|
|
17
18
|
import { runsShowCommand } from "./runs/show.js";
|
|
18
19
|
import { runsLogsCommand } from "./runs/logs.js";
|
|
@@ -25,4 +26,4 @@ import { logoutCommand } from "./logout.js";
|
|
|
25
26
|
import { rejectCommand } from "./reject.js";
|
|
26
27
|
import { workflowsListCommand } from "./workflows.js";
|
|
27
28
|
import { verifyAttestationCommand } from "./verify-attestation.js";
|
|
28
|
-
export { approveCommand, compileCommand, diagnosticsCommand, docsCommand, docsLlmCommand, drainWorkerCommand, endpointsCommand, fixtureCommand, hookInstallCommand, initCommand, loginCommand, logoutCommand, orchestratorsListCommand, orchestratorsUseCommand, orgCurrentCommand, orgListCommand, orgUseCommand, rejectCommand, runLocalCommand, runRemoteCommand, runsCancelCommand, runsListCommand, runsLogsCommand, runsRerunCommand, runsShowCommand, secretsListCommand,
|
|
29
|
+
export { approveCommand, compileCommand, diagnosticsCommand, docsCommand, docsLlmCommand, drainWorkerCommand, endpointsCommand, fixtureCommand, hookInstallCommand, initCommand, loginCommand, logoutCommand, orchestratorsListCommand, orchestratorsUseCommand, orgCurrentCommand, orgListCommand, orgUseCommand, patCreateCommand, previewCommand, previewEvent, rejectCommand, runLocalCommand, runRemoteCommand, runsCancelCommand, runsListCommand, runsLogsCommand, runsRerunCommand, runsShowCommand, secretsListCommand, typesCommand, verifyAttestationCommand, watchCommand, workflowsListCommand };
|
package/dist/commands/init.js
CHANGED
|
@@ -117,10 +117,10 @@ async function initCommand(options = {}) {
|
|
|
117
117
|
logger.info(pc.gray(" 1. Edit workflows in .kici/workflows/"));
|
|
118
118
|
if (options.mjs || options.skipInstall) {
|
|
119
119
|
logger.info(pc.gray(" 2. Run your package manager install in .kici/ to generate a lockfile"));
|
|
120
|
-
logger.info(pc.gray(" 3.
|
|
120
|
+
logger.info(pc.gray(" 3. Preview matching: kici preview push"));
|
|
121
121
|
logger.info(pc.gray(" 4. Commit .kici/ to your repository\n"));
|
|
122
122
|
} else {
|
|
123
|
-
logger.info(pc.gray(" 2.
|
|
123
|
+
logger.info(pc.gray(" 2. Preview matching: kici preview push"));
|
|
124
124
|
logger.info(pc.gray(" 3. Commit .kici/ to your repository\n"));
|
|
125
125
|
}
|
|
126
126
|
return true;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export interface PatCreateOptions {
|
|
2
|
+
/** Token name shown in the dashboard PAT list. Defaults to the agent label. */
|
|
3
|
+
name?: string;
|
|
4
|
+
/** Mint an agent-kind PAT (the only credential the developer MCP server accepts). */
|
|
5
|
+
agent?: boolean;
|
|
6
|
+
/**
|
|
7
|
+
* Agent label (required with `--agent`) — the human-set name recorded on every
|
|
8
|
+
* audit row the agent produces. Also used as the token name when `--name` is
|
|
9
|
+
* omitted.
|
|
10
|
+
*/
|
|
11
|
+
label?: string;
|
|
12
|
+
/** Custom expiry in days (server default: 120). */
|
|
13
|
+
expiresInDays?: number;
|
|
14
|
+
/** Injected fetch for tests. Defaults to the global fetch. */
|
|
15
|
+
fetchImpl?: typeof fetch;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Mint a personal access token under the logged-in user's identity.
|
|
19
|
+
*
|
|
20
|
+
* `kici pat create --agent --name <label>` mints an agent-kind PAT: it inherits
|
|
21
|
+
* the user's permissions (provenance only, no authority change), carries its
|
|
22
|
+
* label into every audit row, and is the credential a coding agent points the
|
|
23
|
+
* KiCI developer MCP server at. The token is printed once — there is no way to
|
|
24
|
+
* retrieve it later.
|
|
25
|
+
*/
|
|
26
|
+
export declare function patCreateCommand(options?: PatCreateOptions): Promise<boolean>;
|
|
27
|
+
//# sourceMappingURL=pat.d.ts.map
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import "../chunk-BTugEXQM.js";
|
|
2
|
+
import { loadGlobalConfig } from "../remote/config.js";
|
|
3
|
+
import pc from "picocolors";
|
|
4
|
+
import { toErrorMessage } from "@kici-dev/core";
|
|
5
|
+
import { PatKind } from "@kici-dev/engine";
|
|
6
|
+
//#region src/commands/pat.ts
|
|
7
|
+
/**
|
|
8
|
+
* Mint a personal access token under the logged-in user's identity.
|
|
9
|
+
*
|
|
10
|
+
* `kici pat create --agent --name <label>` mints an agent-kind PAT: it inherits
|
|
11
|
+
* the user's permissions (provenance only, no authority change), carries its
|
|
12
|
+
* label into every audit row, and is the credential a coding agent points the
|
|
13
|
+
* KiCI developer MCP server at. The token is printed once — there is no way to
|
|
14
|
+
* retrieve it later.
|
|
15
|
+
*/
|
|
16
|
+
async function patCreateCommand(options = {}) {
|
|
17
|
+
const doFetch = options.fetchImpl ?? fetch;
|
|
18
|
+
try {
|
|
19
|
+
const config = await loadGlobalConfig();
|
|
20
|
+
const token = config.pat ?? config.token;
|
|
21
|
+
const endpoint = config.platformEndpoint ?? config.endpoint;
|
|
22
|
+
if (!token || !endpoint) {
|
|
23
|
+
console.error(pc.red("Not logged in. Run `kici login` first."));
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
const kind = options.agent ? PatKind.enum.agent : PatKind.enum.user;
|
|
27
|
+
const label = options.label;
|
|
28
|
+
if (kind === PatKind.enum.agent && !label) {
|
|
29
|
+
console.error(pc.red("An agent PAT requires a label. Pass --name <label>."));
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
const name = options.name ?? label;
|
|
33
|
+
if (!name) {
|
|
34
|
+
console.error(pc.red("A token name is required. Pass --name <name>."));
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
const body = {
|
|
38
|
+
name,
|
|
39
|
+
kind
|
|
40
|
+
};
|
|
41
|
+
if (kind === PatKind.enum.agent) body.agentLabel = label;
|
|
42
|
+
if (options.expiresInDays !== void 0) body.expiresInDays = options.expiresInDays;
|
|
43
|
+
const res = await doFetch(`${endpoint.replace(/\/$/, "")}/api/v1/pats`, {
|
|
44
|
+
method: "POST",
|
|
45
|
+
headers: {
|
|
46
|
+
"Content-Type": "application/json",
|
|
47
|
+
Authorization: `Bearer ${token}`
|
|
48
|
+
},
|
|
49
|
+
body: JSON.stringify(body)
|
|
50
|
+
});
|
|
51
|
+
if (!res.ok) {
|
|
52
|
+
let detail;
|
|
53
|
+
try {
|
|
54
|
+
detail = (await res.json()).error;
|
|
55
|
+
} catch {}
|
|
56
|
+
console.error(pc.red(`Failed to create token (${res.status}): ${detail ?? "request failed"}`));
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
const created = await res.json();
|
|
60
|
+
console.log(pc.bold(kind === PatKind.enum.agent ? "\nAgent PAT created.\n" : "\nPAT created.\n"));
|
|
61
|
+
console.log(`${pc.gray("Name: ")}${created.name}`);
|
|
62
|
+
if (kind === PatKind.enum.agent) console.log(`${pc.gray("Agent: ")}${label}`);
|
|
63
|
+
console.log(`${pc.gray("Expires:")} ${created.expiresAt}`);
|
|
64
|
+
console.log(`\n${pc.gray("Token (shown once — save it now):")}`);
|
|
65
|
+
console.log(pc.cyan(created.token));
|
|
66
|
+
if (kind === PatKind.enum.agent) console.log(pc.gray("\nPoint your coding agent at the KiCI MCP server with this token as the Bearer credential."));
|
|
67
|
+
return true;
|
|
68
|
+
} catch (err) {
|
|
69
|
+
console.error(pc.red(`Failed to create token: ${toErrorMessage(err)}`));
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
//#endregion
|
|
74
|
+
export { patCreateCommand };
|
|
75
|
+
|
|
76
|
+
//# sourceMappingURL=pat.js.map
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { type PayloadOptions } from '../test-runner/payload-builder.js';
|
|
2
|
+
import { type CheckMode } from '@kici-dev/engine';
|
|
3
|
+
/** Options for the kici preview command (dry-run trigger preview) */
|
|
4
|
+
export interface PreviewOptions extends PayloadOptions {
|
|
5
|
+
/** Filter to specific workflow */
|
|
6
|
+
workflow?: string;
|
|
7
|
+
/** Filter to specific job */
|
|
8
|
+
job?: string;
|
|
9
|
+
/** Enable debug output */
|
|
10
|
+
debug?: boolean;
|
|
11
|
+
/** Path to .kici directory (defaults to .kici) */
|
|
12
|
+
kiciDir?: string;
|
|
13
|
+
/** Flat secret overrides: KEY=VALUE */
|
|
14
|
+
secret?: string[];
|
|
15
|
+
/** Context secret overrides: contextName.KEY=VALUE */
|
|
16
|
+
context?: string[];
|
|
17
|
+
}
|
|
18
|
+
/** Options for the kici run remote command */
|
|
19
|
+
export interface RemoteRunOptions extends PreviewOptions {
|
|
20
|
+
/** Run all available fixtures */
|
|
21
|
+
all?: boolean;
|
|
22
|
+
/** Interactively pick fixtures to run (multi-select checkbox). */
|
|
23
|
+
pick?: boolean;
|
|
24
|
+
/** Run matching fixtures concurrently */
|
|
25
|
+
parallel?: boolean;
|
|
26
|
+
/** Fire and forget (print runIds, don't stream) */
|
|
27
|
+
wait?: boolean;
|
|
28
|
+
/** Suppress output except final result */
|
|
29
|
+
quiet?: boolean;
|
|
30
|
+
/** Output structured JSON result */
|
|
31
|
+
json?: boolean;
|
|
32
|
+
/** Output JUnit XML result */
|
|
33
|
+
junit?: string;
|
|
34
|
+
/** Override routing key for this run */
|
|
35
|
+
routingKey?: string;
|
|
36
|
+
/** Show recent run history */
|
|
37
|
+
history?: boolean;
|
|
38
|
+
/** --env KEY=VALUE flag values, uploaded as per-run secrets. */
|
|
39
|
+
envFlags?: string[];
|
|
40
|
+
/** Target organization id (overrides config.activeOrgId). */
|
|
41
|
+
org?: string;
|
|
42
|
+
/** Target orchestrator cluster name (overrides the per-org default). */
|
|
43
|
+
orchestrator?: string;
|
|
44
|
+
/**
|
|
45
|
+
* Run mode resolved from --check / --fail-on-drift, threaded onto the dispatch
|
|
46
|
+
* payload so the orchestrator runs the agent step loop in the requested mode.
|
|
47
|
+
* Defaults to `apply`.
|
|
48
|
+
*/
|
|
49
|
+
checkMode?: CheckMode;
|
|
50
|
+
/** `--target <selector>` values (repeatable), AND-combined into host narrowing. */
|
|
51
|
+
targets?: string[];
|
|
52
|
+
/** `--target-allow-empty`: a target that zeroes a runsOnAll job skips it instead of failing. */
|
|
53
|
+
targetAllowEmpty?: boolean;
|
|
54
|
+
/**
|
|
55
|
+
* `--approve-all` (alias `--yes`): auto-approve every approval gate this run
|
|
56
|
+
* holds on (run-scoped only — the run id this invocation dispatched). The
|
|
57
|
+
* operator must still be clause-eligible per hold; an ineligible hold blocks.
|
|
58
|
+
*/
|
|
59
|
+
approveAll?: boolean;
|
|
60
|
+
/** `--input KEY=VALUE` values (repeatable): typed workflow-dispatch inputs. */
|
|
61
|
+
inputs?: string[];
|
|
62
|
+
}
|
|
63
|
+
/** Result of a single remote fixture run */
|
|
64
|
+
export interface RemoteRunResult {
|
|
65
|
+
fixtureId: string;
|
|
66
|
+
runId: string;
|
|
67
|
+
status: 'accepted' | 'rejected' | 'success' | 'failed' | 'cancelled' | 'error';
|
|
68
|
+
reason?: string;
|
|
69
|
+
observeUrl?: string;
|
|
70
|
+
durationMs?: number;
|
|
71
|
+
jobs?: Array<{
|
|
72
|
+
name: string;
|
|
73
|
+
status: string;
|
|
74
|
+
durationMs?: number;
|
|
75
|
+
}>;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Main preview command entry point.
|
|
79
|
+
*
|
|
80
|
+
* `kici preview <event>` is a dry-run trigger preview only — it executes nothing.
|
|
81
|
+
* If the argument looks like a fixture name (not a known event type), prints a migration message.
|
|
82
|
+
*/
|
|
83
|
+
export declare function previewCommand(event: string | undefined, options: PreviewOptions): Promise<boolean>;
|
|
84
|
+
/**
|
|
85
|
+
* Local-only dry-run mode: compile workflows, match triggers, display what would execute.
|
|
86
|
+
*/
|
|
87
|
+
export declare function previewEvent(event: string, options: PreviewOptions): Promise<boolean>;
|
|
88
|
+
//# sourceMappingURL=preview.d.ts.map
|
|
@@ -9,30 +9,31 @@ import { loadSecretsFile } from "../test-runner/secrets-file.js";
|
|
|
9
9
|
import path from "node:path";
|
|
10
10
|
import pc from "picocolors";
|
|
11
11
|
import { readFile } from "node:fs/promises";
|
|
12
|
+
import { flattenStepInputs } from "@kici-dev/sdk";
|
|
12
13
|
import { logger, toErrorMessage } from "@kici-dev/core";
|
|
13
14
|
import { matchAllWorkflows } from "@kici-dev/engine";
|
|
14
15
|
import { normalizeRunsOnToMatchers } from "@kici-dev/engine/labels/compile";
|
|
15
|
-
//#region src/commands/
|
|
16
|
+
//#region src/commands/preview.ts
|
|
16
17
|
/**
|
|
17
|
-
* Main
|
|
18
|
+
* Main preview command entry point.
|
|
18
19
|
*
|
|
19
|
-
* `kici
|
|
20
|
+
* `kici preview <event>` is a dry-run trigger preview only — it executes nothing.
|
|
20
21
|
* If the argument looks like a fixture name (not a known event type), prints a migration message.
|
|
21
22
|
*/
|
|
22
|
-
async function
|
|
23
|
+
async function previewCommand(event, options) {
|
|
23
24
|
if (options.debug) {
|
|
24
25
|
process.env.KICI_DEBUG = "true";
|
|
25
26
|
logger.info(pc.gray("Debug mode enabled"));
|
|
26
27
|
}
|
|
27
28
|
try {
|
|
28
29
|
if (!event) {
|
|
29
|
-
logger.info(pc.bold("\nUsage: kici
|
|
30
|
+
logger.info(pc.bold("\nUsage: kici preview <event>\n"));
|
|
30
31
|
logger.info(pc.gray("Preview which workflows and jobs would run for a given event.\n"));
|
|
31
32
|
logger.info(pc.gray("Examples:"));
|
|
32
|
-
logger.info(pc.gray(" kici
|
|
33
|
-
logger.info(pc.gray(" kici
|
|
34
|
-
logger.info(pc.gray(" kici
|
|
35
|
-
logger.info(pc.gray(" kici
|
|
33
|
+
logger.info(pc.gray(" kici preview push"));
|
|
34
|
+
logger.info(pc.gray(" kici preview pr:open"));
|
|
35
|
+
logger.info(pc.gray(" kici preview schedule"));
|
|
36
|
+
logger.info(pc.gray(" kici preview lifecycle:workflow_complete\n"));
|
|
36
37
|
logger.info(pc.gray("For remote fixture execution, use: kici run remote [fixture] [options]"));
|
|
37
38
|
logger.info(pc.gray("For local workflow execution, use: kici run local <event> [options]\n"));
|
|
38
39
|
return true;
|
|
@@ -41,7 +42,7 @@ async function testCommand(event, options) {
|
|
|
41
42
|
logger.info(pc.yellow(`\nFixture-based testing has moved to \`kici run remote\`.\nRun \`kici run remote ${event}\` instead.\n`));
|
|
42
43
|
return false;
|
|
43
44
|
}
|
|
44
|
-
return await
|
|
45
|
+
return await previewEvent(event, options);
|
|
45
46
|
} catch (error) {
|
|
46
47
|
const message = toErrorMessage(error);
|
|
47
48
|
logger.error(pc.red(`\nError: ${message}\n`));
|
|
@@ -64,7 +65,7 @@ function isKnownEventArg(arg) {
|
|
|
64
65
|
/**
|
|
65
66
|
* Local-only dry-run mode: compile workflows, match triggers, display what would execute.
|
|
66
67
|
*/
|
|
67
|
-
async function
|
|
68
|
+
async function previewEvent(event, options) {
|
|
68
69
|
try {
|
|
69
70
|
const kiciDir = resolveKiciDir(options.kiciDir);
|
|
70
71
|
logger.info(pc.gray(`KiCI directory: ${kiciDir}`));
|
|
@@ -144,7 +145,7 @@ function workflowsToLockFormat(workflows) {
|
|
|
144
145
|
if ("group" in n) return `__group:${n.group}`;
|
|
145
146
|
return n.name;
|
|
146
147
|
}) ?? [],
|
|
147
|
-
steps: j.steps.map((s) => {
|
|
148
|
+
steps: flattenStepInputs(j.steps).map((s) => {
|
|
148
149
|
if (typeof s === "function") return {
|
|
149
150
|
name: "",
|
|
150
151
|
hasOutputs: false
|
|
@@ -213,6 +214,6 @@ async function loadTestSecrets(kiciDir, secretFlags, contextFlags) {
|
|
|
213
214
|
return secrets;
|
|
214
215
|
}
|
|
215
216
|
//#endregion
|
|
216
|
-
export {
|
|
217
|
+
export { previewCommand, previewEvent };
|
|
217
218
|
|
|
218
|
-
//# sourceMappingURL=
|
|
219
|
+
//# sourceMappingURL=preview.js.map
|
package/dist/commands/run.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
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
|
|
@@ -23,6 +23,16 @@ export declare function lookupDispatchInputsDescriptor(inlineLockFile: string |
|
|
|
23
23
|
* authoritative and applies coercion + defaults exactly once.
|
|
24
24
|
*/
|
|
25
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>;
|
|
26
36
|
/**
|
|
27
37
|
* Run a workflow locally using the local executor.
|
|
28
38
|
* Thin wrapper that delegates to executeLocal from local-executor.
|
package/dist/commands/run.js
CHANGED
|
@@ -3,6 +3,7 @@ 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";
|
|
@@ -90,6 +91,24 @@ function buildDispatchInputs(pairs, descriptor) {
|
|
|
90
91
|
/** Interval between status/log polls while a run is active. */
|
|
91
92
|
const POLL_INTERVAL_MS = 750;
|
|
92
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
|
+
/**
|
|
93
112
|
* Recompile `.kici/workflows` → `kici.lock.json` before a remote run, mirroring
|
|
94
113
|
* `kici run local`. The orchestrator matches triggers and dispatches against the
|
|
95
114
|
* inline lock, so a stale lock would route an edited or newly-added workflow
|
|
@@ -97,12 +116,14 @@ const POLL_INTERVAL_MS = 750;
|
|
|
97
116
|
* abort before any upload or dispatch.
|
|
98
117
|
*/
|
|
99
118
|
async function compileBeforeRemoteRun(options) {
|
|
100
|
-
|
|
119
|
+
const pureStdout = Boolean(options.json || options.quiet);
|
|
120
|
+
const compile = () => compileCommand({
|
|
101
121
|
kiciDir: options.kiciDir ?? ".kici",
|
|
102
122
|
check: false,
|
|
103
123
|
verbose: options.debug ?? false,
|
|
104
|
-
quiet:
|
|
124
|
+
quiet: pureStdout
|
|
105
125
|
});
|
|
126
|
+
return pureStdout ? withStdoutOnStderr(compile) : compile();
|
|
106
127
|
}
|
|
107
128
|
/**
|
|
108
129
|
* Run a workflow locally using the local executor.
|
|
@@ -148,7 +169,8 @@ async function runRemoteCommand(fixture, options) {
|
|
|
148
169
|
console.log(history.formatTable(entries));
|
|
149
170
|
return true;
|
|
150
171
|
}
|
|
151
|
-
const
|
|
172
|
+
const testsDir = path.join(kiciDir, "tests");
|
|
173
|
+
const fixtures = options.json ? await withStdoutOnStderr(() => compileFixtures(testsDir)) : await compileFixtures(testsDir);
|
|
152
174
|
let selected;
|
|
153
175
|
if (options.pick) {
|
|
154
176
|
if (fixtures.length === 0) return listFixtures(fixtures);
|
|
@@ -355,11 +377,12 @@ async function runSingleFixture(fixture, ctx, options, config, history) {
|
|
|
355
377
|
const uploaded = await initAndUpload(ctx, overlay, options);
|
|
356
378
|
const event = buildEventFromFixture(opts);
|
|
357
379
|
{
|
|
358
|
-
const
|
|
380
|
+
const identity = buildLocalRepoIdentity(overlay.repoRoot);
|
|
359
381
|
const repo = event.payload.repository;
|
|
360
382
|
event.payload.repository = {
|
|
361
383
|
...repo ?? {},
|
|
362
|
-
full_name:
|
|
384
|
+
full_name: identity.repoIdentifier,
|
|
385
|
+
provider: identity.provider
|
|
363
386
|
};
|
|
364
387
|
}
|
|
365
388
|
if (!options.quiet) logger.info(pc.gray("Triggering test run..."));
|
|
@@ -589,7 +612,11 @@ async function runDirectWorkflow(workflowName, options) {
|
|
|
589
612
|
try {
|
|
590
613
|
const overlay = await prepareOverlay(options);
|
|
591
614
|
const uploaded = await initAndUpload(ctx, overlay, options);
|
|
592
|
-
const
|
|
615
|
+
const identity = buildLocalRepoIdentity(overlay.repoRoot);
|
|
616
|
+
const payload = { repository: {
|
|
617
|
+
full_name: identity.repoIdentifier,
|
|
618
|
+
provider: identity.provider
|
|
619
|
+
} };
|
|
593
620
|
const encrypted = await buildEncryptedSecrets(overlay.kiciDir, options.envFlags, options.context, uploaded.publicKey);
|
|
594
621
|
const triggerResult = await ctx.client.trigger(ctx.orgId, ctx.target, {
|
|
595
622
|
fixtureId,
|
|
@@ -644,6 +671,6 @@ function displayRemoteResults(results) {
|
|
|
644
671
|
logger.info("");
|
|
645
672
|
}
|
|
646
673
|
//#endregion
|
|
647
|
-
export { buildDispatchInputs, buildTargetSelector, lookupDispatchInputsDescriptor, runLocalCommand, runRemoteCommand };
|
|
674
|
+
export { buildDispatchInputs, buildTargetSelector, lookupDispatchInputsDescriptor, runLocalCommand, runRemoteCommand, withStdoutOnStderr };
|
|
648
675
|
|
|
649
676
|
//# sourceMappingURL=run.js.map
|
|
@@ -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)
|
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 };
|
|
@@ -376,7 +376,7 @@ Source: https://docs.kici.dev/architecture/data-flows/
|
|
|
376
376
|
|
|
377
377
|
This document describes the key data flows through the KiCI architecture: webhook delivery, job execution, developer-initiated remote runs, dependency caching, re-run and cancel, trace ID propagation, internal event routing, and generic webhook ingestion.
|
|
378
378
|
|
|
379
|
-
> **Lock file schema version:** The lock file uses schema version
|
|
379
|
+
> **Lock file schema version:** The lock file uses schema version 29. The orchestrator rejects any fetched lock whose `schemaVersion` does not exactly match the engine version it was built against, so a stale lock must be recompiled with `kici compile` and pushed again after any SDK upgrade that bumps the schema.
|
|
380
380
|
|
|
381
381
|
## Webhook delivery flow
|
|
382
382
|
|
|
@@ -582,7 +582,7 @@ Dep cache misses alone do **not** trigger a build job. Deps are platform-specifi
|
|
|
582
582
|
|
|
583
583
|
### Cross-source / no-contentHash workflows
|
|
584
584
|
|
|
585
|
-
- **Lock files without `contentHash`** (schema v1) skip the source cache entirely; agents compile from source. Regenerate lock files with `kici compile` to enable caching. The current lock file schema version is
|
|
585
|
+
- **Lock files without `contentHash`** (schema v1) skip the source cache entirely; agents compile from source. Regenerate lock files with `kici compile` to enable caching. The current lock file schema version is 29.
|
|
586
586
|
- **Cross-source / global-workflow dispatch** (a workflow registered against source A fired by a webhook on source B) bypasses both caches. The registration's lock file entry still carries `contentHash`, but the cross-source path always clone-and-installs — the eval temp dir doesn't ship `@kici-dev/sdk`. The execution agent still verifies `contentHash` against the cloned source for drift detection.
|
|
587
587
|
|
|
588
588
|
### Build deduplication
|
|
@@ -1150,7 +1150,7 @@ The compiler processes the workflow definition:
|
|
|
1150
1150
|
|
|
1151
1151
|
### Execution time (local test runner)
|
|
1152
1152
|
|
|
1153
|
-
When `kici
|
|
1153
|
+
When `kici run local` runs a workflow:
|
|
1154
1154
|
|
|
1155
1155
|
1. **SDK module resolution:** The runner resolves `setStepOutputsMap` / `setJobOutputsMap` from the same `@kici-dev/sdk` module instance that the workflow uses (ensures the proxy reads from the same map)
|
|
1156
1156
|
2. **Map injection:** Fresh `OutputsMap` and `StepRefMap` are created and injected via `setStepOutputsMap()` / `setStepRefMap()` before each job
|