@kici-dev/compiler 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/auth/headless-detect.d.ts +14 -5
- package/dist/auth/headless-detect.js +50 -9
- package/dist/cli-banner.d.ts +6 -3
- package/dist/cli-banner.js +13 -5
- package/dist/cli.js +180 -48
- package/dist/commands/check-mode.d.ts +1 -1
- package/dist/commands/compile.js +31 -7
- package/dist/commands/diagnostics.js +14 -2
- package/dist/commands/doctor.d.ts +64 -0
- package/dist/commands/doctor.js +413 -0
- package/dist/commands/endpoints.js +6 -0
- package/dist/commands/fixture.js +13 -0
- package/dist/commands/hook.js +3 -2
- package/dist/commands/index.d.ts +13 -1
- package/dist/commands/index.js +10 -3
- package/dist/commands/init-host-os.d.ts +34 -0
- package/dist/commands/init-host-os.js +44 -0
- package/dist/commands/init.d.ts +4 -0
- package/dist/commands/init.js +160 -37
- package/dist/commands/local-trust-root.d.ts +6 -0
- package/dist/commands/local-trust-root.js +52 -0
- package/dist/commands/local.d.ts +65 -0
- package/dist/commands/local.js +206 -0
- package/dist/commands/login.d.ts +2 -0
- package/dist/commands/login.js +41 -1
- package/dist/commands/logout.js +7 -0
- package/dist/commands/notifications.d.ts +61 -0
- package/dist/commands/notifications.js +274 -0
- package/dist/commands/preview.js +9 -2
- package/dist/commands/run-banner.d.ts +31 -0
- package/dist/commands/run-banner.js +25 -0
- package/dist/commands/run-routed.d.ts +53 -0
- package/dist/commands/run-routed.js +185 -0
- package/dist/commands/run.d.ts +0 -17
- package/dist/commands/run.js +44 -58
- package/dist/commands/runs/artifacts/download.d.ts +24 -0
- package/dist/commands/runs/artifacts/download.js +154 -0
- package/dist/commands/runs/artifacts/list.d.ts +5 -0
- package/dist/commands/runs/artifacts/list.js +47 -0
- package/dist/commands/runs/cancel.js +2 -2
- package/dist/commands/runs/list.js +8 -2
- package/dist/commands/secrets-list.d.ts +2 -2
- package/dist/commands/secrets-list.js +4 -4
- package/dist/commands/types.d.ts +3 -3
- package/dist/commands/types.js +4 -4
- package/dist/commands/verify-attestation.d.ts +3 -1
- package/dist/commands/verify-attestation.js +18 -7
- package/dist/errors/formatter.d.ts +14 -1
- package/dist/errors/formatter.js +13 -3
- package/dist/errors/index.d.ts +2 -1
- package/dist/errors/index.js +3 -2
- package/dist/errors/source-location.d.ts +20 -0
- package/dist/errors/source-location.js +45 -0
- package/dist/execution/executor.js +32 -12
- package/dist/fixtures/defaults/index.js +2 -1
- package/dist/generators/secrets-dts.d.ts +9 -9
- package/dist/generators/secrets-dts.js +12 -12
- package/dist/llm-context/llms-architecture.txt +50 -21
- package/dist/llm-context/llms-cli.txt +2667 -1454
- package/dist/llm-context/llms-features.txt +484 -414
- package/dist/llm-context/llms-full.txt +6703 -4687
- package/dist/llm-context/llms-getting-started.txt +311 -55
- package/dist/llm-context/llms-patterns.txt +17 -29
- package/dist/llm-context/llms-providers.txt +10 -1
- package/dist/llm-context/llms-sdk-runtime.txt +2013 -0
- package/dist/llm-context/llms-sdk.txt +596 -2157
- package/dist/llm-context/llms.txt +31 -17
- package/dist/local-plane/orchestrator-process.d.ts +70 -0
- package/dist/local-plane/orchestrator-process.js +129 -0
- package/dist/local-plane/os-mismatch-hint.d.ts +16 -0
- package/dist/local-plane/os-mismatch-hint.js +34 -0
- package/dist/local-plane/paths.d.ts +39 -0
- package/dist/local-plane/paths.js +54 -0
- package/dist/local-plane/plane-liveness.d.ts +68 -0
- package/dist/local-plane/plane-liveness.js +145 -0
- package/dist/local-plane/plane-manager.d.ts +193 -0
- package/dist/local-plane/plane-manager.js +480 -0
- package/dist/local-plane/plane-seed.d.ts +76 -0
- package/dist/local-plane/plane-seed.js +59 -0
- package/dist/local-plane/plane-trigger.d.ts +71 -0
- package/dist/local-plane/plane-trigger.js +110 -0
- package/dist/local-plane/platform-attach.d.ts +53 -0
- package/dist/local-plane/platform-attach.js +107 -0
- package/dist/local-plane/port-holder.d.ts +78 -0
- package/dist/local-plane/port-holder.js +227 -0
- package/dist/local-plane/postgres.d.ts +56 -0
- package/dist/local-plane/postgres.js +187 -0
- package/dist/local-plane/resolve-plane.d.ts +37 -0
- package/dist/local-plane/resolve-plane.js +76 -0
- package/dist/local-plane/run-follow.d.ts +61 -0
- package/dist/local-plane/run-follow.js +151 -0
- package/dist/local-plane/scaler-config.d.ts +68 -0
- package/dist/local-plane/scaler-config.js +132 -0
- package/dist/local-plane/secret-seed.d.ts +59 -0
- package/dist/local-plane/secret-seed.js +112 -0
- package/dist/local-plane/source-provider.d.ts +43 -0
- package/dist/local-plane/source-provider.js +159 -0
- package/dist/local-plane/trusted-routing.d.ts +32 -0
- package/dist/local-plane/trusted-routing.js +47 -0
- package/dist/lockfile/generator.d.ts +14 -1
- package/dist/lockfile/generator.js +103 -37
- package/dist/lockfile/index.d.ts +3 -1
- package/dist/lockfile/index.js +3 -2
- package/dist/lockfile/purity-diagnostics.d.ts +31 -0
- package/dist/lockfile/purity-diagnostics.js +52 -0
- package/dist/postinstall.js +2 -1
- package/dist/remote/artifact-extract.d.ts +8 -0
- package/dist/remote/artifact-extract.js +58 -0
- package/dist/remote/config.d.ts +21 -3
- package/dist/remote/config.js +24 -5
- package/dist/remote/dashboard-client.d.ts +46 -9
- package/dist/remote/dashboard-client.js +54 -11
- package/dist/remote/fs-case.d.ts +21 -0
- package/dist/remote/fs-case.js +45 -0
- package/dist/remote/history.d.ts +9 -3
- package/dist/remote/history.js +79 -10
- package/dist/remote/local-repo-identity.d.ts +1 -1
- package/dist/remote/local-repo-identity.js +2 -1
- package/dist/remote/notifications-client.d.ts +149 -0
- package/dist/remote/notifications-client.js +103 -0
- package/dist/remote/oauth.d.ts +13 -0
- package/dist/remote/oauth.js +31 -5
- package/dist/remote/output/summary.js +76 -14
- package/dist/remote/platform-client.d.ts +1 -1
- package/dist/remote/render.js +30 -9
- package/dist/{local-executor → remote}/secret-loader.d.ts +1 -1
- package/dist/{local-executor → remote}/secret-loader.js +4 -4
- package/dist/remote/secret-upload.d.ts +1 -1
- package/dist/remote/secret-upload.js +2 -2
- package/dist/remote/uploader.d.ts +1 -1
- package/dist/remote/uploader.js +7 -6
- package/dist/templates/agents-md.d.ts +1 -1
- package/dist/templates/agents-md.js +8 -8
- package/dist/templates/index.d.ts +1 -1
- package/dist/templates/index.js +2 -2
- package/dist/templates/package-json.d.ts +15 -0
- package/dist/templates/package-json.js +26 -5
- package/dist/test-runner/dry-run.d.ts +2 -1
- package/dist/test-runner/dry-run.js +18 -1
- package/dist/test-runner/event-types.d.ts +2 -0
- package/dist/test-runner/event-types.js +3 -0
- package/dist/test-runner/job-executor.d.ts +1 -0
- package/dist/test-runner/job-executor.js +82 -44
- package/dist/test-runner/output-formatter.d.ts +5 -2
- package/dist/test-runner/output-formatter.js +6 -4
- package/dist/test-runner/payload-builder.d.ts +7 -1
- package/dist/test-runner/payload-builder.js +11 -2
- package/dist/test-runner/rule-evaluator.d.ts +7 -3
- package/dist/test-runner/rule-evaluator.js +13 -12
- package/dist/{local-executor → test-runner}/runs-on-display.js +1 -1
- package/dist/test-runner/step-context.d.ts +23 -5
- package/dist/test-runner/step-context.js +29 -119
- package/dist/types.d.ts +26 -7
- package/dist/types.js +4 -2
- package/dist/validation/index.d.ts +2 -0
- package/dist/validation/index.js +2 -1
- package/dist/validation/typecheck.d.ts +28 -0
- package/dist/validation/typecheck.js +110 -0
- package/dist/validation/validator.d.ts +9 -4
- package/dist/validation/validator.js +38 -44
- package/package.json +13 -13
- package/sbom.spdx.json +9311 -1528
- package/dist/assets/api-TJJVHrjC.json +0 -118
- package/dist/assets/descriptor-BTtjzN9L.json +0 -1382
- package/dist/assets/package-BpQF9kR8.json +0 -74
- package/dist/assets/package-Ceo2h27X.json +0 -89
- package/dist/assets/source_context-D0atuL28.json +0 -20
- package/dist/assets/type-BFqO8SCZ.json +0 -202
- package/dist/commands/cancel.d.ts +0 -22
- package/dist/commands/detect-package-manager.d.ts +0 -42
- package/dist/commands/held-run-resolve.d.ts +0 -50
- package/dist/commands/status.d.ts +0 -34
- package/dist/commands/test.d.ts +0 -88
- package/dist/errors/codes.d.ts +0 -25
- package/dist/local-executor/dag-scheduler.d.ts +0 -44
- package/dist/local-executor/dag-scheduler.js +0 -183
- package/dist/local-executor/index.d.ts +0 -23
- package/dist/local-executor/index.js +0 -378
- package/dist/local-executor/job-runner.d.ts +0 -47
- package/dist/local-executor/job-runner.js +0 -411
- package/dist/local-executor/materializer.d.ts +0 -44
- package/dist/local-executor/materializer.js +0 -132
- package/dist/local-executor/output-streamer.d.ts +0 -31
- package/dist/local-executor/output-streamer.js +0 -168
- package/dist/local-executor/payload-generator.d.ts +0 -16
- package/dist/local-executor/payload-generator.js +0 -138
- package/dist/local-executor/picker.d.ts +0 -33
- package/dist/local-executor/picker.js +0 -109
- package/dist/local-executor/to-event-payload.d.ts +0 -16
- package/dist/local-executor/to-event-payload.js +0 -21
- package/dist/local-executor/types.d.ts +0 -93
- package/dist/local-executor/types.js +0 -2
- package/dist/local-executor/workflow-lock.d.ts +0 -82
- package/dist/local-executor/workflow-lock.js +0 -0
- package/dist/package-F7UXSDHW.json +0 -74
- package/dist/remote/client.d.ts +0 -210
- package/dist/remote/observer.d.ts +0 -81
- package/dist/test-runner/summary.d.ts +0 -7
- /package/dist/{local-executor → test-runner}/runs-on-display.d.ts +0 -0
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
/** Deadline for the WSL interop probe. A healthy probe answers in single-digit ms. */
|
|
2
|
+
export declare const WSL_INTEROP_PROBE_TIMEOUT_MS = 2000;
|
|
1
3
|
/**
|
|
2
4
|
* Detect if the current environment is headless (no browser available).
|
|
3
5
|
*
|
|
@@ -5,10 +7,17 @@
|
|
|
5
7
|
* (desktop) or the RFC 8628 device authorization flow (headless/SSH).
|
|
6
8
|
*
|
|
7
9
|
* Checks in order:
|
|
8
|
-
* 1. SSH session (SSH_CLIENT, SSH_TTY)
|
|
9
|
-
* 2. CI environments
|
|
10
|
-
*
|
|
11
|
-
*
|
|
10
|
+
* 1. SSH session (SSH_CONNECTION, SSH_CLIENT, SSH_TTY)
|
|
11
|
+
* 2. CI environments — see `isCiEnvironment` in `@kici-dev/core/ci-env` for the
|
|
12
|
+
* opt-out convention and why a vendor marker beats `CI=false`.
|
|
13
|
+
* 3. Container environments (container, DOCKER_CONTAINER, and the
|
|
14
|
+
* /run/.containerenv + /.dockerenv sentinel files)
|
|
15
|
+
* 4. WSL with reachable Windows interop — an interactive desktop, so not
|
|
16
|
+
* headless. WSL without reachable interop is headless, and so is WSL whose
|
|
17
|
+
* interop probe does not answer within the deadline (a hung Windows mount).
|
|
18
|
+
* 5. Linux without display server (no DISPLAY and no WAYLAND_DISPLAY)
|
|
12
19
|
*/
|
|
13
|
-
export declare function isHeadless(
|
|
20
|
+
export declare function isHeadless(opts?: {
|
|
21
|
+
probeTimeoutMs?: number;
|
|
22
|
+
}): Promise<boolean>;
|
|
14
23
|
//# sourceMappingURL=headless-detect.d.ts.map
|
|
@@ -1,5 +1,33 @@
|
|
|
1
1
|
import "../rolldown-runtime-ClRpJifh.js";
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
3
|
+
import pc from "picocolors";
|
|
4
|
+
import { isCiEnvironment } from "@kici-dev/core/ci-env";
|
|
5
|
+
import { canAccessPowerShell, isWsl } from "wsl-utils";
|
|
2
6
|
//#region src/auth/headless-detect.ts
|
|
7
|
+
/** Deadline for the WSL interop probe. A healthy probe answers in single-digit ms. */
|
|
8
|
+
const WSL_INTEROP_PROBE_TIMEOUT_MS = 2e3;
|
|
9
|
+
/**
|
|
10
|
+
* Run the Windows-interop probe under a deadline.
|
|
11
|
+
*
|
|
12
|
+
* `canAccessPowerShell()` does unbounded filesystem I/O against the mounted
|
|
13
|
+
* Windows drive: on a wedged 9p mount it never settles, which would strand the
|
|
14
|
+
* caller. The tri-state result lets the caller tell "the probe said
|
|
15
|
+
* unreachable" from "the probe never answered" — only the latter is announced.
|
|
16
|
+
*/
|
|
17
|
+
async function probeWithDeadline(timeoutMs) {
|
|
18
|
+
const probe = canAccessPowerShell();
|
|
19
|
+
probe.catch(() => {});
|
|
20
|
+
let timer;
|
|
21
|
+
const deadline = new Promise((resolve) => {
|
|
22
|
+
timer = setTimeout(() => resolve("timeout"), timeoutMs);
|
|
23
|
+
timer.unref?.();
|
|
24
|
+
});
|
|
25
|
+
try {
|
|
26
|
+
return await Promise.race([probe, deadline]);
|
|
27
|
+
} finally {
|
|
28
|
+
clearTimeout(timer);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
3
31
|
/**
|
|
4
32
|
* Detect if the current environment is headless (no browser available).
|
|
5
33
|
*
|
|
@@ -7,19 +35,32 @@ import "../rolldown-runtime-ClRpJifh.js";
|
|
|
7
35
|
* (desktop) or the RFC 8628 device authorization flow (headless/SSH).
|
|
8
36
|
*
|
|
9
37
|
* Checks in order:
|
|
10
|
-
* 1. SSH session (SSH_CLIENT, SSH_TTY)
|
|
11
|
-
* 2. CI environments
|
|
12
|
-
*
|
|
13
|
-
*
|
|
38
|
+
* 1. SSH session (SSH_CONNECTION, SSH_CLIENT, SSH_TTY)
|
|
39
|
+
* 2. CI environments — see `isCiEnvironment` in `@kici-dev/core/ci-env` for the
|
|
40
|
+
* opt-out convention and why a vendor marker beats `CI=false`.
|
|
41
|
+
* 3. Container environments (container, DOCKER_CONTAINER, and the
|
|
42
|
+
* /run/.containerenv + /.dockerenv sentinel files)
|
|
43
|
+
* 4. WSL with reachable Windows interop — an interactive desktop, so not
|
|
44
|
+
* headless. WSL without reachable interop is headless, and so is WSL whose
|
|
45
|
+
* interop probe does not answer within the deadline (a hung Windows mount).
|
|
46
|
+
* 5. Linux without display server (no DISPLAY and no WAYLAND_DISPLAY)
|
|
14
47
|
*/
|
|
15
|
-
function isHeadless() {
|
|
16
|
-
if (process.env.SSH_CLIENT || process.env.SSH_TTY) return true;
|
|
17
|
-
if (
|
|
18
|
-
if (process.env.container || process.env.DOCKER_CONTAINER) return true;
|
|
48
|
+
async function isHeadless(opts = {}) {
|
|
49
|
+
if (process.env.SSH_CONNECTION || process.env.SSH_CLIENT || process.env.SSH_TTY) return true;
|
|
50
|
+
if (isCiEnvironment()) return true;
|
|
51
|
+
if (process.env.container || process.env.DOCKER_CONTAINER || existsSync("/run/.containerenv") || existsSync("/.dockerenv")) return true;
|
|
52
|
+
if (isWsl) {
|
|
53
|
+
const reachable = await probeWithDeadline(opts.probeTimeoutMs ?? 2e3);
|
|
54
|
+
if (reachable === "timeout") {
|
|
55
|
+
console.log(pc.dim(" Windows interop probe timed out — using the device flow."));
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
return !reachable;
|
|
59
|
+
}
|
|
19
60
|
if (process.platform === "linux" && !process.env.DISPLAY && !process.env.WAYLAND_DISPLAY) return true;
|
|
20
61
|
return false;
|
|
21
62
|
}
|
|
22
63
|
//#endregion
|
|
23
|
-
export { isHeadless };
|
|
64
|
+
export { WSL_INTEROP_PROBE_TIMEOUT_MS, isHeadless };
|
|
24
65
|
|
|
25
66
|
//# sourceMappingURL=headless-detect.js.map
|
package/dist/cli-banner.d.ts
CHANGED
|
@@ -3,9 +3,12 @@ import type { Command } from 'commander';
|
|
|
3
3
|
* Whether the version banner should be suppressed for the command about to run.
|
|
4
4
|
*
|
|
5
5
|
* Structured-output (`--json`) and quiet (`--quiet`) invocations must keep stdout
|
|
6
|
-
* free of human-facing chrome so callers can parse stdout directly.
|
|
7
|
-
*
|
|
8
|
-
*
|
|
6
|
+
* free of human-facing chrome so callers can parse stdout directly. Walks the
|
|
7
|
+
* command chain checking each command's OWN opts (not `optsWithGlobals()`): a
|
|
8
|
+
* flag set anywhere in the chain suppresses the banner, and reading own opts
|
|
9
|
+
* avoids a parent's default value shadowing a subcommand's explicit flag —
|
|
10
|
+
* `kici run` defines `--quiet` for its routed action, which under
|
|
11
|
+
* `optsWithGlobals()` would mask `kici run remote --quiet`.
|
|
9
12
|
*/
|
|
10
13
|
export declare function shouldSuppressBanner(actionCommand: Command): boolean;
|
|
11
14
|
//# sourceMappingURL=cli-banner.d.ts.map
|
package/dist/cli-banner.js
CHANGED
|
@@ -4,13 +4,21 @@ import "./rolldown-runtime-ClRpJifh.js";
|
|
|
4
4
|
* Whether the version banner should be suppressed for the command about to run.
|
|
5
5
|
*
|
|
6
6
|
* Structured-output (`--json`) and quiet (`--quiet`) invocations must keep stdout
|
|
7
|
-
* free of human-facing chrome so callers can parse stdout directly.
|
|
8
|
-
*
|
|
9
|
-
*
|
|
7
|
+
* free of human-facing chrome so callers can parse stdout directly. Walks the
|
|
8
|
+
* command chain checking each command's OWN opts (not `optsWithGlobals()`): a
|
|
9
|
+
* flag set anywhere in the chain suppresses the banner, and reading own opts
|
|
10
|
+
* avoids a parent's default value shadowing a subcommand's explicit flag —
|
|
11
|
+
* `kici run` defines `--quiet` for its routed action, which under
|
|
12
|
+
* `optsWithGlobals()` would mask `kici run remote --quiet`.
|
|
10
13
|
*/
|
|
11
14
|
function shouldSuppressBanner(actionCommand) {
|
|
12
|
-
|
|
13
|
-
|
|
15
|
+
let cmd = actionCommand;
|
|
16
|
+
while (cmd) {
|
|
17
|
+
const opts = cmd.opts();
|
|
18
|
+
if (opts.json === true || opts.quiet === true) return true;
|
|
19
|
+
cmd = cmd.parent;
|
|
20
|
+
}
|
|
21
|
+
return false;
|
|
14
22
|
}
|
|
15
23
|
//#endregion
|
|
16
24
|
export { shouldSuppressBanner };
|
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.
|
|
10
|
+
const version = "0.2.0";
|
|
11
11
|
/**
|
|
12
12
|
* Top-level commands that were removed, mapped to their current equivalent.
|
|
13
13
|
* Consulted when the CLI hits an unknown command so the user gets a precise
|
|
@@ -16,7 +16,8 @@ const version = "0.1.26";
|
|
|
16
16
|
*/
|
|
17
17
|
const RETIRED_COMMANDS = {
|
|
18
18
|
status: "`kici status` is no longer a command. Use `kici runs list` / `kici runs show <run-id>` to inspect runs, or `kici diagnostics` for orchestrator, scaler, and agent health.",
|
|
19
|
-
cancel: "`kici cancel` is no longer a command. Use `kici runs cancel <run-id>`."
|
|
19
|
+
cancel: "`kici cancel` is no longer a command. Use `kici runs cancel <run-id>`.",
|
|
20
|
+
"run local": "`kici run local` is retired. Every run is now a real routed dispatch — use `kici run <event> --local` (e.g. `kici run push --local`), which runs this machine as an ephemeral agent through the local dev plane."
|
|
20
21
|
};
|
|
21
22
|
/**
|
|
22
23
|
* Redirect message for a retired top-level command, or undefined if the name is
|
|
@@ -43,6 +44,7 @@ function attemptedCommand(program, argv) {
|
|
|
43
44
|
function buildProgram() {
|
|
44
45
|
const program = new Command();
|
|
45
46
|
program.name("kici").description("KiCI workflow compiler").version(version);
|
|
47
|
+
program.enablePositionalOptions();
|
|
46
48
|
program.hook("preAction", (_thisCommand, actionCommand) => {
|
|
47
49
|
if (shouldSuppressBanner(actionCommand)) return;
|
|
48
50
|
console.log(pc.gray(`kici v${version}`));
|
|
@@ -52,7 +54,7 @@ function buildProgram() {
|
|
|
52
54
|
} });
|
|
53
55
|
program.showSuggestionAfterError(true);
|
|
54
56
|
program.showHelpAfterError("(run `kici --help` to see all commands)");
|
|
55
|
-
program.command("compile").description("Compile workflows from .kici/workflows/ to kici.lock.json").option("--check", "Validate workflows without writing lock file", false).option("--kici-dir <path>", "Path to .kici directory", ".kici").option("--verbose", "Detailed output", false).option("--watch", "Watch for changes and recompile", false).action(async (options) => {
|
|
57
|
+
program.command("compile").description("Compile workflows from .kici/workflows/ to kici.lock.json").option("--check", "Validate workflows and type-check sources (tsc --noEmit) without writing lock file", false).option("--kici-dir <path>", "Path to .kici directory", ".kici").option("--verbose", "Detailed output", false).option("--watch", "Watch for changes and recompile", false).action(async (options) => {
|
|
56
58
|
const { compileCommand, watchCommand } = await import("./commands/index.js");
|
|
57
59
|
if (options.watch) await watchCommand({
|
|
58
60
|
kiciDir: options.kiciDir,
|
|
@@ -73,50 +75,26 @@ function buildProgram() {
|
|
|
73
75
|
await fixtureCommand(event, options);
|
|
74
76
|
});
|
|
75
77
|
const runCommand = program.command("run").description("Execute workflows locally or remotely");
|
|
76
|
-
runCommand.
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
if (!options.pick && !event) {
|
|
82
|
-
const { printRunLocalUsage } = await import("./commands/index.js");
|
|
83
|
-
printRunLocalUsage();
|
|
84
|
-
process.exit(2);
|
|
85
|
-
}
|
|
86
|
-
const { runLocalCommand } = await import("./commands/index.js");
|
|
87
|
-
const { resolveCheckMode } = await import("./commands/check-mode.js");
|
|
88
|
-
let checkMode;
|
|
89
|
-
try {
|
|
90
|
-
checkMode = resolveCheckMode({
|
|
91
|
-
check: options.check,
|
|
92
|
-
failOnDrift: options.failOnDrift
|
|
93
|
-
});
|
|
94
|
-
} catch (err) {
|
|
95
|
-
console.error(`Error: ${err instanceof Error ? err.message : String(err)}`);
|
|
78
|
+
runCommand.enablePositionalOptions();
|
|
79
|
+
runCommand.argument("[event]", "Event type for a routed local run (e.g. push, pr:open)").option("--local", "Route the run with this machine as the ephemeral agent", false).option("--offline", "Force the throwaway/independent plane (offline)", false).option("--connected", "Force the connected/hybrid plane (requires attachment)", false).option("--in-place", "Reuse the working tree directly instead of an isolated clone", false).option("--trusted", "Route to the trusted fleet agent profile: steps see the ambient host env (minus the agent identity). Alias: --no-sandbox", false).option("--no-sandbox", "Alias for --trusted (the bwrap sandbox is already off by default)").option("--env <KEY=VALUE>", "Per-run secret (repeatable)", (val, prev) => [...prev, val], []).option("--payload <path>", "Dispatch payload JSON { action?, client_payload? } for a routed dispatch run").option("--kici-dir <path>", "Path to .kici directory", ".kici").option("--quiet", "Suppress the banner + streaming output", false).option("--debug", "Verbose internals", false).action(async (event, options) => {
|
|
80
|
+
const retired = retiredCommandHint(event ? `run ${event}` : void 0);
|
|
81
|
+
if (retired) {
|
|
82
|
+
process.stderr.write(pc.red(`${retired}\n`));
|
|
96
83
|
process.exit(2);
|
|
97
84
|
}
|
|
98
|
-
const
|
|
85
|
+
const { runRoutedCommand } = await import("./commands/index.js");
|
|
86
|
+
const success = await runRoutedCommand({
|
|
99
87
|
event,
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
sha: options.sha,
|
|
106
|
-
payload: options.payload,
|
|
107
|
-
concurrency: options.concurrency,
|
|
108
|
-
keepGoing: options.keepGoing,
|
|
109
|
-
container: options.container,
|
|
88
|
+
local: options.local,
|
|
89
|
+
offline: options.offline,
|
|
90
|
+
connected: options.connected,
|
|
91
|
+
inPlace: options.inPlace,
|
|
92
|
+
trusted: Boolean(options.trusted) || options.sandbox === false,
|
|
110
93
|
env: options.env,
|
|
111
|
-
|
|
112
|
-
quiet: options.quiet,
|
|
113
|
-
json: options.json,
|
|
114
|
-
junit: options.junit,
|
|
115
|
-
files: options.files,
|
|
116
|
-
debug: options.debug,
|
|
94
|
+
payload: options.payload,
|
|
117
95
|
kiciDir: options.kiciDir,
|
|
118
|
-
|
|
119
|
-
|
|
96
|
+
quiet: options.quiet,
|
|
97
|
+
debug: options.debug
|
|
120
98
|
});
|
|
121
99
|
process.exit(success ? 0 : 1);
|
|
122
100
|
});
|
|
@@ -161,7 +139,7 @@ function buildProgram() {
|
|
|
161
139
|
const success = await previewCommand(event, options);
|
|
162
140
|
process.exit(success ? 0 : 1);
|
|
163
141
|
});
|
|
164
|
-
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) => {
|
|
142
|
+
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("--workspace", "Integrate .kici/ into the detected pnpm/npm/yarn workspace so workflows can import sibling packages", false).option("--standalone", "Force a self-contained .kici/ even inside a workspace", 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) => {
|
|
165
143
|
const { initCommand } = await import("./commands/index.js");
|
|
166
144
|
const success = await initCommand({
|
|
167
145
|
...options,
|
|
@@ -174,7 +152,7 @@ function buildProgram() {
|
|
|
174
152
|
const success = await hookInstallCommand({ git: options.git });
|
|
175
153
|
process.exit(success ? 0 : 1);
|
|
176
154
|
});
|
|
177
|
-
program.command("login").description("Authenticate with KiCI via browser OAuth (default) or API key (--token)").option("--token <key>", "API key for direct authentication (legacy)").option("--device", "Force device authorization flow (for headless/SSH environments)").option("--platform-endpoint <url>", "Platform relay URL").option("--oidc-issuer <url>", "OIDC issuer URL (defaults to the hosted KiCI IdP unless a flag/env selects another)").option("--routing-key <key>", "Routing key for webhook source identification").addHelpText("after", `
|
|
155
|
+
program.command("login").description("Authenticate with KiCI via browser OAuth (default) or API key (--token)").option("--token <key>", "API key for direct authentication (legacy)").option("--device", "Force device authorization flow (for headless/SSH environments)").option("--platform-endpoint <url>", "Platform relay URL").option("--oidc-issuer <url>", "OIDC issuer URL (defaults to the hosted KiCI IdP unless a flag/env selects another)").option("--routing-key <key>", "Routing key for webhook source identification").option("--no-attach", "Skip the post-login prompt to attach the local dev plane").addHelpText("after", `
|
|
178
156
|
Environment variables:
|
|
179
157
|
KICI_BROWSER_CMD Custom browser command (use {url} placeholder, or 'none' to suppress)
|
|
180
158
|
KICI_CALLBACK_PORT Fixed port for OAuth PKCE callback server (default: random)
|
|
@@ -188,7 +166,8 @@ Environment variables:
|
|
|
188
166
|
device: options.device,
|
|
189
167
|
platformEndpoint: options.platformEndpoint,
|
|
190
168
|
oidcIssuer: options.oidcIssuer,
|
|
191
|
-
routingKey: options.routingKey
|
|
169
|
+
routingKey: options.routingKey,
|
|
170
|
+
noAttachPrompt: options.attach === false
|
|
192
171
|
});
|
|
193
172
|
process.exit(success ? 0 : 1);
|
|
194
173
|
});
|
|
@@ -224,6 +203,137 @@ Environment variables:
|
|
|
224
203
|
const success = await orchestratorsUseCommand(name, { org: options.org });
|
|
225
204
|
process.exit(success ? 0 : 1);
|
|
226
205
|
});
|
|
206
|
+
const notificationsCommand = program.command("notifications").description("Manage the org's notification channels, subscriptions, and Slack roster");
|
|
207
|
+
const notificationsChannels = notificationsCommand.command("channels").description("Manage notification channels (Slack / email)");
|
|
208
|
+
notificationsChannels.command("list").description("List notification channels").option("--org <id>", "Target organization (overrides the active org)").option("--json", "Output as JSON").action(async (options) => {
|
|
209
|
+
const { notificationsChannelsListCommand } = await import("./commands/index.js");
|
|
210
|
+
const ok = await notificationsChannelsListCommand({
|
|
211
|
+
org: options.org,
|
|
212
|
+
json: options.json
|
|
213
|
+
});
|
|
214
|
+
process.exit(ok ? 0 : 1);
|
|
215
|
+
});
|
|
216
|
+
notificationsChannels.command("add").description("Add a notification channel").requiredOption("--type <slack|email>", "Channel transport type").requiredOption("--name <name>", "Channel display name").option("--connection <id>", "Slack connection id (slack channels)").option("--slack-channel <id>", "Slack channel id (slack channels)").option("--from-name <name>", "Sender name (email channels)").option("--reply-to <email>", "Reply-to address (email channels)").option("--org <id>", "Target organization (overrides the active org)").action(async (options) => {
|
|
217
|
+
const { notificationsChannelsAddCommand } = await import("./commands/index.js");
|
|
218
|
+
const ok = await notificationsChannelsAddCommand({
|
|
219
|
+
org: options.org,
|
|
220
|
+
type: options.type,
|
|
221
|
+
name: options.name,
|
|
222
|
+
connection: options.connection,
|
|
223
|
+
slackChannel: options.slackChannel,
|
|
224
|
+
fromName: options.fromName,
|
|
225
|
+
replyTo: options.replyTo
|
|
226
|
+
});
|
|
227
|
+
process.exit(ok ? 0 : 1);
|
|
228
|
+
});
|
|
229
|
+
notificationsChannels.command("remove").argument("<id>", "Channel id").description("Remove a notification channel").option("--org <id>", "Target organization (overrides the active org)").action(async (id, options) => {
|
|
230
|
+
const { notificationsChannelsRemoveCommand } = await import("./commands/index.js");
|
|
231
|
+
const ok = await notificationsChannelsRemoveCommand(id, { org: options.org });
|
|
232
|
+
process.exit(ok ? 0 : 1);
|
|
233
|
+
});
|
|
234
|
+
const notificationsSubscriptions = notificationsCommand.command("subscriptions").description("Manage notification subscriptions");
|
|
235
|
+
notificationsSubscriptions.command("list").description("List notification subscriptions").option("--org <id>", "Target organization (overrides the active org)").option("--json", "Output as JSON").action(async (options) => {
|
|
236
|
+
const { notificationsSubscriptionsListCommand } = await import("./commands/index.js");
|
|
237
|
+
const ok = await notificationsSubscriptionsListCommand({
|
|
238
|
+
org: options.org,
|
|
239
|
+
json: options.json
|
|
240
|
+
});
|
|
241
|
+
process.exit(ok ? 0 : 1);
|
|
242
|
+
});
|
|
243
|
+
notificationsSubscriptions.command("add").description("Add a notification subscription").requiredOption("--channel <id>", "Target channel id").requiredOption("--on-status <csv>", "Statuses to notify on (e.g. failed,success)").option("--level <run|job>", "Subscription granularity", "run").option("--scope <org|team|user|actor>", "Subscription scope", "org").option("--scope-id <id>", "Scope id (required for team/user scope)").option("--repo-glob <glob>", "Match runs whose repo matches this glob").option("--workflow-glob <glob>", "Match runs whose workflow matches this glob").option("--job-glob <glob>", "Match jobs matching this glob (job level)").option("--mentions <csv>", "Literal Slack member/group ids or emails to mention").option("--recipient-override <csv>", "Override the email recipient set").option("--on-failure-class <csv>", "Only match these failure classes").option("--accumulate-for <ms>", "Digest accumulation window in milliseconds").option("--org <id>", "Target organization (overrides the active org)").action(async (options) => {
|
|
244
|
+
const { notificationsSubscriptionsAddCommand } = await import("./commands/index.js");
|
|
245
|
+
const ok = await notificationsSubscriptionsAddCommand({
|
|
246
|
+
org: options.org,
|
|
247
|
+
channel: options.channel,
|
|
248
|
+
onStatus: options.onStatus,
|
|
249
|
+
level: options.level,
|
|
250
|
+
scope: options.scope,
|
|
251
|
+
scopeId: options.scopeId,
|
|
252
|
+
repoGlob: options.repoGlob,
|
|
253
|
+
workflowGlob: options.workflowGlob,
|
|
254
|
+
jobGlob: options.jobGlob,
|
|
255
|
+
mentions: options.mentions,
|
|
256
|
+
recipientOverride: options.recipientOverride,
|
|
257
|
+
onFailureClass: options.onFailureClass,
|
|
258
|
+
accumulateFor: options.accumulateFor
|
|
259
|
+
});
|
|
260
|
+
process.exit(ok ? 0 : 1);
|
|
261
|
+
});
|
|
262
|
+
notificationsSubscriptions.command("remove").argument("<id>", "Subscription id").description("Remove a notification subscription").option("--org <id>", "Target organization (overrides the active org)").action(async (id, options) => {
|
|
263
|
+
const { notificationsSubscriptionsRemoveCommand } = await import("./commands/index.js");
|
|
264
|
+
const ok = await notificationsSubscriptionsRemoveCommand(id, { org: options.org });
|
|
265
|
+
process.exit(ok ? 0 : 1);
|
|
266
|
+
});
|
|
267
|
+
const notificationsRoster = notificationsCommand.command("roster").description("Manage the Layer 1 Slack-identity roster (actor tagging)");
|
|
268
|
+
notificationsRoster.command("list").description("List Slack-identity roster entries").option("--org <id>", "Target organization (overrides the active org)").option("--json", "Output as JSON").action(async (options) => {
|
|
269
|
+
const { notificationsRosterListCommand } = await import("./commands/index.js");
|
|
270
|
+
const ok = await notificationsRosterListCommand({
|
|
271
|
+
org: options.org,
|
|
272
|
+
json: options.json
|
|
273
|
+
});
|
|
274
|
+
process.exit(ok ? 0 : 1);
|
|
275
|
+
});
|
|
276
|
+
notificationsRoster.command("add").description("Add a Slack-identity roster entry").requiredOption("--connection <id>", "Slack connection id").requiredOption("--subject-kind <kici_user|git_login|email>", "What the subject keys on").requiredOption("--subject <value>", "The KiCI user sub, git login, or email").requiredOption("--value <slackIdEmailOrHandle>", "Slack member id, email, or @handle").option("--input-form <id|username|email>", "How --value should be resolved", "id").option("--org <id>", "Target organization (overrides the active org)").action(async (options) => {
|
|
277
|
+
const { notificationsRosterAddCommand } = await import("./commands/index.js");
|
|
278
|
+
const ok = await notificationsRosterAddCommand({
|
|
279
|
+
org: options.org,
|
|
280
|
+
connection: options.connection,
|
|
281
|
+
subjectKind: options.subjectKind,
|
|
282
|
+
subject: options.subject,
|
|
283
|
+
inputForm: options.inputForm,
|
|
284
|
+
value: options.value
|
|
285
|
+
});
|
|
286
|
+
process.exit(ok ? 0 : 1);
|
|
287
|
+
});
|
|
288
|
+
notificationsRoster.command("remove").argument("<id>", "Roster entry id").description("Remove a Slack-identity roster entry").option("--org <id>", "Target organization (overrides the active org)").action(async (id, options) => {
|
|
289
|
+
const { notificationsRosterRemoveCommand } = await import("./commands/index.js");
|
|
290
|
+
const ok = await notificationsRosterRemoveCommand(id, { org: options.org });
|
|
291
|
+
process.exit(ok ? 0 : 1);
|
|
292
|
+
});
|
|
293
|
+
const localCommand = program.command("local").description("Manage the local dev orchestrator plane");
|
|
294
|
+
localCommand.command("up").description("Start (or reuse) the local dev plane").option("--offline", "Force the independent (offline) plane (does not clear the attachment record)", false).option("--connected", "Force the connected/hybrid plane (requires an attached, reachable Platform)", false).action(async (options) => {
|
|
295
|
+
const { localUpCommand } = await import("./commands/index.js");
|
|
296
|
+
const ok = await localUpCommand({
|
|
297
|
+
offline: options.offline,
|
|
298
|
+
connected: options.connected
|
|
299
|
+
});
|
|
300
|
+
process.exit(ok ? 0 : 1);
|
|
301
|
+
});
|
|
302
|
+
localCommand.command("status").description("Show local dev plane status and control commands").option("--json", "Emit machine-readable JSON (exits 0 for every state)", false).action(async (options) => {
|
|
303
|
+
const { localStatusCommand } = await import("./commands/index.js");
|
|
304
|
+
const ok = await localStatusCommand({ json: options.json });
|
|
305
|
+
process.exit(ok ? 0 : 1);
|
|
306
|
+
});
|
|
307
|
+
for (const [name, desc, fn] of [
|
|
308
|
+
[
|
|
309
|
+
"down",
|
|
310
|
+
"Stop the local dev plane",
|
|
311
|
+
"localDownCommand"
|
|
312
|
+
],
|
|
313
|
+
[
|
|
314
|
+
"logs",
|
|
315
|
+
"Print the local dev plane orchestrator log path",
|
|
316
|
+
"localLogsCommand"
|
|
317
|
+
],
|
|
318
|
+
[
|
|
319
|
+
"attach",
|
|
320
|
+
"Attach the local dev plane to the Platform (hybrid)",
|
|
321
|
+
"localAttachCommand"
|
|
322
|
+
],
|
|
323
|
+
[
|
|
324
|
+
"detach",
|
|
325
|
+
"Detach the local dev plane from the Platform (offline)",
|
|
326
|
+
"localDetachCommand"
|
|
327
|
+
]
|
|
328
|
+
]) localCommand.command(name).description(desc).action(async () => {
|
|
329
|
+
const ok = await (await import("./commands/index.js"))[fn]();
|
|
330
|
+
process.exit(ok ? 0 : 1);
|
|
331
|
+
});
|
|
332
|
+
localCommand.command("trust-root").description("Export the offline dev-signed identity trust root ({ issuer, jwks }) to a file").argument("<file>", "Output path for the { issuer, jwks } trust-root JSON").action(async (file) => {
|
|
333
|
+
const { localTrustRootCommand } = await import("./commands/index.js");
|
|
334
|
+
const ok = await localTrustRootCommand(file);
|
|
335
|
+
process.exit(ok ? 0 : 1);
|
|
336
|
+
});
|
|
227
337
|
program.command("secrets").description("Manage secrets").command("list").description("List test-available secret contexts").action(async () => {
|
|
228
338
|
const { secretsListCommand } = await import("./commands/index.js");
|
|
229
339
|
const success = await secretsListCommand();
|
|
@@ -240,7 +350,7 @@ Environment variables:
|
|
|
240
350
|
process.exit(success ? 0 : 1);
|
|
241
351
|
});
|
|
242
352
|
const runsCommand = program.command("runs").description("Inspect and manage execution runs");
|
|
243
|
-
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("--
|
|
353
|
+
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("--cursor <cursor>", "Keyset cursor for the next page (from a prior nextCursor)").option("--json", "Output raw JSON", false).action(async (options) => {
|
|
244
354
|
const { runsListCommand } = await import("./commands/index.js");
|
|
245
355
|
const success = await runsListCommand(options);
|
|
246
356
|
process.exit(success ? 0 : 1);
|
|
@@ -272,6 +382,20 @@ Environment variables:
|
|
|
272
382
|
});
|
|
273
383
|
process.exit(success ? 0 : 1);
|
|
274
384
|
});
|
|
385
|
+
const runsArtifacts = runsCommand.command("artifacts").description("List and download a run's artifacts");
|
|
386
|
+
runsArtifacts.command("list").argument("<run-id>", "Run ID whose artifacts to list").description("List the artifacts a run uploaded").option("--json", "Output raw JSON", false).action(async (runId, options) => {
|
|
387
|
+
const { runsArtifactsListCommand } = await import("./commands/index.js");
|
|
388
|
+
const success = await runsArtifactsListCommand(runId, { json: options.json });
|
|
389
|
+
process.exit(success ? 0 : 1);
|
|
390
|
+
});
|
|
391
|
+
runsArtifacts.command("download").argument("<run-id>", "Run ID whose artifacts to download").argument("[name]", "Artifact name (omit to download every artifact of the run)").description("Download one artifact, or all of them — extracts by default").option("--archive", "Save the raw .tar.gz instead of extracting", false).option("-o, --output <dir>", "Output directory (default: current directory)").action(async (runId, name, options) => {
|
|
392
|
+
const { runsArtifactsDownloadCommand } = await import("./commands/index.js");
|
|
393
|
+
const success = await runsArtifactsDownloadCommand(runId, name, {
|
|
394
|
+
archive: options.archive,
|
|
395
|
+
output: options.output
|
|
396
|
+
});
|
|
397
|
+
process.exit(success ? 0 : 1);
|
|
398
|
+
});
|
|
275
399
|
program.command("approve").argument("<run-id>", "Run ID whose approval gate to approve").description("Approve a held approval gate for a run").option("--job <name>", "Approve the hold for a specific job").option("--step <index>", "Approve a step-scoped hold (requires --job)").action(async (runId, options) => {
|
|
276
400
|
const { approveCommand } = await import("./commands/index.js");
|
|
277
401
|
const success = await approveCommand(runId, {
|
|
@@ -299,7 +423,15 @@ Environment variables:
|
|
|
299
423
|
const success = await endpointsCommand({ kiciDir: options.kiciDir });
|
|
300
424
|
process.exit(success ? 0 : 1);
|
|
301
425
|
});
|
|
302
|
-
program.command("
|
|
426
|
+
program.command("doctor").description("Diagnose your KiCI setup and print the exact next command for each problem").option("--json", "Output raw JSON instead of a table", false).option("--kici-dir <path>", "Path to the .kici directory", ".kici").action(async (options) => {
|
|
427
|
+
const { doctorCommand } = await import("./commands/index.js");
|
|
428
|
+
const exitCode = await doctorCommand({
|
|
429
|
+
json: options.json,
|
|
430
|
+
kiciDir: options.kiciDir
|
|
431
|
+
});
|
|
432
|
+
process.exit(exitCode);
|
|
433
|
+
});
|
|
434
|
+
program.command("diagnostics").description("Show orchestrators, scalers, and agents (mirrors the dashboard Infrastructure page)").option("--json", "Output raw JSON", false).option("--verbose", "Show extended per-agent fields", false).option("--orchestrator <id>", "Scope the tree to one connection id").action(async (options) => {
|
|
303
435
|
const { diagnosticsCommand } = await import("./commands/index.js");
|
|
304
436
|
const success = await diagnosticsCommand({
|
|
305
437
|
json: options.json,
|
|
@@ -335,7 +467,7 @@ Environment variables:
|
|
|
335
467
|
const success = await drainWorkerCommand({ url: options.url });
|
|
336
468
|
process.exit(success ? 0 : 1);
|
|
337
469
|
});
|
|
338
|
-
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) => {
|
|
470
|
+
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: your configured orchestrator, else the hosted KiCI platform)").option("--audience <aud>", "Expected token audience").option("--json", "Output structured JSON result", false).action(async (artifact, options) => {
|
|
339
471
|
const { verifyAttestationCommand } = await import("./commands/index.js");
|
|
340
472
|
const success = await verifyAttestationCommand(artifact, options);
|
|
341
473
|
process.exit(success ? 0 : 1);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { CheckMode } from '@kici-dev/engine';
|
|
2
|
-
/** The two
|
|
2
|
+
/** The two check-mode flags accepted by `kici run remote`. */
|
|
3
3
|
export interface CheckModeFlags {
|
|
4
4
|
/** --check: report drift, change nothing. */
|
|
5
5
|
check?: boolean;
|
package/dist/commands/compile.js
CHANGED
|
@@ -1,26 +1,39 @@
|
|
|
1
1
|
import "../rolldown-runtime-ClRpJifh.js";
|
|
2
|
-
import { formatError, isCompilerError } from "../errors/formatter.js";
|
|
2
|
+
import { PURITY_FALLBACK_CODE, compilerError, formatError, isCompilerError } from "../errors/formatter.js";
|
|
3
3
|
import "../errors/index.js";
|
|
4
4
|
import { discoverWorkflows, resolveKiciDir } from "../execution/executor.js";
|
|
5
5
|
import "../execution/index.js";
|
|
6
6
|
import { validateConfig } from "../validation/validator.js";
|
|
7
|
+
import { runTypecheck } from "../validation/typecheck.js";
|
|
7
8
|
import "../validation/index.js";
|
|
8
|
-
import {
|
|
9
|
+
import { BREAKING_FLOOR, SCHEMA_VERSION } from "../types.js";
|
|
10
|
+
import { computeLockfileHash, detectGitRoot, generateLockFile, schemaWindowWarning, serializeLockFile } from "../lockfile/generator.js";
|
|
11
|
+
import { collectWorkflowPurityWarnings } from "../lockfile/purity-diagnostics.js";
|
|
9
12
|
import "../lockfile/index.js";
|
|
10
13
|
import path from "node:path";
|
|
11
14
|
import { existsSync } from "node:fs";
|
|
12
15
|
import pc from "picocolors";
|
|
13
|
-
import fs from "node:fs/promises";
|
|
16
|
+
import fs$1 from "node:fs/promises";
|
|
14
17
|
import { logger, toErrorMessage } from "@kici-dev/core";
|
|
15
18
|
import { PackageManager, detectPackageManagerSync } from "@kici-dev/core/package-manager";
|
|
16
19
|
import { execSync } from "node:child_process";
|
|
17
20
|
//#region src/commands/compile.ts
|
|
18
21
|
/**
|
|
22
|
+
* Render an impure dynamic-value function as a `W101` compile warning naming the
|
|
23
|
+
* job, the field, the impurity reason, and the ~5-10s agent-side init-job cost.
|
|
24
|
+
*/
|
|
25
|
+
function formatPurityWarning(w) {
|
|
26
|
+
return formatError(compilerError(PURITY_FALLBACK_CODE, `job "${w.jobName}": ${w.field} function is not pure (${w.reason}). An init job will be required, adding ~5-10s delay.`, {
|
|
27
|
+
severity: "warning",
|
|
28
|
+
suggestion: `Make the ${w.field} function pure (synchronous, referencing only its parameters) to inline it and skip the init job. See https://docs.kici.dev — dynamic values.`
|
|
29
|
+
}));
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
19
32
|
* Read the existing lock file and return its lockfileHash, if present.
|
|
20
33
|
*/
|
|
21
34
|
async function readExistingLockfileHash(lockPath) {
|
|
22
35
|
try {
|
|
23
|
-
const content = await fs.readFile(lockPath, "utf-8");
|
|
36
|
+
const content = await fs$1.readFile(lockPath, "utf-8");
|
|
24
37
|
return JSON.parse(content).lockfileHash ?? void 0;
|
|
25
38
|
} catch {
|
|
26
39
|
return;
|
|
@@ -67,15 +80,18 @@ async function compileCommand(options) {
|
|
|
67
80
|
}
|
|
68
81
|
const { workflows: workflowsWithSource, workflowDir } = await discoverWorkflows(absoluteKiciDir);
|
|
69
82
|
if (options.verbose) logger.debug(pc.dim(`Found ${workflowsWithSource.length} workflow(s) in ${workflowDir}`));
|
|
70
|
-
const validation = validateConfig(workflowsWithSource
|
|
83
|
+
const validation = validateConfig(workflowsWithSource);
|
|
71
84
|
if (!validation.valid) {
|
|
72
85
|
for (const error of validation.errors) logger.error(formatError(error));
|
|
73
86
|
return false;
|
|
74
87
|
}
|
|
75
88
|
if (options.verbose) logger.debug(pc.dim("Validation passed"));
|
|
76
89
|
const lockJson = serializeLockFile(generateLockFile(workflowsWithSource));
|
|
90
|
+
for (const warning of collectWorkflowPurityWarnings(workflowsWithSource)) logger.warn(formatPurityWarning(warning));
|
|
91
|
+
const windowWarning = schemaWindowWarning(BREAKING_FLOOR, SCHEMA_VERSION);
|
|
92
|
+
if (windowWarning) logger.warn(pc.yellow(windowWarning));
|
|
77
93
|
if (!options.check) {
|
|
78
|
-
await fs.writeFile(lockPath, lockJson, "utf-8");
|
|
94
|
+
await fs$1.writeFile(lockPath, lockJson, "utf-8");
|
|
79
95
|
if (!options.quiet) logger.info(pc.green("✓") + ` Compiled workflows → .kici/kici.lock.json` + pc.dim(` (${workflowsWithSource.length} workflow${workflowsWithSource.length !== 1 ? "s" : ""})`));
|
|
80
96
|
try {
|
|
81
97
|
const { loadGlobalConfig } = await import("../remote/config.js");
|
|
@@ -92,7 +108,15 @@ async function compileCommand(options) {
|
|
|
92
108
|
} catch {
|
|
93
109
|
logger.warn(pc.yellow("Could not refresh types (Platform unreachable). Compilation succeeded."));
|
|
94
110
|
}
|
|
95
|
-
} else
|
|
111
|
+
} else {
|
|
112
|
+
const tc = await runTypecheck(absoluteKiciDir);
|
|
113
|
+
if (tc.errors.length > 0) {
|
|
114
|
+
for (const error of tc.errors) logger.error(formatError(error));
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
if (!tc.ran && !options.quiet) logger.info(pc.dim("Type-check skipped (no tsconfig.json — JavaScript mode)"));
|
|
118
|
+
if (!options.quiet) logger.info(pc.green("✓") + ` Workflows are valid` + pc.dim(` (${workflowsWithSource.length} workflow${workflowsWithSource.length !== 1 ? "s" : ""})`));
|
|
119
|
+
}
|
|
96
120
|
return true;
|
|
97
121
|
} catch (error) {
|
|
98
122
|
if (isCompilerError(error)) logger.error(formatError(error));
|
|
@@ -3,8 +3,9 @@ import { DashboardClient, DashboardClientError } from "../remote/dashboard-clien
|
|
|
3
3
|
import { relativeTime } from "../remote/render.js";
|
|
4
4
|
import pc from "picocolors";
|
|
5
5
|
import { logger, toErrorMessage } from "@kici-dev/core";
|
|
6
|
+
import { InfraAlertSeverity, normalizeInfraAlertSeverity } from "@kici-dev/engine";
|
|
6
7
|
//#region src/commands/diagnostics.ts
|
|
7
|
-
/** kici diagnostics — mirrors the dashboard
|
|
8
|
+
/** kici diagnostics — mirrors the dashboard Infrastructure page (infra tree). */
|
|
8
9
|
async function diagnosticsCommand(options = {}) {
|
|
9
10
|
try {
|
|
10
11
|
const client = await DashboardClient.load();
|
|
@@ -36,9 +37,20 @@ function printSummary(s) {
|
|
|
36
37
|
const m = s.executionMetrics;
|
|
37
38
|
console.log(pc.bold("\nDiagnostics") + pc.gray(` runs(24h)=${m.totalRuns} success=${m.successRate}% avg=${m.avgDurationSeconds}s queued=${m.queuedJobs} running=${m.runningJobs}` + (s.orphanedConnections > 0 ? ` orphaned=${s.orphanedConnections}` : "")));
|
|
38
39
|
}
|
|
40
|
+
/**
|
|
41
|
+
* Alert colour per known severity.
|
|
42
|
+
*
|
|
43
|
+
* Typed `Record<InfraAlertSeverity, …>`: adding a severity to the engine enum
|
|
44
|
+
* without colouring it fails `pnpm typecheck` instead of silently inheriting
|
|
45
|
+
* the warning colour.
|
|
46
|
+
*/
|
|
47
|
+
const ALERT_SEVERITY_COLOR = {
|
|
48
|
+
[InfraAlertSeverity.enum.warning]: pc.yellow,
|
|
49
|
+
[InfraAlertSeverity.enum.critical]: pc.red
|
|
50
|
+
};
|
|
39
51
|
function printAlerts(alerts) {
|
|
40
52
|
for (const a of alerts) {
|
|
41
|
-
const color = a.severity
|
|
53
|
+
const color = ALERT_SEVERITY_COLOR[normalizeInfraAlertSeverity(a.severity)];
|
|
42
54
|
console.log(color(` ! [${a.type}] ${a.message}`));
|
|
43
55
|
}
|
|
44
56
|
}
|