@automagik/omni 2.260520.9 → 2.260520.11

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/index.js CHANGED
@@ -22772,7 +22772,7 @@ var require_node_transport = __commonJS((exports) => {
22772
22772
  var util_1 = require_util();
22773
22773
  var tls_1 = __require("tls");
22774
22774
  var { resolve: resolve2 } = __require("path");
22775
- var { readFile, existsSync: existsSync11 } = __require("fs");
22775
+ var { readFile, existsSync: existsSync12 } = __require("fs");
22776
22776
  var dns = __require("dns");
22777
22777
  var VERSION2 = "2.29.3";
22778
22778
  var LANG = "nats.js";
@@ -22888,7 +22888,7 @@ var require_node_transport = __commonJS((exports) => {
22888
22888
  const d = (0, nats_base_client_1.deferred)();
22889
22889
  try {
22890
22890
  fn = resolve2(fn);
22891
- if (!existsSync11(fn)) {
22891
+ if (!existsSync12(fn)) {
22892
22892
  d.reject(new Error(`${fn} doesn't exist`));
22893
22893
  }
22894
22894
  readFile(fn, (err, data2) => {
@@ -61931,8 +61931,8 @@ var init_a2a_provider = __esm(() => {
61931
61931
 
61932
61932
  // ../core/src/providers/nats-genie-provider.ts
61933
61933
  import { mkdir, writeFile } from "fs/promises";
61934
- import { homedir as homedir8 } from "os";
61935
- import { join as join14 } from "path";
61934
+ import { homedir as homedir9 } from "os";
61935
+ import { join as join15 } from "path";
61936
61936
 
61937
61937
  class NatsGenieProvider {
61938
61938
  id;
@@ -62122,10 +62122,10 @@ class NatsGenieProvider {
62122
62122
  }
62123
62123
  async writeDeadLetter(payload, error2) {
62124
62124
  try {
62125
- const dlDir = join14(homedir8(), ".omni", "dead-letters");
62125
+ const dlDir = join15(homedir9(), ".omni", "dead-letters");
62126
62126
  await mkdir(dlDir, { recursive: true });
62127
62127
  const filename = `nats-genie-${Date.now()}-${payload.chatId}.json`;
62128
- await writeFile(join14(dlDir, filename), JSON.stringify({
62128
+ await writeFile(join15(dlDir, filename), JSON.stringify({
62129
62129
  payload,
62130
62130
  error: error2 instanceof Error ? error2.message : String(error2),
62131
62131
  timestamp: new Date().toISOString()
@@ -64004,7 +64004,7 @@ var init_sql = __esm(() => {
64004
64004
  return new SQL([new StringChunk(str)]);
64005
64005
  }
64006
64006
  sql2.raw = raw2;
64007
- function join15(chunks, separator) {
64007
+ function join16(chunks, separator) {
64008
64008
  const result = [];
64009
64009
  for (const [i6, chunk] of chunks.entries()) {
64010
64010
  if (i6 > 0 && separator !== undefined) {
@@ -64014,7 +64014,7 @@ var init_sql = __esm(() => {
64014
64014
  }
64015
64015
  return new SQL(result);
64016
64016
  }
64017
- sql2.join = join15;
64017
+ sql2.join = join16;
64018
64018
  function identifier(value) {
64019
64019
  return new Name(value);
64020
64020
  }
@@ -67241,7 +67241,7 @@ var init_select2 = __esm(() => {
67241
67241
  return (table2, on) => {
67242
67242
  const baseTableName = this.tableName;
67243
67243
  const tableName = getTableLikeName(table2);
67244
- if (typeof tableName === "string" && this.config.joins?.some((join15) => join15.alias === tableName)) {
67244
+ if (typeof tableName === "string" && this.config.joins?.some((join16) => join16.alias === tableName)) {
67245
67245
  throw new Error(`Alias "${tableName}" is already used in this query`);
67246
67246
  }
67247
67247
  if (!this.isPartialSelect) {
@@ -67752,7 +67752,7 @@ var init_update = __esm(() => {
67752
67752
  createJoin(joinType) {
67753
67753
  return (table2, on) => {
67754
67754
  const tableName = getTableLikeName(table2);
67755
- if (typeof tableName === "string" && this.config.joins.some((join15) => join15.alias === tableName)) {
67755
+ if (typeof tableName === "string" && this.config.joins.some((join16) => join16.alias === tableName)) {
67756
67756
  throw new Error(`Alias "${tableName}" is already used in this query`);
67757
67757
  }
67758
67758
  if (typeof on === "function") {
@@ -67802,10 +67802,10 @@ var init_update = __esm(() => {
67802
67802
  const fromFields = this.getTableLikeFields(this.config.from);
67803
67803
  fields[tableName] = fromFields;
67804
67804
  }
67805
- for (const join15 of this.config.joins) {
67806
- const tableName2 = getTableLikeName(join15.table);
67807
- if (typeof tableName2 === "string" && !is(join15.table, SQL)) {
67808
- const fromFields = this.getTableLikeFields(join15.table);
67805
+ for (const join16 of this.config.joins) {
67806
+ const tableName2 = getTableLikeName(join16.table);
67807
+ if (typeof tableName2 === "string" && !is(join16.table, SQL)) {
67808
+ const fromFields = this.getTableLikeFields(join16.table);
67809
67809
  fields[tableName2] = fromFields;
67810
67810
  }
67811
67811
  }
@@ -82474,7 +82474,7 @@ var require_path = __commonJS((exports) => {
82474
82474
  function isAbsolute(path) {
82475
82475
  return path.charAt(0) === "/";
82476
82476
  }
82477
- function join19(...args) {
82477
+ function join20(...args) {
82478
82478
  return normalizePath(args.join("/"));
82479
82479
  }
82480
82480
  function dirname6(path) {
@@ -82499,7 +82499,7 @@ var require_path = __commonJS((exports) => {
82499
82499
  exports.basename = basename6;
82500
82500
  exports.dirname = dirname6;
82501
82501
  exports.isAbsolute = isAbsolute;
82502
- exports.join = join19;
82502
+ exports.join = join20;
82503
82503
  exports.normalizePath = normalizePath;
82504
82504
  exports.relative = relative;
82505
82505
  exports.resolve = resolve4;
@@ -124067,7 +124067,7 @@ import { fileURLToPath } from "url";
124067
124067
  // package.json
124068
124068
  var package_default = {
124069
124069
  name: "@automagik/omni",
124070
- version: "2.260520.9",
124070
+ version: "2.260520.11",
124071
124071
  description: "LLM-optimized CLI for Omni",
124072
124072
  type: "module",
124073
124073
  bin: {
@@ -125268,7 +125268,7 @@ function pm2NotFoundError() {
125268
125268
  }
125269
125269
 
125270
125270
  // src/runtime-env.ts
125271
- import { join as join6 } from "path";
125271
+ import { join as join7 } from "path";
125272
125272
 
125273
125273
  // src/lib/pgserve-transport.ts
125274
125274
  import { existsSync as existsSync4 } from "fs";
@@ -125330,15 +125330,187 @@ function buildDatabaseUrlForTransport(transport, database, options = {}) {
125330
125330
  const password = options.password ?? "postgres";
125331
125331
  const auth = `${encodeURIComponent(username)}:${encodeURIComponent(password)}`;
125332
125332
  if (transport.kind === "unix") {
125333
- const params = new URLSearchParams({
125334
- host: transport.socketDir,
125335
- port: String(transport.port)
125336
- });
125337
- return `postgresql://${auth}@localhost/${encodeURIComponent(database)}?${params.toString()}`;
125333
+ return `postgresql://${auth}@localhost/${encodeURIComponent(database)}`;
125338
125334
  }
125339
125335
  return `postgresql://${auth}@${transport.host}:${transport.port}/${encodeURIComponent(database)}`;
125340
125336
  }
125341
125337
 
125338
+ // src/lib/role-cutover.ts
125339
+ import { createHash as createHash2, randomBytes } from "crypto";
125340
+ import { existsSync as existsSync5, mkdirSync as mkdirSync3, readFileSync as readFileSync4, unlinkSync, writeFileSync as writeFileSync3 } from "fs";
125341
+ import { homedir as homedir3 } from "os";
125342
+ import { join as join6 } from "path";
125343
+ var NAME_PREFIX = "pgserve_";
125344
+ var ROLE_SUFFIX = "_role";
125345
+ var POSTGRES_MAX_IDENT = 63;
125346
+ var FINGERPRINT_HEX_LEN = 12;
125347
+ var OMNI_PUBLISHER = "omni";
125348
+ var SAFE_IDENT = /^[a-z_][a-z0-9_]*$/;
125349
+ function sha256Hex(input) {
125350
+ return createHash2("sha256").update(input, "utf8").digest("hex");
125351
+ }
125352
+ function sanitizeSlug(input) {
125353
+ return input.toLowerCase().replace(/[^a-z0-9_]/g, "_").replace(/^_+|_+$/g, "").replace(/__+/g, "_");
125354
+ }
125355
+ function deriveOmniScopedRoleName() {
125356
+ const fp = sha256Hex("@automagik/omni").slice(0, FINGERPRINT_HEX_LEN);
125357
+ const slug = sanitizeSlug(OMNI_PUBLISHER);
125358
+ const budget = POSTGRES_MAX_IDENT - NAME_PREFIX.length - 1 - fp.length - ROLE_SUFFIX.length;
125359
+ const truncated = slug.slice(0, Math.max(0, budget));
125360
+ return `${NAME_PREFIX}${truncated}_${fp}${ROLE_SUFFIX}`;
125361
+ }
125362
+ function assertSafeIdent(label, value) {
125363
+ if (!SAFE_IDENT.test(value)) {
125364
+ throw new Error(`role-cutover: unsafe ${label} identifier: ${JSON.stringify(value)}`);
125365
+ }
125366
+ }
125367
+ function assertSafePassword(value) {
125368
+ if (!/^[A-Za-z0-9_-]+$/.test(value)) {
125369
+ throw new Error("role-cutover: generated password contains unsafe characters");
125370
+ }
125371
+ }
125372
+ function sentinelDir() {
125373
+ return join6(homedir3(), ".omni");
125374
+ }
125375
+ function sentinelPath() {
125376
+ return join6(sentinelDir(), "scoped-role.json");
125377
+ }
125378
+ function readOmniCutoverSentinel() {
125379
+ const path = sentinelPath();
125380
+ if (!existsSync5(path))
125381
+ return null;
125382
+ try {
125383
+ const raw2 = readFileSync4(path, "utf-8");
125384
+ const parsed = JSON.parse(raw2);
125385
+ if (typeof parsed.roleName === "string" && typeof parsed.database === "string" && typeof parsed.password === "string" && typeof parsed.provisionedAt === "string") {
125386
+ return parsed;
125387
+ }
125388
+ } catch {}
125389
+ return null;
125390
+ }
125391
+ function writeOmniCutoverSentinel(data2) {
125392
+ const dir = sentinelDir();
125393
+ if (!existsSync5(dir))
125394
+ mkdirSync3(dir, { recursive: true, mode: 448 });
125395
+ const path = sentinelPath();
125396
+ writeFileSync3(path, `${JSON.stringify(data2, null, 2)}
125397
+ `, { mode: 384 });
125398
+ }
125399
+ function isOmniRoleCutoverEnabled() {
125400
+ return process.env.OMNI_ROLE_CUTOVER !== "0";
125401
+ }
125402
+ function generatePassword() {
125403
+ return randomBytes(32).toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
125404
+ }
125405
+ async function ensureOmniScopedRole(opts) {
125406
+ const enabled = opts.enabled ?? isOmniRoleCutoverEnabled();
125407
+ if (!enabled) {
125408
+ return { status: "skipped", reason: "disabled" };
125409
+ }
125410
+ const database = opts.database ?? "omni";
125411
+ const port = opts.port ?? 5432;
125412
+ const roleName = deriveOmniScopedRoleName();
125413
+ try {
125414
+ assertSafeIdent("role", roleName);
125415
+ assertSafeIdent("database", database);
125416
+ } catch (err) {
125417
+ return { status: "skipped", reason: err.message };
125418
+ }
125419
+ const existing = readOmniCutoverSentinel();
125420
+ const password = existing && existing.roleName === roleName && existing.database === database ? existing.password : generatePassword();
125421
+ try {
125422
+ assertSafePassword(password);
125423
+ } catch (err) {
125424
+ return { status: "skipped", reason: err.message };
125425
+ }
125426
+ const sqlScript = [
125427
+ `DO $$
125428
+ BEGIN
125429
+ IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = '${roleName}') THEN
125430
+ CREATE ROLE "${roleName}" WITH LOGIN PASSWORD '${password}'
125431
+ NOSUPERUSER NOCREATEDB NOCREATEROLE NOREPLICATION NOBYPASSRLS;
125432
+ ELSE
125433
+ ALTER ROLE "${roleName}" WITH LOGIN PASSWORD '${password}'
125434
+ NOSUPERUSER NOCREATEDB NOCREATEROLE NOREPLICATION NOBYPASSRLS;
125435
+ END IF;
125436
+ END
125437
+ $$;`,
125438
+ `GRANT CONNECT, TEMPORARY ON DATABASE "${database}" TO "${roleName}";`
125439
+ ];
125440
+ const dbCreateOk = await runPsql(sqlScript.join(`
125441
+ `), { socketDir: opts.socketDir, port, database: "postgres" });
125442
+ if (!dbCreateOk) {
125443
+ return { status: "skipped", reason: "psql role provisioning failed" };
125444
+ }
125445
+ const grantsScript = [
125446
+ `GRANT USAGE, CREATE ON SCHEMA public TO "${roleName}";`,
125447
+ `GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO "${roleName}";`,
125448
+ `GRANT USAGE, SELECT, UPDATE ON ALL SEQUENCES IN SCHEMA public TO "${roleName}";`,
125449
+ `ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO "${roleName}";`,
125450
+ `ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT USAGE, SELECT, UPDATE ON SEQUENCES TO "${roleName}";`,
125451
+ `ALTER DEFAULT PRIVILEGES FOR ROLE "${roleName}" IN SCHEMA public GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO "${roleName}";`,
125452
+ `ALTER DEFAULT PRIVILEGES FOR ROLE "${roleName}" IN SCHEMA public GRANT USAGE, SELECT, UPDATE ON SEQUENCES TO "${roleName}";`
125453
+ ].join(`
125454
+ `);
125455
+ const grantsOk = await runPsql(grantsScript, { socketDir: opts.socketDir, port, database });
125456
+ if (!grantsOk) {
125457
+ return { status: "skipped", reason: "psql grant step failed" };
125458
+ }
125459
+ writeOmniCutoverSentinel({
125460
+ roleName,
125461
+ database,
125462
+ password,
125463
+ provisionedAt: new Date().toISOString()
125464
+ });
125465
+ return existing && existing.roleName === roleName ? { status: "refreshed", roleName } : { status: "provisioned", roleName };
125466
+ }
125467
+ async function runPsql(sql, opts) {
125468
+ const proc = Bun.spawn({
125469
+ cmd: [
125470
+ "psql",
125471
+ "-h",
125472
+ opts.socketDir,
125473
+ "-p",
125474
+ String(opts.port),
125475
+ "-U",
125476
+ "postgres",
125477
+ "-d",
125478
+ opts.database,
125479
+ "-v",
125480
+ "ON_ERROR_STOP=1",
125481
+ "-c",
125482
+ sql
125483
+ ],
125484
+ stdout: "pipe",
125485
+ stderr: "pipe",
125486
+ env: { ...process.env, PGPASSWORD: "postgres" }
125487
+ });
125488
+ const stderr = await new Response(proc.stderr).text();
125489
+ const code = await proc.exited;
125490
+ if (code !== 0) {
125491
+ process.stderr.write(`role-cutover: psql exited ${code}: ${stderr.trim()}
125492
+ `);
125493
+ return false;
125494
+ }
125495
+ return true;
125496
+ }
125497
+ function resolveOmniScopedCredentials() {
125498
+ if (!isOmniRoleCutoverEnabled())
125499
+ return null;
125500
+ const sentinel = readOmniCutoverSentinel();
125501
+ if (!sentinel)
125502
+ return null;
125503
+ const expected = deriveOmniScopedRoleName();
125504
+ if (sentinel.roleName !== expected) {
125505
+ return null;
125506
+ }
125507
+ return {
125508
+ username: sentinel.roleName,
125509
+ password: sentinel.password,
125510
+ roleName: sentinel.roleName
125511
+ };
125512
+ }
125513
+
125342
125514
  // src/runtime-env.ts
125343
125515
  var LEGACY_DEFAULT_DATABASE_URL = "postgresql://postgres:postgres@localhost:5432/omni";
125344
125516
  var LEGACY_PHASE2_DATABASE_URL = "postgresql://postgres:postgres@localhost:8432/omni";
@@ -125367,21 +125539,34 @@ function resolveDatabaseUrl(serverConfig) {
125367
125539
  }
125368
125540
  return buildEmbeddedDatabaseUrl(resolvePgservePort(serverConfig));
125369
125541
  }
125542
+ function applyScopedCredentials(url, creds) {
125543
+ if (!creds)
125544
+ return url;
125545
+ try {
125546
+ const parsed = new URL(url);
125547
+ parsed.username = encodeURIComponent(creds.username);
125548
+ parsed.password = encodeURIComponent(creds.password);
125549
+ return parsed.toString();
125550
+ } catch {
125551
+ return url;
125552
+ }
125553
+ }
125370
125554
  function buildRuntimeEnv(serverConfig, cliConfig) {
125371
125555
  const pgservePort = resolvePgservePort(serverConfig);
125372
125556
  const udsActive = probeCanonicalSocketSync();
125373
125557
  const pgHost = udsActive ? resolvePgserveSocketDir() : "";
125374
125558
  const pgPort = udsActive ? String(CANONICAL_PG_PORT) : "";
125559
+ const scopedCreds = resolveOmniScopedCredentials();
125375
125560
  return {
125376
125561
  API_PORT: String(serverConfig.port),
125377
- DATABASE_URL: resolveDatabaseUrl(serverConfig),
125562
+ DATABASE_URL: applyScopedCredentials(resolveDatabaseUrl(serverConfig), scopedCreds),
125378
125563
  PGHOST: pgHost,
125379
125564
  PGPORT: pgPort,
125380
125565
  OMNI_API_KEY: cliConfig.apiKey ?? "",
125381
- MEDIA_STORAGE_PATH: join6(serverConfig.dataDir, "media"),
125382
- OMNI_PACKAGES_DIR: join6(serverConfig.dataDir, "packages"),
125566
+ MEDIA_STORAGE_PATH: join7(serverConfig.dataDir, "media"),
125567
+ OMNI_PACKAGES_DIR: join7(serverConfig.dataDir, "packages"),
125383
125568
  PGSERVE_EMBEDDED: "false",
125384
- PGSERVE_DATA: join6(serverConfig.dataDir, "pgserve"),
125569
+ PGSERVE_DATA: join7(serverConfig.dataDir, "pgserve"),
125385
125570
  PGSERVE_PORT: String(pgservePort),
125386
125571
  NATS_URL: "nats://localhost:4222",
125387
125572
  NODE_ENV: serverConfig.nodeEnv,
@@ -127695,9 +127880,9 @@ function createDeadLettersCommand() {
127695
127880
  }
127696
127881
 
127697
127882
  // src/commands/doctor.ts
127698
- import { existsSync as existsSync8, readdirSync as readdirSync2, statSync as statSync2 } from "fs";
127699
- import { homedir as homedir6 } from "os";
127700
- import { join as join11, resolve } from "path";
127883
+ import { existsSync as existsSync9, readdirSync as readdirSync2, statSync as statSync2 } from "fs";
127884
+ import { homedir as homedir7 } from "os";
127885
+ import { join as join12, resolve } from "path";
127701
127886
  init_config();
127702
127887
 
127703
127888
  // src/health.ts
@@ -127723,14 +127908,14 @@ async function waitForHealth(port, timeoutMs = HEALTH_TIMEOUT_MS) {
127723
127908
 
127724
127909
  // src/install-helpers.ts
127725
127910
  init_config();
127726
- import { existsSync as existsSync6, readdirSync, writeFileSync as writeFileSync4 } from "fs";
127727
- import { homedir as homedir4 } from "os";
127728
- import { join as join8 } from "path";
127911
+ import { existsSync as existsSync7, readdirSync, writeFileSync as writeFileSync5 } from "fs";
127912
+ import { homedir as homedir5 } from "os";
127913
+ import { join as join9 } from "path";
127729
127914
 
127730
127915
  // src/nats-install.ts
127731
- import { chmodSync as chmodSync2, existsSync as existsSync5, mkdirSync as mkdirSync3, writeFileSync as writeFileSync3 } from "fs";
127732
- import { homedir as homedir3 } from "os";
127733
- import { join as join7 } from "path";
127916
+ import { chmodSync as chmodSync2, existsSync as existsSync6, mkdirSync as mkdirSync4, writeFileSync as writeFileSync4 } from "fs";
127917
+ import { homedir as homedir4 } from "os";
127918
+ import { join as join8 } from "path";
127734
127919
 
127735
127920
  // ../../node_modules/.bun/ora@8.2.0/node_modules/ora/index.js
127736
127921
  init_source();
@@ -128620,8 +128805,8 @@ function ora(options) {
128620
128805
 
128621
128806
  // src/nats-install.ts
128622
128807
  init_output();
128623
- var OMNI_DIR = join7(homedir3(), ".omni");
128624
- var NATS_BINARY_PATH = join7(OMNI_DIR, "nats-server");
128808
+ var OMNI_DIR = join8(homedir4(), ".omni");
128809
+ var NATS_BINARY_PATH = join8(OMNI_DIR, "nats-server");
128625
128810
  var NATS_VERSION = "v2.12.4";
128626
128811
  function platformInfo() {
128627
128812
  const platform = process.platform;
@@ -128644,17 +128829,17 @@ async function downloadNats() {
128644
128829
  const url = `https://github.com/nats-io/nats-server/releases/download/${NATS_VERSION}/${fileName}`;
128645
128830
  const spinner = ora(`Downloading NATS ${NATS_VERSION} for ${info2.os}/${info2.arch}...`).start();
128646
128831
  try {
128647
- mkdirSync3(OMNI_DIR, { recursive: true, mode: 448 });
128832
+ mkdirSync4(OMNI_DIR, { recursive: true, mode: 448 });
128648
128833
  const resp = await fetch(url, { signal: AbortSignal.timeout(60000) });
128649
128834
  if (!resp.ok) {
128650
128835
  spinner.fail(`NATS download failed: HTTP ${resp.status}`);
128651
128836
  return false;
128652
128837
  }
128653
- const tarPath = join7(OMNI_DIR, fileName);
128654
- writeFileSync3(tarPath, Buffer.from(await resp.arrayBuffer()));
128838
+ const tarPath = join8(OMNI_DIR, fileName);
128839
+ writeFileSync4(tarPath, Buffer.from(await resp.arrayBuffer()));
128655
128840
  spinner.text = "Extracting NATS binary...";
128656
- const tmpDir = join7(OMNI_DIR, "nats-tmp");
128657
- mkdirSync3(tmpDir, { recursive: true });
128841
+ const tmpDir = join8(OMNI_DIR, "nats-tmp");
128842
+ mkdirSync4(tmpDir, { recursive: true });
128658
128843
  const tar = Bun.spawn({ cmd: ["tar", "-xzf", tarPath, "-C", tmpDir], stdout: "pipe", stderr: "pipe" });
128659
128844
  const [tarCode, tarErr] = await Promise.all([tar.exited, new Response(tar.stderr).text()]);
128660
128845
  if (tarCode !== 0) {
@@ -128679,7 +128864,7 @@ async function downloadNats() {
128679
128864
  }
128680
128865
  }
128681
128866
  async function ensureNats() {
128682
- if (existsSync5(NATS_BINARY_PATH)) {
128867
+ if (existsSync6(NATS_BINARY_PATH)) {
128683
128868
  raw(` \u2713 NATS binary found at ${NATS_BINARY_PATH}`);
128684
128869
  return;
128685
128870
  }
@@ -128689,7 +128874,7 @@ async function ensureNats() {
128689
128874
 
128690
128875
  // src/install-helpers.ts
128691
128876
  init_output();
128692
- var DEFAULT_DATA_DIR = join8(homedir4(), ".omni", "data");
128877
+ var DEFAULT_DATA_DIR = join9(homedir5(), ".omni", "data");
128693
128878
  async function detectReinstall(dataDirOverride) {
128694
128879
  const hasConfig = detectHasConfig();
128695
128880
  const hasPm2Process = await detectHasPm2Process();
@@ -128702,7 +128887,7 @@ async function detectReinstall(dataDirOverride) {
128702
128887
  };
128703
128888
  }
128704
128889
  function detectHasConfig() {
128705
- if (!existsSync6(getConfigPath()))
128890
+ if (!existsSync7(getConfigPath()))
128706
128891
  return false;
128707
128892
  try {
128708
128893
  const parsed = loadConfig();
@@ -128724,7 +128909,7 @@ async function detectHasPm2Process() {
128724
128909
  }
128725
128910
  function detectHasDataDir(dataDirOverride) {
128726
128911
  const dataDir = dataDirOverride ?? DEFAULT_DATA_DIR;
128727
- if (!existsSync6(dataDir))
128912
+ if (!existsSync7(dataDir))
128728
128913
  return false;
128729
128914
  try {
128730
128915
  return readdirSync(dataDir).filter((e) => e !== ".DS_Store").length > 0;
@@ -128778,7 +128963,7 @@ ExecStart=/usr/bin/env omni start
128778
128963
  ExecStop=/usr/bin/env omni stop
128779
128964
  ExecReload=/usr/bin/env omni restart
128780
128965
  Restart=on-failure
128781
- PIDFile=${homedir4()}/.pm2/pm2.pid
128966
+ PIDFile=${homedir5()}/.pm2/pm2.pid
128782
128967
 
128783
128968
  [Install]
128784
128969
  WantedBy=multi-user.target
@@ -128789,7 +128974,7 @@ After=network.target
128789
128974
 
128790
128975
  [Service]
128791
128976
  Type=simple
128792
- ExecStart="${NATS_BINARY_PATH}" -js -sd "${join8(dataDir, "nats")}"
128977
+ ExecStart="${NATS_BINARY_PATH}" -js -sd "${join9(dataDir, "nats")}"
128793
128978
  Restart=on-failure
128794
128979
  RestartSec=5
128795
128980
 
@@ -128797,8 +128982,8 @@ RestartSec=5
128797
128982
  WantedBy=multi-user.target
128798
128983
  `;
128799
128984
  try {
128800
- writeFileSync4("/etc/systemd/system/omni-nats.service", natsUnit, { mode: 420 });
128801
- writeFileSync4("/etc/systemd/system/omni-api.service", apiUnit, { mode: 420 });
128985
+ writeFileSync5("/etc/systemd/system/omni-nats.service", natsUnit, { mode: 420 });
128986
+ writeFileSync5("/etc/systemd/system/omni-api.service", apiUnit, { mode: 420 });
128802
128987
  success("Systemd units written to /etc/systemd/system/");
128803
128988
  raw(`
128804
128989
  Enable with: sudo systemctl enable --now omni-nats omni-api
@@ -128812,9 +128997,9 @@ WantedBy=multi-user.target
128812
128997
  init_config();
128813
128998
  init_output();
128814
128999
  import { spawnSync } from "child_process";
128815
- import { existsSync as existsSync7, mkdirSync as mkdirSync4, readFileSync as readFileSync4, renameSync, statSync, writeFileSync as writeFileSync5 } from "fs";
128816
- import { homedir as homedir5 } from "os";
128817
- import { join as join9 } from "path";
129000
+ import { existsSync as existsSync8, mkdirSync as mkdirSync5, readFileSync as readFileSync5, renameSync, statSync, writeFileSync as writeFileSync6 } from "fs";
129001
+ import { homedir as homedir6 } from "os";
129002
+ import { join as join10 } from "path";
128818
129003
  import { gunzipSync, gzipSync } from "zlib";
128819
129004
  async function isPgserveInstalled() {
128820
129005
  const bin = resolvePgserveBinary();
@@ -128932,6 +129117,16 @@ async function setupCanonicalPgserve() {
128932
129117
  if (port === null)
128933
129118
  return null;
128934
129119
  await ensureOmniDatabaseExists(port);
129120
+ const cutover = await ensureOmniScopedRole({
129121
+ socketDir: resolvePgserveSocketDir(),
129122
+ port,
129123
+ database: OMNI_DATABASE_NAME
129124
+ });
129125
+ if (cutover.status === "provisioned" || cutover.status === "refreshed") {
129126
+ raw(` Scoped role \`${cutover.roleName}\` ${cutover.status} \u2014 omni-api will connect as non-superuser.`);
129127
+ } else if (cutover.status === "skipped" && cutover.reason !== "disabled") {
129128
+ warn(`Scoped-role cutover skipped: ${cutover.reason} \u2014 omni-api falls back to postgres superuser.`);
129129
+ }
128935
129130
  return buildOmniDatabaseUrl(port);
128936
129131
  }
128937
129132
  async function resolveCanonicalPgservePreference(isReinstall, cfg) {
@@ -128963,18 +129158,18 @@ async function resolveCanonicalPgservePreference(isReinstall, cfg) {
128963
129158
  raw("");
128964
129159
  return true;
128965
129160
  }
128966
- var OMNI_EMBEDDED_PGSERVE_DATA_DIR = join9(homedir5(), ".omni", "data", "pgserve");
128967
- var PGSERVE_DEFAULT_DATA_DIR = join9(homedir5(), ".pgserve", "data");
128968
- var PGSERVE_CONFIG_PATH = join9(homedir5(), ".pgserve", "config.json");
128969
- var OMNI_BACKUPS_DIR = join9(homedir5(), ".omni", "backups");
129161
+ var OMNI_EMBEDDED_PGSERVE_DATA_DIR = join10(homedir6(), ".omni", "data", "pgserve");
129162
+ var PGSERVE_DEFAULT_DATA_DIR = join10(homedir6(), ".pgserve", "data");
129163
+ var PGSERVE_CONFIG_PATH = join10(homedir6(), ".pgserve", "config.json");
129164
+ var OMNI_BACKUPS_DIR = join10(homedir6(), ".omni", "backups");
128970
129165
  function getEmbeddedPgserveDataDir() {
128971
129166
  return OMNI_EMBEDDED_PGSERVE_DATA_DIR;
128972
129167
  }
128973
129168
  function getCanonicalPgserveDataDir() {
128974
- if (!existsSync7(PGSERVE_CONFIG_PATH))
129169
+ if (!existsSync8(PGSERVE_CONFIG_PATH))
128975
129170
  return PGSERVE_DEFAULT_DATA_DIR;
128976
129171
  try {
128977
- const raw2 = readFileSync4(PGSERVE_CONFIG_PATH, "utf8");
129172
+ const raw2 = readFileSync5(PGSERVE_CONFIG_PATH, "utf8");
128978
129173
  const parsed = JSON.parse(raw2);
128979
129174
  return typeof parsed.dataDir === "string" && parsed.dataDir.length > 0 ? parsed.dataDir : PGSERVE_DEFAULT_DATA_DIR;
128980
129175
  } catch {
@@ -128982,11 +129177,11 @@ function getCanonicalPgserveDataDir() {
128982
129177
  }
128983
129178
  }
128984
129179
  function looksLikePgDataDir(path) {
128985
- return existsSync7(join9(path, "PG_VERSION")) && existsSync7(join9(path, "base"));
129180
+ return existsSync8(join10(path, "PG_VERSION")) && existsSync8(join10(path, "base"));
128986
129181
  }
128987
129182
  function getSnapshotPath(timestamp = new Date) {
128988
129183
  const ts = timestamp.toISOString().replace(/[:.]/g, "-");
128989
- return join9(OMNI_BACKUPS_DIR, `embedded-migration-${ts}.sql.gz`);
129184
+ return join10(OMNI_BACKUPS_DIR, `embedded-migration-${ts}.sql.gz`);
128990
129185
  }
128991
129186
  function commandIsAvailable(cmd) {
128992
129187
  try {
@@ -129011,7 +129206,7 @@ function pgEnvFromUrl(url) {
129011
129206
  }
129012
129207
  async function dumpEmbeddedDb(currentDatabaseUrl) {
129013
129208
  const embeddedDir = getEmbeddedPgserveDataDir();
129014
- if (!existsSync7(embeddedDir)) {
129209
+ if (!existsSync8(embeddedDir)) {
129015
129210
  return { status: "no-embedded-data", embeddedDir };
129016
129211
  }
129017
129212
  if (!looksLikePgDataDir(embeddedDir)) {
@@ -129022,7 +129217,7 @@ async function dumpEmbeddedDb(currentDatabaseUrl) {
129022
129217
  throw new Error("pg_dump not found in PATH \u2014 install postgresql-client (apt install postgresql-client / brew install postgresql) and retry");
129023
129218
  }
129024
129219
  const snapshotPath = getSnapshotPath();
129025
- mkdirSync4(OMNI_BACKUPS_DIR, { recursive: true, mode: 448 });
129220
+ mkdirSync5(OMNI_BACKUPS_DIR, { recursive: true, mode: 448 });
129026
129221
  raw(" Dumping embedded database via pg_dump...");
129027
129222
  raw(` source data dir: ${embeddedDir}`);
129028
129223
  raw(` snapshot: ${snapshotPath}`);
@@ -129038,7 +129233,7 @@ async function dumpEmbeddedDb(currentDatabaseUrl) {
129038
129233
  }
129039
129234
  const compressed = gzipSync(result.stdout);
129040
129235
  const tmpPath = `${snapshotPath}.tmp`;
129041
- writeFileSync5(tmpPath, compressed, { mode: 384 });
129236
+ writeFileSync6(tmpPath, compressed, { mode: 384 });
129042
129237
  renameSync(tmpPath, snapshotPath);
129043
129238
  const bytes = statSync(snapshotPath).size;
129044
129239
  raw(` snapshot size: ${formatBytes(bytes)}`);
@@ -129056,7 +129251,7 @@ async function restoreSnapshotToCanonical(dump, canonicalDatabaseUrl) {
129056
129251
  raw(` snapshot: ${dump.snapshotPath}`);
129057
129252
  raw(` canonical data dir: ${getCanonicalPgserveDataDir()}`);
129058
129253
  raw(` canonical URL: ${canonicalDatabaseUrl}`);
129059
- const compressed = readFileSync4(dump.snapshotPath);
129254
+ const compressed = readFileSync5(dump.snapshotPath);
129060
129255
  const sql = gunzipSync(compressed);
129061
129256
  const result = spawnSync("psql", ["-v", "ON_ERROR_STOP=1"], {
129062
129257
  env: { ...process.env, ...pgEnvFromUrl(canonicalDatabaseUrl) },
@@ -129087,24 +129282,24 @@ init_output();
129087
129282
 
129088
129283
  // src/server-bundle.ts
129089
129284
  init_output();
129090
- import { dirname as dirname2, join as join10 } from "path";
129285
+ import { dirname as dirname2, join as join11 } from "path";
129091
129286
  import { fileURLToPath as fileURLToPath2 } from "url";
129092
129287
  function getServerBundlePath() {
129093
129288
  try {
129094
129289
  const thisFile = fileURLToPath2(import.meta.url);
129095
129290
  const distDir = dirname2(thisFile);
129096
- return join10(distDir, "server", "index.js");
129291
+ return join11(distDir, "server", "index.js");
129097
129292
  } catch {
129098
- return join10(process.cwd(), "dist", "server", "index.js");
129293
+ return join11(process.cwd(), "dist", "server", "index.js");
129099
129294
  }
129100
129295
  }
129101
129296
  function getServerLauncherPath() {
129102
129297
  try {
129103
129298
  const thisFile = fileURLToPath2(import.meta.url);
129104
129299
  const distDir = dirname2(thisFile);
129105
- return join10(distDir, "..", "bin", "omni-server");
129300
+ return join11(distDir, "..", "bin", "omni-server");
129106
129301
  } catch {
129107
- return join10(process.cwd(), "bin", "omni-server");
129302
+ return join11(process.cwd(), "bin", "omni-server");
129108
129303
  }
129109
129304
  }
129110
129305
  function bundleNotFoundError(bundlePath) {
@@ -129169,10 +129364,10 @@ function productionDeps() {
129169
129364
  }
129170
129365
  },
129171
129366
  findOrphanedDataDirs: () => {
129172
- const roots = [process.cwd(), join11(homedir6(), "workspace"), join11(homedir6(), "repos")];
129367
+ const roots = [process.cwd(), join12(homedir7(), "workspace"), join12(homedir7(), "repos")];
129173
129368
  const found = [];
129174
129369
  for (const root of roots) {
129175
- if (!existsSync8(root))
129370
+ if (!existsSync9(root))
129176
129371
  continue;
129177
129372
  try {
129178
129373
  scanForOrphans(root, found, 0);
@@ -129280,7 +129475,7 @@ function scanForOrphans(dir, acc, depth, maxDepth = 4) {
129280
129475
  for (const name of entries) {
129281
129476
  if (name === "node_modules" || name === ".git")
129282
129477
  continue;
129283
- const full = join11(dir, name);
129478
+ const full = join12(dir, name);
129284
129479
  let stats;
129285
129480
  try {
129286
129481
  stats = statSync2(full);
@@ -129903,7 +130098,7 @@ Safety:
129903
130098
  }
129904
130099
 
129905
130100
  // src/commands/done.ts
129906
- import { existsSync as existsSync9, readFileSync as readFileSync5 } from "fs";
130101
+ import { existsSync as existsSync10, readFileSync as readFileSync6 } from "fs";
129907
130102
  import { basename, extname } from "path";
129908
130103
 
129909
130104
  // src/context.ts
@@ -130012,12 +130207,12 @@ async function handleReact(client, ctx, emoji) {
130012
130207
  await closeTurn(client, "react", `Reacted ${emoji} + turn closed`);
130013
130208
  }
130014
130209
  async function handleMedia(client, ctx, mediaPath, caption) {
130015
- if (!existsSync9(mediaPath)) {
130210
+ if (!existsSync10(mediaPath)) {
130016
130211
  return error(`File not found: ${mediaPath}`);
130017
130212
  }
130018
130213
  try {
130019
130214
  const mediaType = getMediaType(mediaPath);
130020
- const buffer = readFileSync5(mediaPath);
130215
+ const buffer = readFileSync6(mediaPath);
130021
130216
  const base64 = buffer.toString("base64");
130022
130217
  const filename = basename(mediaPath);
130023
130218
  await client.messages.sendMedia({
@@ -130449,7 +130644,7 @@ function createEventsCommand() {
130449
130644
  }
130450
130645
 
130451
130646
  // src/commands/film.ts
130452
- import { writeFileSync as writeFileSync6 } from "fs";
130647
+ import { writeFileSync as writeFileSync7 } from "fs";
130453
130648
  import { resolve as resolvePath } from "path";
130454
130649
  init_output();
130455
130650
  function createFilmCommand() {
@@ -130513,7 +130708,7 @@ function createFilmCommand() {
130513
130708
  const videoBuffer = Buffer.from(result.videoBase64, "base64");
130514
130709
  if (options.output) {
130515
130710
  const outPath = resolvePath(options.output);
130516
- writeFileSync6(outPath, videoBuffer);
130711
+ writeFileSync7(outPath, videoBuffer);
130517
130712
  success("Video saved", { path: outPath, sizeBytes: videoBuffer.length });
130518
130713
  return;
130519
130714
  }
@@ -130537,7 +130732,7 @@ function createFilmCommand() {
130537
130732
  }
130538
130733
 
130539
130734
  // src/commands/follow-up.ts
130540
- import { readFileSync as readFileSync6 } from "fs";
130735
+ import { readFileSync as readFileSync7 } from "fs";
130541
130736
  init_output();
130542
130737
  var VALID_SCOPES = ["agents", "instances", "chats"];
130543
130738
  function assertScope(scope) {
@@ -130555,9 +130750,9 @@ async function resolveScopedId(scope, id) {
130555
130750
  function readJsonArg(raw2) {
130556
130751
  let body = raw2;
130557
130752
  if (body === "-") {
130558
- body = readFileSync6(0, "utf8");
130753
+ body = readFileSync7(0, "utf8");
130559
130754
  } else if (body.startsWith("@")) {
130560
- body = readFileSync6(body.slice(1), "utf8");
130755
+ body = readFileSync7(body.slice(1), "utf8");
130561
130756
  }
130562
130757
  try {
130563
130758
  return JSON.parse(body);
@@ -130709,8 +130904,8 @@ function createHistoryCommand() {
130709
130904
  }
130710
130905
 
130711
130906
  // src/commands/imagine.ts
130712
- import { writeFileSync as writeFileSync7 } from "fs";
130713
- import { basename as basename2, dirname as dirname3, extname as extname2, join as join12 } from "path";
130907
+ import { writeFileSync as writeFileSync8 } from "fs";
130908
+ import { basename as basename2, dirname as dirname3, extname as extname2, join as join13 } from "path";
130714
130909
  init_output();
130715
130910
  var ALLOWED_ASPECT_RATIOS = ["1:1", "4:3", "3:4", "16:9", "9:16", "3:2", "2:3"];
130716
130911
  function extensionForMime(mimeType) {
@@ -130725,9 +130920,9 @@ function buildOutputPath(outputBase, index, total, mimeType) {
130725
130920
  const ext = extname2(outputBase) || extensionForMime(mimeType);
130726
130921
  const stem = basename2(outputBase, extname2(outputBase));
130727
130922
  if (total <= 1) {
130728
- return join12(dir, `${stem}${ext}`);
130923
+ return join13(dir, `${stem}${ext}`);
130729
130924
  }
130730
- return join12(dir, `${stem}-${index + 1}${ext}`);
130925
+ return join13(dir, `${stem}-${index + 1}${ext}`);
130731
130926
  }
130732
130927
  function parseAspectRatio(value) {
130733
130928
  if (!value)
@@ -130800,7 +130995,7 @@ function createImagineCommand() {
130800
130995
  continue;
130801
130996
  const path = buildOutputPath(options.output, i, result.images.length, image.mimeType);
130802
130997
  try {
130803
- writeFileSync7(path, Buffer.from(image.base64, "base64"));
130998
+ writeFileSync8(path, Buffer.from(image.base64, "base64"));
130804
130999
  savedPaths.push(path);
130805
131000
  } catch (err) {
130806
131001
  const message = err instanceof Error ? err.message : "Unknown error";
@@ -130845,12 +131040,12 @@ function createImagineCommand() {
130845
131040
  }
130846
131041
 
130847
131042
  // src/commands/install.ts
130848
- import { existsSync as existsSync10, mkdirSync as mkdirSync5 } from "fs";
130849
- import { homedir as homedir7 } from "os";
130850
- import { join as join13 } from "path";
131043
+ import { existsSync as existsSync11, mkdirSync as mkdirSync6 } from "fs";
131044
+ import { homedir as homedir8 } from "os";
131045
+ import { join as join14 } from "path";
130851
131046
  init_config();
130852
131047
  init_output();
130853
- var DEFAULT_DATA_DIR2 = join13(homedir7(), ".omni", "data");
131048
+ var DEFAULT_DATA_DIR2 = join14(homedir8(), ".omni", "data");
130854
131049
  function computeDefaultDatabaseUrl() {
130855
131050
  return buildEmbeddedDatabaseUrl();
130856
131051
  }
@@ -130949,13 +131144,13 @@ async function startServices(cfg, forceCleanup, forceSystemd, useCanonicalPgserv
130949
131144
  return false;
130950
131145
  }
130951
131146
  const bundlePath = getServerBundlePath();
130952
- if (!existsSync10(bundlePath)) {
131147
+ if (!existsSync11(bundlePath)) {
130953
131148
  warn(`Server bundle not found at: ${bundlePath}
130954
131149
  Install @automagik/omni from npm: bun add -g @automagik/omni
130955
131150
  Or build locally: make cli-build-full`);
130956
131151
  return false;
130957
131152
  }
130958
- mkdirSync5(getPm2LogDir(), { recursive: true });
131153
+ mkdirSync6(getPm2LogDir(), { recursive: true });
130959
131154
  await installPm2Logrotate();
130960
131155
  const runtimeEnv = buildInstallRuntimeEnv(cfg, forceCleanup, useCanonicalPgserve);
130961
131156
  await runPm2(["delete", PM2_PROCESSES.api]);
@@ -130973,10 +131168,10 @@ async function startServices(cfg, forceCleanup, forceSystemd, useCanonicalPgserv
130973
131168
  return false;
130974
131169
  }
130975
131170
  apiSpinner.succeed(`${PM2_PROCESSES.api} started`);
130976
- if (existsSync10(NATS_BINARY_PATH)) {
131171
+ if (existsSync11(NATS_BINARY_PATH)) {
130977
131172
  const natsSpinner = ora(`Starting ${PM2_PROCESSES.nats}...`).start();
130978
- const natsDataDir = join13(cfg.dataDir, "nats");
130979
- mkdirSync5(natsDataDir, { recursive: true });
131173
+ const natsDataDir = join14(cfg.dataDir, "nats");
131174
+ mkdirSync6(natsDataDir, { recursive: true });
130980
131175
  const natsArgs = buildPm2StartArgs({
130981
131176
  kind: "nats",
130982
131177
  script: NATS_BINARY_PATH,
@@ -132652,7 +132847,7 @@ function createLogsCommand() {
132652
132847
  }
132653
132848
 
132654
132849
  // src/commands/media.ts
132655
- import { createWriteStream as createWriteStream2, existsSync as existsSync12, mkdirSync as mkdirSync7, statSync as statSync4 } from "fs";
132850
+ import { createWriteStream as createWriteStream2, existsSync as existsSync13, mkdirSync as mkdirSync8, statSync as statSync4 } from "fs";
132656
132851
  import { basename as basename4, dirname as dirname4, resolve as resolve2 } from "path";
132657
132852
  import { Readable } from "stream";
132658
132853
  import { pipeline } from "stream/promises";
@@ -132715,14 +132910,14 @@ function resolveOutputPath(outputPath, result) {
132715
132910
  const resolved = resolve2(outputPath);
132716
132911
  if (isDirHint)
132717
132912
  return resolve2(resolved, filename);
132718
- if (existsSync12(resolved) && statSync4(resolved).isDirectory())
132913
+ if (existsSync13(resolved) && statSync4(resolved).isDirectory())
132719
132914
  return resolve2(resolved, filename);
132720
132915
  return resolved;
132721
132916
  }
132722
132917
  async function downloadToFile(url, apiKey, destinationPath) {
132723
132918
  const destDir = dirname4(destinationPath);
132724
- if (!existsSync12(destDir))
132725
- mkdirSync7(destDir, { recursive: true });
132919
+ if (!existsSync13(destDir))
132920
+ mkdirSync8(destDir, { recursive: true });
132726
132921
  const resp = await fetch(url, {
132727
132922
  method: "GET",
132728
132923
  headers: apiKey ? { "x-api-key": apiKey } : undefined
@@ -133675,8 +133870,8 @@ init_output();
133675
133870
  init_src();
133676
133871
  import { execFileSync as execFileSync3, execSync } from "child_process";
133677
133872
  import * as nodeCrypto2 from "crypto";
133678
- import { existsSync as existsSync13, mkdirSync as mkdirSync8, readFileSync as readFileSync8, writeFileSync as writeFileSync8 } from "fs";
133679
- import { homedir as homedir9 } from "os";
133873
+ import { existsSync as existsSync14, mkdirSync as mkdirSync9, readFileSync as readFileSync9, writeFileSync as writeFileSync9 } from "fs";
133874
+ import { homedir as homedir10 } from "os";
133680
133875
  import { dirname as dirname5, resolve as resolve3 } from "path";
133681
133876
  import { createInterface as createInterface2 } from "readline";
133682
133877
  init_config();
@@ -133903,19 +134098,19 @@ async function pairDevice(gatewayUrl, gatewayToken, keypair, spinner) {
133903
134098
  ws.close(1000, "pairing complete");
133904
134099
  }
133905
134100
  }
133906
- var OPENCLAW_CONFIG_PATH = resolve3(homedir9(), ".openclaw", "openclaw.json");
134101
+ var OPENCLAW_CONFIG_PATH = resolve3(homedir10(), ".openclaw", "openclaw.json");
133907
134102
  var PLUGIN_MARKER = "plugin-openclaw/omni.ts";
133908
134103
  function readOpenClawConfig(configPath) {
133909
- if (!existsSync13(configPath))
134104
+ if (!existsSync14(configPath))
133910
134105
  return {};
133911
- const raw2 = readFileSync8(configPath, "utf-8").trim();
134106
+ const raw2 = readFileSync9(configPath, "utf-8").trim();
133912
134107
  if (!raw2)
133913
134108
  return {};
133914
134109
  return JSON.parse(raw2);
133915
134110
  }
133916
134111
  function writeOpenClawConfig(configPath, config2) {
133917
- mkdirSync8(dirname5(configPath), { recursive: true, mode: 448 });
133918
- writeFileSync8(configPath, `${JSON.stringify(config2, null, 2)}
134112
+ mkdirSync9(dirname5(configPath), { recursive: true, mode: 448 });
134113
+ writeFileSync9(configPath, `${JSON.stringify(config2, null, 2)}
133919
134114
  `, { mode: 384 });
133920
134115
  }
133921
134116
  function isPluginRegistered(config2, marker, pluginPath) {
@@ -133947,10 +134142,10 @@ function isValidUuid2(value) {
133947
134142
  }
133948
134143
  function resolvePluginPath(explicit) {
133949
134144
  if (explicit) {
133950
- return existsSync13(explicit) ? resolve3(explicit) : null;
134145
+ return existsSync14(explicit) ? resolve3(explicit) : null;
133951
134146
  }
133952
134147
  const cwdCandidate = resolve3(process.cwd(), "packages/plugin-openclaw/omni.ts");
133953
- return existsSync13(cwdCandidate) ? cwdCandidate : null;
134148
+ return existsSync14(cwdCandidate) ? cwdCandidate : null;
133954
134149
  }
133955
134150
  function registerPlugin(config2, pluginPath, configPath) {
133956
134151
  if (hasOpenClawCli()) {
@@ -135000,7 +135195,7 @@ function createSayCommand() {
135000
135195
  }
135001
135196
 
135002
135197
  // src/commands/see.ts
135003
- import { existsSync as existsSync14, readFileSync as readFileSync9, statSync as statSync5 } from "fs";
135198
+ import { existsSync as existsSync15, readFileSync as readFileSync10, statSync as statSync5 } from "fs";
135004
135199
  import { extname as extname4 } from "path";
135005
135200
  init_output();
135006
135201
  var MIME_BY_EXT = {
@@ -135032,7 +135227,7 @@ function parseMaxTokens(value) {
135032
135227
  return n2;
135033
135228
  }
135034
135229
  function loadMedia(file) {
135035
- if (!existsSync14(file)) {
135230
+ if (!existsSync15(file)) {
135036
135231
  error(`File not found: ${file}`);
135037
135232
  }
135038
135233
  const stat = statSync5(file);
@@ -135043,7 +135238,7 @@ function loadMedia(file) {
135043
135238
  error(`File is empty: ${file}`);
135044
135239
  }
135045
135240
  try {
135046
- return { buffer: readFileSync9(file), mimeType: guessMimeType(file) };
135241
+ return { buffer: readFileSync10(file), mimeType: guessMimeType(file) };
135047
135242
  } catch (err2) {
135048
135243
  const message2 = err2 instanceof Error ? err2.message : "Unknown error";
135049
135244
  return error(`Failed to read ${file}: ${message2}`);
@@ -135118,7 +135313,7 @@ function createSeeCommand() {
135118
135313
  }
135119
135314
 
135120
135315
  // src/commands/send.ts
135121
- import { existsSync as existsSync15, readFileSync as readFileSync10 } from "fs";
135316
+ import { existsSync as existsSync16, readFileSync as readFileSync11 } from "fs";
135122
135317
  import { basename as basename5, extname as extname5 } from "path";
135123
135318
  init_source();
135124
135319
  init_config();
@@ -135138,7 +135333,7 @@ function getMediaType2(path) {
135138
135333
  return "document";
135139
135334
  }
135140
135335
  function readFileAsBase64(path) {
135141
- const buffer3 = readFileSync10(path);
135336
+ const buffer3 = readFileSync11(path);
135142
135337
  return buffer3.toString("base64");
135143
135338
  }
135144
135339
  var messageSenders = {
@@ -135159,7 +135354,7 @@ var messageSenders = {
135159
135354
  const { to, media } = options3;
135160
135355
  if (!to || !media)
135161
135356
  return;
135162
- if (!existsSync15(media)) {
135357
+ if (!existsSync16(media)) {
135163
135358
  error(`File not found: ${media}`);
135164
135359
  return;
135165
135360
  }
@@ -135691,9 +135886,9 @@ function pickFilename(mimeType, provider) {
135691
135886
  }
135692
135887
 
135693
135888
  // src/commands/start.ts
135694
- import { existsSync as existsSync16, mkdirSync as mkdirSync9 } from "fs";
135695
- import { homedir as homedir10 } from "os";
135696
- import { join as join15 } from "path";
135889
+ import { existsSync as existsSync17, mkdirSync as mkdirSync10 } from "fs";
135890
+ import { homedir as homedir11 } from "os";
135891
+ import { join as join16 } from "path";
135697
135892
  init_config();
135698
135893
  init_output();
135699
135894
  var START_HEALTH_TIMEOUT_MS = 1e4;
@@ -135702,12 +135897,12 @@ async function runStart() {
135702
135897
  pm2NotFoundError();
135703
135898
  }
135704
135899
  const bundlePath = getServerBundlePath();
135705
- if (!existsSync16(bundlePath)) {
135900
+ if (!existsSync17(bundlePath)) {
135706
135901
  bundleNotFoundError(bundlePath);
135707
135902
  }
135708
135903
  const serverConfig = loadServerConfig();
135709
135904
  const apiPort = serverConfig.port;
135710
- mkdirSync9(getPm2LogDir(), { recursive: true });
135905
+ mkdirSync10(getPm2LogDir(), { recursive: true });
135711
135906
  info(`Starting ${PM2_PROCESSES.api} (port ${apiPort})...`);
135712
135907
  const cliConfig = loadConfig();
135713
135908
  const env2 = buildRuntimeEnv(serverConfig, cliConfig);
@@ -135723,11 +135918,11 @@ async function runStart() {
135723
135918
  error(`Failed to start ${PM2_PROCESSES.api} (pm2 exit code ${apiCode})`, undefined, 1);
135724
135919
  return;
135725
135920
  }
135726
- const natsPath = join15(homedir10(), ".omni", "nats-server");
135727
- if (existsSync16(natsPath)) {
135921
+ const natsPath = join16(homedir11(), ".omni", "nats-server");
135922
+ if (existsSync17(natsPath)) {
135728
135923
  info(`Starting ${PM2_PROCESSES.nats}...`);
135729
- const natsDataDir = join15(serverConfig.dataDir, "nats");
135730
- mkdirSync9(natsDataDir, { recursive: true });
135924
+ const natsDataDir = join16(serverConfig.dataDir, "nats");
135925
+ mkdirSync10(natsDataDir, { recursive: true });
135731
135926
  const natsArgs = buildPm2StartArgs({
135732
135927
  kind: "nats",
135733
135928
  script: natsPath,
@@ -136147,8 +136342,8 @@ function createTurnsCommand() {
136147
136342
  }
136148
136343
 
136149
136344
  // src/commands/update.ts
136150
- import { existsSync as existsSync18 } from "fs";
136151
- import { join as join17 } from "path";
136345
+ import { existsSync as existsSync19 } from "fs";
136346
+ import { join as join18 } from "path";
136152
136347
  import { createInterface as createInterface3 } from "readline";
136153
136348
  init_source();
136154
136349
  init_config();
@@ -136430,9 +136625,9 @@ async function cleanupLegacyArtifacts(skipList) {
136430
136625
  init_output();
136431
136626
 
136432
136627
  // src/update-diagnostics.ts
136433
- import { existsSync as existsSync17, mkdirSync as mkdirSync10, readFileSync as readFileSync11, writeFileSync as writeFileSync9 } from "fs";
136434
- import { homedir as homedir11 } from "os";
136435
- import { join as join16 } from "path";
136628
+ import { existsSync as existsSync18, mkdirSync as mkdirSync11, readFileSync as readFileSync12, writeFileSync as writeFileSync10 } from "fs";
136629
+ import { homedir as homedir12 } from "os";
136630
+ import { join as join17 } from "path";
136436
136631
  var UPDATE_DIAGNOSTICS_SCHEMA_VERSION = 1;
136437
136632
  function createDiagnostics(args) {
136438
136633
  const startedAt = new Date().toISOString();
@@ -136454,18 +136649,18 @@ function createDiagnostics(args) {
136454
136649
  };
136455
136650
  }
136456
136651
  function getDiagnosticsDir() {
136457
- const base = process.env.OMNI_CONFIG_DIR ?? join16(homedir11(), ".omni");
136458
- return join16(base, "logs");
136652
+ const base = process.env.OMNI_CONFIG_DIR ?? join17(homedir12(), ".omni");
136653
+ return join17(base, "logs");
136459
136654
  }
136460
136655
  function getDiagnosticsPath(startedAt) {
136461
136656
  const safe = startedAt.replace(/:/g, "-");
136462
- return join16(getDiagnosticsDir(), `update-diagnostics-${safe}.json`);
136657
+ return join17(getDiagnosticsDir(), `update-diagnostics-${safe}.json`);
136463
136658
  }
136464
136659
  function tailFileLines(path, maxLines) {
136465
- if (!existsSync17(path))
136660
+ if (!existsSync18(path))
136466
136661
  return [];
136467
136662
  try {
136468
- const raw2 = readFileSync11(path, "utf8");
136663
+ const raw2 = readFileSync12(path, "utf8");
136469
136664
  const lines = raw2.split(/\r?\n/);
136470
136665
  if (lines.length > 0 && lines[lines.length - 1] === "")
136471
136666
  lines.pop();
@@ -136498,10 +136693,10 @@ function writeDiagnostics(state, exitCode) {
136498
136693
  const dir = getDiagnosticsDir();
136499
136694
  const path = getDiagnosticsPath(state.startedAt);
136500
136695
  try {
136501
- if (!existsSync17(dir)) {
136502
- mkdirSync10(dir, { recursive: true, mode: 448 });
136696
+ if (!existsSync18(dir)) {
136697
+ mkdirSync11(dir, { recursive: true, mode: 448 });
136503
136698
  }
136504
- writeFileSync9(path, `${JSON.stringify(state, null, 2)}
136699
+ writeFileSync10(path, `${JSON.stringify(state, null, 2)}
136505
136700
  `, { mode: 384 });
136506
136701
  return path;
136507
136702
  } catch {
@@ -136672,7 +136867,7 @@ function printVerifySkippedBanner(latest) {
136672
136867
  }
136673
136868
  function detectParallelNpmGlobalInstall(deps) {
136674
136869
  const npmRootFn = deps?.npmRoot ?? defaultNpmRoot;
136675
- const existsFn = deps?.exists ?? existsSync18;
136870
+ const existsFn = deps?.exists ?? existsSync19;
136676
136871
  let root;
136677
136872
  try {
136678
136873
  root = npmRootFn();
@@ -136682,7 +136877,7 @@ function detectParallelNpmGlobalInstall(deps) {
136682
136877
  if (root === null || root.length === 0) {
136683
136878
  return { detected: false, skipped: "npm-not-on-path" };
136684
136879
  }
136685
- const candidate = join17(root, "@automagik", "omni");
136880
+ const candidate = join18(root, "@automagik", "omni");
136686
136881
  if (existsFn(candidate)) {
136687
136882
  return { detected: true, path: candidate };
136688
136883
  }
@@ -137079,9 +137274,9 @@ function createVoiceCommand() {
137079
137274
  const startTime = Date.now();
137080
137275
  let saveDir = "";
137081
137276
  if (opts.save) {
137082
- const { mkdirSync: mkdirSync11 } = await import("fs");
137277
+ const { mkdirSync: mkdirSync12 } = await import("fs");
137083
137278
  saveDir = opts.save;
137084
- mkdirSync11(saveDir, { recursive: true });
137279
+ mkdirSync12(saveDir, { recursive: true });
137085
137280
  info(`Saving audio to: ${saveDir}`);
137086
137281
  }
137087
137282
  ws.onopen = () => {
@@ -137305,17 +137500,17 @@ init_config();
137305
137500
  init_output();
137306
137501
 
137307
137502
  // src/manifest-pin.ts
137308
- import { existsSync as existsSync19, readFileSync as readFileSync12, renameSync as renameSync3, writeFileSync as writeFileSync10 } from "fs";
137309
- import { homedir as homedir12 } from "os";
137310
- import { join as join18 } from "path";
137503
+ import { existsSync as existsSync20, readFileSync as readFileSync13, renameSync as renameSync3, writeFileSync as writeFileSync11 } from "fs";
137504
+ import { homedir as homedir13 } from "os";
137505
+ import { join as join19 } from "path";
137311
137506
  var PACKAGE_NAME2 = "@automagik/omni";
137312
- var BUN_GLOBAL_MANIFEST = join18(homedir12(), ".bun", "install", "global", "package.json");
137507
+ var BUN_GLOBAL_MANIFEST = join19(homedir13(), ".bun", "install", "global", "package.json");
137313
137508
  function pinManifestEntry(manifestPath, exactVersion) {
137314
- if (!existsSync19(manifestPath))
137509
+ if (!existsSync20(manifestPath))
137315
137510
  return false;
137316
137511
  let manifest;
137317
137512
  try {
137318
- manifest = JSON.parse(readFileSync12(manifestPath, "utf-8"));
137513
+ manifest = JSON.parse(readFileSync13(manifestPath, "utf-8"));
137319
137514
  } catch {
137320
137515
  return false;
137321
137516
  }
@@ -137341,7 +137536,7 @@ function pinManifestEntry(manifestPath, exactVersion) {
137341
137536
  return false;
137342
137537
  const tmp = `${manifestPath}.tmp.${process.pid}`;
137343
137538
  try {
137344
- writeFileSync10(tmp, `${JSON.stringify(manifest, null, 2)}
137539
+ writeFileSync11(tmp, `${JSON.stringify(manifest, null, 2)}
137345
137540
  `, { mode: 420 });
137346
137541
  renameSync3(tmp, manifestPath);
137347
137542
  } catch {
@@ -1 +1 @@
1
- {"version":3,"file":"canonical-pgserve.d.ts","sourceRoot":"","sources":["../../src/lib/canonical-pgserve.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AA4OH;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAepE;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,iCAAiC,CACrD,WAAW,EAAE,OAAO,EACpB,GAAG,EAAE;IAAE,WAAW,EAAE,MAAM,CAAA;CAAE,GAC3B,OAAO,CAAC,OAAO,CAAC,CA6BlB;AAwDD;;;;;;;;;GASG;AACH,wBAAgB,0BAA0B,IAAI,MAAM,CASnD;AAuCD;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAC1B;IAAE,MAAM,EAAE,kBAAkB,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GACnD;IAAE,MAAM,EAAE,uBAAuB,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GACxD;IAAE,MAAM,EAAE,QAAQ,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAEnF;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,cAAc,CAAC,kBAAkB,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC,CA6D5F;AAED;;;;;;;;GAQG;AACH,wBAAsB,0BAA0B,CAC9C,IAAI,EAAE,kBAAkB,EACxB,oBAAoB,EAAE,MAAM,GAC3B,OAAO,CAAC;IAAE,MAAM,EAAE,UAAU,GAAG,SAAS,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAoCpE"}
1
+ {"version":3,"file":"canonical-pgserve.d.ts","sourceRoot":"","sources":["../../src/lib/canonical-pgserve.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AA8OH;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA6BpE;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,iCAAiC,CACrD,WAAW,EAAE,OAAO,EACpB,GAAG,EAAE;IAAE,WAAW,EAAE,MAAM,CAAA;CAAE,GAC3B,OAAO,CAAC,OAAO,CAAC,CA6BlB;AAwDD;;;;;;;;;GASG;AACH,wBAAgB,0BAA0B,IAAI,MAAM,CASnD;AAuCD;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAC1B;IAAE,MAAM,EAAE,kBAAkB,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GACnD;IAAE,MAAM,EAAE,uBAAuB,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GACxD;IAAE,MAAM,EAAE,QAAQ,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAEnF;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,cAAc,CAAC,kBAAkB,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC,CA6D5F;AAED;;;;;;;;GAQG;AACH,wBAAsB,0BAA0B,CAC9C,IAAI,EAAE,kBAAkB,EACxB,oBAAoB,EAAE,MAAM,GAC3B,OAAO,CAAC;IAAE,MAAM,EAAE,UAAU,GAAG,SAAS,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAoCpE"}
@@ -75,21 +75,25 @@ export declare function resolvePgserveControlSocketPath(): string;
75
75
  export declare function probeCanonicalSocketSync(): boolean;
76
76
  /**
77
77
  * Build a `postgresql://` URL pointing at the given transport, using the
78
- * supplied database name. Mirrors the URL shapes documented in
79
- * SHARED-DESIGN.md §5.3 (omni-side scope).
78
+ * supplied database name.
80
79
  *
81
- * UDS shape: `postgresql://postgres:postgres@localhost/omni?host=/run/user/1000/pgserve&port=5432`
80
+ * UDS shape: `postgresql://postgres:postgres@localhost/omni` (plain — no
81
+ * libpq `?host=` query param). Socket routing happens via the
82
+ * PGHOST/PGPORT env vars `buildRuntimeEnv` publishes alongside this URL.
82
83
  * TCP shape: `postgresql://postgres:postgres@127.0.0.1:5432/omni`
83
84
  *
84
- * UDS placeholder host (`localhost`) is intentional. The previous form
85
- * `postgresql://user:pass@/db?host=…` is libpq-valid but rejects when
86
- * parsed by Node's WHATWG `URL()` constructor with "Invalid URL"
87
- * (empty authority between `@` and `/`). omni-api's startup pipeline
88
- * runs `new URL(DATABASE_URL)` for validation/redaction, which
89
- * crashloops `omni-api` with `TypeError [ERR_INVALID_URL]` whenever
90
- * the canonical UDS is reachable. libpq still routes to the socket
91
- * because the `host=` query parameter overrides the URL host —
92
- * placeholder is never dialed.
85
+ * Why no `?host=` for UDS: postgres.js (omni-api's client) rejects URLs
86
+ * carrying the libpq `?host=` query parameter with the error
87
+ * `unrecognized configuration parameter "host"`. That parameter is a
88
+ * libpq-only convention; postgres.js parses URL query params strictly as
89
+ * connection options and bails. Earlier iterations of this helper tried
90
+ * three shapes that all failed for postgres.js:
91
+ * - `postgresql://user:pass@/db?host=/sock` Node WHATWG URL: Invalid URL
92
+ * - `postgresql://user:pass@localhost/db?host=/sock` postgres.js:
93
+ * "unrecognized configuration parameter host"
94
+ * The working shape is the plain `@localhost/db` form, with the actual
95
+ * socket path supplied to postgres.js via PGHOST/PGPORT env vars (which
96
+ * postgres.js inherits as connection defaults).
93
97
  *
94
98
  * The username/password pair is preserved (not derived from the transport)
95
99
  * because omni's pgserve consumer keeps libpq peer-auth via password —
@@ -1 +1 @@
1
- {"version":3,"file":"pgserve-transport.d.ts","sourceRoot":"","sources":["../../src/lib/pgserve-transport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAQH,8FAA8F;AAC9F,eAAO,MAAM,iBAAiB,OAAO,CAAC;AActC;;;;;;GAMG;AACH,MAAM,MAAM,gBAAgB,GACxB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACjD;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAEhD;;;;;;GAMG;AACH,wBAAgB,uBAAuB,IAAI,MAAM,CAIhD;AAED;;;GAGG;AACH,wBAAgB,6BAA6B,IAAI,MAAM,CAEtD;AAED;;;;GAIG;AACH,wBAAgB,+BAA+B,IAAI,MAAM,CAExD;AAED;;;;;;;GAOG;AACH,wBAAgB,wBAAwB,IAAI,OAAO,CAElD;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,4BAA4B,CAC1C,SAAS,EAAE,gBAAgB,EAC3B,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAO,GACrD,MAAM,CAcR;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,uBAAuB,IAAI,OAAO,CAAC,gBAAgB,CAAC,CA+BzE"}
1
+ {"version":3,"file":"pgserve-transport.d.ts","sourceRoot":"","sources":["../../src/lib/pgserve-transport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAQH,8FAA8F;AAC9F,eAAO,MAAM,iBAAiB,OAAO,CAAC;AActC;;;;;;GAMG;AACH,MAAM,MAAM,gBAAgB,GACxB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACjD;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAEhD;;;;;;GAMG;AACH,wBAAgB,uBAAuB,IAAI,MAAM,CAIhD;AAED;;;GAGG;AACH,wBAAgB,6BAA6B,IAAI,MAAM,CAEtD;AAED;;;;GAIG;AACH,wBAAgB,+BAA+B,IAAI,MAAM,CAExD;AAED;;;;;;;GAOG;AACH,wBAAgB,wBAAwB,IAAI,OAAO,CAElD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,4BAA4B,CAC1C,SAAS,EAAE,gBAAgB,EAC3B,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAO,GACrD,MAAM,CAWR;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,uBAAuB,IAAI,OAAO,CAAC,gBAAgB,CAAC,CA+BzE"}
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Dedicated-role cutover — omni-side scoped non-superuser identity.
3
+ *
4
+ * Wish parity: mirrors genie's `src/lib/role-cutover.ts` (the
5
+ * `genie-dedicated-role-cutover` wish). Omni historically connected to
6
+ * canonical pgserve/autopg as the cluster superuser `postgres:postgres`.
7
+ * A bad omni migration or a compromised omni-api could therefore
8
+ * `DROP DATABASE genie`, exhaust the cluster, create roles, etc. —
9
+ * the same blast-radius problem genie solved with role-cutover.
10
+ *
11
+ * This module provisions a dedicated NON-superuser role scoped to omni's
12
+ * own `omni` database, persists the credential in a sentinel file, and
13
+ * is consumed by `buildRuntimeEnv` to rewrite `DATABASE_URL` to the
14
+ * scoped role at omni-api startup.
15
+ *
16
+ * Scope (MVP):
17
+ * - Provision `pgserve_omni_<fp12>_role` with grants scoped to `omni` DB
18
+ * - Generate a random password at provisioning, persist in sentinel
19
+ * - Idempotent: existing role → refresh grants, regenerate sentinel from
20
+ * password (preserves the operator-visible role identifier)
21
+ * - Kill switch: `OMNI_ROLE_CUTOVER=0` forces legacy `postgres`/`postgres`
22
+ * - Best-effort: any failure logs a warning and falls back to legacy creds
23
+ *
24
+ * Out of scope (deferred to a follow-up wish, matching genie's groups):
25
+ * - Advisory-lock concurrency guards (multi-host simultaneous installs)
26
+ * - Full event sink with audit log + sentinel rotation
27
+ * - Per-tenant fingerprint stability handling beyond package.json
28
+ * - doctor.ts validation that the scoped role is in active use
29
+ * - Migration of pre-cutover objects' ownership to the scoped role
30
+ */
31
+ /**
32
+ * Compute the scoped role name for an omni install. Deterministic — same
33
+ * install always produces the same role name across reruns.
34
+ */
35
+ export declare function deriveOmniScopedRoleName(): string;
36
+ export interface OmniRoleCutoverSentinel {
37
+ /** The provisioned role name (matches deriveOmniScopedRoleName output). */
38
+ roleName: string;
39
+ /** Database the role is scoped to (always `omni`). */
40
+ database: string;
41
+ /** Generated password (alphanumeric). */
42
+ password: string;
43
+ /** ISO timestamp of provisioning. */
44
+ provisionedAt: string;
45
+ }
46
+ export declare function readOmniCutoverSentinel(): OmniRoleCutoverSentinel | null;
47
+ export declare function clearOmniCutoverSentinel(): void;
48
+ export declare function isOmniRoleCutoverEnabled(): boolean;
49
+ export interface EnsureOmniScopedRoleOptions {
50
+ /** Path to autopg's canonical Unix socket dir (e.g. /run/user/1000/pgserve). */
51
+ socketDir: string;
52
+ /** Canonical port (default 5432). */
53
+ port?: number;
54
+ /** Database to scope grants to (default 'omni'). */
55
+ database?: string;
56
+ /** Force-enable bypassing the OMNI_ROLE_CUTOVER kill switch (tests). */
57
+ enabled?: boolean;
58
+ }
59
+ export type EnsureOmniScopedRoleResult = {
60
+ status: 'provisioned' | 'refreshed';
61
+ roleName: string;
62
+ } | {
63
+ status: 'skipped';
64
+ reason: string;
65
+ };
66
+ /**
67
+ * Idempotently provision omni's scoped role + grants on canonical pgserve.
68
+ *
69
+ * Side effects:
70
+ * - CREATE ROLE if not exists (or ALTER PASSWORD if exists to keep sentinel in sync)
71
+ * - GRANTs scoped to the omni database
72
+ * - Sentinel written at ~/.omni/scoped-role.json
73
+ *
74
+ * Failure mode: best-effort. Any psql / spawn failure returns
75
+ * `{ status: 'skipped', reason }` and emits a stderr warn. omni-api
76
+ * continues with the legacy `postgres:postgres` path.
77
+ */
78
+ export declare function ensureOmniScopedRole(opts: EnsureOmniScopedRoleOptions): Promise<EnsureOmniScopedRoleResult>;
79
+ export interface ScopedCredentialOverride {
80
+ username: string;
81
+ password: string;
82
+ roleName: string;
83
+ }
84
+ /**
85
+ * Returns the scoped-role credentials to override `postgres:postgres` with
86
+ * at runtime, or null when cutover is disabled / sentinel missing / kill
87
+ * switch active. Pure: no DB roundtrip.
88
+ *
89
+ * Consumed by buildRuntimeEnv when constructing DATABASE_URL.
90
+ */
91
+ export declare function resolveOmniScopedCredentials(): ScopedCredentialOverride | null;
92
+ //# sourceMappingURL=role-cutover.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"role-cutover.d.ts","sourceRoot":"","sources":["../../src/lib/role-cutover.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AA+BH;;;GAGG;AACH,wBAAgB,wBAAwB,IAAI,MAAM,CAUjD;AAqBD,MAAM,WAAW,uBAAuB;IACtC,2EAA2E;IAC3E,QAAQ,EAAE,MAAM,CAAC;IACjB,sDAAsD;IACtD,QAAQ,EAAE,MAAM,CAAC;IACjB,yCAAyC;IACzC,QAAQ,EAAE,MAAM,CAAC;IACjB,qCAAqC;IACrC,aAAa,EAAE,MAAM,CAAC;CACvB;AAUD,wBAAgB,uBAAuB,IAAI,uBAAuB,GAAG,IAAI,CAkBxE;AASD,wBAAgB,wBAAwB,IAAI,IAAI,CAM/C;AAMD,wBAAgB,wBAAwB,IAAI,OAAO,CAElD;AAWD,MAAM,WAAW,2BAA2B;IAC1C,gFAAgF;IAChF,SAAS,EAAE,MAAM,CAAC;IAClB,qCAAqC;IACrC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,oDAAoD;IACpD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,wEAAwE;IACxE,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,MAAM,0BAA0B,GAClC;IAAE,MAAM,EAAE,aAAa,GAAG,WAAW,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GACzD;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAE1C;;;;;;;;;;;GAWG;AACH,wBAAsB,oBAAoB,CAAC,IAAI,EAAE,2BAA2B,GAAG,OAAO,CAAC,0BAA0B,CAAC,CAyEjH;AA0CD,MAAM,WAAW,wBAAwB;IACvC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;GAMG;AACH,wBAAgB,4BAA4B,IAAI,wBAAwB,GAAG,IAAI,CAc9E"}
@@ -101,6 +101,15 @@ export declare function resolvePgservePort(serverConfig: ServerConfig): number;
101
101
  * This function never reads `process.env.DATABASE_URL`.
102
102
  */
103
103
  export declare function resolveDatabaseUrl(serverConfig: ServerConfig): string;
104
+ /**
105
+ * Replace the userinfo in a postgresql:// URL with the scoped-role
106
+ * credentials. Returns the URL unchanged when `creds` is null. Pure;
107
+ * URL-safe via WHATWG URL.
108
+ */
109
+ export declare function applyScopedCredentials(url: string, creds: {
110
+ username: string;
111
+ password: string;
112
+ } | null): string;
104
113
  /**
105
114
  * Build the complete runtime env for the omni-api process.
106
115
  *
@@ -1 +1 @@
1
- {"version":3,"file":"runtime-env.d.ts","sourceRoot":"","sources":["../src/runtime-env.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAGH,OAAO,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAQxD;;;GAGG;AACH,MAAM,MAAM,UAAU,GAAG;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IAQrB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,gBAAgB,EAAE,MAAM,CAAC;IACzB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAQF;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,oBAAoB,OAAO,CAAC;AAEzC,0EAA0E;AAC1E,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAE/D;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,WAAW,GAAE,MAA6B,GAAG,MAAM,CAE3F;AAED;;;;;GAKG;AACH,wBAAgB,+BAA+B,IAAI,MAAM,CAKxD;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,YAAY,EAAE,YAAY,GAAG,MAAM,CAMrE;AAgBD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,kBAAkB,CAAC,YAAY,EAAE,YAAY,GAAG,MAAM,CAiBrE;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,eAAe,CAAC,YAAY,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,GAAG,UAAU,CA+BzF"}
1
+ {"version":3,"file":"runtime-env.d.ts","sourceRoot":"","sources":["../src/runtime-env.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAGH,OAAO,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AASxD;;;GAGG;AACH,MAAM,MAAM,UAAU,GAAG;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IAQrB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,gBAAgB,EAAE,MAAM,CAAC;IACzB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAQF;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,oBAAoB,OAAO,CAAC;AAEzC,0EAA0E;AAC1E,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAE/D;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,WAAW,GAAE,MAA6B,GAAG,MAAM,CAE3F;AAED;;;;;GAKG;AACH,wBAAgB,+BAA+B,IAAI,MAAM,CAKxD;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,YAAY,EAAE,YAAY,GAAG,MAAM,CAMrE;AAgBD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,kBAAkB,CAAC,YAAY,EAAE,YAAY,GAAG,MAAM,CAiBrE;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,GAAG,MAAM,CAWhH;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,eAAe,CAAC,YAAY,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,GAAG,UAAU,CAqCzF"}
@@ -230137,7 +230137,7 @@ var init_sentry_scrub = __esm(() => {
230137
230137
  var require_package8 = __commonJS((exports, module) => {
230138
230138
  module.exports = {
230139
230139
  name: "@omni/api",
230140
- version: "2.260520.9",
230140
+ version: "2.260520.11",
230141
230141
  type: "module",
230142
230142
  exports: {
230143
230143
  ".": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@automagik/omni",
3
- "version": "2.260520.9",
3
+ "version": "2.260520.11",
4
4
  "description": "LLM-optimized CLI for Omni",
5
5
  "type": "module",
6
6
  "bin": {