@kici-dev/compiler 0.1.16 → 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.
Files changed (136) hide show
  1. package/dist/auth/headless-detect.js +1 -1
  2. package/dist/cli-banner.js +1 -1
  3. package/dist/cli.js +56 -19
  4. package/dist/commands/approve.js +1 -1
  5. package/dist/commands/compile.js +5 -3
  6. package/dist/commands/diagnostics.d.ts +7 -0
  7. package/dist/commands/diagnostics.js +58 -0
  8. package/dist/commands/docs.js +1 -1
  9. package/dist/commands/drain-worker.js +1 -1
  10. package/dist/commands/endpoints.js +1 -1
  11. package/dist/commands/fixture.js +1 -1
  12. package/dist/commands/held-run-client.js +1 -1
  13. package/dist/commands/held-run-resolve.js +1 -1
  14. package/dist/commands/hook.js +1 -1
  15. package/dist/commands/index.d.ts +16 -4
  16. package/dist/commands/index.js +10 -4
  17. package/dist/commands/init.js +2 -2
  18. package/dist/commands/login.d.ts +0 -2
  19. package/dist/commands/login.js +1 -3
  20. package/dist/commands/logout.js +1 -1
  21. package/dist/commands/orchestrators.d.ts +25 -0
  22. package/dist/commands/orchestrators.js +115 -0
  23. package/dist/commands/org.js +1 -1
  24. package/dist/commands/reject.js +1 -1
  25. package/dist/commands/run.d.ts +2 -9
  26. package/dist/commands/run.js +256 -315
  27. package/dist/commands/runs/cancel.d.ts +6 -0
  28. package/dist/commands/runs/cancel.js +32 -0
  29. package/dist/commands/runs/list.d.ts +6 -0
  30. package/dist/commands/runs/list.js +49 -0
  31. package/dist/commands/runs/logs.d.ts +7 -0
  32. package/dist/commands/runs/logs.js +67 -0
  33. package/dist/commands/runs/rerun.d.ts +5 -0
  34. package/dist/commands/runs/rerun.js +21 -0
  35. package/dist/commands/runs/show.d.ts +5 -0
  36. package/dist/commands/runs/show.js +65 -0
  37. package/dist/commands/secrets-list.d.ts +7 -9
  38. package/dist/commands/secrets-list.js +40 -64
  39. package/dist/commands/test.d.ts +4 -0
  40. package/dist/commands/test.js +1 -1
  41. package/dist/commands/types.d.ts +3 -5
  42. package/dist/commands/types.js +13 -37
  43. package/dist/commands/verify-attestation.d.ts +12 -0
  44. package/dist/commands/verify-attestation.js +69 -0
  45. package/dist/commands/watch.js +1 -1
  46. package/dist/commands/workflows.js +14 -34
  47. package/dist/errors/capability-gap.js +1 -1
  48. package/dist/errors/formatter.js +1 -1
  49. package/dist/errors/index.js +1 -1
  50. package/dist/execution/executor.js +1 -1
  51. package/dist/execution/index.js +1 -1
  52. package/dist/execution/sdk-alias.js +1 -1
  53. package/dist/execution/ts-loader.js +1 -1
  54. package/dist/fixtures/compiler.js +1 -1
  55. package/dist/fixtures/defaults/index.js +1 -1
  56. package/dist/format.js +1 -1
  57. package/dist/generators/secrets-dts.js +2 -2
  58. package/dist/hooks/detector.js +1 -1
  59. package/dist/hooks/index.js +1 -1
  60. package/dist/hooks/installer.js +1 -1
  61. package/dist/hooks/templates.js +1 -1
  62. package/dist/index.js +1 -1
  63. package/dist/llm-context/llms-full.txt +1047 -132
  64. package/dist/llm-context/llms.txt +4 -1
  65. package/dist/local-executor/dag-scheduler.js +1 -1
  66. package/dist/local-executor/index.js +1 -1
  67. package/dist/local-executor/job-runner.js +37 -16
  68. package/dist/local-executor/materializer.js +1 -1
  69. package/dist/local-executor/output-streamer.js +1 -1
  70. package/dist/local-executor/payload-generator.js +1 -1
  71. package/dist/local-executor/picker.js +1 -1
  72. package/dist/local-executor/secret-loader.js +1 -1
  73. package/dist/local-executor/to-event-payload.js +1 -1
  74. package/dist/local-executor/types.js +1 -1
  75. package/dist/local-executor/workflow-lock.js +0 -0
  76. package/dist/lockfile/generator.d.ts +7 -5
  77. package/dist/lockfile/generator.js +21 -18
  78. package/dist/lockfile/hash-files.js +1 -1
  79. package/dist/lockfile/hasher.js +1 -1
  80. package/dist/lockfile/index.js +1 -1
  81. package/dist/lockfile/purity-analyzer.js +1 -1
  82. package/dist/postinstall.js +1 -1
  83. package/dist/provenance-trust-root.d.ts +14 -0
  84. package/dist/provenance-trust-root.js +49 -0
  85. package/dist/remote/config.d.ts +6 -2
  86. package/dist/remote/config.js +7 -4
  87. package/dist/remote/dashboard-client.d.ts +92 -0
  88. package/dist/remote/dashboard-client.js +168 -0
  89. package/dist/remote/encryption.js +3 -4
  90. package/dist/remote/history.js +1 -1
  91. package/dist/remote/oauth.js +1 -1
  92. package/dist/remote/oidc-discovery.js +1 -1
  93. package/dist/remote/output/json.js +1 -1
  94. package/dist/remote/output/junit.js +1 -1
  95. package/dist/remote/output/streaming.js +1 -1
  96. package/dist/remote/output/summary.js +1 -1
  97. package/dist/remote/platform-client.d.ts +142 -0
  98. package/dist/remote/platform-client.js +187 -0
  99. package/dist/remote/prod-defaults.js +1 -1
  100. package/dist/remote/render.d.ts +11 -0
  101. package/dist/remote/render.js +48 -0
  102. package/dist/remote/secret-upload.js +1 -1
  103. package/dist/remote/uploader.d.ts +9 -0
  104. package/dist/remote/uploader.js +51 -4
  105. package/dist/templates/agents-md.d.ts +1 -1
  106. package/dist/templates/agents-md.js +8 -3
  107. package/dist/templates/index.js +1 -1
  108. package/dist/templates/package-json.js +4 -5
  109. package/dist/templates/tsconfig-json.js +1 -1
  110. package/dist/templates/workflows/hello-world.js +2 -2
  111. package/dist/templates/workflows/hello-world.ts +1 -1
  112. package/dist/templates/workflows/pr-checks.js +3 -3
  113. package/dist/templates/workflows/pr-checks.ts +2 -2
  114. package/dist/test-runner/dry-run.js +1 -1
  115. package/dist/test-runner/event-types.js +1 -1
  116. package/dist/test-runner/git-detector.js +1 -1
  117. package/dist/test-runner/index.js +1 -1
  118. package/dist/test-runner/job-executor.js +1 -1
  119. package/dist/test-runner/output-formatter.js +1 -1
  120. package/dist/test-runner/payload-builder.js +1 -1
  121. package/dist/test-runner/rule-evaluator.js +1 -1
  122. package/dist/test-runner/secrets-file.js +1 -1
  123. package/dist/test-runner/step-context.js +10 -6
  124. package/dist/types.d.ts +8 -5
  125. package/dist/types.js +2 -1
  126. package/dist/validation/index.js +1 -1
  127. package/dist/validation/validator.js +1 -1
  128. package/dist/workflows/hello-world.ts +1 -1
  129. package/dist/workflows/pr-checks.ts +2 -2
  130. package/package.json +5 -4
  131. package/sbom.spdx.json +68 -38
  132. package/dist/commands/cancel.js +0 -124
  133. package/dist/commands/status.js +0 -212
  134. package/dist/remote/client.js +0 -203
  135. package/dist/remote/observer.js +0 -174
  136. /package/dist/{chunk-gOLHoazu.js → chunk-BTugEXQM.js} +0 -0
@@ -34,7 +34,7 @@ The full markdown bundle of every page indexed here is available at https://docs
34
34
  ## CLI and authoring
35
35
 
36
36
  - [CLI authentication](https://docs.kici.dev/user/cli-auth/): Authenticate the KiCI CLI with browser OAuth, device flow, or API key paste
37
- - [CLI reference](https://docs.kici.dev/user/cli-reference/): All CLI commands: compile, run (local/remote), test, login, logout, org, status, cancel, secrets, types, fixture, init, hook, endpoints, workflows, docs, admin
37
+ - [CLI reference](https://docs.kici.dev/user/cli-reference/): All CLI commands: compile, run (local/remote), orchestrators, test, login, logout, org, diagnostics, runs (list/show/logs/rerun/cancel), secrets, types, fixture, init, hook, endpoints, workflows, docs, admin
38
38
  - [Lifecycle hooks](https://docs.kici.dev/user/hooks/): SDK hook API for cancel, cleanup, success, failure, and step-level callbacks
39
39
  - [Lock file and workflow drift](https://docs.kici.dev/user/lock-file-and-drift/): Keep the lock file in sync with your workflow source and avoid drift
40
40
  - [Testing guide](https://docs.kici.dev/user/testing-guide/): Running remote test fixtures with kici run remote
@@ -43,6 +43,7 @@ The full markdown bundle of every page indexed here is available at https://docs
43
43
  ## Workflow features
44
44
 
45
45
  - [Account and sign-in](https://docs.kici.dev/user/account-and-login/): How your KiCI account relates to sign-in methods, and how to change the way you sign in.
46
+ - [Approval gates](https://docs.kici.dev/user/approvals/): Pause a workflow for human sign-off at step, job, or workflow granularity with requireApproval
46
47
  - [Concurrency groups](https://docs.kici.dev/user/concurrency/): Control parallel execution with auto-cancel and queue modes
47
48
  - [Dashboard](https://docs.kici.dev/user/dashboard/)
48
49
  - [Dynamic values](https://docs.kici.dev/user/dynamic-values/)
@@ -51,11 +52,13 @@ The full markdown bundle of every page indexed here is available at https://docs
51
52
  - [Event system](https://docs.kici.dev/user/events/): How KiCI's event model works -- event types, the registration model, event matching, and circuit breaker protection
52
53
  - [Global workflows](https://docs.kici.dev/user/global-workflows/): Cross-repo workflows that run on events from any repo in the same org
53
54
  - [Private npm registries](https://docs.kici.dev/user/private-registries/): Authenticate `npm install` against private registries (CodeArtifact, GitHub Packages, Verdaccio, …) from a workflow's `.kici/package.json`
55
+ - [Build provenance and attestations](https://docs.kici.dev/user/provenance/): Generate and verify signed SLSA provenance for the artifacts your workflows build
54
56
  - [Secrets](https://docs.kici.dev/user/secrets/): How to access secrets in KiCI workflow steps
55
57
 
56
58
  ## Providers
57
59
 
58
60
  - [GitHub App provider](https://docs.kici.dev/user/providers/github/): Connect KiCI to GitHub via a GitHub App — full Checks API, installation-token clones, and cross-org dispatch
61
+ - [Local filesystem (file://) source](https://docs.kici.dev/user/providers/local-file/): Register a git repo present on the agent filesystem as a file:// source, triggered by the kici-admin CLI or a push hook
59
62
  - [Universal-git provider](https://docs.kici.dev/user/providers/universal-git/): Connect Forgejo, Gitea, Gogs, GitLab, or plain GitHub via webhook + PAT or SSH deploy key
60
63
 
61
64
  ## Architecture overview
@@ -1,4 +1,4 @@
1
- import "../chunk-gOLHoazu.js";
1
+ import "../chunk-BTugEXQM.js";
2
2
  //#region src/local-executor/dag-scheduler.ts
3
3
  /**
4
4
  * Detect cycles using Kahn's algorithm.
@@ -1,4 +1,4 @@
1
- import "../chunk-gOLHoazu.js";
1
+ import "../chunk-BTugEXQM.js";
2
2
  import { discoverWorkflows, resolveKiciDir } from "../execution/executor.js";
3
3
  import "../execution/index.js";
4
4
  import { transformTriggers } from "../lockfile/generator.js";
@@ -1,4 +1,4 @@
1
- import "../chunk-gOLHoazu.js";
1
+ import "../chunk-BTugEXQM.js";
2
2
  import { ensureTsLoaderHook } from "../execution/ts-loader.js";
3
3
  import { formatter } from "../test-runner/output-formatter.js";
4
4
  import { createStepContext } from "../test-runner/step-context.js";
@@ -7,6 +7,7 @@ import { toEventPayload } from "./to-event-payload.js";
7
7
  import { pathToFileURL } from "node:url";
8
8
  import path from "node:path";
9
9
  import { applyIncludeExclude, expandMatrix, isDynamicJobFn, setJobOutputsMap, setStepOutputsMap, setStepRefMap } from "@kici-dev/sdk";
10
+ import { formatMatrixSuffix } from "@kici-dev/engine";
10
11
  //#region src/local-executor/job-runner.ts
11
12
  /**
12
13
  * Job resolution (matrix/dynamic) and single-job execution with step context.
@@ -39,15 +40,6 @@ async function resolveSdkSetters(kiciDir) {
39
40
  };
40
41
  }
41
42
  /**
42
- * Format matrix values into a display string for the job name.
43
- * Single-dimension: "node-18"
44
- * Multi-dimensional: "linux, 18"
45
- */
46
- function formatMatrixSuffix(matrixValues) {
47
- if ("value" in matrixValues && matrixValues.value !== void 0) return matrixValues.value;
48
- return Object.values(matrixValues).filter((v) => v !== void 0).join(", ");
49
- }
50
- /**
51
43
  * Resolve a needs entry to a string name.
52
44
  * Handles Job objects, strings, DynamicGroupRef, and object forms.
53
45
  */
@@ -58,6 +50,27 @@ function resolveNeedName(need) {
58
50
  return need.name;
59
51
  }
60
52
  /**
53
+ * Maintain the base-name `{ byMatrix, merged }` envelope as each matrix child
54
+ * completes. `merged` is rebuilt last-write-wins in suffix order so the result
55
+ * is deterministic regardless of child completion order — matching the remote
56
+ * path's name-ordered merge.
57
+ */
58
+ function updateBaseMatrixEnvelope(jobOutputsMap, baseName, matrixValues, childOutputs) {
59
+ const existing = jobOutputsMap.get(baseName);
60
+ const byMatrix = existing && "byMatrix" in existing ? { ...existing.byMatrix } : {};
61
+ const suffix = formatMatrixSuffix(matrixValues);
62
+ byMatrix[suffix] = childOutputs;
63
+ let merged = {};
64
+ for (const key of Object.keys(byMatrix).sort()) merged = {
65
+ ...merged,
66
+ ...byMatrix[key]
67
+ };
68
+ jobOutputsMap.set(baseName, {
69
+ byMatrix,
70
+ merged
71
+ });
72
+ }
73
+ /**
61
74
  * Resolve all jobs in a workflow, expanding matrix jobs and evaluating dynamic jobs.
62
75
  *
63
76
  * - Static jobs: create ResolvedJob with name, needs, job reference
@@ -82,10 +95,13 @@ async function resolveJobs(workflow, event) {
82
95
  debug: () => {}
83
96
  },
84
97
  env: { ...process.env },
85
- kici: { infrastructure: { list: () => Promise.resolve({
86
- scalers: [],
87
- agents: []
88
- }) } }
98
+ kici: {
99
+ infrastructure: { list: () => Promise.resolve({
100
+ scalers: [],
101
+ agents: []
102
+ }) },
103
+ oidc: { token: () => Promise.reject(/* @__PURE__ */ new Error("ctx.kici.oidc.token() is not available during local execution")) }
104
+ }
89
105
  });
90
106
  for (const genJob of generatedJobs) {
91
107
  const genResolved = await resolveStaticJob(genJob, expansionMap);
@@ -285,11 +301,16 @@ async function executeResolvedJobInner(resolvedJob, context, startTime) {
285
301
  }
286
302
  }
287
303
  const stepsWithOutputs = stepResults.filter((s) => s.outputs != null);
288
- if (stepsWithOutputs.length === 1 && stepResults.length === 1) context.jobOutputsMap.set(expandedName, stepsWithOutputs[0].outputs);
304
+ let jobOutputs;
305
+ if (stepsWithOutputs.length === 1 && stepResults.length === 1) jobOutputs = stepsWithOutputs[0].outputs;
289
306
  else if (stepsWithOutputs.length > 0) {
290
307
  const aggregated = {};
291
308
  for (const stepResult of stepsWithOutputs) aggregated[stepResult.name] = stepResult.outputs;
292
- context.jobOutputsMap.set(expandedName, aggregated);
309
+ jobOutputs = aggregated;
310
+ }
311
+ if (jobOutputs) {
312
+ context.jobOutputsMap.set(expandedName, jobOutputs);
313
+ if (expandedName !== job.name) updateBaseMatrixEnvelope(context.jobOutputsMap, job.name, matrixValues, jobOutputs);
293
314
  }
294
315
  const durationMs = Date.now() - startTime;
295
316
  formatter.logJobComplete(expandedName, durationMs);
@@ -1,4 +1,4 @@
1
- import "../chunk-gOLHoazu.js";
1
+ import "../chunk-BTugEXQM.js";
2
2
  import { selectOverlayFiles } from "../remote/uploader.js";
3
3
  import path from "node:path";
4
4
  import fs from "node:fs/promises";
@@ -1,4 +1,4 @@
1
- import "../chunk-gOLHoazu.js";
1
+ import "../chunk-BTugEXQM.js";
2
2
  import pc from "picocolors";
3
3
  import { logger } from "@kici-dev/core";
4
4
  //#region src/local-executor/output-streamer.ts
@@ -1,4 +1,4 @@
1
- import "../chunk-gOLHoazu.js";
1
+ import "../chunk-BTugEXQM.js";
2
2
  import { parseEventArg } from "../test-runner/event-types.js";
3
3
  import { buildEventPayload } from "../test-runner/payload-builder.js";
4
4
  import { execSync } from "node:child_process";
@@ -1,4 +1,4 @@
1
- import "../chunk-gOLHoazu.js";
1
+ import "../chunk-BTugEXQM.js";
2
2
  import { transformTriggers } from "../lockfile/generator.js";
3
3
  import { parseEventArg, triggerSummary, triggerToEventArg } from "../test-runner/event-types.js";
4
4
  import pc from "picocolors";
@@ -1,4 +1,4 @@
1
- import "../chunk-gOLHoazu.js";
1
+ import "../chunk-BTugEXQM.js";
2
2
  import { loadSecretsFile } from "../test-runner/secrets-file.js";
3
3
  import path from "node:path";
4
4
  import { readFile } from "node:fs/promises";
@@ -1,4 +1,4 @@
1
- import "../chunk-gOLHoazu.js";
1
+ import "../chunk-BTugEXQM.js";
2
2
  //#region src/local-executor/to-event-payload.ts
3
3
  /**
4
4
  * Map a {@link SimulatedEvent} into the normalized SDK {@link EventPayload}
@@ -1,2 +1,2 @@
1
- import "../chunk-gOLHoazu.js";
1
+ import "../chunk-BTugEXQM.js";
2
2
  export {};
@@ -13,11 +13,13 @@ export declare function detectGitRoot(): string;
13
13
  *
14
14
  * The authoritative lockfile differs by manager: `.kici/package-lock.json` for
15
15
  * npm, the repo-root `pnpm-lock.yaml` for a pnpm workspace, the repo-root
16
- * `yarn.lock` for yarn. A pnpm/yarn `.kici/` member resolves against the root
17
- * lockfile, so keying on `.kici/package-lock.json` alone would miss the
18
- * authoritative graph. The hash input is prefixed with the manager name so two
19
- * managers can never collide on identical lockfile bytes (and a restored tree
20
- * can never be the wrong layout for the agent's manager).
16
+ * `yarn.lock` for a yarn workspace. A pnpm/yarn `.kici/` member resolves against
17
+ * the root lockfile, so keying on `.kici/package-lock.json` alone would miss the
18
+ * authoritative graph. A standalone `.kici` yarn project (its own
19
+ * `packageManager` field + `.kici/yarn.lock`, no root signal) is detected from
20
+ * `.kici/` and keyed on `.kici/yarn.lock`. The hash input is prefixed with the
21
+ * manager name so two managers can never collide on identical lockfile bytes
22
+ * (and a restored tree can never be the wrong layout for the agent's manager).
21
23
  *
22
24
  * @param gitRoot - Absolute path to git repository root
23
25
  * @returns Hex SHA-256 hash string, or null if no lockfile is found
@@ -1,4 +1,4 @@
1
- import "../chunk-gOLHoazu.js";
1
+ import "../chunk-BTugEXQM.js";
2
2
  import { SCHEMA_VERSION as SCHEMA_VERSION$1 } from "../types.js";
3
3
  import { computeContentHash } from "./hasher.js";
4
4
  import { resolveHashFiles } from "./hash-files.js";
@@ -37,23 +37,24 @@ function detectGitRoot() {
37
37
  *
38
38
  * The authoritative lockfile differs by manager: `.kici/package-lock.json` for
39
39
  * npm, the repo-root `pnpm-lock.yaml` for a pnpm workspace, the repo-root
40
- * `yarn.lock` for yarn. A pnpm/yarn `.kici/` member resolves against the root
41
- * lockfile, so keying on `.kici/package-lock.json` alone would miss the
42
- * authoritative graph. The hash input is prefixed with the manager name so two
43
- * managers can never collide on identical lockfile bytes (and a restored tree
44
- * can never be the wrong layout for the agent's manager).
40
+ * `yarn.lock` for a yarn workspace. A pnpm/yarn `.kici/` member resolves against
41
+ * the root lockfile, so keying on `.kici/package-lock.json` alone would miss the
42
+ * authoritative graph. A standalone `.kici` yarn project (its own
43
+ * `packageManager` field + `.kici/yarn.lock`, no root signal) is detected from
44
+ * `.kici/` and keyed on `.kici/yarn.lock`. The hash input is prefixed with the
45
+ * manager name so two managers can never collide on identical lockfile bytes
46
+ * (and a restored tree can never be the wrong layout for the agent's manager).
45
47
  *
46
48
  * @param gitRoot - Absolute path to git repository root
47
49
  * @returns Hex SHA-256 hash string, or null if no lockfile is found
48
50
  */
49
51
  function computeLockfileHash(gitRoot) {
50
- const pm = detectPackageManagerSync(gitRoot);
51
- const lockfilePath = pm === PackageManager.Pnpm ? path.join(gitRoot, "pnpm-lock.yaml") : pm === PackageManager.Yarn ? path.join(gitRoot, "yarn.lock") : path.join(gitRoot, ".kici", "package-lock.json");
52
- try {
52
+ const pm = detectPackageManagerSync(gitRoot) === PackageManager.Npm ? detectPackageManagerSync(path.join(gitRoot, ".kici")) : detectPackageManagerSync(gitRoot);
53
+ const candidates = pm === PackageManager.Pnpm ? [path.join(gitRoot, "pnpm-lock.yaml")] : pm === PackageManager.Yarn ? [path.join(gitRoot, "yarn.lock"), path.join(gitRoot, ".kici", "yarn.lock")] : [path.join(gitRoot, ".kici", "package-lock.json")];
54
+ for (const lockfilePath of candidates) try {
53
55
  return sha256(`${pm}\n${readFileSync(lockfilePath, "utf-8")}`);
54
- } catch {
55
- return null;
56
- }
56
+ } catch {}
57
+ return null;
57
58
  }
58
59
  /**
59
60
  * Format export reference with hash syntax.
@@ -455,15 +456,17 @@ function normalizeRunsOnForLock(runsOn) {
455
456
  };
456
457
  }
457
458
  /**
458
- * Validate runsOn labels:
459
- * 1. Reject kici:* reserved prefix in user-supplied labels.
460
- * 2. Reject overlap between required and excluded labels.
459
+ * Validate runsOn labels: reject overlap between required and excluded labels.
460
+ *
461
+ * `kici:` labels ARE valid runsOn selectors. runsOn expresses a requirement on
462
+ * candidate agents — it only narrows the set, it never grants authority — so
463
+ * targeting a `kici:os:linux` / `kici:role:builder` label is benign. The forgery
464
+ * boundary is label *setting* (scaler labelSet validation + the agent
465
+ * register-time scope gate), which is enforced elsewhere and unaffected here.
461
466
  */
462
467
  function validateRunsOn(runsOn, jobName) {
463
- const labels = typeof runsOn === "string" ? [runsOn] : Array.isArray(runsOn) ? runsOn : Array.isArray(runsOn.labels) ? runsOn.labels : [runsOn.labels];
464
- const reservedLabels = labels.filter((l) => l.toLowerCase().startsWith("kici:"));
465
- if (reservedLabels.length > 0) throw new Error(`Job "${jobName}": labels with 'kici:' prefix are reserved and cannot be used in runsOn: ${reservedLabels.join(", ")}`);
466
468
  if (typeof runsOn === "string" || Array.isArray(runsOn)) return;
469
+ const labels = Array.isArray(runsOn.labels) ? runsOn.labels : [runsOn.labels];
467
470
  const exclude = runsOn.exclude ? Array.isArray(runsOn.exclude) ? runsOn.exclude : [runsOn.exclude] : [];
468
471
  const overlap = labels.filter((l) => exclude.includes(l));
469
472
  if (overlap.length > 0) throw new Error(`Job "${jobName}": labels and exclude overlap on [${overlap.join(", ")}]. A label cannot be both required and excluded.`);
@@ -1,4 +1,4 @@
1
- import "../chunk-gOLHoazu.js";
1
+ import "../chunk-BTugEXQM.js";
2
2
  import path from "node:path";
3
3
  import { readFileSync } from "node:fs";
4
4
  import fg from "fast-glob";
@@ -1,4 +1,4 @@
1
- import "../chunk-gOLHoazu.js";
1
+ import "../chunk-BTugEXQM.js";
2
2
  import { normalizeLineEndings, sha256 } from "@kici-dev/core";
3
3
  //#region src/lockfile/hasher.ts
4
4
  /**
@@ -1,4 +1,4 @@
1
- import "../chunk-gOLHoazu.js";
1
+ import "../chunk-BTugEXQM.js";
2
2
  import { COMPILE_SCHEMA_VERSION, computeContentHash } from "./hasher.js";
3
3
  import { computeLockfileHash, detectGitRoot, generateLockFile, serializeLockFile } from "./generator.js";
4
4
  export { COMPILE_SCHEMA_VERSION, computeContentHash, computeLockfileHash, detectGitRoot, generateLockFile, serializeLockFile };
@@ -1,4 +1,4 @@
1
- import "../chunk-gOLHoazu.js";
1
+ import "../chunk-BTugEXQM.js";
2
2
  import ts from "typescript";
3
3
  //#region src/lockfile/purity-analyzer.ts
4
4
  /**
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import "./chunk-gOLHoazu.js";
2
+ import "./chunk-BTugEXQM.js";
3
3
  import path from "node:path";
4
4
  import { readFile } from "node:fs/promises";
5
5
  import { spawn } from "node:child_process";
@@ -0,0 +1,14 @@
1
+ /** Structural JWKS shape — the engine verifier owns the real `jose` type. */
2
+ export interface JsonWebKeySet {
3
+ keys: Record<string, unknown>[];
4
+ }
5
+ export interface TrustRoot {
6
+ issuer: string;
7
+ jwks: JsonWebKeySet;
8
+ }
9
+ /**
10
+ * Resolve `--trust-root`: an HTTPS issuer URL (discovery → `jwks_uri` → JWKS) or
11
+ * a self-contained offline file `{ issuer, jwks }`.
12
+ */
13
+ export declare function resolveTrustRoot(trustRoot: string): Promise<TrustRoot>;
14
+ //# sourceMappingURL=provenance-trust-root.d.ts.map
@@ -0,0 +1,49 @@
1
+ import "./chunk-BTugEXQM.js";
2
+ import { readFile } from "node:fs/promises";
3
+ //#region src/provenance-trust-root.ts
4
+ /**
5
+ * Trust-root resolution for `kici verify-attestation`.
6
+ *
7
+ * The verifier never blindly trusts a provenance token's own `iss`: the trusted
8
+ * issuer + its JWKS are supplied out-of-band via `--trust-root`. This resolver
9
+ * turns that flag into a concrete `{ issuer, jwks }`:
10
+ *
11
+ * - an **HTTPS issuer URL** (online): fetch `<url>/.well-known/openid-configuration`,
12
+ * read its `issuer` + `jwks_uri`, then fetch the JWKS;
13
+ * - a **local file path** (offline / air-gapped): a self-contained
14
+ * `{ "issuer": "...", "jwks": { "keys": [...] } }` JSON document, no network.
15
+ *
16
+ * Node-specific (`fetch` + `fs`) so the engine verify core stays pure /
17
+ * browser-safe; the JWKS is passed straight through to the engine, which owns
18
+ * the crypto, so this module defines only a structural `JsonWebKeySet` type
19
+ * rather than depending on `jose`.
20
+ */
21
+ /**
22
+ * Resolve `--trust-root`: an HTTPS issuer URL (discovery → `jwks_uri` → JWKS) or
23
+ * a self-contained offline file `{ issuer, jwks }`.
24
+ */
25
+ async function resolveTrustRoot(trustRoot) {
26
+ if (/^https?:\/\//.test(trustRoot)) {
27
+ const base = trustRoot.replace(/\/+$/, "");
28
+ const disco = await fetchJson(`${base}/.well-known/openid-configuration`);
29
+ return {
30
+ issuer: typeof disco.issuer === "string" ? disco.issuer : base,
31
+ jwks: await fetchJson(typeof disco.jwks_uri === "string" ? disco.jwks_uri : `${base}/.well-known/jwks.json`)
32
+ };
33
+ }
34
+ const file = JSON.parse(await readFile(trustRoot, "utf-8"));
35
+ if (typeof file.issuer !== "string" || !file.jwks || !Array.isArray(file.jwks.keys)) throw new Error("trust-root file must contain { issuer, jwks: { keys: [...] } }");
36
+ return {
37
+ issuer: file.issuer,
38
+ jwks: file.jwks
39
+ };
40
+ }
41
+ async function fetchJson(url) {
42
+ const res = await fetch(url);
43
+ if (!res.ok) throw new Error(`failed to fetch ${url}: ${res.status}`);
44
+ return await res.json();
45
+ }
46
+ //#endregion
47
+ export { resolveTrustRoot };
48
+
49
+ //# sourceMappingURL=provenance-trust-root.js.map
@@ -9,8 +9,6 @@ export interface GlobalConfig {
9
9
  endpoint?: string;
10
10
  /** Platform relay URL */
11
11
  platformEndpoint?: string;
12
- /** Connection mode: 'platform' or 'direct' */
13
- connectionMode?: 'platform' | 'direct';
14
12
  /** Routing key for webhook source identification (e.g., 'github:42') */
15
13
  routingKey?: string;
16
14
  /** Personal access token (from OAuth login) */
@@ -23,6 +21,12 @@ export interface GlobalConfig {
23
21
  activeOrgId?: string;
24
22
  /** User email from OIDC token */
25
23
  userEmail?: string;
24
+ /**
25
+ * Per-org default orchestrator cluster for `kici run remote`, keyed by org id.
26
+ * Set by `kici orchestrators use <cluster>`; consulted when `--orchestrator`
27
+ * is omitted so a developer with one preferred cluster types no flag.
28
+ */
29
+ defaultClusters?: Record<string, string>;
26
30
  }
27
31
  /**
28
32
  * Returns the global KiCI config directory path.
@@ -1,9 +1,8 @@
1
- import "../chunk-gOLHoazu.js";
1
+ import "../chunk-BTugEXQM.js";
2
2
  import path from "node:path";
3
3
  import fs from "node:fs/promises";
4
4
  import os from "node:os";
5
5
  //#region src/remote/config.ts
6
- const VALID_CONNECTION_MODES = ["platform", "direct"];
7
6
  /**
8
7
  * Strips unknown keys and validates known fields from a raw config object.
9
8
  * Returns a clean GlobalConfig with only recognized, valid fields.
@@ -15,13 +14,17 @@ function sanitizeConfig(raw) {
15
14
  if (typeof obj.token === "string") config.token = obj.token;
16
15
  if (typeof obj.endpoint === "string") config.endpoint = obj.endpoint;
17
16
  if (typeof obj.platformEndpoint === "string") config.platformEndpoint = obj.platformEndpoint;
18
- if (typeof obj.connectionMode === "string" && VALID_CONNECTION_MODES.includes(obj.connectionMode)) config.connectionMode = obj.connectionMode;
19
17
  if (typeof obj.routingKey === "string") config.routingKey = obj.routingKey;
20
18
  if (typeof obj.pat === "string") config.pat = obj.pat;
21
19
  if (typeof obj.patId === "string") config.patId = obj.patId;
22
20
  if (typeof obj.patExpiresAt === "string") config.patExpiresAt = obj.patExpiresAt;
23
21
  if (typeof obj.activeOrgId === "string") config.activeOrgId = obj.activeOrgId;
24
22
  if (typeof obj.userEmail === "string") config.userEmail = obj.userEmail;
23
+ if (typeof obj.defaultClusters === "object" && obj.defaultClusters !== null && !Array.isArray(obj.defaultClusters)) {
24
+ const clusters = {};
25
+ for (const [orgId, clusterName] of Object.entries(obj.defaultClusters)) if (typeof clusterName === "string") clusters[orgId] = clusterName;
26
+ if (Object.keys(clusters).length > 0) config.defaultClusters = clusters;
27
+ }
25
28
  return config;
26
29
  }
27
30
  /**
@@ -76,13 +79,13 @@ async function mergeGlobalConfig(partial) {
76
79
  if (partial.token !== void 0) merged.token = partial.token;
77
80
  if (partial.endpoint !== void 0) merged.endpoint = partial.endpoint;
78
81
  if (partial.platformEndpoint !== void 0) merged.platformEndpoint = partial.platformEndpoint;
79
- if (partial.connectionMode !== void 0) merged.connectionMode = partial.connectionMode;
80
82
  if (partial.routingKey !== void 0) merged.routingKey = partial.routingKey;
81
83
  if (partial.pat !== void 0) merged.pat = partial.pat;
82
84
  if (partial.patId !== void 0) merged.patId = partial.patId;
83
85
  if (partial.patExpiresAt !== void 0) merged.patExpiresAt = partial.patExpiresAt;
84
86
  if (partial.activeOrgId !== void 0) merged.activeOrgId = partial.activeOrgId;
85
87
  if (partial.userEmail !== void 0) merged.userEmail = partial.userEmail;
88
+ if (partial.defaultClusters !== void 0) merged.defaultClusters = partial.defaultClusters;
86
89
  await saveGlobalConfig(merged);
87
90
  return merged;
88
91
  }
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Typed client for the Platform org-scoped dashboard API (the endpoints the
3
+ * web UI uses). Authenticated with the stored PAT + active org. This is the
4
+ * only place in the CLI that knows these routes.
5
+ */
6
+ import { z } from 'zod';
7
+ import { type RunListResponse, type RunListItem, type DiagnosticsInfrastructureResponse, type DiagnosticsSummaryResponse, type DashboardRunDetailApiResponse, type DashboardStepLogsApiResponse, type RegistrationItem } from '@kici-dev/engine';
8
+ import { type GlobalConfig } from './config.js';
9
+ export type DashboardErrorKind = 'not_logged_in' | 'no_active_org' | 'unauthorized' | 'forbidden' | 'not_found' | 'conflict' | 'cooldown' | 'orchestrator_offline' | 'http';
10
+ /** Typed error raised by every DashboardClient method on a non-2xx response. */
11
+ export declare class DashboardClientError extends Error {
12
+ readonly kind: DashboardErrorKind;
13
+ readonly status?: number | undefined;
14
+ constructor(kind: DashboardErrorKind, message: string, status?: number | undefined);
15
+ }
16
+ /** Filters accepted by the runs-list endpoint. */
17
+ export interface RunsListFilters {
18
+ status?: string;
19
+ workflow?: string;
20
+ branch?: string;
21
+ repo?: string;
22
+ trigger?: string;
23
+ source?: string;
24
+ since?: string;
25
+ page?: number;
26
+ }
27
+ /** Result of {@link DashboardClient.listRegistrations}. */
28
+ export interface RegistrationsListResult {
29
+ registrations: RegistrationItem[];
30
+ registryVersion: number;
31
+ registryUpdatedAt: string;
32
+ }
33
+ /** Filters accepted by the registrations-list endpoint. */
34
+ export interface RegistrationsListFilters {
35
+ triggerType?: string;
36
+ repoIdentifier?: string;
37
+ }
38
+ /**
39
+ * A secret context (environment) as surfaced to the developer CLI's
40
+ * `secrets list` / `types` commands. The orchestrator returns the per-env
41
+ * secret key names (never values) when `includeSecrets` is requested.
42
+ */
43
+ declare const environmentContextSchema: z.ZodObject<{
44
+ name: z.ZodString;
45
+ enabled: z.ZodBoolean;
46
+ allowLocalExecution: z.ZodBoolean;
47
+ secretKeys: z.ZodDefault<z.ZodArray<z.ZodString>>;
48
+ }, z.core.$strip>;
49
+ /** A secret context (environment) returned by {@link DashboardClient.listEnvironments}. */
50
+ export type EnvironmentContext = z.infer<typeof environmentContextSchema>;
51
+ export declare class DashboardClient {
52
+ private readonly endpoint;
53
+ private readonly token;
54
+ private readonly orgId;
55
+ private constructor();
56
+ static fromConfig(config: GlobalConfig): DashboardClient;
57
+ static load(): Promise<DashboardClient>;
58
+ private orgUrl;
59
+ private request;
60
+ private throwForStatus;
61
+ /** Generic GET helper used by typed methods (and tests). */
62
+ getJson(path: string): Promise<unknown>;
63
+ /** Generic POST helper used by typed methods (and tests). */
64
+ postJson(path: string, body?: unknown): Promise<unknown>;
65
+ getDiagnosticsSummary(): Promise<DiagnosticsSummaryResponse>;
66
+ getInfrastructure(): Promise<DiagnosticsInfrastructureResponse>;
67
+ listRuns(filters?: RunsListFilters): Promise<RunListResponse>;
68
+ getRun(runId: string): Promise<RunListItem>;
69
+ getRunDetail(runId: string): Promise<DashboardRunDetailApiResponse>;
70
+ getStepLogs(runId: string, jobId: string, stepIndex: number): Promise<DashboardStepLogsApiResponse>;
71
+ rerunRun(runId: string): Promise<{
72
+ newRunId: string;
73
+ }>;
74
+ cancelRun(runId: string, force: boolean): Promise<{
75
+ cancelledJobs?: number;
76
+ }>;
77
+ cancelByBranch(branch: string): Promise<{
78
+ cancelledRuns?: number;
79
+ }>;
80
+ /** List the org's permanently registered workflows (GET /registrations). */
81
+ listRegistrations(filters?: RegistrationsListFilters): Promise<RegistrationsListResult>;
82
+ /**
83
+ * List the org's environments as secret contexts (GET /environments).
84
+ *
85
+ * Pass `includeSecrets` to have the orchestrator attach each environment's
86
+ * reachable secret key names (never values). Used by `kici secrets list`
87
+ * and `kici types`.
88
+ */
89
+ listEnvironments(includeSecrets?: boolean): Promise<EnvironmentContext[]>;
90
+ }
91
+ export {};
92
+ //# sourceMappingURL=dashboard-client.d.ts.map