@kici-dev/compiler 0.1.25 → 0.1.27

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 (96) hide show
  1. package/dist/cli-banner.d.ts +6 -3
  2. package/dist/cli-banner.js +13 -5
  3. package/dist/cli.js +66 -43
  4. package/dist/commands/check-mode.d.ts +1 -1
  5. package/dist/commands/compile.js +3 -3
  6. package/dist/commands/index.d.ts +5 -1
  7. package/dist/commands/index.js +6 -3
  8. package/dist/commands/init.js +1 -1
  9. package/dist/commands/local-trust-root.d.ts +6 -0
  10. package/dist/commands/local-trust-root.js +52 -0
  11. package/dist/commands/local.d.ts +39 -0
  12. package/dist/commands/local.js +137 -0
  13. package/dist/commands/login.d.ts +2 -0
  14. package/dist/commands/login.js +40 -0
  15. package/dist/commands/logout.js +7 -0
  16. package/dist/commands/preview.js +1 -1
  17. package/dist/commands/run-banner.d.ts +31 -0
  18. package/dist/commands/run-banner.js +25 -0
  19. package/dist/commands/run-routed.d.ts +53 -0
  20. package/dist/commands/run-routed.js +176 -0
  21. package/dist/commands/run.d.ts +0 -17
  22. package/dist/commands/run.js +7 -50
  23. package/dist/commands/secrets-list.d.ts +2 -2
  24. package/dist/commands/secrets-list.js +4 -4
  25. package/dist/commands/types.d.ts +3 -3
  26. package/dist/commands/types.js +4 -4
  27. package/dist/execution/executor.js +7 -7
  28. package/dist/generators/secrets-dts.d.ts +9 -9
  29. package/dist/generators/secrets-dts.js +12 -12
  30. package/dist/llm-context/llms-architecture.txt +2 -2
  31. package/dist/llm-context/llms-cli.txt +674 -340
  32. package/dist/llm-context/llms-features.txt +334 -336
  33. package/dist/llm-context/llms-full.txt +1207 -892
  34. package/dist/llm-context/llms-getting-started.txt +7 -15
  35. package/dist/llm-context/llms-patterns.txt +5 -23
  36. package/dist/llm-context/llms-providers.txt +10 -1
  37. package/dist/llm-context/llms-sdk.txt +12 -12
  38. package/dist/llm-context/llms.txt +5 -5
  39. package/dist/local-executor/secret-loader.d.ts +1 -1
  40. package/dist/local-plane/orchestrator-process.d.ts +65 -0
  41. package/dist/local-plane/orchestrator-process.js +115 -0
  42. package/dist/local-plane/paths.d.ts +39 -0
  43. package/dist/local-plane/paths.js +54 -0
  44. package/dist/local-plane/plane-manager.d.ts +151 -0
  45. package/dist/local-plane/plane-manager.js +340 -0
  46. package/dist/local-plane/plane-seed.d.ts +76 -0
  47. package/dist/local-plane/plane-seed.js +59 -0
  48. package/dist/local-plane/plane-trigger.d.ts +62 -0
  49. package/dist/local-plane/plane-trigger.js +97 -0
  50. package/dist/local-plane/platform-attach.d.ts +53 -0
  51. package/dist/local-plane/platform-attach.js +111 -0
  52. package/dist/local-plane/postgres.d.ts +44 -0
  53. package/dist/local-plane/postgres.js +165 -0
  54. package/dist/local-plane/resolve-plane.d.ts +37 -0
  55. package/dist/local-plane/resolve-plane.js +76 -0
  56. package/dist/local-plane/run-follow.d.ts +41 -0
  57. package/dist/local-plane/run-follow.js +104 -0
  58. package/dist/local-plane/scaler-config.d.ts +54 -0
  59. package/dist/local-plane/scaler-config.js +114 -0
  60. package/dist/local-plane/secret-seed.d.ts +59 -0
  61. package/dist/local-plane/secret-seed.js +112 -0
  62. package/dist/local-plane/source-provider.d.ts +43 -0
  63. package/dist/local-plane/source-provider.js +165 -0
  64. package/dist/local-plane/trusted-routing.d.ts +32 -0
  65. package/dist/local-plane/trusted-routing.js +47 -0
  66. package/dist/lockfile/generator.js +7 -7
  67. package/dist/remote/dashboard-client.d.ts +7 -7
  68. package/dist/remote/dashboard-client.js +7 -7
  69. package/dist/remote/platform-client.d.ts +1 -1
  70. package/dist/remote/secret-loader.d.ts +18 -0
  71. package/dist/{local-executor → remote}/secret-loader.js +4 -4
  72. package/dist/remote/secret-upload.d.ts +1 -1
  73. package/dist/remote/secret-upload.js +2 -2
  74. package/dist/remote/uploader.d.ts +1 -1
  75. package/dist/remote/uploader.js +2 -2
  76. package/dist/templates/agents-md.d.ts +1 -1
  77. package/dist/templates/agents-md.js +2 -2
  78. package/dist/templates/package-json.js +1 -1
  79. package/dist/test-runner/job-executor.js +1 -1
  80. package/dist/test-runner/runs-on-display.d.ts +9 -0
  81. package/dist/{local-executor → test-runner}/runs-on-display.js +1 -1
  82. package/dist/test-runner/step-context.d.ts +1 -1
  83. package/dist/test-runner/step-context.js +2 -2
  84. package/dist/types.d.ts +6 -6
  85. package/package.json +7 -4
  86. package/sbom.spdx.json +9884 -1459
  87. package/dist/local-executor/dag-scheduler.js +0 -183
  88. package/dist/local-executor/index.js +0 -378
  89. package/dist/local-executor/job-runner.js +0 -411
  90. package/dist/local-executor/materializer.js +0 -132
  91. package/dist/local-executor/output-streamer.js +0 -168
  92. package/dist/local-executor/payload-generator.js +0 -138
  93. package/dist/local-executor/picker.js +0 -109
  94. package/dist/local-executor/to-event-payload.js +0 -21
  95. package/dist/local-executor/types.js +0 -2
  96. package/dist/local-executor/workflow-lock.js +0 -0
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Route a `kici run --local --trusted` run onto the plane's trusted label set
3
+ * by appending a routing label to every job's `runsOn` in the workdir lock the
4
+ * plane orchestrator reads.
5
+ *
6
+ * The orchestrator resolves each job's target agent from the lock's `runsOn`
7
+ * selectors (subset match + smallest-set-wins in the scaler label matcher).
8
+ * A default run leaves `runsOn` untouched, so a `runsOn: ['default']` job lands
9
+ * on the sandboxed `['default']` label set — byte-identical to a non-trusted
10
+ * run. `--trusted` appends the non-reserved `self-hosted` label, which only the
11
+ * trusted `['default','self-hosted']` label set carries, forcing every job onto
12
+ * the trusted profile.
13
+ *
14
+ * This is routing-by-label to a PRE-CONFIGURED trusted scaler label set — the
15
+ * `KICI_TRUSTED_ENV` value lives only in that label set's env (the plane's own
16
+ * config), never on a dispatch payload. The lock patch adds a label
17
+ * requirement, not the trusted flag itself.
18
+ */
19
+ /** Handle to restore the lock to its pre-patch bytes. */
20
+ export interface RunsOnLabelInjection {
21
+ /** Rewrite the original bytes captured before the patch. */
22
+ restore: () => void;
23
+ }
24
+ /**
25
+ * Append an exact-match `runsOn` selector for `label` to every job in the lock
26
+ * at `lockPath`, unless the job already requires it. Returns a `restore()` that
27
+ * rewrites the original file bytes (call it in a `finally` — for an in-place run
28
+ * it un-dirties the developer's tree; for an isolated run the throwaway clone is
29
+ * removed anyway).
30
+ */
31
+ export declare function injectRunsOnLabel(lockPath: string, label: string): RunsOnLabelInjection;
32
+ //# sourceMappingURL=trusted-routing.d.ts.map
@@ -0,0 +1,47 @@
1
+ import "../rolldown-runtime-ClRpJifh.js";
2
+ import fs from "node:fs";
3
+ //#region src/local-plane/trusted-routing.ts
4
+ /**
5
+ * Route a `kici run --local --trusted` run onto the plane's trusted label set
6
+ * by appending a routing label to every job's `runsOn` in the workdir lock the
7
+ * plane orchestrator reads.
8
+ *
9
+ * The orchestrator resolves each job's target agent from the lock's `runsOn`
10
+ * selectors (subset match + smallest-set-wins in the scaler label matcher).
11
+ * A default run leaves `runsOn` untouched, so a `runsOn: ['default']` job lands
12
+ * on the sandboxed `['default']` label set — byte-identical to a non-trusted
13
+ * run. `--trusted` appends the non-reserved `self-hosted` label, which only the
14
+ * trusted `['default','self-hosted']` label set carries, forcing every job onto
15
+ * the trusted profile.
16
+ *
17
+ * This is routing-by-label to a PRE-CONFIGURED trusted scaler label set — the
18
+ * `KICI_TRUSTED_ENV` value lives only in that label set's env (the plane's own
19
+ * config), never on a dispatch payload. The lock patch adds a label
20
+ * requirement, not the trusted flag itself.
21
+ */
22
+ /**
23
+ * Append an exact-match `runsOn` selector for `label` to every job in the lock
24
+ * at `lockPath`, unless the job already requires it. Returns a `restore()` that
25
+ * rewrites the original file bytes (call it in a `finally` — for an in-place run
26
+ * it un-dirties the developer's tree; for an isolated run the throwaway clone is
27
+ * removed anyway).
28
+ */
29
+ function injectRunsOnLabel(lockPath, label) {
30
+ const original = fs.readFileSync(lockPath, "utf-8");
31
+ const lock = JSON.parse(original);
32
+ for (const workflow of lock.workflows ?? []) for (const job of workflow.jobs ?? []) {
33
+ const runsOn = job.runsOn ??= [];
34
+ if (!runsOn.some((m) => m.kind === "exact" && m.value === label)) runsOn.push({
35
+ kind: "exact",
36
+ value: label
37
+ });
38
+ }
39
+ fs.writeFileSync(lockPath, JSON.stringify(lock, null, 2) + "\n");
40
+ return { restore: () => {
41
+ fs.writeFileSync(lockPath, original);
42
+ } };
43
+ }
44
+ //#endregion
45
+ export { injectRunsOnLabel };
46
+
47
+ //# sourceMappingURL=trusted-routing.js.map
@@ -485,12 +485,12 @@ function validateRunsOn(runsOn, jobName) {
485
485
  if (overlap.length > 0) throw new Error(`Job "${jobName}": labels and exclude overlap on [${overlap.join(", ")}]. A label cannot be both required and excluded.`);
486
486
  }
487
487
  /**
488
- * Transform one environment reference (static name or function) into a lock
488
+ * Transform one context reference (static name or function) into a lock
489
489
  * `{ value, dynamic }` entry. A function element is analyzed for purity: a pure
490
490
  * function becomes an inline expression resolvable at two-phase eval; an impure
491
491
  * one carries only the `dynamic` flag (the agent runs an init job to resolve it).
492
492
  */
493
- function transformEnvironmentRef(ref, jobName) {
493
+ function transformContextRef(ref, jobName) {
494
494
  if (typeof ref === "function") {
495
495
  const fnSource = ref.toString();
496
496
  const purity = analyzePurity(fnSource);
@@ -501,7 +501,7 @@ function transformEnvironmentRef(ref, jobName) {
501
501
  },
502
502
  dynamic: true
503
503
  };
504
- console.warn(`[kici] Job "${jobName}": environment function is not pure (${purity.reason}). An init job will be required, adding ~5-10s delay.`);
504
+ console.warn(`[kici] Job "${jobName}": context function is not pure (${purity.reason}). An init job will be required, adding ~5-10s delay.`);
505
505
  return {
506
506
  value: "",
507
507
  dynamic: true
@@ -522,9 +522,9 @@ function transformJob(job, configPath, index, gitRoot, uuidToName) {
522
522
  if (job.maxParallel !== void 0 && job.maxParallel < 1) throw new Error(`job '${job.name}': maxParallel must be >= 1`);
523
523
  if (!(job.matrix !== void 0 || job.runsOnAll !== void 0) && (job.maxParallel !== void 0 || job.failFast !== void 0)) console.warn(`[kici] job '${job.name}': maxParallel/failFast are ignored without matrix or runsOnAll (no fan-out to bound)`);
524
524
  if (job.runsOn !== void 0) validateRunsOn(job.runsOn, job.name);
525
- const environmentFields = {};
526
- const envRefs = job.environments ?? (job.environment !== void 0 ? [job.environment] : void 0);
527
- if (envRefs !== void 0 && envRefs.length > 0) environmentFields.environments = envRefs.map((ref) => transformEnvironmentRef(ref, job.name));
525
+ const contextFields = {};
526
+ const contextRefs = job.contexts ?? (job.context !== void 0 ? [job.context] : void 0);
527
+ if (contextRefs !== void 0 && contextRefs.length > 0) contextFields.contexts = contextRefs.map((ref) => transformContextRef(ref, job.name));
528
528
  const envFields = {};
529
529
  if (job.env !== void 0) {
530
530
  if (typeof job.env === "function") {
@@ -576,7 +576,7 @@ function transformJob(job, configPath, index, gitRoot, uuidToName) {
576
576
  ...job.checkout !== void 0 && { checkout: job.checkout },
577
577
  ...job.cache !== void 0 && { cache: normalizeCacheSpecs(job.cache) },
578
578
  ...job.container !== void 0 && { container: job.container },
579
- ...environmentFields,
579
+ ...contextFields,
580
580
  ...envFields,
581
581
  ...concurrencyFields,
582
582
  ...job.onCancel !== void 0 && { hasOnCancel: true },
@@ -36,18 +36,18 @@ export interface RegistrationsListFilters {
36
36
  repoIdentifier?: string;
37
37
  }
38
38
  /**
39
- * A secret context (environment) as surfaced to the developer CLI's
39
+ * A secret context (context) as surfaced to the developer CLI's
40
40
  * `secrets list` / `types` commands. The orchestrator returns the per-env
41
41
  * secret key names (never values) when `includeSecrets` is requested.
42
42
  */
43
- declare const environmentContextSchema: z.ZodObject<{
43
+ declare const contextContextSchema: z.ZodObject<{
44
44
  name: z.ZodString;
45
45
  enabled: z.ZodBoolean;
46
46
  allowLocalExecution: z.ZodBoolean;
47
47
  secretKeys: z.ZodDefault<z.ZodArray<z.ZodString>>;
48
48
  }, z.core.$strip>;
49
- /** A secret context (environment) returned by {@link DashboardClient.listEnvironments}. */
50
- export type EnvironmentContext = z.infer<typeof environmentContextSchema>;
49
+ /** A secret context (context) returned by {@link DashboardClient.listContexts}. */
50
+ export type ContextContext = z.infer<typeof contextContextSchema>;
51
51
  export declare class DashboardClient {
52
52
  private readonly endpoint;
53
53
  private readonly token;
@@ -80,13 +80,13 @@ export declare class DashboardClient {
80
80
  /** List the org's permanently registered workflows (GET /registrations). */
81
81
  listRegistrations(filters?: RegistrationsListFilters): Promise<RegistrationsListResult>;
82
82
  /**
83
- * List the org's environments as secret contexts (GET /environments).
83
+ * List the org's contexts as secret contexts (GET /contexts).
84
84
  *
85
- * Pass `includeSecrets` to have the orchestrator attach each environment's
85
+ * Pass `includeSecrets` to have the orchestrator attach each context's
86
86
  * reachable secret key names (never values). Used by `kici secrets list`
87
87
  * and `kici types`.
88
88
  */
89
- listEnvironments(includeSecrets?: boolean): Promise<EnvironmentContext[]>;
89
+ listContexts(includeSecrets?: boolean): Promise<ContextContext[]>;
90
90
  }
91
91
  export {};
92
92
  //# sourceMappingURL=dashboard-client.d.ts.map
@@ -29,17 +29,17 @@ const registrationsListSchema = z.object({
29
29
  registryUpdatedAt: z.string()
30
30
  });
31
31
  /**
32
- * A secret context (environment) as surfaced to the developer CLI's
32
+ * A secret context (context) as surfaced to the developer CLI's
33
33
  * `secrets list` / `types` commands. The orchestrator returns the per-env
34
34
  * secret key names (never values) when `includeSecrets` is requested.
35
35
  */
36
- const environmentContextSchema = z.object({
36
+ const contextContextSchema = z.object({
37
37
  name: z.string(),
38
38
  enabled: z.boolean(),
39
39
  allowLocalExecution: z.boolean(),
40
40
  secretKeys: z.array(z.string()).default([])
41
41
  });
42
- const environmentsListSchema = z.object({ environments: z.array(environmentContextSchema).default([]) });
42
+ const contextsListSchema = z.object({ contexts: z.array(contextContextSchema).default([]) });
43
43
  const STATUS_ERROR_MAP = {
44
44
  401: ["unauthorized", "Authentication failed. Run `kici login` to re-authenticate."],
45
45
  403: ["forbidden", "Access denied."],
@@ -151,15 +151,15 @@ var DashboardClient = class DashboardClient {
151
151
  return registrationsListSchema.parse(await this.getJson(`/registrations${suffix}`));
152
152
  }
153
153
  /**
154
- * List the org's environments as secret contexts (GET /environments).
154
+ * List the org's contexts as secret contexts (GET /contexts).
155
155
  *
156
- * Pass `includeSecrets` to have the orchestrator attach each environment's
156
+ * Pass `includeSecrets` to have the orchestrator attach each context's
157
157
  * reachable secret key names (never values). Used by `kici secrets list`
158
158
  * and `kici types`.
159
159
  */
160
- async listEnvironments(includeSecrets = false) {
160
+ async listContexts(includeSecrets = false) {
161
161
  const suffix = includeSecrets ? "?includeSecrets=true" : "";
162
- return environmentsListSchema.parse(await this.getJson(`/environments${suffix}`)).environments;
162
+ return contextsListSchema.parse(await this.getJson(`/contexts${suffix}`)).contexts;
163
163
  }
164
164
  };
165
165
  //#endregion
@@ -94,7 +94,7 @@ export interface PlatformTriggerResponse {
94
94
  status: 'accepted' | 'rejected';
95
95
  reason?: string;
96
96
  jobIds?: string[];
97
- /** User-visible warnings on acceptance (e.g. skipped non-test bound environments). */
97
+ /** User-visible warnings on acceptance (e.g. skipped non-test bound contexts). */
98
98
  warnings?: string[];
99
99
  }
100
100
  export interface PlatformRunStatusResponse {
@@ -0,0 +1,18 @@
1
+ import type { ParsedSecrets } from '../test-runner/secrets-file.js';
2
+ /**
3
+ * Load secrets from multiple sources with merge precedence.
4
+ *
5
+ * Merge order (lowest to highest priority):
6
+ * 1. .kici/.secrets (INI-style, backward compat)
7
+ * 2. .kici/.env.local (dotenv format)
8
+ * 3. .kici/secrets.yaml (YAML with context scopes, merged flat)
9
+ * 4. --env KEY=VALUE CLI flags
10
+ *
11
+ * Note: process.env is NOT merged here -- it's handled at step-context level.
12
+ *
13
+ * @param kiciDir - Path to the .kici directory
14
+ * @param envFlags - Optional --env KEY=VALUE flag values
15
+ * @returns Merged secrets with correct precedence
16
+ */
17
+ export declare function loadLocalSecrets(kiciDir: string, envFlags?: string[]): Promise<ParsedSecrets>;
18
+ //# sourceMappingURL=secret-loader.d.ts.map
@@ -3,7 +3,7 @@ import { loadSecretsFile } from "../test-runner/secrets-file.js";
3
3
  import path from "node:path";
4
4
  import { readFile } from "node:fs/promises";
5
5
  import { parse } from "yaml";
6
- //#region src/local-executor/secret-loader.ts
6
+ //#region src/remote/secret-loader.ts
7
7
  /**
8
8
  * Parse a dotenv-style file (.env.local) into flat key-value pairs.
9
9
  * Lines starting with # are comments. Blank lines are ignored.
@@ -24,8 +24,8 @@ function parseDotenv(content) {
24
24
  }
25
25
  /**
26
26
  * Parse a secrets.yaml file.
27
- * Expected format: top-level keys are environment names, values are key-value maps.
28
- * For local execution, all environments are merged flat (no environment resolution).
27
+ * Expected format: top-level keys are context names, values are key-value maps.
28
+ * For local execution, all contexts are merged flat (no context resolution).
29
29
  */
30
30
  function parseSecretsYaml(content) {
31
31
  const parsed = parse(content);
@@ -66,7 +66,7 @@ async function readFileOrNull(filePath) {
66
66
  * Merge order (lowest to highest priority):
67
67
  * 1. .kici/.secrets (INI-style, backward compat)
68
68
  * 2. .kici/.env.local (dotenv format)
69
- * 3. .kici/secrets.yaml (YAML with environment scopes, merged flat)
69
+ * 3. .kici/secrets.yaml (YAML with context scopes, merged flat)
70
70
  * 4. --env KEY=VALUE CLI flags
71
71
  *
72
72
  * Note: process.env is NOT merged here -- it's handled at step-context level.
@@ -6,7 +6,7 @@
6
6
  */
7
7
  export declare function parseContextFlags(flags: string[] | undefined): Record<string, Record<string, string>>;
8
8
  /**
9
- * Load the developer's local secrets (same sources as `kici run local`: the
9
+ * Load the developer's local secrets (same sources as `kici run --local`: the
10
10
  * `.kici` secret files plus `--env` flat flags) and `--context` namespaced
11
11
  * flags, and encrypt them to the orchestrator's per-upload X25519 public key.
12
12
  * `--context` values override `.kici/.secrets` file contexts for the same key.
@@ -1,5 +1,5 @@
1
1
  import "../rolldown-runtime-ClRpJifh.js";
2
- import { loadLocalSecrets } from "../local-executor/secret-loader.js";
2
+ import { loadLocalSecrets } from "./secret-loader.js";
3
3
  import { encryptJson } from "@kici-dev/core";
4
4
  //#region src/remote/secret-upload.ts
5
5
  /**
@@ -25,7 +25,7 @@ function parseContextFlags(flags) {
25
25
  return contexts;
26
26
  }
27
27
  /**
28
- * Load the developer's local secrets (same sources as `kici run local`: the
28
+ * Load the developer's local secrets (same sources as `kici run --local`: the
29
29
  * `.kici` secret files plus `--env` flat flags) and `--context` namespaced
30
30
  * flags, and encrypt them to the orchestrator's per-upload X25519 public key.
31
31
  * `--context` values override `.kici/.secrets` file contexts for the same key.
@@ -82,7 +82,7 @@ export interface OverlaySelection {
82
82
  * When `fullWorkingTree` is set (the `kici run remote` path), the entire
83
83
  * `.git` directory is additively included so the extracted overlay is a real
84
84
  * git repository on the agent — workflow steps that shell out to git then work
85
- * exactly as they do under `kici run local`. The `.git` files are added after
85
+ * exactly as they do under `kici run --local`. The `.git` files are added after
86
86
  * `.kiciignore` filtering (git internals are never subject to working-tree
87
87
  * ignore globs).
88
88
  *
@@ -44,7 +44,7 @@ function isGitDirPath(relPath) {
44
44
  * clone on the agent — we enumerate the directory explicitly. Including the
45
45
  * whole `.git` directory (objects, refs, HEAD, index, config, packed-refs)
46
46
  * makes the extracted overlay a real git repository, so workflow steps that
47
- * shell out to git work exactly as they do under `kici run local`.
47
+ * shell out to git work exactly as they do under `kici run --local`.
48
48
  */
49
49
  async function collectGitDirFiles(repoRoot) {
50
50
  const gitRoot = path.join(repoRoot, ".git");
@@ -94,7 +94,7 @@ async function loadKiciIgnore(kiciIgnorePath) {
94
94
  * When `fullWorkingTree` is set (the `kici run remote` path), the entire
95
95
  * `.git` directory is additively included so the extracted overlay is a real
96
96
  * git repository on the agent — workflow steps that shell out to git then work
97
- * exactly as they do under `kici run local`. The `.git` files are added after
97
+ * exactly as they do under `kici run --local`. The `.git` files are added after
98
98
  * `.kiciignore` filtering (git internals are never subject to working-tree
99
99
  * ignore globs).
100
100
  *
@@ -4,5 +4,5 @@
4
4
  * picked up by Claude Code, Cursor, Aider, and other coding agents that scan
5
5
  * the working tree for an authoring context file.
6
6
  */
7
- export declare const agentsMdTemplate = "# KiCI workflow authoring guide\n\nThis project uses KiCI \u2014 a TypeScript-native CI/CD workflow engine \u2014 instead\nof YAML-based CI. Workflows live in `.kici/workflows/*.ts`, are compiled\ninto a portable lock file, and executed by self-hosted agents.\n\n## Where the API surface lives\n\n- Public SDK types: `node_modules/@kici-dev/sdk/dist/index.d.ts` \u2014 read this\n for the canonical signatures of `workflow`, `job`, `step`, `pr`,\n `push`, `schedule`, `matrix`, `rule`, `dynamicJob`, etc.\n- Bundled offline reference for coding agents: `kici docs llm` prints the\n full markdown documentation bundle to stdout. `kici docs llm --index`\n prints just the curated link index (llms.txt format).\n- Online docs:\n - <https://kici.dev/docs/> \u2014 published docs site.\n - <https://kici.dev/llms.txt> \u2014 curated index for LLM consumers.\n - <https://kici.dev/llms-full.txt> \u2014 full markdown bundle.\n - Key pages: `user/sdk-reference`, `user/workflow-patterns`,\n `user/testing-guide`, `user/hooks`, `user/secrets`.\n\n## The five core patterns\n\n1. **Push trigger** \u2014 `on: push({ branches: 'main' })`. Pair with `paths`\n to scope to subtrees.\n\n ```ts\n import { workflow, job, step, push } from '@kici-dev/sdk';\n\n export default workflow('build', {\n on: push({ branches: 'main' }),\n jobs: [\n job('build', {\n runsOn: 'kici:os:linux',\n steps: [step('install', async ({ $ }) => { await $`pnpm install`; })],\n }),\n ],\n });\n ```\n\n `kici:os:linux` targets any agent reporting that OS \u2014 every agent\n self-reports `kici:os:` / `kici:arch:` / `kici:host:`. Use a custom label\n (e.g. `'gpu'`, `'prod-pool'`) to target a specific agent pool your scaler\n defines.\n\n2. **PR + matrix** \u2014 `pr({ target: 'main' })` plus a matrix over node\n versions. The matrix expands at dispatch time.\n\n ```ts\n import { workflow, job, step, pr, matrix } from '@kici-dev/sdk';\n\n export default workflow('test-matrix', {\n on: pr({ target: 'main' }),\n jobs: [\n job('test', {\n runsOn: 'kici:os:linux',\n strategy: { matrix: matrix({ node: ['20', '22', '24'] }) },\n steps: [\n step('test', async ({ $, matrix }) => {\n await $`node --version`;\n await $`pnpm install`;\n await $`pnpm test`;\n return { node: matrix.node };\n }),\n ],\n }),\n ],\n });\n ```\n\n3. **Lifecycle hooks** \u2014 `onFailure` / `onSuccess` / `onCancel` on a\n job or workflow run after the main steps in their own scope.\n\n4. **Secrets** \u2014 declared scopes resolve at dispatch:\n\n ```ts\n step('deploy', async ({ $, secrets }) => {\n await $`./scripts/deploy.sh`.env({ DEPLOY_TOKEN: secrets.production.DEPLOY_TOKEN });\n });\n ```\n\n Run `kici secrets list` to enumerate the contexts available for testing.\n\n5. **Dynamic jobs** \u2014 `dynamicJob` and `dynamicGroup` build the DAG at\n runtime from a step's outputs. Don't try to compute job names at top level;\n the lock file would be wrong.\n\n## Anti-patterns\n\n- **Do NOT write `.yml` / `.yaml` CI files** \u2014 KiCI replaces that entire\n layer. There is no compatibility shim.\n- **Do NOT `import` from any `@kici-dev/*` package's `/dist/...`\n subpath** \u2014 those are not part of the public API and break across versions.\n Import from the package root.\n- **Do NOT `await` outside step bodies.** The top-level workflow file is\n loaded by the compiler synchronously; async I/O at module scope means the\n lock file emits before it resolves and the workflow appears empty.\n- **Do NOT mutate shared variables between jobs.** Each job runs in its own\n agent process. Use `needs` + step outputs to thread values.\n- **Do NOT hand-edit `kici.lock.json`.** Regenerate it via `kici compile`.\n\n## Local commands a coding agent should run\n\n| Command | Purpose |\n| ------------------------------- | ------------------------------------------- |\n| `pnpm kici compile --check` | Validate workflow source without writing. |\n| `pnpm kici preview pr:open --debug` | Preview which workflows match an event. |\n| `pnpm kici run local push` | Execute workflows locally with no orchestrator. |\n| `pnpm kici docs llm` | Print the full LLM documentation bundle. |\n| `pnpm kici docs llm --index` | Print the curated link index. |\n\nIf `pnpm kici` isn't in scripts, fall back to `npx kici`.\n\n## Loop\n\n1. Read the SDK types from `node_modules/@kici-dev/sdk/dist/index.d.ts`.\n2. Pipe `kici docs llm` into the agent's context if it doesn't already have\n the full bundle.\n3. Edit a workflow under `.kici/workflows/`.\n4. Run `kici compile --check` (zero exit means valid).\n5. Run `kici preview <event>` to preview matching.\n6. Run `kici run local <event>` to execute locally before pushing.\n";
7
+ export declare const agentsMdTemplate = "# KiCI workflow authoring guide\n\nThis project uses KiCI \u2014 a TypeScript-native CI/CD workflow engine \u2014 instead\nof YAML-based CI. Workflows live in `.kici/workflows/*.ts`, are compiled\ninto a portable lock file, and executed by self-hosted agents.\n\n## Where the API surface lives\n\n- Public SDK types: `node_modules/@kici-dev/sdk/dist/index.d.ts` \u2014 read this\n for the canonical signatures of `workflow`, `job`, `step`, `pr`,\n `push`, `schedule`, `matrix`, `rule`, `dynamicJob`, etc.\n- Bundled offline reference for coding agents: `kici docs llm` prints the\n full markdown documentation bundle to stdout. `kici docs llm --index`\n prints just the curated link index (llms.txt format).\n- Online docs:\n - <https://kici.dev/docs/> \u2014 published docs site.\n - <https://kici.dev/llms.txt> \u2014 curated index for LLM consumers.\n - <https://kici.dev/llms-full.txt> \u2014 full markdown bundle.\n - Key pages: `user/sdk-reference`, `user/workflow-patterns`,\n `user/testing-guide`, `user/hooks`, `user/secrets`.\n\n## The five core patterns\n\n1. **Push trigger** \u2014 `on: push({ branches: 'main' })`. Pair with `paths`\n to scope to subtrees.\n\n ```ts\n import { workflow, job, step, push } from '@kici-dev/sdk';\n\n export default workflow('build', {\n on: push({ branches: 'main' }),\n jobs: [\n job('build', {\n runsOn: 'kici:os:linux',\n steps: [step('install', async ({ $ }) => { await $`pnpm install`; })],\n }),\n ],\n });\n ```\n\n `kici:os:linux` targets any agent reporting that OS \u2014 every agent\n self-reports `kici:os:` / `kici:arch:` / `kici:host:`. Use a custom label\n (e.g. `'gpu'`, `'prod-pool'`) to target a specific agent pool your scaler\n defines.\n\n2. **PR + matrix** \u2014 `pr({ target: 'main' })` plus a matrix over node\n versions. The matrix expands at dispatch time.\n\n ```ts\n import { workflow, job, step, pr, matrix } from '@kici-dev/sdk';\n\n export default workflow('test-matrix', {\n on: pr({ target: 'main' }),\n jobs: [\n job('test', {\n runsOn: 'kici:os:linux',\n strategy: { matrix: matrix({ node: ['20', '22', '24'] }) },\n steps: [\n step('test', async ({ $, matrix }) => {\n await $`node --version`;\n await $`pnpm install`;\n await $`pnpm test`;\n return { node: matrix.node };\n }),\n ],\n }),\n ],\n });\n ```\n\n3. **Lifecycle hooks** \u2014 `onFailure` / `onSuccess` / `onCancel` on a\n job or workflow run after the main steps in their own scope.\n\n4. **Secrets** \u2014 declared scopes resolve at dispatch:\n\n ```ts\n step('deploy', async ({ $, secrets }) => {\n await $`./scripts/deploy.sh`.env({ DEPLOY_TOKEN: secrets.production.DEPLOY_TOKEN });\n });\n ```\n\n Run `kici secrets list` to enumerate the contexts available for testing.\n\n5. **Dynamic jobs** \u2014 `dynamicJob` and `dynamicGroup` build the DAG at\n runtime from a step's outputs. Don't try to compute job names at top level;\n the lock file would be wrong.\n\n## Anti-patterns\n\n- **Do NOT write `.yml` / `.yaml` CI files** \u2014 KiCI replaces that entire\n layer. There is no compatibility shim.\n- **Do NOT `import` from any `@kici-dev/*` package's `/dist/...`\n subpath** \u2014 those are not part of the public API and break across versions.\n Import from the package root.\n- **Do NOT `await` outside step bodies.** The top-level workflow file is\n loaded by the compiler synchronously; async I/O at module scope means the\n lock file emits before it resolves and the workflow appears empty.\n- **Do NOT mutate shared variables between jobs.** Each job runs in its own\n agent process. Use `needs` + step outputs to thread values.\n- **Do NOT hand-edit `kici.lock.json`.** Regenerate it via `kici compile`.\n\n## Local commands a coding agent should run\n\n| Command | Purpose |\n| ------------------------------- | ------------------------------------------- |\n| `pnpm kici compile --check` | Validate workflow source without writing. |\n| `pnpm kici preview pr:open --debug` | Preview which workflows match an event. |\n| `pnpm kici run push --local` | Execute a workflow locally (this machine as an ephemeral agent). |\n| `pnpm kici docs llm` | Print the full LLM documentation bundle. |\n| `pnpm kici docs llm --index` | Print the curated link index. |\n\nIf `pnpm kici` isn't in scripts, fall back to `npx kici`.\n\n## Loop\n\n1. Read the SDK types from `node_modules/@kici-dev/sdk/dist/index.d.ts`.\n2. Pipe `kici docs llm` into the agent's context if it doesn't already have\n the full bundle.\n3. Edit a workflow under `.kici/workflows/`.\n4. Run `kici compile --check` (zero exit means valid).\n5. Run `kici preview <event>` to preview matching.\n6. Run `kici run <event> --local` to execute locally before pushing.\n";
8
8
  //# sourceMappingURL=agents-md.d.ts.map
@@ -113,7 +113,7 @@ into a portable lock file, and executed by self-hosted agents.
113
113
  | ------------------------------- | ------------------------------------------- |
114
114
  | \`pnpm kici compile --check\` | Validate workflow source without writing. |
115
115
  | \`pnpm kici preview pr:open --debug\` | Preview which workflows match an event. |
116
- | \`pnpm kici run local push\` | Execute workflows locally with no orchestrator. |
116
+ | \`pnpm kici run push --local\` | Execute a workflow locally (this machine as an ephemeral agent). |
117
117
  | \`pnpm kici docs llm\` | Print the full LLM documentation bundle. |
118
118
  | \`pnpm kici docs llm --index\` | Print the curated link index. |
119
119
 
@@ -127,7 +127,7 @@ If \`pnpm kici\` isn't in scripts, fall back to \`npx kici\`.
127
127
  3. Edit a workflow under \`.kici/workflows/\`.
128
128
  4. Run \`kici compile --check\` (zero exit means valid).
129
129
  5. Run \`kici preview <event>\` to preview matching.
130
- 6. Run \`kici run local <event>\` to execute locally before pushing.
130
+ 6. Run \`kici run <event> --local\` to execute locally before pushing.
131
131
  `;
132
132
  //#endregion
133
133
  export { agentsMdTemplate };
@@ -1,6 +1,6 @@
1
1
  import "../rolldown-runtime-ClRpJifh.js";
2
2
  //#region src/templates/package-json.ts
3
- const sdkVersion = "0.1.25";
3
+ const sdkVersion = "0.1.27";
4
4
  /**
5
5
  * Generate package.json content for .kici/ directory
6
6
  *
@@ -2,7 +2,7 @@ import "../rolldown-runtime-ClRpJifh.js";
2
2
  import { formatter } from "./output-formatter.js";
3
3
  import { createStepContext } from "./step-context.js";
4
4
  import { createRuleContext, evaluateRules as evaluateRulesWithFormatting } from "./rule-evaluator.js";
5
- import { localRunsOnString } from "../local-executor/runs-on-display.js";
5
+ import { localRunsOnString } from "./runs-on-display.js";
6
6
  import { pathToFileURL } from "node:url";
7
7
  import path from "node:path";
8
8
  import pc from "picocolors";
@@ -0,0 +1,9 @@
1
+ import type { RunsOn } from '@kici-dev/sdk';
2
+ /**
3
+ * Render a job's `runsOn` to the comma-joined label string the local/test
4
+ * runners surface as `ctx.job.runsOn`. A `runsOnAll` job has no `runsOn` —
5
+ * locally it runs once on this machine, so we surface the marker `'runsOnAll'`.
6
+ * RegExp selectors render via their `/source/flags` literal.
7
+ */
8
+ export declare function localRunsOnString(runsOn: RunsOn | undefined): string;
9
+ //# sourceMappingURL=runs-on-display.d.ts.map
@@ -1,5 +1,5 @@
1
1
  import "../rolldown-runtime-ClRpJifh.js";
2
- //#region src/local-executor/runs-on-display.ts
2
+ //#region src/test-runner/runs-on-display.ts
3
3
  /** Render one selector element (string label or RegExp) for the local display string. */
4
4
  function runsOnElementString(el) {
5
5
  return el instanceof RegExp ? el.toString() : el;
@@ -11,5 +11,5 @@ import type { StepContext, WorkflowInfo, JobInfo, MatrixValues } from '@kici-dev
11
11
  export declare function createStepContext(workflowInfo: WorkflowInfo, jobInfo: JobInfo, repoRoot: string, inputs?: Record<string, unknown>, matrix?: MatrixValues, testSecrets?: {
12
12
  flat: Record<string, string>;
13
13
  contexts: Record<string, Record<string, string>>;
14
- }, environment?: string, rawPayload?: Record<string, unknown>, provider?: string, dispatchInputs?: Readonly<Record<string, string | number | boolean | null>>, signal?: AbortSignal): StepContext;
14
+ }, context?: string, rawPayload?: Record<string, unknown>, provider?: string, dispatchInputs?: Readonly<Record<string, string | number | boolean | null>>, signal?: AbortSignal): StepContext;
15
15
  //# sourceMappingURL=step-context.d.ts.map
@@ -42,7 +42,7 @@ function createTestLogger(jobName) {
42
42
  * `ctx.$` would inherit `process.cwd()` — i.e. wherever the user invoked
43
43
  * `kici` — which silently breaks any step that uses relative paths.
44
44
  */
45
- function createStepContext(workflowInfo, jobInfo, repoRoot, inputs = {}, matrix, testSecrets, environment, rawPayload, provider, dispatchInputs = {}, signal = new AbortController().signal) {
45
+ function createStepContext(workflowInfo, jobInfo, repoRoot, inputs = {}, matrix, testSecrets, context, rawPayload, provider, dispatchInputs = {}, signal = new AbortController().signal) {
46
46
  const flat = testSecrets?.flat ?? {};
47
47
  const namespacedSecrets = testSecrets?.contexts ?? {};
48
48
  const mergedFlat = { ...flat };
@@ -116,7 +116,7 @@ function createStepContext(workflowInfo, jobInfo, repoRoot, inputs = {}, matrix,
116
116
  job: jobInfo,
117
117
  matrix,
118
118
  isTestRun: false,
119
- environment,
119
+ context,
120
120
  ...rawPayload && { rawPayload },
121
121
  ...provider && { provider },
122
122
  secrets: secretsHandle.secrets,
package/dist/types.d.ts CHANGED
@@ -28,7 +28,7 @@ export interface LockApproval {
28
28
  readonly when: 'always' | 'drift';
29
29
  }
30
30
  /** Schema version - re-exported from engine as single source of truth */
31
- export declare const SCHEMA_VERSION: 29;
31
+ export declare const SCHEMA_VERSION: 30;
32
32
  /**
33
33
  * Source file reference with meaningful path.
34
34
  * Format: file is relative path from git root, export uses hash syntax.
@@ -441,11 +441,11 @@ export interface LockJob {
441
441
  env?: Record<string, string>;
442
442
  };
443
443
  /**
444
- * Deployment environments in merge order. Each entry is a static name or inline
444
+ * Bound contexts in merge order. Each entry is a static name or inline
445
445
  * expression (pure function); `dynamic` is set when it is a function resolved at
446
446
  * two-phase eval. Later entries override earlier ones on name collisions.
447
447
  */
448
- readonly environments?: ReadonlyArray<{
448
+ readonly contexts?: ReadonlyArray<{
449
449
  value: string | LockInlineValue;
450
450
  dynamic: boolean;
451
451
  }>;
@@ -517,12 +517,12 @@ export type LockJobOrFactory = LockJob | LockDynamicJobFn;
517
517
  /**
518
518
  * Private npm registry declaration in the lock file.
519
519
  * Carries URL/scope/secret-reference but NOT the resolved token — the orchestrator
520
- * resolves the token at dispatch via the per-environment secretResolver path.
520
+ * resolves the token at dispatch via the per-context secretResolver path.
521
521
  */
522
522
  export interface LockRegistry {
523
523
  readonly url: string;
524
524
  readonly scope?: string;
525
- /** Qualified secret reference: `<environment>:<secret-name>`. */
525
+ /** Qualified secret reference: `<context>:<secret-name>`. */
526
526
  readonly tokenSecret: string;
527
527
  readonly alwaysAuth?: boolean;
528
528
  }
@@ -554,7 +554,7 @@ export interface LockWorkflow {
554
554
  */
555
555
  readonly registries?: readonly LockRegistry[];
556
556
  /**
557
- * Extra qualified secret refs (`<environment>:<secret-name>`) to project as env vars
557
+ * Extra qualified secret refs (`<context>:<secret-name>`) to project as env vars
558
558
  * on the install subprocess for use with a customer-committed `.kici/.npmrc`.
559
559
  */
560
560
  readonly installEnv?: readonly string[];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kici-dev/compiler",
3
- "version": "0.1.25",
3
+ "version": "0.1.27",
4
4
  "description": "Compiler and CLI for KiCI workflows. Compiles `.kici/workflows/*.ts` to a `kici.lock.json` file consumed by the orchestrator and agents, and runs workflows locally or against a remote orchestrator.",
5
5
  "keywords": [
6
6
  "ci",
@@ -49,6 +49,7 @@
49
49
  "@inquirer/prompts": "^8.5.2",
50
50
  "chokidar": "^5.0.0",
51
51
  "commander": "^15.0.0",
52
+ "embedded-postgres": "18.4.0-beta.17",
52
53
  "fast-glob": "^3.3.3",
53
54
  "open": "^11.0.0",
54
55
  "picocolors": "^1.1.1",
@@ -60,11 +61,13 @@
60
61
  "yaml": "^2.9.0",
61
62
  "zod": "^4.4.3",
62
63
  "zx": "^8.8.5",
63
- "@kici-dev/core": "0.1.25",
64
- "@kici-dev/engine": "0.1.25"
64
+ "@kici-dev/orchestrator": "0.1.27",
65
+ "@kici-dev/core": "0.1.27",
66
+ "@kici-dev/agent": "0.1.27",
67
+ "@kici-dev/engine": "0.1.27"
65
68
  },
66
69
  "peerDependencies": {
67
- "@kici-dev/sdk": "0.1.25"
70
+ "@kici-dev/sdk": "0.1.27"
68
71
  },
69
72
  "devDependencies": {
70
73
  "@types/proper-lockfile": "^4.1.4"