@kici-dev/compiler 0.1.15 → 0.1.17
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.js +1 -1
- package/dist/cli-banner.js +1 -1
- package/dist/cli.d.ts +9 -1
- package/dist/cli.js +251 -183
- package/dist/commands/approve.d.ts +23 -0
- package/dist/commands/approve.js +46 -0
- package/dist/commands/compile.js +6 -4
- package/dist/commands/diagnostics.d.ts +7 -0
- package/dist/commands/diagnostics.js +58 -0
- package/dist/commands/docs.js +3 -3
- package/dist/commands/drain-worker.js +1 -1
- package/dist/commands/endpoints.js +2 -2
- package/dist/commands/fixture.js +1 -1
- package/dist/commands/held-run-client.d.ts +26 -0
- package/dist/commands/held-run-client.js +98 -0
- package/dist/commands/held-run-resolve.d.ts +45 -0
- package/dist/commands/held-run-resolve.js +53 -0
- package/dist/commands/hook.js +2 -2
- package/dist/commands/index.d.ts +20 -4
- package/dist/commands/index.js +12 -4
- package/dist/commands/init.js +3 -3
- package/dist/commands/login.d.ts +0 -2
- package/dist/commands/login.js +1 -3
- package/dist/commands/logout.js +1 -1
- package/dist/commands/orchestrators.d.ts +25 -0
- package/dist/commands/orchestrators.js +115 -0
- package/dist/commands/org.js +1 -1
- package/dist/commands/reject.d.ts +25 -0
- package/dist/commands/reject.js +49 -0
- package/dist/commands/run.d.ts +2 -9
- package/dist/commands/run.js +257 -316
- package/dist/commands/runs/cancel.d.ts +6 -0
- package/dist/commands/runs/cancel.js +32 -0
- package/dist/commands/runs/list.d.ts +6 -0
- package/dist/commands/runs/list.js +49 -0
- package/dist/commands/runs/logs.d.ts +7 -0
- package/dist/commands/runs/logs.js +67 -0
- package/dist/commands/runs/rerun.d.ts +5 -0
- package/dist/commands/runs/rerun.js +21 -0
- package/dist/commands/runs/show.d.ts +5 -0
- package/dist/commands/runs/show.js +65 -0
- package/dist/commands/secrets-list.d.ts +7 -9
- package/dist/commands/secrets-list.js +40 -64
- package/dist/commands/test.d.ts +4 -0
- package/dist/commands/test.js +2 -2
- package/dist/commands/types.d.ts +3 -5
- package/dist/commands/types.js +14 -38
- package/dist/commands/verify-attestation.d.ts +12 -0
- package/dist/commands/verify-attestation.js +69 -0
- package/dist/commands/watch.js +2 -2
- package/dist/commands/workflows.js +14 -34
- package/dist/errors/capability-gap.js +1 -1
- package/dist/errors/formatter.js +1 -1
- package/dist/errors/index.js +1 -1
- package/dist/execution/executor.js +3 -3
- package/dist/execution/index.js +1 -1
- package/dist/execution/sdk-alias.js +2 -2
- package/dist/execution/ts-loader.js +1 -1
- package/dist/fixtures/compiler.js +3 -3
- package/dist/fixtures/defaults/index.js +3 -3
- package/dist/format.js +1 -1
- package/dist/generators/secrets-dts.js +2 -2
- package/dist/hooks/detector.js +2 -2
- package/dist/hooks/index.js +1 -1
- package/dist/hooks/installer.js +2 -2
- package/dist/hooks/templates.js +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/llm-context/llms-full.txt +1180 -131
- package/dist/llm-context/llms.txt +6 -2
- package/dist/local-executor/dag-scheduler.js +1 -1
- package/dist/local-executor/index.js +2 -2
- package/dist/local-executor/job-runner.js +38 -17
- package/dist/local-executor/materializer.js +2 -2
- package/dist/local-executor/output-streamer.js +1 -1
- package/dist/local-executor/payload-generator.js +1 -1
- package/dist/local-executor/picker.js +1 -1
- package/dist/local-executor/secret-loader.js +2 -2
- package/dist/local-executor/to-event-payload.js +1 -1
- package/dist/local-executor/types.js +1 -1
- package/dist/local-executor/workflow-lock.js +0 -0
- package/dist/lockfile/generator.d.ts +7 -5
- package/dist/lockfile/generator.js +38 -23
- package/dist/lockfile/hash-files.js +2 -2
- package/dist/lockfile/hasher.js +1 -1
- package/dist/lockfile/index.js +1 -1
- package/dist/lockfile/purity-analyzer.js +1 -1
- package/dist/postinstall.js +2 -2
- package/dist/provenance-trust-root.d.ts +14 -0
- package/dist/provenance-trust-root.js +49 -0
- package/dist/remote/config.d.ts +6 -2
- package/dist/remote/config.js +8 -5
- package/dist/remote/dashboard-client.d.ts +92 -0
- package/dist/remote/dashboard-client.js +168 -0
- package/dist/remote/encryption.js +3 -4
- package/dist/remote/history.js +2 -2
- package/dist/remote/oauth.js +1 -1
- package/dist/remote/oidc-discovery.js +1 -1
- package/dist/remote/output/json.js +1 -1
- package/dist/remote/output/junit.js +1 -1
- package/dist/remote/output/streaming.js +1 -1
- package/dist/remote/output/summary.js +1 -1
- package/dist/remote/platform-client.d.ts +142 -0
- package/dist/remote/platform-client.js +187 -0
- package/dist/remote/prod-defaults.js +1 -1
- package/dist/remote/render.d.ts +11 -0
- package/dist/remote/render.js +48 -0
- package/dist/remote/secret-upload.js +1 -1
- package/dist/remote/uploader.d.ts +9 -0
- package/dist/remote/uploader.js +52 -5
- package/dist/templates/agents-md.d.ts +1 -1
- package/dist/templates/agents-md.js +8 -3
- package/dist/templates/index.js +2 -2
- package/dist/templates/package-json.js +4 -5
- package/dist/templates/tsconfig-json.js +1 -1
- package/dist/templates/workflows/hello-world.js +2 -2
- package/dist/templates/workflows/hello-world.ts +1 -1
- package/dist/templates/workflows/pr-checks.js +3 -3
- package/dist/templates/workflows/pr-checks.ts +2 -2
- package/dist/test-runner/dry-run.js +1 -1
- package/dist/test-runner/event-types.js +1 -1
- package/dist/test-runner/git-detector.js +2 -2
- package/dist/test-runner/index.js +1 -1
- package/dist/test-runner/job-executor.js +3 -3
- package/dist/test-runner/output-formatter.js +1 -1
- package/dist/test-runner/payload-builder.js +1 -1
- package/dist/test-runner/rule-evaluator.js +1 -1
- package/dist/test-runner/secrets-file.js +2 -2
- package/dist/test-runner/step-context.js +11 -7
- package/dist/types.d.ts +24 -6
- package/dist/types.js +2 -1
- package/dist/validation/index.js +1 -1
- package/dist/validation/validator.js +1 -1
- package/dist/workflows/hello-world.ts +1 -1
- package/dist/workflows/pr-checks.ts +2 -2
- package/package.json +5 -4
- package/sbom.spdx.json +68 -38
- package/dist/commands/cancel.js +0 -124
- package/dist/commands/status.js +0 -212
- package/dist/remote/client.js +0 -203
- package/dist/remote/observer.js +0 -174
- /package/dist/{chunk-gOLHoazu.js → chunk-BTugEXQM.js} +0 -0
package/dist/cli-banner.js
CHANGED
package/dist/cli.d.ts
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
/**
|
|
4
|
+
* Build the kici Commander program with every command registered. Exported so
|
|
5
|
+
* the surface registry can walk the real command tree without parsing argv (no
|
|
6
|
+
* action runs during a tree walk).
|
|
7
|
+
*/
|
|
8
|
+
export declare function buildProgram(): Command;
|
|
9
|
+
/** Build the program and parse argv — the bin-shim entry point. */
|
|
10
|
+
export declare function runCli(argv?: string[]): void;
|
|
3
11
|
//# sourceMappingURL=cli.d.ts.map
|
package/dist/cli.js
CHANGED
|
@@ -1,100 +1,108 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import "./chunk-
|
|
2
|
+
import "./chunk-BTugEXQM.js";
|
|
3
3
|
import { shouldSuppressBanner } from "./cli-banner.js";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { resolve } from "node:path";
|
|
4
6
|
import { Argument, Command, Option } from "commander";
|
|
5
7
|
import pc from "picocolors";
|
|
6
8
|
//#region src/cli.ts
|
|
7
|
-
const version = "0.1.
|
|
8
|
-
|
|
9
|
-
program.
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
program
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
const
|
|
9
|
+
const version = "0.1.17";
|
|
10
|
+
/**
|
|
11
|
+
* Build the kici Commander program with every command registered. Exported so
|
|
12
|
+
* the surface registry can walk the real command tree without parsing argv (no
|
|
13
|
+
* action runs during a tree walk).
|
|
14
|
+
*/
|
|
15
|
+
function buildProgram() {
|
|
16
|
+
const program = new Command();
|
|
17
|
+
program.name("kici").description("KiCI workflow compiler").version(version);
|
|
18
|
+
program.hook("preAction", (_thisCommand, actionCommand) => {
|
|
19
|
+
if (shouldSuppressBanner(actionCommand)) return;
|
|
20
|
+
console.log(pc.gray(`kici v${version}`));
|
|
21
|
+
});
|
|
22
|
+
program.configureOutput({ outputError: (str, write) => {
|
|
23
|
+
write(pc.red(str));
|
|
24
|
+
} });
|
|
25
|
+
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) => {
|
|
26
|
+
const { compileCommand, watchCommand } = await import("./commands/index.js");
|
|
27
|
+
if (options.watch) await watchCommand({
|
|
25
28
|
kiciDir: options.kiciDir,
|
|
26
|
-
check: options.check,
|
|
27
29
|
verbose: options.verbose
|
|
28
30
|
});
|
|
31
|
+
else {
|
|
32
|
+
const success = await compileCommand({
|
|
33
|
+
kiciDir: options.kiciDir,
|
|
34
|
+
check: options.check,
|
|
35
|
+
verbose: options.verbose
|
|
36
|
+
});
|
|
37
|
+
process.exit(success ? 0 : 1);
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
const fixtureEventArg = new Argument("<event>", "Event to generate fixture for (e.g., pr:open, push, schedule, lifecycle:workflow_complete)");
|
|
41
|
+
program.command("fixture").addArgument(fixtureEventArg).description("Generate fixture template for event type").option("--output <path>", "Write to file instead of stdout").action(async (event, options) => {
|
|
42
|
+
const { fixtureCommand } = await import("./commands/index.js");
|
|
43
|
+
await fixtureCommand(event, options);
|
|
44
|
+
});
|
|
45
|
+
const runCommand = program.command("run").description("Execute workflows locally or remotely");
|
|
46
|
+
runCommand.command("local").argument("[event]", "Event type (e.g., push, pr:open, schedule) — optional with --pick").description("Execute workflows locally without orchestrator infrastructure").option("-p, --pick", "Interactively pick a workflow and trigger to simulate", false).option("--workflow <name>", "Run only the specified workflow").option("--job <name>", "Run only the specified job (and its dependencies)").option("--branch <name>", "Override detected git branch").option("--sha <hash>", "Override detected git SHA").option("--payload <path>", "Path to explicit event payload JSON file").option("--concurrency <n>", "Max parallel jobs (default: CPU cores)", parseInt).option("--keep-going", "Continue after job failure", false).option("--container", "Use Podman container isolation", false).option("--env <KEY=VALUE>", "Environment variable override (repeatable)", (val, prev) => [...prev, val], []).option("--quiet", "Suppress streaming output", false).option("--json", "Output structured JSON result", false).option("--junit <path>", "Output JUnit XML result").option("--files <path>", "Override changed file paths (repeatable, default: git diff)", (val, prev) => [...prev, val], []).option("--debug", "Verbose internals", false).option("--kici-dir <path>", "Path to .kici directory", ".kici").option("--in-place", "Run against the real working directory instead of an isolated tmp checkout", false).option("--keep", "Always retain the isolated tmp checkout (default: keep only on failure)", false).action(async (event, options) => {
|
|
47
|
+
if (options.pick && options.workflow) {
|
|
48
|
+
console.error("Error: --pick is mutually exclusive with --workflow.");
|
|
49
|
+
process.exit(2);
|
|
50
|
+
}
|
|
51
|
+
if (!options.pick && !event) {
|
|
52
|
+
console.error("Error: missing event argument. Pass an event or use --pick.");
|
|
53
|
+
process.exit(2);
|
|
54
|
+
}
|
|
55
|
+
const { runLocalCommand } = await import("./commands/index.js");
|
|
56
|
+
const success = await runLocalCommand({
|
|
57
|
+
event,
|
|
58
|
+
pick: options.pick,
|
|
59
|
+
workflow: options.workflow,
|
|
60
|
+
job: options.job,
|
|
61
|
+
branch: options.branch,
|
|
62
|
+
sha: options.sha,
|
|
63
|
+
payload: options.payload,
|
|
64
|
+
concurrency: options.concurrency,
|
|
65
|
+
keepGoing: options.keepGoing,
|
|
66
|
+
container: options.container,
|
|
67
|
+
env: options.env,
|
|
68
|
+
quiet: options.quiet,
|
|
69
|
+
json: options.json,
|
|
70
|
+
junit: options.junit,
|
|
71
|
+
files: options.files,
|
|
72
|
+
debug: options.debug,
|
|
73
|
+
kiciDir: options.kiciDir,
|
|
74
|
+
inPlace: options.inPlace,
|
|
75
|
+
keep: options.keep
|
|
76
|
+
});
|
|
77
|
+
process.exit(success ? 0 : 1);
|
|
78
|
+
});
|
|
79
|
+
runCommand.command("remote").argument("[fixture]", "Fixture name or glob pattern (omit to list available)").description("Execute fixtures remotely via orchestrator").option("--workflow <name>", "Run a specific workflow directly (bypass triggers)").option("--all", "Run all available fixtures", false).option("--parallel", "Run matching fixtures concurrently", false).option("--no-wait", "Fire and forget (print runIds, don't stream)").option("--quiet", "Suppress output except final result", false).option("--json", "Output structured JSON result", false).option("--junit <path>", "Output JUnit XML result").option("--history", "Show recent run history", false).option("--routing-key <key>", "Override routing key for this run").option("--org <id>", "Target organization (overrides the active org)").option("--orchestrator <name>", "Target orchestrator cluster (overrides the per-org default)").option("--debug", "Verbose internals", false).option("--kici-dir <path>", "Path to .kici directory", ".kici").option("--context <ctx.key=value>", "Inject a namespaced context secret, uploaded encrypted to the orchestrator (repeatable)", (val, prev) => [...prev, val], []).option("--env <KEY=VALUE>", "Provide a per-run secret (repeatable); uploaded encrypted to the orchestrator", (val, prev) => [...prev, val], []).action(async (fixture, options) => {
|
|
80
|
+
const { runRemoteCommand } = await import("./commands/index.js");
|
|
81
|
+
const success = await runRemoteCommand(fixture, {
|
|
82
|
+
...options,
|
|
83
|
+
envFlags: options.env
|
|
84
|
+
});
|
|
85
|
+
process.exit(success ? 0 : 1);
|
|
86
|
+
});
|
|
87
|
+
program.command("test").argument("[event]", "Event type to preview (e.g., push, pr:open, schedule)").description("Preview which workflows match a trigger event (dry-run)").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) => {
|
|
88
|
+
const { testCommand } = await import("./commands/index.js");
|
|
89
|
+
const success = await testCommand(event, options);
|
|
90
|
+
process.exit(success ? 0 : 1);
|
|
91
|
+
});
|
|
92
|
+
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) => {
|
|
93
|
+
const { initCommand } = await import("./commands/index.js");
|
|
94
|
+
const success = await initCommand({
|
|
95
|
+
...options,
|
|
96
|
+
noAgentsMd: options.agentsMd === false
|
|
97
|
+
});
|
|
29
98
|
process.exit(success ? 0 : 1);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
const runCommand = program.command("run").description("Execute workflows locally or remotely");
|
|
38
|
-
runCommand.command("local").argument("[event]", "Event type (e.g., push, pr:open, schedule) — optional with --pick").description("Execute workflows locally without orchestrator infrastructure").option("-p, --pick", "Interactively pick a workflow and trigger to simulate", false).option("--workflow <name>", "Run only the specified workflow").option("--job <name>", "Run only the specified job (and its dependencies)").option("--branch <name>", "Override detected git branch").option("--sha <hash>", "Override detected git SHA").option("--payload <path>", "Path to explicit event payload JSON file").option("--concurrency <n>", "Max parallel jobs (default: CPU cores)", parseInt).option("--keep-going", "Continue after job failure", false).option("--container", "Use Podman container isolation", false).option("--env <KEY=VALUE>", "Environment variable override (repeatable)", (val, prev) => [...prev, val], []).option("--quiet", "Suppress streaming output", false).option("--json", "Output structured JSON result", false).option("--junit <path>", "Output JUnit XML result").option("--files <path>", "Override changed file paths (repeatable, default: git diff)", (val, prev) => [...prev, val], []).option("--debug", "Verbose internals", false).option("--kici-dir <path>", "Path to .kici directory", ".kici").option("--in-place", "Run against the real working directory instead of an isolated tmp checkout", false).option("--keep", "Always retain the isolated tmp checkout (default: keep only on failure)", false).action(async (event, options) => {
|
|
39
|
-
if (options.pick && options.workflow) {
|
|
40
|
-
console.error("Error: --pick is mutually exclusive with --workflow.");
|
|
41
|
-
process.exit(2);
|
|
42
|
-
}
|
|
43
|
-
if (!options.pick && !event) {
|
|
44
|
-
console.error("Error: missing event argument. Pass an event or use --pick.");
|
|
45
|
-
process.exit(2);
|
|
46
|
-
}
|
|
47
|
-
const { runLocalCommand } = await import("./commands/index.js");
|
|
48
|
-
const success = await runLocalCommand({
|
|
49
|
-
event,
|
|
50
|
-
pick: options.pick,
|
|
51
|
-
workflow: options.workflow,
|
|
52
|
-
job: options.job,
|
|
53
|
-
branch: options.branch,
|
|
54
|
-
sha: options.sha,
|
|
55
|
-
payload: options.payload,
|
|
56
|
-
concurrency: options.concurrency,
|
|
57
|
-
keepGoing: options.keepGoing,
|
|
58
|
-
container: options.container,
|
|
59
|
-
env: options.env,
|
|
60
|
-
quiet: options.quiet,
|
|
61
|
-
json: options.json,
|
|
62
|
-
junit: options.junit,
|
|
63
|
-
files: options.files,
|
|
64
|
-
debug: options.debug,
|
|
65
|
-
kiciDir: options.kiciDir,
|
|
66
|
-
inPlace: options.inPlace,
|
|
67
|
-
keep: options.keep
|
|
68
|
-
});
|
|
69
|
-
process.exit(success ? 0 : 1);
|
|
70
|
-
});
|
|
71
|
-
runCommand.command("remote").argument("[fixture]", "Fixture name or glob pattern (omit to list available)").description("Execute fixtures remotely via orchestrator").option("--workflow <name>", "Run a specific workflow directly (bypass triggers)").option("--all", "Run all available fixtures", false).option("--parallel", "Run matching fixtures concurrently", false).option("--no-wait", "Fire and forget (print runIds, don't stream)").option("--quiet", "Suppress output except final result", false).option("--json", "Output structured JSON result", false).option("--junit <path>", "Output JUnit XML result").option("--history", "Show recent run history", false).option("--routing-key <key>", "Override routing key for this run").option("--debug", "Verbose internals", false).option("--kici-dir <path>", "Path to .kici directory", ".kici").option("--context <ctx.key=value>", "Inject a namespaced context secret, uploaded encrypted to the orchestrator (repeatable)", (val, prev) => [...prev, val], []).option("--env <KEY=VALUE>", "Provide a per-run secret (repeatable); uploaded encrypted to the orchestrator", (val, prev) => [...prev, val], []).action(async (fixture, options) => {
|
|
72
|
-
const { runRemoteCommand } = await import("./commands/index.js");
|
|
73
|
-
const success = await runRemoteCommand(fixture, {
|
|
74
|
-
...options,
|
|
75
|
-
envFlags: options.env
|
|
76
|
-
});
|
|
77
|
-
process.exit(success ? 0 : 1);
|
|
78
|
-
});
|
|
79
|
-
program.command("test").argument("[event]", "Event type to preview (e.g., push, pr:open, schedule)").description("Preview which workflows match a trigger event (dry-run)").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) => {
|
|
80
|
-
const { testCommand } = await import("./commands/index.js");
|
|
81
|
-
const success = await testCommand(event, options);
|
|
82
|
-
process.exit(success ? 0 : 1);
|
|
83
|
-
});
|
|
84
|
-
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) => {
|
|
85
|
-
const { initCommand } = await import("./commands/index.js");
|
|
86
|
-
const success = await initCommand({
|
|
87
|
-
...options,
|
|
88
|
-
noAgentsMd: options.agentsMd === false
|
|
89
|
-
});
|
|
90
|
-
process.exit(success ? 0 : 1);
|
|
91
|
-
});
|
|
92
|
-
program.command("hook").description("Manage pre-commit hooks").command("install").description("Install kici compile pre-commit hook").option("--git", "Use raw git hook (.git/hooks/pre-commit)", false).action(async (options) => {
|
|
93
|
-
const { hookInstallCommand } = await import("./commands/index.js");
|
|
94
|
-
const success = await hookInstallCommand({ git: options.git });
|
|
95
|
-
process.exit(success ? 0 : 1);
|
|
96
|
-
});
|
|
97
|
-
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("--endpoint <url>", "Orchestrator URL for direct connection").option("--platform-endpoint <url>", "Platform relay URL").option("--routing-key <key>", "Routing key for webhook source identification").addHelpText("after", `
|
|
99
|
+
});
|
|
100
|
+
program.command("hook").description("Manage pre-commit hooks").command("install").description("Install kici compile pre-commit hook").option("--git", "Use raw git hook (.git/hooks/pre-commit)", false).action(async (options) => {
|
|
101
|
+
const { hookInstallCommand } = await import("./commands/index.js");
|
|
102
|
+
const success = await hookInstallCommand({ git: options.git });
|
|
103
|
+
process.exit(success ? 0 : 1);
|
|
104
|
+
});
|
|
105
|
+
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("--routing-key <key>", "Routing key for webhook source identification").addHelpText("after", `
|
|
98
106
|
Environment variables:
|
|
99
107
|
KICI_BROWSER_CMD Custom browser command (use {url} placeholder, or 'none' to suppress)
|
|
100
108
|
KICI_CALLBACK_PORT Fixed port for OAuth PKCE callback server (default: random)
|
|
@@ -102,101 +110,161 @@ Environment variables:
|
|
|
102
110
|
KICI_OIDC_ISSUER Override OIDC issuer URL
|
|
103
111
|
KICI_OIDC_CLIENT_ID Override OIDC client ID
|
|
104
112
|
`).action(async (options) => {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
const
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
});
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
113
|
+
const { loginCommand } = await import("./commands/index.js");
|
|
114
|
+
const success = await loginCommand({
|
|
115
|
+
token: options.token,
|
|
116
|
+
device: options.device,
|
|
117
|
+
platformEndpoint: options.platformEndpoint,
|
|
118
|
+
routingKey: options.routingKey
|
|
119
|
+
});
|
|
120
|
+
process.exit(success ? 0 : 1);
|
|
121
|
+
});
|
|
122
|
+
program.command("logout").description("Revoke PAT and clear local credentials").action(async () => {
|
|
123
|
+
const { logoutCommand } = await import("./commands/index.js");
|
|
124
|
+
const success = await logoutCommand();
|
|
125
|
+
process.exit(success ? 0 : 1);
|
|
126
|
+
});
|
|
127
|
+
const orgCommand = program.command("org").description("Manage organizations");
|
|
128
|
+
orgCommand.command("list").description("List organizations you belong to").action(async () => {
|
|
129
|
+
const { orgListCommand } = await import("./commands/index.js");
|
|
130
|
+
const success = await orgListCommand();
|
|
131
|
+
process.exit(success ? 0 : 1);
|
|
132
|
+
});
|
|
133
|
+
orgCommand.command("use").argument("<name>", "Organization name or ID").description("Switch active organization").action(async (name) => {
|
|
134
|
+
const { orgUseCommand } = await import("./commands/index.js");
|
|
135
|
+
const success = await orgUseCommand(name);
|
|
136
|
+
process.exit(success ? 0 : 1);
|
|
137
|
+
});
|
|
138
|
+
orgCommand.command("current").description("Show current active organization").action(async () => {
|
|
139
|
+
const { orgCurrentCommand } = await import("./commands/index.js");
|
|
140
|
+
const success = await orgCurrentCommand();
|
|
141
|
+
process.exit(success ? 0 : 1);
|
|
142
|
+
});
|
|
143
|
+
const orchestratorsCommand = program.command("orchestrators").description("Inspect the org's orchestrator clusters and pick a default for run remote");
|
|
144
|
+
orchestratorsCommand.command("list").description("List the connected orchestrator clusters for the active org").option("--org <id>", "Target organization (overrides the active org)").action(async (options) => {
|
|
145
|
+
const { orchestratorsListCommand } = await import("./commands/index.js");
|
|
146
|
+
const success = await orchestratorsListCommand({ org: options.org });
|
|
147
|
+
process.exit(success ? 0 : 1);
|
|
148
|
+
});
|
|
149
|
+
orchestratorsCommand.command("use").argument("<name>", "Orchestrator cluster name").description("Set the per-org default orchestrator cluster for run remote").option("--org <id>", "Target organization (overrides the active org)").action(async (name, options) => {
|
|
150
|
+
const { orchestratorsUseCommand } = await import("./commands/index.js");
|
|
151
|
+
const success = await orchestratorsUseCommand(name, { org: options.org });
|
|
152
|
+
process.exit(success ? 0 : 1);
|
|
153
|
+
});
|
|
154
|
+
program.command("secrets").description("Manage secrets").command("list").description("List test-available secret contexts").action(async () => {
|
|
155
|
+
const { secretsListCommand } = await import("./commands/index.js");
|
|
156
|
+
const success = await secretsListCommand();
|
|
157
|
+
process.exit(success ? 0 : 1);
|
|
158
|
+
});
|
|
159
|
+
const runsCommand = program.command("runs").description("Inspect and manage execution runs");
|
|
160
|
+
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) => {
|
|
161
|
+
const { runsListCommand } = await import("./commands/index.js");
|
|
162
|
+
const success = await runsListCommand(options);
|
|
163
|
+
process.exit(success ? 0 : 1);
|
|
164
|
+
});
|
|
165
|
+
runsCommand.command("show").argument("<run-id>", "Run ID to inspect").description("Show a run summary with its jobs and steps").option("--json", "Output raw JSON", false).action(async (runId, options) => {
|
|
166
|
+
const { runsShowCommand } = await import("./commands/index.js");
|
|
167
|
+
const success = await runsShowCommand(runId, { json: options.json });
|
|
168
|
+
process.exit(success ? 0 : 1);
|
|
169
|
+
});
|
|
170
|
+
runsCommand.command("logs").argument("<run-id>", "Run ID").description("Print step logs for a run").option("--job <name>", "Only logs for this job").option("-f, --follow", "Tail logs for a live run", false).option("--json", "Output raw JSON", false).action(async (runId, options) => {
|
|
171
|
+
const { runsLogsCommand } = await import("./commands/index.js");
|
|
172
|
+
const success = await runsLogsCommand(runId, {
|
|
173
|
+
job: options.job,
|
|
174
|
+
follow: options.follow,
|
|
175
|
+
json: options.json
|
|
176
|
+
});
|
|
177
|
+
process.exit(success ? 0 : 1);
|
|
178
|
+
});
|
|
179
|
+
runsCommand.command("rerun").argument("<run-id>", "Run ID to rerun").description("Re-trigger a run").option("--json", "Output raw JSON", false).action(async (runId, options) => {
|
|
180
|
+
const { runsRerunCommand } = await import("./commands/index.js");
|
|
181
|
+
const success = await runsRerunCommand(runId, { json: options.json });
|
|
182
|
+
process.exit(success ? 0 : 1);
|
|
183
|
+
});
|
|
184
|
+
runsCommand.command("cancel").argument("[run-id]", "Run ID to cancel").description("Cancel a run, or all in-progress runs on a branch").option("--force", "Force cancel (kill immediately, skip hooks)", false).option("--branch <name>", "Cancel all in-progress runs on this branch").action(async (runId, options) => {
|
|
185
|
+
const { runsCancelCommand } = await import("./commands/index.js");
|
|
186
|
+
const success = await runsCancelCommand(runId, {
|
|
187
|
+
force: options.force,
|
|
188
|
+
branch: options.branch
|
|
189
|
+
});
|
|
190
|
+
process.exit(success ? 0 : 1);
|
|
191
|
+
});
|
|
192
|
+
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) => {
|
|
193
|
+
const { approveCommand } = await import("./commands/index.js");
|
|
194
|
+
const success = await approveCommand(runId, {
|
|
195
|
+
job: options.job,
|
|
196
|
+
step: options.step
|
|
197
|
+
});
|
|
198
|
+
process.exit(success ? 0 : 1);
|
|
199
|
+
});
|
|
200
|
+
program.command("reject").argument("<run-id>", "Run ID whose approval gate to reject").description("Reject a held approval gate for a run").option("--job <name>", "Reject the hold for a specific job").option("--step <index>", "Reject a step-scoped hold (requires --job)").requiredOption("--reason <text>", "Reason for the rejection").action(async (runId, options) => {
|
|
201
|
+
const { rejectCommand } = await import("./commands/index.js");
|
|
202
|
+
const success = await rejectCommand(runId, {
|
|
203
|
+
job: options.job,
|
|
204
|
+
step: options.step,
|
|
205
|
+
reason: options.reason
|
|
206
|
+
});
|
|
207
|
+
process.exit(success ? 0 : 1);
|
|
208
|
+
});
|
|
209
|
+
program.command("types").description("Generate TypeScript declarations for secret contexts").option("--kici-dir <path>", "Path to .kici directory", ".kici").action(async (options) => {
|
|
210
|
+
const { typesCommand } = await import("./commands/index.js");
|
|
211
|
+
const success = await typesCommand({ kiciDir: options.kiciDir });
|
|
212
|
+
process.exit(success ? 0 : 1);
|
|
213
|
+
});
|
|
214
|
+
program.command("endpoints").description("List all webhook entrypoints for the current project").option("--kici-dir <path>", "Path to .kici directory", ".kici").action(async (options) => {
|
|
215
|
+
const { endpointsCommand } = await import("./commands/index.js");
|
|
216
|
+
const success = await endpointsCommand({ kiciDir: options.kiciDir });
|
|
217
|
+
process.exit(success ? 0 : 1);
|
|
218
|
+
});
|
|
219
|
+
program.command("diagnostics").description("Show orchestrators, scalers, and agents (mirrors the dashboard Diagnostics 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) => {
|
|
220
|
+
const { diagnosticsCommand } = await import("./commands/index.js");
|
|
221
|
+
const success = await diagnosticsCommand({
|
|
222
|
+
json: options.json,
|
|
223
|
+
verbose: options.verbose,
|
|
224
|
+
orchestrator: options.orchestrator
|
|
225
|
+
});
|
|
226
|
+
process.exit(success ? 0 : 1);
|
|
227
|
+
});
|
|
228
|
+
program.command("workflows").description("Manage workflow registrations").command("list").description("List permanently registered workflows").option("--json", "Output as JSON", false).option("--stale <duration>", "Filter stale registrations (e.g., 30d, 7d)").option("--trigger-type <type>", "Filter by trigger type").option("--repo <repo>", "Filter by repository").action(async (options) => {
|
|
229
|
+
const { workflowsListCommand } = await import("./commands/index.js");
|
|
230
|
+
const success = await workflowsListCommand({
|
|
231
|
+
json: options.json,
|
|
232
|
+
stale: options.stale,
|
|
233
|
+
triggerType: options.triggerType,
|
|
234
|
+
repo: options.repo
|
|
235
|
+
});
|
|
236
|
+
process.exit(success ? 0 : 1);
|
|
237
|
+
});
|
|
238
|
+
program.command("docs").description("Open the KiCI documentation site in the default browser").option("--no-open", "Print the docs URL instead of opening a browser").action(async (options) => {
|
|
239
|
+
const { docsCommand } = await import("./commands/index.js");
|
|
240
|
+
const success = await docsCommand({ open: options.open });
|
|
241
|
+
process.exit(success ? 0 : 1);
|
|
242
|
+
}).command("llm").description("Print the bundled LLM context (llms-full.txt) to stdout").option("--index", "Print the curated llms.txt index instead of the full bundle", false).option("--out <path>", "Write the bundle to a file instead of stdout").action(async (options) => {
|
|
243
|
+
const { docsLlmCommand } = await import("./commands/index.js");
|
|
244
|
+
const success = await docsLlmCommand({
|
|
245
|
+
index: options.index,
|
|
246
|
+
out: options.out
|
|
247
|
+
});
|
|
248
|
+
process.exit(success ? 0 : 1);
|
|
249
|
+
});
|
|
250
|
+
program.command("admin").description("Operator-facing commands for running instances").command("drain-worker").description("Trigger graceful drain on a worker instance").requiredOption("--url <url>", "Worker URL (e.g., http://worker-host:<port>)").action(async (options) => {
|
|
251
|
+
const { drainWorkerCommand } = await import("./commands/index.js");
|
|
252
|
+
const success = await drainWorkerCommand({ url: options.url });
|
|
253
|
+
process.exit(success ? 0 : 1);
|
|
254
|
+
});
|
|
255
|
+
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) => {
|
|
256
|
+
const { verifyAttestationCommand } = await import("./commands/index.js");
|
|
257
|
+
const success = await verifyAttestationCommand(artifact, options);
|
|
258
|
+
process.exit(success ? 0 : 1);
|
|
259
|
+
});
|
|
260
|
+
return program;
|
|
261
|
+
}
|
|
262
|
+
/** Build the program and parse argv — the bin-shim entry point. */
|
|
263
|
+
function runCli(argv = process.argv) {
|
|
264
|
+
buildProgram().parse(argv);
|
|
265
|
+
}
|
|
266
|
+
if (resolve(process.argv[1] ?? "") === fileURLToPath(import.meta.url)) runCli();
|
|
199
267
|
//#endregion
|
|
200
|
-
export {};
|
|
268
|
+
export { buildProgram, runCli };
|
|
201
269
|
|
|
202
270
|
//# sourceMappingURL=cli.js.map
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* kici approve command
|
|
3
|
+
*
|
|
4
|
+
* Approves a held approval gate for a run. Resolves the held element by
|
|
5
|
+
* `--job` / `--step` (or the sole pending hold), then records the approval via
|
|
6
|
+
* the Platform dashboard API (PAT auth).
|
|
7
|
+
*/
|
|
8
|
+
/** Options for the approve command. */
|
|
9
|
+
export interface ApproveOptions {
|
|
10
|
+
/** Match a hold by its job name. */
|
|
11
|
+
job?: string;
|
|
12
|
+
/** Match a step-scoped hold by its step index. */
|
|
13
|
+
step?: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Approve a held approval gate.
|
|
17
|
+
*
|
|
18
|
+
* @param runId - The run whose hold to approve.
|
|
19
|
+
* @param options - Job/step filters to disambiguate the held element.
|
|
20
|
+
* @returns true on success, false on error.
|
|
21
|
+
*/
|
|
22
|
+
export declare function approveCommand(runId: string, options?: ApproveOptions): Promise<boolean>;
|
|
23
|
+
//# sourceMappingURL=approve.d.ts.map
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import "../chunk-BTugEXQM.js";
|
|
2
|
+
import { listHeldRunsForRun, postApprove, resolveHeldRunContext } from "./held-run-client.js";
|
|
3
|
+
import { resolveHeldRunId } from "./held-run-resolve.js";
|
|
4
|
+
import pc from "picocolors";
|
|
5
|
+
import { logger, toErrorMessage } from "@kici-dev/core";
|
|
6
|
+
//#region src/commands/approve.ts
|
|
7
|
+
/**
|
|
8
|
+
* kici approve command
|
|
9
|
+
*
|
|
10
|
+
* Approves a held approval gate for a run. Resolves the held element by
|
|
11
|
+
* `--job` / `--step` (or the sole pending hold), then records the approval via
|
|
12
|
+
* the Platform dashboard API (PAT auth).
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* Approve a held approval gate.
|
|
16
|
+
*
|
|
17
|
+
* @param runId - The run whose hold to approve.
|
|
18
|
+
* @param options - Job/step filters to disambiguate the held element.
|
|
19
|
+
* @returns true on success, false on error.
|
|
20
|
+
*/
|
|
21
|
+
async function approveCommand(runId, options = {}) {
|
|
22
|
+
try {
|
|
23
|
+
const ctx = await resolveHeldRunContext();
|
|
24
|
+
if (!ctx) return false;
|
|
25
|
+
const resolution = resolveHeldRunId(await listHeldRunsForRun(ctx, runId), {
|
|
26
|
+
job: options.job,
|
|
27
|
+
step: options.step
|
|
28
|
+
});
|
|
29
|
+
if (!resolution.ok) {
|
|
30
|
+
logger.error(pc.red(resolution.error));
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
logger.info(`Approving held run ${pc.cyan(resolution.heldRunId)} for run ${pc.cyan(runId)}...`);
|
|
34
|
+
if (!await postApprove(ctx, resolution.heldRunId)) return false;
|
|
35
|
+
logger.info(pc.green("Approval recorded."));
|
|
36
|
+
logger.info(pc.dim("If the requirement still has unsatisfied clauses, the run stays held until they are."));
|
|
37
|
+
return true;
|
|
38
|
+
} catch (error) {
|
|
39
|
+
logger.error(pc.red(`Error: ${toErrorMessage(error)}`));
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
//#endregion
|
|
44
|
+
export { approveCommand };
|
|
45
|
+
|
|
46
|
+
//# sourceMappingURL=approve.js.map
|
package/dist/commands/compile.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import "../chunk-
|
|
1
|
+
import "../chunk-BTugEXQM.js";
|
|
2
2
|
import { formatError, isCompilerError } from "../errors/formatter.js";
|
|
3
3
|
import "../errors/index.js";
|
|
4
4
|
import { discoverWorkflows, resolveKiciDir } from "../execution/executor.js";
|
|
@@ -7,10 +7,10 @@ import { validateConfig } from "../validation/validator.js";
|
|
|
7
7
|
import "../validation/index.js";
|
|
8
8
|
import { computeLockfileHash, detectGitRoot, generateLockFile, serializeLockFile } from "../lockfile/generator.js";
|
|
9
9
|
import "../lockfile/index.js";
|
|
10
|
+
import path from "node:path";
|
|
10
11
|
import pc from "picocolors";
|
|
11
12
|
import { existsSync } from "node:fs";
|
|
12
13
|
import fs from "node:fs/promises";
|
|
13
|
-
import path from "node:path";
|
|
14
14
|
import { logger, toErrorMessage } from "@kici-dev/core";
|
|
15
15
|
import { execSync } from "node:child_process";
|
|
16
16
|
//#region src/commands/compile.ts
|
|
@@ -80,12 +80,14 @@ async function compileCommand(options) {
|
|
|
80
80
|
try {
|
|
81
81
|
const { loadGlobalConfig } = await import("../remote/config.js");
|
|
82
82
|
const config = await loadGlobalConfig();
|
|
83
|
-
|
|
83
|
+
const hasToken = Boolean(config.pat ?? config.token);
|
|
84
|
+
const hasEndpoint = Boolean(config.platformEndpoint ?? config.endpoint);
|
|
85
|
+
if (hasToken && hasEndpoint && config.activeOrgId) {
|
|
84
86
|
const { typesCommand } = await import("./types.js");
|
|
85
87
|
await typesCommand({ kiciDir });
|
|
86
88
|
}
|
|
87
89
|
} catch {
|
|
88
|
-
logger.warn(pc.yellow("Could not refresh types (
|
|
90
|
+
logger.warn(pc.yellow("Could not refresh types (Platform unreachable). Compilation succeeded."));
|
|
89
91
|
}
|
|
90
92
|
} else logger.info(pc.green("✓") + ` Workflows are valid` + pc.dim(` (${workflowsWithSource.length} workflow${workflowsWithSource.length !== 1 ? "s" : ""})`));
|
|
91
93
|
return true;
|