@automagik/omni 2.260508.2 → 2.260508.4

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
@@ -21292,7 +21292,7 @@ var require_node_transport = __commonJS((exports) => {
21292
21292
  var util_1 = require_util();
21293
21293
  var tls_1 = __require("tls");
21294
21294
  var { resolve: resolve2 } = __require("path");
21295
- var { readFile, existsSync: existsSync10 } = __require("fs");
21295
+ var { readFile, existsSync: existsSync11 } = __require("fs");
21296
21296
  var dns = __require("dns");
21297
21297
  var VERSION2 = "2.29.3";
21298
21298
  var LANG = "nats.js";
@@ -21408,7 +21408,7 @@ var require_node_transport = __commonJS((exports) => {
21408
21408
  const d = (0, nats_base_client_1.deferred)();
21409
21409
  try {
21410
21410
  fn = resolve2(fn);
21411
- if (!existsSync10(fn)) {
21411
+ if (!existsSync11(fn)) {
21412
21412
  d.reject(new Error(`${fn} doesn't exist`));
21413
21413
  }
21414
21414
  readFile(fn, (err, data2) => {
@@ -61871,7 +61871,7 @@ var init_a2a_provider = __esm(() => {
61871
61871
  // ../core/src/providers/nats-genie-provider.ts
61872
61872
  import { mkdir, writeFile } from "fs/promises";
61873
61873
  import { homedir as homedir8 } from "os";
61874
- import { join as join13 } from "path";
61874
+ import { join as join14 } from "path";
61875
61875
 
61876
61876
  class NatsGenieProvider {
61877
61877
  id;
@@ -62061,10 +62061,10 @@ class NatsGenieProvider {
62061
62061
  }
62062
62062
  async writeDeadLetter(payload, error2) {
62063
62063
  try {
62064
- const dlDir = join13(homedir8(), ".omni", "dead-letters");
62064
+ const dlDir = join14(homedir8(), ".omni", "dead-letters");
62065
62065
  await mkdir(dlDir, { recursive: true });
62066
62066
  const filename = `nats-genie-${Date.now()}-${payload.chatId}.json`;
62067
- await writeFile(join13(dlDir, filename), JSON.stringify({
62067
+ await writeFile(join14(dlDir, filename), JSON.stringify({
62068
62068
  payload,
62069
62069
  error: error2 instanceof Error ? error2.message : String(error2),
62070
62070
  timestamp: new Date().toISOString()
@@ -63927,7 +63927,7 @@ var init_sql = __esm(() => {
63927
63927
  return new SQL([new StringChunk(str)]);
63928
63928
  }
63929
63929
  sql2.raw = raw2;
63930
- function join14(chunks, separator) {
63930
+ function join15(chunks, separator) {
63931
63931
  const result = [];
63932
63932
  for (const [i6, chunk] of chunks.entries()) {
63933
63933
  if (i6 > 0 && separator !== undefined) {
@@ -63937,7 +63937,7 @@ var init_sql = __esm(() => {
63937
63937
  }
63938
63938
  return new SQL(result);
63939
63939
  }
63940
- sql2.join = join14;
63940
+ sql2.join = join15;
63941
63941
  function identifier(value) {
63942
63942
  return new Name(value);
63943
63943
  }
@@ -67164,7 +67164,7 @@ var init_select2 = __esm(() => {
67164
67164
  return (table2, on) => {
67165
67165
  const baseTableName = this.tableName;
67166
67166
  const tableName = getTableLikeName(table2);
67167
- if (typeof tableName === "string" && this.config.joins?.some((join14) => join14.alias === tableName)) {
67167
+ if (typeof tableName === "string" && this.config.joins?.some((join15) => join15.alias === tableName)) {
67168
67168
  throw new Error(`Alias "${tableName}" is already used in this query`);
67169
67169
  }
67170
67170
  if (!this.isPartialSelect) {
@@ -67675,7 +67675,7 @@ var init_update = __esm(() => {
67675
67675
  createJoin(joinType) {
67676
67676
  return (table2, on) => {
67677
67677
  const tableName = getTableLikeName(table2);
67678
- if (typeof tableName === "string" && this.config.joins.some((join14) => join14.alias === tableName)) {
67678
+ if (typeof tableName === "string" && this.config.joins.some((join15) => join15.alias === tableName)) {
67679
67679
  throw new Error(`Alias "${tableName}" is already used in this query`);
67680
67680
  }
67681
67681
  if (typeof on === "function") {
@@ -67725,10 +67725,10 @@ var init_update = __esm(() => {
67725
67725
  const fromFields = this.getTableLikeFields(this.config.from);
67726
67726
  fields[tableName] = fromFields;
67727
67727
  }
67728
- for (const join14 of this.config.joins) {
67729
- const tableName2 = getTableLikeName(join14.table);
67730
- if (typeof tableName2 === "string" && !is(join14.table, SQL)) {
67731
- const fromFields = this.getTableLikeFields(join14.table);
67728
+ for (const join15 of this.config.joins) {
67729
+ const tableName2 = getTableLikeName(join15.table);
67730
+ if (typeof tableName2 === "string" && !is(join15.table, SQL)) {
67731
+ const fromFields = this.getTableLikeFields(join15.table);
67732
67732
  fields[tableName2] = fromFields;
67733
67733
  }
67734
67734
  }
@@ -82397,7 +82397,7 @@ var require_path = __commonJS((exports) => {
82397
82397
  function isAbsolute(path) {
82398
82398
  return path.charAt(0) === "/";
82399
82399
  }
82400
- function join18(...args) {
82400
+ function join19(...args) {
82401
82401
  return normalizePath(args.join("/"));
82402
82402
  }
82403
82403
  function dirname6(path) {
@@ -82422,7 +82422,7 @@ var require_path = __commonJS((exports) => {
82422
82422
  exports.basename = basename6;
82423
82423
  exports.dirname = dirname6;
82424
82424
  exports.isAbsolute = isAbsolute;
82425
- exports.join = join18;
82425
+ exports.join = join19;
82426
82426
  exports.normalizePath = normalizePath;
82427
82427
  exports.relative = relative;
82428
82428
  exports.resolve = resolve4;
@@ -123990,7 +123990,7 @@ import { fileURLToPath } from "url";
123990
123990
  // package.json
123991
123991
  var package_default = {
123992
123992
  name: "@automagik/omni",
123993
- version: "2.260508.2",
123993
+ version: "2.260508.4",
123994
123994
  description: "LLM-optimized CLI for Omni",
123995
123995
  type: "module",
123996
123996
  bin: {
@@ -125191,12 +125191,47 @@ function pm2NotFoundError() {
125191
125191
  }
125192
125192
 
125193
125193
  // src/runtime-env.ts
125194
+ import { join as join6 } from "path";
125195
+
125196
+ // src/lib/pgserve-transport.ts
125197
+ import { existsSync as existsSync4 } from "fs";
125194
125198
  import { join as join5 } from "path";
125199
+ var CANONICAL_PG_PORT = 5432;
125200
+ function resolvePgserveSocketDir() {
125201
+ const xdg = process.env.XDG_RUNTIME_DIR;
125202
+ const base = xdg && xdg.length > 0 ? xdg : "/tmp";
125203
+ return join5(base, "pgserve");
125204
+ }
125205
+ function resolvePgserveLibpqSocketPath() {
125206
+ return join5(resolvePgserveSocketDir(), `.s.PGSQL.${CANONICAL_PG_PORT}`);
125207
+ }
125208
+ function probeCanonicalSocketSync() {
125209
+ return existsSync4(resolvePgserveLibpqSocketPath());
125210
+ }
125211
+ function buildDatabaseUrlForTransport(transport, database, options = {}) {
125212
+ const username = options.username ?? "postgres";
125213
+ const password = options.password ?? "postgres";
125214
+ const auth = `${encodeURIComponent(username)}:${encodeURIComponent(password)}`;
125215
+ if (transport.kind === "unix") {
125216
+ const params = new URLSearchParams({
125217
+ host: transport.socketDir,
125218
+ port: String(transport.port)
125219
+ });
125220
+ return `postgresql://${auth}@/${encodeURIComponent(database)}?${params.toString()}`;
125221
+ }
125222
+ return `postgresql://${auth}@${transport.host}:${transport.port}/${encodeURIComponent(database)}`;
125223
+ }
125224
+
125225
+ // src/runtime-env.ts
125195
125226
  var LEGACY_DEFAULT_DATABASE_URL = "postgresql://postgres:postgres@localhost:5432/omni";
125227
+ var LEGACY_PHASE2_DATABASE_URL = "postgresql://postgres:postgres@localhost:8432/omni";
125196
125228
  var DEFAULT_PGSERVE_PORT = 8432;
125197
125229
  function buildEmbeddedDatabaseUrl(pgservePort = DEFAULT_PGSERVE_PORT) {
125198
125230
  return `postgresql://postgres:postgres@localhost:${pgservePort}/omni`;
125199
125231
  }
125232
+ function buildCanonicalSocketDatabaseUrl() {
125233
+ return buildDatabaseUrlForTransport({ kind: "unix", socketDir: resolvePgserveSocketDir(), port: CANONICAL_PG_PORT }, "omni");
125234
+ }
125200
125235
  function resolvePgservePort(serverConfig) {
125201
125236
  const maybe = serverConfig.pgservePort;
125202
125237
  if (typeof maybe === "number" && Number.isFinite(maybe) && maybe > 0) {
@@ -125204,24 +125239,27 @@ function resolvePgservePort(serverConfig) {
125204
125239
  }
125205
125240
  return DEFAULT_PGSERVE_PORT;
125206
125241
  }
125242
+ var LEGACY_DATABASE_URLS = [LEGACY_DEFAULT_DATABASE_URL, LEGACY_PHASE2_DATABASE_URL];
125207
125243
  function resolveDatabaseUrl(serverConfig) {
125208
125244
  const stored = serverConfig.databaseUrl?.trim() ?? "";
125209
- if (stored && stored !== LEGACY_DEFAULT_DATABASE_URL) {
125245
+ if (stored && !LEGACY_DATABASE_URLS.includes(stored)) {
125210
125246
  return stored;
125211
125247
  }
125248
+ if (probeCanonicalSocketSync()) {
125249
+ return buildCanonicalSocketDatabaseUrl();
125250
+ }
125212
125251
  return buildEmbeddedDatabaseUrl(resolvePgservePort(serverConfig));
125213
125252
  }
125214
125253
  function buildRuntimeEnv(serverConfig, cliConfig) {
125215
125254
  const pgservePort = resolvePgservePort(serverConfig);
125216
- const optOutOfCanonical = serverConfig.useCanonicalPgserve === false;
125217
125255
  return {
125218
125256
  API_PORT: String(serverConfig.port),
125219
125257
  DATABASE_URL: resolveDatabaseUrl(serverConfig),
125220
125258
  OMNI_API_KEY: cliConfig.apiKey ?? "",
125221
- MEDIA_STORAGE_PATH: join5(serverConfig.dataDir, "media"),
125222
- OMNI_PACKAGES_DIR: join5(serverConfig.dataDir, "packages"),
125223
- PGSERVE_EMBEDDED: optOutOfCanonical ? "true" : "false",
125224
- PGSERVE_DATA: join5(serverConfig.dataDir, "pgserve"),
125259
+ MEDIA_STORAGE_PATH: join6(serverConfig.dataDir, "media"),
125260
+ OMNI_PACKAGES_DIR: join6(serverConfig.dataDir, "packages"),
125261
+ PGSERVE_EMBEDDED: "false",
125262
+ PGSERVE_DATA: join6(serverConfig.dataDir, "pgserve"),
125225
125263
  PGSERVE_PORT: String(pgservePort),
125226
125264
  NATS_URL: "nats://localhost:4222",
125227
125265
  NODE_ENV: serverConfig.nodeEnv,
@@ -127535,9 +127573,9 @@ function createDeadLettersCommand() {
127535
127573
  }
127536
127574
 
127537
127575
  // src/commands/doctor.ts
127538
- import { existsSync as existsSync7, readdirSync as readdirSync2, statSync as statSync2 } from "fs";
127576
+ import { existsSync as existsSync8, readdirSync as readdirSync2, statSync as statSync2 } from "fs";
127539
127577
  import { homedir as homedir6 } from "os";
127540
- import { join as join10, resolve } from "path";
127578
+ import { join as join11, resolve } from "path";
127541
127579
  init_config();
127542
127580
 
127543
127581
  // src/health.ts
@@ -127563,14 +127601,14 @@ async function waitForHealth(port, timeoutMs = HEALTH_TIMEOUT_MS) {
127563
127601
 
127564
127602
  // src/install-helpers.ts
127565
127603
  init_config();
127566
- import { existsSync as existsSync5, readdirSync, writeFileSync as writeFileSync4 } from "fs";
127604
+ import { existsSync as existsSync6, readdirSync, writeFileSync as writeFileSync4 } from "fs";
127567
127605
  import { homedir as homedir4 } from "os";
127568
- import { join as join7 } from "path";
127606
+ import { join as join8 } from "path";
127569
127607
 
127570
127608
  // src/nats-install.ts
127571
- import { chmodSync as chmodSync2, existsSync as existsSync4, mkdirSync as mkdirSync3, writeFileSync as writeFileSync3 } from "fs";
127609
+ import { chmodSync as chmodSync2, existsSync as existsSync5, mkdirSync as mkdirSync3, writeFileSync as writeFileSync3 } from "fs";
127572
127610
  import { homedir as homedir3 } from "os";
127573
- import { join as join6 } from "path";
127611
+ import { join as join7 } from "path";
127574
127612
 
127575
127613
  // ../../node_modules/.bun/ora@8.2.0/node_modules/ora/index.js
127576
127614
  init_source();
@@ -128460,8 +128498,8 @@ function ora(options) {
128460
128498
 
128461
128499
  // src/nats-install.ts
128462
128500
  init_output();
128463
- var OMNI_DIR = join6(homedir3(), ".omni");
128464
- var NATS_BINARY_PATH = join6(OMNI_DIR, "nats-server");
128501
+ var OMNI_DIR = join7(homedir3(), ".omni");
128502
+ var NATS_BINARY_PATH = join7(OMNI_DIR, "nats-server");
128465
128503
  var NATS_VERSION = "v2.12.4";
128466
128504
  function platformInfo() {
128467
128505
  const platform = process.platform;
@@ -128490,10 +128528,10 @@ async function downloadNats() {
128490
128528
  spinner.fail(`NATS download failed: HTTP ${resp.status}`);
128491
128529
  return false;
128492
128530
  }
128493
- const tarPath = join6(OMNI_DIR, fileName);
128531
+ const tarPath = join7(OMNI_DIR, fileName);
128494
128532
  writeFileSync3(tarPath, Buffer.from(await resp.arrayBuffer()));
128495
128533
  spinner.text = "Extracting NATS binary...";
128496
- const tmpDir = join6(OMNI_DIR, "nats-tmp");
128534
+ const tmpDir = join7(OMNI_DIR, "nats-tmp");
128497
128535
  mkdirSync3(tmpDir, { recursive: true });
128498
128536
  const tar = Bun.spawn({ cmd: ["tar", "-xzf", tarPath, "-C", tmpDir], stdout: "pipe", stderr: "pipe" });
128499
128537
  const [tarCode, tarErr] = await Promise.all([tar.exited, new Response(tar.stderr).text()]);
@@ -128519,7 +128557,7 @@ async function downloadNats() {
128519
128557
  }
128520
128558
  }
128521
128559
  async function ensureNats() {
128522
- if (existsSync4(NATS_BINARY_PATH)) {
128560
+ if (existsSync5(NATS_BINARY_PATH)) {
128523
128561
  raw(` \u2713 NATS binary found at ${NATS_BINARY_PATH}`);
128524
128562
  return;
128525
128563
  }
@@ -128529,7 +128567,7 @@ async function ensureNats() {
128529
128567
 
128530
128568
  // src/install-helpers.ts
128531
128569
  init_output();
128532
- var DEFAULT_DATA_DIR = join7(homedir4(), ".omni", "data");
128570
+ var DEFAULT_DATA_DIR = join8(homedir4(), ".omni", "data");
128533
128571
  async function detectReinstall(dataDirOverride) {
128534
128572
  const hasConfig = detectHasConfig();
128535
128573
  const hasPm2Process = await detectHasPm2Process();
@@ -128542,7 +128580,7 @@ async function detectReinstall(dataDirOverride) {
128542
128580
  };
128543
128581
  }
128544
128582
  function detectHasConfig() {
128545
- if (!existsSync5(getConfigPath()))
128583
+ if (!existsSync6(getConfigPath()))
128546
128584
  return false;
128547
128585
  try {
128548
128586
  const parsed = loadConfig();
@@ -128564,7 +128602,7 @@ async function detectHasPm2Process() {
128564
128602
  }
128565
128603
  function detectHasDataDir(dataDirOverride) {
128566
128604
  const dataDir = dataDirOverride ?? DEFAULT_DATA_DIR;
128567
- if (!existsSync5(dataDir))
128605
+ if (!existsSync6(dataDir))
128568
128606
  return false;
128569
128607
  try {
128570
128608
  return readdirSync(dataDir).filter((e) => e !== ".DS_Store").length > 0;
@@ -128629,7 +128667,7 @@ After=network.target
128629
128667
 
128630
128668
  [Service]
128631
128669
  Type=simple
128632
- ExecStart="${NATS_BINARY_PATH}" -js -sd "${join7(dataDir, "nats")}"
128670
+ ExecStart="${NATS_BINARY_PATH}" -js -sd "${join8(dataDir, "nats")}"
128633
128671
  Restart=on-failure
128634
128672
  RestartSec=5
128635
128673
 
@@ -128652,9 +128690,9 @@ WantedBy=multi-user.target
128652
128690
  init_config();
128653
128691
  init_output();
128654
128692
  import { spawnSync } from "child_process";
128655
- import { existsSync as existsSync6, mkdirSync as mkdirSync4, readFileSync as readFileSync4, renameSync, statSync, writeFileSync as writeFileSync5 } from "fs";
128693
+ import { existsSync as existsSync7, mkdirSync as mkdirSync4, readFileSync as readFileSync4, renameSync, statSync, writeFileSync as writeFileSync5 } from "fs";
128656
128694
  import { homedir as homedir5 } from "os";
128657
- import { join as join8 } from "path";
128695
+ import { join as join9 } from "path";
128658
128696
  import { gunzipSync, gzipSync } from "zlib";
128659
128697
  var PGSERVE_REQUIRED_VERSION = "^2.1.0";
128660
128698
  async function isPgserveInstalled() {
@@ -128749,15 +128787,15 @@ async function resolveCanonicalPgservePreference(isReinstall, cfg) {
128749
128787
  raw("");
128750
128788
  return true;
128751
128789
  }
128752
- var OMNI_EMBEDDED_PGSERVE_DATA_DIR = join8(homedir5(), ".omni", "data", "pgserve");
128753
- var PGSERVE_DEFAULT_DATA_DIR = join8(homedir5(), ".pgserve", "data");
128754
- var PGSERVE_CONFIG_PATH = join8(homedir5(), ".pgserve", "config.json");
128755
- var OMNI_BACKUPS_DIR = join8(homedir5(), ".omni", "backups");
128790
+ var OMNI_EMBEDDED_PGSERVE_DATA_DIR = join9(homedir5(), ".omni", "data", "pgserve");
128791
+ var PGSERVE_DEFAULT_DATA_DIR = join9(homedir5(), ".pgserve", "data");
128792
+ var PGSERVE_CONFIG_PATH = join9(homedir5(), ".pgserve", "config.json");
128793
+ var OMNI_BACKUPS_DIR = join9(homedir5(), ".omni", "backups");
128756
128794
  function getEmbeddedPgserveDataDir() {
128757
128795
  return OMNI_EMBEDDED_PGSERVE_DATA_DIR;
128758
128796
  }
128759
128797
  function getCanonicalPgserveDataDir() {
128760
- if (!existsSync6(PGSERVE_CONFIG_PATH))
128798
+ if (!existsSync7(PGSERVE_CONFIG_PATH))
128761
128799
  return PGSERVE_DEFAULT_DATA_DIR;
128762
128800
  try {
128763
128801
  const raw2 = readFileSync4(PGSERVE_CONFIG_PATH, "utf8");
@@ -128768,11 +128806,11 @@ function getCanonicalPgserveDataDir() {
128768
128806
  }
128769
128807
  }
128770
128808
  function looksLikePgDataDir(path) {
128771
- return existsSync6(join8(path, "PG_VERSION")) && existsSync6(join8(path, "base"));
128809
+ return existsSync7(join9(path, "PG_VERSION")) && existsSync7(join9(path, "base"));
128772
128810
  }
128773
128811
  function getSnapshotPath(timestamp = new Date) {
128774
128812
  const ts = timestamp.toISOString().replace(/[:.]/g, "-");
128775
- return join8(OMNI_BACKUPS_DIR, `embedded-migration-${ts}.sql.gz`);
128813
+ return join9(OMNI_BACKUPS_DIR, `embedded-migration-${ts}.sql.gz`);
128776
128814
  }
128777
128815
  function commandIsAvailable(cmd) {
128778
128816
  try {
@@ -128797,7 +128835,7 @@ function pgEnvFromUrl(url) {
128797
128835
  }
128798
128836
  async function dumpEmbeddedDb(currentDatabaseUrl) {
128799
128837
  const embeddedDir = getEmbeddedPgserveDataDir();
128800
- if (!existsSync6(embeddedDir)) {
128838
+ if (!existsSync7(embeddedDir)) {
128801
128839
  return { status: "no-embedded-data", embeddedDir };
128802
128840
  }
128803
128841
  if (!looksLikePgDataDir(embeddedDir)) {
@@ -128873,24 +128911,24 @@ init_output();
128873
128911
 
128874
128912
  // src/server-bundle.ts
128875
128913
  init_output();
128876
- import { dirname as dirname2, join as join9 } from "path";
128914
+ import { dirname as dirname2, join as join10 } from "path";
128877
128915
  import { fileURLToPath as fileURLToPath2 } from "url";
128878
128916
  function getServerBundlePath() {
128879
128917
  try {
128880
128918
  const thisFile = fileURLToPath2(import.meta.url);
128881
128919
  const distDir = dirname2(thisFile);
128882
- return join9(distDir, "server", "index.js");
128920
+ return join10(distDir, "server", "index.js");
128883
128921
  } catch {
128884
- return join9(process.cwd(), "dist", "server", "index.js");
128922
+ return join10(process.cwd(), "dist", "server", "index.js");
128885
128923
  }
128886
128924
  }
128887
128925
  function getServerLauncherPath() {
128888
128926
  try {
128889
128927
  const thisFile = fileURLToPath2(import.meta.url);
128890
128928
  const distDir = dirname2(thisFile);
128891
- return join9(distDir, "..", "bin", "omni-server");
128929
+ return join10(distDir, "..", "bin", "omni-server");
128892
128930
  } catch {
128893
- return join9(process.cwd(), "bin", "omni-server");
128931
+ return join10(process.cwd(), "bin", "omni-server");
128894
128932
  }
128895
128933
  }
128896
128934
  function bundleNotFoundError(bundlePath) {
@@ -128955,10 +128993,10 @@ function productionDeps() {
128955
128993
  }
128956
128994
  },
128957
128995
  findOrphanedDataDirs: () => {
128958
- const roots = [process.cwd(), join10(homedir6(), "workspace"), join10(homedir6(), "repos")];
128996
+ const roots = [process.cwd(), join11(homedir6(), "workspace"), join11(homedir6(), "repos")];
128959
128997
  const found = [];
128960
128998
  for (const root of roots) {
128961
- if (!existsSync7(root))
128999
+ if (!existsSync8(root))
128962
129000
  continue;
128963
129001
  try {
128964
129002
  scanForOrphans(root, found, 0);
@@ -129027,7 +129065,31 @@ function productionDeps() {
129027
129065
  dumpEmbeddedDb,
129028
129066
  restoreSnapshotToCanonical,
129029
129067
  getCanonicalPgserveDataDir,
129030
- saveServerConfig
129068
+ saveServerConfig,
129069
+ findPortOwner: async (port) => {
129070
+ try {
129071
+ const proc = Bun.spawn(["ss", "-tlnpH", `sport = :${port}`], {
129072
+ stdout: "pipe",
129073
+ stderr: "ignore"
129074
+ });
129075
+ const stdout = await new Response(proc.stdout).text();
129076
+ const exitCode = await proc.exited;
129077
+ if (exitCode !== 0)
129078
+ return null;
129079
+ const match = stdout.match(/pid=(\d+)/);
129080
+ return match ? Number.parseInt(match[1], 10) : null;
129081
+ } catch {
129082
+ return null;
129083
+ }
129084
+ },
129085
+ processKill: (pid, signal) => {
129086
+ try {
129087
+ process.kill(pid, signal);
129088
+ return true;
129089
+ } catch {
129090
+ return false;
129091
+ }
129092
+ }
129031
129093
  };
129032
129094
  }
129033
129095
  function scanForOrphans(dir, acc, depth, maxDepth = 4) {
@@ -129042,7 +129104,7 @@ function scanForOrphans(dir, acc, depth, maxDepth = 4) {
129042
129104
  for (const name of entries) {
129043
129105
  if (name === "node_modules" || name === ".git")
129044
129106
  continue;
129045
- const full = join10(dir, name);
129107
+ const full = join11(dir, name);
129046
129108
  let stats;
129047
129109
  try {
129048
129110
  stats = statSync2(full);
@@ -129162,36 +129224,41 @@ async function checkPm2MaxRestarts(deps) {
129162
129224
  if (!processes) {
129163
129225
  return { id: "pm2-max-restarts", level: "WARN", detail: "pm2 not reachable" };
129164
129226
  }
129165
- const apiEntry = processes.find((p) => p.name === PM2_PROCESSES.api);
129166
- if (!apiEntry) {
129167
- return { id: "pm2-max-restarts", level: "WARN", detail: `${PM2_PROCESSES.api} not found in pm2` };
129168
- }
129169
- const maxRestarts = apiEntry.pm2_env?.max_restarts;
129170
- if (typeof maxRestarts !== "number") {
129171
- return {
129172
- id: "pm2-max-restarts",
129173
- level: "FAIL",
129174
- detail: `${PM2_PROCESSES.api} has no max_restarts set \u2014 crash loops are unbounded`
129175
- };
129176
- }
129177
- if (maxRestarts === 0 || maxRestarts >= 1000) {
129178
- return {
129179
- id: "pm2-max-restarts",
129180
- level: "FAIL",
129181
- detail: `${PM2_PROCESSES.api} max_restarts=${maxRestarts} \u2014 crash loops are effectively unbounded`
129182
- };
129227
+ const issues = [];
129228
+ let hasFail = false;
129229
+ const targets = [PM2_PROCESSES.api, PM2_PROCESSES.nats];
129230
+ for (const name of targets) {
129231
+ const entry = processes.find((p) => p.name === name);
129232
+ if (!entry) {
129233
+ issues.push(`${name} not found in pm2`);
129234
+ continue;
129235
+ }
129236
+ const v = entry.pm2_env?.max_restarts;
129237
+ if (typeof v !== "number") {
129238
+ hasFail = true;
129239
+ issues.push(`${name} has no max_restarts set \u2014 crash loops are unbounded`);
129240
+ continue;
129241
+ }
129242
+ if (v === 0 || v >= 1000) {
129243
+ hasFail = true;
129244
+ issues.push(`${name} max_restarts=${v} \u2014 crash loops are effectively unbounded`);
129245
+ continue;
129246
+ }
129247
+ if (!(v >= 5 && v <= 50)) {
129248
+ issues.push(`${name} max_restarts=${v} \u2014 expected 5..50`);
129249
+ }
129183
129250
  }
129184
- if (maxRestarts >= 5 && maxRestarts <= 50) {
129251
+ if (issues.length === 0) {
129185
129252
  return {
129186
129253
  id: "pm2-max-restarts",
129187
129254
  level: "OK",
129188
- detail: `${PM2_PROCESSES.api} max_restarts=${maxRestarts}`
129255
+ detail: `${PM2_PROCESSES.api} and ${PM2_PROCESSES.nats} max_restarts in hardened range`
129189
129256
  };
129190
129257
  }
129191
129258
  return {
129192
129259
  id: "pm2-max-restarts",
129193
- level: "WARN",
129194
- detail: `${PM2_PROCESSES.api} max_restarts=${maxRestarts} \u2014 expected 5..50`
129260
+ level: hasFail ? "FAIL" : "WARN",
129261
+ detail: issues.join("; ")
129195
129262
  };
129196
129263
  }
129197
129264
  async function checkPm2LogrotateInstalled(deps) {
@@ -129226,6 +129293,48 @@ async function checkPm2LogrotateInstalled(deps) {
129226
129293
  detail: "pm2-logrotate installed with expected settings"
129227
129294
  };
129228
129295
  }
129296
+ function canonicalPortTargets(serverConfig) {
129297
+ return [
129298
+ { name: PM2_PROCESSES.api, port: serverConfig.port },
129299
+ { name: PM2_PROCESSES.nats, port: 4222 }
129300
+ ];
129301
+ }
129302
+ async function checkPortCanonicalOwner(deps) {
129303
+ const processes = await deps.getPm2Processes();
129304
+ if (!processes) {
129305
+ return { id: "port-canonical-owner", level: "WARN", detail: "pm2 not reachable" };
129306
+ }
129307
+ const { serverConfig } = deps.loadState();
129308
+ const targets = canonicalPortTargets(serverConfig);
129309
+ const issues = [];
129310
+ for (const { name, port } of targets) {
129311
+ const pm2Entry = processes.find((p) => p.name === name);
129312
+ const pm2Pid = pm2Entry?.pid;
129313
+ const ownerPid = await deps.findPortOwner(port);
129314
+ if (ownerPid === null) {
129315
+ continue;
129316
+ }
129317
+ if (typeof pm2Pid !== "number" || pm2Pid <= 0) {
129318
+ issues.push(`${name}:${port} owned by pid=${ownerPid} but pm2 has no PID for ${name}`);
129319
+ continue;
129320
+ }
129321
+ if (ownerPid !== pm2Pid) {
129322
+ issues.push(`${name}:${port} owned by non-pm2 pid=${ownerPid} (pm2 child pid=${pm2Pid})`);
129323
+ }
129324
+ }
129325
+ if (issues.length === 0) {
129326
+ return {
129327
+ id: "port-canonical-owner",
129328
+ level: "OK",
129329
+ detail: "all canonical ports owned by pm2-managed processes"
129330
+ };
129331
+ }
129332
+ return {
129333
+ id: "port-canonical-owner",
129334
+ level: "FAIL",
129335
+ detail: issues.join("; ")
129336
+ };
129337
+ }
129229
129338
  async function fixPm2EnvDrift(deps) {
129230
129339
  const { serverConfig, cliConfig } = deps.loadState();
129231
129340
  const env2 = buildRuntimeEnv(serverConfig, cliConfig);
@@ -129335,6 +129444,83 @@ async function fixPgserveCanonical(deps) {
129335
129444
  const dataNote = dumpResult.status === "dumped" && restoreOutcome.status === "restored" ? `restored ${dumpResult.snapshotPath} into ${canonicalDir} (omni-api \u2192 ${url})` : dumpResult.status === "no-embedded-data" ? `no embedded data to migrate; canonical started empty at ${canonicalDir} (omni-api \u2192 ${url})` : `embedded data dir invalid; canonical started empty at ${canonicalDir} (omni-api \u2192 ${url})`;
129336
129445
  return `migrated to canonical pgserve@^2.1.0; ${dataNote}`;
129337
129446
  }
129447
+ async function waitForPortRelease(deps, pid, port) {
129448
+ for (let i = 0;i < 10; i++) {
129449
+ await deps.sleepMs(500);
129450
+ const stillOwner = await deps.findPortOwner(port);
129451
+ if (stillOwner !== pid)
129452
+ return true;
129453
+ }
129454
+ return false;
129455
+ }
129456
+ async function reclaimPortFromSquatter(deps, target, pm2Pid, managedPids) {
129457
+ const { name, port } = target;
129458
+ const ownerPid = await deps.findPortOwner(port);
129459
+ if (ownerPid === null)
129460
+ return null;
129461
+ if (typeof pm2Pid === "number" && ownerPid === pm2Pid)
129462
+ return null;
129463
+ if (managedPids.has(ownerPid)) {
129464
+ return `SKIPPED ${name}:${port} squatter pid=${ownerPid} is itself pm2-managed`;
129465
+ }
129466
+ if (!deps.processKill(ownerPid, "SIGTERM")) {
129467
+ return `FAILED ${name}:${port} could not signal pid=${ownerPid} (EPERM/ESRCH)`;
129468
+ }
129469
+ const released = await waitForPortRelease(deps, ownerPid, port);
129470
+ if (!released) {
129471
+ deps.processKill(ownerPid, "SIGKILL");
129472
+ await deps.sleepMs(500);
129473
+ }
129474
+ const code = await deps.runPm2(["restart", name]);
129475
+ if (code !== 0) {
129476
+ return `FAILED ${name}:${port} pm2 restart exited ${code} after killing pid=${ownerPid}`;
129477
+ }
129478
+ return `reclaimed ${name}:${port} from non-pm2 pid=${ownerPid}`;
129479
+ }
129480
+ async function fixPortCanonicalOwner(deps) {
129481
+ const processes = await deps.getPm2Processes();
129482
+ if (!processes) {
129483
+ throw new Error("pm2 not reachable \u2014 cannot reconcile port ownership");
129484
+ }
129485
+ const { serverConfig } = deps.loadState();
129486
+ const targets = canonicalPortTargets(serverConfig);
129487
+ const managedPids = new Set(processes.map((p) => p.pid).filter((p) => typeof p === "number" && p > 0));
129488
+ const repairs = [];
129489
+ for (const target of targets) {
129490
+ const pm2Entry = processes.find((p) => p.name === target.name);
129491
+ const outcome = await reclaimPortFromSquatter(deps, target, pm2Entry?.pid, managedPids);
129492
+ if (outcome !== null)
129493
+ repairs.push(outcome);
129494
+ }
129495
+ if (repairs.length === 0)
129496
+ return "no port-ownership conflicts to reconcile";
129497
+ return repairs.join("; ");
129498
+ }
129499
+ async function restartNonOnlineProcesses(deps) {
129500
+ const processes = await deps.getPm2Processes();
129501
+ if (!processes)
129502
+ return [];
129503
+ const restarted = [];
129504
+ for (const name of [PM2_PROCESSES.api, PM2_PROCESSES.nats]) {
129505
+ const entry = processes.find((p) => p.name === name);
129506
+ if (entry?.pm2_env?.status !== "online") {
129507
+ const code = await deps.runPm2(["restart", name]);
129508
+ if (code === 0)
129509
+ restarted.push(name);
129510
+ }
129511
+ }
129512
+ return restarted;
129513
+ }
129514
+ async function fixPm2Status(deps) {
129515
+ const portRepairs = await fixPortCanonicalOwner(deps);
129516
+ const restarted = await restartNonOnlineProcesses(deps);
129517
+ const parts = [];
129518
+ if (portRepairs !== "no port-ownership conflicts to reconcile")
129519
+ parts.push(portRepairs);
129520
+ if (restarted.length > 0)
129521
+ parts.push(`restarted ${restarted.join(", ")}`);
129522
+ return parts.length > 0 ? parts.join("; ") : "no pm2 status remediation needed";
129523
+ }
129338
129524
  function fixOrphanedDataDirs(deps) {
129339
129525
  const found = deps.findOrphanedDataDirs();
129340
129526
  if (found.length === 0) {
@@ -129400,7 +129586,8 @@ async function runAllChecks(deps) {
129400
129586
  await checkPm2MaxRestarts(deps),
129401
129587
  await checkPm2LogrotateInstalled(deps),
129402
129588
  await checkSigningKeyForLockedInstances(deps),
129403
- checkPgserveCanonical(deps)
129589
+ checkPgserveCanonical(deps),
129590
+ await checkPortCanonicalOwner(deps)
129404
129591
  ];
129405
129592
  }
129406
129593
  async function applyFix(deps, check) {
@@ -129417,6 +129604,10 @@ async function applyFix(deps, check) {
129417
129604
  return await fixPm2LogrotateInstalled(deps);
129418
129605
  if (check.id === "pgserve-canonical")
129419
129606
  return await fixPgserveCanonical(deps);
129607
+ if (check.id === "port-canonical-owner")
129608
+ return await fixPortCanonicalOwner(deps);
129609
+ if (check.id === "pm2-status")
129610
+ return await fixPm2Status(deps);
129420
129611
  return null;
129421
129612
  } catch (err) {
129422
129613
  const msg = err instanceof Error ? err.message : String(err);
@@ -129508,9 +129699,10 @@ Checks:
129508
129699
  orphaned-data-dirs .pgserve-data directories outside ~/.omni
129509
129700
  version-match CLI version vs. /api/v2/health version field
129510
129701
  pm2-status omni-api and omni-nats both online in pm2
129511
- pm2-max-restarts omni-api max_restarts is in the hardened range
129702
+ pm2-max-restarts omni-api + omni-nats max_restarts in hardened range
129512
129703
  pm2-logrotate-installed pm2-logrotate module installed with expected settings
129513
129704
  pgserve-canonical using canonical pgserve@^2.1.0 (shared backbone) vs. embedded
129705
+ port-canonical-owner canonical ports (NATS, API) owned by pm2-managed PIDs
129514
129706
 
129515
129707
  Safety:
129516
129708
  --fix NEVER touches ~/.omni/data/pgserve \u2014 it only operates on the pm2
@@ -129533,7 +129725,7 @@ Safety:
129533
129725
  }
129534
129726
 
129535
129727
  // src/commands/done.ts
129536
- import { existsSync as existsSync8, readFileSync as readFileSync5 } from "fs";
129728
+ import { existsSync as existsSync9, readFileSync as readFileSync5 } from "fs";
129537
129729
  import { basename, extname } from "path";
129538
129730
 
129539
129731
  // src/context.ts
@@ -129642,7 +129834,7 @@ async function handleReact(client, ctx, emoji) {
129642
129834
  await closeTurn(client, "react", `Reacted ${emoji} + turn closed`);
129643
129835
  }
129644
129836
  async function handleMedia(client, ctx, mediaPath, caption) {
129645
- if (!existsSync8(mediaPath)) {
129837
+ if (!existsSync9(mediaPath)) {
129646
129838
  return error(`File not found: ${mediaPath}`);
129647
129839
  }
129648
129840
  try {
@@ -130340,7 +130532,7 @@ function createHistoryCommand() {
130340
130532
 
130341
130533
  // src/commands/imagine.ts
130342
130534
  import { writeFileSync as writeFileSync7 } from "fs";
130343
- import { basename as basename2, dirname as dirname3, extname as extname2, join as join11 } from "path";
130535
+ import { basename as basename2, dirname as dirname3, extname as extname2, join as join12 } from "path";
130344
130536
  init_output();
130345
130537
  var ALLOWED_ASPECT_RATIOS = ["1:1", "4:3", "3:4", "16:9", "9:16", "3:2", "2:3"];
130346
130538
  function extensionForMime(mimeType) {
@@ -130355,9 +130547,9 @@ function buildOutputPath(outputBase, index, total, mimeType) {
130355
130547
  const ext = extname2(outputBase) || extensionForMime(mimeType);
130356
130548
  const stem = basename2(outputBase, extname2(outputBase));
130357
130549
  if (total <= 1) {
130358
- return join11(dir, `${stem}${ext}`);
130550
+ return join12(dir, `${stem}${ext}`);
130359
130551
  }
130360
- return join11(dir, `${stem}-${index + 1}${ext}`);
130552
+ return join12(dir, `${stem}-${index + 1}${ext}`);
130361
130553
  }
130362
130554
  function parseAspectRatio(value) {
130363
130555
  if (!value)
@@ -130475,12 +130667,12 @@ function createImagineCommand() {
130475
130667
  }
130476
130668
 
130477
130669
  // src/commands/install.ts
130478
- import { existsSync as existsSync9, mkdirSync as mkdirSync5 } from "fs";
130670
+ import { existsSync as existsSync10, mkdirSync as mkdirSync5 } from "fs";
130479
130671
  import { homedir as homedir7 } from "os";
130480
- import { join as join12 } from "path";
130672
+ import { join as join13 } from "path";
130481
130673
  init_config();
130482
130674
  init_output();
130483
- var DEFAULT_DATA_DIR2 = join12(homedir7(), ".omni", "data");
130675
+ var DEFAULT_DATA_DIR2 = join13(homedir7(), ".omni", "data");
130484
130676
  function computeDefaultDatabaseUrl() {
130485
130677
  return buildEmbeddedDatabaseUrl();
130486
130678
  }
@@ -130579,7 +130771,7 @@ async function startServices(cfg, forceCleanup, forceSystemd, useCanonicalPgserv
130579
130771
  return false;
130580
130772
  }
130581
130773
  const bundlePath = getServerBundlePath();
130582
- if (!existsSync9(bundlePath)) {
130774
+ if (!existsSync10(bundlePath)) {
130583
130775
  warn(`Server bundle not found at: ${bundlePath}
130584
130776
  Install @automagik/omni from npm: bun add -g @automagik/omni
130585
130777
  Or build locally: make cli-build-full`);
@@ -130603,9 +130795,9 @@ async function startServices(cfg, forceCleanup, forceSystemd, useCanonicalPgserv
130603
130795
  return false;
130604
130796
  }
130605
130797
  apiSpinner.succeed(`${PM2_PROCESSES.api} started`);
130606
- if (existsSync9(NATS_BINARY_PATH)) {
130798
+ if (existsSync10(NATS_BINARY_PATH)) {
130607
130799
  const natsSpinner = ora(`Starting ${PM2_PROCESSES.nats}...`).start();
130608
- const natsDataDir = join12(cfg.dataDir, "nats");
130800
+ const natsDataDir = join13(cfg.dataDir, "nats");
130609
130801
  mkdirSync5(natsDataDir, { recursive: true });
130610
130802
  const natsArgs = buildPm2StartArgs({
130611
130803
  kind: "nats",
@@ -132282,7 +132474,7 @@ function createLogsCommand() {
132282
132474
  }
132283
132475
 
132284
132476
  // src/commands/media.ts
132285
- import { createWriteStream as createWriteStream2, existsSync as existsSync11, mkdirSync as mkdirSync7, statSync as statSync4 } from "fs";
132477
+ import { createWriteStream as createWriteStream2, existsSync as existsSync12, mkdirSync as mkdirSync7, statSync as statSync4 } from "fs";
132286
132478
  import { basename as basename4, dirname as dirname4, resolve as resolve2 } from "path";
132287
132479
  import { Readable } from "stream";
132288
132480
  import { pipeline } from "stream/promises";
@@ -132345,13 +132537,13 @@ function resolveOutputPath(outputPath, result) {
132345
132537
  const resolved = resolve2(outputPath);
132346
132538
  if (isDirHint)
132347
132539
  return resolve2(resolved, filename);
132348
- if (existsSync11(resolved) && statSync4(resolved).isDirectory())
132540
+ if (existsSync12(resolved) && statSync4(resolved).isDirectory())
132349
132541
  return resolve2(resolved, filename);
132350
132542
  return resolved;
132351
132543
  }
132352
132544
  async function downloadToFile(url, apiKey, destinationPath) {
132353
132545
  const destDir = dirname4(destinationPath);
132354
- if (!existsSync11(destDir))
132546
+ if (!existsSync12(destDir))
132355
132547
  mkdirSync7(destDir, { recursive: true });
132356
132548
  const resp = await fetch(url, {
132357
132549
  method: "GET",
@@ -133305,7 +133497,7 @@ init_output();
133305
133497
  init_src();
133306
133498
  import { execFileSync as execFileSync2, execSync } from "child_process";
133307
133499
  import * as nodeCrypto2 from "crypto";
133308
- import { existsSync as existsSync12, mkdirSync as mkdirSync8, readFileSync as readFileSync8, writeFileSync as writeFileSync8 } from "fs";
133500
+ import { existsSync as existsSync13, mkdirSync as mkdirSync8, readFileSync as readFileSync8, writeFileSync as writeFileSync8 } from "fs";
133309
133501
  import { homedir as homedir9 } from "os";
133310
133502
  import { dirname as dirname5, resolve as resolve3 } from "path";
133311
133503
  import { createInterface as createInterface2 } from "readline";
@@ -133536,7 +133728,7 @@ async function pairDevice(gatewayUrl, gatewayToken, keypair, spinner) {
133536
133728
  var OPENCLAW_CONFIG_PATH = resolve3(homedir9(), ".openclaw", "openclaw.json");
133537
133729
  var PLUGIN_MARKER = "plugin-openclaw/omni.ts";
133538
133730
  function readOpenClawConfig(configPath) {
133539
- if (!existsSync12(configPath))
133731
+ if (!existsSync13(configPath))
133540
133732
  return {};
133541
133733
  const raw2 = readFileSync8(configPath, "utf-8").trim();
133542
133734
  if (!raw2)
@@ -133577,10 +133769,10 @@ function isValidUuid2(value) {
133577
133769
  }
133578
133770
  function resolvePluginPath(explicit) {
133579
133771
  if (explicit) {
133580
- return existsSync12(explicit) ? resolve3(explicit) : null;
133772
+ return existsSync13(explicit) ? resolve3(explicit) : null;
133581
133773
  }
133582
133774
  const cwdCandidate = resolve3(process.cwd(), "packages/plugin-openclaw/omni.ts");
133583
- return existsSync12(cwdCandidate) ? cwdCandidate : null;
133775
+ return existsSync13(cwdCandidate) ? cwdCandidate : null;
133584
133776
  }
133585
133777
  function registerPlugin(config2, pluginPath, configPath) {
133586
133778
  if (hasOpenClawCli()) {
@@ -134289,6 +134481,167 @@ ${formatExamples(examples)}`);
134289
134481
  return cmd;
134290
134482
  }
134291
134483
 
134484
+ // src/lib/requirements.ts
134485
+ import { spawn } from "child_process";
134486
+ var REQUIREMENTS = Object.freeze({
134487
+ pgserve: ">=2.3",
134488
+ genie: ">=5.0"
134489
+ });
134490
+ var PEER_BINARIES = Object.freeze({
134491
+ pgserve: "pgserve",
134492
+ genie: "genie"
134493
+ });
134494
+ var PEER_VERSION_TIMEOUT_MS = 5000;
134495
+ function parseVersionTriple(raw2) {
134496
+ const match = raw2.match(/(\d+)\.(\d+)(?:\.(\d+))?/);
134497
+ if (!match)
134498
+ return null;
134499
+ const major = Number.parseInt(match[1] ?? "", 10);
134500
+ const minor = Number.parseInt(match[2] ?? "", 10);
134501
+ const patch = match[3] !== undefined ? Number.parseInt(match[3], 10) : 0;
134502
+ if (!Number.isFinite(major) || !Number.isFinite(minor) || !Number.isFinite(patch))
134503
+ return null;
134504
+ return { major, minor, patch };
134505
+ }
134506
+ function parseConstraint(spec) {
134507
+ const trimmed = spec.trim();
134508
+ if (!trimmed.startsWith(">=")) {
134509
+ throw new Error(`Unsupported version constraint shape: "${spec}". Only \`>=X.Y[.Z]\` is supported by REQUIREMENTS.`);
134510
+ }
134511
+ const triple = parseVersionTriple(trimmed.slice(2));
134512
+ if (!triple) {
134513
+ throw new Error(`Could not parse version triple from constraint: "${spec}"`);
134514
+ }
134515
+ return triple;
134516
+ }
134517
+ function compareVersions(a2, b8) {
134518
+ if (a2.major !== b8.major)
134519
+ return a2.major - b8.major;
134520
+ if (a2.minor !== b8.minor)
134521
+ return a2.minor - b8.minor;
134522
+ return a2.patch - b8.patch;
134523
+ }
134524
+ function fetchPeerVersion(binary) {
134525
+ return new Promise((resolve4) => {
134526
+ let settled = false;
134527
+ let stdout = "";
134528
+ let stderr = "";
134529
+ const proc = spawn(binary, ["--version"], { stdio: ["ignore", "pipe", "pipe"] });
134530
+ const timer2 = setTimeout(() => {
134531
+ if (settled)
134532
+ return;
134533
+ settled = true;
134534
+ proc.kill("SIGTERM");
134535
+ resolve4(null);
134536
+ }, PEER_VERSION_TIMEOUT_MS);
134537
+ timer2.unref();
134538
+ proc.stdout?.setEncoding("utf8");
134539
+ proc.stderr?.setEncoding("utf8");
134540
+ proc.stdout?.on("data", (chunk) => {
134541
+ stdout += chunk;
134542
+ });
134543
+ proc.stderr?.on("data", (chunk) => {
134544
+ stderr += chunk;
134545
+ });
134546
+ proc.on("error", () => {
134547
+ if (settled)
134548
+ return;
134549
+ settled = true;
134550
+ clearTimeout(timer2);
134551
+ resolve4(null);
134552
+ });
134553
+ proc.on("close", (code) => {
134554
+ if (settled)
134555
+ return;
134556
+ settled = true;
134557
+ clearTimeout(timer2);
134558
+ if (code !== 0) {
134559
+ resolve4(null);
134560
+ return;
134561
+ }
134562
+ const out = stdout.trim();
134563
+ if (out.length > 0) {
134564
+ resolve4(out);
134565
+ return;
134566
+ }
134567
+ const err2 = stderr.trim();
134568
+ resolve4(err2.length > 0 ? err2 : null);
134569
+ });
134570
+ });
134571
+ }
134572
+ async function checkPeerVersion(name, currentOverride) {
134573
+ const required = REQUIREMENTS[name];
134574
+ if (!required) {
134575
+ return {
134576
+ name,
134577
+ required: "",
134578
+ current: null,
134579
+ ok: false,
134580
+ reason: `Unknown peer: ${name}. Known peers: ${Object.keys(REQUIREMENTS).join(", ")}.`
134581
+ };
134582
+ }
134583
+ const binary = PEER_BINARIES[name];
134584
+ const raw2 = currentOverride !== undefined ? currentOverride : binary !== undefined ? await fetchPeerVersion(binary) : null;
134585
+ if (raw2 === null) {
134586
+ return {
134587
+ name,
134588
+ required,
134589
+ current: null,
134590
+ ok: false,
134591
+ reason: `Peer "${name}" not installed or did not respond to \`${binary ?? name} --version\` within ${PEER_VERSION_TIMEOUT_MS}ms.`
134592
+ };
134593
+ }
134594
+ const triple = parseVersionTriple(raw2);
134595
+ if (!triple) {
134596
+ return {
134597
+ name,
134598
+ required,
134599
+ current: raw2,
134600
+ ok: false,
134601
+ reason: `Could not parse version triple from \`${binary ?? name} --version\` output: ${JSON.stringify(raw2)}.`
134602
+ };
134603
+ }
134604
+ const ok3 = compareVersions(triple, parseConstraint(required)) >= 0;
134605
+ const currentString = `${triple.major}.${triple.minor}.${triple.patch}`;
134606
+ return {
134607
+ name,
134608
+ required,
134609
+ current: currentString,
134610
+ ok: ok3,
134611
+ reason: ok3 ? undefined : `Peer "${name}" version ${currentString} does not satisfy ${required}. Run \`${binary ?? name} update\` first.`
134612
+ };
134613
+ }
134614
+ async function checkAllPeers() {
134615
+ const out = [];
134616
+ for (const name of Object.keys(REQUIREMENTS)) {
134617
+ out.push(await checkPeerVersion(name));
134618
+ }
134619
+ return out;
134620
+ }
134621
+
134622
+ // src/commands/requirements.ts
134623
+ init_output();
134624
+ function createRequirementsCommand() {
134625
+ return new Command("requirements").description("Show declared peer-version requirements (pgserve, genie) and live status").option("--check", "Exit non-zero if any peer fails its required version").action(async (opts) => {
134626
+ const peers = await checkAllPeers();
134627
+ const allOk = peers.every((p11) => p11.ok);
134628
+ data({
134629
+ requirements: REQUIREMENTS,
134630
+ peers: peers.map((p11) => ({
134631
+ name: p11.name,
134632
+ required: p11.required,
134633
+ current: p11.current,
134634
+ ok: p11.ok,
134635
+ ...p11.reason ? { reason: p11.reason } : {}
134636
+ })),
134637
+ ok: allOk
134638
+ });
134639
+ if (opts.check && !allOk) {
134640
+ process.exitCode = 1;
134641
+ }
134642
+ });
134643
+ }
134644
+
134292
134645
  // src/commands/restart.ts
134293
134646
  init_config();
134294
134647
  init_output();
@@ -134469,7 +134822,7 @@ function createSayCommand() {
134469
134822
  }
134470
134823
 
134471
134824
  // src/commands/see.ts
134472
- import { existsSync as existsSync13, readFileSync as readFileSync9, statSync as statSync5 } from "fs";
134825
+ import { existsSync as existsSync14, readFileSync as readFileSync9, statSync as statSync5 } from "fs";
134473
134826
  import { extname as extname4 } from "path";
134474
134827
  init_output();
134475
134828
  var MIME_BY_EXT = {
@@ -134501,7 +134854,7 @@ function parseMaxTokens(value) {
134501
134854
  return n2;
134502
134855
  }
134503
134856
  function loadMedia(file) {
134504
- if (!existsSync13(file)) {
134857
+ if (!existsSync14(file)) {
134505
134858
  error(`File not found: ${file}`);
134506
134859
  }
134507
134860
  const stat = statSync5(file);
@@ -134587,7 +134940,7 @@ function createSeeCommand() {
134587
134940
  }
134588
134941
 
134589
134942
  // src/commands/send.ts
134590
- import { existsSync as existsSync14, readFileSync as readFileSync10 } from "fs";
134943
+ import { existsSync as existsSync15, readFileSync as readFileSync10 } from "fs";
134591
134944
  import { basename as basename5, extname as extname5 } from "path";
134592
134945
  init_source();
134593
134946
  init_config();
@@ -134628,7 +134981,7 @@ var messageSenders = {
134628
134981
  const { to, media } = options3;
134629
134982
  if (!to || !media)
134630
134983
  return;
134631
- if (!existsSync14(media)) {
134984
+ if (!existsSync15(media)) {
134632
134985
  error(`File not found: ${media}`);
134633
134986
  return;
134634
134987
  }
@@ -135160,9 +135513,9 @@ function pickFilename(mimeType, provider) {
135160
135513
  }
135161
135514
 
135162
135515
  // src/commands/start.ts
135163
- import { existsSync as existsSync15, mkdirSync as mkdirSync9 } from "fs";
135516
+ import { existsSync as existsSync16, mkdirSync as mkdirSync9 } from "fs";
135164
135517
  import { homedir as homedir10 } from "os";
135165
- import { join as join14 } from "path";
135518
+ import { join as join15 } from "path";
135166
135519
  init_config();
135167
135520
  init_output();
135168
135521
  var START_HEALTH_TIMEOUT_MS = 1e4;
@@ -135171,7 +135524,7 @@ async function runStart() {
135171
135524
  pm2NotFoundError();
135172
135525
  }
135173
135526
  const bundlePath = getServerBundlePath();
135174
- if (!existsSync15(bundlePath)) {
135527
+ if (!existsSync16(bundlePath)) {
135175
135528
  bundleNotFoundError(bundlePath);
135176
135529
  }
135177
135530
  const serverConfig = loadServerConfig();
@@ -135192,10 +135545,10 @@ async function runStart() {
135192
135545
  error(`Failed to start ${PM2_PROCESSES.api} (pm2 exit code ${apiCode})`, undefined, 1);
135193
135546
  return;
135194
135547
  }
135195
- const natsPath = join14(homedir10(), ".omni", "nats-server");
135196
- if (existsSync15(natsPath)) {
135548
+ const natsPath = join15(homedir10(), ".omni", "nats-server");
135549
+ if (existsSync16(natsPath)) {
135197
135550
  info(`Starting ${PM2_PROCESSES.nats}...`);
135198
- const natsDataDir = join14(serverConfig.dataDir, "nats");
135551
+ const natsDataDir = join15(serverConfig.dataDir, "nats");
135199
135552
  mkdirSync9(natsDataDir, { recursive: true });
135200
135553
  const natsArgs = buildPm2StartArgs({
135201
135554
  kind: "nats",
@@ -135616,8 +135969,8 @@ function createTurnsCommand() {
135616
135969
  }
135617
135970
 
135618
135971
  // src/commands/update.ts
135619
- import { existsSync as existsSync17 } from "fs";
135620
- import { join as join16 } from "path";
135972
+ import { existsSync as existsSync18 } from "fs";
135973
+ import { join as join17 } from "path";
135621
135974
  import { createInterface as createInterface3 } from "readline";
135622
135975
  init_source();
135623
135976
  init_config();
@@ -135899,9 +136252,9 @@ async function cleanupLegacyArtifacts(skipList) {
135899
136252
  init_output();
135900
136253
 
135901
136254
  // src/update-diagnostics.ts
135902
- import { existsSync as existsSync16, mkdirSync as mkdirSync10, readFileSync as readFileSync11, writeFileSync as writeFileSync9 } from "fs";
136255
+ import { existsSync as existsSync17, mkdirSync as mkdirSync10, readFileSync as readFileSync11, writeFileSync as writeFileSync9 } from "fs";
135903
136256
  import { homedir as homedir11 } from "os";
135904
- import { join as join15 } from "path";
136257
+ import { join as join16 } from "path";
135905
136258
  var UPDATE_DIAGNOSTICS_SCHEMA_VERSION = 1;
135906
136259
  function createDiagnostics(args) {
135907
136260
  const startedAt = new Date().toISOString();
@@ -135923,15 +136276,15 @@ function createDiagnostics(args) {
135923
136276
  };
135924
136277
  }
135925
136278
  function getDiagnosticsDir() {
135926
- const base = process.env.OMNI_CONFIG_DIR ?? join15(homedir11(), ".omni");
135927
- return join15(base, "logs");
136279
+ const base = process.env.OMNI_CONFIG_DIR ?? join16(homedir11(), ".omni");
136280
+ return join16(base, "logs");
135928
136281
  }
135929
136282
  function getDiagnosticsPath(startedAt) {
135930
136283
  const safe = startedAt.replace(/:/g, "-");
135931
- return join15(getDiagnosticsDir(), `update-diagnostics-${safe}.json`);
136284
+ return join16(getDiagnosticsDir(), `update-diagnostics-${safe}.json`);
135932
136285
  }
135933
136286
  function tailFileLines(path, maxLines) {
135934
- if (!existsSync16(path))
136287
+ if (!existsSync17(path))
135935
136288
  return [];
135936
136289
  try {
135937
136290
  const raw2 = readFileSync11(path, "utf8");
@@ -135967,7 +136320,7 @@ function writeDiagnostics(state, exitCode) {
135967
136320
  const dir = getDiagnosticsDir();
135968
136321
  const path = getDiagnosticsPath(state.startedAt);
135969
136322
  try {
135970
- if (!existsSync16(dir)) {
136323
+ if (!existsSync17(dir)) {
135971
136324
  mkdirSync10(dir, { recursive: true, mode: 448 });
135972
136325
  }
135973
136326
  writeFileSync9(path, `${JSON.stringify(state, null, 2)}
@@ -136141,7 +136494,7 @@ function printVerifySkippedBanner(latest) {
136141
136494
  }
136142
136495
  function detectParallelNpmGlobalInstall(deps) {
136143
136496
  const npmRootFn = deps?.npmRoot ?? defaultNpmRoot;
136144
- const existsFn = deps?.exists ?? existsSync17;
136497
+ const existsFn = deps?.exists ?? existsSync18;
136145
136498
  let root;
136146
136499
  try {
136147
136500
  root = npmRootFn();
@@ -136151,7 +136504,7 @@ function detectParallelNpmGlobalInstall(deps) {
136151
136504
  if (root === null || root.length === 0) {
136152
136505
  return { detected: false, skipped: "npm-not-on-path" };
136153
136506
  }
136154
- const candidate = join16(root, "@automagik", "omni");
136507
+ const candidate = join17(root, "@automagik", "omni");
136155
136508
  if (existsFn(candidate)) {
136156
136509
  return { detected: true, path: candidate };
136157
136510
  }
@@ -136302,61 +136655,6 @@ async function promptConfirm(question) {
136302
136655
  });
136303
136656
  });
136304
136657
  }
136305
- var PHASE_2_CUTOFF_MINOR = 260502;
136306
- function isAtOrPastPhase2(version2) {
136307
- const [_major, minorStr] = version2.split(".");
136308
- const minor = Number.parseInt(minorStr ?? "", 10);
136309
- if (!Number.isFinite(minor))
136310
- return false;
136311
- return minor >= PHASE_2_CUTOFF_MINOR;
136312
- }
136313
- function isPgserveOnPath() {
136314
- try {
136315
- const result = Bun.spawnSync({
136316
- cmd: ["pgserve", "port"],
136317
- stdout: "pipe",
136318
- stderr: "pipe",
136319
- timeout: 3000
136320
- });
136321
- return result.exitCode === 0;
136322
- } catch {
136323
- return false;
136324
- }
136325
- }
136326
- function checkCanonicalPgservePreflight(args) {
136327
- if (isAtOrPastPhase2(args.currentVersion))
136328
- return null;
136329
- if (!isAtOrPastPhase2(args.targetVersion))
136330
- return null;
136331
- if (args.useCanonicalPgserve === true)
136332
- return null;
136333
- if (args.useCanonicalPgserve === false)
136334
- return null;
136335
- if (args.pgserveOnPath)
136336
- return null;
136337
- return [
136338
- "Refusing to upgrade \u2014 this would break omni-api on next restart.",
136339
- "",
136340
- ` Target version v${args.targetVersion} ships the phase-2 canonical-pgserve default flip`,
136341
- " (omni#596). Your current install has `useCanonicalPgserve` unset and no `pgserve`",
136342
- " binary on PATH, so omni-api would boot with PGSERVE_EMBEDDED=false and fail to",
136343
- " connect to a non-existent canonical pgserve.",
136344
- "",
136345
- " Pick one of:",
136346
- "",
136347
- " (recommended) Migrate to canonical pgserve:",
136348
- " bun add -g pgserve@^2.1.0",
136349
- " omni doctor --fix # automated pg_dump \u2192 install \u2192 restore",
136350
- " omni update # then re-run",
136351
- "",
136352
- " (transitional) Pin embedded explicitly:",
136353
- " omni config set server.useCanonicalPgserve 'false'",
136354
- " omni update # then re-run",
136355
- "",
136356
- " Bypass this check (NOT recommended) with: omni update --skip-canonical-preflight"
136357
- ].join(`
136358
- `);
136359
- }
136360
136658
  async function runUpdate(options3) {
136361
136659
  const channel2 = resolveChannel(options3);
136362
136660
  if (options3.next || options3.stable) {
@@ -136389,23 +136687,6 @@ async function runUpdate(options3) {
136389
136687
  success(`Already up to date (v${latest}, channel: ${channel2})`);
136390
136688
  return finalize(0);
136391
136689
  }
136392
- if (!options3.skipCanonicalPreflight) {
136393
- diagnostics.preflight.ran = true;
136394
- const serverConfig = loadServerConfig();
136395
- const preflightError = checkCanonicalPgservePreflight({
136396
- currentVersion: currentClean,
136397
- targetVersion: latest,
136398
- useCanonicalPgserve: serverConfig.useCanonicalPgserve,
136399
- pgserveOnPath: isPgserveOnPath()
136400
- });
136401
- if (preflightError !== null) {
136402
- diagnostics.preflight.blocked = true;
136403
- diagnostics.preflight.reason = preflightError.split(`
136404
- `)[0];
136405
- warn(preflightError);
136406
- return finalize(1);
136407
- }
136408
- }
136409
136690
  info(`Update available: v${currentClean} \u2192 v${latest} (${channel2})`);
136410
136691
  if (!options3.yes) {
136411
136692
  const confirmed = await promptConfirm(`Update from v${currentClean} to v${latest}? [Y/n] `);
@@ -136451,7 +136732,7 @@ function parseSkipCleanupList(value) {
136451
136732
  return new Set(names);
136452
136733
  }
136453
136734
  function createUpdateCommand() {
136454
- return new Command("update").description(`Update ${PACKAGE_NAME} to the latest version (restart only services already running)`).option("-y, --yes", "Skip confirmation prompts (non-interactive)").option("--no-restart", "Update CLI only; skip service restarts and verification").option("--no-verify", "Restart services but skip the post-restart probe (use when a release ships a broken /api/v2/health and operators need to roll forward)").option("--no-legacy-cleanup", "Skip every registered legacy-artifact cleanup (e.g. nats-reply-sidecar)").option("--no-sidecar-cleanup", "Deprecated alias for --no-legacy-cleanup").option("--skip-cleanup <names>", 'Comma-separated list of legacy-cleanup registry entries to skip (e.g. "nats-reply-sidecar")').option("--next", "Switch to dev builds (npm @next tag) and persist as default").option("--stable", "Switch to stable releases (npm @latest tag) and persist as default").option("--skip-canonical-preflight", "Bypass the canonical-pgserve phase-2 pre-flight (NOT recommended; for operators who pre-installed pgserve via a path the auto-detector misses)").option("--skip-maintenance", `Skip the post-update maintenance hook (read-only \`omni doctor\` sweep). Also honored via the ${OMNI_UPDATE_SKIP_MAINTENANCE_ENV} env var.`).addHelpText("after", `
136735
+ return new Command("update").description(`Update ${PACKAGE_NAME} to the latest version (restart only services already running)`).option("-y, --yes", "Skip confirmation prompts (non-interactive)").option("--no-restart", "Update CLI only; skip service restarts and verification").option("--no-verify", "Restart services but skip the post-restart probe (use when a release ships a broken /api/v2/health and operators need to roll forward)").option("--no-legacy-cleanup", "Skip every registered legacy-artifact cleanup (e.g. nats-reply-sidecar)").option("--no-sidecar-cleanup", "Deprecated alias for --no-legacy-cleanup").option("--skip-cleanup <names>", 'Comma-separated list of legacy-cleanup registry entries to skip (e.g. "nats-reply-sidecar")').option("--next", "Switch to dev builds (npm @next tag) and persist as default").option("--stable", "Switch to stable releases (npm @latest tag) and persist as default").option("--skip-maintenance", `Skip the post-update maintenance hook (read-only \`omni doctor\` sweep). Also honored via the ${OMNI_UPDATE_SKIP_MAINTENANCE_ENV} env var.`).addHelpText("after", `
136455
136736
  Channels:
136456
136737
  - stable (default) \u2014 tracks the npm @latest tag, bumped from main branch releases.
136457
136738
  - next (dev builds) \u2014 tracks the npm @next tag, bumped on every CI-green dev merge.
@@ -136846,13 +137127,13 @@ init_config();
136846
137127
  init_output();
136847
137128
 
136848
137129
  // src/manifest-pin.ts
136849
- import { existsSync as existsSync18, readFileSync as readFileSync12, renameSync as renameSync3, writeFileSync as writeFileSync10 } from "fs";
137130
+ import { existsSync as existsSync19, readFileSync as readFileSync12, renameSync as renameSync3, writeFileSync as writeFileSync10 } from "fs";
136850
137131
  import { homedir as homedir12 } from "os";
136851
- import { join as join17 } from "path";
137132
+ import { join as join18 } from "path";
136852
137133
  var PACKAGE_NAME2 = "@automagik/omni";
136853
- var BUN_GLOBAL_MANIFEST = join17(homedir12(), ".bun", "install", "global", "package.json");
137134
+ var BUN_GLOBAL_MANIFEST = join18(homedir12(), ".bun", "install", "global", "package.json");
136854
137135
  function pinManifestEntry(manifestPath, exactVersion) {
136855
- if (!existsSync18(manifestPath))
137136
+ if (!existsSync19(manifestPath))
136856
137137
  return false;
136857
137138
  let manifest;
136858
137139
  try {
@@ -137296,6 +137577,12 @@ var COMMANDS = [
137296
137577
  helpGroup: "System",
137297
137578
  helpDescription: "Diagnose and repair the embedded omni runtime"
137298
137579
  },
137580
+ {
137581
+ create: createRequirementsCommand,
137582
+ category: "standard",
137583
+ helpGroup: "System",
137584
+ helpDescription: "Show declared peer-version requirements (pgserve, genie)"
137585
+ },
137299
137586
  {
137300
137587
  create: createMediaCommand,
137301
137588
  category: "standard",