@suveren/gateway 0.13.1 → 0.14.0

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.
@@ -316,6 +316,11 @@ async function start(args) {
316
316
  detached: true,
317
317
  stdio: ['ignore', out, out],
318
318
  env: process.env,
319
+ // Windows: `detached` gives the child its OWN console, which shows as a
320
+ // window for the gateway's whole lifetime — and closing it kills the
321
+ // gateway. Output goes to the log file anyway, so hide it. No effect
322
+ // on macOS/Linux.
323
+ windowsHide: true,
319
324
  });
320
325
  writeFileSync(PID_FILE, String(child.pid), 'utf8');
321
326
  child.unref();
@@ -5,8 +5,8 @@ import {
5
5
 
6
6
  // src/index.ts
7
7
  import { randomBytes as randomBytes3 } from "crypto";
8
- import { existsSync as existsSync10, readFileSync as readFileSync12, renameSync as renameSync2 } from "fs";
9
- import { dirname as dirname8, join as join12 } from "path";
8
+ import { existsSync as existsSync11, readFileSync as readFileSync13, renameSync as renameSync2 } from "fs";
9
+ import { dirname as dirname9, join as join13 } from "path";
10
10
  import { homedir as homedir7 } from "os";
11
11
  import express from "express";
12
12
  import { createProxyMiddleware } from "http-proxy-middleware";
@@ -292,6 +292,35 @@ var Vault = class {
292
292
  }
293
293
  };
294
294
 
295
+ // src/lib/install-method.ts
296
+ import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
297
+ import { dirname as dirname2, join as join2 } from "path";
298
+ var INSTALL_MARKER = "install-method.json";
299
+ function readInstallMarker(bundleRoot) {
300
+ const file = join2(bundleRoot, INSTALL_MARKER);
301
+ if (!existsSync2(file)) return null;
302
+ try {
303
+ const parsed = JSON.parse(readFileSync2(file, "utf8"));
304
+ return typeof parsed.method === "string" ? parsed.method : null;
305
+ } catch {
306
+ return null;
307
+ }
308
+ }
309
+ function detectInstallMethod({ dir, dockerEnv, managed }) {
310
+ if (managed) return "managed";
311
+ if (readInstallMarker(dirname2(dirname2(dir))) === "msi") return "msi";
312
+ if (dockerEnv) return "docker";
313
+ if (dir.includes("/node_modules/@suveren/gateway/")) return "npm";
314
+ let cursor = dir;
315
+ for (let i = 0; i < 8; i++) {
316
+ if (existsSync2(join2(cursor, ".git"))) return "dev";
317
+ const parent = dirname2(cursor);
318
+ if (parent === cursor) break;
319
+ cursor = parent;
320
+ }
321
+ return "npm";
322
+ }
323
+
295
324
  // src/routes/auth.ts
296
325
  import { Router } from "express";
297
326
 
@@ -632,12 +661,12 @@ async function loadOrGenerateKeyPair(vault2) {
632
661
  }
633
662
 
634
663
  // src/lib/client-version.ts
635
- import { readFileSync as readFileSync2 } from "fs";
636
- import { join as join2 } from "path";
664
+ import { readFileSync as readFileSync3 } from "fs";
665
+ import { join as join3 } from "path";
637
666
  var UNKNOWN = "unknown";
638
667
  function readJson(path) {
639
668
  try {
640
- return JSON.parse(readFileSync2(path, "utf8"));
669
+ return JSON.parse(readFileSync3(path, "utf8"));
641
670
  } catch {
642
671
  return null;
643
672
  }
@@ -648,13 +677,13 @@ function detectGatewayVersion() {
648
677
  const start = import.meta.dirname ?? process.cwd();
649
678
  let dir = start;
650
679
  for (let up = 0; up < 6; up++) {
651
- const pkg = readJson(join2(dir, "package.json"));
680
+ const pkg = readJson(join3(dir, "package.json"));
652
681
  const name = pkg?.name;
653
682
  const version = pkg?.version;
654
683
  if (typeof version === "string" && (name === "@suveren/gateway" || name === "suveren-gateway")) {
655
684
  return version;
656
685
  }
657
- const parent = join2(dir, "..");
686
+ const parent = join3(dir, "..");
658
687
  if (parent === dir) break;
659
688
  dir = parent;
660
689
  }
@@ -669,16 +698,16 @@ function clientVersionHeaders() {
669
698
 
670
699
  // src/lib/as-pairing.ts
671
700
  import { createHash as createHash2 } from "crypto";
672
- import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync3, unlinkSync, writeFileSync as writeFileSync2 } from "fs";
673
- import { dirname as dirname2, join as join3 } from "path";
701
+ import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync4, unlinkSync, writeFileSync as writeFileSync2 } from "fs";
702
+ import { dirname as dirname3, join as join4 } from "path";
674
703
  function pairingPath(dataDir) {
675
- return join3(dataDir, "as-pairing.json");
704
+ return join4(dataDir, "as-pairing.json");
676
705
  }
677
706
  function readPairing(dataDir) {
678
707
  const path = pairingPath(dataDir);
679
- if (!existsSync2(path)) return null;
708
+ if (!existsSync3(path)) return null;
680
709
  try {
681
- const data = JSON.parse(readFileSync3(path, "utf-8"));
710
+ const data = JSON.parse(readFileSync4(path, "utf-8"));
682
711
  if (typeof data.asUrl !== "string" || typeof data.publicKeyHex !== "string") return null;
683
712
  return {
684
713
  asUrl: data.asUrl,
@@ -698,7 +727,7 @@ function writePairing(dataDir, asUrl, publicKeyHex, opts = {}) {
698
727
  ...opts.tlsSpkiPinHex ? { tlsSpkiPinHex: opts.tlsSpkiPinHex } : {}
699
728
  };
700
729
  const path = pairingPath(dataDir);
701
- mkdirSync2(dirname2(path), { recursive: true, mode: 448 });
730
+ mkdirSync2(dirname3(path), { recursive: true, mode: 448 });
702
731
  writeFileSync2(path, JSON.stringify(pairing, null, 2), { encoding: "utf-8", mode: 384 });
703
732
  return pairing;
704
733
  }
@@ -715,7 +744,7 @@ function recordTlsPin(dataDir, asUrl, tlsSpkiPinHex) {
715
744
  function clearPairing(dataDir) {
716
745
  const path = pairingPath(dataDir);
717
746
  try {
718
- if (existsSync2(path)) unlinkSync(path);
747
+ if (existsSync3(path)) unlinkSync(path);
719
748
  } catch {
720
749
  }
721
750
  }
@@ -733,7 +762,7 @@ import { canonicalize } from "@hap/core";
733
762
  import { createHash as createHash3 } from "crypto";
734
763
  import { checkServerIdentity as defaultCheckServerIdentity, rootCertificates } from "tls";
735
764
  import { Agent as HttpsAgent2 } from "https";
736
- import { readFileSync as readFileSync4 } from "fs";
765
+ import { readFileSync as readFileSync5 } from "fs";
737
766
  import { Agent, ProxyAgent, fetch as undiciFetch } from "undici";
738
767
 
739
768
  // src/lib/proxy-env.ts
@@ -868,7 +897,7 @@ function effectiveCa() {
868
897
  const path = process.env.NODE_EXTRA_CA_CERTS;
869
898
  if (!path) return void 0;
870
899
  try {
871
- return [...rootCertificates, readFileSync4(path, "utf-8")];
900
+ return [...rootCertificates, readFileSync5(path, "utf-8")];
872
901
  } catch {
873
902
  return void 0;
874
903
  }
@@ -1172,12 +1201,12 @@ async function verifyAsHoldsKey(asUrl, publicKeyHex, pinning = { enforce: false,
1172
1201
  }
1173
1202
 
1174
1203
  // src/lib/as-config.ts
1175
- import { existsSync as existsSync4, mkdirSync as mkdirSync3, readFileSync as readFileSync6, writeFileSync as writeFileSync3 } from "fs";
1176
- import { dirname as dirname3, join as join5 } from "path";
1204
+ import { existsSync as existsSync5, mkdirSync as mkdirSync3, readFileSync as readFileSync7, writeFileSync as writeFileSync3 } from "fs";
1205
+ import { dirname as dirname4, join as join6 } from "path";
1177
1206
 
1178
1207
  // src/lib/policy.ts
1179
- import { existsSync as existsSync3, readFileSync as readFileSync5 } from "fs";
1180
- import { join as join4 } from "path";
1208
+ import { existsSync as existsSync4, readFileSync as readFileSync6 } from "fs";
1209
+ import { join as join5 } from "path";
1181
1210
  import { spawnSync } from "child_process";
1182
1211
  var POLICY_KEYS = ["AsUrl", "CaFile", "PinTls", "Proxy", "NoProxy", "Simulation", "InstallMethod"];
1183
1212
  var DEFAULT_REGISTRY_BASE_KEY = "SOFTWARE\\Policies\\Suveren\\Gateway";
@@ -1212,7 +1241,7 @@ function validateAsUrl(candidate) {
1212
1241
  function validateCaFile(candidate) {
1213
1242
  const trimmed = candidate.trim();
1214
1243
  if (!trimmed) return { ok: false, error: "The CA file path is empty." };
1215
- if (!existsSync3(trimmed)) return { ok: false, error: `No file at "${trimmed}".` };
1244
+ if (!existsSync4(trimmed)) return { ok: false, error: `No file at "${trimmed}".` };
1216
1245
  return { ok: true, path: trimmed };
1217
1246
  }
1218
1247
  function validateProxyUrl(candidate) {
@@ -1278,7 +1307,7 @@ function policyFilePath() {
1278
1307
  if (process.env.SUVEREN_POLICY_FILE) return process.env.SUVEREN_POLICY_FILE;
1279
1308
  if (process.platform === "win32") {
1280
1309
  const programData = process.env.ProgramData || process.env.PROGRAMDATA || "C:\\ProgramData";
1281
- return join4(programData, "Suveren", "gateway-policy.json");
1310
+ return join5(programData, "Suveren", "gateway-policy.json");
1282
1311
  }
1283
1312
  if (process.platform === "darwin") {
1284
1313
  return "/Library/Application Support/Suveren/gateway-policy.json";
@@ -1288,10 +1317,10 @@ function policyFilePath() {
1288
1317
  function readPolicyFile() {
1289
1318
  const path = policyFilePath();
1290
1319
  const source = `the policy file (${path})`;
1291
- if (!existsSync3(path)) return { values: {}, source };
1320
+ if (!existsSync4(path)) return { values: {}, source };
1292
1321
  let data;
1293
1322
  try {
1294
- data = JSON.parse(readFileSync5(path, "utf8"));
1323
+ data = JSON.parse(readFileSync6(path, "utf8"));
1295
1324
  } catch (err) {
1296
1325
  throw new Error(`Could not parse policy file ${path}: ${err instanceof Error ? err.message : String(err)}`);
1297
1326
  }
@@ -1395,14 +1424,14 @@ function readPolicy() {
1395
1424
  // src/lib/as-config.ts
1396
1425
  var DEFAULT_AS_URL = "https://www.suveren.ai";
1397
1426
  function configPath(dataDir) {
1398
- return join5(dataDir, "config.json");
1427
+ return join6(dataDir, "config.json");
1399
1428
  }
1400
1429
  function readAsConfigStrict(dataDir) {
1401
1430
  const path = configPath(dataDir);
1402
- if (!existsSync4(path)) return {};
1431
+ if (!existsSync5(path)) return {};
1403
1432
  let data;
1404
1433
  try {
1405
- data = JSON.parse(readFileSync6(path, "utf-8"));
1434
+ data = JSON.parse(readFileSync7(path, "utf-8"));
1406
1435
  } catch (err) {
1407
1436
  throw new Error(
1408
1437
  `Could not parse ${path}: ${err instanceof Error ? err.message : String(err)}`
@@ -1417,9 +1446,9 @@ function readAsConfigStrict(dataDir) {
1417
1446
  }
1418
1447
  function readAsConfig(dataDir) {
1419
1448
  const path = configPath(dataDir);
1420
- if (!existsSync4(path)) return {};
1449
+ if (!existsSync5(path)) return {};
1421
1450
  try {
1422
- const data = JSON.parse(readFileSync6(path, "utf-8"));
1451
+ const data = JSON.parse(readFileSync7(path, "utf-8"));
1423
1452
  const out = {};
1424
1453
  if (typeof data.asUrl === "string") out.asUrl = data.asUrl;
1425
1454
  if (typeof data.caFile === "string") out.caFile = data.caFile;
@@ -1433,7 +1462,7 @@ function readAsConfig(dataDir) {
1433
1462
  function writeAsConfig(dataDir, patch) {
1434
1463
  const merged = { ...readAsConfig(dataDir), ...patch };
1435
1464
  const path = configPath(dataDir);
1436
- mkdirSync3(dirname3(path), { recursive: true, mode: 448 });
1465
+ mkdirSync3(dirname4(path), { recursive: true, mode: 448 });
1437
1466
  writeFileSync3(path, JSON.stringify(merged, null, 2), { encoding: "utf-8", mode: 384 });
1438
1467
  return merged;
1439
1468
  }
@@ -2437,18 +2466,18 @@ async function testAIConnectivity(config) {
2437
2466
  }
2438
2467
 
2439
2468
  // src/lib/agent-brief-store.ts
2440
- import { existsSync as existsSync5, readFileSync as readFileSync7 } from "fs";
2469
+ import { existsSync as existsSync6, readFileSync as readFileSync8 } from "fs";
2441
2470
  import { homedir as homedir2 } from "os";
2442
- import { join as join6 } from "path";
2471
+ import { join as join7 } from "path";
2443
2472
  var AGENT_CONTEXT_MAX_BYTES = 16 * 1024;
2444
2473
  function agentBriefPath() {
2445
- const dataDir = process.env.SUVEREN_DATA_DIR ?? join6(homedir2(), ".suveren");
2446
- return join6(dataDir, "context.md");
2474
+ const dataDir = process.env.SUVEREN_DATA_DIR ?? join7(homedir2(), ".suveren");
2475
+ return join7(dataDir, "context.md");
2447
2476
  }
2448
2477
  function readAgentBrief() {
2449
2478
  const filePath = agentBriefPath();
2450
- if (!existsSync5(filePath)) return "";
2451
- return readFileSync7(filePath, "utf-8");
2479
+ if (!existsSync6(filePath)) return "";
2480
+ return readFileSync8(filePath, "utf-8");
2452
2481
  }
2453
2482
 
2454
2483
  // src/routes/ai.ts
@@ -2812,28 +2841,28 @@ function createMCPRouter() {
2812
2841
  // src/routes/autostart.ts
2813
2842
  import { Router as Router6 } from "express";
2814
2843
  import { execFile } from "child_process";
2815
- import { existsSync as existsSync6 } from "fs";
2844
+ import { existsSync as existsSync7 } from "fs";
2816
2845
  import { dirname as pathDirname, resolve } from "path";
2817
2846
  import { fileURLToPath } from "url";
2818
2847
  import { promisify } from "util";
2819
2848
  var run = promisify(execFile);
2820
2849
  var SUPPORTED = /* @__PURE__ */ new Set(["darwin", "win32", "linux"]);
2821
2850
  var MODULE_DIR = pathDirname(fileURLToPath(import.meta.url));
2822
- function findCli(dirname9 = MODULE_DIR) {
2851
+ function findCli(dirname10 = MODULE_DIR) {
2823
2852
  const candidates = [
2824
2853
  // Bundled (the shipped layout): dist/control-plane → dist → root → bin
2825
- resolve(dirname9, "..", "..", "bin", "suveren-gateway.js"),
2854
+ resolve(dirname10, "..", "..", "bin", "suveren-gateway.js"),
2826
2855
  // Bundled, were the routes/ directory ever preserved.
2827
- resolve(dirname9, "..", "..", "..", "bin", "suveren-gateway.js"),
2856
+ resolve(dirname10, "..", "..", "..", "bin", "suveren-gateway.js"),
2828
2857
  // Dev, running from source: the repo's own bundle directory.
2829
- resolve(dirname9, "..", "..", "..", "..", "bundle", "bin", "suveren-gateway.js"),
2830
- resolve(dirname9, "..", "..", "..", "..", "..", "bundle", "bin", "suveren-gateway.js")
2858
+ resolve(dirname10, "..", "..", "..", "..", "bundle", "bin", "suveren-gateway.js"),
2859
+ resolve(dirname10, "..", "..", "..", "..", "..", "bundle", "bin", "suveren-gateway.js")
2831
2860
  // Deliberately NO process.cwd() fallback: it makes the result depend on
2832
2861
  // where the process happened to be launched from, so the same install
2833
2862
  // resolves differently between a shell and a login service — and it would
2834
2863
  // mask a genuinely missing CLI whenever the cwd happened to be the repo.
2835
2864
  ];
2836
- return candidates.find(existsSync6) ?? null;
2865
+ return candidates.find(existsSync7) ?? null;
2837
2866
  }
2838
2867
  async function cli(args) {
2839
2868
  const bin = findCli();
@@ -2914,16 +2943,16 @@ function createAutostartRouter() {
2914
2943
  import { spawn, spawnSync as spawnSync2 } from "child_process";
2915
2944
 
2916
2945
  // src/lib/notifier-icon.ts
2917
- import { writeFileSync as writeFileSync4, mkdirSync as mkdirSync4, existsSync as existsSync7 } from "fs";
2946
+ import { writeFileSync as writeFileSync4, mkdirSync as mkdirSync4, existsSync as existsSync8 } from "fs";
2918
2947
  import { homedir as homedir3 } from "os";
2919
- import { join as join7, dirname as dirname4 } from "path";
2948
+ import { join as join8, dirname as dirname5 } from "path";
2920
2949
  var ICON_BASE64 = "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";
2921
2950
  function ensureNotifierIcon(dataDir) {
2922
2951
  try {
2923
- const dir = dataDir ?? process.env.SUVEREN_DATA_DIR ?? join7(homedir3(), ".suveren");
2924
- const path = join7(dir, "notifier-icon.png");
2925
- if (!existsSync7(path)) {
2926
- mkdirSync4(dirname4(path), { recursive: true });
2952
+ const dir = dataDir ?? process.env.SUVEREN_DATA_DIR ?? join8(homedir3(), ".suveren");
2953
+ const path = join8(dir, "notifier-icon.png");
2954
+ if (!existsSync8(path)) {
2955
+ mkdirSync4(dirname5(path), { recursive: true });
2927
2956
  writeFileSync4(path, Buffer.from(ICON_BASE64, "base64"));
2928
2957
  }
2929
2958
  return path;
@@ -3126,17 +3155,17 @@ import { Router as Router9 } from "express";
3126
3155
 
3127
3156
  // src/routes/approved-intents.ts
3128
3157
  import { Router as Router8 } from "express";
3129
- import { readFileSync as readFileSync8, writeFileSync as writeFileSync5, existsSync as existsSync8, mkdirSync as mkdirSync5 } from "fs";
3158
+ import { readFileSync as readFileSync9, writeFileSync as writeFileSync5, existsSync as existsSync9, mkdirSync as mkdirSync5 } from "fs";
3130
3159
  import { homedir as homedir4 } from "os";
3131
- import { join as join8 } from "path";
3132
- var SUVEREN_DATA_DIR = process.env.SUVEREN_DATA_DIR ?? join8(homedir4(), ".suveren");
3133
- var FILE_PATH = join8(SUVEREN_DATA_DIR, "approved-intents.enc.json");
3160
+ import { join as join9 } from "path";
3161
+ var SUVEREN_DATA_DIR = process.env.SUVEREN_DATA_DIR ?? join9(homedir4(), ".suveren");
3162
+ var FILE_PATH = join9(SUVEREN_DATA_DIR, "approved-intents.enc.json");
3134
3163
  function readFile() {
3135
- if (!existsSync8(FILE_PATH)) {
3164
+ if (!existsSync9(FILE_PATH)) {
3136
3165
  return { version: 1, entries: {} };
3137
3166
  }
3138
3167
  try {
3139
- return JSON.parse(readFileSync8(FILE_PATH, "utf-8"));
3168
+ return JSON.parse(readFileSync9(FILE_PATH, "utf-8"));
3140
3169
  } catch {
3141
3170
  return { version: 1, entries: {} };
3142
3171
  }
@@ -3420,7 +3449,7 @@ function createDecryptIntentRouter(vault2) {
3420
3449
 
3421
3450
  // src/lib/update-checker.ts
3422
3451
  import { execSync } from "child_process";
3423
- import { dirname as dirname5 } from "path";
3452
+ import { dirname as dirname6 } from "path";
3424
3453
  import { fileURLToPath as fileURLToPath2 } from "url";
3425
3454
  var GHCR_IMAGE = "suverenai/suveren-gateway";
3426
3455
  var NPM_PACKAGE = "@suveren/gateway";
@@ -3486,7 +3515,7 @@ function compareSemver(a, b) {
3486
3515
  return 0;
3487
3516
  }
3488
3517
  function checkDev() {
3489
- const cwd = dirname5(fileURLToPath2(import.meta.url));
3518
+ const cwd = dirname6(fileURLToPath2(import.meta.url));
3490
3519
  try {
3491
3520
  execSync("git fetch origin --quiet", { cwd, stdio: "ignore", timeout: 15e3 });
3492
3521
  const out = execSync("git rev-list HEAD..origin/main --count", {
@@ -3509,7 +3538,7 @@ async function check() {
3509
3538
  checkDev();
3510
3539
  return;
3511
3540
  }
3512
- if (installMethod === "npm" || installMethod === "managed") {
3541
+ if (installMethod === "npm" || installMethod === "managed" || installMethod === "msi") {
3513
3542
  await checkNpm();
3514
3543
  return;
3515
3544
  }
@@ -3559,19 +3588,19 @@ data: ${data}
3559
3588
  import { Router as Router12 } from "express";
3560
3589
 
3561
3590
  // src/lib/gateway-settings.ts
3562
- import { readFileSync as readFileSync9, writeFileSync as writeFileSync6, mkdirSync as mkdirSync6 } from "fs";
3591
+ import { readFileSync as readFileSync10, writeFileSync as writeFileSync6, mkdirSync as mkdirSync6 } from "fs";
3563
3592
  import { homedir as homedir5 } from "os";
3564
- import { join as join9, dirname as dirname6 } from "path";
3593
+ import { join as join10, dirname as dirname7 } from "path";
3565
3594
  var DEFAULT_SETTINGS = {
3566
3595
  desktopNotifications: true
3567
3596
  };
3568
3597
  function settingsPath(dataDir) {
3569
- const dir = dataDir ?? process.env.SUVEREN_DATA_DIR ?? join9(homedir5(), ".suveren");
3570
- return join9(dir, "settings.json");
3598
+ const dir = dataDir ?? process.env.SUVEREN_DATA_DIR ?? join10(homedir5(), ".suveren");
3599
+ return join10(dir, "settings.json");
3571
3600
  }
3572
3601
  function readSettings(dataDir) {
3573
3602
  try {
3574
- const raw = JSON.parse(readFileSync9(settingsPath(dataDir), "utf8"));
3603
+ const raw = JSON.parse(readFileSync10(settingsPath(dataDir), "utf8"));
3575
3604
  return {
3576
3605
  desktopNotifications: typeof raw.desktopNotifications === "boolean" ? raw.desktopNotifications : DEFAULT_SETTINGS.desktopNotifications
3577
3606
  };
@@ -3585,7 +3614,7 @@ function writeSettings(patch, dataDir) {
3585
3614
  ...typeof patch.desktopNotifications === "boolean" ? { desktopNotifications: patch.desktopNotifications } : {}
3586
3615
  };
3587
3616
  const path = settingsPath(dataDir);
3588
- mkdirSync6(dirname6(path), { recursive: true });
3617
+ mkdirSync6(dirname7(path), { recursive: true });
3589
3618
  writeFileSync6(path, JSON.stringify(next, null, 2) + "\n", "utf8");
3590
3619
  return next;
3591
3620
  }
@@ -3618,20 +3647,20 @@ function createGatewaySettingsRouter() {
3618
3647
  import { Router as Router13 } from "express";
3619
3648
 
3620
3649
  // src/lib/archived-mandates-store.ts
3621
- import { readFileSync as readFileSync10, writeFileSync as writeFileSync7, mkdirSync as mkdirSync7, renameSync } from "fs";
3650
+ import { readFileSync as readFileSync11, writeFileSync as writeFileSync7, mkdirSync as mkdirSync7, renameSync } from "fs";
3622
3651
  import { homedir as homedir6 } from "os";
3623
- import { join as join10, dirname as dirname7 } from "path";
3652
+ import { join as join11, dirname as dirname8 } from "path";
3624
3653
  var ID_PATTERN = /^[A-Za-z0-9_.:-]{1,200}$/;
3625
3654
  function isValidMandateId(id) {
3626
3655
  return typeof id === "string" && ID_PATTERN.test(id);
3627
3656
  }
3628
3657
  function storePath(dataDir) {
3629
- const dir = dataDir ?? process.env.SUVEREN_DATA_DIR ?? join10(homedir6(), ".suveren");
3630
- return join10(dir, "archived-mandates.json");
3658
+ const dir = dataDir ?? process.env.SUVEREN_DATA_DIR ?? join11(homedir6(), ".suveren");
3659
+ return join11(dir, "archived-mandates.json");
3631
3660
  }
3632
3661
  function readArchived(dataDir) {
3633
3662
  try {
3634
- const raw = JSON.parse(readFileSync10(storePath(dataDir), "utf8"));
3663
+ const raw = JSON.parse(readFileSync11(storePath(dataDir), "utf8"));
3635
3664
  if (!Array.isArray(raw.archived)) return [];
3636
3665
  return [...new Set(raw.archived.filter(isValidMandateId))];
3637
3666
  } catch {
@@ -3641,7 +3670,7 @@ function readArchived(dataDir) {
3641
3670
  function writeArchived(ids, dataDir) {
3642
3671
  const next = [...new Set(ids.filter(isValidMandateId))].sort();
3643
3672
  const path = storePath(dataDir);
3644
- mkdirSync7(dirname7(path), { recursive: true });
3673
+ mkdirSync7(dirname8(path), { recursive: true });
3645
3674
  const tmp = `${path}.tmp`;
3646
3675
  writeFileSync7(tmp, JSON.stringify({ archived: next }, null, 2) + "\n", "utf8");
3647
3676
  renameSync(tmp, path);
@@ -3937,17 +3966,17 @@ function buildSessionHealth(vault2) {
3937
3966
  }
3938
3967
 
3939
3968
  // src/lib/denials-reader.ts
3940
- import { existsSync as existsSync9, readFileSync as readFileSync11 } from "fs";
3941
- import { join as join11 } from "path";
3969
+ import { existsSync as existsSync10, readFileSync as readFileSync12 } from "fs";
3970
+ import { join as join12 } from "path";
3942
3971
  function loadDenials(dataDir, decrypt) {
3943
- const encPath = join11(dataDir, "denials.enc.json");
3944
- const plainPath = join11(dataDir, "denials.json");
3945
- if (existsSync9(encPath)) {
3946
- const { blob } = JSON.parse(readFileSync11(encPath, "utf-8"));
3972
+ const encPath = join12(dataDir, "denials.enc.json");
3973
+ const plainPath = join12(dataDir, "denials.json");
3974
+ if (existsSync10(encPath)) {
3975
+ const { blob } = JSON.parse(readFileSync12(encPath, "utf-8"));
3947
3976
  return JSON.parse(decrypt(blob)).records ?? [];
3948
3977
  }
3949
- if (existsSync9(plainPath)) {
3950
- return JSON.parse(readFileSync11(plainPath, "utf-8")).records ?? [];
3978
+ if (existsSync10(plainPath)) {
3979
+ return JSON.parse(readFileSync12(plainPath, "utf-8")).records ?? [];
3951
3980
  }
3952
3981
  return [];
3953
3982
  }
@@ -3971,9 +4000,9 @@ function isSimulationMode() {
3971
4000
  // src/index.ts
3972
4001
  (function migrateDataDir() {
3973
4002
  if (process.env.SUVEREN_DATA_DIR) return;
3974
- const oldDir = join12(homedir7(), ".hap");
3975
- const newDir = join12(homedir7(), ".suveren");
3976
- if (!existsSync10(newDir) && existsSync10(oldDir)) {
4003
+ const oldDir = join13(homedir7(), ".hap");
4004
+ const newDir = join13(homedir7(), ".suveren");
4005
+ if (!existsSync11(newDir) && existsSync11(oldDir)) {
3977
4006
  try {
3978
4007
  renameSync2(oldDir, newDir);
3979
4008
  console.error(`[Control Plane] Migrated data directory: ${oldDir} \u2192 ${newDir}`);
@@ -3983,14 +4012,14 @@ function isSimulationMode() {
3983
4012
  }
3984
4013
  }
3985
4014
  })();
3986
- var DATA_DIR = process.env.SUVEREN_DATA_DIR ?? join12(homedir7(), ".suveren");
4015
+ var DATA_DIR = process.env.SUVEREN_DATA_DIR ?? join13(homedir7(), ".suveren");
3987
4016
  var SP_URL = resolveAsUrl(DATA_DIR);
3988
4017
  validatePinTlsForUrl(resolvePinTls(DATA_DIR), SP_URL);
3989
4018
  var POLICY_LOCKED = [...readPolicy().locked];
3990
4019
  var POLICY_LOCKED_INSTALL_METHOD = readPolicy().policy.installMethod;
3991
4020
  var port = parseInt(process.env.SUVEREN_CP_PORT ?? "3402", 10);
3992
4021
  var HAP_MODE = process.env.HAP_MODE ?? "personal";
3993
- var UI_DIST = process.env.HAP_UI_DIST ?? join12(import.meta.dirname ?? __dirname, "../../ui/dist");
4022
+ var UI_DIST = process.env.HAP_UI_DIST ?? join13(import.meta.dirname ?? __dirname, "../../ui/dist");
3994
4023
  var vault = new Vault(DATA_DIR);
3995
4024
  (function repairIfAsUrlChanged() {
3996
4025
  const pairing = readPairing(DATA_DIR);
@@ -4414,7 +4443,7 @@ app.get("/as-pairing", authGuard, (_req, res) => {
4414
4443
  });
4415
4444
  app.get("/denials", authGuard, (req, res) => {
4416
4445
  try {
4417
- const dataDir = process.env.SUVEREN_DATA_DIR ?? join12(homedir7(), ".suveren");
4446
+ const dataDir = process.env.SUVEREN_DATA_DIR ?? join13(homedir7(), ".suveren");
4418
4447
  const all = loadDenials(dataDir, (blob) => vault.decrypt(blob));
4419
4448
  const since = Number(req.query.since);
4420
4449
  const limit = Number(req.query.limit);
@@ -4467,7 +4496,7 @@ app.put("/agent-brief/context", jsonParser, authGuard, async (req, res) => {
4467
4496
  }
4468
4497
  const { mkdirSync: mkdirSync8, writeFileSync: writeFileSync8, renameSync: renameSync3 } = await import("fs");
4469
4498
  const filePath = agentBriefPath();
4470
- mkdirSync8(dirname8(filePath), { recursive: true });
4499
+ mkdirSync8(dirname9(filePath), { recursive: true });
4471
4500
  const tmpPath = `${filePath}.tmp`;
4472
4501
  writeFileSync8(tmpPath, content, "utf-8");
4473
4502
  renameSync3(tmpPath, filePath);
@@ -4544,30 +4573,23 @@ app.use(
4544
4573
  }
4545
4574
  })
4546
4575
  );
4547
- function detectInstallMethod() {
4548
- if (process.env.SUVEREN_INSTALL_METHOD === "managed" || POLICY_LOCKED_INSTALL_METHOD === "managed") return "managed";
4549
- if (existsSync10("/.dockerenv")) return "docker";
4550
- const dir = import.meta.dirname ?? __dirname;
4551
- if (dir.includes("/node_modules/@suveren/gateway/")) return "npm";
4552
- let cursor = dir;
4553
- for (let i = 0; i < 8; i++) {
4554
- if (existsSync10(join12(cursor, ".git"))) return "dev";
4555
- const parent = dirname8(cursor);
4556
- if (parent === cursor) break;
4557
- cursor = parent;
4558
- }
4559
- return "npm";
4576
+ function detectInstallMethod2() {
4577
+ return detectInstallMethod({
4578
+ dir: import.meta.dirname ?? __dirname,
4579
+ dockerEnv: existsSync11("/.dockerenv"),
4580
+ managed: process.env.SUVEREN_INSTALL_METHOD === "managed" || POLICY_LOCKED_INSTALL_METHOD === "managed"
4581
+ });
4560
4582
  }
4561
- var INSTALL_METHOD = detectInstallMethod();
4583
+ var INSTALL_METHOD = detectInstallMethod2();
4562
4584
  function detectRunningVersion() {
4563
4585
  if (INSTALL_METHOD === "docker") {
4564
4586
  return process.env.HAP_BUILD_SHA ?? "dev";
4565
4587
  }
4566
4588
  const dir = import.meta.dirname ?? __dirname;
4567
- const bundlePkg = join12(dir, "..", "..", "package.json");
4568
- if (existsSync10(bundlePkg)) {
4589
+ const bundlePkg = join13(dir, "..", "..", "package.json");
4590
+ if (existsSync11(bundlePkg)) {
4569
4591
  try {
4570
- const pkg = JSON.parse(readFileSync12(bundlePkg, "utf8"));
4592
+ const pkg = JSON.parse(readFileSync13(bundlePkg, "utf8"));
4571
4593
  if (pkg.name === "@suveren/gateway" && typeof pkg.version === "string") {
4572
4594
  return pkg.version;
4573
4595
  }
@@ -4606,7 +4628,7 @@ app.get("/health", async (req, res) => {
4606
4628
  }
4607
4629
  });
4608
4630
  });
4609
- if (existsSync10(UI_DIST)) {
4631
+ if (existsSync11(UI_DIST)) {
4610
4632
  app.use(express.static(UI_DIST, {
4611
4633
  setHeaders: (res, filePath) => {
4612
4634
  if (filePath.endsWith("index.html")) {
@@ -4616,7 +4638,7 @@ if (existsSync10(UI_DIST)) {
4616
4638
  }));
4617
4639
  app.get("*", (_req, res) => {
4618
4640
  res.setHeader("Cache-Control", "no-store, must-revalidate");
4619
- res.sendFile(join12(UI_DIST, "index.html"));
4641
+ res.sendFile(join13(UI_DIST, "index.html"));
4620
4642
  });
4621
4643
  } else {
4622
4644
  app.get("/", (_req, res) => {
@@ -4638,16 +4660,26 @@ app.listen(port, "0.0.0.0", () => {
4638
4660
  console.error(`[Control Plane] UI dist: ${UI_DIST}`);
4639
4661
  console.error(`[Control Plane] Internal secret: configured`);
4640
4662
  console.error(`[Control Plane] MCP server: ${MCP_BASE}`);
4641
- getManifests().then((d) => {
4642
- const n = d?.manifests?.length ?? 0;
4643
- if (n === 0) {
4644
- console.error(`[Control Plane] \u26A0 MCP server at ${MCP_BASE} returned 0 integration manifests \u2014 wrong SUVEREN_MCP_INTERNAL_URL? (dev MCP is :3431, npm is :3430)`);
4645
- } else {
4646
- console.error(`[Control Plane] Integrations: ${n} manifests loaded from ${MCP_BASE}`);
4647
- void backfillReadPolicyDefaults(d);
4663
+ void (async () => {
4664
+ const deadline = Date.now() + 6e4;
4665
+ let lastErr;
4666
+ for (let delay = 500; Date.now() < deadline; delay = Math.min(delay * 2, 5e3)) {
4667
+ try {
4668
+ const d = await getManifests();
4669
+ const n = d?.manifests?.length ?? 0;
4670
+ if (n === 0) {
4671
+ console.error(`[Control Plane] \u26A0 MCP server at ${MCP_BASE} returned 0 integration manifests \u2014 wrong SUVEREN_MCP_INTERNAL_URL? (dev MCP is :3431, npm is :3430)`);
4672
+ } else {
4673
+ console.error(`[Control Plane] Integrations: ${n} manifests loaded from ${MCP_BASE}`);
4674
+ void backfillReadPolicyDefaults(d);
4675
+ }
4676
+ return;
4677
+ } catch (err) {
4678
+ lastErr = err;
4679
+ await new Promise((r) => setTimeout(r, delay));
4680
+ }
4648
4681
  }
4649
- }).catch((err) => {
4650
- console.error(`[Control Plane] \u26A0 Could not reach MCP server at ${MCP_BASE} for manifests \u2014 wrong SUVEREN_MCP_INTERNAL_URL? (dev=:3431, npm=:3430). ${err instanceof Error ? err.message : err}`);
4651
- });
4682
+ console.error(`[Control Plane] \u26A0 Could not reach MCP server at ${MCP_BASE} for manifests within 60 s \u2014 wrong SUVEREN_MCP_INTERNAL_URL? (dev=:3431, npm=:3430). ${lastErr instanceof Error ? lastErr.message : lastErr}`);
4683
+ })();
4652
4684
  startUpdateChecker(INSTALL_METHOD, RUNNING_VERSION);
4653
4685
  });