@kici-dev/compiler 0.1.26 → 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,151 @@
1
+ /** Whether the plane runs offline (independent) or attached to the Platform (hybrid). */
2
+ export type PlaneMode = 'independent' | 'hybrid';
3
+ /**
4
+ * Attachment record for a hybrid plane: the Platform relay it dials, the org it
5
+ * is scoped to, and the Platform api_keys id of its minted orchestrator key (for
6
+ * later revoke). The orchestrator token itself is NEVER stored here — it lives
7
+ * in a sibling 0600 file so it can't land in a world-readable stamp.
8
+ */
9
+ export interface PlaneAttachment {
10
+ /** Orchestrator KICI_PLATFORM_URL — a ws(s)://…/ws relay URL. */
11
+ platformWsUrl: string;
12
+ /** HTTPS Platform API base (provenance/verify context, key revoke). */
13
+ platformApiBase: string;
14
+ orgId: string;
15
+ /** Platform api_keys id of the minted orchestrator key. */
16
+ keyId: string;
17
+ }
18
+ /** On-disk record of the running plane, written on boot, read on status/down. */
19
+ export interface PlaneStamp {
20
+ orchestratorPid: number;
21
+ port: number;
22
+ pgKind: 'embedded' | 'podman';
23
+ kiciVersion: string;
24
+ stampVersion: number;
25
+ /** Offline (independent) vs attached (hybrid). Absent (legacy) reads as independent. */
26
+ mode?: PlaneMode;
27
+ }
28
+ export interface PlaneStatus {
29
+ running: boolean;
30
+ pid?: number;
31
+ port?: number;
32
+ pgKind?: 'embedded' | 'podman';
33
+ stampVersion?: number;
34
+ url?: string;
35
+ /** Bootstrap admin token the CLI presents to the plane's admin API. */
36
+ adminToken?: string;
37
+ /** Offline (independent) vs attached (hybrid). */
38
+ mode: PlaneMode;
39
+ /** Present iff mode === 'hybrid'. */
40
+ attachment?: PlaneAttachment;
41
+ }
42
+ /**
43
+ * Read the plane's persisted Platform orchestrator token (mode 0600), or null
44
+ * when the plane is independent/offline. Kept out of the stamp so the token
45
+ * never lands in a world-readable file.
46
+ */
47
+ export declare function readPlatformToken(): string | null;
48
+ /** Persist the Platform orchestrator token (mode 0600). */
49
+ export declare function writePlatformToken(token: string): void;
50
+ /** Remove the persisted Platform orchestrator token (on detach). */
51
+ export declare function clearPlatformToken(): void;
52
+ /**
53
+ * Read the durable attachment record (survives `kici local down`), or null when
54
+ * the plane is not attached. This — not the running stamp — is the source of
55
+ * truth for "is this plane attached to the Platform".
56
+ */
57
+ export declare function readAttachment(): PlaneAttachment | null;
58
+ /** Persist the durable attachment record (never the token). */
59
+ export declare function writeAttachment(attachment: PlaneAttachment): void;
60
+ /** Remove the durable attachment record (on detach). */
61
+ export declare function clearAttachment(): void;
62
+ /**
63
+ * Read the plane's persisted bootstrap admin token, generating + persisting one
64
+ * (mode 0600) on first boot. A warm plane reuses the same token across CLI
65
+ * invocations so a running orchestrator keeps accepting the CLI's admin calls.
66
+ */
67
+ export declare function readOrCreateAdminToken(): string;
68
+ /** Read the plane's admin token without generating one (null when absent). */
69
+ export declare function planeAdminToken(): string | null;
70
+ /**
71
+ * Read the plane's local master secret key, generating + persisting a fresh 64
72
+ * hex-char key (mode 0600) on first boot. Stable across boots so DB-encrypted
73
+ * material stays decryptable. Freshly generated — never derived from any sops
74
+ * secret. Enables the orchestrator's secrets subsystem, which gates its admin
75
+ * API surface.
76
+ */
77
+ export declare function readOrCreateSecretKey(): string;
78
+ /** Absolute path of the dev-signed identity's private JWK key file. */
79
+ export declare function devIdentityKeyFile(): string;
80
+ /** Absolute path of the dev-signed identity's public JWK (written by the plane orchestrator). */
81
+ export declare function devIdentityPublicJwkFile(): string;
82
+ /**
83
+ * Read the plane's dev-signed identity keypair, generating + persisting a fresh
84
+ * EC P-256 private JWK (mode 0600) on first boot. Stable across boots so a
85
+ * `kici local trust-root` export stays valid for previously-minted tokens.
86
+ * Freshly generated — NEVER derived from any sops secret or real key. Only the
87
+ * private key is written here; the plane orchestrator derives + writes the
88
+ * public JWK next to it. Returns the private-key file path passed to the
89
+ * orchestrator via KICI_DEV_IDENTITY_KEY_FILE.
90
+ */
91
+ export declare function readOrCreateDevIdentity(): string;
92
+ /** Absolute path of the plane orchestrator's log file. */
93
+ export declare function planeLogPath(): string;
94
+ /** Read the plane's current status by probing `/ready` against the stamped port. */
95
+ export declare function planeStatus(): Promise<PlaneStatus>;
96
+ /** Attach parameters for a hybrid plane boot (see attachPlane). */
97
+ export interface PlaneUpAttach {
98
+ platformWsUrl: string;
99
+ platformToken: string;
100
+ platformApiBase: string;
101
+ orgId: string;
102
+ keyId: string;
103
+ }
104
+ export interface PlaneUpOptions {
105
+ /** Boot the plane hybrid (attached to the Platform) instead of independent. */
106
+ attach?: PlaneUpAttach;
107
+ }
108
+ /**
109
+ * Start (or reuse) the local dev plane. Idempotent: a healthy running plane
110
+ * **whose stamped mode matches the requested mode** is returned as-is; a mode
111
+ * change (independent↔hybrid) forces a teardown + reboot. Otherwise Postgres +
112
+ * the orchestrator are booted and a fresh stamp + pidfile are written. When
113
+ * `attach` is present the orchestrator boots hybrid against the Platform relay;
114
+ * otherwise it boots independent with the dev-signed identity.
115
+ */
116
+ export declare function planeUp(opts?: PlaneUpOptions): Promise<PlaneStatus>;
117
+ /**
118
+ * Stop the local dev plane. Teardown is reconstructed from the stamp (the
119
+ * start-time Postgres handle does not survive a separate CLI invocation):
120
+ * SIGTERM the orchestrator, stop Postgres by backend kind, then clear the
121
+ * pidfile + stamp.
122
+ */
123
+ export declare function planeDown(): Promise<void>;
124
+ /**
125
+ * Poll until process `pid` has exited (SIGTERM already sent), escalating to
126
+ * SIGKILL if it outlives the grace period, so the caller can rely on the
127
+ * listening socket being released once this resolves. `process.kill(pid, 0)`
128
+ * throws `ESRCH` once the process is gone.
129
+ */
130
+ export declare function waitForProcessExit(pid: number, graceMs?: number): Promise<void>;
131
+ /**
132
+ * Attach the local dev plane to the hosted Platform: mint an org-scoped
133
+ * orchestrator key with the logged-in PAT, then (re)boot the plane hybrid
134
+ * against the Platform relay. Registration with the Platform is implicit — the
135
+ * hybrid orchestrator's PlatformClient sends `source.register` on WS auth.
136
+ */
137
+ export declare function attachPlane(args: {
138
+ apiBase: string;
139
+ pat: string;
140
+ orgId: string;
141
+ }): Promise<PlaneStatus>;
142
+ /**
143
+ * Detach the local dev plane: best-effort revoke the minted orchestrator key on
144
+ * the Platform, clear the durable attachment + token, then reboot the plane
145
+ * independent (offline). The revoke is non-fatal — a detach must succeed even
146
+ * offline or with an expired PAT.
147
+ */
148
+ export declare function detachPlane(opts?: {
149
+ pat?: string;
150
+ }): Promise<PlaneStatus>;
151
+ //# sourceMappingURL=plane-manager.d.ts.map
@@ -0,0 +1,340 @@
1
+ import "../rolldown-runtime-ClRpJifh.js";
2
+ import { planePaths, planePorts } from "./paths.js";
3
+ import { orchestratorReady, spawnOrchestrator } from "./orchestrator-process.js";
4
+ import { startPlanePostgres, stopPlanePostgres } from "./postgres.js";
5
+ import { writeScalerConfig } from "./scaler-config.js";
6
+ import { derivePlatformWsUrl, mintOrchestratorKey, revokeOrchestratorKey } from "./platform-attach.js";
7
+ import path from "node:path";
8
+ import fs from "node:fs";
9
+ import { generateKeyPairSync, randomBytes } from "node:crypto";
10
+ //#region src/local-plane/plane-manager.ts
11
+ const kiciVersion = "0.1.27";
12
+ /**
13
+ * Read the plane's persisted Platform orchestrator token (mode 0600), or null
14
+ * when the plane is independent/offline. Kept out of the stamp so the token
15
+ * never lands in a world-readable file.
16
+ */
17
+ function readPlatformToken() {
18
+ try {
19
+ return fs.readFileSync(planePaths().platformTokenFile, "utf-8").trim() || null;
20
+ } catch {
21
+ return null;
22
+ }
23
+ }
24
+ /** Persist the Platform orchestrator token (mode 0600). */
25
+ function writePlatformToken(token) {
26
+ const { platformTokenFile, root } = planePaths();
27
+ fs.mkdirSync(root, { recursive: true });
28
+ fs.writeFileSync(platformTokenFile, token, { mode: 384 });
29
+ }
30
+ /** Remove the persisted Platform orchestrator token (on detach). */
31
+ function clearPlatformToken() {
32
+ fs.rmSync(planePaths().platformTokenFile, { force: true });
33
+ }
34
+ /**
35
+ * Read the durable attachment record (survives `kici local down`), or null when
36
+ * the plane is not attached. This — not the running stamp — is the source of
37
+ * truth for "is this plane attached to the Platform".
38
+ */
39
+ function readAttachment() {
40
+ try {
41
+ return JSON.parse(fs.readFileSync(planePaths().attachmentFile, "utf-8"));
42
+ } catch {
43
+ return null;
44
+ }
45
+ }
46
+ /** Persist the durable attachment record (never the token). */
47
+ function writeAttachment(attachment) {
48
+ const { attachmentFile, root } = planePaths();
49
+ fs.mkdirSync(root, { recursive: true });
50
+ fs.writeFileSync(attachmentFile, JSON.stringify(attachment, null, 2));
51
+ }
52
+ /** Remove the durable attachment record (on detach). */
53
+ function clearAttachment() {
54
+ fs.rmSync(planePaths().attachmentFile, { force: true });
55
+ }
56
+ /**
57
+ * Read the plane's persisted bootstrap admin token, generating + persisting one
58
+ * (mode 0600) on first boot. A warm plane reuses the same token across CLI
59
+ * invocations so a running orchestrator keeps accepting the CLI's admin calls.
60
+ */
61
+ function readOrCreateAdminToken() {
62
+ const { adminTokenFile, root } = planePaths();
63
+ try {
64
+ const existing = fs.readFileSync(adminTokenFile, "utf-8").trim();
65
+ if (existing) return existing;
66
+ } catch {}
67
+ fs.mkdirSync(root, { recursive: true });
68
+ const token = `kici-local-${randomBytes(24).toString("hex")}`;
69
+ fs.writeFileSync(adminTokenFile, token, { mode: 384 });
70
+ return token;
71
+ }
72
+ /** Read the plane's admin token without generating one (null when absent). */
73
+ function planeAdminToken() {
74
+ try {
75
+ return fs.readFileSync(planePaths().adminTokenFile, "utf-8").trim() || null;
76
+ } catch {
77
+ return null;
78
+ }
79
+ }
80
+ /**
81
+ * Read the plane's local master secret key, generating + persisting a fresh 64
82
+ * hex-char key (mode 0600) on first boot. Stable across boots so DB-encrypted
83
+ * material stays decryptable. Freshly generated — never derived from any sops
84
+ * secret. Enables the orchestrator's secrets subsystem, which gates its admin
85
+ * API surface.
86
+ */
87
+ function readOrCreateSecretKey() {
88
+ const { secretKeyFile, root } = planePaths();
89
+ try {
90
+ const existing = fs.readFileSync(secretKeyFile, "utf-8").trim();
91
+ if (existing) return existing;
92
+ } catch {}
93
+ fs.mkdirSync(root, { recursive: true });
94
+ const key = randomBytes(32).toString("hex");
95
+ fs.writeFileSync(secretKeyFile, key, { mode: 384 });
96
+ return key;
97
+ }
98
+ /** Absolute path of the dev-signed identity's private JWK key file. */
99
+ function devIdentityKeyFile() {
100
+ return path.join(planePaths().devIdentityDir, "identity.jwk");
101
+ }
102
+ /** Absolute path of the dev-signed identity's public JWK (written by the plane orchestrator). */
103
+ function devIdentityPublicJwkFile() {
104
+ return path.join(planePaths().devIdentityDir, "identity.pub.jwk");
105
+ }
106
+ /**
107
+ * Read the plane's dev-signed identity keypair, generating + persisting a fresh
108
+ * EC P-256 private JWK (mode 0600) on first boot. Stable across boots so a
109
+ * `kici local trust-root` export stays valid for previously-minted tokens.
110
+ * Freshly generated — NEVER derived from any sops secret or real key. Only the
111
+ * private key is written here; the plane orchestrator derives + writes the
112
+ * public JWK next to it. Returns the private-key file path passed to the
113
+ * orchestrator via KICI_DEV_IDENTITY_KEY_FILE.
114
+ */
115
+ function readOrCreateDevIdentity() {
116
+ const keyFile = devIdentityKeyFile();
117
+ try {
118
+ if (fs.readFileSync(keyFile, "utf-8").trim()) return keyFile;
119
+ } catch {}
120
+ fs.mkdirSync(planePaths().devIdentityDir, {
121
+ recursive: true,
122
+ mode: 448
123
+ });
124
+ const { privateKey } = generateKeyPairSync("ec", { namedCurve: "P-256" });
125
+ const jwk = privateKey.export({ format: "jwk" });
126
+ fs.writeFileSync(keyFile, JSON.stringify(jwk, null, 2), { mode: 384 });
127
+ return keyFile;
128
+ }
129
+ function readStamp() {
130
+ try {
131
+ return JSON.parse(fs.readFileSync(planePaths().stampFile, "utf-8"));
132
+ } catch {
133
+ return null;
134
+ }
135
+ }
136
+ function writeStamp(stamp) {
137
+ const { root, stampFile, pidfile } = planePaths();
138
+ fs.mkdirSync(root, { recursive: true });
139
+ fs.writeFileSync(stampFile, JSON.stringify(stamp, null, 2));
140
+ fs.writeFileSync(pidfile, String(stamp.orchestratorPid));
141
+ }
142
+ function orchestratorUrl(port) {
143
+ return `http://127.0.0.1:${port}`;
144
+ }
145
+ /** Absolute path of the plane orchestrator's log file. */
146
+ function planeLogPath() {
147
+ return planePaths().logFile;
148
+ }
149
+ /** Read the plane's current status by probing `/ready` against the stamped port. */
150
+ async function planeStatus() {
151
+ const stamp = readStamp();
152
+ const port = stamp?.port ?? planePorts().orchestrator;
153
+ if (!await orchestratorReady(port)) return {
154
+ running: false,
155
+ mode: stamp?.mode ?? "independent",
156
+ attachment: readAttachment() ?? void 0
157
+ };
158
+ return {
159
+ running: true,
160
+ pid: stamp?.orchestratorPid,
161
+ port,
162
+ pgKind: stamp?.pgKind,
163
+ stampVersion: stamp?.stampVersion,
164
+ url: orchestratorUrl(port),
165
+ adminToken: planeAdminToken() ?? void 0,
166
+ mode: stamp?.mode ?? "independent",
167
+ attachment: readAttachment() ?? void 0
168
+ };
169
+ }
170
+ /**
171
+ * Start (or reuse) the local dev plane. Idempotent: a healthy running plane
172
+ * **whose stamped mode matches the requested mode** is returned as-is; a mode
173
+ * change (independent↔hybrid) forces a teardown + reboot. Otherwise Postgres +
174
+ * the orchestrator are booted and a fresh stamp + pidfile are written. When
175
+ * `attach` is present the orchestrator boots hybrid against the Platform relay;
176
+ * otherwise it boots independent with the dev-signed identity.
177
+ */
178
+ async function planeUp(opts = {}) {
179
+ const { orchestrator: port } = planePorts();
180
+ const existing = readStamp();
181
+ const requestedMode = opts.attach ? "hybrid" : "independent";
182
+ if (existing && existing.stampVersion !== 3) {
183
+ await planeDown();
184
+ fs.rmSync(planePaths().pgData, {
185
+ recursive: true,
186
+ force: true
187
+ });
188
+ } else if ((existing?.mode ?? "independent") !== requestedMode && await orchestratorReady(port)) await planeDown();
189
+ else if (await orchestratorReady(port)) return {
190
+ running: true,
191
+ pid: existing?.orchestratorPid,
192
+ port,
193
+ pgKind: existing?.pgKind,
194
+ stampVersion: existing?.stampVersion,
195
+ url: orchestratorUrl(port),
196
+ adminToken: planeAdminToken() ?? void 0,
197
+ mode: existing?.mode ?? "independent",
198
+ attachment: readAttachment() ?? void 0
199
+ };
200
+ const adminToken = readOrCreateAdminToken();
201
+ const secretKey = readOrCreateSecretKey();
202
+ const scalerConfigFile = writeScalerConfig(port);
203
+ const pg = await startPlanePostgres();
204
+ let orch;
205
+ if (opts.attach) {
206
+ writePlatformToken(opts.attach.platformToken);
207
+ writeAttachment({
208
+ platformWsUrl: opts.attach.platformWsUrl,
209
+ platformApiBase: opts.attach.platformApiBase,
210
+ orgId: opts.attach.orgId,
211
+ keyId: opts.attach.keyId
212
+ });
213
+ orch = await spawnOrchestrator(pg.url, {
214
+ adminToken,
215
+ secretKey,
216
+ scalerConfigFile,
217
+ attach: {
218
+ platformWsUrl: opts.attach.platformWsUrl,
219
+ platformToken: opts.attach.platformToken
220
+ }
221
+ });
222
+ } else {
223
+ const devIdentityKey = readOrCreateDevIdentity();
224
+ orch = await spawnOrchestrator(pg.url, {
225
+ adminToken,
226
+ secretKey,
227
+ scalerConfigFile,
228
+ devIdentityKeyFile: devIdentityKey
229
+ });
230
+ }
231
+ writeStamp({
232
+ orchestratorPid: orch.pid,
233
+ port: orch.port,
234
+ pgKind: pg.kind,
235
+ kiciVersion,
236
+ stampVersion: 3,
237
+ mode: requestedMode
238
+ });
239
+ return {
240
+ running: true,
241
+ pid: orch.pid,
242
+ port: orch.port,
243
+ pgKind: pg.kind,
244
+ stampVersion: 3,
245
+ url: orchestratorUrl(orch.port),
246
+ adminToken,
247
+ mode: requestedMode,
248
+ attachment: readAttachment() ?? void 0
249
+ };
250
+ }
251
+ /**
252
+ * Stop the local dev plane. Teardown is reconstructed from the stamp (the
253
+ * start-time Postgres handle does not survive a separate CLI invocation):
254
+ * SIGTERM the orchestrator, stop Postgres by backend kind, then clear the
255
+ * pidfile + stamp.
256
+ */
257
+ async function planeDown() {
258
+ const stamp = readStamp();
259
+ const { pidfile, stampFile } = planePaths();
260
+ if (stamp) {
261
+ try {
262
+ process.kill(stamp.orchestratorPid, "SIGTERM");
263
+ } catch {}
264
+ await waitForProcessExit(stamp.orchestratorPid);
265
+ await stopPlanePostgres(stamp.pgKind);
266
+ }
267
+ fs.rmSync(pidfile, { force: true });
268
+ fs.rmSync(stampFile, { force: true });
269
+ }
270
+ /**
271
+ * Poll until process `pid` has exited (SIGTERM already sent), escalating to
272
+ * SIGKILL if it outlives the grace period, so the caller can rely on the
273
+ * listening socket being released once this resolves. `process.kill(pid, 0)`
274
+ * throws `ESRCH` once the process is gone.
275
+ */
276
+ async function waitForProcessExit(pid, graceMs = 1e4) {
277
+ const deadline = Date.now() + graceMs;
278
+ let killed = false;
279
+ for (;;) {
280
+ try {
281
+ process.kill(pid, 0);
282
+ } catch {
283
+ return;
284
+ }
285
+ if (!killed && Date.now() > deadline) {
286
+ try {
287
+ process.kill(pid, "SIGKILL");
288
+ } catch {
289
+ return;
290
+ }
291
+ killed = true;
292
+ }
293
+ await new Promise((r) => setTimeout(r, 100));
294
+ }
295
+ }
296
+ /**
297
+ * Attach the local dev plane to the hosted Platform: mint an org-scoped
298
+ * orchestrator key with the logged-in PAT, then (re)boot the plane hybrid
299
+ * against the Platform relay. Registration with the Platform is implicit — the
300
+ * hybrid orchestrator's PlatformClient sends `source.register` on WS auth.
301
+ */
302
+ async function attachPlane(args) {
303
+ const platformWsUrl = derivePlatformWsUrl(args.apiBase);
304
+ const minted = await mintOrchestratorKey({
305
+ apiBase: args.apiBase,
306
+ pat: args.pat,
307
+ orgId: args.orgId,
308
+ name: "local dev plane"
309
+ });
310
+ return planeUp({ attach: {
311
+ platformWsUrl,
312
+ platformToken: minted.key,
313
+ platformApiBase: args.apiBase,
314
+ orgId: args.orgId,
315
+ keyId: minted.keyId
316
+ } });
317
+ }
318
+ /**
319
+ * Detach the local dev plane: best-effort revoke the minted orchestrator key on
320
+ * the Platform, clear the durable attachment + token, then reboot the plane
321
+ * independent (offline). The revoke is non-fatal — a detach must succeed even
322
+ * offline or with an expired PAT.
323
+ */
324
+ async function detachPlane(opts = {}) {
325
+ const attachment = readAttachment();
326
+ if (attachment && opts.pat) await revokeOrchestratorKey({
327
+ apiBase: attachment.platformApiBase,
328
+ pat: opts.pat,
329
+ orgId: attachment.orgId,
330
+ keyId: attachment.keyId
331
+ }).catch(() => false);
332
+ clearAttachment();
333
+ clearPlatformToken();
334
+ await planeDown();
335
+ return planeUp();
336
+ }
337
+ //#endregion
338
+ export { attachPlane, clearAttachment, clearPlatformToken, detachPlane, devIdentityKeyFile, devIdentityPublicJwkFile, planeAdminToken, planeDown, planeLogPath, planeStatus, planeUp, readAttachment, readOrCreateAdminToken, readOrCreateDevIdentity, readOrCreateSecretKey, readPlatformToken, waitForProcessExit, writeAttachment, writePlatformToken };
339
+
340
+ //# sourceMappingURL=plane-manager.js.map
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Seed the local `file://` source the plane dispatches an offline routed run
3
+ * through. Idempotent: a stable `kici-local` source is created once and its
4
+ * `repoBasePath` is re-pointed at the current workdir on every run (the isolated
5
+ * profile materializes a fresh tmp clone each time). The org is the independent
6
+ * orchestrator's `__default__` sentinel — the orchestrator DB has no org table,
7
+ * so seeding an org is just passing this id.
8
+ */
9
+ /** Independent-mode default org sentinel used by the local plane. */
10
+ export declare const LOCAL_ORG_ID = "__default__";
11
+ /** Stable name of the plane's local source (reused + re-pointed across runs). */
12
+ export declare const LOCAL_SOURCE_NAME = "kici-local";
13
+ /** Minimal surface of AdminApiClient plane-seed needs (for test injection). */
14
+ export interface PlaneSeedClient {
15
+ listGenericSources(orgId: string, includeDeleted?: boolean): Promise<{
16
+ sources: Array<{
17
+ id: string;
18
+ name: string;
19
+ provider_type?: string;
20
+ }>;
21
+ }>;
22
+ createGenericSource(data: {
23
+ orgId: string;
24
+ name: string;
25
+ providerType?: string;
26
+ verificationMethod?: string;
27
+ localConfig?: {
28
+ repoBasePath: string;
29
+ cloneUrlBase?: string;
30
+ inPlace?: boolean;
31
+ };
32
+ }): Promise<{
33
+ source: {
34
+ id: string;
35
+ name: string;
36
+ };
37
+ }>;
38
+ updateGenericSource(id: string, data: {
39
+ localConfig?: {
40
+ repoBasePath: string;
41
+ cloneUrlBase?: string;
42
+ inPlace?: boolean;
43
+ } | null;
44
+ }): Promise<{
45
+ source: {
46
+ id: string;
47
+ name: string;
48
+ };
49
+ }>;
50
+ }
51
+ /** Result of seeding: the org + the (created or reused) source. */
52
+ export interface SeededSource {
53
+ orgId: string;
54
+ sourceId: string;
55
+ sourceName: string;
56
+ }
57
+ /**
58
+ * Ensure the plane has a local `file://` source pointed at `repoDir`. Creates
59
+ * the `kici-local` source on first use; on subsequent runs it re-points the
60
+ * existing source at the new workdir (idempotent reuse). Returns the org +
61
+ * source ids the trigger uses.
62
+ */
63
+ export declare function ensureLocalSource(planeUrl: string, adminToken: string, opts: {
64
+ repoDir: string;
65
+ orgId?: string;
66
+ name?: string;
67
+ /**
68
+ * In-place profile: `repoDir` is the operator's real working tree, so the
69
+ * plane skips the source-pack `__build__` job and each job runs the tree
70
+ * directly. Always written (true/false) so a subsequent isolated run resets
71
+ * a previously in-place source.
72
+ */
73
+ inPlace?: boolean;
74
+ client?: PlaneSeedClient;
75
+ }): Promise<SeededSource>;
76
+ //# sourceMappingURL=plane-seed.d.ts.map
@@ -0,0 +1,59 @@
1
+ import "../rolldown-runtime-ClRpJifh.js";
2
+ import { AdminApiClient } from "@kici-dev/orchestrator";
3
+ //#region src/local-plane/plane-seed.ts
4
+ /**
5
+ * Seed the local `file://` source the plane dispatches an offline routed run
6
+ * through. Idempotent: a stable `kici-local` source is created once and its
7
+ * `repoBasePath` is re-pointed at the current workdir on every run (the isolated
8
+ * profile materializes a fresh tmp clone each time). The org is the independent
9
+ * orchestrator's `__default__` sentinel — the orchestrator DB has no org table,
10
+ * so seeding an org is just passing this id.
11
+ */
12
+ /** Independent-mode default org sentinel used by the local plane. */
13
+ const LOCAL_ORG_ID = "__default__";
14
+ /** Stable name of the plane's local source (reused + re-pointed across runs). */
15
+ const LOCAL_SOURCE_NAME = "kici-local";
16
+ /**
17
+ * Ensure the plane has a local `file://` source pointed at `repoDir`. Creates
18
+ * the `kici-local` source on first use; on subsequent runs it re-points the
19
+ * existing source at the new workdir (idempotent reuse). Returns the org +
20
+ * source ids the trigger uses.
21
+ */
22
+ async function ensureLocalSource(planeUrl, adminToken, opts) {
23
+ const orgId = opts.orgId ?? "__default__";
24
+ const name = opts.name ?? "kici-local";
25
+ const inPlace = opts.inPlace === true;
26
+ const client = opts.client ?? new AdminApiClient(planeUrl, adminToken);
27
+ const { sources } = await client.listGenericSources(orgId);
28
+ const existing = sources.find((s) => s.name === name && s.provider_type === "local");
29
+ if (existing) {
30
+ const updated = await client.updateGenericSource(existing.id, { localConfig: {
31
+ repoBasePath: opts.repoDir,
32
+ inPlace
33
+ } });
34
+ return {
35
+ orgId,
36
+ sourceId: updated.source.id,
37
+ sourceName: updated.source.name
38
+ };
39
+ }
40
+ const created = await client.createGenericSource({
41
+ orgId,
42
+ name,
43
+ providerType: "local",
44
+ verificationMethod: "none",
45
+ localConfig: {
46
+ repoBasePath: opts.repoDir,
47
+ inPlace
48
+ }
49
+ });
50
+ return {
51
+ orgId,
52
+ sourceId: created.source.id,
53
+ sourceName: created.source.name
54
+ };
55
+ }
56
+ //#endregion
57
+ export { LOCAL_ORG_ID, LOCAL_SOURCE_NAME, ensureLocalSource };
58
+
59
+ //# sourceMappingURL=plane-seed.js.map
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Trigger an offline routed run against the local plane and discover its runId.
3
+ *
4
+ * A local repo has no forge to send a webhook, so this posts a GitHub-shaped
5
+ * synthetic push to the plane's provider-agnostic generic webhook route (the
6
+ * same wire shape the `kici-admin source trigger-local` path builds). The
7
+ * webhook is unauthenticated (the edge accepts it and returns 202); the run is
8
+ * created asynchronously, so this then polls the admin runs list — authenticated
9
+ * with the plane's bootstrap admin token — to resolve the created runId.
10
+ *
11
+ * The source's bundle hot-reload is debounced, so a first trigger can land
12
+ * before the plane has registered the (re-pointed) local source. This resends
13
+ * the webhook after a grace window until a run appears or the timeout elapses.
14
+ */
15
+ /** A minimal admin-read client (AdminApiClient.get) — injectable for tests. */
16
+ export interface RunDiscoveryClient {
17
+ get<T>(path: string): Promise<T>;
18
+ }
19
+ export interface LocalTriggerInput {
20
+ orgId: string;
21
+ sourceId: string;
22
+ repoFullName: string;
23
+ event: 'push' | 'pull_request' | 'dispatch';
24
+ ref: string;
25
+ sha: string;
26
+ defaultBranch: string;
27
+ /**
28
+ * Dispatch event action (`dispatch()` `types` matcher key). Only used when
29
+ * `event === 'dispatch'`; the local normalizer reads it from `payload.action`,
30
+ * so exactly one `types`-filtered workflow matches.
31
+ */
32
+ action?: string;
33
+ /** Dispatch `client_payload` (steps read `ctx.rawPayload.client_payload`). */
34
+ clientPayload?: unknown;
35
+ }
36
+ export interface LocalTriggerRequest {
37
+ path: string;
38
+ headers: Record<string, string>;
39
+ body: string;
40
+ }
41
+ /**
42
+ * Build the GitHub-shaped webhook request the plane's local provider normalizer
43
+ * expects. Mirrors `buildLocalTriggerRequest` in the orchestrator's
44
+ * `cli/commands/local-trigger.ts` (kept local to honour the compiler-only scope
45
+ * of this phase — no orchestrator export is added).
46
+ */
47
+ export declare function buildLocalTriggerRequest(input: LocalTriggerInput): LocalTriggerRequest;
48
+ /** POST the trigger request to the plane. Returns the HTTP status. */
49
+ export declare function sendLocalTrigger(planeUrl: string, req: LocalTriggerRequest): Promise<number>;
50
+ export interface TriggerRunOptions {
51
+ client?: RunDiscoveryClient;
52
+ pollIntervalMs?: number;
53
+ resendAfterMs?: number;
54
+ timeoutMs?: number;
55
+ }
56
+ /**
57
+ * Trigger the run and resolve its runId. Sends the synthetic push, then polls
58
+ * the admin runs list (`created_at > since`) for the newest run, resending the
59
+ * webhook past a grace window to absorb source hot-reload latency.
60
+ */
61
+ export declare function triggerRun(planeUrl: string, adminToken: string, input: LocalTriggerInput, opts?: TriggerRunOptions): Promise<string>;
62
+ //# sourceMappingURL=plane-trigger.d.ts.map