@kici-dev/orchestrator 0.1.13 → 0.1.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -1517,8 +1517,8 @@ var init_client = __esmMin((() => {
1517
1517
  //#region src/db/migrations/001_initial.ts
1518
1518
  init_client();
1519
1519
  var _001_initial_exports = /* @__PURE__ */ __exportAll({
1520
- down: () => down$23,
1521
- up: () => up$23
1520
+ down: () => down$24,
1521
+ up: () => up$24
1522
1522
  });
1523
1523
  /**
1524
1524
  * Squashed initial migration -- creates the complete Orchestrator database schema.
@@ -2210,7 +2210,7 @@ const DDL_STATEMENTS = [
2210
2210
  `ALTER TABLE ONLY public.held_runs
2211
2211
  ADD CONSTRAINT held_runs_environment_id_fkey FOREIGN KEY (environment_id) REFERENCES public.environments(id);`
2212
2212
  ];
2213
- async function up$23(db) {
2213
+ async function up$24(db) {
2214
2214
  for (const stmt of DDL_STATEMENTS) await sql.raw(stmt).execute(db);
2215
2215
  await sql`
2216
2216
  INSERT INTO cluster_meta (key, value)
@@ -2232,7 +2232,7 @@ async function up$23(db) {
2232
2232
  * Rollback drops everything created above. Uses CASCADE on table drops to cut
2233
2233
  * through the FK graph without relying on exact topological order.
2234
2234
  */
2235
- async function down$23(db) {
2235
+ async function down$24(db) {
2236
2236
  for (const [trig, tbl] of [["source_secrets_change_trigger", "scoped_secrets"], ["sources_change_trigger", "sources"]]) await sql.raw(`DROP TRIGGER IF EXISTS ${trig} ON public.${tbl}`).execute(db);
2237
2237
  for (const table of [
2238
2238
  "workflow_registrations",
@@ -2279,8 +2279,8 @@ async function down$23(db) {
2279
2279
  //#endregion
2280
2280
  //#region src/db/migrations/002_config_versions_key_version.ts
2281
2281
  var _002_config_versions_key_version_exports = /* @__PURE__ */ __exportAll({
2282
- down: () => down$22,
2283
- up: () => up$22
2282
+ down: () => down$23,
2283
+ up: () => up$23
2284
2284
  });
2285
2285
  /**
2286
2286
  * Add key_version column to config_versions so that sensitive-field encryption
@@ -2294,13 +2294,13 @@ var _002_config_versions_key_version_exports = /* @__PURE__ */ __exportAll({
2294
2294
  * No index is needed: rotation does a full-table scan; reads are by
2295
2295
  * `version` primary key and never filter on `key_version`.
2296
2296
  */
2297
- async function up$22(db) {
2297
+ async function up$23(db) {
2298
2298
  await sql`
2299
2299
  ALTER TABLE public.config_versions
2300
2300
  ADD COLUMN key_version integer NOT NULL DEFAULT 1
2301
2301
  `.execute(db);
2302
2302
  }
2303
- async function down$22(db) {
2303
+ async function down$23(db) {
2304
2304
  await sql`
2305
2305
  ALTER TABLE public.config_versions
2306
2306
  DROP COLUMN key_version
@@ -2309,8 +2309,8 @@ async function down$22(db) {
2309
2309
  //#endregion
2310
2310
  //#region src/db/migrations/003_access_log.ts
2311
2311
  var _003_access_log_exports = /* @__PURE__ */ __exportAll({
2312
- down: () => down$21,
2313
- up: () => up$21
2312
+ down: () => down$22,
2313
+ up: () => up$22
2314
2314
  });
2315
2315
  /**
2316
2316
  * Access log: one row per read or orchestrator-admin mutation attributable
@@ -2334,7 +2334,7 @@ var _003_access_log_exports = /* @__PURE__ */ __exportAll({
2334
2334
  * Retention is TTL-based via expires_at; packages/orchestrator/src/queue/
2335
2335
  * cleanup.ts picks up the prune pass.
2336
2336
  */
2337
- async function up$21(db) {
2337
+ async function up$22(db) {
2338
2338
  await sql`
2339
2339
  CREATE TABLE public.access_log (
2340
2340
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
@@ -2372,28 +2372,28 @@ async function up$21(db) {
2372
2372
  ON public.access_log (actor_type, actor_id, created_at DESC)
2373
2373
  `.execute(db);
2374
2374
  }
2375
- async function down$21(db) {
2375
+ async function down$22(db) {
2376
2376
  await sql`DROP TABLE IF EXISTS public.access_log`.execute(db);
2377
2377
  }
2378
2378
  //#endregion
2379
2379
  //#region src/db/migrations/004_rename_bundle_to_source.ts
2380
2380
  var _004_rename_bundle_to_source_exports = /* @__PURE__ */ __exportAll({
2381
- down: () => down$20,
2382
- up: () => up$20
2381
+ down: () => down$21,
2382
+ up: () => up$21
2383
2383
  });
2384
- async function up$20(db) {
2384
+ async function up$21(db) {
2385
2385
  await db.schema.alterTable("dispatch_queue").renameColumn("bundle_url", "source_tar_url").execute();
2386
2386
  await db.schema.alterTable("dispatch_queue").renameColumn("bundle_hash", "source_tar_hash").execute();
2387
2387
  }
2388
- async function down$20(db) {
2388
+ async function down$21(db) {
2389
2389
  await db.schema.alterTable("dispatch_queue").renameColumn("source_tar_url", "bundle_url").execute();
2390
2390
  await db.schema.alterTable("dispatch_queue").renameColumn("source_tar_hash", "bundle_hash").execute();
2391
2391
  }
2392
2392
  //#endregion
2393
2393
  //#region src/db/migrations/005_cold_store_chunk_counter.ts
2394
2394
  var _005_cold_store_chunk_counter_exports = /* @__PURE__ */ __exportAll({
2395
- down: () => down$19,
2396
- up: () => up$19
2395
+ down: () => down$20,
2396
+ up: () => up$20
2397
2397
  });
2398
2398
  /**
2399
2399
  * Cold-store chunk counter table.
@@ -2410,7 +2410,7 @@ var _005_cold_store_chunk_counter_exports = /* @__PURE__ */ __exportAll({
2410
2410
  *
2411
2411
  * sections 5 and 8.
2412
2412
  */
2413
- async function up$19(db) {
2413
+ async function up$20(db) {
2414
2414
  await sql`
2415
2415
  CREATE TABLE public.cold_store_chunk_counts (
2416
2416
  db TEXT NOT NULL,
@@ -2428,14 +2428,14 @@ async function up$19(db) {
2428
2428
  ON public.cold_store_chunk_counts (db, table_name)
2429
2429
  `.execute(db);
2430
2430
  }
2431
- async function down$19(db) {
2431
+ async function down$20(db) {
2432
2432
  await sql`DROP TABLE IF EXISTS public.cold_store_chunk_counts`.execute(db);
2433
2433
  }
2434
2434
  //#endregion
2435
2435
  //#region src/db/migrations/006_runs_jobs_steps_archived_at.ts
2436
2436
  var _006_runs_jobs_steps_archived_at_exports = /* @__PURE__ */ __exportAll({
2437
- down: () => down$18,
2438
- up: () => up$18
2437
+ down: () => down$19,
2438
+ up: () => up$19
2439
2439
  });
2440
2440
  /**
2441
2441
  * `execution_runs` / `execution_jobs` / `execution_steps` cold-store
@@ -2471,7 +2471,7 @@ var _006_runs_jobs_steps_archived_at_exports = /* @__PURE__ */ __exportAll({
2471
2471
  * - `idx_execution_jobs_routing_key_created (routing_key, created_at)`
2472
2472
  * - `idx_execution_steps_routing_key_created (routing_key, created_at)`
2473
2473
  */
2474
- async function up$18(db) {
2474
+ async function up$19(db) {
2475
2475
  await sql`
2476
2476
  ALTER TABLE public.execution_runs
2477
2477
  ADD COLUMN archived_at TIMESTAMPTZ NULL,
@@ -2516,7 +2516,7 @@ async function up$18(db) {
2516
2516
  ON public.execution_steps (routing_key, created_at)
2517
2517
  `.execute(db);
2518
2518
  }
2519
- async function down$18(db) {
2519
+ async function down$19(db) {
2520
2520
  await sql`DROP INDEX IF EXISTS public.idx_execution_steps_routing_key_created`.execute(db);
2521
2521
  await sql`
2522
2522
  ALTER TABLE public.execution_steps
@@ -2541,8 +2541,8 @@ async function down$18(db) {
2541
2541
  //#endregion
2542
2542
  //#region src/db/migrations/007_audit_logs_archived_at.ts
2543
2543
  var _007_audit_logs_archived_at_exports = /* @__PURE__ */ __exportAll({
2544
- down: () => down$17,
2545
- up: () => up$17
2544
+ down: () => down$18,
2545
+ up: () => up$18
2546
2546
  });
2547
2547
  /**
2548
2548
  * `secret_audit_log` and `access_log` cold-store schema additions, plus
@@ -2582,7 +2582,7 @@ var _007_audit_logs_archived_at_exports = /* @__PURE__ */ __exportAll({
2582
2582
  * `down()` would not have meaningful retention bounds. Acceptable for
2583
2583
  * staging.
2584
2584
  */
2585
- async function up$17(db) {
2585
+ async function up$18(db) {
2586
2586
  await sql`
2587
2587
  ALTER TABLE public.secret_audit_log
2588
2588
  ADD COLUMN archived_at TIMESTAMPTZ NULL,
@@ -2603,7 +2603,7 @@ async function up$17(db) {
2603
2603
  DROP COLUMN IF EXISTS expires_at
2604
2604
  `.execute(db);
2605
2605
  }
2606
- async function down$17(db) {
2606
+ async function down$18(db) {
2607
2607
  await sql`
2608
2608
  ALTER TABLE public.access_log
2609
2609
  ADD COLUMN expires_at TIMESTAMPTZ NOT NULL DEFAULT (now() + INTERVAL '90 days')
@@ -2631,8 +2631,8 @@ async function down$17(db) {
2631
2631
  //#endregion
2632
2632
  //#region src/db/migrations/008_event_log_archived_at.ts
2633
2633
  var _008_event_log_archived_at_exports = /* @__PURE__ */ __exportAll({
2634
- down: () => down$16,
2635
- up: () => up$16
2634
+ down: () => down$17,
2635
+ up: () => up$17
2636
2636
  });
2637
2637
  /**
2638
2638
  * `event_log` cold-store schema additions plus removal of the
@@ -2670,7 +2670,7 @@ var _008_event_log_archived_at_exports = /* @__PURE__ */ __exportAll({
2670
2670
  * — best effort; rows inserted between `up()` and a hypothetical
2671
2671
  * `down()` would not have meaningful retention bounds.
2672
2672
  */
2673
- async function up$16(db) {
2673
+ async function up$17(db) {
2674
2674
  await sql`
2675
2675
  ALTER TABLE public.event_log
2676
2676
  ADD COLUMN archived_at TIMESTAMPTZ NULL,
@@ -2686,7 +2686,7 @@ async function up$16(db) {
2686
2686
  DROP COLUMN IF EXISTS expires_at
2687
2687
  `.execute(db);
2688
2688
  }
2689
- async function down$16(db) {
2689
+ async function down$17(db) {
2690
2690
  await sql`
2691
2691
  ALTER TABLE public.event_log
2692
2692
  ADD COLUMN expires_at TIMESTAMPTZ NOT NULL DEFAULT (now() + INTERVAL '30 days')
@@ -2705,8 +2705,8 @@ async function down$16(db) {
2705
2705
  //#endregion
2706
2706
  //#region src/db/migrations/009_access_log_trigram.ts
2707
2707
  var _009_access_log_trigram_exports = /* @__PURE__ */ __exportAll({
2708
- down: () => down$15,
2709
- up: () => up$15
2708
+ down: () => down$16,
2709
+ up: () => up$16
2710
2710
  });
2711
2711
  /**
2712
2712
  * Trigram (pg_trgm) index on access_log.error_message for the federated
@@ -2719,7 +2719,7 @@ var _009_access_log_trigram_exports = /* @__PURE__ */ __exportAll({
2719
2719
  * EXISTS` are both safe to re-run. No CONCURRENTLY because Kysely runs
2720
2720
  * migrations inside a transaction; the lock is brief on a sampled table.
2721
2721
  */
2722
- async function up$15(db) {
2722
+ async function up$16(db) {
2723
2723
  await sql`CREATE EXTENSION IF NOT EXISTS pg_trgm`.execute(db);
2724
2724
  await sql`
2725
2725
  CREATE INDEX IF NOT EXISTS access_log_error_message_trgm_idx
@@ -2728,14 +2728,14 @@ async function up$15(db) {
2728
2728
  WHERE error_message IS NOT NULL
2729
2729
  `.execute(db);
2730
2730
  }
2731
- async function down$15(db) {
2731
+ async function down$16(db) {
2732
2732
  await sql`DROP INDEX IF EXISTS public.access_log_error_message_trgm_idx`.execute(db);
2733
2733
  }
2734
2734
  //#endregion
2735
2735
  //#region src/db/migrations/010_cold_store_chunks.ts
2736
2736
  var _010_cold_store_chunks_exports = /* @__PURE__ */ __exportAll({
2737
- down: () => down$14,
2738
- up: () => up$14
2737
+ down: () => down$15,
2738
+ up: () => up$15
2739
2739
  });
2740
2740
  /**
2741
2741
  * Cold-store chunk index — Phase 2 (cold-store purge).
@@ -2767,7 +2767,7 @@ var _010_cold_store_chunks_exports = /* @__PURE__ */ __exportAll({
2767
2767
  * forever. Adapters that don't opt into per-bucket archival via
2768
2768
  * `coldTtlDays` don't insert here either.
2769
2769
  */
2770
- async function up$14(db) {
2770
+ async function up$15(db) {
2771
2771
  await sql`
2772
2772
  CREATE TABLE public.cold_store_chunks (
2773
2773
  db TEXT NOT NULL,
@@ -2794,14 +2794,14 @@ async function up$14(db) {
2794
2794
  ON public.cold_store_chunks (db, table_name, tenant_id, archived_at DESC)
2795
2795
  `.execute(db);
2796
2796
  }
2797
- async function down$14(db) {
2797
+ async function down$15(db) {
2798
2798
  await sql`DROP TABLE IF EXISTS public.cold_store_chunks`.execute(db);
2799
2799
  }
2800
2800
  //#endregion
2801
2801
  //#region src/db/migrations/011_drop_source_secrets_notify.ts
2802
2802
  var _011_drop_source_secrets_notify_exports = /* @__PURE__ */ __exportAll({
2803
- down: () => down$13,
2804
- up: () => up$13
2803
+ down: () => down$14,
2804
+ up: () => up$14
2805
2805
  });
2806
2806
  /**
2807
2807
  * Drop the `source_secrets_change_trigger` and the
@@ -2820,11 +2820,11 @@ var _011_drop_source_secrets_notify_exports = /* @__PURE__ */ __exportAll({
2820
2820
  * in `001_initial.ts`. They wake up no consumer until the `WebhookSecretManager`
2821
2821
  * is restored, so this migration is safe to roll back.
2822
2822
  */
2823
- async function up$13(db) {
2823
+ async function up$14(db) {
2824
2824
  await sql`DROP TRIGGER IF EXISTS source_secrets_change_trigger ON public.scoped_secrets`.execute(db);
2825
2825
  await sql`DROP FUNCTION IF EXISTS public.notify_source_secrets_change() CASCADE`.execute(db);
2826
2826
  }
2827
- async function down$13(db) {
2827
+ async function down$14(db) {
2828
2828
  await sql`
2829
2829
  CREATE OR REPLACE FUNCTION public.notify_source_secrets_change() RETURNS trigger
2830
2830
  LANGUAGE plpgsql
@@ -2863,8 +2863,8 @@ async function down$13(db) {
2863
2863
  //#endregion
2864
2864
  //#region src/db/migrations/012_peer_credentials_active_uniq.ts
2865
2865
  var _012_peer_credentials_active_uniq_exports = /* @__PURE__ */ __exportAll({
2866
- down: () => down$12,
2867
- up: () => up$12
2866
+ down: () => down$13,
2867
+ up: () => up$13
2868
2868
  });
2869
2869
  /**
2870
2870
  * Add a partial unique index on `peer_credentials (instance_id) WHERE
@@ -2890,7 +2890,7 @@ var _012_peer_credentials_active_uniq_exports = /* @__PURE__ */ __exportAll({
2890
2890
  * `down()` only drops the index; it does NOT undo the dedupe (there's no
2891
2891
  * safe way to recreate revoked rows, and the dedupe is monotonic).
2892
2892
  */
2893
- async function up$12(db) {
2893
+ async function up$13(db) {
2894
2894
  await sql`
2895
2895
  UPDATE public.peer_credentials
2896
2896
  SET revoked_at = NOW()
@@ -2908,14 +2908,14 @@ async function up$12(db) {
2908
2908
  WHERE revoked_at IS NULL
2909
2909
  `.execute(db);
2910
2910
  }
2911
- async function down$12(db) {
2911
+ async function down$13(db) {
2912
2912
  await sql`DROP INDEX IF EXISTS public.peer_credentials_active_uniq`.execute(db);
2913
2913
  }
2914
2914
  //#endregion
2915
2915
  //#region src/db/migrations/013_execution_log_bytes.ts
2916
2916
  var _013_execution_log_bytes_exports = /* @__PURE__ */ __exportAll({
2917
- down: () => down$11,
2918
- up: () => up$11
2917
+ down: () => down$12,
2918
+ up: () => up$12
2919
2919
  });
2920
2920
  /**
2921
2921
  * Add `log_bytes BIGINT NOT NULL DEFAULT 0` columns to `execution_runs` and
@@ -2934,7 +2934,7 @@ var _013_execution_log_bytes_exports = /* @__PURE__ */ __exportAll({
2934
2934
  *
2935
2935
  * Idempotent (`ADD COLUMN IF NOT EXISTS`).
2936
2936
  */
2937
- async function up$11(db) {
2937
+ async function up$12(db) {
2938
2938
  await sql`
2939
2939
  ALTER TABLE public.execution_runs
2940
2940
  ADD COLUMN IF NOT EXISTS log_bytes BIGINT NOT NULL DEFAULT 0
@@ -2944,15 +2944,15 @@ async function up$11(db) {
2944
2944
  ADD COLUMN IF NOT EXISTS log_bytes BIGINT NOT NULL DEFAULT 0
2945
2945
  `.execute(db);
2946
2946
  }
2947
- async function down$11(db) {
2947
+ async function down$12(db) {
2948
2948
  await sql`ALTER TABLE public.execution_runs DROP COLUMN IF EXISTS log_bytes`.execute(db);
2949
2949
  await sql`ALTER TABLE public.execution_jobs DROP COLUMN IF EXISTS log_bytes`.execute(db);
2950
2950
  }
2951
2951
  //#endregion
2952
2952
  //#region src/db/migrations/014_kici_events_lease_retry.ts
2953
2953
  var _014_kici_events_lease_retry_exports = /* @__PURE__ */ __exportAll({
2954
- down: () => down$10,
2955
- up: () => up$10
2954
+ down: () => down$11,
2955
+ up: () => up$11
2956
2956
  });
2957
2957
  /**
2958
2958
  * Add lease + retry + DLQ columns to `kici_events` so the EventRouter can
@@ -2986,7 +2986,7 @@ var _014_kici_events_lease_retry_exports = /* @__PURE__ */ __exportAll({
2986
2986
  *
2987
2987
  * Idempotent (`ADD COLUMN IF NOT EXISTS` + `CREATE INDEX IF NOT EXISTS`).
2988
2988
  */
2989
- async function up$10(db) {
2989
+ async function up$11(db) {
2990
2990
  await sql`
2991
2991
  ALTER TABLE public.kici_events
2992
2992
  ADD COLUMN IF NOT EXISTS claimed_at TIMESTAMPTZ,
@@ -3017,7 +3017,7 @@ async function up$10(db) {
3017
3017
  WHERE dlq_at IS NOT NULL
3018
3018
  `.execute(db);
3019
3019
  }
3020
- async function down$10(db) {
3020
+ async function down$11(db) {
3021
3021
  await sql`DROP INDEX IF EXISTS public.idx_kici_events_dlq`.execute(db);
3022
3022
  await sql`DROP INDEX IF EXISTS public.idx_kici_events_lease_expired`.execute(db);
3023
3023
  await sql`DROP INDEX IF EXISTS public.idx_kici_events_retry_due`.execute(db);
@@ -3035,8 +3035,8 @@ async function down$10(db) {
3035
3035
  //#endregion
3036
3036
  //#region src/db/migrations/015_org_settings_customer_scoped.ts
3037
3037
  var _015_org_settings_customer_scoped_exports = /* @__PURE__ */ __exportAll({
3038
- down: () => down$9,
3039
- up: () => up$9
3038
+ down: () => down$10,
3039
+ up: () => up$10
3040
3040
  });
3041
3041
  /**
3042
3042
  * Org-scope `org_settings` and qualify each glob entry by source.
@@ -3064,7 +3064,7 @@ var _015_org_settings_customer_scoped_exports = /* @__PURE__ */ __exportAll({
3064
3064
  * Idempotent: a re-run on an already-migrated DB sees `customer_id` exists
3065
3065
  * and the list columns are already jsonb, so it is a no-op.
3066
3066
  */
3067
- async function up$9(db) {
3067
+ async function up$10(db) {
3068
3068
  if ((await sql`
3069
3069
  SELECT EXISTS (
3070
3070
  SELECT 1 FROM information_schema.columns
@@ -3189,7 +3189,7 @@ async function up$9(db) {
3189
3189
  await sql`DROP TABLE _org_settings_merged`.execute(db);
3190
3190
  await sql`DROP TABLE _org_settings_stage`.execute(db);
3191
3191
  }
3192
- async function down$9(db) {
3192
+ async function down$10(db) {
3193
3193
  if (!(await sql`
3194
3194
  SELECT EXISTS (
3195
3195
  SELECT 1 FROM information_schema.columns
@@ -3214,8 +3214,8 @@ async function down$9(db) {
3214
3214
  //#endregion
3215
3215
  //#region src/db/migrations/016_org_settings_allow_http_npm.ts
3216
3216
  var _016_org_settings_allow_http_npm_exports = /* @__PURE__ */ __exportAll({
3217
- down: () => down$8,
3218
- up: () => up$8
3217
+ down: () => down$9,
3218
+ up: () => up$9
3219
3219
  });
3220
3220
  /**
3221
3221
  * Add `org_settings.allow_http_npm_registries boolean NOT NULL DEFAULT false`.
@@ -3228,7 +3228,7 @@ var _016_org_settings_allow_http_npm_exports = /* @__PURE__ */ __exportAll({
3228
3228
  *
3229
3229
  * Idempotent: a re-run on a DB that already has the column is a no-op.
3230
3230
  */
3231
- async function up$8(db) {
3231
+ async function up$9(db) {
3232
3232
  if ((await sql`
3233
3233
  SELECT EXISTS (
3234
3234
  SELECT 1 FROM information_schema.columns
@@ -3242,7 +3242,7 @@ async function up$8(db) {
3242
3242
  ADD COLUMN allow_http_npm_registries boolean NOT NULL DEFAULT false
3243
3243
  `.execute(db);
3244
3244
  }
3245
- async function down$8(db) {
3245
+ async function down$9(db) {
3246
3246
  await sql`
3247
3247
  ALTER TABLE public.org_settings DROP COLUMN IF EXISTS allow_http_npm_registries
3248
3248
  `.execute(db);
@@ -3250,8 +3250,8 @@ async function down$8(db) {
3250
3250
  //#endregion
3251
3251
  //#region src/db/migrations/017_org_id_widen.ts
3252
3252
  var _017_org_id_widen_exports = /* @__PURE__ */ __exportAll({
3253
- down: () => down$7,
3254
- up: () => up$7
3253
+ down: () => down$8,
3254
+ up: () => up$8
3255
3255
  });
3256
3256
  /**
3257
3257
  * Widen every orchestrator-side `org_id varchar(12)` column to
@@ -3291,17 +3291,17 @@ const ORG_ID_TABLES$1 = [
3291
3291
  "held_runs",
3292
3292
  "scoped_secrets"
3293
3293
  ];
3294
- async function up$7(db) {
3294
+ async function up$8(db) {
3295
3295
  for (const table of ORG_ID_TABLES$1) await sql.raw(`ALTER TABLE public.${table} ALTER COLUMN org_id TYPE varchar(16)`).execute(db);
3296
3296
  }
3297
- async function down$7(db) {
3297
+ async function down$8(db) {
3298
3298
  for (const table of ORG_ID_TABLES$1) await sql.raw(`ALTER TABLE public.${table} ALTER COLUMN org_id TYPE varchar(12)`).execute(db);
3299
3299
  }
3300
3300
  //#endregion
3301
3301
  //#region src/db/migrations/018_org_id_prefix_backfill.ts
3302
3302
  var _018_org_id_prefix_backfill_exports = /* @__PURE__ */ __exportAll({
3303
- down: () => down$6,
3304
- up: () => up$6
3303
+ down: () => down$7,
3304
+ up: () => up$7
3305
3305
  });
3306
3306
  /**
3307
3307
  * Prefix every orchestrator-side tenant string with `org_` to align
@@ -3346,19 +3346,19 @@ const CUSTOMER_ID_TABLES = [
3346
3346
  "workflow_registrations",
3347
3347
  "org_settings"
3348
3348
  ];
3349
- async function up$6(db) {
3349
+ async function up$7(db) {
3350
3350
  for (const table of ORG_ID_TABLES) await sql.raw(`UPDATE public.${table} SET org_id = 'org_' || org_id WHERE org_id <> 'kici-admin' AND org_id NOT LIKE 'org\\_%' ESCAPE '\\'`).execute(db);
3351
3351
  for (const table of CUSTOMER_ID_TABLES) await sql.raw(`UPDATE public.${table} SET customer_id = 'org_' || customer_id WHERE customer_id <> 'kici-admin' AND customer_id NOT LIKE 'org\\_%' ESCAPE '\\'`).execute(db);
3352
3352
  }
3353
- async function down$6(db) {
3353
+ async function down$7(db) {
3354
3354
  for (const table of CUSTOMER_ID_TABLES) await sql.raw(`UPDATE public.${table} SET customer_id = substring(customer_id from 5) WHERE customer_id LIKE 'org\\_%' ESCAPE '\\'`).execute(db);
3355
3355
  for (const table of ORG_ID_TABLES) await sql.raw(`UPDATE public.${table} SET org_id = substring(org_id from 5) WHERE org_id LIKE 'org\\_%' ESCAPE '\\'`).execute(db);
3356
3356
  }
3357
3357
  //#endregion
3358
3358
  //#region src/db/migrations/019_generic_sources_change_notify.ts
3359
3359
  var _019_generic_sources_change_notify_exports = /* @__PURE__ */ __exportAll({
3360
- down: () => down$5,
3361
- up: () => up$5
3360
+ down: () => down$6,
3361
+ up: () => up$6
3362
3362
  });
3363
3363
  /**
3364
3364
  * Add a Postgres trigger on `generic_webhook_sources` that emits
@@ -3381,7 +3381,7 @@ var _019_generic_sources_change_notify_exports = /* @__PURE__ */ __exportAll({
3381
3381
  * (`notify_sources_change()` + `sources_change_trigger`, defined in
3382
3382
  * `001_initial.ts`).
3383
3383
  */
3384
- async function up$5(db) {
3384
+ async function up$6(db) {
3385
3385
  await sql`
3386
3386
  CREATE FUNCTION public.notify_generic_sources_change() RETURNS trigger
3387
3387
  LANGUAGE plpgsql
@@ -3402,15 +3402,15 @@ async function up$5(db) {
3402
3402
  FOR EACH ROW EXECUTE FUNCTION public.notify_generic_sources_change()
3403
3403
  `.execute(db);
3404
3404
  }
3405
- async function down$5(db) {
3405
+ async function down$6(db) {
3406
3406
  await sql`DROP TRIGGER IF EXISTS generic_sources_change_trigger ON public.generic_webhook_sources`.execute(db);
3407
3407
  await sql`DROP FUNCTION IF EXISTS public.notify_generic_sources_change()`.execute(db);
3408
3408
  }
3409
3409
  //#endregion
3410
3410
  //#region src/db/migrations/020_org_settings_dashboard_write_policy.ts
3411
3411
  var _020_org_settings_dashboard_write_policy_exports = /* @__PURE__ */ __exportAll({
3412
- down: () => down$4,
3413
- up: () => up$4
3412
+ down: () => down$5,
3413
+ up: () => up$5
3414
3414
  });
3415
3415
  /**
3416
3416
  * Add `org_settings.dashboard_write_policy jsonb NOT NULL DEFAULT '{}'`.
@@ -3425,7 +3425,7 @@ var _020_org_settings_dashboard_write_policy_exports = /* @__PURE__ */ __exportA
3425
3425
  *
3426
3426
  * Idempotent: a re-run on a DB that already has the column is a no-op.
3427
3427
  */
3428
- async function up$4(db) {
3428
+ async function up$5(db) {
3429
3429
  if ((await sql`
3430
3430
  SELECT EXISTS (
3431
3431
  SELECT 1 FROM information_schema.columns
@@ -3439,7 +3439,7 @@ async function up$4(db) {
3439
3439
  ADD COLUMN dashboard_write_policy jsonb NOT NULL DEFAULT '{}'::jsonb
3440
3440
  `.execute(db);
3441
3441
  }
3442
- async function down$4(db) {
3442
+ async function down$5(db) {
3443
3443
  await sql`
3444
3444
  ALTER TABLE public.org_settings DROP COLUMN IF EXISTS dashboard_write_policy
3445
3445
  `.execute(db);
@@ -3447,8 +3447,8 @@ async function down$4(db) {
3447
3447
  //#endregion
3448
3448
  //#region src/db/migrations/021_check_run_tracking.ts
3449
3449
  var _021_check_run_tracking_exports = /* @__PURE__ */ __exportAll({
3450
- down: () => down$3,
3451
- up: () => up$3
3450
+ down: () => down$4,
3451
+ up: () => up$4
3452
3452
  });
3453
3453
  /**
3454
3454
  * Add `check_run_tracking` table for HA-safe check-run state persistence.
@@ -3472,7 +3472,7 @@ var _021_check_run_tracking_exports = /* @__PURE__ */ __exportAll({
3472
3472
  *
3473
3473
  * Idempotent: a re-run on a DB that already has the table is a no-op.
3474
3474
  */
3475
- async function up$3(db) {
3475
+ async function up$4(db) {
3476
3476
  if ((await sql`
3477
3477
  SELECT EXISTS (
3478
3478
  SELECT 1 FROM information_schema.tables
@@ -3503,14 +3503,14 @@ async function up$3(db) {
3503
3503
  WHERE run_id IS NOT NULL
3504
3504
  `.execute(db);
3505
3505
  }
3506
- async function down$3(db) {
3506
+ async function down$4(db) {
3507
3507
  await sql`DROP TABLE IF EXISTS public.check_run_tracking`.execute(db);
3508
3508
  }
3509
3509
  //#endregion
3510
3510
  //#region src/db/migrations/022_scaler_manager_state.ts
3511
3511
  var _022_scaler_manager_state_exports = /* @__PURE__ */ __exportAll({
3512
- down: () => down$2,
3513
- up: () => up$2
3512
+ down: () => down$3,
3513
+ up: () => up$3
3514
3514
  });
3515
3515
  /**
3516
3516
  * Add three tables persisting `ScalerManager` per-coord state:
@@ -3537,7 +3537,7 @@ var _022_scaler_manager_state_exports = /* @__PURE__ */ __exportAll({
3537
3537
  * Idempotent: a re-run on a DB that already has any of these tables
3538
3538
  * leaves the existing one alone.
3539
3539
  */
3540
- async function up$2(db) {
3540
+ async function up$3(db) {
3541
3541
  const tableExists = async (name) => {
3542
3542
  return (await sql`
3543
3543
  SELECT EXISTS (
@@ -3587,7 +3587,7 @@ async function up$2(db) {
3587
3587
  `.execute(db);
3588
3588
  }
3589
3589
  }
3590
- async function down$2(db) {
3590
+ async function down$3(db) {
3591
3591
  await sql`DROP TABLE IF EXISTS public.scaler_reservations`.execute(db);
3592
3592
  await sql`DROP TABLE IF EXISTS public.scaler_agent_jobs`.execute(db);
3593
3593
  await sql`DROP TABLE IF EXISTS public.scaler_spawning_agents`.execute(db);
@@ -3595,8 +3595,8 @@ async function down$2(db) {
3595
3595
  //#endregion
3596
3596
  //#region src/db/migrations/023_dispatch_queue_recovery_deadline.ts
3597
3597
  var _023_dispatch_queue_recovery_deadline_exports = /* @__PURE__ */ __exportAll({
3598
- down: () => down$1,
3599
- up: () => up$1
3598
+ down: () => down$2,
3599
+ up: () => up$2
3600
3600
  });
3601
3601
  /**
3602
3602
  * Add `dispatch_queue.recovery_deadline TIMESTAMPTZ` and
@@ -3620,7 +3620,7 @@ var _023_dispatch_queue_recovery_deadline_exports = /* @__PURE__ */ __exportAll(
3620
3620
  * Idempotent: re-running on a DB that already has either column is a
3621
3621
  * no-op.
3622
3622
  */
3623
- async function up$1(db) {
3623
+ async function up$2(db) {
3624
3624
  const colExists = async (name) => {
3625
3625
  return (await sql`
3626
3626
  SELECT EXISTS (
@@ -3645,7 +3645,7 @@ async function up$1(db) {
3645
3645
  WHERE recovery_deadline IS NOT NULL
3646
3646
  `.execute(db);
3647
3647
  }
3648
- async function down$1(db) {
3648
+ async function down$2(db) {
3649
3649
  await sql`DROP INDEX IF EXISTS public.idx_dispatch_queue_recovery_deadline`.execute(db);
3650
3650
  await sql`
3651
3651
  ALTER TABLE public.dispatch_queue DROP COLUMN IF EXISTS recovery_agent_id
@@ -3657,8 +3657,8 @@ async function down$1(db) {
3657
3657
  //#endregion
3658
3658
  //#region src/db/migrations/024_dispatch_queue_provisioning_error.ts
3659
3659
  var _024_dispatch_queue_provisioning_error_exports = /* @__PURE__ */ __exportAll({
3660
- down: () => down,
3661
- up: () => up
3660
+ down: () => down$1,
3661
+ up: () => up$1
3662
3662
  });
3663
3663
  /**
3664
3664
  * Add `dispatch_queue.last_provisioning_error TEXT` recording the most
@@ -3674,7 +3674,7 @@ var _024_dispatch_queue_provisioning_error_exports = /* @__PURE__ */ __exportAll
3674
3674
  *
3675
3675
  * Idempotent: re-running on a DB that already has the column is a no-op.
3676
3676
  */
3677
- async function up(db) {
3677
+ async function up$1(db) {
3678
3678
  const colExists = async (name) => {
3679
3679
  return (await sql`
3680
3680
  SELECT EXISTS (
@@ -3690,12 +3690,58 @@ async function up(db) {
3690
3690
  ADD COLUMN last_provisioning_error TEXT
3691
3691
  `.execute(db);
3692
3692
  }
3693
- async function down(db) {
3693
+ async function down$1(db) {
3694
3694
  await sql`
3695
3695
  ALTER TABLE public.dispatch_queue DROP COLUMN IF EXISTS last_provisioning_error
3696
3696
  `.execute(db);
3697
3697
  }
3698
3698
  //#endregion
3699
+ //#region src/db/migrations/025_init_failure.ts
3700
+ var _025_init_failure_exports = /* @__PURE__ */ __exportAll({
3701
+ down: () => down,
3702
+ up: () => up
3703
+ });
3704
+ /**
3705
+ * Add `init_failure jsonb` columns to `execution_runs` and `execution_jobs`.
3706
+ *
3707
+ * Presence of this column on a row means the run/job never executed a step
3708
+ * because of an init-phase failure; absence (NULL) means a normal run.
3709
+ * Shape on the wire is `InitFailure` from `@kici-dev/engine`. The dashboard
3710
+ * reads this column directly so it can render the right banner without
3711
+ * round-tripping to the orchestrator (which may be offline).
3712
+ *
3713
+ * Idempotent: re-running on a DB that already has either column is a no-op
3714
+ * for that column.
3715
+ */
3716
+ async function up(db) {
3717
+ const colExists = async (table, name) => {
3718
+ return (await sql`
3719
+ SELECT EXISTS (
3720
+ SELECT 1 FROM information_schema.columns
3721
+ WHERE table_schema = 'public'
3722
+ AND table_name = ${table}
3723
+ AND column_name = ${name}
3724
+ ) AS exists
3725
+ `.execute(db)).rows[0]?.exists ?? false;
3726
+ };
3727
+ if (!await colExists("execution_runs", "init_failure")) await sql`
3728
+ ALTER TABLE public.execution_runs
3729
+ ADD COLUMN init_failure JSONB DEFAULT NULL
3730
+ `.execute(db);
3731
+ if (!await colExists("execution_jobs", "init_failure")) await sql`
3732
+ ALTER TABLE public.execution_jobs
3733
+ ADD COLUMN init_failure JSONB DEFAULT NULL
3734
+ `.execute(db);
3735
+ }
3736
+ async function down(db) {
3737
+ await sql`
3738
+ ALTER TABLE public.execution_jobs DROP COLUMN IF EXISTS init_failure
3739
+ `.execute(db);
3740
+ await sql`
3741
+ ALTER TABLE public.execution_runs DROP COLUMN IF EXISTS init_failure
3742
+ `.execute(db);
3743
+ }
3744
+ //#endregion
3699
3745
  //#region src/db/migration-provider.ts
3700
3746
  function createMigrationProvider() {
3701
3747
  return { async getMigrations() {
@@ -3723,7 +3769,8 @@ function createMigrationProvider() {
3723
3769
  "021_check_run_tracking": _021_check_run_tracking_exports,
3724
3770
  "022_scaler_manager_state": _022_scaler_manager_state_exports,
3725
3771
  "023_dispatch_queue_recovery_deadline": _023_dispatch_queue_recovery_deadline_exports,
3726
- "024_dispatch_queue_provisioning_error": _024_dispatch_queue_provisioning_error_exports
3772
+ "024_dispatch_queue_provisioning_error": _024_dispatch_queue_provisioning_error_exports,
3773
+ "025_init_failure": _025_init_failure_exports
3727
3774
  };
3728
3775
  } };
3729
3776
  }
@@ -3865,7 +3912,7 @@ function registerDbCommands(program, getClient) {
3865
3912
  process.exit(1);
3866
3913
  }
3867
3914
  });
3868
- db.command("ensure <name>").description("CREATE DATABASE IF NOT EXISTS (idempotent)").option("--database-url <url>", "Admin DB URL (else KICI_DATABASE_URL / DATABASE_URL)").option("--owner <role>", "DB owner role (default: URL user). Pass when the admin connection is privileged but the new DB should be owned by a separate non-privileged role.").option("--revoke-connect-public", "After ensure, REVOKE CONNECT ON DATABASE \"<name>\" FROM PUBLIC (recommended on shared clusters).").action(async (name, opts) => {
3915
+ db.command("ensure <name>").description("CREATE DATABASE IF NOT EXISTS (idempotent)").option("--database-url <url>", "Admin DB URL (else KICI_DATABASE_URL / DATABASE_URL)").option("--owner <role>", "DB owner role (default: URL user). Pass when the admin connection is privileged but the new DB should be owned by a separate non-privileged role.").option("--revoke-connect-public", "After ensure, REVOKE CONNECT ON DATABASE \"<name>\" FROM PUBLIC (recommended on shared clusters).").option("--grant-connect-role <role>", "After ensure (and any --revoke-connect-public), GRANT CONNECT ON DATABASE \"<name>\" TO \"<role>\". Repeatable.", (val, acc) => acc.concat([val]), []).action(async (name, opts) => {
3869
3916
  try {
3870
3917
  const baseUrl = resolveDatabaseUrl$1(opts.databaseUrl);
3871
3918
  const url = new URL(baseUrl);
@@ -3874,9 +3921,10 @@ function registerDbCommands(program, getClient) {
3874
3921
  logInvocation(`ensure ${name}`, targetUrl);
3875
3922
  const outcome = await ensureDatabase(targetUrl, {
3876
3923
  owner: opts.owner,
3877
- revokeConnectFromPublic: !!opts.revokeConnectPublic
3924
+ revokeConnectFromPublic: !!opts.revokeConnectPublic,
3925
+ grantConnectToRoles: opts.grantConnectRole
3878
3926
  });
3879
- const suffix = (opts.owner ? ` (owner=${opts.owner})` : "") + (opts.revokeConnectPublic ? " [revoked CONNECT from PUBLIC]" : "");
3927
+ const suffix = (opts.owner ? ` (owner=${opts.owner})` : "") + (opts.revokeConnectPublic ? " [revoked CONNECT from PUBLIC]" : "") + (opts.grantConnectRole.length ? ` [granted CONNECT to: ${opts.grantConnectRole.join(", ")}]` : "");
3880
3928
  console.log(`db ensure: ${name} — ${outcome}${suffix}`);
3881
3929
  } catch (err) {
3882
3930
  console.error(`Error: ${toErrorMessage(err)}`);
@@ -6236,6 +6284,23 @@ function writeManifest(instanceDir, manifest) {
6236
6284
  fs.writeFileSync(file, JSON.stringify(manifest, null, 2) + "\n", "utf-8");
6237
6285
  return file;
6238
6286
  }
6287
+ /**
6288
+ * Read the running kici-admin's version from the orchestrator package.json.
6289
+ *
6290
+ * `process.env.npm_package_version` is only populated under `npm run` and is
6291
+ * undefined when kici-admin runs as a globally-installed binary, which is the
6292
+ * actual install path. Reading from the package.json on disk is the only
6293
+ * reliable source.
6294
+ */
6295
+ function readKiciVersion() {
6296
+ try {
6297
+ const pkgUrl = new URL("../../../../package.json", import.meta.url);
6298
+ const pkg = JSON.parse(fs.readFileSync(fileURLToPath(pkgUrl), "utf-8"));
6299
+ return typeof pkg.version === "string" ? pkg.version : "unknown";
6300
+ } catch {
6301
+ return "unknown";
6302
+ }
6303
+ }
6239
6304
  //#endregion
6240
6305
  //#region src/cli/service/instance/index-file.ts
6241
6306
  /**
@@ -8221,7 +8286,18 @@ function startDevPostgres(containerName) {
8221
8286
  if (err instanceof Error && err.message.includes("already exists")) throw err;
8222
8287
  }
8223
8288
  console.log(`Starting dev PostgreSQL container "${containerName}" on port ${port}...`);
8224
- execSync(`${runtime} run -d --name ${containerName} -p ${port}:5432 -e POSTGRES_PASSWORD=${password} -e POSTGRES_DB=kici postgres:18-trixie`, { stdio: "inherit" });
8289
+ const tmpEnvFile = path.join(fs.mkdtempSync(path.join(os.tmpdir(), "kici-dev-pg-")), "postgres.env");
8290
+ try {
8291
+ fs.writeFileSync(tmpEnvFile, `POSTGRES_PASSWORD=${password}\n`, { mode: 384 });
8292
+ execSync(`${runtime} run -d --name ${containerName} -p ${port}:5432 --env-file ${tmpEnvFile} -e POSTGRES_DB=kici postgres:18-trixie`, { stdio: "inherit" });
8293
+ } finally {
8294
+ try {
8295
+ fs.rmSync(path.dirname(tmpEnvFile), {
8296
+ recursive: true,
8297
+ force: true
8298
+ });
8299
+ } catch {}
8300
+ }
8225
8301
  return `postgresql://postgres:${password}@localhost:${port}/kici`;
8226
8302
  }
8227
8303
  function registerOrchestratorInstall(orchestrator) {
@@ -8331,7 +8407,7 @@ function registerOrchestratorInstall(orchestrator) {
8331
8407
  logDir,
8332
8408
  installBase: getInstallBase(platform, serviceName),
8333
8409
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
8334
- kiciVersion: process.env.npm_package_version ?? "unknown"
8410
+ kiciVersion: readKiciVersion()
8335
8411
  });
8336
8412
  try {
8337
8413
  appendIndexEntry(kiciRoot, {
@@ -8837,7 +8913,7 @@ function registerAgentInstall(agent) {
8837
8913
  logDir,
8838
8914
  installBase: getInstallBase(platform, serviceName),
8839
8915
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
8840
- kiciVersion: process.env.npm_package_version ?? "unknown"
8916
+ kiciVersion: readKiciVersion()
8841
8917
  });
8842
8918
  try {
8843
8919
  appendIndexEntry(kiciRoot, {