@solongate/proxy 0.83.55 → 0.83.57

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
@@ -6187,14 +6187,213 @@ var init_cli_utils = __esm({
6187
6187
  }
6188
6188
  });
6189
6189
 
6190
+ // src/hook-launcher.ts
6191
+ function launcherScript(pinnedNode) {
6192
+ const pinned = pinnedNode.replace(/'/g, `'\\''`);
6193
+ return `#!/bin/sh
6194
+ # SolonGate hook launcher \u2014 generated by \`solongate init --global\` / \`repair\`.
6195
+ #
6196
+ # Finds a working node and execs the hook with it. Do not edit: a reinstall
6197
+ # overwrites this file, and on macOS it is chflags-locked besides.
6198
+ #
6199
+ # The reason it exists rather than the hook naming a node directly: an absolute
6200
+ # node path recorded at install time is a Homebrew Cellar path or an nvm version
6201
+ # directory, and both are deleted by a routine upgrade. The hook then could not
6202
+ # start, nothing was enforced, nothing was logged, and every check still said
6203
+ # the guard was registered \u2014 because it was.
6204
+
6205
+ set -u
6206
+
6207
+ script="\${1:-}"
6208
+ [ -n "$script" ] || { echo "solongate: launcher called with no hook script" >&2; exit 1; }
6209
+ shift
6210
+
6211
+ hook=\${script##*/}
6212
+ home=\${HOME:-~}
6213
+ beatdir="$home/.solongate/${BEAT_DIR}"
6214
+
6215
+ # The beat. Written BEFORE node is resolved, because its whole job is to record
6216
+ # that the client invoked us \u2014 which is true even when everything after this
6217
+ # line fails. The file's modification time is the timestamp; nothing is forked
6218
+ # to produce one, and the directory test is a builtin.
6219
+ #
6220
+ # The braces matter. A redirect into a missing directory is reported by the
6221
+ # SHELL, before the command runs, so a \`2>/dev/null\` on the printf alone does
6222
+ # not suppress it \u2014 it lands on the hook's stderr, and Claude Code shows a
6223
+ # hook's stderr to the person using it. Redirecting the group catches both.
6224
+ beat() {
6225
+ [ -d "$beatdir" ] || mkdir -p "$beatdir" 2>/dev/null || return 0
6226
+ { printf '%s\\n' "$1" > "$beatdir/$hook"; } 2>/dev/null || true
6227
+ }
6228
+
6229
+ try() {
6230
+ [ -n "\${1:-}" ] && [ -x "$1" ]
6231
+ }
6232
+
6233
+ resolve_node() {
6234
+ # Told explicitly.
6235
+ if try "\${SOLONGATE_NODE:-}"; then echo "$SOLONGATE_NODE"; return 0; fi
6236
+ # The node this was installed with.
6237
+ if try '${pinned}'; then echo '${pinned}'; return 0; fi
6238
+ # PATH, when the client gave us one worth having.
6239
+ p=$(command -v node 2>/dev/null) || p=
6240
+ if try "$p"; then echo "$p"; return 0; fi
6241
+ # The fixed locations.
6242
+ for c in ${NODE_CANDIDATES.map((c2) => `"${c2}"`).join(" ")}; do
6243
+ for g in $c; do
6244
+ if try "$g"; then echo "$g"; return 0; fi
6245
+ done
6246
+ done
6247
+ # The version managers.
6248
+ for c in ${NODE_GLOBS.join(" ")}; do
6249
+ for g in $c; do
6250
+ if try "$g"; then echo "$g"; return 0; fi
6251
+ done
6252
+ done
6253
+ return 1
6254
+ }
6255
+
6256
+ node_bin=$(resolve_node) || node_bin=
6257
+
6258
+ # --sg-doctor: report what would be used and leave. This is what \`solongate
6259
+ # doctor\` runs, so the health check exercises the REAL resolution rather than a
6260
+ # copy of it that can drift.
6261
+ if [ "$script" = "--sg-doctor" ] || [ "\${1:-}" = "--sg-doctor" ]; then
6262
+ [ -n "$node_bin" ] && { echo "$node_bin"; exit 0; }
6263
+ echo "no node found" >&2
6264
+ exit 1
6265
+ fi
6266
+
6267
+ if [ -z "$node_bin" ]; then
6268
+ beat "no-node"
6269
+ # Nothing can be enforced without node, and which way to fail is not a
6270
+ # judgement call: the guard is fail-closed, so it refuses the call and says
6271
+ # why. Everything else here only records what already happened, and refusing
6272
+ # a tool call because the log could not be written would be a worse product
6273
+ # than a gap in the log.
6274
+ echo "solongate: no node runtime found, so $hook did not run." >&2
6275
+ echo "solongate: run \\\`solongate repair\\\` in a terminal, or set SOLONGATE_NODE to your node binary." >&2
6276
+ case "$hook" in
6277
+ guard.mjs) echo "solongate: this tool call is REFUSED \u2014 the guard is fail-closed." >&2; exit 2 ;;
6278
+ *) exit 0 ;;
6279
+ esac
6280
+ fi
6281
+
6282
+ beat "$node_bin"
6283
+ exec "$node_bin" "$script" "$@"
6284
+ `;
6285
+ }
6286
+ var NODE_CANDIDATES, NODE_GLOBS, LAUNCHER_NAME, BEAT_DIR;
6287
+ var init_hook_launcher = __esm({
6288
+ "src/hook-launcher.ts"() {
6289
+ "use strict";
6290
+ NODE_CANDIDATES = [
6291
+ // Homebrew, by the STABLE symlink rather than the Cellar path behind it —
6292
+ // the exact distinction this file exists for. Apple Silicon then Intel.
6293
+ "/opt/homebrew/bin/node",
6294
+ "/usr/local/bin/node",
6295
+ // Homebrew's keg-only layout, both prefixes.
6296
+ "/opt/homebrew/opt/node/bin/node",
6297
+ "/usr/local/opt/node/bin/node",
6298
+ // Distro and hand-built.
6299
+ "/usr/bin/node",
6300
+ "/usr/local/n/versions/node/*/bin/node",
6301
+ "/snap/bin/node"
6302
+ ];
6303
+ NODE_GLOBS = [
6304
+ // nvm. NVM_DIR is exported by its own shell hook, which a non-interactive
6305
+ // hook environment does not run, so the default location is tried too.
6306
+ '"${NVM_DIR:-}"/versions/node/*/bin/node',
6307
+ '"$home"/.nvm/versions/node/*/bin/node',
6308
+ // fnm, both the XDG location and the macOS Application Support one.
6309
+ '"$home"/.local/share/fnm/node-versions/*/installation/bin/node',
6310
+ '"$home"/Library/Application Support/fnm/node-versions/*/installation/bin/node',
6311
+ // Volta.
6312
+ '"$home"/.volta/tools/image/node/*/bin/node',
6313
+ // asdf, old layout and the current plugin one.
6314
+ '"$home"/.asdf/installs/nodejs/*/bin/node',
6315
+ '"$home"/.asdf/installs/node/*/bin/node'
6316
+ ];
6317
+ LAUNCHER_NAME = "sg-run.sh";
6318
+ BEAT_DIR = ".beat";
6319
+ }
6320
+ });
6321
+
6322
+ // src/hook-health.ts
6323
+ import { execFileSync as execFileSync2 } from "child_process";
6324
+ import { existsSync as existsSync3, readFileSync as readFileSync4, statSync } from "fs";
6325
+ import { join as join4 } from "path";
6326
+ import { homedir as homedir2 } from "os";
6327
+ function hookCanStart() {
6328
+ const launcher = join4(hooksDir(), LAUNCHER_NAME);
6329
+ if (process.platform === "win32") {
6330
+ const ok = existsSync3(process.execPath);
6331
+ return { ok, node: process.execPath, detail: ok ? process.execPath : `${process.execPath} is gone` };
6332
+ }
6333
+ if (!existsSync3(launcher)) {
6334
+ return { ok: false, detail: "hook launcher missing - run `solongate repair`" };
6335
+ }
6336
+ try {
6337
+ const out2 = execFileSync2("/bin/sh", [launcher, "--sg-doctor"], {
6338
+ encoding: "utf-8",
6339
+ timeout: 5e3,
6340
+ stdio: ["ignore", "pipe", "pipe"]
6341
+ }).trim();
6342
+ if (!out2) return { ok: false, detail: "launcher found no node runtime - set SOLONGATE_NODE or install node" };
6343
+ return { ok: true, node: out2, detail: out2 };
6344
+ } catch (e) {
6345
+ const msg = e instanceof Error ? e.message : String(e);
6346
+ return { ok: false, detail: `launcher will not run: ${msg.split("\n")[0]}` };
6347
+ }
6348
+ }
6349
+ function hookBeats() {
6350
+ const dir = join4(sgDir(), BEAT_DIR);
6351
+ const out2 = [];
6352
+ for (const hook of ["guard.mjs", "audit.mjs", "conversation.mjs", "stop.mjs"]) {
6353
+ const f = join4(dir, hook);
6354
+ try {
6355
+ const st = statSync(f);
6356
+ out2.push({ hook, at: st.mtime, node: readFileSync4(f, "utf-8").trim() });
6357
+ } catch {
6358
+ }
6359
+ }
6360
+ return out2.sort((a, b) => b.at.getTime() - a.at.getTime());
6361
+ }
6362
+ function guardBeat() {
6363
+ return hookBeats().find((b) => b.hook === "guard.mjs") ?? null;
6364
+ }
6365
+ function agoLabel(d) {
6366
+ const s = Math.max(0, Math.round((Date.now() - d.getTime()) / 1e3));
6367
+ if (s < 60) return s <= 3 ? "just now" : `${s}s ago`;
6368
+ if (s < 3600) return `${Math.round(s / 60)}m ago`;
6369
+ if (s < 86400) return `${Math.round(s / 3600)}h ago`;
6370
+ return `${Math.round(s / 86400)}d ago`;
6371
+ }
6372
+ var sgDir, hooksDir;
6373
+ var init_hook_health = __esm({
6374
+ "src/hook-health.ts"() {
6375
+ "use strict";
6376
+ init_hook_launcher();
6377
+ sgDir = () => join4(homedir2(), ".solongate");
6378
+ hooksDir = () => join4(sgDir(), "hooks");
6379
+ }
6380
+ });
6381
+
6190
6382
  // src/global-install.ts
6191
6383
  var global_install_exports = {};
6192
6384
  __export(global_install_exports, {
6385
+ BEAT_DIR: () => BEAT_DIR,
6386
+ LAUNCHER_NAME: () => LAUNCHER_NAME,
6387
+ agoLabel: () => agoLabel,
6193
6388
  clearGuardUpdateCheck: () => clearGuardUpdateCheck,
6194
6389
  codexDetected: () => codexDetected,
6195
6390
  codexHooksStatus: () => codexHooksStatus,
6196
6391
  globalPaths: () => globalPaths,
6392
+ guardBeat: () => guardBeat,
6197
6393
  guardHookOutdated: () => guardHookOutdated,
6394
+ hookBeats: () => hookBeats,
6395
+ hookCanStart: () => hookCanStart,
6396
+ hookCommandFor: () => hookCommandFor,
6198
6397
  installClaudeShim: () => installClaudeShim,
6199
6398
  installGlobalQuiet: () => installGlobalQuiet,
6200
6399
  installGlobalWithKey: () => installGlobalWithKey,
@@ -6202,6 +6401,7 @@ __export(global_install_exports, {
6202
6401
  isCodexGuardInstalled: () => isCodexGuardInstalled,
6203
6402
  isGuardInstalled: () => isGuardInstalled,
6204
6403
  isOpencodeGuardInstalled: () => isOpencodeGuardInstalled,
6404
+ launcherScript: () => launcherScript,
6205
6405
  lockProtected: () => lockProtected,
6206
6406
  opencodeDetected: () => opencodeDetected,
6207
6407
  removeClaudeShim: () => removeClaudeShim,
@@ -6212,39 +6412,40 @@ __export(global_install_exports, {
6212
6412
  sweepStrayScratchDirs: () => sweepStrayScratchDirs,
6213
6413
  uninstallGlobalQuiet: () => uninstallGlobalQuiet,
6214
6414
  unlockProtected: () => unlockProtected,
6415
+ writeLauncher: () => writeLauncher,
6215
6416
  writeProtectedFile: () => writeProtectedFile
6216
6417
  });
6217
- import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, existsSync as existsSync3, mkdirSync as mkdirSync3, rmSync as rmSync2, rmdirSync, readdirSync, statSync, chmodSync, copyFileSync, renameSync } from "fs";
6218
- import { resolve as resolve3, join as join4, dirname } from "path";
6219
- import { homedir as homedir2 } from "os";
6418
+ import { readFileSync as readFileSync5, writeFileSync as writeFileSync3, existsSync as existsSync4, mkdirSync as mkdirSync3, rmSync as rmSync2, rmdirSync, readdirSync, statSync as statSync2, chmodSync, copyFileSync, renameSync } from "fs";
6419
+ import { resolve as resolve3, join as join5, dirname, basename } from "path";
6420
+ import { homedir as homedir3 } from "os";
6220
6421
  import { createRequire } from "module";
6221
6422
  import { fileURLToPath } from "url";
6222
6423
  import { createInterface } from "readline";
6223
- import { execFileSync as execFileSync2, spawn } from "child_process";
6424
+ import { execFileSync as execFileSync3, spawn } from "child_process";
6224
6425
  function lockFile(file) {
6225
- if (!existsSync3(file)) return;
6426
+ if (!existsSync4(file)) return;
6226
6427
  try {
6227
6428
  if (process.platform === "win32") {
6228
6429
  try {
6229
- execFileSync2("icacls", [file, "/deny", "*S-1-1-0:(WD,AD,DC,DE,WDAC,WO)"], { stdio: "ignore" });
6430
+ execFileSync3("icacls", [file, "/deny", "*S-1-1-0:(WD,AD,DC,DE,WDAC,WO)"], { stdio: "ignore" });
6230
6431
  } catch {
6231
6432
  }
6232
6433
  try {
6233
- execFileSync2("icacls", [file, "/grant", "*S-1-3-4:(RX)"], { stdio: "ignore" });
6434
+ execFileSync3("icacls", [file, "/grant", "*S-1-3-4:(RX)"], { stdio: "ignore" });
6234
6435
  } catch {
6235
6436
  }
6236
6437
  try {
6237
- execFileSync2("attrib", ["+R", file], { stdio: "ignore" });
6438
+ execFileSync3("attrib", ["+R", file], { stdio: "ignore" });
6238
6439
  } catch {
6239
6440
  }
6240
6441
  } else if (process.platform === "darwin") {
6241
6442
  try {
6242
- execFileSync2("chflags", ["uchg", file], { stdio: "ignore" });
6443
+ execFileSync3("chflags", ["uchg", file], { stdio: "ignore" });
6243
6444
  } catch {
6244
6445
  }
6245
6446
  } else {
6246
6447
  try {
6247
- execFileSync2("chattr", ["+i", file], { stdio: "ignore" });
6448
+ execFileSync3("chattr", ["+i", file], { stdio: "ignore" });
6248
6449
  } catch {
6249
6450
  }
6250
6451
  try {
@@ -6256,33 +6457,33 @@ function lockFile(file) {
6256
6457
  }
6257
6458
  }
6258
6459
  function unlockFile(file) {
6259
- if (!existsSync3(file)) return;
6460
+ if (!existsSync4(file)) return;
6260
6461
  try {
6261
6462
  if (process.platform === "win32") {
6262
6463
  try {
6263
- execFileSync2("icacls", [file, "/remove:g", "*S-1-3-4"], { stdio: "ignore" });
6464
+ execFileSync3("icacls", [file, "/remove:g", "*S-1-3-4"], { stdio: "ignore" });
6264
6465
  } catch {
6265
6466
  }
6266
6467
  try {
6267
- execFileSync2("icacls", [file, "/remove:d", "*S-1-1-0"], { stdio: "ignore" });
6468
+ execFileSync3("icacls", [file, "/remove:d", "*S-1-1-0"], { stdio: "ignore" });
6268
6469
  } catch {
6269
6470
  }
6270
6471
  try {
6271
- execFileSync2("icacls", [file, "/reset"], { stdio: "ignore" });
6472
+ execFileSync3("icacls", [file, "/reset"], { stdio: "ignore" });
6272
6473
  } catch {
6273
6474
  }
6274
6475
  try {
6275
- execFileSync2("attrib", ["-R", file], { stdio: "ignore" });
6476
+ execFileSync3("attrib", ["-R", file], { stdio: "ignore" });
6276
6477
  } catch {
6277
6478
  }
6278
6479
  } else if (process.platform === "darwin") {
6279
6480
  try {
6280
- execFileSync2("chflags", ["nouchg", file], { stdio: "ignore" });
6481
+ execFileSync3("chflags", ["nouchg", file], { stdio: "ignore" });
6281
6482
  } catch {
6282
6483
  }
6283
6484
  } else {
6284
6485
  try {
6285
- execFileSync2("chattr", ["-i", file], { stdio: "ignore" });
6486
+ execFileSync3("chattr", ["-i", file], { stdio: "ignore" });
6286
6487
  } catch {
6287
6488
  }
6288
6489
  try {
@@ -6296,14 +6497,19 @@ function unlockFile(file) {
6296
6497
  function protectedTargets() {
6297
6498
  const p = globalPaths();
6298
6499
  return [
6299
- join4(p.hooksDir, "guard.mjs"),
6300
- join4(p.hooksDir, "audit.mjs"),
6301
- join4(p.hooksDir, "stop.mjs"),
6302
- join4(p.hooksDir, "shield.mjs"),
6500
+ join5(p.hooksDir, "guard.mjs"),
6501
+ join5(p.hooksDir, "audit.mjs"),
6502
+ join5(p.hooksDir, "stop.mjs"),
6503
+ join5(p.hooksDir, "shield.mjs"),
6303
6504
  // The conversation record is locked with the rest. A guest who could edit
6304
6505
  // it could decide what their host sees them say, which is the same class of
6305
6506
  // problem as editing the guard.
6306
- join4(p.hooksDir, "conversation.mjs"),
6507
+ join5(p.hooksDir, "conversation.mjs"),
6508
+ // The launcher is the enforcement path now: every hook command in every
6509
+ // client config runs THROUGH it. A program that could rewrite it could
6510
+ // point every hook at /bin/true and disarm the guard without touching a
6511
+ // single file that used to be locked.
6512
+ join5(p.hooksDir, LAUNCHER_NAME),
6307
6513
  p.configPath,
6308
6514
  p.settingsPath,
6309
6515
  p.antigravityHooksPath,
@@ -6337,60 +6543,60 @@ function writeProtectedFile(file, contents) {
6337
6543
  }
6338
6544
  }
6339
6545
  function globalPaths() {
6340
- const home = homedir2();
6341
- const sgDir = join4(home, ".solongate");
6342
- const hooksDir = join4(sgDir, "hooks");
6343
- const claudeDir = join4(home, ".claude");
6344
- const antigravityDir = join4(home, ".gemini", "config");
6345
- const codexDir = process.env["CODEX_HOME"] ? resolve3(process.env["CODEX_HOME"]) : join4(home, ".codex");
6346
- const opencodeDir = join4(process.env["XDG_CONFIG_HOME"] ? resolve3(process.env["XDG_CONFIG_HOME"]) : join4(home, ".config"), "opencode");
6347
- const binDir = join4(sgDir, "bin");
6546
+ const home = homedir3();
6547
+ const sgDir2 = join5(home, ".solongate");
6548
+ const hooksDir2 = join5(sgDir2, "hooks");
6549
+ const claudeDir = join5(home, ".claude");
6550
+ const antigravityDir = join5(home, ".gemini", "config");
6551
+ const codexDir = process.env["CODEX_HOME"] ? resolve3(process.env["CODEX_HOME"]) : join5(home, ".codex");
6552
+ const opencodeDir = join5(process.env["XDG_CONFIG_HOME"] ? resolve3(process.env["XDG_CONFIG_HOME"]) : join5(home, ".config"), "opencode");
6553
+ const binDir = join5(sgDir2, "bin");
6348
6554
  return {
6349
6555
  home,
6350
- sgDir,
6351
- hooksDir,
6556
+ sgDir: sgDir2,
6557
+ hooksDir: hooksDir2,
6352
6558
  binDir,
6353
6559
  claudeDir,
6354
6560
  antigravityDir,
6355
6561
  codexDir,
6356
6562
  opencodeDir,
6357
- settingsPath: join4(claudeDir, "settings.json"),
6358
- backupPath: join4(claudeDir, "settings.solongate.bak"),
6359
- configPath: join4(sgDir, "cloud-guard.json"),
6563
+ settingsPath: join5(claudeDir, "settings.json"),
6564
+ backupPath: join5(claudeDir, "settings.solongate.bak"),
6565
+ configPath: join5(sgDir2, "cloud-guard.json"),
6360
6566
  // Antigravity reads global hooks from ~/.gemini/config/hooks.json. Only the
6361
6567
  // guard is registered there (PreToolUse); Antigravity's ALLOW-path audit is
6362
6568
  // covered by the passive session-log collector, not a hook.
6363
- antigravityHooksPath: join4(antigravityDir, "hooks.json"),
6364
- antigravityBackupPath: join4(antigravityDir, "hooks.solongate.bak"),
6569
+ antigravityHooksPath: join5(antigravityDir, "hooks.json"),
6570
+ antigravityBackupPath: join5(antigravityDir, "hooks.solongate.bak"),
6365
6571
  // Codex reads user-level hooks from ~/.codex/hooks.json (or a [hooks] table
6366
6572
  // in ~/.codex/config.toml — we use the JSON file so we never have to rewrite
6367
6573
  // the user's TOML, which also holds the hook TRUST state Codex manages).
6368
- codexHooksPath: join4(codexDir, "hooks.json"),
6369
- codexBackupPath: join4(codexDir, "hooks.solongate.bak"),
6370
- codexConfigPath: join4(codexDir, "config.toml"),
6574
+ codexHooksPath: join5(codexDir, "hooks.json"),
6575
+ codexBackupPath: join5(codexDir, "hooks.solongate.bak"),
6576
+ codexConfigPath: join5(codexDir, "config.toml"),
6371
6577
  // OpenCode scans its plugin folder at startup and loads every module in it.
6372
6578
  // Measured on 1.18.10: BOTH `plugin/` and `plugins/` are scanned, so the
6373
6579
  // docs and the field reports are each half right. We write the documented
6374
6580
  // one. There is nothing to register anywhere — dropping the file IS the
6375
6581
  // installation, which also means deleting the file IS the uninstall.
6376
- opencodePluginDir: join4(opencodeDir, "plugins"),
6377
- opencodePluginPath: join4(opencodeDir, "plugins", "solongate.js")
6582
+ opencodePluginDir: join5(opencodeDir, "plugins"),
6583
+ opencodePluginPath: join5(opencodeDir, "plugins", "solongate.js")
6378
6584
  };
6379
6585
  }
6380
6586
  function clearGuardUpdateCheck() {
6381
6587
  try {
6382
- rmSync2(join4(globalPaths().sgDir, ".hook-update-check"), { force: true });
6588
+ rmSync2(join5(globalPaths().sgDir, ".hook-update-check"), { force: true });
6383
6589
  return true;
6384
6590
  } catch {
6385
6591
  return false;
6386
6592
  }
6387
6593
  }
6388
6594
  function readHook(filename) {
6389
- return readFileSync4(join4(HOOKS_DIR, filename), "utf-8");
6595
+ return readFileSync5(join5(HOOKS_DIR, filename), "utf-8");
6390
6596
  }
6391
6597
  function firstAccountCredential() {
6392
6598
  try {
6393
- const raw = JSON.parse(readFileSync4(join4(homedir2(), ".solongate", "accounts.json"), "utf-8"));
6599
+ const raw = JSON.parse(readFileSync5(join5(homedir3(), ".solongate", "accounts.json"), "utf-8"));
6394
6600
  if (Array.isArray(raw)) {
6395
6601
  const acc = raw.find((a) => a && typeof a.apiKey === "string" && a.apiKey);
6396
6602
  if (acc) return { apiKey: acc.apiKey, apiUrl: typeof acc.apiUrl === "string" ? acc.apiUrl : void 0 };
@@ -6400,8 +6606,8 @@ function firstAccountCredential() {
6400
6606
  return {};
6401
6607
  }
6402
6608
  function readGuard() {
6403
- const bundled = join4(HOOKS_DIR, "guard.bundled.mjs");
6404
- return existsSync3(bundled) ? readFileSync4(bundled, "utf-8") : readHook("guard.mjs");
6609
+ const bundled = join5(HOOKS_DIR, "guard.bundled.mjs");
6610
+ return existsSync4(bundled) ? readFileSync5(bundled, "utf-8") : readHook("guard.mjs");
6405
6611
  }
6406
6612
  function installGoBinaries(binDir) {
6407
6613
  const os_ = process.platform === "win32" ? "win32" : process.platform;
@@ -6421,10 +6627,10 @@ function installGoBinaries(binDir) {
6421
6627
  return placed;
6422
6628
  }
6423
6629
  for (const name of ["solongate-guard", "solongate"]) {
6424
- const from = join4(pkgDir, name + suffix);
6425
- const to = join4(binDir, name + suffix);
6630
+ const from = join5(pkgDir, name + suffix);
6631
+ const to = join5(binDir, name + suffix);
6426
6632
  try {
6427
- if (!existsSync3(from)) continue;
6633
+ if (!existsSync4(from)) continue;
6428
6634
  const tmp = to + ".new";
6429
6635
  copyFileSync(from, tmp);
6430
6636
  chmodSync(tmp, 493);
@@ -6436,16 +6642,14 @@ function installGoBinaries(binDir) {
6436
6642
  return placed;
6437
6643
  }
6438
6644
  function antigravityHookCommand(guardAbs) {
6439
- const nodeBin = process.execPath.replace(/\\/g, "/");
6440
- const call = process.platform === "win32" ? "& " : "";
6441
- return `${call}"${nodeBin}" "${guardAbs.replace(/\\/g, "/")}" antigravity "Antigravity"`;
6645
+ return hookCommandFor(dirname(guardAbs), basename(guardAbs), "antigravity", "Antigravity");
6442
6646
  }
6443
6647
  function installAntigravityGuard(p, guardAbs) {
6444
6648
  mkdirSync3(p.antigravityDir, { recursive: true });
6445
6649
  let existing = {};
6446
- if (existsSync3(p.antigravityHooksPath)) {
6447
- const raw = readFileSync4(p.antigravityHooksPath, "utf-8");
6448
- if (!existsSync3(p.antigravityBackupPath)) writeFileSync3(p.antigravityBackupPath, raw);
6650
+ if (existsSync4(p.antigravityHooksPath)) {
6651
+ const raw = readFileSync5(p.antigravityHooksPath, "utf-8");
6652
+ if (!existsSync4(p.antigravityBackupPath)) writeFileSync3(p.antigravityBackupPath, raw);
6449
6653
  try {
6450
6654
  existing = JSON.parse(raw);
6451
6655
  } catch {
@@ -6461,9 +6665,9 @@ function installAntigravityGuard(p, guardAbs) {
6461
6665
  writeFileSync3(p.antigravityHooksPath, JSON.stringify(merged, null, 2) + "\n");
6462
6666
  }
6463
6667
  function removeAntigravityGuard(p) {
6464
- if (!existsSync3(p.antigravityHooksPath)) return;
6668
+ if (!existsSync4(p.antigravityHooksPath)) return;
6465
6669
  try {
6466
- const s = JSON.parse(readFileSync4(p.antigravityHooksPath, "utf-8"));
6670
+ const s = JSON.parse(readFileSync5(p.antigravityHooksPath, "utf-8"));
6467
6671
  if (!(ANTIGRAVITY_GROUP in s)) return;
6468
6672
  delete s[ANTIGRAVITY_GROUP];
6469
6673
  writeFileSync3(p.antigravityHooksPath, JSON.stringify(s, null, 2) + "\n");
@@ -6471,8 +6675,10 @@ function removeAntigravityGuard(p) {
6471
6675
  }
6472
6676
  }
6473
6677
  function codexHookCommand(scriptAbs) {
6474
- const nodeBin = process.execPath.replace(/\\/g, "/");
6475
- return `"${nodeBin}" "${scriptAbs.replace(/\\/g, "/")}" codex "Codex"`;
6678
+ if (process.platform === "win32") {
6679
+ return `"${process.execPath.replace(/\\/g, "/")}" "${scriptAbs.replace(/\\/g, "/")}" codex "Codex"`;
6680
+ }
6681
+ return hookCommandFor(dirname(scriptAbs), basename(scriptAbs), "codex", "Codex");
6476
6682
  }
6477
6683
  function isOurCodexGroup(group) {
6478
6684
  const hooks = Array.isArray(group?.hooks) ? group.hooks : [];
@@ -6480,10 +6686,10 @@ function isOurCodexGroup(group) {
6480
6686
  }
6481
6687
  function readCodexHooksFile(path) {
6482
6688
  const out2 = { hooks: {}, rest: {} };
6483
- if (!existsSync3(path)) return out2;
6689
+ if (!existsSync4(path)) return out2;
6484
6690
  let raw;
6485
6691
  try {
6486
- raw = JSON.parse(readFileSync4(path, "utf-8"));
6692
+ raw = JSON.parse(readFileSync5(path, "utf-8"));
6487
6693
  } catch {
6488
6694
  return out2;
6489
6695
  }
@@ -6528,10 +6734,10 @@ function writeCodexHooksFile(path, file) {
6528
6734
  body["hooks"] = hooks;
6529
6735
  writeFileSync3(path, JSON.stringify(body, null, 2) + "\n");
6530
6736
  }
6531
- function installCodexGuard(p, hooksDir) {
6737
+ function installCodexGuard(p, hooksDir2) {
6532
6738
  mkdirSync3(p.codexDir, { recursive: true });
6533
- if (existsSync3(p.codexHooksPath) && !existsSync3(p.codexBackupPath)) {
6534
- writeFileSync3(p.codexBackupPath, readFileSync4(p.codexHooksPath, "utf-8"));
6739
+ if (existsSync4(p.codexHooksPath) && !existsSync4(p.codexBackupPath)) {
6740
+ writeFileSync3(p.codexBackupPath, readFileSync5(p.codexHooksPath, "utf-8"));
6535
6741
  }
6536
6742
  const file = readCodexHooksFile(p.codexHooksPath);
6537
6743
  const script = {
@@ -6555,7 +6761,7 @@ function installCodexGuard(p, hooksDir) {
6555
6761
  ...ev === "Stop" ? {} : { matcher: "*" },
6556
6762
  hooks: [{
6557
6763
  type: "command",
6558
- command: codexHookCommand(join4(hooksDir, script[ev]).replace(/\\/g, "/")),
6764
+ command: codexHookCommand(join5(hooksDir2, script[ev]).replace(/\\/g, "/")),
6559
6765
  timeout: CODEX_TIMEOUT_SEC,
6560
6766
  statusMessage: status[ev]
6561
6767
  }]
@@ -6565,7 +6771,7 @@ function installCodexGuard(p, hooksDir) {
6565
6771
  writeCodexHooksFile(p.codexHooksPath, file);
6566
6772
  }
6567
6773
  function removeCodexGuard(p) {
6568
- if (!existsSync3(p.codexHooksPath)) return;
6774
+ if (!existsSync4(p.codexHooksPath)) return;
6569
6775
  try {
6570
6776
  const file = readCodexHooksFile(p.codexHooksPath);
6571
6777
  let changed = false;
@@ -6591,7 +6797,7 @@ function isCodexGuardInstalled() {
6591
6797
  }
6592
6798
  function codexDetected() {
6593
6799
  try {
6594
- return existsSync3(globalPaths().codexDir);
6800
+ return existsSync4(globalPaths().codexDir);
6595
6801
  } catch {
6596
6802
  return false;
6597
6803
  }
@@ -6601,7 +6807,7 @@ function codexHooksStatus() {
6601
6807
  const registered = isCodexGuardInstalled();
6602
6808
  let trusted = false, disabled = false;
6603
6809
  try {
6604
- const toml = readFileSync4(p.codexConfigPath, "utf-8");
6810
+ const toml = readFileSync5(p.codexConfigPath, "utf-8");
6605
6811
  trusted = /trusted_hash\s*=/.test(toml);
6606
6812
  disabled = /^\s*hooks\s*=\s*false\s*$/m.test(toml);
6607
6813
  } catch {
@@ -6620,10 +6826,10 @@ function removeOpencodeGuard(p) {
6620
6826
  } catch {
6621
6827
  }
6622
6828
  }
6623
- function warmPolicyCache(hooksDir, agents) {
6829
+ function warmPolicyCache(hooksDir2, agents) {
6624
6830
  for (const agent of agents) {
6625
6831
  try {
6626
- const child = spawn(process.execPath, [join4(hooksDir, "guard.mjs"), agent, "--sg-refresh-policy"], {
6832
+ const child = spawn(process.execPath, [join5(hooksDir2, "guard.mjs"), agent, "--sg-refresh-policy"], {
6627
6833
  detached: true,
6628
6834
  stdio: "ignore",
6629
6835
  windowsHide: true
@@ -6637,23 +6843,23 @@ function warmPolicyCache(hooksDir, agents) {
6637
6843
  }
6638
6844
  function isOpencodeGuardInstalled() {
6639
6845
  try {
6640
- return readFileSync4(globalPaths().opencodePluginPath, "utf-8").includes("tool.execute.before");
6846
+ return readFileSync5(globalPaths().opencodePluginPath, "utf-8").includes("tool.execute.before");
6641
6847
  } catch {
6642
6848
  return false;
6643
6849
  }
6644
6850
  }
6645
6851
  function opencodeDetected() {
6646
6852
  try {
6647
- return existsSync3(globalPaths().opencodeDir);
6853
+ return existsSync4(globalPaths().opencodeDir);
6648
6854
  } catch {
6649
6855
  return false;
6650
6856
  }
6651
6857
  }
6652
- function sweepStrayScratchDirs(root = homedir2(), maxDepth = 6, budget = 4e4) {
6858
+ function sweepStrayScratchDirs(root = homedir3(), maxDepth = 6, budget = 4e4) {
6653
6859
  let removed = 0;
6654
6860
  let visited = 0;
6655
6861
  const skip = /* @__PURE__ */ new Set(["node_modules", ".git", "dist", ".next", "build"]);
6656
- const store = join4(homedir2(), ".solongate");
6862
+ const store = join5(homedir3(), ".solongate");
6657
6863
  const walk = (dir, depth) => {
6658
6864
  if (depth > maxDepth || visited++ > budget) return;
6659
6865
  let entries;
@@ -6664,11 +6870,11 @@ function sweepStrayScratchDirs(root = homedir2(), maxDepth = 6, budget = 4e4) {
6664
6870
  }
6665
6871
  for (const name of entries) {
6666
6872
  if (skip.has(name)) continue;
6667
- const full = join4(dir, name);
6873
+ const full = join5(dir, name);
6668
6874
  if (full === store) continue;
6669
6875
  let isDir = false;
6670
6876
  try {
6671
- isDir = statSync(full).isDirectory();
6877
+ isDir = statSync2(full).isDirectory();
6672
6878
  } catch {
6673
6879
  continue;
6674
6880
  }
@@ -6679,7 +6885,7 @@ function sweepStrayScratchDirs(root = homedir2(), maxDepth = 6, budget = 4e4) {
6679
6885
  for (const f of readdirSync(full)) {
6680
6886
  if (SCRATCH_FILES.has(f)) {
6681
6887
  try {
6682
- rmSync2(join4(full, f), { force: true });
6888
+ rmSync2(join5(full, f), { force: true });
6683
6889
  } catch {
6684
6890
  left.push(f);
6685
6891
  }
@@ -6719,12 +6925,12 @@ function runGlobalRestore() {
6719
6925
  removeOpencodeGuard(p);
6720
6926
  } catch {
6721
6927
  }
6722
- if (existsSync3(p.backupPath)) {
6723
- writeFileSync3(p.settingsPath, readFileSync4(p.backupPath, "utf-8"));
6928
+ if (existsSync4(p.backupPath)) {
6929
+ writeFileSync3(p.settingsPath, readFileSync5(p.backupPath, "utf-8"));
6724
6930
  console.log(` Restored ${p.settingsPath} from backup.`);
6725
- } else if (existsSync3(p.settingsPath)) {
6931
+ } else if (existsSync4(p.settingsPath)) {
6726
6932
  try {
6727
- const s = JSON.parse(readFileSync4(p.settingsPath, "utf-8"));
6933
+ const s = JSON.parse(readFileSync5(p.settingsPath, "utf-8"));
6728
6934
  delete s.hooks;
6729
6935
  writeFileSync3(p.settingsPath, JSON.stringify(s, null, 2) + "\n");
6730
6936
  console.log(` Removed SolonGate hooks from ${p.settingsPath}.`);
@@ -6737,12 +6943,17 @@ function runGlobalRestore() {
6737
6943
  }
6738
6944
  function repairQuiet() {
6739
6945
  const p = globalPaths();
6740
- const has = (f) => existsSync3(f);
6741
- const guardFile = join4(p.hooksDir, "guard.mjs");
6946
+ const has = (f) => existsSync4(f);
6947
+ const guardFile = join5(p.hooksDir, "guard.mjs");
6742
6948
  const line = (label, ok, yes, no) => ({ label, ok, detail: ok ? yes : no });
6949
+ const runtime = () => {
6950
+ const r2 = hookCanStart();
6951
+ return { label: "hook runtime", ok: r2.ok, detail: r2.ok ? `node ${r2.detail}` : r2.detail };
6952
+ };
6743
6953
  const before = [
6744
6954
  line("guard hook file", has(guardFile), "present", "MISSING"),
6745
6955
  line("cloud credential", has(p.configPath), "present", "MISSING"),
6956
+ runtime(),
6746
6957
  line("Claude hooks", isGuardInstalled(), "guard registered", "guard NOT registered"),
6747
6958
  line("Antigravity hooks", has(p.antigravityHooksPath), "guard registered", "guard NOT registered"),
6748
6959
  line("Codex hooks", isCodexGuardInstalled(), "guard registered", "guard NOT registered"),
@@ -6752,6 +6963,7 @@ function repairQuiet() {
6752
6963
  if (!r.ok) return { ok: false, message: r.message, before, after: [], notes: [] };
6753
6964
  const after = [
6754
6965
  { label: "guard hook file", ok: true, detail: `present (v${installedGuardVersion() ?? "?"})` },
6966
+ runtime(),
6755
6967
  line("Claude hooks", isGuardInstalled(), "guard registered", "NOT registered"),
6756
6968
  line("Antigravity hooks", has(p.antigravityHooksPath), "guard registered", "NOT registered"),
6757
6969
  line("Codex hooks", isCodexGuardInstalled(), "guard registered", "NOT registered"),
@@ -6812,7 +7024,7 @@ function installGlobalQuiet() {
6812
7024
  let apiKey = process.env["SOLONGATE_API_KEY"] || "";
6813
7025
  let apiUrl = process.env["SOLONGATE_API_URL"] || "https://api.solongate.com";
6814
7026
  try {
6815
- const cfg = JSON.parse(readFileSync4(p.configPath, "utf-8"));
7027
+ const cfg = JSON.parse(readFileSync5(p.configPath, "utf-8"));
6816
7028
  if (cfg && typeof cfg.apiKey === "string") apiKey = apiKey || cfg.apiKey;
6817
7029
  if (cfg && typeof cfg.apiUrl === "string") apiUrl = cfg.apiUrl;
6818
7030
  } catch {
@@ -6828,26 +7040,26 @@ function installGlobalQuiet() {
6828
7040
  mkdirSync3(p.hooksDir, { recursive: true });
6829
7041
  mkdirSync3(p.claudeDir, { recursive: true });
6830
7042
  unlockProtected();
6831
- writeFileSync3(join4(p.hooksDir, "guard.mjs"), readGuard());
7043
+ writeFileSync3(join5(p.hooksDir, "guard.mjs"), readGuard());
6832
7044
  installGoBinaries(p.binDir);
6833
- writeFileSync3(join4(p.hooksDir, "audit.mjs"), readHook("audit.mjs"));
6834
- writeFileSync3(join4(p.hooksDir, "stop.mjs"), readHook("stop.mjs"));
6835
- writeFileSync3(join4(p.hooksDir, "shield.mjs"), readHook("shield.mjs"));
6836
- writeFileSync3(join4(p.hooksDir, "conversation.mjs"), readHook("conversation.mjs"));
7045
+ writeFileSync3(join5(p.hooksDir, "audit.mjs"), readHook("audit.mjs"));
7046
+ writeFileSync3(join5(p.hooksDir, "stop.mjs"), readHook("stop.mjs"));
7047
+ writeFileSync3(join5(p.hooksDir, "shield.mjs"), readHook("shield.mjs"));
7048
+ writeFileSync3(join5(p.hooksDir, "conversation.mjs"), readHook("conversation.mjs"));
7049
+ writeLauncher(p.hooksDir);
7050
+ writeLauncher(p.hooksDir);
6837
7051
  writeFileSync3(p.configPath, JSON.stringify({ apiKey, apiUrl }, null, 2) + "\n");
6838
7052
  let existing = {};
6839
- if (existsSync3(p.settingsPath)) {
6840
- const raw = readFileSync4(p.settingsPath, "utf-8");
6841
- if (!existsSync3(p.backupPath)) writeFileSync3(p.backupPath, raw);
7053
+ if (existsSync4(p.settingsPath)) {
7054
+ const raw = readFileSync5(p.settingsPath, "utf-8");
7055
+ if (!existsSync4(p.backupPath)) writeFileSync3(p.backupPath, raw);
6842
7056
  try {
6843
7057
  existing = JSON.parse(raw);
6844
7058
  } catch {
6845
7059
  existing = {};
6846
7060
  }
6847
7061
  }
6848
- const nodeBin = process.execPath.replace(/\\/g, "/");
6849
- const call = process.platform === "win32" ? "& " : "";
6850
- const hookCmd = (script) => `${call}"${nodeBin}" "${join4(p.hooksDir, script).replace(/\\/g, "/")}" claude-code "Claude Code"`;
7062
+ const hookCmd = (script) => hookCommandFor(p.hooksDir, script);
6851
7063
  const merged = {
6852
7064
  ...existing,
6853
7065
  hooks: {
@@ -6874,7 +7086,7 @@ function installGlobalQuiet() {
6874
7086
  };
6875
7087
  writeFileSync3(p.settingsPath, JSON.stringify(merged, null, 2) + "\n");
6876
7088
  try {
6877
- installAntigravityGuard(p, join4(p.hooksDir, "guard.mjs").replace(/\\/g, "/"));
7089
+ installAntigravityGuard(p, join5(p.hooksDir, "guard.mjs").replace(/\\/g, "/"));
6878
7090
  } catch {
6879
7091
  }
6880
7092
  try {
@@ -6895,7 +7107,7 @@ function installGlobalQuiet() {
6895
7107
  function installedGuardVersion() {
6896
7108
  try {
6897
7109
  const p = globalPaths();
6898
- const s = readFileSync4(join4(p.hooksDir, "guard.mjs"), "utf-8");
7110
+ const s = readFileSync5(join5(p.hooksDir, "guard.mjs"), "utf-8");
6899
7111
  const m = s.match(/HOOK_VERSION\s*=\s*(\d+)/);
6900
7112
  return m ? parseInt(m[1], 10) : null;
6901
7113
  } catch {
@@ -6905,16 +7117,35 @@ function installedGuardVersion() {
6905
7117
  function guardHookOutdated() {
6906
7118
  try {
6907
7119
  const p = globalPaths();
6908
- return readFileSync4(join4(p.hooksDir, "guard.mjs"), "utf-8") !== readGuard();
7120
+ return readFileSync5(join5(p.hooksDir, "guard.mjs"), "utf-8") !== readGuard();
6909
7121
  } catch {
6910
7122
  return false;
6911
7123
  }
6912
7124
  }
7125
+ function hookCommandFor(hooksDir2, script, client = "claude-code", label = "Claude Code") {
7126
+ const target = join5(hooksDir2, script).replace(/\\/g, "/");
7127
+ if (process.platform === "win32") {
7128
+ return `& "${process.execPath.replace(/\\/g, "/")}" "${target}" ${client} "${label}"`;
7129
+ }
7130
+ const launcher = join5(hooksDir2, LAUNCHER_NAME).replace(/\\/g, "/");
7131
+ return `/bin/sh "${launcher}" "${target}" ${client} "${label}"`;
7132
+ }
7133
+ function writeLauncher(hooksDir2) {
7134
+ writeFileSync3(join5(hooksDir2, LAUNCHER_NAME), launcherScript(process.execPath));
7135
+ try {
7136
+ chmodSync(join5(hooksDir2, LAUNCHER_NAME), 493);
7137
+ } catch {
7138
+ }
7139
+ try {
7140
+ mkdirSync3(join5(hooksDir2, "..", BEAT_DIR), { recursive: true });
7141
+ } catch {
7142
+ }
7143
+ }
6913
7144
  function isGuardInstalled() {
6914
7145
  try {
6915
7146
  const p = globalPaths();
6916
- if (!existsSync3(p.settingsPath)) return false;
6917
- const s = JSON.parse(readFileSync4(p.settingsPath, "utf-8"));
7147
+ if (!existsSync4(p.settingsPath)) return false;
7148
+ const s = JSON.parse(readFileSync5(p.settingsPath, "utf-8"));
6918
7149
  return !!s.hooks && JSON.stringify(s.hooks).includes(".solongate");
6919
7150
  } catch {
6920
7151
  return false;
@@ -6937,8 +7168,8 @@ function uninstallGlobalQuiet() {
6937
7168
  removeOpencodeGuard(p);
6938
7169
  } catch {
6939
7170
  }
6940
- if (!existsSync3(p.settingsPath)) return { ok: true, message: "guard removed (open a new session)" };
6941
- const s = JSON.parse(readFileSync4(p.settingsPath, "utf-8"));
7171
+ if (!existsSync4(p.settingsPath)) return { ok: true, message: "guard removed (open a new session)" };
7172
+ const s = JSON.parse(readFileSync5(p.settingsPath, "utf-8"));
6942
7173
  delete s.hooks;
6943
7174
  writeFileSync3(p.settingsPath, JSON.stringify(s, null, 2) + "\n");
6944
7175
  return { ok: true, message: "guard removed (open a new session)" };
@@ -6952,7 +7183,7 @@ function escapeRe(s) {
6952
7183
  function resolveRealClaude() {
6953
7184
  try {
6954
7185
  const finder = process.platform === "win32" ? "where" : "which";
6955
- const out2 = execFileSync2(finder, ["claude"], { encoding: "utf-8" }).split(/\r?\n/).map((s) => s.trim()).filter(Boolean);
7186
+ const out2 = execFileSync3(finder, ["claude"], { encoding: "utf-8" }).split(/\r?\n/).map((s) => s.trim()).filter(Boolean);
6956
7187
  if (process.platform === "win32") {
6957
7188
  const low = (s) => s.toLowerCase();
6958
7189
  return out2.find((l) => low(l).endsWith(".cmd")) || out2.find((l) => low(l).endsWith(".exe")) || out2.find((l) => low(l).endsWith(".bat")) || out2[0] || null;
@@ -6965,17 +7196,17 @@ function resolveRealClaude() {
6965
7196
  function shimTargets() {
6966
7197
  if (process.platform === "win32") {
6967
7198
  try {
6968
- const prof = execFileSync2("powershell", ["-NoProfile", "-Command", "$PROFILE.CurrentUserAllHosts"], { encoding: "utf-8" }).trim();
7199
+ const prof = execFileSync3("powershell", ["-NoProfile", "-Command", "$PROFILE.CurrentUserAllHosts"], { encoding: "utf-8" }).trim();
6969
7200
  return prof ? [prof] : [];
6970
7201
  } catch {
6971
7202
  return [];
6972
7203
  }
6973
7204
  }
6974
- return [".bashrc", ".zshrc", ".profile"].map((f) => join4(homedir2(), f)).filter((f) => existsSync3(f));
7205
+ return [".bashrc", ".zshrc", ".profile"].map((f) => join5(homedir3(), f)).filter((f) => existsSync4(f));
6975
7206
  }
6976
7207
  function writeShimBlock(file, block2) {
6977
7208
  const re = new RegExp(escapeRe(SHIM_BEGIN) + "[\\s\\S]*?" + escapeRe(SHIM_END) + "\\r?\\n?", "g");
6978
- let content = existsSync3(file) ? readFileSync4(file, "utf-8") : "";
7209
+ let content = existsSync4(file) ? readFileSync5(file, "utf-8") : "";
6979
7210
  content = content.replace(re, "");
6980
7211
  if (block2) {
6981
7212
  if (content.length && !content.endsWith("\n")) content += "\n";
@@ -7020,7 +7251,7 @@ async function runGlobalInstall(opts = {}) {
7020
7251
  let apiKey = opts.apiKey || process.env["SOLONGATE_API_KEY"] || "";
7021
7252
  if (!apiKey || apiKey === "sg_live_your_key_here") {
7022
7253
  try {
7023
- const cfg = JSON.parse(readFileSync4(p.configPath, "utf-8"));
7254
+ const cfg = JSON.parse(readFileSync5(p.configPath, "utf-8"));
7024
7255
  if (cfg && typeof cfg.apiKey === "string") apiKey = cfg.apiKey;
7025
7256
  } catch {
7026
7257
  }
@@ -7040,19 +7271,19 @@ async function runGlobalInstall(opts = {}) {
7040
7271
  mkdirSync3(p.hooksDir, { recursive: true });
7041
7272
  mkdirSync3(p.claudeDir, { recursive: true });
7042
7273
  unlockProtected();
7043
- writeFileSync3(join4(p.hooksDir, "guard.mjs"), readGuard());
7044
- writeFileSync3(join4(p.hooksDir, "audit.mjs"), readHook("audit.mjs"));
7045
- writeFileSync3(join4(p.hooksDir, "stop.mjs"), readHook("stop.mjs"));
7046
- writeFileSync3(join4(p.hooksDir, "shield.mjs"), readHook("shield.mjs"));
7047
- writeFileSync3(join4(p.hooksDir, "conversation.mjs"), readHook("conversation.mjs"));
7274
+ writeFileSync3(join5(p.hooksDir, "guard.mjs"), readGuard());
7275
+ writeFileSync3(join5(p.hooksDir, "audit.mjs"), readHook("audit.mjs"));
7276
+ writeFileSync3(join5(p.hooksDir, "stop.mjs"), readHook("stop.mjs"));
7277
+ writeFileSync3(join5(p.hooksDir, "shield.mjs"), readHook("shield.mjs"));
7278
+ writeFileSync3(join5(p.hooksDir, "conversation.mjs"), readHook("conversation.mjs"));
7048
7279
  console.log(` Installed hooks \u2192 ${p.hooksDir}`);
7049
- installClaudeShim(join4(p.hooksDir, "shield.mjs"));
7280
+ installClaudeShim(join5(p.hooksDir, "shield.mjs"));
7050
7281
  writeFileSync3(p.configPath, JSON.stringify({ apiKey, apiUrl }, null, 2) + "\n");
7051
7282
  console.log(` Wrote ${p.configPath}`);
7052
7283
  let existing = {};
7053
- if (existsSync3(p.settingsPath)) {
7054
- const raw = readFileSync4(p.settingsPath, "utf-8");
7055
- if (!existsSync3(p.backupPath)) {
7284
+ if (existsSync4(p.settingsPath)) {
7285
+ const raw = readFileSync5(p.settingsPath, "utf-8");
7286
+ if (!existsSync4(p.backupPath)) {
7056
7287
  writeFileSync3(p.backupPath, raw);
7057
7288
  console.log(` Backed up existing settings \u2192 ${p.backupPath}`);
7058
7289
  }
@@ -7062,22 +7293,17 @@ async function runGlobalInstall(opts = {}) {
7062
7293
  existing = {};
7063
7294
  }
7064
7295
  }
7065
- const guardAbs = join4(p.hooksDir, "guard.mjs").replace(/\\/g, "/");
7066
- const auditAbs = join4(p.hooksDir, "audit.mjs").replace(/\\/g, "/");
7067
- const stopAbs = join4(p.hooksDir, "stop.mjs").replace(/\\/g, "/");
7068
- const convAbs = join4(p.hooksDir, "conversation.mjs").replace(/\\/g, "/");
7069
- const nodeBin = process.execPath.replace(/\\/g, "/");
7070
- const call = process.platform === "win32" ? "& " : "";
7071
- const hookCmd = (script) => `${call}"${nodeBin}" "${script}" claude-code "Claude Code"`;
7296
+ const guardAbs = join5(p.hooksDir, "guard.mjs").replace(/\\/g, "/");
7297
+ const hookCmd = (script) => hookCommandFor(p.hooksDir, script);
7072
7298
  const merged = {
7073
7299
  ...existing,
7074
7300
  hooks: {
7075
- PreToolUse: [{ matcher: "", hooks: [{ type: "command", command: hookCmd(guardAbs) }] }],
7076
- PostToolUse: [{ matcher: "", hooks: [{ type: "command", command: hookCmd(auditAbs) }] }],
7077
- UserPromptSubmit: [{ matcher: "", hooks: [{ type: "command", command: hookCmd(convAbs) }] }],
7301
+ PreToolUse: [{ matcher: "", hooks: [{ type: "command", command: hookCmd("guard.mjs") }] }],
7302
+ PostToolUse: [{ matcher: "", hooks: [{ type: "command", command: hookCmd("audit.mjs") }] }],
7303
+ UserPromptSubmit: [{ matcher: "", hooks: [{ type: "command", command: hookCmd("conversation.mjs") }] }],
7078
7304
  Stop: [
7079
- { matcher: "", hooks: [{ type: "command", command: hookCmd(stopAbs) }] },
7080
- { matcher: "", hooks: [{ type: "command", command: hookCmd(convAbs) }] }
7305
+ { matcher: "", hooks: [{ type: "command", command: hookCmd("stop.mjs") }] },
7306
+ { matcher: "", hooks: [{ type: "command", command: hookCmd("conversation.mjs") }] }
7081
7307
  ]
7082
7308
  }
7083
7309
  };
@@ -7122,6 +7348,10 @@ var __dirname, HOOKS_DIR, ANTIGRAVITY_GROUP, CODEX_EVENTS, CODEX_TIMEOUT_SEC, SC
7122
7348
  var init_global_install = __esm({
7123
7349
  "src/global-install.ts"() {
7124
7350
  "use strict";
7351
+ init_hook_launcher();
7352
+ init_hook_launcher();
7353
+ init_hook_health();
7354
+ init_hook_health();
7125
7355
  __dirname = dirname(fileURLToPath(import.meta.url));
7126
7356
  HOOKS_DIR = resolve3(__dirname, "..", "hooks");
7127
7357
  ANTIGRAVITY_GROUP = "solongate-guard";
@@ -7152,14 +7382,14 @@ __export(self_update_exports, {
7152
7382
  tuiUpdateFlow: () => tuiUpdateFlow,
7153
7383
  updateNow: () => updateNow
7154
7384
  });
7155
- import { execFile, execFileSync as execFileSync3, spawn as spawn2 } from "child_process";
7156
- import { access, mkdirSync as mkdirSync4, openSync, readFileSync as readFileSync5, writeFileSync as writeFileSync4, constants as FS } from "fs";
7157
- import { homedir as homedir3 } from "os";
7158
- import { dirname as dirname2, join as join5, sep } from "path";
7385
+ import { execFile, execFileSync as execFileSync4, spawn as spawn2 } from "child_process";
7386
+ import { access, mkdirSync as mkdirSync4, openSync, readFileSync as readFileSync6, writeFileSync as writeFileSync4, constants as FS } from "fs";
7387
+ import { homedir as homedir4 } from "os";
7388
+ import { dirname as dirname2, join as join6, sep } from "path";
7159
7389
  import { fileURLToPath as fileURLToPath2 } from "url";
7160
7390
  function lockHeldAt() {
7161
7391
  try {
7162
- const ts = Number(readFileSync5(LOCK_FILE, "utf-8").trim().split(/\s+/)[1] ?? 0);
7392
+ const ts = Number(readFileSync6(LOCK_FILE, "utf-8").trim().split(/\s+/)[1] ?? 0);
7163
7393
  if (!Number.isFinite(ts) || Date.now() - ts >= LOCK_STALE_MS) return null;
7164
7394
  return ts;
7165
7395
  } catch {
@@ -7168,7 +7398,7 @@ function lockHeldAt() {
7168
7398
  }
7169
7399
  function takeInstallLock() {
7170
7400
  try {
7171
- mkdirSync4(join5(homedir3(), ".solongate"), { recursive: true });
7401
+ mkdirSync4(join6(homedir4(), ".solongate"), { recursive: true });
7172
7402
  writeFileSync4(LOCK_FILE, `${process.pid} ${Date.now()}
7173
7403
  `);
7174
7404
  } catch {
@@ -7183,7 +7413,7 @@ function releaseInstallLock() {
7183
7413
  }
7184
7414
  function readState() {
7185
7415
  try {
7186
- const s = JSON.parse(readFileSync5(STATE_FILE, "utf-8"));
7416
+ const s = JSON.parse(readFileSync6(STATE_FILE, "utf-8"));
7187
7417
  return s && typeof s === "object" ? s : {};
7188
7418
  } catch {
7189
7419
  return {};
@@ -7191,7 +7421,7 @@ function readState() {
7191
7421
  }
7192
7422
  function writeState(s) {
7193
7423
  try {
7194
- mkdirSync4(join5(homedir3(), ".solongate"), { recursive: true });
7424
+ mkdirSync4(join6(homedir4(), ".solongate"), { recursive: true });
7195
7425
  writeFileSync4(STATE_FILE, JSON.stringify(s));
7196
7426
  } catch {
7197
7427
  }
@@ -7212,7 +7442,7 @@ function setAutoUpdate(on) {
7212
7442
  }
7213
7443
  function currentVersion() {
7214
7444
  try {
7215
- const pkg = JSON.parse(readFileSync5(join5(dirname2(fileURLToPath2(import.meta.url)), "..", "package.json"), "utf-8"));
7445
+ const pkg = JSON.parse(readFileSync6(join6(dirname2(fileURLToPath2(import.meta.url)), "..", "package.json"), "utf-8"));
7216
7446
  return pkg.version ?? "0.0.0";
7217
7447
  } catch {
7218
7448
  return "0.0.0";
@@ -7249,7 +7479,7 @@ async function fetchLatest() {
7249
7479
  function spawnGlobalInstall(version) {
7250
7480
  if (lockHeldAt() !== null) return false;
7251
7481
  try {
7252
- mkdirSync4(join5(homedir3(), ".solongate"), { recursive: true });
7482
+ mkdirSync4(join6(homedir4(), ".solongate"), { recursive: true });
7253
7483
  takeInstallLock();
7254
7484
  const log3 = openSync(LOG_FILE, "a");
7255
7485
  const p = spawn2("npm", ["install", "-g", `${PKG}@${version}`], {
@@ -7320,7 +7550,7 @@ async function runUpdateCommand() {
7320
7550
  }
7321
7551
  try {
7322
7552
  if (newerThan(latest, cur)) {
7323
- execFileSync3("solongate", ["repair"], {
7553
+ execFileSync4("solongate", ["repair"], {
7324
7554
  env: { ...process.env, SOLONGATE_INTERNAL: "1" },
7325
7555
  stdio: "inherit",
7326
7556
  shell: process.platform === "win32"
@@ -7337,7 +7567,7 @@ async function runUpdateCommand() {
7337
7567
  function runGlobalInstall2(version) {
7338
7568
  return new Promise((resolve8) => {
7339
7569
  try {
7340
- mkdirSync4(join5(homedir3(), ".solongate"), { recursive: true });
7570
+ mkdirSync4(join6(homedir4(), ".solongate"), { recursive: true });
7341
7571
  execFile(
7342
7572
  "npm",
7343
7573
  ["install", "-g", `${PKG}@${version}`],
@@ -7530,9 +7760,9 @@ var init_self_update = __esm({
7530
7760
  PKG = "@solongate/proxy";
7531
7761
  CHECK_EVERY_MS = 30 * 60 * 1e3;
7532
7762
  ATTEMPT_EVERY_MS = 6 * 60 * 60 * 1e3;
7533
- STATE_FILE = join5(homedir3(), ".solongate", ".self-update.json");
7534
- LOG_FILE = join5(homedir3(), ".solongate", "self-update.log");
7535
- LOCK_FILE = join5(homedir3(), ".solongate", ".update-install.lock");
7763
+ STATE_FILE = join6(homedir4(), ".solongate", ".self-update.json");
7764
+ LOG_FILE = join6(homedir4(), ".solongate", "self-update.log");
7765
+ LOCK_FILE = join6(homedir4(), ".solongate", ".update-install.lock");
7536
7766
  LOCK_STALE_MS = 3 * 6e4;
7537
7767
  LOCK_WAIT_MS = 9e4;
7538
7768
  sleep = (ms) => new Promise((r) => setTimeout(r, ms));
@@ -7552,13 +7782,13 @@ __export(logs_server_daemon_exports, {
7552
7782
  stopLogsServerDaemon: () => stopLogsServerDaemon
7553
7783
  });
7554
7784
  import { spawn as spawn3 } from "child_process";
7555
- import { mkdirSync as mkdirSync5, openSync as openSync2, readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "fs";
7556
- import { homedir as homedir4 } from "os";
7557
- import { dirname as dirname3, join as join6 } from "path";
7785
+ import { mkdirSync as mkdirSync5, openSync as openSync2, readFileSync as readFileSync7, writeFileSync as writeFileSync5 } from "fs";
7786
+ import { homedir as homedir5 } from "os";
7787
+ import { dirname as dirname3, join as join7 } from "path";
7558
7788
  import { fileURLToPath as fileURLToPath3 } from "url";
7559
7789
  function readState2() {
7560
7790
  try {
7561
- const s = JSON.parse(readFileSync6(STATE_FILE2, "utf-8"));
7791
+ const s = JSON.parse(readFileSync7(STATE_FILE2, "utf-8"));
7562
7792
  return s && typeof s === "object" ? s : {};
7563
7793
  } catch {
7564
7794
  return {};
@@ -7597,7 +7827,7 @@ function startLogsServerDaemon() {
7597
7827
  try {
7598
7828
  mkdirSync5(DIR, { recursive: true });
7599
7829
  const log3 = openSync2(LOG_FILE2, "a");
7600
- const cli = join6(dirname3(fileURLToPath3(import.meta.url)), "index.js");
7830
+ const cli = join7(dirname3(fileURLToPath3(import.meta.url)), "index.js");
7601
7831
  const p = spawn3(process.execPath, [cli, "logs-server"], {
7602
7832
  detached: true,
7603
7833
  stdio: ["ignore", log3, log3],
@@ -7637,22 +7867,22 @@ var DIR, STATE_FILE2, LOG_FILE2, LOGS_SERVER_PORT;
7637
7867
  var init_logs_server_daemon = __esm({
7638
7868
  "src/logs-server-daemon.ts"() {
7639
7869
  "use strict";
7640
- DIR = join6(homedir4(), ".solongate");
7641
- STATE_FILE2 = join6(DIR, ".logs-server.json");
7642
- LOG_FILE2 = join6(DIR, "logs-server.log");
7870
+ DIR = join7(homedir5(), ".solongate");
7871
+ STATE_FILE2 = join7(DIR, ".logs-server.json");
7872
+ LOG_FILE2 = join7(DIR, "logs-server.log");
7643
7873
  LOGS_SERVER_PORT = 8788;
7644
7874
  }
7645
7875
  });
7646
7876
 
7647
7877
  // src/tui/config.ts
7648
- import { readFileSync as readFileSync7 } from "fs";
7649
- import { homedir as homedir5 } from "os";
7650
- import { join as join7 } from "path";
7878
+ import { readFileSync as readFileSync8 } from "fs";
7879
+ import { homedir as homedir6 } from "os";
7880
+ import { join as join8 } from "path";
7651
7881
  function loadConfig() {
7652
7882
  if (cached) return cached;
7653
7883
  const defaults = { notifications: true };
7654
7884
  try {
7655
- const raw = readFileSync7(join7(homedir5(), ".solongate", "tui-config.json"), "utf-8");
7885
+ const raw = readFileSync8(join8(homedir6(), ".solongate", "tui-config.json"), "utf-8");
7656
7886
  const j = JSON.parse(raw);
7657
7887
  cached = {
7658
7888
  notifications: j.notifications !== false,
@@ -7823,16 +8053,16 @@ var init_components = __esm({
7823
8053
  });
7824
8054
 
7825
8055
  // src/tui/local-log.ts
7826
- import { closeSync, existsSync as existsSync4, openSync as openSync3, readdirSync as readdirSync2, readFileSync as readFileSync8, readSync, statSync as statSync2, writeFileSync as writeFileSync6 } from "fs";
7827
- import { homedir as homedir6 } from "os";
8056
+ import { closeSync, existsSync as existsSync5, openSync as openSync3, readdirSync as readdirSync2, readFileSync as readFileSync9, readSync, statSync as statSync3, writeFileSync as writeFileSync6 } from "fs";
8057
+ import { homedir as homedir7 } from "os";
7828
8058
  import { createHash as createHash2 } from "crypto";
7829
- import { isAbsolute, join as join8 } from "path";
8059
+ import { isAbsolute, join as join9 } from "path";
7830
8060
  function localLogsSetting() {
7831
8061
  const off = { enabled: false, configuredPath: null, usableHere: true, file: DEFAULT_LOCAL_LOG };
7832
8062
  try {
7833
8063
  for (const cache of policyCachesNewestFirst()) {
7834
8064
  try {
7835
- const c2 = JSON.parse(readFileSync8(cache, "utf-8"));
8065
+ const c2 = JSON.parse(readFileSync9(cache, "utf-8"));
7836
8066
  const l = c2?.security?.localLogs;
7837
8067
  if (!l || typeof l.enabled !== "boolean") continue;
7838
8068
  if (!l.enabled) return { ...off, configuredPath: typeof l.path === "string" ? l.path.trim() || null : null };
@@ -7840,8 +8070,8 @@ function localLogsSetting() {
7840
8070
  const dir = raw.replace(/[\\/]+$/, "");
7841
8071
  if (!dir) return { enabled: true, configuredPath: null, usableHere: true, file: DEFAULT_LOCAL_LOG };
7842
8072
  if (!isAbsolute(dir)) return { enabled: true, configuredPath: raw, usableHere: false, file: DEFAULT_LOCAL_LOG };
7843
- const file = join8(dir, "solongate-audit.jsonl");
7844
- const usable = existsSync4(file) || existsSync4(dir);
8073
+ const file = join9(dir, "solongate-audit.jsonl");
8074
+ const usable = existsSync5(file) || existsSync5(dir);
7845
8075
  return { enabled: true, configuredPath: raw, usableHere: usable, file: usable ? file : DEFAULT_LOCAL_LOG };
7846
8076
  } catch {
7847
8077
  }
@@ -7851,12 +8081,12 @@ function localLogsSetting() {
7851
8081
  return off;
7852
8082
  }
7853
8083
  function policyCachesNewestFirst() {
7854
- const sgDir = join8(homedir6(), ".solongate");
7855
- return readdirSync2(sgDir).filter((f) => f.startsWith(".policy-cache-") && f.endsWith(".json")).map((f) => {
7856
- const p = join8(sgDir, f);
8084
+ const sgDir2 = join9(homedir7(), ".solongate");
8085
+ return readdirSync2(sgDir2).filter((f) => f.startsWith(".policy-cache-") && f.endsWith(".json")).map((f) => {
8086
+ const p = join9(sgDir2, f);
7857
8087
  let mtime = 0;
7858
8088
  try {
7859
- mtime = statSync2(p).mtimeMs;
8089
+ mtime = statSync3(p).mtimeMs;
7860
8090
  } catch {
7861
8091
  }
7862
8092
  return { p, mtime };
@@ -7864,27 +8094,27 @@ function policyCachesNewestFirst() {
7864
8094
  }
7865
8095
  function localLogFile() {
7866
8096
  try {
7867
- const sgDir = join8(homedir6(), ".solongate");
7868
- const caches = readdirSync2(sgDir).filter((f) => f.startsWith(".policy-cache-") && f.endsWith(".json")).map((f) => {
7869
- const p = join8(sgDir, f);
8097
+ const sgDir2 = join9(homedir7(), ".solongate");
8098
+ const caches = readdirSync2(sgDir2).filter((f) => f.startsWith(".policy-cache-") && f.endsWith(".json")).map((f) => {
8099
+ const p = join9(sgDir2, f);
7870
8100
  let mtime = 0;
7871
8101
  try {
7872
- mtime = statSync2(p).mtimeMs;
8102
+ mtime = statSync3(p).mtimeMs;
7873
8103
  } catch {
7874
8104
  }
7875
8105
  return { p, mtime };
7876
8106
  }).sort((a, b) => b.mtime - a.mtime);
7877
8107
  for (const { p } of caches) {
7878
8108
  try {
7879
- const c2 = JSON.parse(readFileSync8(p, "utf-8"));
8109
+ const c2 = JSON.parse(readFileSync9(p, "utf-8"));
7880
8110
  const l = c2?.security?.localLogs;
7881
8111
  if (!l || !l.enabled || typeof l.path !== "string" || !l.path.trim()) continue;
7882
8112
  const dir = l.path.trim().replace(/[\\/]+$/, "");
7883
8113
  if (!dir) continue;
7884
8114
  if (!isAbsolute(dir)) return DEFAULT_LOCAL_LOG;
7885
- const file = join8(dir, "solongate-audit.jsonl");
7886
- if (existsSync4(file)) return file;
7887
- return existsSync4(dir) ? file : DEFAULT_LOCAL_LOG;
8115
+ const file = join9(dir, "solongate-audit.jsonl");
8116
+ if (existsSync5(file)) return file;
8117
+ return existsSync5(dir) ? file : DEFAULT_LOCAL_LOG;
7888
8118
  } catch {
7889
8119
  }
7890
8120
  }
@@ -7894,11 +8124,11 @@ function localLogFile() {
7894
8124
  }
7895
8125
  function ensureLocalLogOwner(activeApiKey) {
7896
8126
  try {
7897
- const marker = join8(homedir6(), ".solongate", "local-logs", ".owner");
8127
+ const marker = join9(homedir7(), ".solongate", "local-logs", ".owner");
7898
8128
  const want = activeApiKey ? createHash2("sha256").update(activeApiKey).digest("hex").slice(0, 16) : "";
7899
8129
  let have = "";
7900
8130
  try {
7901
- have = readFileSync8(marker, "utf-8").trim();
8131
+ have = readFileSync9(marker, "utf-8").trim();
7902
8132
  } catch {
7903
8133
  }
7904
8134
  if (have === want) return false;
@@ -7913,7 +8143,7 @@ function ensureLocalLogOwner(activeApiKey) {
7913
8143
  }
7914
8144
  function tailLines(file, maxBytes = 131072) {
7915
8145
  try {
7916
- const size = statSync2(file).size;
8146
+ const size = statSync3(file).size;
7917
8147
  const start = Math.max(0, size - maxBytes);
7918
8148
  const fd = openSync3(file, "r");
7919
8149
  const buf = Buffer.alloc(size - start);
@@ -7926,35 +8156,10 @@ function tailLines(file, maxBytes = 131072) {
7926
8156
  return [];
7927
8157
  }
7928
8158
  }
7929
- function deleteLocalEntry(at, tool, session) {
7930
- try {
7931
- const file = localLogFile();
7932
- const lines = readFileSync8(file, "utf-8").split("\n");
7933
- let removed = 0;
7934
- const kept = lines.filter((line) => {
7935
- if (!line.trim()) return false;
7936
- if (removed) return true;
7937
- try {
7938
- const j = JSON.parse(line);
7939
- const hit = Date.parse(j.ts ?? "") === at && (j.tool ?? "?") === tool && (!session || j.session_id === session);
7940
- if (hit) {
7941
- removed++;
7942
- return false;
7943
- }
7944
- } catch {
7945
- }
7946
- return true;
7947
- });
7948
- if (removed) writeFileSync6(file, kept.length ? kept.join("\n") + "\n" : "");
7949
- return removed;
7950
- } catch {
7951
- return 0;
7952
- }
7953
- }
7954
8159
  function clearLocalLog() {
7955
8160
  try {
7956
8161
  const file = localLogFile();
7957
- const n = readFileSync8(file, "utf-8").split("\n").filter(Boolean).length;
8162
+ const n = readFileSync9(file, "utf-8").split("\n").filter(Boolean).length;
7958
8163
  writeFileSync6(file, "");
7959
8164
  return n;
7960
8165
  } catch {
@@ -7972,8 +8177,8 @@ function reasonSignals(reason) {
7972
8177
  }
7973
8178
  function ownMark() {
7974
8179
  try {
7975
- const p = join8(homedir6(), ".solongate", "cloud-guard.json");
7976
- const c2 = JSON.parse(readFileSync8(p, "utf-8"));
8180
+ const p = join9(homedir7(), ".solongate", "cloud-guard.json");
8181
+ const c2 = JSON.parse(readFileSync9(p, "utf-8"));
7977
8182
  return c2?.apiKey ? createHash2("sha256").update(c2.apiKey).digest("hex").slice(0, 16) : "";
7978
8183
  } catch {
7979
8184
  return "";
@@ -7997,7 +8202,7 @@ var DEFAULT_LOCAL_LOG, LOCAL_LOG, DLP_REASON, RL_REASON;
7997
8202
  var init_local_log = __esm({
7998
8203
  "src/tui/local-log.ts"() {
7999
8204
  "use strict";
8000
- DEFAULT_LOCAL_LOG = join8(homedir6(), ".solongate", "local-logs", "solongate-audit.jsonl");
8205
+ DEFAULT_LOCAL_LOG = join9(homedir7(), ".solongate", "local-logs", "solongate-audit.jsonl");
8001
8206
  LOCAL_LOG = localLogFile();
8002
8207
  DLP_REASON = /security layer \(dlp\)/i;
8003
8208
  RL_REASON = /security layer \(rate limit\)|rate[- ]?limit(?:ed)?\b.*exceed|exceeded \d+ calls/i;
@@ -8005,13 +8210,13 @@ var init_local_log = __esm({
8005
8210
  });
8006
8211
 
8007
8212
  // src/api-client/client.ts
8008
- import { readFileSync as readFileSync9, writeFileSync as writeFileSync7, mkdirSync as mkdirSync6, existsSync as existsSync5 } from "fs";
8009
- import { resolve as resolve4, join as join9 } from "path";
8010
- import { homedir as homedir7 } from "os";
8213
+ import { readFileSync as readFileSync10, writeFileSync as writeFileSync7, mkdirSync as mkdirSync6, existsSync as existsSync6 } from "fs";
8214
+ import { resolve as resolve4, join as join10 } from "path";
8215
+ import { homedir as homedir8 } from "os";
8011
8216
  function listAccounts() {
8012
8217
  let list5 = [];
8013
8218
  try {
8014
- const raw = JSON.parse(readFileSync9(accountsFile(), "utf-8"));
8219
+ const raw = JSON.parse(readFileSync10(accountsFile(), "utf-8"));
8015
8220
  if (Array.isArray(raw)) list5 = raw.filter((a) => a && typeof a.apiKey === "string");
8016
8221
  } catch {
8017
8222
  }
@@ -8025,7 +8230,7 @@ function saveAccount(acc) {
8025
8230
  try {
8026
8231
  const list5 = (() => {
8027
8232
  try {
8028
- const raw = JSON.parse(readFileSync9(accountsFile(), "utf-8"));
8233
+ const raw = JSON.parse(readFileSync10(accountsFile(), "utf-8"));
8029
8234
  return Array.isArray(raw) ? raw.filter((a) => a && a.apiKey) : [];
8030
8235
  } catch {
8031
8236
  return [];
@@ -8033,7 +8238,7 @@ function saveAccount(acc) {
8033
8238
  })();
8034
8239
  const next = list5.filter((a) => a.apiKey !== acc.apiKey);
8035
8240
  next.unshift({ ...acc, addedAt: acc.addedAt ?? Date.now() });
8036
- mkdirSync6(join9(homedir7(), ".solongate"), { recursive: true });
8241
+ mkdirSync6(join10(homedir8(), ".solongate"), { recursive: true });
8037
8242
  writeFileSync7(accountsFile(), JSON.stringify(next, null, 2));
8038
8243
  } catch {
8039
8244
  }
@@ -8042,7 +8247,7 @@ function removeAccount(apiKey) {
8042
8247
  try {
8043
8248
  const list5 = (() => {
8044
8249
  try {
8045
- const raw = JSON.parse(readFileSync9(accountsFile(), "utf-8"));
8250
+ const raw = JSON.parse(readFileSync10(accountsFile(), "utf-8"));
8046
8251
  return Array.isArray(raw) ? raw.filter((a) => a && a.apiKey) : [];
8047
8252
  } catch {
8048
8253
  return [];
@@ -8064,12 +8269,12 @@ function isActiveAccount(apiKey) {
8064
8269
  }
8065
8270
  function setActiveAccount(creds) {
8066
8271
  try {
8067
- const dir = join9(homedir7(), ".solongate");
8272
+ const dir = join10(homedir8(), ".solongate");
8068
8273
  mkdirSync6(dir, { recursive: true });
8069
- const p = join9(dir, ["cloud", "guard.json"].join("-"));
8274
+ const p = join10(dir, ["cloud", "guard.json"].join("-"));
8070
8275
  let existing = {};
8071
8276
  try {
8072
- existing = JSON.parse(readFileSync9(p, "utf-8"));
8277
+ existing = JSON.parse(readFileSync10(p, "utf-8"));
8073
8278
  } catch {
8074
8279
  }
8075
8280
  if (!writeProtectedFile(p, JSON.stringify({ ...existing, apiKey: creds.apiKey, apiUrl: creds.apiUrl }, null, 2))) return false;
@@ -8081,14 +8286,14 @@ function setActiveAccount(creds) {
8081
8286
  }
8082
8287
  function clearActiveCredential() {
8083
8288
  try {
8084
- const p = join9(homedir7(), ".solongate", ["cloud", "guard.json"].join("-"));
8085
- if (!existsSync5(p)) {
8289
+ const p = join10(homedir8(), ".solongate", ["cloud", "guard.json"].join("-"));
8290
+ if (!existsSync6(p)) {
8086
8291
  cached2 = null;
8087
8292
  return true;
8088
8293
  }
8089
8294
  let existing = {};
8090
8295
  try {
8091
- existing = JSON.parse(readFileSync9(p, "utf-8"));
8296
+ existing = JSON.parse(readFileSync10(p, "utf-8"));
8092
8297
  } catch {
8093
8298
  }
8094
8299
  delete existing.apiKey;
@@ -8103,9 +8308,9 @@ function clearActiveCredential() {
8103
8308
  }
8104
8309
  function loginCredentialFile() {
8105
8310
  try {
8106
- const p = join9(homedir7(), ".solongate", "cloud-guard.json");
8107
- if (!existsSync5(p)) return {};
8108
- const c2 = JSON.parse(readFileSync9(p, "utf-8"));
8311
+ const p = join10(homedir8(), ".solongate", "cloud-guard.json");
8312
+ if (!existsSync6(p)) return {};
8313
+ const c2 = JSON.parse(readFileSync10(p, "utf-8"));
8109
8314
  return c2 && typeof c2 === "object" ? c2 : {};
8110
8315
  } catch {
8111
8316
  return {};
@@ -8114,8 +8319,8 @@ function loginCredentialFile() {
8114
8319
  function dotenvApiKey() {
8115
8320
  try {
8116
8321
  const envPath = resolve4(".env");
8117
- if (!existsSync5(envPath)) return void 0;
8118
- for (const line of readFileSync9(envPath, "utf-8").split("\n")) {
8322
+ if (!existsSync6(envPath)) return void 0;
8323
+ for (const line of readFileSync10(envPath, "utf-8").split("\n")) {
8119
8324
  const trimmed = line.trim();
8120
8325
  if (!trimmed || trimmed.startsWith("#")) continue;
8121
8326
  const eq = trimmed.indexOf("=");
@@ -8219,7 +8424,7 @@ var init_client = __esm({
8219
8424
  "use strict";
8220
8425
  init_global_install();
8221
8426
  DEFAULT_API_URL2 = "https://api.solongate.com";
8222
- accountsFile = () => join9(homedir7(), ".solongate", "accounts.json");
8427
+ accountsFile = () => join10(homedir8(), ".solongate", "accounts.json");
8223
8428
  viewOverride = null;
8224
8429
  ApiError = class extends Error {
8225
8430
  status;
@@ -8495,19 +8700,11 @@ var audit_exports = {};
8495
8700
  __export(audit_exports, {
8496
8701
  block: () => block,
8497
8702
  list: () => list2,
8498
- remove: () => remove2,
8499
- removeAll: () => removeAll,
8500
8703
  whitelist: () => whitelist
8501
8704
  });
8502
8705
  function list2(query = {}) {
8503
8706
  return request("GET", "/audit-logs", { query });
8504
8707
  }
8505
- function remove2(ids) {
8506
- return request("DELETE", "/audit-logs", { body: { ids } });
8507
- }
8508
- function removeAll() {
8509
- return request("DELETE", "/audit-logs", { body: { scope: "logs" } });
8510
- }
8511
8708
  function whitelist(id, scope = "exact") {
8512
8709
  return request("POST", `/audit-logs/${encodeURIComponent(id)}/whitelist`, { body: { scope } });
8513
8710
  }
@@ -8711,8 +8908,8 @@ var init_hooks = __esm({
8711
8908
  import { Box as Box2, Text as Text2, useInput } from "ink";
8712
8909
  import TextInput from "ink-text-input";
8713
8910
  import { mkdirSync as mkdirSync7, writeFileSync as writeFileSync8 } from "fs";
8714
- import { homedir as homedir8 } from "os";
8715
- import { join as join10, resolve as resolve5 } from "path";
8911
+ import { homedir as homedir9 } from "os";
8912
+ import { join as join11, resolve as resolve5 } from "path";
8716
8913
  import { useCallback as useCallback2, useEffect as useEffect2, useRef as useRef2, useState as useState2 } from "react";
8717
8914
  import { Fragment as Fragment2, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
8718
8915
  function extractTarget(detail) {
@@ -9269,9 +9466,9 @@ function LivePanel({ active: active2 }) {
9269
9466
  else if (input === "x") toggleSignal("dlp");
9270
9467
  else if (input === "r") toggleSignal("ratelimit");
9271
9468
  else if (input === "e") {
9272
- const file = join10(homedir8(), ".solongate", "live-export.jsonl");
9469
+ const file = join11(homedir9(), ".solongate", "live-export.jsonl");
9273
9470
  try {
9274
- mkdirSync7(join10(homedir8(), ".solongate"), { recursive: true });
9471
+ mkdirSync7(join11(homedir9(), ".solongate"), { recursive: true });
9275
9472
  writeFileSync8(file, visibleDesc.map((x) => JSON.stringify(x)).join("\n") + "\n");
9276
9473
  setActionMsg({ text: `\u2713 exported ${visibleDesc.length} lines \u2192 ${file}`, level: "ok", until: Date.now() + 6e3 });
9277
9474
  } catch (err2) {
@@ -9709,7 +9906,7 @@ var init_Live = __esm({
9709
9906
  }
9710
9907
  return h.toString(16);
9711
9908
  };
9712
- RING = join10(homedir8(), ".solongate", "projects", projectKey(resolve5(process.cwd())), ".eval-ring.jsonl");
9909
+ RING = join11(homedir9(), ".solongate", "projects", projectKey(resolve5(process.cwd())), ".eval-ring.jsonl");
9713
9910
  fmtUp = (ms) => {
9714
9911
  const s = Math.floor(ms / 1e3);
9715
9912
  const p = (n) => String(n).padStart(2, "0");
@@ -10995,8 +11192,8 @@ var init_Dlp = __esm({
10995
11192
  import { Box as Box7, Text as Text7, useInput as useInput6 } from "ink";
10996
11193
  import TextInput5 from "ink-text-input";
10997
11194
  import { mkdirSync as mkdirSync8, writeFileSync as writeFileSync9 } from "fs";
10998
- import { homedir as homedir9 } from "os";
10999
- import { join as join11 } from "path";
11195
+ import { homedir as homedir10 } from "os";
11196
+ import { join as join12 } from "path";
11000
11197
  import { useState as useState7 } from "react";
11001
11198
  import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
11002
11199
  function loadLocalRows() {
@@ -11038,7 +11235,6 @@ function AuditPanel({ active: active2, focused }) {
11038
11235
  const [si, setSi] = useState7(0);
11039
11236
  const [sessSearch, setSessSearch] = useState7("");
11040
11237
  const [sessSel, setSessSel] = useState7(0);
11041
- const [confirm, setConfirm] = useState7(null);
11042
11238
  const [msg, setMsg] = useState7(null);
11043
11239
  const [showHelp, setShowHelp] = useState7(false);
11044
11240
  const [frozen, setFrozen] = useState7(false);
@@ -11120,34 +11316,11 @@ function AuditPanel({ active: active2, focused }) {
11120
11316
  const currentSess = sessionsFiltered[Math.min(sessSel, Math.max(0, sessionsFiltered.length - 1))];
11121
11317
  const logsLoading = (source === "cloud" ? cloudQ.loading : localQ.loading) && !editing;
11122
11318
  const sessLoading = source === "cloud" ? agentsQ.loading : localQ.loading;
11123
- const doDelete = (kind) => {
11124
- setMsg({ text: "deleting\u2026", level: "ok" });
11125
- const run12 = async () => {
11126
- if (source === "cloud") {
11127
- if (kind === "one") {
11128
- if (!current) throw new Error("nothing selected");
11129
- await api.audit.remove([current.id]);
11130
- } else {
11131
- await api.audit.removeAll();
11132
- }
11133
- cloudQ.reload();
11134
- statsQ.reloadQuiet();
11135
- } else {
11136
- const n = kind === "one" && current ? deleteLocalEntry(current.at, current.tool, current.session) : kind === "all" ? clearLocalLog() : 0;
11137
- if (!n) throw new Error("entry not found in the local file");
11138
- localQ.reload();
11139
- }
11140
- };
11141
- run12().then(() => {
11142
- setMsg({ text: kind === "one" ? "\u2713 entry deleted" : `\u2713 ALL ${source} logs deleted`, level: "ok" });
11143
- toTop();
11144
- }).catch((e) => setMsg({ text: "\u2717 " + (e instanceof Error ? e.message : String(e)), level: "bad" }));
11145
- };
11146
11319
  const doExport = (kind) => {
11147
11320
  setMsg({ text: "exporting\u2026", level: "ok" });
11148
11321
  const run12 = async () => {
11149
- const dir = join11(homedir9(), ".solongate");
11150
- const file = join11(dir, `audit-export-${source}.jsonl`);
11322
+ const dir = join12(homedir10(), ".solongate");
11323
+ const file = join12(dir, `audit-export-${source}.jsonl`);
11151
11324
  let rows2;
11152
11325
  if (kind === "page") rows2 = pageRows;
11153
11326
  else if (source === "cloud") {
@@ -11193,8 +11366,7 @@ function AuditPanel({ active: active2, focused }) {
11193
11366
  return;
11194
11367
  }
11195
11368
  if (view === "logs" ? logsLoading : sessLoading) return;
11196
- if (confirm && input !== "x" && input !== "X") {
11197
- setConfirm(null);
11369
+ if (msg) {
11198
11370
  setMsg(null);
11199
11371
  }
11200
11372
  if (input === "s") {
@@ -11258,23 +11430,6 @@ function AuditPanel({ active: active2, focused }) {
11258
11430
  setGi((n) => (n + 1) % SIGNALS.length);
11259
11431
  setPage(0);
11260
11432
  toTop();
11261
- } else if (input === "x") {
11262
- if (!current) return;
11263
- if (confirm?.kind !== "one" || confirm.key !== current.id) {
11264
- setConfirm({ kind: "one", key: current.id });
11265
- setMsg({ text: `x = delete ONLY the selected entry: ${current.decision} ${current.tool} (${ago(current.at)} ago) \u2014 press x again`, level: "bad" });
11266
- return;
11267
- }
11268
- setConfirm(null);
11269
- doDelete("one");
11270
- } else if (input === "X") {
11271
- if (confirm?.kind !== "all") {
11272
- setConfirm({ kind: "all", key: "all" });
11273
- setMsg({ text: `\u26A0 X = delete ALL ${source} logs \u2014 every one of the ${total} matched entries! press X again`, level: "bad" });
11274
- return;
11275
- }
11276
- setConfirm(null);
11277
- doDelete("all");
11278
11433
  } else if (input === "e") doExport("page");
11279
11434
  else if (input === "E") doExport("all");
11280
11435
  else if (input === "t") setEditing("tool");
@@ -11588,8 +11743,6 @@ var init_Audit = __esm({
11588
11743
  ["g", "signal filter: all \u2192 dlp \u2192 ratelimit"],
11589
11744
  ["t / n", "tool / agent filter (type, enter done)"],
11590
11745
  ["/", "free-text search"],
11591
- ["x", "delete ONLY the selected entry (press x twice)"],
11592
- ["X", "delete ALL matched logs of the source (press X twice)"],
11593
11746
  ["e", "export this page \u2192 ~/.solongate/audit-export-<src>.jsonl"],
11594
11747
  ["E", "export ALL matched rows (cloud: up to 10k)"],
11595
11748
  ["c", "clear every filter (incl. session)"]
@@ -11751,9 +11904,9 @@ var init_args = __esm({
11751
11904
  });
11752
11905
 
11753
11906
  // src/commands/doctor.ts
11754
- import { existsSync as existsSync6, readFileSync as readFileSync10, statSync as statSync3 } from "fs";
11755
- import { homedir as homedir10 } from "os";
11756
- import { join as join12 } from "path";
11907
+ import { existsSync as existsSync7, readFileSync as readFileSync11, statSync as statSync4 } from "fs";
11908
+ import { homedir as homedir11 } from "os";
11909
+ import { join as join13 } from "path";
11757
11910
  async function collectChecks() {
11758
11911
  const checks = [];
11759
11912
  if (!isAuthenticated()) {
@@ -11801,8 +11954,32 @@ async function collectChecks() {
11801
11954
  ok: claudeReg,
11802
11955
  detail: claudeReg ? "guard registered" : "guard NOT registered - run `solongate repair`"
11803
11956
  });
11804
- if (existsSync6(globalPaths().antigravityDir)) {
11805
- const reg = existsSync6(globalPaths().antigravityHooksPath);
11957
+ if (claudeReg) {
11958
+ const start = hookCanStart();
11959
+ checks.push({
11960
+ name: "hook runtime",
11961
+ ok: start.ok,
11962
+ detail: start.ok ? `node ${start.detail}` : `${start.detail} - nothing is being enforced or logged`
11963
+ });
11964
+ const beat = guardBeat();
11965
+ if (!beat) {
11966
+ checks.push({
11967
+ name: "guard fired",
11968
+ ok: "warn",
11969
+ detail: "never - open your agent and run one tool call, then check again"
11970
+ });
11971
+ } else if (beat.node === "no-node") {
11972
+ checks.push({
11973
+ name: "guard fired",
11974
+ ok: false,
11975
+ detail: `${agoLabel(beat.at)}, but found no node to run with - run \`solongate repair\``
11976
+ });
11977
+ } else {
11978
+ checks.push({ name: "guard fired", ok: true, detail: `${agoLabel(beat.at)} \xB7 ${beat.node}` });
11979
+ }
11980
+ }
11981
+ if (existsSync7(globalPaths().antigravityDir)) {
11982
+ const reg = existsSync7(globalPaths().antigravityHooksPath);
11806
11983
  checks.push({
11807
11984
  name: "Antigravity hooks",
11808
11985
  ok: reg,
@@ -11830,7 +12007,7 @@ async function collectChecks() {
11830
12007
  });
11831
12008
  }
11832
12009
  try {
11833
- const raw = readFileSync10(join12(homedir10(), ".solongate", ".key-rejected.json"), "utf-8");
12010
+ const raw = readFileSync11(join13(homedir11(), ".solongate", ".key-rejected.json"), "utf-8");
11834
12011
  const m = JSON.parse(raw);
11835
12012
  const ageMin = m.ts ? Math.round((Date.now() - m.ts) / 6e4) : null;
11836
12013
  checks.push({
@@ -11841,8 +12018,8 @@ async function collectChecks() {
11841
12018
  } catch {
11842
12019
  }
11843
12020
  const LOCAL_LOG2 = localLogFile();
11844
- if (existsSync6(LOCAL_LOG2)) {
11845
- const st = statSync3(LOCAL_LOG2);
12021
+ if (existsSync7(LOCAL_LOG2)) {
12022
+ const st = statSync4(LOCAL_LOG2);
11846
12023
  const ageMin = (Date.now() - st.mtimeMs) / 6e4;
11847
12024
  checks.push({ name: "local logs", ok: true, detail: `on \xB7 ${(st.size / 1024).toFixed(0)}KB \xB7 last write ${ageMin < 1 ? "just now" : Math.round(ageMin) + "m ago"}` });
11848
12025
  } else {
@@ -11875,6 +12052,7 @@ var init_doctor = __esm({
11875
12052
  "use strict";
11876
12053
  init_api_client();
11877
12054
  init_global_install();
12055
+ init_hook_health();
11878
12056
  init_local_log();
11879
12057
  init_format();
11880
12058
  init_args();
@@ -12982,8 +13160,8 @@ __export(tui_exports, {
12982
13160
  launchTui: () => launchTui
12983
13161
  });
12984
13162
  import { appendFileSync as appendFileSync2, mkdirSync as mkdirSync9 } from "fs";
12985
- import { homedir as homedir11 } from "os";
12986
- import { join as join13 } from "path";
13163
+ import { homedir as homedir12 } from "os";
13164
+ import { join as join14 } from "path";
12987
13165
  import { render } from "ink";
12988
13166
  import { jsx as jsx10 } from "react/jsx-runtime";
12989
13167
  async function launchTui() {
@@ -12994,11 +13172,11 @@ async function launchTui() {
12994
13172
  return;
12995
13173
  }
12996
13174
  process.stdout.write("\x1B[?1049h\x1B[H");
12997
- const debugLog = join13(homedir11(), ".solongate", "dataroom-debug.log");
13175
+ const debugLog = join14(homedir12(), ".solongate", "dataroom-debug.log");
12998
13176
  const saved = { log: console.log, warn: console.warn, error: console.error, info: console.info, debug: console.debug };
12999
13177
  const toFile = (level) => (...args) => {
13000
13178
  try {
13001
- mkdirSync9(join13(homedir11(), ".solongate"), { recursive: true });
13179
+ mkdirSync9(join14(homedir12(), ".solongate"), { recursive: true });
13002
13180
  appendFileSync2(debugLog, `${(/* @__PURE__ */ new Date()).toISOString()} [${level}] ${args.map((a) => typeof a === "string" ? a : JSON.stringify(a)).join(" ")}
13003
13181
  `);
13004
13182
  } catch {
@@ -13025,7 +13203,7 @@ var init_tui = __esm({
13025
13203
  });
13026
13204
 
13027
13205
  // src/commands/policy.ts
13028
- import { readFileSync as readFileSync11 } from "fs";
13206
+ import { readFileSync as readFileSync12 } from "fs";
13029
13207
  async function run2(argv) {
13030
13208
  const { positionals, flags } = parse(argv);
13031
13209
  const sub = positionals[0];
@@ -13234,7 +13412,7 @@ function printRules(rules) {
13234
13412
  }
13235
13413
  async function resolveRules(target) {
13236
13414
  if (target.endsWith(".json")) {
13237
- const parsed = JSON.parse(readFileSync11(target, "utf-8"));
13415
+ const parsed = JSON.parse(readFileSync12(target, "utf-8"));
13238
13416
  return parsed.rules ?? [];
13239
13417
  }
13240
13418
  const p = await api.policies.get(target);
@@ -13733,11 +13911,11 @@ var init_agents2 = __esm({
13733
13911
  });
13734
13912
 
13735
13913
  // src/commands/trace.ts
13736
- import { readdirSync as readdirSync3, readFileSync as readFileSync12 } from "fs";
13737
- import { homedir as homedir12 } from "os";
13738
- import { join as join14, resolve as resolve6 } from "path";
13914
+ import { readdirSync as readdirSync3, readFileSync as readFileSync13 } from "fs";
13915
+ import { homedir as homedir13 } from "os";
13916
+ import { join as join15, resolve as resolve6 } from "path";
13739
13917
  function readAllRings() {
13740
- const root = join14(homedir12(), ".solongate", "projects");
13918
+ const root = join15(homedir13(), ".solongate", "projects");
13741
13919
  let dirs;
13742
13920
  try {
13743
13921
  dirs = readdirSync3(root);
@@ -13748,7 +13926,7 @@ function readAllRings() {
13748
13926
  for (const d of dirs) {
13749
13927
  let text;
13750
13928
  try {
13751
- text = readFileSync12(join14(root, d, ".eval-ring.jsonl"), "utf-8");
13929
+ text = readFileSync13(join15(root, d, ".eval-ring.jsonl"), "utf-8");
13752
13930
  } catch {
13753
13931
  continue;
13754
13932
  }
@@ -13841,10 +14019,10 @@ var init_trace = __esm({
13841
14019
  });
13842
14020
 
13843
14021
  // src/commands/watch.ts
13844
- import { closeSync as closeSync2, existsSync as existsSync7, openSync as openSync4, readSync as readSync2, statSync as statSync4 } from "fs";
14022
+ import { closeSync as closeSync2, existsSync as existsSync8, openSync as openSync4, readSync as readSync2, statSync as statSync5 } from "fs";
13845
14023
  function tailLocal(file, maxBytes = 131072) {
13846
14024
  try {
13847
- const size = statSync4(file).size;
14025
+ const size = statSync5(file).size;
13848
14026
  const start = Math.max(0, size - maxBytes);
13849
14027
  const fd = openSync4(file, "r");
13850
14028
  const buf = Buffer.alloc(size - start);
@@ -13886,7 +14064,7 @@ async function run9(argv) {
13886
14064
  };
13887
14065
  const pollLocal = () => {
13888
14066
  const LOCAL_LOG2 = localLogFile();
13889
- if (cloudOnly || !existsSync7(LOCAL_LOG2)) return;
14067
+ if (cloudOnly || !existsSync8(LOCAL_LOG2)) return;
13890
14068
  const rows = [];
13891
14069
  for (const line of tailLocal(LOCAL_LOG2)) {
13892
14070
  try {
@@ -14158,9 +14336,9 @@ __export(logs_server_exports, {
14158
14336
  runLogsServer: () => runLogsServer
14159
14337
  });
14160
14338
  import { createServer } from "http";
14161
- import { readFileSync as readFileSync13, statSync as statSync5 } from "fs";
14162
- import { resolve as resolve7, join as join15, isAbsolute as isAbsolute2 } from "path";
14163
- import { homedir as homedir13 } from "os";
14339
+ import { readFileSync as readFileSync14, statSync as statSync6 } from "fs";
14340
+ import { resolve as resolve7, join as join16, isAbsolute as isAbsolute2 } from "path";
14341
+ import { homedir as homedir14 } from "os";
14164
14342
  import { readdirSync as readdirSync4 } from "fs";
14165
14343
  function allowedOrigins() {
14166
14344
  const base = [
@@ -14177,15 +14355,15 @@ function resolveLocalLogDir(rawPath) {
14177
14355
  const dir = String(rawPath || "").trim().replace(/[\\/]+$/, "");
14178
14356
  if (!dir) return null;
14179
14357
  if (isAbsolute2(dir)) return dir;
14180
- return resolve7(homedir13(), ".solongate", "local-logs");
14358
+ return resolve7(homedir14(), ".solongate", "local-logs");
14181
14359
  }
14182
14360
  async function findLogDir() {
14183
- const base = resolve7(homedir13(), ".solongate");
14361
+ const base = resolve7(homedir14(), ".solongate");
14184
14362
  try {
14185
14363
  const files = readdirSync4(base).filter((f) => f.startsWith(".policy-cache-") && f.endsWith(".json"));
14186
14364
  for (const f of files) {
14187
14365
  try {
14188
- const c2 = JSON.parse(readFileSync13(join15(base, f), "utf-8"));
14366
+ const c2 = JSON.parse(readFileSync14(join16(base, f), "utf-8"));
14189
14367
  const p = c2?.security?.localLogs?.path;
14190
14368
  if (typeof p === "string" && p.trim()) return { dir: resolveLocalLogDir(p), configured: p };
14191
14369
  } catch {
@@ -14194,7 +14372,7 @@ async function findLogDir() {
14194
14372
  } catch {
14195
14373
  }
14196
14374
  try {
14197
- const cfgRaw = readFileSync13(join15(base, "cloud-guard.json"), "utf-8");
14375
+ const cfgRaw = readFileSync14(join16(base, "cloud-guard.json"), "utf-8");
14198
14376
  const { apiKey, apiUrl } = JSON.parse(cfgRaw);
14199
14377
  if (apiKey) {
14200
14378
  const url = `${apiUrl || "https://api.solongate.com"}/api/v1/policies/active`;
@@ -14223,9 +14401,9 @@ function setCors(req, res) {
14223
14401
  }
14224
14402
  function fileInfo(dir) {
14225
14403
  if (!dir) return { file: null, exists: false, size: 0, mtimeMs: 0 };
14226
- const file = join15(dir, LOG_FILENAME);
14404
+ const file = join16(dir, LOG_FILENAME);
14227
14405
  try {
14228
- const st = statSync5(file);
14406
+ const st = statSync6(file);
14229
14407
  return { file, exists: true, size: st.size, mtimeMs: st.mtimeMs };
14230
14408
  } catch {
14231
14409
  return { file, exists: false, size: 0, mtimeMs: 0 };
@@ -14306,7 +14484,7 @@ async function runLogsServer() {
14306
14484
  return;
14307
14485
  }
14308
14486
  try {
14309
- const text = readFileSync13(info.file, "utf-8");
14487
+ const text = readFileSync14(info.file, "utf-8");
14310
14488
  res.writeHead(200, { "Content-Type": "text/plain; charset=utf-8", "Last-Modified": lastMod, "X-Solongate-Exists": "1" });
14311
14489
  res.end(text);
14312
14490
  } catch {
@@ -14359,9 +14537,9 @@ var init_logs_server = __esm({
14359
14537
  });
14360
14538
 
14361
14539
  // src/index.ts
14362
- import { readFileSync as readFileSync14 } from "fs";
14540
+ import { readFileSync as readFileSync15 } from "fs";
14363
14541
  import { fileURLToPath as fileURLToPath4 } from "url";
14364
- import { dirname as dirname4, join as join16 } from "path";
14542
+ import { dirname as dirname4, join as join17 } from "path";
14365
14543
 
14366
14544
  // src/config.ts
14367
14545
  import { readFileSync, existsSync } from "fs";
@@ -15474,9 +15652,9 @@ function extractFilenames(args) {
15474
15652
  if (isUrl) return;
15475
15653
  if (trimmed.includes("/") || trimmed.includes("\\")) {
15476
15654
  const parts = trimmed.split(/[/\\]/);
15477
- const basename = parts[parts.length - 1];
15478
- if (basename && looksLikeFilename(basename)) {
15479
- addFilename(basename);
15655
+ const basename2 = parts[parts.length - 1];
15656
+ if (basename2 && looksLikeFilename(basename2)) {
15657
+ addFilename(basename2);
15480
15658
  }
15481
15659
  }
15482
15660
  const lower = trimmed.toLowerCase();
@@ -15494,9 +15672,9 @@ function extractFilenames(args) {
15494
15672
  }
15495
15673
  if (word.includes("/") || word.includes("\\")) {
15496
15674
  const parts = word.split(/[/\\]/);
15497
- const basename = parts[parts.length - 1];
15498
- if (basename && looksLikeFilename(basename)) {
15499
- addFilename(basename);
15675
+ const basename2 = parts[parts.length - 1];
15676
+ if (basename2 && looksLikeFilename(basename2)) {
15677
+ addFilename(basename2);
15500
15678
  }
15501
15679
  }
15502
15680
  if (word.includes("*") || word.includes("?")) {
@@ -17756,8 +17934,8 @@ if (!IS_HUMAN_CLI) {
17756
17934
  }
17757
17935
  var PKG_VERSION = (() => {
17758
17936
  try {
17759
- const p = join16(dirname4(fileURLToPath4(import.meta.url)), "..", "package.json");
17760
- return JSON.parse(readFileSync14(p, "utf-8")).version || "unknown";
17937
+ const p = join17(dirname4(fileURLToPath4(import.meta.url)), "..", "package.json");
17938
+ return JSON.parse(readFileSync15(p, "utf-8")).version || "unknown";
17761
17939
  } catch {
17762
17940
  return "unknown";
17763
17941
  }