@kici-dev/compiler 0.1.27 → 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.
Files changed (153) hide show
  1. package/dist/auth/headless-detect.d.ts +14 -5
  2. package/dist/auth/headless-detect.js +50 -9
  3. package/dist/cli.js +120 -11
  4. package/dist/commands/compile.js +28 -4
  5. package/dist/commands/diagnostics.js +14 -2
  6. package/dist/commands/doctor.d.ts +64 -0
  7. package/dist/commands/doctor.js +413 -0
  8. package/dist/commands/endpoints.js +6 -0
  9. package/dist/commands/fixture.js +13 -0
  10. package/dist/commands/hook.js +3 -2
  11. package/dist/commands/index.d.ts +8 -0
  12. package/dist/commands/index.js +5 -1
  13. package/dist/commands/init-host-os.d.ts +34 -0
  14. package/dist/commands/init-host-os.js +44 -0
  15. package/dist/commands/init.d.ts +4 -0
  16. package/dist/commands/init.js +159 -36
  17. package/dist/commands/local.d.ts +28 -2
  18. package/dist/commands/local.js +74 -5
  19. package/dist/commands/login.js +1 -1
  20. package/dist/commands/notifications.d.ts +61 -0
  21. package/dist/commands/notifications.js +274 -0
  22. package/dist/commands/preview.js +8 -1
  23. package/dist/commands/run-routed.js +10 -1
  24. package/dist/commands/run.js +41 -12
  25. package/dist/commands/runs/artifacts/download.d.ts +24 -0
  26. package/dist/commands/runs/artifacts/download.js +154 -0
  27. package/dist/commands/runs/artifacts/list.d.ts +5 -0
  28. package/dist/commands/runs/artifacts/list.js +47 -0
  29. package/dist/commands/runs/cancel.js +2 -2
  30. package/dist/commands/runs/list.js +8 -2
  31. package/dist/commands/verify-attestation.d.ts +3 -1
  32. package/dist/commands/verify-attestation.js +18 -7
  33. package/dist/errors/formatter.d.ts +14 -1
  34. package/dist/errors/formatter.js +13 -3
  35. package/dist/errors/index.d.ts +2 -1
  36. package/dist/errors/index.js +3 -2
  37. package/dist/errors/source-location.d.ts +20 -0
  38. package/dist/errors/source-location.js +45 -0
  39. package/dist/execution/executor.js +25 -5
  40. package/dist/fixtures/defaults/index.js +2 -1
  41. package/dist/llm-context/llms-architecture.txt +48 -19
  42. package/dist/llm-context/llms-cli.txt +2461 -1582
  43. package/dist/llm-context/llms-features.txt +178 -106
  44. package/dist/llm-context/llms-full.txt +6124 -4423
  45. package/dist/llm-context/llms-getting-started.txt +306 -42
  46. package/dist/llm-context/llms-patterns.txt +13 -7
  47. package/dist/llm-context/llms-sdk-runtime.txt +2013 -0
  48. package/dist/llm-context/llms-sdk.txt +591 -2152
  49. package/dist/llm-context/llms.txt +30 -16
  50. package/dist/local-plane/orchestrator-process.d.ts +12 -7
  51. package/dist/local-plane/orchestrator-process.js +28 -14
  52. package/dist/local-plane/os-mismatch-hint.d.ts +16 -0
  53. package/dist/local-plane/os-mismatch-hint.js +34 -0
  54. package/dist/local-plane/plane-liveness.d.ts +68 -0
  55. package/dist/local-plane/plane-liveness.js +145 -0
  56. package/dist/local-plane/plane-manager.d.ts +60 -18
  57. package/dist/local-plane/plane-manager.js +210 -70
  58. package/dist/local-plane/plane-trigger.d.ts +13 -4
  59. package/dist/local-plane/plane-trigger.js +27 -14
  60. package/dist/local-plane/platform-attach.js +1 -5
  61. package/dist/local-plane/port-holder.d.ts +78 -0
  62. package/dist/local-plane/port-holder.js +227 -0
  63. package/dist/local-plane/postgres.d.ts +15 -3
  64. package/dist/local-plane/postgres.js +34 -12
  65. package/dist/local-plane/run-follow.d.ts +20 -0
  66. package/dist/local-plane/run-follow.js +51 -4
  67. package/dist/local-plane/scaler-config.d.ts +28 -14
  68. package/dist/local-plane/scaler-config.js +59 -41
  69. package/dist/local-plane/source-provider.js +4 -10
  70. package/dist/lockfile/generator.d.ts +14 -1
  71. package/dist/lockfile/generator.js +99 -33
  72. package/dist/lockfile/index.d.ts +3 -1
  73. package/dist/lockfile/index.js +3 -2
  74. package/dist/lockfile/purity-diagnostics.d.ts +31 -0
  75. package/dist/lockfile/purity-diagnostics.js +52 -0
  76. package/dist/postinstall.js +2 -1
  77. package/dist/remote/artifact-extract.d.ts +8 -0
  78. package/dist/remote/artifact-extract.js +58 -0
  79. package/dist/remote/config.d.ts +21 -3
  80. package/dist/remote/config.js +24 -5
  81. package/dist/remote/dashboard-client.d.ts +39 -2
  82. package/dist/remote/dashboard-client.js +47 -4
  83. package/dist/remote/fs-case.d.ts +21 -0
  84. package/dist/remote/fs-case.js +45 -0
  85. package/dist/remote/history.d.ts +9 -3
  86. package/dist/remote/history.js +79 -10
  87. package/dist/remote/local-repo-identity.d.ts +1 -1
  88. package/dist/remote/local-repo-identity.js +2 -1
  89. package/dist/remote/notifications-client.d.ts +149 -0
  90. package/dist/remote/notifications-client.js +103 -0
  91. package/dist/remote/oauth.d.ts +13 -0
  92. package/dist/remote/oauth.js +31 -5
  93. package/dist/remote/output/summary.js +76 -14
  94. package/dist/remote/render.js +30 -9
  95. package/dist/remote/uploader.js +5 -4
  96. package/dist/templates/agents-md.d.ts +1 -1
  97. package/dist/templates/agents-md.js +6 -6
  98. package/dist/templates/index.d.ts +1 -1
  99. package/dist/templates/index.js +2 -2
  100. package/dist/templates/package-json.d.ts +15 -0
  101. package/dist/templates/package-json.js +26 -5
  102. package/dist/test-runner/dry-run.d.ts +2 -1
  103. package/dist/test-runner/dry-run.js +18 -1
  104. package/dist/test-runner/event-types.d.ts +2 -0
  105. package/dist/test-runner/event-types.js +3 -0
  106. package/dist/test-runner/job-executor.d.ts +1 -0
  107. package/dist/test-runner/job-executor.js +81 -43
  108. package/dist/test-runner/output-formatter.d.ts +5 -2
  109. package/dist/test-runner/output-formatter.js +6 -4
  110. package/dist/test-runner/payload-builder.d.ts +7 -1
  111. package/dist/test-runner/payload-builder.js +11 -2
  112. package/dist/test-runner/rule-evaluator.d.ts +7 -3
  113. package/dist/test-runner/rule-evaluator.js +13 -12
  114. package/dist/test-runner/step-context.d.ts +23 -5
  115. package/dist/test-runner/step-context.js +28 -118
  116. package/dist/types.d.ts +21 -2
  117. package/dist/types.js +4 -2
  118. package/dist/validation/index.d.ts +2 -0
  119. package/dist/validation/index.js +2 -1
  120. package/dist/validation/typecheck.d.ts +28 -0
  121. package/dist/validation/typecheck.js +110 -0
  122. package/dist/validation/validator.d.ts +9 -4
  123. package/dist/validation/validator.js +38 -44
  124. package/package.json +12 -15
  125. package/sbom.spdx.json +1322 -1964
  126. package/dist/assets/api-TJJVHrjC.json +0 -118
  127. package/dist/assets/descriptor-BTtjzN9L.json +0 -1382
  128. package/dist/assets/package-BpQF9kR8.json +0 -74
  129. package/dist/assets/package-Ceo2h27X.json +0 -89
  130. package/dist/assets/source_context-D0atuL28.json +0 -20
  131. package/dist/assets/type-BFqO8SCZ.json +0 -202
  132. package/dist/commands/cancel.d.ts +0 -22
  133. package/dist/commands/detect-package-manager.d.ts +0 -42
  134. package/dist/commands/held-run-resolve.d.ts +0 -50
  135. package/dist/commands/status.d.ts +0 -34
  136. package/dist/commands/test.d.ts +0 -88
  137. package/dist/errors/codes.d.ts +0 -25
  138. package/dist/local-executor/dag-scheduler.d.ts +0 -44
  139. package/dist/local-executor/index.d.ts +0 -23
  140. package/dist/local-executor/job-runner.d.ts +0 -47
  141. package/dist/local-executor/materializer.d.ts +0 -44
  142. package/dist/local-executor/output-streamer.d.ts +0 -31
  143. package/dist/local-executor/payload-generator.d.ts +0 -16
  144. package/dist/local-executor/picker.d.ts +0 -33
  145. package/dist/local-executor/runs-on-display.d.ts +0 -9
  146. package/dist/local-executor/secret-loader.d.ts +0 -18
  147. package/dist/local-executor/to-event-payload.d.ts +0 -16
  148. package/dist/local-executor/types.d.ts +0 -93
  149. package/dist/local-executor/workflow-lock.d.ts +0 -82
  150. package/dist/package-F7UXSDHW.json +0 -74
  151. package/dist/remote/client.d.ts +0 -210
  152. package/dist/remote/observer.d.ts +0 -81
  153. package/dist/test-runner/summary.d.ts +0 -7
@@ -15,7 +15,13 @@ async function runsListCommand(options = {}) {
15
15
  return true;
16
16
  }
17
17
  if (page.runs.length === 0) {
18
- console.log(pc.gray("No runs found."));
18
+ const activity = await client.getWebhookActivity().catch(() => null);
19
+ if (activity && activity.received > 0) {
20
+ const win = activity.windowMinutes === 60 ? "the last hour" : `the last ${activity.windowMinutes} minutes`;
21
+ const headline = activity.orchestratorUnavailable || activity.matched === void 0 ? `${activity.received} webhooks received in ${win} but none produced a run` : `${activity.received} webhooks received in ${win}, ${activity.matched} matched`;
22
+ console.log(pc.yellow(`${headline}.`));
23
+ console.log(pc.gray(`Run ${pc.cyan("kici preview push")} to test your triggers locally.`));
24
+ } else console.log(pc.gray("No runs found."));
19
25
  return true;
20
26
  }
21
27
  const rows = page.runs.map((r) => [
@@ -36,7 +42,7 @@ async function runsListCommand(options = {}) {
36
42
  "started",
37
43
  "duration"
38
44
  ], rows));
39
- console.log(pc.gray(`\nPage ${page.page} · ${page.runs.length} of ${page.total}${page.hasMore ? " (more — use --page)" : ""}`));
45
+ console.log(pc.gray(`\n${page.runs.length} of ~${page.approxTotal} runs${page.nextCursor ? ` (more — use --cursor ${page.nextCursor})` : ""}`));
40
46
  return true;
41
47
  } catch (err) {
42
48
  logger.error(pc.red(err instanceof DashboardClientError ? err.message : toErrorMessage(err)));
@@ -3,7 +3,9 @@ export interface VerifyAttestationOptions {
3
3
  bundle?: string;
4
4
  /**
5
5
  * Trusted issuer URL (online discovery) or a self-contained `{ issuer, jwks }`
6
- * file. Optional — defaults to the hosted KiCI Platform's provenance issuer.
6
+ * file. Optional — defaults to the configured orchestrator, falling back to
7
+ * the hosted KiCI Platform's provenance issuer when no orchestrator is
8
+ * configured.
7
9
  */
8
10
  trustRoot?: string;
9
11
  /** Expected token audience (defaults to the KiCI provenance audience). */
@@ -1,5 +1,6 @@
1
1
  import "../rolldown-runtime-ClRpJifh.js";
2
2
  import { resolveTrustRoot } from "../provenance-trust-root.js";
3
+ import { loadGlobalConfig } from "../remote/config.js";
3
4
  import "../remote/prod-defaults.js";
4
5
  import pc from "picocolors";
5
6
  import { readFile } from "node:fs/promises";
@@ -16,10 +17,14 @@ import { verifyKiciBundle } from "@kici-dev/engine/provenance/verify";
16
17
  * `@kici-dev/engine`. The engine owns all crypto; this command is the thin Node
17
18
  * wrapper (fs / fetch / artifact digest / output).
18
19
  *
19
- * `--trust-root` is optional: when omitted it defaults to the hosted KiCI
20
- * Platform's provenance issuer, so the common case (verifying a bundle attested
21
- * on the hosted platform) needs no flag. Pass `--trust-root` to verify against a
22
- * different environment (e.g. staging) or an offline `{ issuer, jwks }` file.
20
+ * `--trust-root` is optional: when omitted it defaults to the CONFIGURED
21
+ * ORCHESTRATOR (its own `.well-known`), which now owns provenance signing the
22
+ * natural root of trust for a self-hosted customer. When no orchestrator is
23
+ * configured it falls back to the hosted KiCI Platform's provenance issuer (for
24
+ * historical Platform-signed bundles, which keep verifying forever). Pass
25
+ * `--trust-root` to verify against a different environment or an offline
26
+ * `{ issuer, jwks }` file (air-gap). The token `iss` is always pinned to the
27
+ * trust root out-of-band — a bundle can never name its own trusted issuer.
23
28
  *
24
29
  * Returns a boolean (verified) so `cli.ts` can map it to an exit code (0/1).
25
30
  */
@@ -29,9 +34,14 @@ async function verifyAttestationCommand(artifact, options = {}) {
29
34
  logger.error(pc.red("Error: --bundle <path|url> is required"));
30
35
  return false;
31
36
  }
32
- const trustRoot = options.trustRoot ?? "https://api.kici.dev";
37
+ const configuredOrchestrator = (await loadGlobalConfig().catch(() => null))?.endpoint;
38
+ const trustRoot = options.trustRoot ?? configuredOrchestrator ?? "https://api.kici.dev";
33
39
  const usingDefault = !options.trustRoot;
34
- if (usingDefault) logger.info(pc.gray(`Using default trust root ${trustRoot} (pass --trust-root to override)`));
40
+ const usingConfiguredOrchestrator = usingDefault && !!configuredOrchestrator;
41
+ if (usingDefault) {
42
+ const which = usingConfiguredOrchestrator ? "configured orchestrator" : "hosted KiCI platform";
43
+ logger.info(pc.gray(`Using default trust root ${trustRoot} (${which}; pass --trust-root to override)`));
44
+ }
35
45
  const bundle = JSON.parse(await readBundle(options.bundle));
36
46
  let resolved;
37
47
  try {
@@ -39,7 +49,8 @@ async function verifyAttestationCommand(artifact, options = {}) {
39
49
  } catch (error) {
40
50
  const msg = toErrorMessage(error);
41
51
  if (usingDefault && /\b503\b/.test(msg)) {
42
- logger.error(pc.red(`Error: build provenance is not enabled on the hosted KiCI platform yet (${trustRoot} returned 503). Pass --trust-root to verify against another environment (e.g. staging) or an offline { issuer, jwks } file.`));
52
+ const where = usingConfiguredOrchestrator ? `your configured orchestrator (${trustRoot})` : `the hosted KiCI platform (${trustRoot})`;
53
+ logger.error(pc.red(`Error: build provenance signing is not enabled on ${where} yet (returned 503). Pass --trust-root to verify against another environment or an offline { issuer, jwks } file.`));
43
54
  return false;
44
55
  }
45
56
  throw error;
@@ -1,5 +1,16 @@
1
- /** Error code string (e.g., 'E001', 'E102'). */
1
+ /**
2
+ * Error code string. Thrown compile errors use `E<digits>` (e.g. 'E001', 'E102');
3
+ * advisory, render-only diagnostics use `W<digits>` (e.g. 'W101'). `isCompilerError`
4
+ * only matches the `E<digits>` family — warning codes are never thrown, only rendered.
5
+ */
2
6
  type ErrorCode = string;
7
+ /** Diagnostic severity. Errors abort compilation; warnings are advisory (compile still succeeds). */
8
+ export declare enum DiagnosticSeverity {
9
+ Error = "error",
10
+ Warning = "warning"
11
+ }
12
+ /** Warning code for the impure dynamic-value → init-job fallback. */
13
+ export declare const PURITY_FALLBACK_CODE = "W101";
3
14
  /** Source location for error reporting */
4
15
  export interface SourceLocation {
5
16
  readonly file: string;
@@ -12,6 +23,7 @@ export interface CompilerError {
12
23
  readonly message: string;
13
24
  readonly location?: SourceLocation;
14
25
  readonly suggestion?: string;
26
+ readonly severity?: DiagnosticSeverity;
15
27
  }
16
28
  /**
17
29
  * Format error in GNU standard format: file:line:column: error [CODE]: message
@@ -25,6 +37,7 @@ export declare function formatError(error: CompilerError): string;
25
37
  export declare function compilerError(code: ErrorCode, message: string, options?: {
26
38
  location?: SourceLocation;
27
39
  suggestion?: string;
40
+ severity?: DiagnosticSeverity;
28
41
  }): CompilerError;
29
42
  /** Check if an error is a CompilerError (codes are E + digits, e.g. E001, E102) */
30
43
  export declare function isCompilerError(error: unknown): error is CompilerError;
@@ -1,6 +1,14 @@
1
1
  import "../rolldown-runtime-ClRpJifh.js";
2
2
  import pc from "picocolors";
3
3
  //#region src/errors/formatter.ts
4
+ /** Diagnostic severity. Errors abort compilation; warnings are advisory (compile still succeeds). */
5
+ let DiagnosticSeverity = /* @__PURE__ */ function(DiagnosticSeverity) {
6
+ DiagnosticSeverity["Error"] = "error";
7
+ DiagnosticSeverity["Warning"] = "warning";
8
+ return DiagnosticSeverity;
9
+ }({});
10
+ /** Warning code for the impure dynamic-value → init-job fallback. */
11
+ const PURITY_FALLBACK_CODE = "W101";
4
12
  /**
5
13
  * Format error in GNU standard format: file:line:column: error [CODE]: message
6
14
  *
@@ -11,7 +19,8 @@ import pc from "picocolors";
11
19
  function formatError(error) {
12
20
  const parts = [];
13
21
  if (error.location) parts.push(pc.cyan(`${error.location.file}:${error.location.line}:${error.location.column}`));
14
- parts.push(pc.red("error") + pc.gray(` [${error.code}]`) + ": " + error.message);
22
+ const label = error.severity === "warning" ? pc.yellow("warning") : pc.red("error");
23
+ parts.push(label + pc.gray(` [${error.code}]`) + ": " + error.message);
15
24
  let output = parts.join(" ");
16
25
  if (error.suggestion) output += "\n " + pc.dim(`Suggestion: ${error.suggestion}`);
17
26
  return output;
@@ -22,7 +31,8 @@ function compilerError(code, message, options) {
22
31
  code,
23
32
  message,
24
33
  location: options?.location,
25
- suggestion: options?.suggestion
34
+ suggestion: options?.suggestion,
35
+ severity: options?.severity
26
36
  };
27
37
  }
28
38
  /** Check if an error is a CompilerError (codes are E + digits, e.g. E001, E102) */
@@ -30,6 +40,6 @@ function isCompilerError(error) {
30
40
  return typeof error === "object" && error !== null && "code" in error && "message" in error && typeof error.code === "string" && /^E\d+$/.test(error.code);
31
41
  }
32
42
  //#endregion
33
- export { compilerError, formatError, isCompilerError };
43
+ export { DiagnosticSeverity, PURITY_FALLBACK_CODE, compilerError, formatError, isCompilerError };
34
44
 
35
45
  //# sourceMappingURL=formatter.js.map
@@ -1,5 +1,6 @@
1
- export { formatError, compilerError, isCompilerError } from './formatter.js';
1
+ export { formatError, compilerError, isCompilerError, DiagnosticSeverity, PURITY_FALLBACK_CODE, } from './formatter.js';
2
2
  export type { SourceLocation, CompilerError } from './formatter.js';
3
3
  export { CapabilityGapError, formatCapabilityGapError } from './capability-gap.js';
4
4
  export type { CapabilityGapInfo } from './capability-gap.js';
5
+ export { firstStepLocation, locationForJob, locationForWorkflow } from './source-location.js';
5
6
  //# sourceMappingURL=index.d.ts.map
@@ -1,4 +1,5 @@
1
1
  import "../rolldown-runtime-ClRpJifh.js";
2
- import { compilerError, formatError, isCompilerError } from "./formatter.js";
2
+ import { DiagnosticSeverity, PURITY_FALLBACK_CODE, compilerError, formatError, isCompilerError } from "./formatter.js";
3
3
  import { CapabilityGapError, formatCapabilityGapError } from "./capability-gap.js";
4
- export { CapabilityGapError, compilerError, formatCapabilityGapError, formatError, isCompilerError };
4
+ import { firstStepLocation, locationForJob, locationForWorkflow } from "./source-location.js";
5
+ export { CapabilityGapError, DiagnosticSeverity, PURITY_FALLBACK_CODE, compilerError, firstStepLocation, formatCapabilityGapError, formatError, isCompilerError, locationForJob, locationForWorkflow };
@@ -0,0 +1,20 @@
1
+ import type { Job } from '@kici-dev/sdk';
2
+ import type { SourceLocation } from './formatter.js';
3
+ /**
4
+ * First step (walking one level into parallel groups) that carries a captured
5
+ * `_sourceLocation`. `step()` records a precise V8 call-site; bare functions and
6
+ * parallel-group wrappers do not, so this returns the first real anchor found.
7
+ */
8
+ export declare function firstStepLocation(job: Job): SourceLocation | undefined;
9
+ /**
10
+ * Best available location for a job-scoped error: its first step's captured
11
+ * location when a step exists, else the workflow source file at line 1
12
+ * (`job()` itself captures no call-site).
13
+ */
14
+ export declare function locationForJob(job: Job, workflowFile: string): SourceLocation;
15
+ /**
16
+ * Location for a workflow-scoped error: `workflow()` captures no call-site, so
17
+ * the best anchor is the workflow's source file at line 1.
18
+ */
19
+ export declare function locationForWorkflow(file: string): SourceLocation;
20
+ //# sourceMappingURL=source-location.d.ts.map
@@ -0,0 +1,45 @@
1
+ import "../rolldown-runtime-ClRpJifh.js";
2
+ //#region src/errors/source-location.ts
3
+ /**
4
+ * First step (walking one level into parallel groups) that carries a captured
5
+ * `_sourceLocation`. `step()` records a precise V8 call-site; bare functions and
6
+ * parallel-group wrappers do not, so this returns the first real anchor found.
7
+ */
8
+ function firstStepLocation(job) {
9
+ for (const entry of job.steps ?? []) {
10
+ const stepLike = entry;
11
+ if (stepLike._sourceLocation) return stepLike._sourceLocation;
12
+ const group = entry;
13
+ if (Array.isArray(group.steps)) {
14
+ const inner = group.steps.find((c) => c._sourceLocation)?._sourceLocation;
15
+ if (inner) return inner;
16
+ }
17
+ }
18
+ }
19
+ /**
20
+ * Best available location for a job-scoped error: its first step's captured
21
+ * location when a step exists, else the workflow source file at line 1
22
+ * (`job()` itself captures no call-site).
23
+ */
24
+ function locationForJob(job, workflowFile) {
25
+ return firstStepLocation(job) ?? {
26
+ file: workflowFile,
27
+ line: 1,
28
+ column: 1
29
+ };
30
+ }
31
+ /**
32
+ * Location for a workflow-scoped error: `workflow()` captures no call-site, so
33
+ * the best anchor is the workflow's source file at line 1.
34
+ */
35
+ function locationForWorkflow(file) {
36
+ return {
37
+ file,
38
+ line: 1,
39
+ column: 1
40
+ };
41
+ }
42
+ //#endregion
43
+ export { firstStepLocation, locationForJob, locationForWorkflow };
44
+
45
+ //# sourceMappingURL=source-location.js.map
@@ -8,6 +8,30 @@ import { existsSync } from "node:fs";
8
8
  import fs$1 from "node:fs/promises";
9
9
  //#region src/execution/executor.ts
10
10
  /**
11
+ * Map a caught runtime error's stack to a `SourceLocation` in the entry file.
12
+ * Scans for the first stack frame referencing `entryPoint` (ignoring the
13
+ * `?t=` cache-buster and the `file://` scheme) and returns its line/column;
14
+ * falls back to `entryPoint` at line 1 when no frame matches.
15
+ */
16
+ function locateInEntry(stack, entryPoint) {
17
+ const fallback = {
18
+ file: entryPoint,
19
+ line: 1,
20
+ column: 1
21
+ };
22
+ if (!stack) return fallback;
23
+ const needle = entryPoint.split("?")[0];
24
+ for (const raw of stack.split("\n")) {
25
+ const m = raw.match(/(.+?):(\d+):(\d+)\)?$/);
26
+ if (m && m[1].includes(needle)) return {
27
+ file: entryPoint,
28
+ line: parseInt(m[2], 10),
29
+ column: parseInt(m[3], 10)
30
+ };
31
+ }
32
+ return fallback;
33
+ }
34
+ /**
11
35
  * Load a TypeScript workflow/config module by direct dynamic import.
12
36
  *
13
37
  * Relies on the `@kici-dev/core/ts-loader-hook` ESM loader hook, registered
@@ -34,11 +58,7 @@ async function loadModule(entryPoint, errorContext) {
34
58
  } catch (err) {
35
59
  const message = err.message ?? "Failed to load module";
36
60
  throw compilerError("E003", `Failed to load ${errorContext.fileLabel} module: ${message}`, {
37
- location: {
38
- file: errorContext.filePath,
39
- line: 1,
40
- column: 1
41
- },
61
+ location: locateInEntry(err.stack, errorContext.filePath),
42
62
  suggestion: `Check for TypeScript or runtime errors in your ${errorContext.fileLabel}. Make sure you invoke the workflow via the kici CLI (the bin shim registers the oxc-transform loader hook that handles TS files).`
43
63
  });
44
64
  }
@@ -86,7 +86,8 @@ const FIXTURES = {
86
86
  * @throws Error if event is unknown
87
87
  */
88
88
  function getDefaultFixture(event) {
89
- const fixture = FIXTURES[event.toLowerCase().trim()];
89
+ const normalized = event.toLowerCase().trim();
90
+ const fixture = FIXTURES[normalized];
90
91
  if (!fixture) {
91
92
  const available = Object.keys(FIXTURES).filter((k, i, arr) => arr.indexOf(k) === i).join(", ");
92
93
  throw new Error(`Unknown event type: ${event}\nAvailable events: ${available}`);
@@ -19,7 +19,7 @@ Per-orchestrator settings loaded from a YAML file. These are instance-specific a
19
19
  ```typescript
20
20
  interface LocalConfig {
21
21
  database: { url: string };
22
- instance?: { id?: string; mode?: 'platform' | 'hybrid' | 'independent' };
22
+ instance?: { id?: string; mode?: 'platform' | 'hybrid' | 'independent' | 'observed' };
23
23
  server?: { port?: number; basePath?: string; logLevel?: string };
24
24
  scaler?: { configPath?: string; configDir?: string };
25
25
  }
@@ -56,7 +56,7 @@ The merged result type used throughout the codebase. Combines `LocalConfig` + `S
56
56
  ```typescript
57
57
  interface AppConfig {
58
58
  instanceId: string; // From local config or auto-generated
59
- mode: 'platform' | 'hybrid' | 'independent';
59
+ mode: 'platform' | 'hybrid' | 'independent' | 'observed';
60
60
  databaseUrl: string; // Flattened from database.url
61
61
  port: number; // Flattened from server.port
62
62
  basePath: string;
@@ -376,7 +376,7 @@ Source: https://docs.kici.dev/architecture/data-flows/
376
376
 
377
377
  This document describes the key data flows through the KiCI architecture: webhook delivery, job execution, developer-initiated remote runs, dependency caching, re-run and cancel, trace ID propagation, internal event routing, and generic webhook ingestion.
378
378
 
379
- > **Lock file schema version:** The lock file uses schema version 29. The orchestrator rejects any fetched lock whose `schemaVersion` does not exactly match the engine version it was built against, so a stale lock must be recompiled with `kici compile` and pushed again after any SDK upgrade that bumps the schema.
379
+ > **Lock file schema version:** The orchestrator accepts a compatibility window of lock schema versions rather than an exact match. A lock is accepted when its `schemaVersion` is at or above the orchestrator's oldest supported version (additive bumps add fields older readers ignore) and the orchestrator's own schema is at or above the lock's `minReaderVersion` (the newest breaking version at compile time). A lock below the floor must be recompiled with `kici compile` and pushed; a lock requiring a newer reader means the orchestrator must be upgraded. Both out-of-window cases are rejected with an actionable error rather than a silent mis-route. See [lock file and drift](https://docs.kici.dev/user/lock-file-and-drift/#schema-compatibility-window).
380
380
 
381
381
  ## Webhook delivery flow
382
382
 
@@ -582,7 +582,7 @@ Dep cache misses alone do **not** trigger a build job. Deps are platform-specifi
582
582
 
583
583
  ### Cross-source / no-contentHash workflows
584
584
 
585
- - **Lock files without `contentHash`** (schema v1) skip the source cache entirely; agents compile from source. Regenerate lock files with `kici compile` to enable caching. The current lock file schema version is 29.
585
+ - **Lock files without `contentHash`** (schema v1) skip the source cache entirely; agents compile from source. Regenerate lock files with `kici compile` to enable caching. The current lock file schema version is 31.
586
586
  - **Cross-source / global-workflow dispatch** (a workflow registered against source A fired by a webhook on source B) bypasses both caches. The registration's lock file entry still carries `contentHash`, but the cross-source path always clone-and-installs — the eval temp dir doesn't ship `@kici-dev/sdk`. The execution agent still verifies `contentHash` against the cloned source for drift detection.
587
587
 
588
588
  ### Build deduplication
@@ -670,7 +670,7 @@ Agents receive pre-signed S3 GET URLs (15-minute expiry) directly in `job.dispat
670
670
 
671
671
  The source/dep cache above is internal: the orchestrator owns its keys and decides when to hit or build. The **user-facing cache** is driven by the workflow author — the declarative `cache: { key, paths, restoreKeys? }` on a job/step, or the imperative `ctx.cache.restore()` / `ctx.cache.save()` API (see [SDK caching reference](https://docs.kici.dev/user/sdk/caching/)). It reuses the same object-storage backend and the same direct-to-storage presigned-URL transport, but the agent — not the orchestrator — initiates each restore and save over WebSocket.
672
672
 
673
- The agent's cache module archives `paths` into a gzipped tarball (computing a SHA-256 over the bytes) and streams downloads back through a checksum-verified extract pipeline. The orchestrator's `UserCache` owns the `cache/<orgId>/<repoId>/<scope>/<key>` namespacing, the immutable first-save check, the `restoreKeys` prefix scan, the two-phase atomic save, and per-org quota/TTL eviction.
673
+ The agent's cache module archives `paths` into a gzipped tarball (computing a SHA-256 over the bytes) and streams downloads back through a checksum-verified extract pipeline. The orchestrator's `UserCache` owns the `cache/<orgId>/<repoId>/<scope>/<key>-<discriminator>` namespacing (the discriminator is a hash of the exact cache key, so two keys differing only by case stay two objects on a case-insensitive store), the immutable first-save check, the `restoreKeys` prefix scan, the two-phase atomic save, and per-org quota/TTL eviction.
674
674
 
675
675
  ### Restore flow
676
676
 
@@ -951,7 +951,7 @@ POST /webhook/:orgId/generic/:sourceId
951
951
 
952
952
  ## Database topology
953
953
 
954
- The orchestrator owns its own PostgreSQL database, with the authoritative `execution_runs`, `execution_jobs`, `execution_steps`, `dispatch_queue`, `dedup_cache`, `workflow_registrations`, `environments` / `scoped_secrets` / `environment_bindings`, `agent_tokens`, `cluster_meta`, and related tables. Each orchestrator deployment uses its own `KICI_DATABASE_URL`; database users are scoped per service.
954
+ The orchestrator owns its own PostgreSQL database, with the authoritative `execution_runs`, `execution_jobs`, `execution_steps`, `dispatch_queue`, `dedup_cache`, `workflow_registrations`, `contexts` / `scoped_secrets` / `context_bindings`, `agent_tokens`, `cluster_meta`, and related tables. Each orchestrator deployment uses its own `KICI_DATABASE_URL`; database users are scoped per service.
955
955
 
956
956
  ## Execution reporting flow
957
957
 
@@ -1135,7 +1135,7 @@ Output chaining allows steps to consume outputs from preceding steps (within a j
1135
1135
  When workflow code runs at definition time (`step()`, `job()` calls):
1136
1136
 
1137
1137
  - `step()` creates an `OutputProxy<T>` via `createStepOutputProxy(stepName)` and attaches it as `.result`
1138
- - `job()` creates an `OutputProxy<any>` via `createJobOutputProxy(jobName)` and attaches it as `.result`
1138
+ - `job()` creates an `OutputProxy<TOutputs>` (the job's inferred output shape — nested by step name for a multi-step job, flat for the `run:` shorthand) via `createJobOutputProxy(jobName)` and attaches it as `.result`, so cross-job reads type-check
1139
1139
  - The proxy is an ES6 `Proxy` object that defers all property access to a module-global `OutputsMap`
1140
1140
  - No outputs exist yet -- accessing `.result.field` before execution throws "has not produced outputs yet"
1141
1141
 
@@ -1219,7 +1219,7 @@ The Platform tier exposes a `/ws/browser` WebSocket endpoint for dashboard clien
1219
1219
  - [Architecture overview](https://docs.kici.dev/architecture/overview/) -- three-tier model and component responsibilities
1220
1220
  - [Protocol messages](https://docs.kici.dev/architecture/protocol-messages/) -- WebSocket message schemas
1221
1221
  - [Event system internals](https://docs.kici.dev/architecture/webhooks/event-system/) -- event router, registration model, cron scheduler
1222
- - [State machine](https://docs.kici.dev/architecture/execution/state-machine/) -- job execution state transitions
1222
+ - [Execution lifecycle](https://docs.kici.dev/architecture/execution/state-machine/) -- run, job, and step status vocabularies and terminal states
1223
1223
  - [Webhook delivery](https://docs.kici.dev/architecture/webhooks/webhook-delivery/) -- detailed webhook processing pipeline
1224
1224
  - [Operator: dependency caching](https://docs.kici.dev/operator/dependency-caching/) -- configuration guide
1225
1225
  - [Operator: monitoring & tracing](https://docs.kici.dev/operator/observability/monitoring/) -- trace fields and Loki queries
@@ -1248,6 +1248,7 @@ flowchart LR
1248
1248
  AGENT_B["Agent\n(arm64)"]
1249
1249
 
1250
1250
  GH -- "HTTP\n(webhooks)" --> PLATFORM
1251
+ GH -. "HTTP direct webhook\n(hybrid / observed / independent)" .-> ORCH_A
1251
1252
  PLATFORM <-- "WebSocket\n(relay + telemetry)" --> ORCH_A
1252
1253
  PLATFORM <-- "WebSocket\n(relay + telemetry)" --> ORCH_B
1253
1254
  ORCH_A <-- "WebSocket P2P\n(reroute + progress\n+ Raft)" --> ORCH_B
@@ -1260,7 +1261,19 @@ flowchart LR
1260
1261
 
1261
1262
  **Why three tiers?** Trust boundaries. The Platform relay never sees customer code -- it only verifies webhook signatures and forwards payloads. The orchestrator matches triggers against the lock file without cloning repositories. Only the agent, running on customer infrastructure, clones code and executes steps.
1262
1263
 
1263
- This model also supports an independent deployment without the hosted Platform: the orchestrator and agent run on customer infrastructure, with the orchestrator receiving webhooks directly from GitHub instead of through the Platform relay.
1264
+ This model also supports pointing webhooks **directly** at the orchestrator,
1265
+ bypassing the Platform relay. In **hybrid** mode the orchestrator keeps its
1266
+ Platform connection for the dashboard and telemetry while GitHub delivers events
1267
+ straight to the orchestrator's ingress — so a Platform outage never drops a build
1268
+ trigger. **Observed** mode drops the relay leg entirely: webhooks reach only the
1269
+ orchestrator's own ingress (no payload ever transits KiCI) while the Platform
1270
+ connection stays up for the hosted dashboard, and the orchestrator's sources
1271
+ register as observe-only — recorded and dashboard-visible, but excluded from
1272
+ every relay-candidate lookup. In a fully **independent** deployment the
1273
+ orchestrator and agent run on customer infrastructure with no Platform at all,
1274
+ receiving webhooks directly. For
1275
+ exactly which capabilities the hosted Platform provides in each case, see
1276
+ [What requires the hosted Platform](https://docs.kici.dev/operator/orchestrator/platform-capabilities/).
1264
1277
 
1265
1278
  ## Component responsibilities
1266
1279
 
@@ -1275,7 +1288,7 @@ The Platform never processes, stores, or executes customer code, and never sees
1275
1288
  The orchestrator is the execution brain. It decides what to run and dispatches work to agents.
1276
1289
 
1277
1290
  - **Trigger matching** -- Evaluates lock file triggers against webhook payloads to determine which jobs to run. Uses branch, path, and event matching via picomatch.
1278
- - **Lock file caching** -- Fetches `kici.lock.json` from the configured provider's API (GitHub, generic webhook, universal-git, or internal). An LRU cache wraps the per-provider fetcher, keyed by `{provider}:{repo}:{ref}` so cross-provider fallback resolutions stay isolated.
1291
+ - **Lock file caching** -- Fetches `kici.lock.json` via the configured source's fetcher (GitHub API, universal-git clone for generic webhook sources backed by a git URL, or the local filesystem for `file://` sources). An LRU cache wraps the per-provider fetcher, keyed by `{provider}:{repo}:{ref}` so cross-provider fallback resolutions stay isolated.
1279
1292
  - **Agent registry** -- Tracks connected agents with label-based routing for job dispatch.
1280
1293
  - **Job queue** -- PostgreSQL-backed FIFO queue for reliable dispatch.
1281
1294
  - **Webhook pipeline** -- Dedup, event mapping, lock file fetch, trigger matching, and job dispatch in a single pipeline.
@@ -1290,12 +1303,13 @@ The orchestrator is the execution brain. It decides what to run and dispatches w
1290
1303
  The agent is the execution worker. It runs on customer infrastructure and has full access to customer code.
1291
1304
 
1292
1305
  - **Repository cloning** -- Clones the target repo with token-based auth (token in HTTP headers, not URLs, to prevent leakage).
1293
- - **Step execution** -- Runs steps sequentially with full `StepContext` (zx shell, logger, environment, workflow/job metadata).
1294
- - **Docker support** -- Container-based step execution via `docker exec` for isolated environments.
1306
+ - **Step execution** -- Runs steps in declaration order with full `StepContext` (zx shell, logger, environment, workflow/job metadata). Steps wrapped in a `parallel()` group run concurrently behind a `maxParallel` window, and each child reports as its own observable step with its own logs, status, timing, and retry.
1307
+ - **Execution sandboxes** -- Runs the workflow runner as a separate child process with a sanitized environment, in one of three sandboxes: bare metal (process fork, with optional bubblewrap namespace isolation), a container runtime (the whole job lifecycle runs inside a disposable container), or inside a Firecracker microVM. Agent-internal credentials never reach customer workflow code.
1295
1308
  - **Log streaming** -- Chunked log streaming back to the orchestrator with configurable size limits.
1309
+ - **Dependency caching** -- Packs, uploads, and restores installed workflow dependencies so repeat runs skip the install step.
1296
1310
  - **Graceful shutdown** -- SIGTERM with 10s grace period, SIGUSR1 for drain mode.
1297
1311
 
1298
- > Source: `packages/agent/src/execution/job-runner.ts` (job lifecycle), `packages/agent/src/server.ts` (entry point)
1312
+ > Source: `packages/agent/src/execution/job-runner.ts` (job lifecycle), `packages/agent/src/execution/sandbox/` (execution sandboxes and the parallel step scheduler), `packages/agent/src/server.ts` (entry point)
1299
1313
 
1300
1314
  ## Supporting packages
1301
1315
 
@@ -1306,14 +1320,22 @@ Shared business logic used by all three tiers. Single source of truth for cross-
1306
1320
  - Protocol message schemas (Zod-based, direction-specific unions including dashboard REST-over-WS, browser live streaming, the test-relay control plane, log pull, run events, peer-to-peer, cluster join, and source registration)
1307
1321
  - Provider interfaces (WebhookNormalizer, LockFileFetcher, ChangedFilesFetcher, CloneTokenProvider, RepoUrlBuilder, ContributorResolver, CheckStatusPoster)
1308
1322
  - Trigger matching engine (branch, path, event evaluation)
1309
- - Execution state machine (11 states, 16 events, pure functions)
1323
+ - Dispatch inputs (input descriptors, extraction from the trigger event, and coercion to typed values)
1324
+ - Matrix expansion and fanout (combination expansion with include/exclude, job-name suffix formatting, and materialization of one matrix or multi-host job into N dispatchable children)
1325
+ - Execution status vocabulary (run/job/step status enums + terminal-state sets; lifecycle owned by the orchestrator's execution tracker)
1326
+ - Check mode (the idempotent run modes `apply` / `check` / `check-fail-on-drift` and the per-step outcome vocabulary)
1310
1327
  - Webhook signature verification (HMAC-SHA256, timing-safe)
1311
1328
  - WebSocket close codes (unified across all tiers)
1312
1329
  - WebSocket rate limiting (WsRateLimiter)
1313
1330
  - Environment allowlist (safe env var filtering)
1314
1331
  - Secrets management (secret context resolution)
1315
- - Environment model (scoped secrets, env merge, protection gates)
1332
+ - Context model (scoped secrets, ordered context merge, protection gates)
1333
+ - Approval requirements (normalized approver clauses shared by the orchestrator gate, the resolver, the held-run store, and the agent step round-trip)
1334
+ - Build provenance (in-toto statement schema, DSSE envelope, attestation bundle, verification)
1335
+ - Artifact name contract (the shared filesystem/URL-safe name schema the orchestrator, agent, and SDK all validate against)
1336
+ - Developer MCP tool schemas (argument schemas for the AI-agent tool surface)
1316
1337
  - Label utilities (platform label derivation, runsOn normalization, `kici:*` set-only reserved namespace, role labels)
1338
+ - Host inventory (the canonical queryable host-roster schema shared by the orchestrator's roster store, the agent-facing inventory API, and the SDK's `ctx.kici.inventory`)
1317
1339
  - Audit policy and retention (per-action access-log sampling, warm-retention windows for cold-store eligibility, federated activity row schema)
1318
1340
  - Scaler backend type enum (`container`, `bare-metal`, `firecracker`, `kubernetes`)
1319
1341
  - Registration trigger type enum (registerable trigger discriminator)
@@ -1331,7 +1353,9 @@ User-facing SDK for defining workflows in TypeScript. Provides factory functions
1331
1353
 
1332
1354
  CLI tooling for workflow authors. Compiles `.kici/workflows/*.ts` to `.kici/kici.lock.json`, provides watch mode, local test execution, project initialization, and pre-commit hook integration.
1333
1355
 
1334
- > Source: `packages/compiler/src/`
1356
+ It also runs the **local dev plane** -- an on-demand, fully local execution stack (embedded PostgreSQL, an orchestrator process, and a bare-metal-scaled agent) that lets an author run a workflow end-to-end on their own machine. That is why the compiler depends on `@kici-dev/orchestrator` and `@kici-dev/agent`: it resolves and spawns their built entry points rather than reimplementing them. See [Local dev plane](https://docs.kici.dev/operator/orchestrator/local-dev-plane/).
1357
+
1358
+ > Source: `packages/compiler/src/` (`local-plane/` for the local dev plane)
1335
1359
 
1336
1360
  ### `@kici-dev/core`
1337
1361
 
@@ -1357,7 +1381,7 @@ Unscoped wrapper package that provides the `kici` CLI command. Re-exports `@kici
1357
1381
 
1358
1382
  ### `kici-admin` (admin CLI wrapper)
1359
1383
 
1360
- Unscoped wrapper package that provides the `kici-admin` CLI command. Re-exports `@kici-dev/orchestrator/cli` for orchestrator administration tasks.
1384
+ Unscoped wrapper package that ships two binaries: `kici-admin`, which re-exports `@kici-dev/orchestrator/cli` for orchestrator administration tasks, and `kici-agent`, which re-exports `@kici-dev/agent/server` to run an agent. It therefore depends on both `@kici-dev/orchestrator` and `@kici-dev/agent` (the `KICIADMIN → AGENT` edge in the graph below).
1361
1385
 
1362
1386
  > Source: `packages/kici-admin/`
1363
1387
 
@@ -1380,10 +1404,13 @@ flowchart TD
1380
1404
  DASH --> ENGINE
1381
1405
  DASH -.->|dev| PLATFORM
1382
1406
  SHARED --> CORE
1407
+ SHARED --> ENGINE
1383
1408
  SDK --> ENGINE
1384
1409
  SDK --> CORE
1385
1410
  COMPILER --> ENGINE
1386
1411
  COMPILER --> CORE
1412
+ COMPILER --> ORCH
1413
+ COMPILER --> AGENT
1387
1414
  COMPILER -.->|peer| SDK
1388
1415
  PLATFORM --> ENGINE
1389
1416
  PLATFORM --> SHARED
@@ -1402,10 +1429,12 @@ flowchart TD
1402
1429
  KICIADMIN --> AGENT
1403
1430
  ```
1404
1431
 
1405
- **Leaf packages** (no `@kici` dependencies): `@kici-dev/core` and `@kici-dev/engine`. These can be tested and built independently. `@kici-dev/shared` builds on `@kici-dev/core` and re-exports it. The dashboard depends on `@kici-dev/engine` for shared types (protocol schemas, state machine) and imports the Platform's API type definitions as a dev dependency, but communicates with backend services at runtime via HTTP/WebSocket, not at compile time.
1432
+ **Leaf packages** (no `@kici` dependencies): `@kici-dev/core` and `@kici-dev/engine`. These can be tested and built independently. `@kici-dev/shared` builds on `@kici-dev/core` (which it re-exports) and on `@kici-dev/engine` for shared vocabularies. The dashboard depends on `@kici-dev/engine` for shared types (protocol schemas, execution status enums) and imports the Platform's API type definitions as a dev dependency, but communicates with backend services at runtime via HTTP/WebSocket, not at compile time.
1406
1433
 
1407
1434
  **Runtime tiers** (Platform, orchestrator, agent) all depend on `@kici-dev/engine` for shared business logic and `@kici-dev/shared` for utilities. Only the agent depends on `@kici-dev/sdk` (it loads workflow definitions at runtime).
1408
1435
 
1436
+ The `COMPILER → ORCH` and `COMPILER → AGENT` edges exist solely for the local dev plane: the compiler spawns a local orchestrator and agent so an author can execute a workflow end-to-end without any deployed infrastructure. Nothing in the compile path itself reaches into either tier.
1437
+
1409
1438
  ## Connection overview
1410
1439
 
1411
1440
  KiCI uses three WebSocket layers for real-time communication.
@@ -1433,7 +1462,7 @@ KiCI uses application-level tenant isolation. The Platform dashboard API accepts
1433
1462
  ## See also
1434
1463
 
1435
1464
  - [Multi-Orchestrator Architecture](https://docs.kici.dev/architecture/clustering/multi-orchestrator/) -- P2P clustering, Raft consensus, job rerouting
1436
- - [State Machine](https://docs.kici.dev/architecture/execution/state-machine/) -- execution lifecycle tracking across all tiers
1465
+ - [Execution lifecycle](https://docs.kici.dev/architecture/execution/state-machine/) -- run, job, and step status vocabularies and the tracker that owns lifecycle state
1437
1466
  - [Protocol Messages](https://docs.kici.dev/architecture/protocol-messages/) -- WebSocket message schemas for all three layers
1438
1467
  - [Webhook Delivery](https://docs.kici.dev/architecture/webhooks/webhook-delivery/) -- end-to-end trace of a webhook through all three tiers
1439
1468