@automagik/omni 2.260520.10 → 2.260520.12
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 +344 -143
- package/dist/lib/canonical-pgserve.d.ts.map +1 -1
- package/dist/lib/role-cutover.d.ts +92 -0
- package/dist/lib/role-cutover.d.ts.map +1 -0
- package/dist/runtime-env.d.ts +9 -0
- package/dist/runtime-env.d.ts.map +1 -1
- package/dist/server/index.js +1 -1
- package/package.json +1 -1
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:
|
|
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 (!
|
|
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
|
|
61935
|
-
import { join as
|
|
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 =
|
|
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(
|
|
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
|
|
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 =
|
|
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((
|
|
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((
|
|
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
|
|
67806
|
-
const tableName2 = getTableLikeName(
|
|
67807
|
-
if (typeof tableName2 === "string" && !is(
|
|
67808
|
-
const fromFields = this.getTableLikeFields(
|
|
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
|
|
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 =
|
|
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.
|
|
124070
|
+
version: "2.260520.12",
|
|
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
|
|
125271
|
+
import { join as join7 } from "path";
|
|
125272
125272
|
|
|
125273
125273
|
// src/lib/pgserve-transport.ts
|
|
125274
125274
|
import { existsSync as existsSync4 } from "fs";
|
|
@@ -125335,6 +125335,184 @@ function buildDatabaseUrlForTransport(transport, database, options = {}) {
|
|
|
125335
125335
|
return `postgresql://${auth}@${transport.host}:${transport.port}/${encodeURIComponent(database)}`;
|
|
125336
125336
|
}
|
|
125337
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, CREATE 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
|
+
"CREATE EXTENSION IF NOT EXISTS pgcrypto;",
|
|
125447
|
+
`ALTER SCHEMA public OWNER TO "${roleName}";`,
|
|
125448
|
+
`GRANT USAGE, CREATE ON SCHEMA public TO "${roleName}";`,
|
|
125449
|
+
`GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO "${roleName}";`,
|
|
125450
|
+
`GRANT USAGE, SELECT, UPDATE ON ALL SEQUENCES IN SCHEMA public TO "${roleName}";`,
|
|
125451
|
+
`ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO "${roleName}";`,
|
|
125452
|
+
`ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT USAGE, SELECT, UPDATE ON SEQUENCES TO "${roleName}";`,
|
|
125453
|
+
`ALTER DEFAULT PRIVILEGES FOR ROLE "${roleName}" IN SCHEMA public GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO "${roleName}";`,
|
|
125454
|
+
`ALTER DEFAULT PRIVILEGES FOR ROLE "${roleName}" IN SCHEMA public GRANT USAGE, SELECT, UPDATE ON SEQUENCES TO "${roleName}";`
|
|
125455
|
+
].join(`
|
|
125456
|
+
`);
|
|
125457
|
+
const grantsOk = await runPsql(grantsScript, { socketDir: opts.socketDir, port, database });
|
|
125458
|
+
if (!grantsOk) {
|
|
125459
|
+
return { status: "skipped", reason: "psql grant step failed" };
|
|
125460
|
+
}
|
|
125461
|
+
writeOmniCutoverSentinel({
|
|
125462
|
+
roleName,
|
|
125463
|
+
database,
|
|
125464
|
+
password,
|
|
125465
|
+
provisionedAt: new Date().toISOString()
|
|
125466
|
+
});
|
|
125467
|
+
return existing && existing.roleName === roleName ? { status: "refreshed", roleName } : { status: "provisioned", roleName };
|
|
125468
|
+
}
|
|
125469
|
+
async function runPsql(sql, opts) {
|
|
125470
|
+
const proc = Bun.spawn({
|
|
125471
|
+
cmd: [
|
|
125472
|
+
"psql",
|
|
125473
|
+
"-h",
|
|
125474
|
+
opts.socketDir,
|
|
125475
|
+
"-p",
|
|
125476
|
+
String(opts.port),
|
|
125477
|
+
"-U",
|
|
125478
|
+
"postgres",
|
|
125479
|
+
"-d",
|
|
125480
|
+
opts.database,
|
|
125481
|
+
"-v",
|
|
125482
|
+
"ON_ERROR_STOP=1",
|
|
125483
|
+
"-c",
|
|
125484
|
+
sql
|
|
125485
|
+
],
|
|
125486
|
+
stdout: "pipe",
|
|
125487
|
+
stderr: "pipe",
|
|
125488
|
+
env: { ...process.env, PGPASSWORD: "postgres" }
|
|
125489
|
+
});
|
|
125490
|
+
const stderr = await new Response(proc.stderr).text();
|
|
125491
|
+
const code = await proc.exited;
|
|
125492
|
+
if (code !== 0) {
|
|
125493
|
+
process.stderr.write(`role-cutover: psql exited ${code}: ${stderr.trim()}
|
|
125494
|
+
`);
|
|
125495
|
+
return false;
|
|
125496
|
+
}
|
|
125497
|
+
return true;
|
|
125498
|
+
}
|
|
125499
|
+
function resolveOmniScopedCredentials() {
|
|
125500
|
+
if (!isOmniRoleCutoverEnabled())
|
|
125501
|
+
return null;
|
|
125502
|
+
const sentinel = readOmniCutoverSentinel();
|
|
125503
|
+
if (!sentinel)
|
|
125504
|
+
return null;
|
|
125505
|
+
const expected = deriveOmniScopedRoleName();
|
|
125506
|
+
if (sentinel.roleName !== expected) {
|
|
125507
|
+
return null;
|
|
125508
|
+
}
|
|
125509
|
+
return {
|
|
125510
|
+
username: sentinel.roleName,
|
|
125511
|
+
password: sentinel.password,
|
|
125512
|
+
roleName: sentinel.roleName
|
|
125513
|
+
};
|
|
125514
|
+
}
|
|
125515
|
+
|
|
125338
125516
|
// src/runtime-env.ts
|
|
125339
125517
|
var LEGACY_DEFAULT_DATABASE_URL = "postgresql://postgres:postgres@localhost:5432/omni";
|
|
125340
125518
|
var LEGACY_PHASE2_DATABASE_URL = "postgresql://postgres:postgres@localhost:8432/omni";
|
|
@@ -125363,21 +125541,34 @@ function resolveDatabaseUrl(serverConfig) {
|
|
|
125363
125541
|
}
|
|
125364
125542
|
return buildEmbeddedDatabaseUrl(resolvePgservePort(serverConfig));
|
|
125365
125543
|
}
|
|
125544
|
+
function applyScopedCredentials(url, creds) {
|
|
125545
|
+
if (!creds)
|
|
125546
|
+
return url;
|
|
125547
|
+
try {
|
|
125548
|
+
const parsed = new URL(url);
|
|
125549
|
+
parsed.username = encodeURIComponent(creds.username);
|
|
125550
|
+
parsed.password = encodeURIComponent(creds.password);
|
|
125551
|
+
return parsed.toString();
|
|
125552
|
+
} catch {
|
|
125553
|
+
return url;
|
|
125554
|
+
}
|
|
125555
|
+
}
|
|
125366
125556
|
function buildRuntimeEnv(serverConfig, cliConfig) {
|
|
125367
125557
|
const pgservePort = resolvePgservePort(serverConfig);
|
|
125368
125558
|
const udsActive = probeCanonicalSocketSync();
|
|
125369
125559
|
const pgHost = udsActive ? resolvePgserveSocketDir() : "";
|
|
125370
125560
|
const pgPort = udsActive ? String(CANONICAL_PG_PORT) : "";
|
|
125561
|
+
const scopedCreds = resolveOmniScopedCredentials();
|
|
125371
125562
|
return {
|
|
125372
125563
|
API_PORT: String(serverConfig.port),
|
|
125373
|
-
DATABASE_URL: resolveDatabaseUrl(serverConfig),
|
|
125564
|
+
DATABASE_URL: applyScopedCredentials(resolveDatabaseUrl(serverConfig), scopedCreds),
|
|
125374
125565
|
PGHOST: pgHost,
|
|
125375
125566
|
PGPORT: pgPort,
|
|
125376
125567
|
OMNI_API_KEY: cliConfig.apiKey ?? "",
|
|
125377
|
-
MEDIA_STORAGE_PATH:
|
|
125378
|
-
OMNI_PACKAGES_DIR:
|
|
125568
|
+
MEDIA_STORAGE_PATH: join7(serverConfig.dataDir, "media"),
|
|
125569
|
+
OMNI_PACKAGES_DIR: join7(serverConfig.dataDir, "packages"),
|
|
125379
125570
|
PGSERVE_EMBEDDED: "false",
|
|
125380
|
-
PGSERVE_DATA:
|
|
125571
|
+
PGSERVE_DATA: join7(serverConfig.dataDir, "pgserve"),
|
|
125381
125572
|
PGSERVE_PORT: String(pgservePort),
|
|
125382
125573
|
NATS_URL: "nats://localhost:4222",
|
|
125383
125574
|
NODE_ENV: serverConfig.nodeEnv,
|
|
@@ -127691,9 +127882,9 @@ function createDeadLettersCommand() {
|
|
|
127691
127882
|
}
|
|
127692
127883
|
|
|
127693
127884
|
// src/commands/doctor.ts
|
|
127694
|
-
import { existsSync as
|
|
127695
|
-
import { homedir as
|
|
127696
|
-
import { join as
|
|
127885
|
+
import { existsSync as existsSync9, readdirSync as readdirSync2, statSync as statSync2 } from "fs";
|
|
127886
|
+
import { homedir as homedir7 } from "os";
|
|
127887
|
+
import { join as join12, resolve } from "path";
|
|
127697
127888
|
init_config();
|
|
127698
127889
|
|
|
127699
127890
|
// src/health.ts
|
|
@@ -127719,14 +127910,14 @@ async function waitForHealth(port, timeoutMs = HEALTH_TIMEOUT_MS) {
|
|
|
127719
127910
|
|
|
127720
127911
|
// src/install-helpers.ts
|
|
127721
127912
|
init_config();
|
|
127722
|
-
import { existsSync as
|
|
127723
|
-
import { homedir as
|
|
127724
|
-
import { join as
|
|
127913
|
+
import { existsSync as existsSync7, readdirSync, writeFileSync as writeFileSync5 } from "fs";
|
|
127914
|
+
import { homedir as homedir5 } from "os";
|
|
127915
|
+
import { join as join9 } from "path";
|
|
127725
127916
|
|
|
127726
127917
|
// src/nats-install.ts
|
|
127727
|
-
import { chmodSync as chmodSync2, existsSync as
|
|
127728
|
-
import { homedir as
|
|
127729
|
-
import { join as
|
|
127918
|
+
import { chmodSync as chmodSync2, existsSync as existsSync6, mkdirSync as mkdirSync4, writeFileSync as writeFileSync4 } from "fs";
|
|
127919
|
+
import { homedir as homedir4 } from "os";
|
|
127920
|
+
import { join as join8 } from "path";
|
|
127730
127921
|
|
|
127731
127922
|
// ../../node_modules/.bun/ora@8.2.0/node_modules/ora/index.js
|
|
127732
127923
|
init_source();
|
|
@@ -128616,8 +128807,8 @@ function ora(options) {
|
|
|
128616
128807
|
|
|
128617
128808
|
// src/nats-install.ts
|
|
128618
128809
|
init_output();
|
|
128619
|
-
var OMNI_DIR =
|
|
128620
|
-
var NATS_BINARY_PATH =
|
|
128810
|
+
var OMNI_DIR = join8(homedir4(), ".omni");
|
|
128811
|
+
var NATS_BINARY_PATH = join8(OMNI_DIR, "nats-server");
|
|
128621
128812
|
var NATS_VERSION = "v2.12.4";
|
|
128622
128813
|
function platformInfo() {
|
|
128623
128814
|
const platform = process.platform;
|
|
@@ -128640,17 +128831,17 @@ async function downloadNats() {
|
|
|
128640
128831
|
const url = `https://github.com/nats-io/nats-server/releases/download/${NATS_VERSION}/${fileName}`;
|
|
128641
128832
|
const spinner = ora(`Downloading NATS ${NATS_VERSION} for ${info2.os}/${info2.arch}...`).start();
|
|
128642
128833
|
try {
|
|
128643
|
-
|
|
128834
|
+
mkdirSync4(OMNI_DIR, { recursive: true, mode: 448 });
|
|
128644
128835
|
const resp = await fetch(url, { signal: AbortSignal.timeout(60000) });
|
|
128645
128836
|
if (!resp.ok) {
|
|
128646
128837
|
spinner.fail(`NATS download failed: HTTP ${resp.status}`);
|
|
128647
128838
|
return false;
|
|
128648
128839
|
}
|
|
128649
|
-
const tarPath =
|
|
128650
|
-
|
|
128840
|
+
const tarPath = join8(OMNI_DIR, fileName);
|
|
128841
|
+
writeFileSync4(tarPath, Buffer.from(await resp.arrayBuffer()));
|
|
128651
128842
|
spinner.text = "Extracting NATS binary...";
|
|
128652
|
-
const tmpDir =
|
|
128653
|
-
|
|
128843
|
+
const tmpDir = join8(OMNI_DIR, "nats-tmp");
|
|
128844
|
+
mkdirSync4(tmpDir, { recursive: true });
|
|
128654
128845
|
const tar = Bun.spawn({ cmd: ["tar", "-xzf", tarPath, "-C", tmpDir], stdout: "pipe", stderr: "pipe" });
|
|
128655
128846
|
const [tarCode, tarErr] = await Promise.all([tar.exited, new Response(tar.stderr).text()]);
|
|
128656
128847
|
if (tarCode !== 0) {
|
|
@@ -128675,7 +128866,7 @@ async function downloadNats() {
|
|
|
128675
128866
|
}
|
|
128676
128867
|
}
|
|
128677
128868
|
async function ensureNats() {
|
|
128678
|
-
if (
|
|
128869
|
+
if (existsSync6(NATS_BINARY_PATH)) {
|
|
128679
128870
|
raw(` \u2713 NATS binary found at ${NATS_BINARY_PATH}`);
|
|
128680
128871
|
return;
|
|
128681
128872
|
}
|
|
@@ -128685,7 +128876,7 @@ async function ensureNats() {
|
|
|
128685
128876
|
|
|
128686
128877
|
// src/install-helpers.ts
|
|
128687
128878
|
init_output();
|
|
128688
|
-
var DEFAULT_DATA_DIR =
|
|
128879
|
+
var DEFAULT_DATA_DIR = join9(homedir5(), ".omni", "data");
|
|
128689
128880
|
async function detectReinstall(dataDirOverride) {
|
|
128690
128881
|
const hasConfig = detectHasConfig();
|
|
128691
128882
|
const hasPm2Process = await detectHasPm2Process();
|
|
@@ -128698,7 +128889,7 @@ async function detectReinstall(dataDirOverride) {
|
|
|
128698
128889
|
};
|
|
128699
128890
|
}
|
|
128700
128891
|
function detectHasConfig() {
|
|
128701
|
-
if (!
|
|
128892
|
+
if (!existsSync7(getConfigPath()))
|
|
128702
128893
|
return false;
|
|
128703
128894
|
try {
|
|
128704
128895
|
const parsed = loadConfig();
|
|
@@ -128720,7 +128911,7 @@ async function detectHasPm2Process() {
|
|
|
128720
128911
|
}
|
|
128721
128912
|
function detectHasDataDir(dataDirOverride) {
|
|
128722
128913
|
const dataDir = dataDirOverride ?? DEFAULT_DATA_DIR;
|
|
128723
|
-
if (!
|
|
128914
|
+
if (!existsSync7(dataDir))
|
|
128724
128915
|
return false;
|
|
128725
128916
|
try {
|
|
128726
128917
|
return readdirSync(dataDir).filter((e) => e !== ".DS_Store").length > 0;
|
|
@@ -128774,7 +128965,7 @@ ExecStart=/usr/bin/env omni start
|
|
|
128774
128965
|
ExecStop=/usr/bin/env omni stop
|
|
128775
128966
|
ExecReload=/usr/bin/env omni restart
|
|
128776
128967
|
Restart=on-failure
|
|
128777
|
-
PIDFile=${
|
|
128968
|
+
PIDFile=${homedir5()}/.pm2/pm2.pid
|
|
128778
128969
|
|
|
128779
128970
|
[Install]
|
|
128780
128971
|
WantedBy=multi-user.target
|
|
@@ -128785,7 +128976,7 @@ After=network.target
|
|
|
128785
128976
|
|
|
128786
128977
|
[Service]
|
|
128787
128978
|
Type=simple
|
|
128788
|
-
ExecStart="${NATS_BINARY_PATH}" -js -sd "${
|
|
128979
|
+
ExecStart="${NATS_BINARY_PATH}" -js -sd "${join9(dataDir, "nats")}"
|
|
128789
128980
|
Restart=on-failure
|
|
128790
128981
|
RestartSec=5
|
|
128791
128982
|
|
|
@@ -128793,8 +128984,8 @@ RestartSec=5
|
|
|
128793
128984
|
WantedBy=multi-user.target
|
|
128794
128985
|
`;
|
|
128795
128986
|
try {
|
|
128796
|
-
|
|
128797
|
-
|
|
128987
|
+
writeFileSync5("/etc/systemd/system/omni-nats.service", natsUnit, { mode: 420 });
|
|
128988
|
+
writeFileSync5("/etc/systemd/system/omni-api.service", apiUnit, { mode: 420 });
|
|
128798
128989
|
success("Systemd units written to /etc/systemd/system/");
|
|
128799
128990
|
raw(`
|
|
128800
128991
|
Enable with: sudo systemctl enable --now omni-nats omni-api
|
|
@@ -128808,9 +128999,9 @@ WantedBy=multi-user.target
|
|
|
128808
128999
|
init_config();
|
|
128809
129000
|
init_output();
|
|
128810
129001
|
import { spawnSync } from "child_process";
|
|
128811
|
-
import { existsSync as
|
|
128812
|
-
import { homedir as
|
|
128813
|
-
import { join as
|
|
129002
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync5, readFileSync as readFileSync5, renameSync, statSync, writeFileSync as writeFileSync6 } from "fs";
|
|
129003
|
+
import { homedir as homedir6 } from "os";
|
|
129004
|
+
import { join as join10 } from "path";
|
|
128814
129005
|
import { gunzipSync, gzipSync } from "zlib";
|
|
128815
129006
|
async function isPgserveInstalled() {
|
|
128816
129007
|
const bin = resolvePgserveBinary();
|
|
@@ -128928,6 +129119,16 @@ async function setupCanonicalPgserve() {
|
|
|
128928
129119
|
if (port === null)
|
|
128929
129120
|
return null;
|
|
128930
129121
|
await ensureOmniDatabaseExists(port);
|
|
129122
|
+
const cutover = await ensureOmniScopedRole({
|
|
129123
|
+
socketDir: resolvePgserveSocketDir(),
|
|
129124
|
+
port,
|
|
129125
|
+
database: OMNI_DATABASE_NAME
|
|
129126
|
+
});
|
|
129127
|
+
if (cutover.status === "provisioned" || cutover.status === "refreshed") {
|
|
129128
|
+
raw(` Scoped role \`${cutover.roleName}\` ${cutover.status} \u2014 omni-api will connect as non-superuser.`);
|
|
129129
|
+
} else if (cutover.status === "skipped" && cutover.reason !== "disabled") {
|
|
129130
|
+
warn(`Scoped-role cutover skipped: ${cutover.reason} \u2014 omni-api falls back to postgres superuser.`);
|
|
129131
|
+
}
|
|
128931
129132
|
return buildOmniDatabaseUrl(port);
|
|
128932
129133
|
}
|
|
128933
129134
|
async function resolveCanonicalPgservePreference(isReinstall, cfg) {
|
|
@@ -128959,18 +129160,18 @@ async function resolveCanonicalPgservePreference(isReinstall, cfg) {
|
|
|
128959
129160
|
raw("");
|
|
128960
129161
|
return true;
|
|
128961
129162
|
}
|
|
128962
|
-
var OMNI_EMBEDDED_PGSERVE_DATA_DIR =
|
|
128963
|
-
var PGSERVE_DEFAULT_DATA_DIR =
|
|
128964
|
-
var PGSERVE_CONFIG_PATH =
|
|
128965
|
-
var OMNI_BACKUPS_DIR =
|
|
129163
|
+
var OMNI_EMBEDDED_PGSERVE_DATA_DIR = join10(homedir6(), ".omni", "data", "pgserve");
|
|
129164
|
+
var PGSERVE_DEFAULT_DATA_DIR = join10(homedir6(), ".pgserve", "data");
|
|
129165
|
+
var PGSERVE_CONFIG_PATH = join10(homedir6(), ".pgserve", "config.json");
|
|
129166
|
+
var OMNI_BACKUPS_DIR = join10(homedir6(), ".omni", "backups");
|
|
128966
129167
|
function getEmbeddedPgserveDataDir() {
|
|
128967
129168
|
return OMNI_EMBEDDED_PGSERVE_DATA_DIR;
|
|
128968
129169
|
}
|
|
128969
129170
|
function getCanonicalPgserveDataDir() {
|
|
128970
|
-
if (!
|
|
129171
|
+
if (!existsSync8(PGSERVE_CONFIG_PATH))
|
|
128971
129172
|
return PGSERVE_DEFAULT_DATA_DIR;
|
|
128972
129173
|
try {
|
|
128973
|
-
const raw2 =
|
|
129174
|
+
const raw2 = readFileSync5(PGSERVE_CONFIG_PATH, "utf8");
|
|
128974
129175
|
const parsed = JSON.parse(raw2);
|
|
128975
129176
|
return typeof parsed.dataDir === "string" && parsed.dataDir.length > 0 ? parsed.dataDir : PGSERVE_DEFAULT_DATA_DIR;
|
|
128976
129177
|
} catch {
|
|
@@ -128978,11 +129179,11 @@ function getCanonicalPgserveDataDir() {
|
|
|
128978
129179
|
}
|
|
128979
129180
|
}
|
|
128980
129181
|
function looksLikePgDataDir(path) {
|
|
128981
|
-
return
|
|
129182
|
+
return existsSync8(join10(path, "PG_VERSION")) && existsSync8(join10(path, "base"));
|
|
128982
129183
|
}
|
|
128983
129184
|
function getSnapshotPath(timestamp = new Date) {
|
|
128984
129185
|
const ts = timestamp.toISOString().replace(/[:.]/g, "-");
|
|
128985
|
-
return
|
|
129186
|
+
return join10(OMNI_BACKUPS_DIR, `embedded-migration-${ts}.sql.gz`);
|
|
128986
129187
|
}
|
|
128987
129188
|
function commandIsAvailable(cmd) {
|
|
128988
129189
|
try {
|
|
@@ -129007,7 +129208,7 @@ function pgEnvFromUrl(url) {
|
|
|
129007
129208
|
}
|
|
129008
129209
|
async function dumpEmbeddedDb(currentDatabaseUrl) {
|
|
129009
129210
|
const embeddedDir = getEmbeddedPgserveDataDir();
|
|
129010
|
-
if (!
|
|
129211
|
+
if (!existsSync8(embeddedDir)) {
|
|
129011
129212
|
return { status: "no-embedded-data", embeddedDir };
|
|
129012
129213
|
}
|
|
129013
129214
|
if (!looksLikePgDataDir(embeddedDir)) {
|
|
@@ -129018,7 +129219,7 @@ async function dumpEmbeddedDb(currentDatabaseUrl) {
|
|
|
129018
129219
|
throw new Error("pg_dump not found in PATH \u2014 install postgresql-client (apt install postgresql-client / brew install postgresql) and retry");
|
|
129019
129220
|
}
|
|
129020
129221
|
const snapshotPath = getSnapshotPath();
|
|
129021
|
-
|
|
129222
|
+
mkdirSync5(OMNI_BACKUPS_DIR, { recursive: true, mode: 448 });
|
|
129022
129223
|
raw(" Dumping embedded database via pg_dump...");
|
|
129023
129224
|
raw(` source data dir: ${embeddedDir}`);
|
|
129024
129225
|
raw(` snapshot: ${snapshotPath}`);
|
|
@@ -129034,7 +129235,7 @@ async function dumpEmbeddedDb(currentDatabaseUrl) {
|
|
|
129034
129235
|
}
|
|
129035
129236
|
const compressed = gzipSync(result.stdout);
|
|
129036
129237
|
const tmpPath = `${snapshotPath}.tmp`;
|
|
129037
|
-
|
|
129238
|
+
writeFileSync6(tmpPath, compressed, { mode: 384 });
|
|
129038
129239
|
renameSync(tmpPath, snapshotPath);
|
|
129039
129240
|
const bytes = statSync(snapshotPath).size;
|
|
129040
129241
|
raw(` snapshot size: ${formatBytes(bytes)}`);
|
|
@@ -129052,7 +129253,7 @@ async function restoreSnapshotToCanonical(dump, canonicalDatabaseUrl) {
|
|
|
129052
129253
|
raw(` snapshot: ${dump.snapshotPath}`);
|
|
129053
129254
|
raw(` canonical data dir: ${getCanonicalPgserveDataDir()}`);
|
|
129054
129255
|
raw(` canonical URL: ${canonicalDatabaseUrl}`);
|
|
129055
|
-
const compressed =
|
|
129256
|
+
const compressed = readFileSync5(dump.snapshotPath);
|
|
129056
129257
|
const sql = gunzipSync(compressed);
|
|
129057
129258
|
const result = spawnSync("psql", ["-v", "ON_ERROR_STOP=1"], {
|
|
129058
129259
|
env: { ...process.env, ...pgEnvFromUrl(canonicalDatabaseUrl) },
|
|
@@ -129083,24 +129284,24 @@ init_output();
|
|
|
129083
129284
|
|
|
129084
129285
|
// src/server-bundle.ts
|
|
129085
129286
|
init_output();
|
|
129086
|
-
import { dirname as dirname2, join as
|
|
129287
|
+
import { dirname as dirname2, join as join11 } from "path";
|
|
129087
129288
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
129088
129289
|
function getServerBundlePath() {
|
|
129089
129290
|
try {
|
|
129090
129291
|
const thisFile = fileURLToPath2(import.meta.url);
|
|
129091
129292
|
const distDir = dirname2(thisFile);
|
|
129092
|
-
return
|
|
129293
|
+
return join11(distDir, "server", "index.js");
|
|
129093
129294
|
} catch {
|
|
129094
|
-
return
|
|
129295
|
+
return join11(process.cwd(), "dist", "server", "index.js");
|
|
129095
129296
|
}
|
|
129096
129297
|
}
|
|
129097
129298
|
function getServerLauncherPath() {
|
|
129098
129299
|
try {
|
|
129099
129300
|
const thisFile = fileURLToPath2(import.meta.url);
|
|
129100
129301
|
const distDir = dirname2(thisFile);
|
|
129101
|
-
return
|
|
129302
|
+
return join11(distDir, "..", "bin", "omni-server");
|
|
129102
129303
|
} catch {
|
|
129103
|
-
return
|
|
129304
|
+
return join11(process.cwd(), "bin", "omni-server");
|
|
129104
129305
|
}
|
|
129105
129306
|
}
|
|
129106
129307
|
function bundleNotFoundError(bundlePath) {
|
|
@@ -129165,10 +129366,10 @@ function productionDeps() {
|
|
|
129165
129366
|
}
|
|
129166
129367
|
},
|
|
129167
129368
|
findOrphanedDataDirs: () => {
|
|
129168
|
-
const roots = [process.cwd(),
|
|
129369
|
+
const roots = [process.cwd(), join12(homedir7(), "workspace"), join12(homedir7(), "repos")];
|
|
129169
129370
|
const found = [];
|
|
129170
129371
|
for (const root of roots) {
|
|
129171
|
-
if (!
|
|
129372
|
+
if (!existsSync9(root))
|
|
129172
129373
|
continue;
|
|
129173
129374
|
try {
|
|
129174
129375
|
scanForOrphans(root, found, 0);
|
|
@@ -129276,7 +129477,7 @@ function scanForOrphans(dir, acc, depth, maxDepth = 4) {
|
|
|
129276
129477
|
for (const name of entries) {
|
|
129277
129478
|
if (name === "node_modules" || name === ".git")
|
|
129278
129479
|
continue;
|
|
129279
|
-
const full =
|
|
129480
|
+
const full = join12(dir, name);
|
|
129280
129481
|
let stats;
|
|
129281
129482
|
try {
|
|
129282
129483
|
stats = statSync2(full);
|
|
@@ -129899,7 +130100,7 @@ Safety:
|
|
|
129899
130100
|
}
|
|
129900
130101
|
|
|
129901
130102
|
// src/commands/done.ts
|
|
129902
|
-
import { existsSync as
|
|
130103
|
+
import { existsSync as existsSync10, readFileSync as readFileSync6 } from "fs";
|
|
129903
130104
|
import { basename, extname } from "path";
|
|
129904
130105
|
|
|
129905
130106
|
// src/context.ts
|
|
@@ -130008,12 +130209,12 @@ async function handleReact(client, ctx, emoji) {
|
|
|
130008
130209
|
await closeTurn(client, "react", `Reacted ${emoji} + turn closed`);
|
|
130009
130210
|
}
|
|
130010
130211
|
async function handleMedia(client, ctx, mediaPath, caption) {
|
|
130011
|
-
if (!
|
|
130212
|
+
if (!existsSync10(mediaPath)) {
|
|
130012
130213
|
return error(`File not found: ${mediaPath}`);
|
|
130013
130214
|
}
|
|
130014
130215
|
try {
|
|
130015
130216
|
const mediaType = getMediaType(mediaPath);
|
|
130016
|
-
const buffer =
|
|
130217
|
+
const buffer = readFileSync6(mediaPath);
|
|
130017
130218
|
const base64 = buffer.toString("base64");
|
|
130018
130219
|
const filename = basename(mediaPath);
|
|
130019
130220
|
await client.messages.sendMedia({
|
|
@@ -130445,7 +130646,7 @@ function createEventsCommand() {
|
|
|
130445
130646
|
}
|
|
130446
130647
|
|
|
130447
130648
|
// src/commands/film.ts
|
|
130448
|
-
import { writeFileSync as
|
|
130649
|
+
import { writeFileSync as writeFileSync7 } from "fs";
|
|
130449
130650
|
import { resolve as resolvePath } from "path";
|
|
130450
130651
|
init_output();
|
|
130451
130652
|
function createFilmCommand() {
|
|
@@ -130509,7 +130710,7 @@ function createFilmCommand() {
|
|
|
130509
130710
|
const videoBuffer = Buffer.from(result.videoBase64, "base64");
|
|
130510
130711
|
if (options.output) {
|
|
130511
130712
|
const outPath = resolvePath(options.output);
|
|
130512
|
-
|
|
130713
|
+
writeFileSync7(outPath, videoBuffer);
|
|
130513
130714
|
success("Video saved", { path: outPath, sizeBytes: videoBuffer.length });
|
|
130514
130715
|
return;
|
|
130515
130716
|
}
|
|
@@ -130533,7 +130734,7 @@ function createFilmCommand() {
|
|
|
130533
130734
|
}
|
|
130534
130735
|
|
|
130535
130736
|
// src/commands/follow-up.ts
|
|
130536
|
-
import { readFileSync as
|
|
130737
|
+
import { readFileSync as readFileSync7 } from "fs";
|
|
130537
130738
|
init_output();
|
|
130538
130739
|
var VALID_SCOPES = ["agents", "instances", "chats"];
|
|
130539
130740
|
function assertScope(scope) {
|
|
@@ -130551,9 +130752,9 @@ async function resolveScopedId(scope, id) {
|
|
|
130551
130752
|
function readJsonArg(raw2) {
|
|
130552
130753
|
let body = raw2;
|
|
130553
130754
|
if (body === "-") {
|
|
130554
|
-
body =
|
|
130755
|
+
body = readFileSync7(0, "utf8");
|
|
130555
130756
|
} else if (body.startsWith("@")) {
|
|
130556
|
-
body =
|
|
130757
|
+
body = readFileSync7(body.slice(1), "utf8");
|
|
130557
130758
|
}
|
|
130558
130759
|
try {
|
|
130559
130760
|
return JSON.parse(body);
|
|
@@ -130705,8 +130906,8 @@ function createHistoryCommand() {
|
|
|
130705
130906
|
}
|
|
130706
130907
|
|
|
130707
130908
|
// src/commands/imagine.ts
|
|
130708
|
-
import { writeFileSync as
|
|
130709
|
-
import { basename as basename2, dirname as dirname3, extname as extname2, join as
|
|
130909
|
+
import { writeFileSync as writeFileSync8 } from "fs";
|
|
130910
|
+
import { basename as basename2, dirname as dirname3, extname as extname2, join as join13 } from "path";
|
|
130710
130911
|
init_output();
|
|
130711
130912
|
var ALLOWED_ASPECT_RATIOS = ["1:1", "4:3", "3:4", "16:9", "9:16", "3:2", "2:3"];
|
|
130712
130913
|
function extensionForMime(mimeType) {
|
|
@@ -130721,9 +130922,9 @@ function buildOutputPath(outputBase, index, total, mimeType) {
|
|
|
130721
130922
|
const ext = extname2(outputBase) || extensionForMime(mimeType);
|
|
130722
130923
|
const stem = basename2(outputBase, extname2(outputBase));
|
|
130723
130924
|
if (total <= 1) {
|
|
130724
|
-
return
|
|
130925
|
+
return join13(dir, `${stem}${ext}`);
|
|
130725
130926
|
}
|
|
130726
|
-
return
|
|
130927
|
+
return join13(dir, `${stem}-${index + 1}${ext}`);
|
|
130727
130928
|
}
|
|
130728
130929
|
function parseAspectRatio(value) {
|
|
130729
130930
|
if (!value)
|
|
@@ -130796,7 +130997,7 @@ function createImagineCommand() {
|
|
|
130796
130997
|
continue;
|
|
130797
130998
|
const path = buildOutputPath(options.output, i, result.images.length, image.mimeType);
|
|
130798
130999
|
try {
|
|
130799
|
-
|
|
131000
|
+
writeFileSync8(path, Buffer.from(image.base64, "base64"));
|
|
130800
131001
|
savedPaths.push(path);
|
|
130801
131002
|
} catch (err) {
|
|
130802
131003
|
const message = err instanceof Error ? err.message : "Unknown error";
|
|
@@ -130841,12 +131042,12 @@ function createImagineCommand() {
|
|
|
130841
131042
|
}
|
|
130842
131043
|
|
|
130843
131044
|
// src/commands/install.ts
|
|
130844
|
-
import { existsSync as
|
|
130845
|
-
import { homedir as
|
|
130846
|
-
import { join as
|
|
131045
|
+
import { existsSync as existsSync11, mkdirSync as mkdirSync6 } from "fs";
|
|
131046
|
+
import { homedir as homedir8 } from "os";
|
|
131047
|
+
import { join as join14 } from "path";
|
|
130847
131048
|
init_config();
|
|
130848
131049
|
init_output();
|
|
130849
|
-
var DEFAULT_DATA_DIR2 =
|
|
131050
|
+
var DEFAULT_DATA_DIR2 = join14(homedir8(), ".omni", "data");
|
|
130850
131051
|
function computeDefaultDatabaseUrl() {
|
|
130851
131052
|
return buildEmbeddedDatabaseUrl();
|
|
130852
131053
|
}
|
|
@@ -130945,13 +131146,13 @@ async function startServices(cfg, forceCleanup, forceSystemd, useCanonicalPgserv
|
|
|
130945
131146
|
return false;
|
|
130946
131147
|
}
|
|
130947
131148
|
const bundlePath = getServerBundlePath();
|
|
130948
|
-
if (!
|
|
131149
|
+
if (!existsSync11(bundlePath)) {
|
|
130949
131150
|
warn(`Server bundle not found at: ${bundlePath}
|
|
130950
131151
|
Install @automagik/omni from npm: bun add -g @automagik/omni
|
|
130951
131152
|
Or build locally: make cli-build-full`);
|
|
130952
131153
|
return false;
|
|
130953
131154
|
}
|
|
130954
|
-
|
|
131155
|
+
mkdirSync6(getPm2LogDir(), { recursive: true });
|
|
130955
131156
|
await installPm2Logrotate();
|
|
130956
131157
|
const runtimeEnv = buildInstallRuntimeEnv(cfg, forceCleanup, useCanonicalPgserve);
|
|
130957
131158
|
await runPm2(["delete", PM2_PROCESSES.api]);
|
|
@@ -130969,10 +131170,10 @@ async function startServices(cfg, forceCleanup, forceSystemd, useCanonicalPgserv
|
|
|
130969
131170
|
return false;
|
|
130970
131171
|
}
|
|
130971
131172
|
apiSpinner.succeed(`${PM2_PROCESSES.api} started`);
|
|
130972
|
-
if (
|
|
131173
|
+
if (existsSync11(NATS_BINARY_PATH)) {
|
|
130973
131174
|
const natsSpinner = ora(`Starting ${PM2_PROCESSES.nats}...`).start();
|
|
130974
|
-
const natsDataDir =
|
|
130975
|
-
|
|
131175
|
+
const natsDataDir = join14(cfg.dataDir, "nats");
|
|
131176
|
+
mkdirSync6(natsDataDir, { recursive: true });
|
|
130976
131177
|
const natsArgs = buildPm2StartArgs({
|
|
130977
131178
|
kind: "nats",
|
|
130978
131179
|
script: NATS_BINARY_PATH,
|
|
@@ -132648,7 +132849,7 @@ function createLogsCommand() {
|
|
|
132648
132849
|
}
|
|
132649
132850
|
|
|
132650
132851
|
// src/commands/media.ts
|
|
132651
|
-
import { createWriteStream as createWriteStream2, existsSync as
|
|
132852
|
+
import { createWriteStream as createWriteStream2, existsSync as existsSync13, mkdirSync as mkdirSync8, statSync as statSync4 } from "fs";
|
|
132652
132853
|
import { basename as basename4, dirname as dirname4, resolve as resolve2 } from "path";
|
|
132653
132854
|
import { Readable } from "stream";
|
|
132654
132855
|
import { pipeline } from "stream/promises";
|
|
@@ -132711,14 +132912,14 @@ function resolveOutputPath(outputPath, result) {
|
|
|
132711
132912
|
const resolved = resolve2(outputPath);
|
|
132712
132913
|
if (isDirHint)
|
|
132713
132914
|
return resolve2(resolved, filename);
|
|
132714
|
-
if (
|
|
132915
|
+
if (existsSync13(resolved) && statSync4(resolved).isDirectory())
|
|
132715
132916
|
return resolve2(resolved, filename);
|
|
132716
132917
|
return resolved;
|
|
132717
132918
|
}
|
|
132718
132919
|
async function downloadToFile(url, apiKey, destinationPath) {
|
|
132719
132920
|
const destDir = dirname4(destinationPath);
|
|
132720
|
-
if (!
|
|
132721
|
-
|
|
132921
|
+
if (!existsSync13(destDir))
|
|
132922
|
+
mkdirSync8(destDir, { recursive: true });
|
|
132722
132923
|
const resp = await fetch(url, {
|
|
132723
132924
|
method: "GET",
|
|
132724
132925
|
headers: apiKey ? { "x-api-key": apiKey } : undefined
|
|
@@ -133671,8 +133872,8 @@ init_output();
|
|
|
133671
133872
|
init_src();
|
|
133672
133873
|
import { execFileSync as execFileSync3, execSync } from "child_process";
|
|
133673
133874
|
import * as nodeCrypto2 from "crypto";
|
|
133674
|
-
import { existsSync as
|
|
133675
|
-
import { homedir as
|
|
133875
|
+
import { existsSync as existsSync14, mkdirSync as mkdirSync9, readFileSync as readFileSync9, writeFileSync as writeFileSync9 } from "fs";
|
|
133876
|
+
import { homedir as homedir10 } from "os";
|
|
133676
133877
|
import { dirname as dirname5, resolve as resolve3 } from "path";
|
|
133677
133878
|
import { createInterface as createInterface2 } from "readline";
|
|
133678
133879
|
init_config();
|
|
@@ -133899,19 +134100,19 @@ async function pairDevice(gatewayUrl, gatewayToken, keypair, spinner) {
|
|
|
133899
134100
|
ws.close(1000, "pairing complete");
|
|
133900
134101
|
}
|
|
133901
134102
|
}
|
|
133902
|
-
var OPENCLAW_CONFIG_PATH = resolve3(
|
|
134103
|
+
var OPENCLAW_CONFIG_PATH = resolve3(homedir10(), ".openclaw", "openclaw.json");
|
|
133903
134104
|
var PLUGIN_MARKER = "plugin-openclaw/omni.ts";
|
|
133904
134105
|
function readOpenClawConfig(configPath) {
|
|
133905
|
-
if (!
|
|
134106
|
+
if (!existsSync14(configPath))
|
|
133906
134107
|
return {};
|
|
133907
|
-
const raw2 =
|
|
134108
|
+
const raw2 = readFileSync9(configPath, "utf-8").trim();
|
|
133908
134109
|
if (!raw2)
|
|
133909
134110
|
return {};
|
|
133910
134111
|
return JSON.parse(raw2);
|
|
133911
134112
|
}
|
|
133912
134113
|
function writeOpenClawConfig(configPath, config2) {
|
|
133913
|
-
|
|
133914
|
-
|
|
134114
|
+
mkdirSync9(dirname5(configPath), { recursive: true, mode: 448 });
|
|
134115
|
+
writeFileSync9(configPath, `${JSON.stringify(config2, null, 2)}
|
|
133915
134116
|
`, { mode: 384 });
|
|
133916
134117
|
}
|
|
133917
134118
|
function isPluginRegistered(config2, marker, pluginPath) {
|
|
@@ -133943,10 +134144,10 @@ function isValidUuid2(value) {
|
|
|
133943
134144
|
}
|
|
133944
134145
|
function resolvePluginPath(explicit) {
|
|
133945
134146
|
if (explicit) {
|
|
133946
|
-
return
|
|
134147
|
+
return existsSync14(explicit) ? resolve3(explicit) : null;
|
|
133947
134148
|
}
|
|
133948
134149
|
const cwdCandidate = resolve3(process.cwd(), "packages/plugin-openclaw/omni.ts");
|
|
133949
|
-
return
|
|
134150
|
+
return existsSync14(cwdCandidate) ? cwdCandidate : null;
|
|
133950
134151
|
}
|
|
133951
134152
|
function registerPlugin(config2, pluginPath, configPath) {
|
|
133952
134153
|
if (hasOpenClawCli()) {
|
|
@@ -134996,7 +135197,7 @@ function createSayCommand() {
|
|
|
134996
135197
|
}
|
|
134997
135198
|
|
|
134998
135199
|
// src/commands/see.ts
|
|
134999
|
-
import { existsSync as
|
|
135200
|
+
import { existsSync as existsSync15, readFileSync as readFileSync10, statSync as statSync5 } from "fs";
|
|
135000
135201
|
import { extname as extname4 } from "path";
|
|
135001
135202
|
init_output();
|
|
135002
135203
|
var MIME_BY_EXT = {
|
|
@@ -135028,7 +135229,7 @@ function parseMaxTokens(value) {
|
|
|
135028
135229
|
return n2;
|
|
135029
135230
|
}
|
|
135030
135231
|
function loadMedia(file) {
|
|
135031
|
-
if (!
|
|
135232
|
+
if (!existsSync15(file)) {
|
|
135032
135233
|
error(`File not found: ${file}`);
|
|
135033
135234
|
}
|
|
135034
135235
|
const stat = statSync5(file);
|
|
@@ -135039,7 +135240,7 @@ function loadMedia(file) {
|
|
|
135039
135240
|
error(`File is empty: ${file}`);
|
|
135040
135241
|
}
|
|
135041
135242
|
try {
|
|
135042
|
-
return { buffer:
|
|
135243
|
+
return { buffer: readFileSync10(file), mimeType: guessMimeType(file) };
|
|
135043
135244
|
} catch (err2) {
|
|
135044
135245
|
const message2 = err2 instanceof Error ? err2.message : "Unknown error";
|
|
135045
135246
|
return error(`Failed to read ${file}: ${message2}`);
|
|
@@ -135114,7 +135315,7 @@ function createSeeCommand() {
|
|
|
135114
135315
|
}
|
|
135115
135316
|
|
|
135116
135317
|
// src/commands/send.ts
|
|
135117
|
-
import { existsSync as
|
|
135318
|
+
import { existsSync as existsSync16, readFileSync as readFileSync11 } from "fs";
|
|
135118
135319
|
import { basename as basename5, extname as extname5 } from "path";
|
|
135119
135320
|
init_source();
|
|
135120
135321
|
init_config();
|
|
@@ -135134,7 +135335,7 @@ function getMediaType2(path) {
|
|
|
135134
135335
|
return "document";
|
|
135135
135336
|
}
|
|
135136
135337
|
function readFileAsBase64(path) {
|
|
135137
|
-
const buffer3 =
|
|
135338
|
+
const buffer3 = readFileSync11(path);
|
|
135138
135339
|
return buffer3.toString("base64");
|
|
135139
135340
|
}
|
|
135140
135341
|
var messageSenders = {
|
|
@@ -135155,7 +135356,7 @@ var messageSenders = {
|
|
|
135155
135356
|
const { to, media } = options3;
|
|
135156
135357
|
if (!to || !media)
|
|
135157
135358
|
return;
|
|
135158
|
-
if (!
|
|
135359
|
+
if (!existsSync16(media)) {
|
|
135159
135360
|
error(`File not found: ${media}`);
|
|
135160
135361
|
return;
|
|
135161
135362
|
}
|
|
@@ -135687,9 +135888,9 @@ function pickFilename(mimeType, provider) {
|
|
|
135687
135888
|
}
|
|
135688
135889
|
|
|
135689
135890
|
// src/commands/start.ts
|
|
135690
|
-
import { existsSync as
|
|
135691
|
-
import { homedir as
|
|
135692
|
-
import { join as
|
|
135891
|
+
import { existsSync as existsSync17, mkdirSync as mkdirSync10 } from "fs";
|
|
135892
|
+
import { homedir as homedir11 } from "os";
|
|
135893
|
+
import { join as join16 } from "path";
|
|
135693
135894
|
init_config();
|
|
135694
135895
|
init_output();
|
|
135695
135896
|
var START_HEALTH_TIMEOUT_MS = 1e4;
|
|
@@ -135698,12 +135899,12 @@ async function runStart() {
|
|
|
135698
135899
|
pm2NotFoundError();
|
|
135699
135900
|
}
|
|
135700
135901
|
const bundlePath = getServerBundlePath();
|
|
135701
|
-
if (!
|
|
135902
|
+
if (!existsSync17(bundlePath)) {
|
|
135702
135903
|
bundleNotFoundError(bundlePath);
|
|
135703
135904
|
}
|
|
135704
135905
|
const serverConfig = loadServerConfig();
|
|
135705
135906
|
const apiPort = serverConfig.port;
|
|
135706
|
-
|
|
135907
|
+
mkdirSync10(getPm2LogDir(), { recursive: true });
|
|
135707
135908
|
info(`Starting ${PM2_PROCESSES.api} (port ${apiPort})...`);
|
|
135708
135909
|
const cliConfig = loadConfig();
|
|
135709
135910
|
const env2 = buildRuntimeEnv(serverConfig, cliConfig);
|
|
@@ -135719,11 +135920,11 @@ async function runStart() {
|
|
|
135719
135920
|
error(`Failed to start ${PM2_PROCESSES.api} (pm2 exit code ${apiCode})`, undefined, 1);
|
|
135720
135921
|
return;
|
|
135721
135922
|
}
|
|
135722
|
-
const natsPath =
|
|
135723
|
-
if (
|
|
135923
|
+
const natsPath = join16(homedir11(), ".omni", "nats-server");
|
|
135924
|
+
if (existsSync17(natsPath)) {
|
|
135724
135925
|
info(`Starting ${PM2_PROCESSES.nats}...`);
|
|
135725
|
-
const natsDataDir =
|
|
135726
|
-
|
|
135926
|
+
const natsDataDir = join16(serverConfig.dataDir, "nats");
|
|
135927
|
+
mkdirSync10(natsDataDir, { recursive: true });
|
|
135727
135928
|
const natsArgs = buildPm2StartArgs({
|
|
135728
135929
|
kind: "nats",
|
|
135729
135930
|
script: natsPath,
|
|
@@ -136143,8 +136344,8 @@ function createTurnsCommand() {
|
|
|
136143
136344
|
}
|
|
136144
136345
|
|
|
136145
136346
|
// src/commands/update.ts
|
|
136146
|
-
import { existsSync as
|
|
136147
|
-
import { join as
|
|
136347
|
+
import { existsSync as existsSync19 } from "fs";
|
|
136348
|
+
import { join as join18 } from "path";
|
|
136148
136349
|
import { createInterface as createInterface3 } from "readline";
|
|
136149
136350
|
init_source();
|
|
136150
136351
|
init_config();
|
|
@@ -136426,9 +136627,9 @@ async function cleanupLegacyArtifacts(skipList) {
|
|
|
136426
136627
|
init_output();
|
|
136427
136628
|
|
|
136428
136629
|
// src/update-diagnostics.ts
|
|
136429
|
-
import { existsSync as
|
|
136430
|
-
import { homedir as
|
|
136431
|
-
import { join as
|
|
136630
|
+
import { existsSync as existsSync18, mkdirSync as mkdirSync11, readFileSync as readFileSync12, writeFileSync as writeFileSync10 } from "fs";
|
|
136631
|
+
import { homedir as homedir12 } from "os";
|
|
136632
|
+
import { join as join17 } from "path";
|
|
136432
136633
|
var UPDATE_DIAGNOSTICS_SCHEMA_VERSION = 1;
|
|
136433
136634
|
function createDiagnostics(args) {
|
|
136434
136635
|
const startedAt = new Date().toISOString();
|
|
@@ -136450,18 +136651,18 @@ function createDiagnostics(args) {
|
|
|
136450
136651
|
};
|
|
136451
136652
|
}
|
|
136452
136653
|
function getDiagnosticsDir() {
|
|
136453
|
-
const base = process.env.OMNI_CONFIG_DIR ??
|
|
136454
|
-
return
|
|
136654
|
+
const base = process.env.OMNI_CONFIG_DIR ?? join17(homedir12(), ".omni");
|
|
136655
|
+
return join17(base, "logs");
|
|
136455
136656
|
}
|
|
136456
136657
|
function getDiagnosticsPath(startedAt) {
|
|
136457
136658
|
const safe = startedAt.replace(/:/g, "-");
|
|
136458
|
-
return
|
|
136659
|
+
return join17(getDiagnosticsDir(), `update-diagnostics-${safe}.json`);
|
|
136459
136660
|
}
|
|
136460
136661
|
function tailFileLines(path, maxLines) {
|
|
136461
|
-
if (!
|
|
136662
|
+
if (!existsSync18(path))
|
|
136462
136663
|
return [];
|
|
136463
136664
|
try {
|
|
136464
|
-
const raw2 =
|
|
136665
|
+
const raw2 = readFileSync12(path, "utf8");
|
|
136465
136666
|
const lines = raw2.split(/\r?\n/);
|
|
136466
136667
|
if (lines.length > 0 && lines[lines.length - 1] === "")
|
|
136467
136668
|
lines.pop();
|
|
@@ -136494,10 +136695,10 @@ function writeDiagnostics(state, exitCode) {
|
|
|
136494
136695
|
const dir = getDiagnosticsDir();
|
|
136495
136696
|
const path = getDiagnosticsPath(state.startedAt);
|
|
136496
136697
|
try {
|
|
136497
|
-
if (!
|
|
136498
|
-
|
|
136698
|
+
if (!existsSync18(dir)) {
|
|
136699
|
+
mkdirSync11(dir, { recursive: true, mode: 448 });
|
|
136499
136700
|
}
|
|
136500
|
-
|
|
136701
|
+
writeFileSync10(path, `${JSON.stringify(state, null, 2)}
|
|
136501
136702
|
`, { mode: 384 });
|
|
136502
136703
|
return path;
|
|
136503
136704
|
} catch {
|
|
@@ -136668,7 +136869,7 @@ function printVerifySkippedBanner(latest) {
|
|
|
136668
136869
|
}
|
|
136669
136870
|
function detectParallelNpmGlobalInstall(deps) {
|
|
136670
136871
|
const npmRootFn = deps?.npmRoot ?? defaultNpmRoot;
|
|
136671
|
-
const existsFn = deps?.exists ??
|
|
136872
|
+
const existsFn = deps?.exists ?? existsSync19;
|
|
136672
136873
|
let root;
|
|
136673
136874
|
try {
|
|
136674
136875
|
root = npmRootFn();
|
|
@@ -136678,7 +136879,7 @@ function detectParallelNpmGlobalInstall(deps) {
|
|
|
136678
136879
|
if (root === null || root.length === 0) {
|
|
136679
136880
|
return { detected: false, skipped: "npm-not-on-path" };
|
|
136680
136881
|
}
|
|
136681
|
-
const candidate =
|
|
136882
|
+
const candidate = join18(root, "@automagik", "omni");
|
|
136682
136883
|
if (existsFn(candidate)) {
|
|
136683
136884
|
return { detected: true, path: candidate };
|
|
136684
136885
|
}
|
|
@@ -137075,9 +137276,9 @@ function createVoiceCommand() {
|
|
|
137075
137276
|
const startTime = Date.now();
|
|
137076
137277
|
let saveDir = "";
|
|
137077
137278
|
if (opts.save) {
|
|
137078
|
-
const { mkdirSync:
|
|
137279
|
+
const { mkdirSync: mkdirSync12 } = await import("fs");
|
|
137079
137280
|
saveDir = opts.save;
|
|
137080
|
-
|
|
137281
|
+
mkdirSync12(saveDir, { recursive: true });
|
|
137081
137282
|
info(`Saving audio to: ${saveDir}`);
|
|
137082
137283
|
}
|
|
137083
137284
|
ws.onopen = () => {
|
|
@@ -137301,17 +137502,17 @@ init_config();
|
|
|
137301
137502
|
init_output();
|
|
137302
137503
|
|
|
137303
137504
|
// src/manifest-pin.ts
|
|
137304
|
-
import { existsSync as
|
|
137305
|
-
import { homedir as
|
|
137306
|
-
import { join as
|
|
137505
|
+
import { existsSync as existsSync20, readFileSync as readFileSync13, renameSync as renameSync3, writeFileSync as writeFileSync11 } from "fs";
|
|
137506
|
+
import { homedir as homedir13 } from "os";
|
|
137507
|
+
import { join as join19 } from "path";
|
|
137307
137508
|
var PACKAGE_NAME2 = "@automagik/omni";
|
|
137308
|
-
var BUN_GLOBAL_MANIFEST =
|
|
137509
|
+
var BUN_GLOBAL_MANIFEST = join19(homedir13(), ".bun", "install", "global", "package.json");
|
|
137309
137510
|
function pinManifestEntry(manifestPath, exactVersion) {
|
|
137310
|
-
if (!
|
|
137511
|
+
if (!existsSync20(manifestPath))
|
|
137311
137512
|
return false;
|
|
137312
137513
|
let manifest;
|
|
137313
137514
|
try {
|
|
137314
|
-
manifest = JSON.parse(
|
|
137515
|
+
manifest = JSON.parse(readFileSync13(manifestPath, "utf-8"));
|
|
137315
137516
|
} catch {
|
|
137316
137517
|
return false;
|
|
137317
137518
|
}
|
|
@@ -137337,7 +137538,7 @@ function pinManifestEntry(manifestPath, exactVersion) {
|
|
|
137337
137538
|
return false;
|
|
137338
137539
|
const tmp = `${manifestPath}.tmp.${process.pid}`;
|
|
137339
137540
|
try {
|
|
137340
|
-
|
|
137541
|
+
writeFileSync11(tmp, `${JSON.stringify(manifest, null, 2)}
|
|
137341
137542
|
`, { mode: 420 });
|
|
137342
137543
|
renameSync3(tmp, manifestPath);
|
|
137343
137544
|
} catch {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"canonical-pgserve.d.ts","sourceRoot":"","sources":["../../src/lib/canonical-pgserve.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;
|
|
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"}
|
|
@@ -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,CAsFjH;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"}
|
package/dist/runtime-env.d.ts
CHANGED
|
@@ -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;
|
|
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"}
|
package/dist/server/index.js
CHANGED
|
@@ -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.
|
|
230140
|
+
version: "2.260520.12",
|
|
230141
230141
|
type: "module",
|
|
230142
230142
|
exports: {
|
|
230143
230143
|
".": {
|