@solongate/proxy 0.83.56 → 0.83.58

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,17 @@ 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");
6646
+ }
6647
+ function antigravityConversationCommand(guardAbs) {
6648
+ return hookCommandFor(dirname(guardAbs), "conversation.mjs", "antigravity", "Antigravity");
6442
6649
  }
6443
6650
  function installAntigravityGuard(p, guardAbs) {
6444
6651
  mkdirSync3(p.antigravityDir, { recursive: true });
6445
6652
  let existing = {};
6446
- if (existsSync3(p.antigravityHooksPath)) {
6447
- const raw = readFileSync4(p.antigravityHooksPath, "utf-8");
6448
- if (!existsSync3(p.antigravityBackupPath)) writeFileSync3(p.antigravityBackupPath, raw);
6653
+ if (existsSync4(p.antigravityHooksPath)) {
6654
+ const raw = readFileSync5(p.antigravityHooksPath, "utf-8");
6655
+ if (!existsSync4(p.antigravityBackupPath)) writeFileSync3(p.antigravityBackupPath, raw);
6449
6656
  try {
6450
6657
  existing = JSON.parse(raw);
6451
6658
  } catch {
@@ -6455,15 +6662,16 @@ function installAntigravityGuard(p, guardAbs) {
6455
6662
  const merged = {
6456
6663
  ...existing,
6457
6664
  [ANTIGRAVITY_GROUP]: {
6458
- PreToolUse: [{ matcher: "", hooks: [{ type: "command", command: antigravityHookCommand(guardAbs) }] }]
6665
+ PreToolUse: [{ matcher: "", hooks: [{ type: "command", command: antigravityHookCommand(guardAbs) }] }],
6666
+ Stop: [{ matcher: "", hooks: [{ type: "command", command: antigravityConversationCommand(guardAbs) }] }]
6459
6667
  }
6460
6668
  };
6461
6669
  writeFileSync3(p.antigravityHooksPath, JSON.stringify(merged, null, 2) + "\n");
6462
6670
  }
6463
6671
  function removeAntigravityGuard(p) {
6464
- if (!existsSync3(p.antigravityHooksPath)) return;
6672
+ if (!existsSync4(p.antigravityHooksPath)) return;
6465
6673
  try {
6466
- const s = JSON.parse(readFileSync4(p.antigravityHooksPath, "utf-8"));
6674
+ const s = JSON.parse(readFileSync5(p.antigravityHooksPath, "utf-8"));
6467
6675
  if (!(ANTIGRAVITY_GROUP in s)) return;
6468
6676
  delete s[ANTIGRAVITY_GROUP];
6469
6677
  writeFileSync3(p.antigravityHooksPath, JSON.stringify(s, null, 2) + "\n");
@@ -6471,8 +6679,10 @@ function removeAntigravityGuard(p) {
6471
6679
  }
6472
6680
  }
6473
6681
  function codexHookCommand(scriptAbs) {
6474
- const nodeBin = process.execPath.replace(/\\/g, "/");
6475
- return `"${nodeBin}" "${scriptAbs.replace(/\\/g, "/")}" codex "Codex"`;
6682
+ if (process.platform === "win32") {
6683
+ return `"${process.execPath.replace(/\\/g, "/")}" "${scriptAbs.replace(/\\/g, "/")}" codex "Codex"`;
6684
+ }
6685
+ return hookCommandFor(dirname(scriptAbs), basename(scriptAbs), "codex", "Codex");
6476
6686
  }
6477
6687
  function isOurCodexGroup(group) {
6478
6688
  const hooks = Array.isArray(group?.hooks) ? group.hooks : [];
@@ -6480,10 +6690,10 @@ function isOurCodexGroup(group) {
6480
6690
  }
6481
6691
  function readCodexHooksFile(path) {
6482
6692
  const out2 = { hooks: {}, rest: {} };
6483
- if (!existsSync3(path)) return out2;
6693
+ if (!existsSync4(path)) return out2;
6484
6694
  let raw;
6485
6695
  try {
6486
- raw = JSON.parse(readFileSync4(path, "utf-8"));
6696
+ raw = JSON.parse(readFileSync5(path, "utf-8"));
6487
6697
  } catch {
6488
6698
  return out2;
6489
6699
  }
@@ -6528,10 +6738,10 @@ function writeCodexHooksFile(path, file) {
6528
6738
  body["hooks"] = hooks;
6529
6739
  writeFileSync3(path, JSON.stringify(body, null, 2) + "\n");
6530
6740
  }
6531
- function installCodexGuard(p, hooksDir) {
6741
+ function installCodexGuard(p, hooksDir2) {
6532
6742
  mkdirSync3(p.codexDir, { recursive: true });
6533
- if (existsSync3(p.codexHooksPath) && !existsSync3(p.codexBackupPath)) {
6534
- writeFileSync3(p.codexBackupPath, readFileSync4(p.codexHooksPath, "utf-8"));
6743
+ if (existsSync4(p.codexHooksPath) && !existsSync4(p.codexBackupPath)) {
6744
+ writeFileSync3(p.codexBackupPath, readFileSync5(p.codexHooksPath, "utf-8"));
6535
6745
  }
6536
6746
  const file = readCodexHooksFile(p.codexHooksPath);
6537
6747
  const script = {
@@ -6555,7 +6765,7 @@ function installCodexGuard(p, hooksDir) {
6555
6765
  ...ev === "Stop" ? {} : { matcher: "*" },
6556
6766
  hooks: [{
6557
6767
  type: "command",
6558
- command: codexHookCommand(join4(hooksDir, script[ev]).replace(/\\/g, "/")),
6768
+ command: codexHookCommand(join5(hooksDir2, script[ev]).replace(/\\/g, "/")),
6559
6769
  timeout: CODEX_TIMEOUT_SEC,
6560
6770
  statusMessage: status[ev]
6561
6771
  }]
@@ -6565,7 +6775,7 @@ function installCodexGuard(p, hooksDir) {
6565
6775
  writeCodexHooksFile(p.codexHooksPath, file);
6566
6776
  }
6567
6777
  function removeCodexGuard(p) {
6568
- if (!existsSync3(p.codexHooksPath)) return;
6778
+ if (!existsSync4(p.codexHooksPath)) return;
6569
6779
  try {
6570
6780
  const file = readCodexHooksFile(p.codexHooksPath);
6571
6781
  let changed = false;
@@ -6591,7 +6801,7 @@ function isCodexGuardInstalled() {
6591
6801
  }
6592
6802
  function codexDetected() {
6593
6803
  try {
6594
- return existsSync3(globalPaths().codexDir);
6804
+ return existsSync4(globalPaths().codexDir);
6595
6805
  } catch {
6596
6806
  return false;
6597
6807
  }
@@ -6601,7 +6811,7 @@ function codexHooksStatus() {
6601
6811
  const registered = isCodexGuardInstalled();
6602
6812
  let trusted = false, disabled = false;
6603
6813
  try {
6604
- const toml = readFileSync4(p.codexConfigPath, "utf-8");
6814
+ const toml = readFileSync5(p.codexConfigPath, "utf-8");
6605
6815
  trusted = /trusted_hash\s*=/.test(toml);
6606
6816
  disabled = /^\s*hooks\s*=\s*false\s*$/m.test(toml);
6607
6817
  } catch {
@@ -6620,10 +6830,10 @@ function removeOpencodeGuard(p) {
6620
6830
  } catch {
6621
6831
  }
6622
6832
  }
6623
- function warmPolicyCache(hooksDir, agents) {
6833
+ function warmPolicyCache(hooksDir2, agents) {
6624
6834
  for (const agent of agents) {
6625
6835
  try {
6626
- const child = spawn(process.execPath, [join4(hooksDir, "guard.mjs"), agent, "--sg-refresh-policy"], {
6836
+ const child = spawn(process.execPath, [join5(hooksDir2, "guard.mjs"), agent, "--sg-refresh-policy"], {
6627
6837
  detached: true,
6628
6838
  stdio: "ignore",
6629
6839
  windowsHide: true
@@ -6637,23 +6847,23 @@ function warmPolicyCache(hooksDir, agents) {
6637
6847
  }
6638
6848
  function isOpencodeGuardInstalled() {
6639
6849
  try {
6640
- return readFileSync4(globalPaths().opencodePluginPath, "utf-8").includes("tool.execute.before");
6850
+ return readFileSync5(globalPaths().opencodePluginPath, "utf-8").includes("tool.execute.before");
6641
6851
  } catch {
6642
6852
  return false;
6643
6853
  }
6644
6854
  }
6645
6855
  function opencodeDetected() {
6646
6856
  try {
6647
- return existsSync3(globalPaths().opencodeDir);
6857
+ return existsSync4(globalPaths().opencodeDir);
6648
6858
  } catch {
6649
6859
  return false;
6650
6860
  }
6651
6861
  }
6652
- function sweepStrayScratchDirs(root = homedir2(), maxDepth = 6, budget = 4e4) {
6862
+ function sweepStrayScratchDirs(root = homedir3(), maxDepth = 6, budget = 4e4) {
6653
6863
  let removed = 0;
6654
6864
  let visited = 0;
6655
6865
  const skip = /* @__PURE__ */ new Set(["node_modules", ".git", "dist", ".next", "build"]);
6656
- const store = join4(homedir2(), ".solongate");
6866
+ const store = join5(homedir3(), ".solongate");
6657
6867
  const walk = (dir, depth) => {
6658
6868
  if (depth > maxDepth || visited++ > budget) return;
6659
6869
  let entries;
@@ -6664,11 +6874,11 @@ function sweepStrayScratchDirs(root = homedir2(), maxDepth = 6, budget = 4e4) {
6664
6874
  }
6665
6875
  for (const name of entries) {
6666
6876
  if (skip.has(name)) continue;
6667
- const full = join4(dir, name);
6877
+ const full = join5(dir, name);
6668
6878
  if (full === store) continue;
6669
6879
  let isDir = false;
6670
6880
  try {
6671
- isDir = statSync(full).isDirectory();
6881
+ isDir = statSync2(full).isDirectory();
6672
6882
  } catch {
6673
6883
  continue;
6674
6884
  }
@@ -6679,7 +6889,7 @@ function sweepStrayScratchDirs(root = homedir2(), maxDepth = 6, budget = 4e4) {
6679
6889
  for (const f of readdirSync(full)) {
6680
6890
  if (SCRATCH_FILES.has(f)) {
6681
6891
  try {
6682
- rmSync2(join4(full, f), { force: true });
6892
+ rmSync2(join5(full, f), { force: true });
6683
6893
  } catch {
6684
6894
  left.push(f);
6685
6895
  }
@@ -6719,12 +6929,12 @@ function runGlobalRestore() {
6719
6929
  removeOpencodeGuard(p);
6720
6930
  } catch {
6721
6931
  }
6722
- if (existsSync3(p.backupPath)) {
6723
- writeFileSync3(p.settingsPath, readFileSync4(p.backupPath, "utf-8"));
6932
+ if (existsSync4(p.backupPath)) {
6933
+ writeFileSync3(p.settingsPath, readFileSync5(p.backupPath, "utf-8"));
6724
6934
  console.log(` Restored ${p.settingsPath} from backup.`);
6725
- } else if (existsSync3(p.settingsPath)) {
6935
+ } else if (existsSync4(p.settingsPath)) {
6726
6936
  try {
6727
- const s = JSON.parse(readFileSync4(p.settingsPath, "utf-8"));
6937
+ const s = JSON.parse(readFileSync5(p.settingsPath, "utf-8"));
6728
6938
  delete s.hooks;
6729
6939
  writeFileSync3(p.settingsPath, JSON.stringify(s, null, 2) + "\n");
6730
6940
  console.log(` Removed SolonGate hooks from ${p.settingsPath}.`);
@@ -6737,12 +6947,17 @@ function runGlobalRestore() {
6737
6947
  }
6738
6948
  function repairQuiet() {
6739
6949
  const p = globalPaths();
6740
- const has = (f) => existsSync3(f);
6741
- const guardFile = join4(p.hooksDir, "guard.mjs");
6950
+ const has = (f) => existsSync4(f);
6951
+ const guardFile = join5(p.hooksDir, "guard.mjs");
6742
6952
  const line = (label, ok, yes, no) => ({ label, ok, detail: ok ? yes : no });
6953
+ const runtime = () => {
6954
+ const r2 = hookCanStart();
6955
+ return { label: "hook runtime", ok: r2.ok, detail: r2.ok ? `node ${r2.detail}` : r2.detail };
6956
+ };
6743
6957
  const before = [
6744
6958
  line("guard hook file", has(guardFile), "present", "MISSING"),
6745
6959
  line("cloud credential", has(p.configPath), "present", "MISSING"),
6960
+ runtime(),
6746
6961
  line("Claude hooks", isGuardInstalled(), "guard registered", "guard NOT registered"),
6747
6962
  line("Antigravity hooks", has(p.antigravityHooksPath), "guard registered", "guard NOT registered"),
6748
6963
  line("Codex hooks", isCodexGuardInstalled(), "guard registered", "guard NOT registered"),
@@ -6752,6 +6967,7 @@ function repairQuiet() {
6752
6967
  if (!r.ok) return { ok: false, message: r.message, before, after: [], notes: [] };
6753
6968
  const after = [
6754
6969
  { label: "guard hook file", ok: true, detail: `present (v${installedGuardVersion() ?? "?"})` },
6970
+ runtime(),
6755
6971
  line("Claude hooks", isGuardInstalled(), "guard registered", "NOT registered"),
6756
6972
  line("Antigravity hooks", has(p.antigravityHooksPath), "guard registered", "NOT registered"),
6757
6973
  line("Codex hooks", isCodexGuardInstalled(), "guard registered", "NOT registered"),
@@ -6812,7 +7028,7 @@ function installGlobalQuiet() {
6812
7028
  let apiKey = process.env["SOLONGATE_API_KEY"] || "";
6813
7029
  let apiUrl = process.env["SOLONGATE_API_URL"] || "https://api.solongate.com";
6814
7030
  try {
6815
- const cfg = JSON.parse(readFileSync4(p.configPath, "utf-8"));
7031
+ const cfg = JSON.parse(readFileSync5(p.configPath, "utf-8"));
6816
7032
  if (cfg && typeof cfg.apiKey === "string") apiKey = apiKey || cfg.apiKey;
6817
7033
  if (cfg && typeof cfg.apiUrl === "string") apiUrl = cfg.apiUrl;
6818
7034
  } catch {
@@ -6828,26 +7044,26 @@ function installGlobalQuiet() {
6828
7044
  mkdirSync3(p.hooksDir, { recursive: true });
6829
7045
  mkdirSync3(p.claudeDir, { recursive: true });
6830
7046
  unlockProtected();
6831
- writeFileSync3(join4(p.hooksDir, "guard.mjs"), readGuard());
7047
+ writeFileSync3(join5(p.hooksDir, "guard.mjs"), readGuard());
6832
7048
  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"));
7049
+ writeFileSync3(join5(p.hooksDir, "audit.mjs"), readHook("audit.mjs"));
7050
+ writeFileSync3(join5(p.hooksDir, "stop.mjs"), readHook("stop.mjs"));
7051
+ writeFileSync3(join5(p.hooksDir, "shield.mjs"), readHook("shield.mjs"));
7052
+ writeFileSync3(join5(p.hooksDir, "conversation.mjs"), readHook("conversation.mjs"));
7053
+ writeLauncher(p.hooksDir);
7054
+ writeLauncher(p.hooksDir);
6837
7055
  writeFileSync3(p.configPath, JSON.stringify({ apiKey, apiUrl }, null, 2) + "\n");
6838
7056
  let existing = {};
6839
- if (existsSync3(p.settingsPath)) {
6840
- const raw = readFileSync4(p.settingsPath, "utf-8");
6841
- if (!existsSync3(p.backupPath)) writeFileSync3(p.backupPath, raw);
7057
+ if (existsSync4(p.settingsPath)) {
7058
+ const raw = readFileSync5(p.settingsPath, "utf-8");
7059
+ if (!existsSync4(p.backupPath)) writeFileSync3(p.backupPath, raw);
6842
7060
  try {
6843
7061
  existing = JSON.parse(raw);
6844
7062
  } catch {
6845
7063
  existing = {};
6846
7064
  }
6847
7065
  }
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"`;
7066
+ const hookCmd = (script) => hookCommandFor(p.hooksDir, script);
6851
7067
  const merged = {
6852
7068
  ...existing,
6853
7069
  hooks: {
@@ -6874,7 +7090,7 @@ function installGlobalQuiet() {
6874
7090
  };
6875
7091
  writeFileSync3(p.settingsPath, JSON.stringify(merged, null, 2) + "\n");
6876
7092
  try {
6877
- installAntigravityGuard(p, join4(p.hooksDir, "guard.mjs").replace(/\\/g, "/"));
7093
+ installAntigravityGuard(p, join5(p.hooksDir, "guard.mjs").replace(/\\/g, "/"));
6878
7094
  } catch {
6879
7095
  }
6880
7096
  try {
@@ -6895,7 +7111,7 @@ function installGlobalQuiet() {
6895
7111
  function installedGuardVersion() {
6896
7112
  try {
6897
7113
  const p = globalPaths();
6898
- const s = readFileSync4(join4(p.hooksDir, "guard.mjs"), "utf-8");
7114
+ const s = readFileSync5(join5(p.hooksDir, "guard.mjs"), "utf-8");
6899
7115
  const m = s.match(/HOOK_VERSION\s*=\s*(\d+)/);
6900
7116
  return m ? parseInt(m[1], 10) : null;
6901
7117
  } catch {
@@ -6905,16 +7121,35 @@ function installedGuardVersion() {
6905
7121
  function guardHookOutdated() {
6906
7122
  try {
6907
7123
  const p = globalPaths();
6908
- return readFileSync4(join4(p.hooksDir, "guard.mjs"), "utf-8") !== readGuard();
7124
+ return readFileSync5(join5(p.hooksDir, "guard.mjs"), "utf-8") !== readGuard();
6909
7125
  } catch {
6910
7126
  return false;
6911
7127
  }
6912
7128
  }
7129
+ function hookCommandFor(hooksDir2, script, client = "claude-code", label = "Claude Code") {
7130
+ const target = join5(hooksDir2, script).replace(/\\/g, "/");
7131
+ if (process.platform === "win32") {
7132
+ return `& "${process.execPath.replace(/\\/g, "/")}" "${target}" ${client} "${label}"`;
7133
+ }
7134
+ const launcher = join5(hooksDir2, LAUNCHER_NAME).replace(/\\/g, "/");
7135
+ return `/bin/sh "${launcher}" "${target}" ${client} "${label}"`;
7136
+ }
7137
+ function writeLauncher(hooksDir2) {
7138
+ writeFileSync3(join5(hooksDir2, LAUNCHER_NAME), launcherScript(process.execPath));
7139
+ try {
7140
+ chmodSync(join5(hooksDir2, LAUNCHER_NAME), 493);
7141
+ } catch {
7142
+ }
7143
+ try {
7144
+ mkdirSync3(join5(hooksDir2, "..", BEAT_DIR), { recursive: true });
7145
+ } catch {
7146
+ }
7147
+ }
6913
7148
  function isGuardInstalled() {
6914
7149
  try {
6915
7150
  const p = globalPaths();
6916
- if (!existsSync3(p.settingsPath)) return false;
6917
- const s = JSON.parse(readFileSync4(p.settingsPath, "utf-8"));
7151
+ if (!existsSync4(p.settingsPath)) return false;
7152
+ const s = JSON.parse(readFileSync5(p.settingsPath, "utf-8"));
6918
7153
  return !!s.hooks && JSON.stringify(s.hooks).includes(".solongate");
6919
7154
  } catch {
6920
7155
  return false;
@@ -6937,8 +7172,8 @@ function uninstallGlobalQuiet() {
6937
7172
  removeOpencodeGuard(p);
6938
7173
  } catch {
6939
7174
  }
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"));
7175
+ if (!existsSync4(p.settingsPath)) return { ok: true, message: "guard removed (open a new session)" };
7176
+ const s = JSON.parse(readFileSync5(p.settingsPath, "utf-8"));
6942
7177
  delete s.hooks;
6943
7178
  writeFileSync3(p.settingsPath, JSON.stringify(s, null, 2) + "\n");
6944
7179
  return { ok: true, message: "guard removed (open a new session)" };
@@ -6952,7 +7187,7 @@ function escapeRe(s) {
6952
7187
  function resolveRealClaude() {
6953
7188
  try {
6954
7189
  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);
7190
+ const out2 = execFileSync3(finder, ["claude"], { encoding: "utf-8" }).split(/\r?\n/).map((s) => s.trim()).filter(Boolean);
6956
7191
  if (process.platform === "win32") {
6957
7192
  const low = (s) => s.toLowerCase();
6958
7193
  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 +7200,17 @@ function resolveRealClaude() {
6965
7200
  function shimTargets() {
6966
7201
  if (process.platform === "win32") {
6967
7202
  try {
6968
- const prof = execFileSync2("powershell", ["-NoProfile", "-Command", "$PROFILE.CurrentUserAllHosts"], { encoding: "utf-8" }).trim();
7203
+ const prof = execFileSync3("powershell", ["-NoProfile", "-Command", "$PROFILE.CurrentUserAllHosts"], { encoding: "utf-8" }).trim();
6969
7204
  return prof ? [prof] : [];
6970
7205
  } catch {
6971
7206
  return [];
6972
7207
  }
6973
7208
  }
6974
- return [".bashrc", ".zshrc", ".profile"].map((f) => join4(homedir2(), f)).filter((f) => existsSync3(f));
7209
+ return [".bashrc", ".zshrc", ".profile"].map((f) => join5(homedir3(), f)).filter((f) => existsSync4(f));
6975
7210
  }
6976
7211
  function writeShimBlock(file, block2) {
6977
7212
  const re = new RegExp(escapeRe(SHIM_BEGIN) + "[\\s\\S]*?" + escapeRe(SHIM_END) + "\\r?\\n?", "g");
6978
- let content = existsSync3(file) ? readFileSync4(file, "utf-8") : "";
7213
+ let content = existsSync4(file) ? readFileSync5(file, "utf-8") : "";
6979
7214
  content = content.replace(re, "");
6980
7215
  if (block2) {
6981
7216
  if (content.length && !content.endsWith("\n")) content += "\n";
@@ -7020,7 +7255,7 @@ async function runGlobalInstall(opts = {}) {
7020
7255
  let apiKey = opts.apiKey || process.env["SOLONGATE_API_KEY"] || "";
7021
7256
  if (!apiKey || apiKey === "sg_live_your_key_here") {
7022
7257
  try {
7023
- const cfg = JSON.parse(readFileSync4(p.configPath, "utf-8"));
7258
+ const cfg = JSON.parse(readFileSync5(p.configPath, "utf-8"));
7024
7259
  if (cfg && typeof cfg.apiKey === "string") apiKey = cfg.apiKey;
7025
7260
  } catch {
7026
7261
  }
@@ -7040,19 +7275,19 @@ async function runGlobalInstall(opts = {}) {
7040
7275
  mkdirSync3(p.hooksDir, { recursive: true });
7041
7276
  mkdirSync3(p.claudeDir, { recursive: true });
7042
7277
  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"));
7278
+ writeFileSync3(join5(p.hooksDir, "guard.mjs"), readGuard());
7279
+ writeFileSync3(join5(p.hooksDir, "audit.mjs"), readHook("audit.mjs"));
7280
+ writeFileSync3(join5(p.hooksDir, "stop.mjs"), readHook("stop.mjs"));
7281
+ writeFileSync3(join5(p.hooksDir, "shield.mjs"), readHook("shield.mjs"));
7282
+ writeFileSync3(join5(p.hooksDir, "conversation.mjs"), readHook("conversation.mjs"));
7048
7283
  console.log(` Installed hooks \u2192 ${p.hooksDir}`);
7049
- installClaudeShim(join4(p.hooksDir, "shield.mjs"));
7284
+ installClaudeShim(join5(p.hooksDir, "shield.mjs"));
7050
7285
  writeFileSync3(p.configPath, JSON.stringify({ apiKey, apiUrl }, null, 2) + "\n");
7051
7286
  console.log(` Wrote ${p.configPath}`);
7052
7287
  let existing = {};
7053
- if (existsSync3(p.settingsPath)) {
7054
- const raw = readFileSync4(p.settingsPath, "utf-8");
7055
- if (!existsSync3(p.backupPath)) {
7288
+ if (existsSync4(p.settingsPath)) {
7289
+ const raw = readFileSync5(p.settingsPath, "utf-8");
7290
+ if (!existsSync4(p.backupPath)) {
7056
7291
  writeFileSync3(p.backupPath, raw);
7057
7292
  console.log(` Backed up existing settings \u2192 ${p.backupPath}`);
7058
7293
  }
@@ -7062,22 +7297,17 @@ async function runGlobalInstall(opts = {}) {
7062
7297
  existing = {};
7063
7298
  }
7064
7299
  }
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"`;
7300
+ const guardAbs = join5(p.hooksDir, "guard.mjs").replace(/\\/g, "/");
7301
+ const hookCmd = (script) => hookCommandFor(p.hooksDir, script);
7072
7302
  const merged = {
7073
7303
  ...existing,
7074
7304
  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) }] }],
7305
+ PreToolUse: [{ matcher: "", hooks: [{ type: "command", command: hookCmd("guard.mjs") }] }],
7306
+ PostToolUse: [{ matcher: "", hooks: [{ type: "command", command: hookCmd("audit.mjs") }] }],
7307
+ UserPromptSubmit: [{ matcher: "", hooks: [{ type: "command", command: hookCmd("conversation.mjs") }] }],
7078
7308
  Stop: [
7079
- { matcher: "", hooks: [{ type: "command", command: hookCmd(stopAbs) }] },
7080
- { matcher: "", hooks: [{ type: "command", command: hookCmd(convAbs) }] }
7309
+ { matcher: "", hooks: [{ type: "command", command: hookCmd("stop.mjs") }] },
7310
+ { matcher: "", hooks: [{ type: "command", command: hookCmd("conversation.mjs") }] }
7081
7311
  ]
7082
7312
  }
7083
7313
  };
@@ -7122,6 +7352,10 @@ var __dirname, HOOKS_DIR, ANTIGRAVITY_GROUP, CODEX_EVENTS, CODEX_TIMEOUT_SEC, SC
7122
7352
  var init_global_install = __esm({
7123
7353
  "src/global-install.ts"() {
7124
7354
  "use strict";
7355
+ init_hook_launcher();
7356
+ init_hook_launcher();
7357
+ init_hook_health();
7358
+ init_hook_health();
7125
7359
  __dirname = dirname(fileURLToPath(import.meta.url));
7126
7360
  HOOKS_DIR = resolve3(__dirname, "..", "hooks");
7127
7361
  ANTIGRAVITY_GROUP = "solongate-guard";
@@ -7152,14 +7386,14 @@ __export(self_update_exports, {
7152
7386
  tuiUpdateFlow: () => tuiUpdateFlow,
7153
7387
  updateNow: () => updateNow
7154
7388
  });
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";
7389
+ import { execFile, execFileSync as execFileSync4, spawn as spawn2 } from "child_process";
7390
+ import { access, mkdirSync as mkdirSync4, openSync, readFileSync as readFileSync6, writeFileSync as writeFileSync4, constants as FS } from "fs";
7391
+ import { homedir as homedir4 } from "os";
7392
+ import { dirname as dirname2, join as join6, sep } from "path";
7159
7393
  import { fileURLToPath as fileURLToPath2 } from "url";
7160
7394
  function lockHeldAt() {
7161
7395
  try {
7162
- const ts = Number(readFileSync5(LOCK_FILE, "utf-8").trim().split(/\s+/)[1] ?? 0);
7396
+ const ts = Number(readFileSync6(LOCK_FILE, "utf-8").trim().split(/\s+/)[1] ?? 0);
7163
7397
  if (!Number.isFinite(ts) || Date.now() - ts >= LOCK_STALE_MS) return null;
7164
7398
  return ts;
7165
7399
  } catch {
@@ -7168,7 +7402,7 @@ function lockHeldAt() {
7168
7402
  }
7169
7403
  function takeInstallLock() {
7170
7404
  try {
7171
- mkdirSync4(join5(homedir3(), ".solongate"), { recursive: true });
7405
+ mkdirSync4(join6(homedir4(), ".solongate"), { recursive: true });
7172
7406
  writeFileSync4(LOCK_FILE, `${process.pid} ${Date.now()}
7173
7407
  `);
7174
7408
  } catch {
@@ -7183,7 +7417,7 @@ function releaseInstallLock() {
7183
7417
  }
7184
7418
  function readState() {
7185
7419
  try {
7186
- const s = JSON.parse(readFileSync5(STATE_FILE, "utf-8"));
7420
+ const s = JSON.parse(readFileSync6(STATE_FILE, "utf-8"));
7187
7421
  return s && typeof s === "object" ? s : {};
7188
7422
  } catch {
7189
7423
  return {};
@@ -7191,7 +7425,7 @@ function readState() {
7191
7425
  }
7192
7426
  function writeState(s) {
7193
7427
  try {
7194
- mkdirSync4(join5(homedir3(), ".solongate"), { recursive: true });
7428
+ mkdirSync4(join6(homedir4(), ".solongate"), { recursive: true });
7195
7429
  writeFileSync4(STATE_FILE, JSON.stringify(s));
7196
7430
  } catch {
7197
7431
  }
@@ -7212,7 +7446,7 @@ function setAutoUpdate(on) {
7212
7446
  }
7213
7447
  function currentVersion() {
7214
7448
  try {
7215
- const pkg = JSON.parse(readFileSync5(join5(dirname2(fileURLToPath2(import.meta.url)), "..", "package.json"), "utf-8"));
7449
+ const pkg = JSON.parse(readFileSync6(join6(dirname2(fileURLToPath2(import.meta.url)), "..", "package.json"), "utf-8"));
7216
7450
  return pkg.version ?? "0.0.0";
7217
7451
  } catch {
7218
7452
  return "0.0.0";
@@ -7249,7 +7483,7 @@ async function fetchLatest() {
7249
7483
  function spawnGlobalInstall(version) {
7250
7484
  if (lockHeldAt() !== null) return false;
7251
7485
  try {
7252
- mkdirSync4(join5(homedir3(), ".solongate"), { recursive: true });
7486
+ mkdirSync4(join6(homedir4(), ".solongate"), { recursive: true });
7253
7487
  takeInstallLock();
7254
7488
  const log3 = openSync(LOG_FILE, "a");
7255
7489
  const p = spawn2("npm", ["install", "-g", `${PKG}@${version}`], {
@@ -7320,7 +7554,7 @@ async function runUpdateCommand() {
7320
7554
  }
7321
7555
  try {
7322
7556
  if (newerThan(latest, cur)) {
7323
- execFileSync3("solongate", ["repair"], {
7557
+ execFileSync4("solongate", ["repair"], {
7324
7558
  env: { ...process.env, SOLONGATE_INTERNAL: "1" },
7325
7559
  stdio: "inherit",
7326
7560
  shell: process.platform === "win32"
@@ -7337,7 +7571,7 @@ async function runUpdateCommand() {
7337
7571
  function runGlobalInstall2(version) {
7338
7572
  return new Promise((resolve8) => {
7339
7573
  try {
7340
- mkdirSync4(join5(homedir3(), ".solongate"), { recursive: true });
7574
+ mkdirSync4(join6(homedir4(), ".solongate"), { recursive: true });
7341
7575
  execFile(
7342
7576
  "npm",
7343
7577
  ["install", "-g", `${PKG}@${version}`],
@@ -7530,9 +7764,9 @@ var init_self_update = __esm({
7530
7764
  PKG = "@solongate/proxy";
7531
7765
  CHECK_EVERY_MS = 30 * 60 * 1e3;
7532
7766
  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");
7767
+ STATE_FILE = join6(homedir4(), ".solongate", ".self-update.json");
7768
+ LOG_FILE = join6(homedir4(), ".solongate", "self-update.log");
7769
+ LOCK_FILE = join6(homedir4(), ".solongate", ".update-install.lock");
7536
7770
  LOCK_STALE_MS = 3 * 6e4;
7537
7771
  LOCK_WAIT_MS = 9e4;
7538
7772
  sleep = (ms) => new Promise((r) => setTimeout(r, ms));
@@ -7552,13 +7786,13 @@ __export(logs_server_daemon_exports, {
7552
7786
  stopLogsServerDaemon: () => stopLogsServerDaemon
7553
7787
  });
7554
7788
  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";
7789
+ import { mkdirSync as mkdirSync5, openSync as openSync2, readFileSync as readFileSync7, writeFileSync as writeFileSync5 } from "fs";
7790
+ import { homedir as homedir5 } from "os";
7791
+ import { dirname as dirname3, join as join7 } from "path";
7558
7792
  import { fileURLToPath as fileURLToPath3 } from "url";
7559
7793
  function readState2() {
7560
7794
  try {
7561
- const s = JSON.parse(readFileSync6(STATE_FILE2, "utf-8"));
7795
+ const s = JSON.parse(readFileSync7(STATE_FILE2, "utf-8"));
7562
7796
  return s && typeof s === "object" ? s : {};
7563
7797
  } catch {
7564
7798
  return {};
@@ -7597,7 +7831,7 @@ function startLogsServerDaemon() {
7597
7831
  try {
7598
7832
  mkdirSync5(DIR, { recursive: true });
7599
7833
  const log3 = openSync2(LOG_FILE2, "a");
7600
- const cli = join6(dirname3(fileURLToPath3(import.meta.url)), "index.js");
7834
+ const cli = join7(dirname3(fileURLToPath3(import.meta.url)), "index.js");
7601
7835
  const p = spawn3(process.execPath, [cli, "logs-server"], {
7602
7836
  detached: true,
7603
7837
  stdio: ["ignore", log3, log3],
@@ -7637,22 +7871,22 @@ var DIR, STATE_FILE2, LOG_FILE2, LOGS_SERVER_PORT;
7637
7871
  var init_logs_server_daemon = __esm({
7638
7872
  "src/logs-server-daemon.ts"() {
7639
7873
  "use strict";
7640
- DIR = join6(homedir4(), ".solongate");
7641
- STATE_FILE2 = join6(DIR, ".logs-server.json");
7642
- LOG_FILE2 = join6(DIR, "logs-server.log");
7874
+ DIR = join7(homedir5(), ".solongate");
7875
+ STATE_FILE2 = join7(DIR, ".logs-server.json");
7876
+ LOG_FILE2 = join7(DIR, "logs-server.log");
7643
7877
  LOGS_SERVER_PORT = 8788;
7644
7878
  }
7645
7879
  });
7646
7880
 
7647
7881
  // 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";
7882
+ import { readFileSync as readFileSync8 } from "fs";
7883
+ import { homedir as homedir6 } from "os";
7884
+ import { join as join8 } from "path";
7651
7885
  function loadConfig() {
7652
7886
  if (cached) return cached;
7653
7887
  const defaults = { notifications: true };
7654
7888
  try {
7655
- const raw = readFileSync7(join7(homedir5(), ".solongate", "tui-config.json"), "utf-8");
7889
+ const raw = readFileSync8(join8(homedir6(), ".solongate", "tui-config.json"), "utf-8");
7656
7890
  const j = JSON.parse(raw);
7657
7891
  cached = {
7658
7892
  notifications: j.notifications !== false,
@@ -7823,16 +8057,16 @@ var init_components = __esm({
7823
8057
  });
7824
8058
 
7825
8059
  // 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";
8060
+ import { closeSync, existsSync as existsSync5, openSync as openSync3, readdirSync as readdirSync2, readFileSync as readFileSync9, readSync, statSync as statSync3, writeFileSync as writeFileSync6 } from "fs";
8061
+ import { homedir as homedir7 } from "os";
7828
8062
  import { createHash as createHash2 } from "crypto";
7829
- import { isAbsolute, join as join8 } from "path";
8063
+ import { isAbsolute, join as join9 } from "path";
7830
8064
  function localLogsSetting() {
7831
8065
  const off = { enabled: false, configuredPath: null, usableHere: true, file: DEFAULT_LOCAL_LOG };
7832
8066
  try {
7833
8067
  for (const cache of policyCachesNewestFirst()) {
7834
8068
  try {
7835
- const c2 = JSON.parse(readFileSync8(cache, "utf-8"));
8069
+ const c2 = JSON.parse(readFileSync9(cache, "utf-8"));
7836
8070
  const l = c2?.security?.localLogs;
7837
8071
  if (!l || typeof l.enabled !== "boolean") continue;
7838
8072
  if (!l.enabled) return { ...off, configuredPath: typeof l.path === "string" ? l.path.trim() || null : null };
@@ -7840,8 +8074,8 @@ function localLogsSetting() {
7840
8074
  const dir = raw.replace(/[\\/]+$/, "");
7841
8075
  if (!dir) return { enabled: true, configuredPath: null, usableHere: true, file: DEFAULT_LOCAL_LOG };
7842
8076
  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);
8077
+ const file = join9(dir, "solongate-audit.jsonl");
8078
+ const usable = existsSync5(file) || existsSync5(dir);
7845
8079
  return { enabled: true, configuredPath: raw, usableHere: usable, file: usable ? file : DEFAULT_LOCAL_LOG };
7846
8080
  } catch {
7847
8081
  }
@@ -7851,12 +8085,12 @@ function localLogsSetting() {
7851
8085
  return off;
7852
8086
  }
7853
8087
  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);
8088
+ const sgDir2 = join9(homedir7(), ".solongate");
8089
+ return readdirSync2(sgDir2).filter((f) => f.startsWith(".policy-cache-") && f.endsWith(".json")).map((f) => {
8090
+ const p = join9(sgDir2, f);
7857
8091
  let mtime = 0;
7858
8092
  try {
7859
- mtime = statSync2(p).mtimeMs;
8093
+ mtime = statSync3(p).mtimeMs;
7860
8094
  } catch {
7861
8095
  }
7862
8096
  return { p, mtime };
@@ -7864,27 +8098,27 @@ function policyCachesNewestFirst() {
7864
8098
  }
7865
8099
  function localLogFile() {
7866
8100
  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);
8101
+ const sgDir2 = join9(homedir7(), ".solongate");
8102
+ const caches = readdirSync2(sgDir2).filter((f) => f.startsWith(".policy-cache-") && f.endsWith(".json")).map((f) => {
8103
+ const p = join9(sgDir2, f);
7870
8104
  let mtime = 0;
7871
8105
  try {
7872
- mtime = statSync2(p).mtimeMs;
8106
+ mtime = statSync3(p).mtimeMs;
7873
8107
  } catch {
7874
8108
  }
7875
8109
  return { p, mtime };
7876
8110
  }).sort((a, b) => b.mtime - a.mtime);
7877
8111
  for (const { p } of caches) {
7878
8112
  try {
7879
- const c2 = JSON.parse(readFileSync8(p, "utf-8"));
8113
+ const c2 = JSON.parse(readFileSync9(p, "utf-8"));
7880
8114
  const l = c2?.security?.localLogs;
7881
8115
  if (!l || !l.enabled || typeof l.path !== "string" || !l.path.trim()) continue;
7882
8116
  const dir = l.path.trim().replace(/[\\/]+$/, "");
7883
8117
  if (!dir) continue;
7884
8118
  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;
8119
+ const file = join9(dir, "solongate-audit.jsonl");
8120
+ if (existsSync5(file)) return file;
8121
+ return existsSync5(dir) ? file : DEFAULT_LOCAL_LOG;
7888
8122
  } catch {
7889
8123
  }
7890
8124
  }
@@ -7894,11 +8128,11 @@ function localLogFile() {
7894
8128
  }
7895
8129
  function ensureLocalLogOwner(activeApiKey) {
7896
8130
  try {
7897
- const marker = join8(homedir6(), ".solongate", "local-logs", ".owner");
8131
+ const marker = join9(homedir7(), ".solongate", "local-logs", ".owner");
7898
8132
  const want = activeApiKey ? createHash2("sha256").update(activeApiKey).digest("hex").slice(0, 16) : "";
7899
8133
  let have = "";
7900
8134
  try {
7901
- have = readFileSync8(marker, "utf-8").trim();
8135
+ have = readFileSync9(marker, "utf-8").trim();
7902
8136
  } catch {
7903
8137
  }
7904
8138
  if (have === want) return false;
@@ -7913,7 +8147,7 @@ function ensureLocalLogOwner(activeApiKey) {
7913
8147
  }
7914
8148
  function tailLines(file, maxBytes = 131072) {
7915
8149
  try {
7916
- const size = statSync2(file).size;
8150
+ const size = statSync3(file).size;
7917
8151
  const start = Math.max(0, size - maxBytes);
7918
8152
  const fd = openSync3(file, "r");
7919
8153
  const buf = Buffer.alloc(size - start);
@@ -7929,7 +8163,7 @@ function tailLines(file, maxBytes = 131072) {
7929
8163
  function clearLocalLog() {
7930
8164
  try {
7931
8165
  const file = localLogFile();
7932
- const n = readFileSync8(file, "utf-8").split("\n").filter(Boolean).length;
8166
+ const n = readFileSync9(file, "utf-8").split("\n").filter(Boolean).length;
7933
8167
  writeFileSync6(file, "");
7934
8168
  return n;
7935
8169
  } catch {
@@ -7947,8 +8181,8 @@ function reasonSignals(reason) {
7947
8181
  }
7948
8182
  function ownMark() {
7949
8183
  try {
7950
- const p = join8(homedir6(), ".solongate", "cloud-guard.json");
7951
- const c2 = JSON.parse(readFileSync8(p, "utf-8"));
8184
+ const p = join9(homedir7(), ".solongate", "cloud-guard.json");
8185
+ const c2 = JSON.parse(readFileSync9(p, "utf-8"));
7952
8186
  return c2?.apiKey ? createHash2("sha256").update(c2.apiKey).digest("hex").slice(0, 16) : "";
7953
8187
  } catch {
7954
8188
  return "";
@@ -7972,7 +8206,7 @@ var DEFAULT_LOCAL_LOG, LOCAL_LOG, DLP_REASON, RL_REASON;
7972
8206
  var init_local_log = __esm({
7973
8207
  "src/tui/local-log.ts"() {
7974
8208
  "use strict";
7975
- DEFAULT_LOCAL_LOG = join8(homedir6(), ".solongate", "local-logs", "solongate-audit.jsonl");
8209
+ DEFAULT_LOCAL_LOG = join9(homedir7(), ".solongate", "local-logs", "solongate-audit.jsonl");
7976
8210
  LOCAL_LOG = localLogFile();
7977
8211
  DLP_REASON = /security layer \(dlp\)/i;
7978
8212
  RL_REASON = /security layer \(rate limit\)|rate[- ]?limit(?:ed)?\b.*exceed|exceeded \d+ calls/i;
@@ -7980,13 +8214,13 @@ var init_local_log = __esm({
7980
8214
  });
7981
8215
 
7982
8216
  // src/api-client/client.ts
7983
- import { readFileSync as readFileSync9, writeFileSync as writeFileSync7, mkdirSync as mkdirSync6, existsSync as existsSync5 } from "fs";
7984
- import { resolve as resolve4, join as join9 } from "path";
7985
- import { homedir as homedir7 } from "os";
8217
+ import { readFileSync as readFileSync10, writeFileSync as writeFileSync7, mkdirSync as mkdirSync6, existsSync as existsSync6 } from "fs";
8218
+ import { resolve as resolve4, join as join10 } from "path";
8219
+ import { homedir as homedir8 } from "os";
7986
8220
  function listAccounts() {
7987
8221
  let list5 = [];
7988
8222
  try {
7989
- const raw = JSON.parse(readFileSync9(accountsFile(), "utf-8"));
8223
+ const raw = JSON.parse(readFileSync10(accountsFile(), "utf-8"));
7990
8224
  if (Array.isArray(raw)) list5 = raw.filter((a) => a && typeof a.apiKey === "string");
7991
8225
  } catch {
7992
8226
  }
@@ -8000,7 +8234,7 @@ function saveAccount(acc) {
8000
8234
  try {
8001
8235
  const list5 = (() => {
8002
8236
  try {
8003
- const raw = JSON.parse(readFileSync9(accountsFile(), "utf-8"));
8237
+ const raw = JSON.parse(readFileSync10(accountsFile(), "utf-8"));
8004
8238
  return Array.isArray(raw) ? raw.filter((a) => a && a.apiKey) : [];
8005
8239
  } catch {
8006
8240
  return [];
@@ -8008,7 +8242,7 @@ function saveAccount(acc) {
8008
8242
  })();
8009
8243
  const next = list5.filter((a) => a.apiKey !== acc.apiKey);
8010
8244
  next.unshift({ ...acc, addedAt: acc.addedAt ?? Date.now() });
8011
- mkdirSync6(join9(homedir7(), ".solongate"), { recursive: true });
8245
+ mkdirSync6(join10(homedir8(), ".solongate"), { recursive: true });
8012
8246
  writeFileSync7(accountsFile(), JSON.stringify(next, null, 2));
8013
8247
  } catch {
8014
8248
  }
@@ -8017,7 +8251,7 @@ function removeAccount(apiKey) {
8017
8251
  try {
8018
8252
  const list5 = (() => {
8019
8253
  try {
8020
- const raw = JSON.parse(readFileSync9(accountsFile(), "utf-8"));
8254
+ const raw = JSON.parse(readFileSync10(accountsFile(), "utf-8"));
8021
8255
  return Array.isArray(raw) ? raw.filter((a) => a && a.apiKey) : [];
8022
8256
  } catch {
8023
8257
  return [];
@@ -8039,12 +8273,12 @@ function isActiveAccount(apiKey) {
8039
8273
  }
8040
8274
  function setActiveAccount(creds) {
8041
8275
  try {
8042
- const dir = join9(homedir7(), ".solongate");
8276
+ const dir = join10(homedir8(), ".solongate");
8043
8277
  mkdirSync6(dir, { recursive: true });
8044
- const p = join9(dir, ["cloud", "guard.json"].join("-"));
8278
+ const p = join10(dir, ["cloud", "guard.json"].join("-"));
8045
8279
  let existing = {};
8046
8280
  try {
8047
- existing = JSON.parse(readFileSync9(p, "utf-8"));
8281
+ existing = JSON.parse(readFileSync10(p, "utf-8"));
8048
8282
  } catch {
8049
8283
  }
8050
8284
  if (!writeProtectedFile(p, JSON.stringify({ ...existing, apiKey: creds.apiKey, apiUrl: creds.apiUrl }, null, 2))) return false;
@@ -8056,14 +8290,14 @@ function setActiveAccount(creds) {
8056
8290
  }
8057
8291
  function clearActiveCredential() {
8058
8292
  try {
8059
- const p = join9(homedir7(), ".solongate", ["cloud", "guard.json"].join("-"));
8060
- if (!existsSync5(p)) {
8293
+ const p = join10(homedir8(), ".solongate", ["cloud", "guard.json"].join("-"));
8294
+ if (!existsSync6(p)) {
8061
8295
  cached2 = null;
8062
8296
  return true;
8063
8297
  }
8064
8298
  let existing = {};
8065
8299
  try {
8066
- existing = JSON.parse(readFileSync9(p, "utf-8"));
8300
+ existing = JSON.parse(readFileSync10(p, "utf-8"));
8067
8301
  } catch {
8068
8302
  }
8069
8303
  delete existing.apiKey;
@@ -8078,9 +8312,9 @@ function clearActiveCredential() {
8078
8312
  }
8079
8313
  function loginCredentialFile() {
8080
8314
  try {
8081
- const p = join9(homedir7(), ".solongate", "cloud-guard.json");
8082
- if (!existsSync5(p)) return {};
8083
- const c2 = JSON.parse(readFileSync9(p, "utf-8"));
8315
+ const p = join10(homedir8(), ".solongate", "cloud-guard.json");
8316
+ if (!existsSync6(p)) return {};
8317
+ const c2 = JSON.parse(readFileSync10(p, "utf-8"));
8084
8318
  return c2 && typeof c2 === "object" ? c2 : {};
8085
8319
  } catch {
8086
8320
  return {};
@@ -8089,8 +8323,8 @@ function loginCredentialFile() {
8089
8323
  function dotenvApiKey() {
8090
8324
  try {
8091
8325
  const envPath = resolve4(".env");
8092
- if (!existsSync5(envPath)) return void 0;
8093
- for (const line of readFileSync9(envPath, "utf-8").split("\n")) {
8326
+ if (!existsSync6(envPath)) return void 0;
8327
+ for (const line of readFileSync10(envPath, "utf-8").split("\n")) {
8094
8328
  const trimmed = line.trim();
8095
8329
  if (!trimmed || trimmed.startsWith("#")) continue;
8096
8330
  const eq = trimmed.indexOf("=");
@@ -8194,7 +8428,7 @@ var init_client = __esm({
8194
8428
  "use strict";
8195
8429
  init_global_install();
8196
8430
  DEFAULT_API_URL2 = "https://api.solongate.com";
8197
- accountsFile = () => join9(homedir7(), ".solongate", "accounts.json");
8431
+ accountsFile = () => join10(homedir8(), ".solongate", "accounts.json");
8198
8432
  viewOverride = null;
8199
8433
  ApiError = class extends Error {
8200
8434
  status;
@@ -8678,8 +8912,8 @@ var init_hooks = __esm({
8678
8912
  import { Box as Box2, Text as Text2, useInput } from "ink";
8679
8913
  import TextInput from "ink-text-input";
8680
8914
  import { mkdirSync as mkdirSync7, writeFileSync as writeFileSync8 } from "fs";
8681
- import { homedir as homedir8 } from "os";
8682
- import { join as join10, resolve as resolve5 } from "path";
8915
+ import { homedir as homedir9 } from "os";
8916
+ import { join as join11, resolve as resolve5 } from "path";
8683
8917
  import { useCallback as useCallback2, useEffect as useEffect2, useRef as useRef2, useState as useState2 } from "react";
8684
8918
  import { Fragment as Fragment2, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
8685
8919
  function extractTarget(detail) {
@@ -9236,9 +9470,9 @@ function LivePanel({ active: active2 }) {
9236
9470
  else if (input === "x") toggleSignal("dlp");
9237
9471
  else if (input === "r") toggleSignal("ratelimit");
9238
9472
  else if (input === "e") {
9239
- const file = join10(homedir8(), ".solongate", "live-export.jsonl");
9473
+ const file = join11(homedir9(), ".solongate", "live-export.jsonl");
9240
9474
  try {
9241
- mkdirSync7(join10(homedir8(), ".solongate"), { recursive: true });
9475
+ mkdirSync7(join11(homedir9(), ".solongate"), { recursive: true });
9242
9476
  writeFileSync8(file, visibleDesc.map((x) => JSON.stringify(x)).join("\n") + "\n");
9243
9477
  setActionMsg({ text: `\u2713 exported ${visibleDesc.length} lines \u2192 ${file}`, level: "ok", until: Date.now() + 6e3 });
9244
9478
  } catch (err2) {
@@ -9676,7 +9910,7 @@ var init_Live = __esm({
9676
9910
  }
9677
9911
  return h.toString(16);
9678
9912
  };
9679
- RING = join10(homedir8(), ".solongate", "projects", projectKey(resolve5(process.cwd())), ".eval-ring.jsonl");
9913
+ RING = join11(homedir9(), ".solongate", "projects", projectKey(resolve5(process.cwd())), ".eval-ring.jsonl");
9680
9914
  fmtUp = (ms) => {
9681
9915
  const s = Math.floor(ms / 1e3);
9682
9916
  const p = (n) => String(n).padStart(2, "0");
@@ -10962,8 +11196,8 @@ var init_Dlp = __esm({
10962
11196
  import { Box as Box7, Text as Text7, useInput as useInput6 } from "ink";
10963
11197
  import TextInput5 from "ink-text-input";
10964
11198
  import { mkdirSync as mkdirSync8, writeFileSync as writeFileSync9 } from "fs";
10965
- import { homedir as homedir9 } from "os";
10966
- import { join as join11 } from "path";
11199
+ import { homedir as homedir10 } from "os";
11200
+ import { join as join12 } from "path";
10967
11201
  import { useState as useState7 } from "react";
10968
11202
  import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
10969
11203
  function loadLocalRows() {
@@ -11089,8 +11323,8 @@ function AuditPanel({ active: active2, focused }) {
11089
11323
  const doExport = (kind) => {
11090
11324
  setMsg({ text: "exporting\u2026", level: "ok" });
11091
11325
  const run12 = async () => {
11092
- const dir = join11(homedir9(), ".solongate");
11093
- const file = join11(dir, `audit-export-${source}.jsonl`);
11326
+ const dir = join12(homedir10(), ".solongate");
11327
+ const file = join12(dir, `audit-export-${source}.jsonl`);
11094
11328
  let rows2;
11095
11329
  if (kind === "page") rows2 = pageRows;
11096
11330
  else if (source === "cloud") {
@@ -11674,9 +11908,9 @@ var init_args = __esm({
11674
11908
  });
11675
11909
 
11676
11910
  // src/commands/doctor.ts
11677
- import { existsSync as existsSync6, readFileSync as readFileSync10, statSync as statSync3 } from "fs";
11678
- import { homedir as homedir10 } from "os";
11679
- import { join as join12 } from "path";
11911
+ import { existsSync as existsSync7, readFileSync as readFileSync11, statSync as statSync4 } from "fs";
11912
+ import { homedir as homedir11 } from "os";
11913
+ import { join as join13 } from "path";
11680
11914
  async function collectChecks() {
11681
11915
  const checks = [];
11682
11916
  if (!isAuthenticated()) {
@@ -11724,8 +11958,32 @@ async function collectChecks() {
11724
11958
  ok: claudeReg,
11725
11959
  detail: claudeReg ? "guard registered" : "guard NOT registered - run `solongate repair`"
11726
11960
  });
11727
- if (existsSync6(globalPaths().antigravityDir)) {
11728
- const reg = existsSync6(globalPaths().antigravityHooksPath);
11961
+ if (claudeReg) {
11962
+ const start = hookCanStart();
11963
+ checks.push({
11964
+ name: "hook runtime",
11965
+ ok: start.ok,
11966
+ detail: start.ok ? `node ${start.detail}` : `${start.detail} - nothing is being enforced or logged`
11967
+ });
11968
+ const beat = guardBeat();
11969
+ if (!beat) {
11970
+ checks.push({
11971
+ name: "guard fired",
11972
+ ok: "warn",
11973
+ detail: "never - open your agent and run one tool call, then check again"
11974
+ });
11975
+ } else if (beat.node === "no-node") {
11976
+ checks.push({
11977
+ name: "guard fired",
11978
+ ok: false,
11979
+ detail: `${agoLabel(beat.at)}, but found no node to run with - run \`solongate repair\``
11980
+ });
11981
+ } else {
11982
+ checks.push({ name: "guard fired", ok: true, detail: `${agoLabel(beat.at)} \xB7 ${beat.node}` });
11983
+ }
11984
+ }
11985
+ if (existsSync7(globalPaths().antigravityDir)) {
11986
+ const reg = existsSync7(globalPaths().antigravityHooksPath);
11729
11987
  checks.push({
11730
11988
  name: "Antigravity hooks",
11731
11989
  ok: reg,
@@ -11753,7 +12011,7 @@ async function collectChecks() {
11753
12011
  });
11754
12012
  }
11755
12013
  try {
11756
- const raw = readFileSync10(join12(homedir10(), ".solongate", ".key-rejected.json"), "utf-8");
12014
+ const raw = readFileSync11(join13(homedir11(), ".solongate", ".key-rejected.json"), "utf-8");
11757
12015
  const m = JSON.parse(raw);
11758
12016
  const ageMin = m.ts ? Math.round((Date.now() - m.ts) / 6e4) : null;
11759
12017
  checks.push({
@@ -11764,8 +12022,8 @@ async function collectChecks() {
11764
12022
  } catch {
11765
12023
  }
11766
12024
  const LOCAL_LOG2 = localLogFile();
11767
- if (existsSync6(LOCAL_LOG2)) {
11768
- const st = statSync3(LOCAL_LOG2);
12025
+ if (existsSync7(LOCAL_LOG2)) {
12026
+ const st = statSync4(LOCAL_LOG2);
11769
12027
  const ageMin = (Date.now() - st.mtimeMs) / 6e4;
11770
12028
  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"}` });
11771
12029
  } else {
@@ -11798,6 +12056,7 @@ var init_doctor = __esm({
11798
12056
  "use strict";
11799
12057
  init_api_client();
11800
12058
  init_global_install();
12059
+ init_hook_health();
11801
12060
  init_local_log();
11802
12061
  init_format();
11803
12062
  init_args();
@@ -12905,8 +13164,8 @@ __export(tui_exports, {
12905
13164
  launchTui: () => launchTui
12906
13165
  });
12907
13166
  import { appendFileSync as appendFileSync2, mkdirSync as mkdirSync9 } from "fs";
12908
- import { homedir as homedir11 } from "os";
12909
- import { join as join13 } from "path";
13167
+ import { homedir as homedir12 } from "os";
13168
+ import { join as join14 } from "path";
12910
13169
  import { render } from "ink";
12911
13170
  import { jsx as jsx10 } from "react/jsx-runtime";
12912
13171
  async function launchTui() {
@@ -12917,11 +13176,11 @@ async function launchTui() {
12917
13176
  return;
12918
13177
  }
12919
13178
  process.stdout.write("\x1B[?1049h\x1B[H");
12920
- const debugLog = join13(homedir11(), ".solongate", "dataroom-debug.log");
13179
+ const debugLog = join14(homedir12(), ".solongate", "dataroom-debug.log");
12921
13180
  const saved = { log: console.log, warn: console.warn, error: console.error, info: console.info, debug: console.debug };
12922
13181
  const toFile = (level) => (...args) => {
12923
13182
  try {
12924
- mkdirSync9(join13(homedir11(), ".solongate"), { recursive: true });
13183
+ mkdirSync9(join14(homedir12(), ".solongate"), { recursive: true });
12925
13184
  appendFileSync2(debugLog, `${(/* @__PURE__ */ new Date()).toISOString()} [${level}] ${args.map((a) => typeof a === "string" ? a : JSON.stringify(a)).join(" ")}
12926
13185
  `);
12927
13186
  } catch {
@@ -12948,7 +13207,7 @@ var init_tui = __esm({
12948
13207
  });
12949
13208
 
12950
13209
  // src/commands/policy.ts
12951
- import { readFileSync as readFileSync11 } from "fs";
13210
+ import { readFileSync as readFileSync12 } from "fs";
12952
13211
  async function run2(argv) {
12953
13212
  const { positionals, flags } = parse(argv);
12954
13213
  const sub = positionals[0];
@@ -13157,7 +13416,7 @@ function printRules(rules) {
13157
13416
  }
13158
13417
  async function resolveRules(target) {
13159
13418
  if (target.endsWith(".json")) {
13160
- const parsed = JSON.parse(readFileSync11(target, "utf-8"));
13419
+ const parsed = JSON.parse(readFileSync12(target, "utf-8"));
13161
13420
  return parsed.rules ?? [];
13162
13421
  }
13163
13422
  const p = await api.policies.get(target);
@@ -13656,11 +13915,11 @@ var init_agents2 = __esm({
13656
13915
  });
13657
13916
 
13658
13917
  // src/commands/trace.ts
13659
- import { readdirSync as readdirSync3, readFileSync as readFileSync12 } from "fs";
13660
- import { homedir as homedir12 } from "os";
13661
- import { join as join14, resolve as resolve6 } from "path";
13918
+ import { readdirSync as readdirSync3, readFileSync as readFileSync13 } from "fs";
13919
+ import { homedir as homedir13 } from "os";
13920
+ import { join as join15, resolve as resolve6 } from "path";
13662
13921
  function readAllRings() {
13663
- const root = join14(homedir12(), ".solongate", "projects");
13922
+ const root = join15(homedir13(), ".solongate", "projects");
13664
13923
  let dirs;
13665
13924
  try {
13666
13925
  dirs = readdirSync3(root);
@@ -13671,7 +13930,7 @@ function readAllRings() {
13671
13930
  for (const d of dirs) {
13672
13931
  let text;
13673
13932
  try {
13674
- text = readFileSync12(join14(root, d, ".eval-ring.jsonl"), "utf-8");
13933
+ text = readFileSync13(join15(root, d, ".eval-ring.jsonl"), "utf-8");
13675
13934
  } catch {
13676
13935
  continue;
13677
13936
  }
@@ -13764,10 +14023,10 @@ var init_trace = __esm({
13764
14023
  });
13765
14024
 
13766
14025
  // src/commands/watch.ts
13767
- import { closeSync as closeSync2, existsSync as existsSync7, openSync as openSync4, readSync as readSync2, statSync as statSync4 } from "fs";
14026
+ import { closeSync as closeSync2, existsSync as existsSync8, openSync as openSync4, readSync as readSync2, statSync as statSync5 } from "fs";
13768
14027
  function tailLocal(file, maxBytes = 131072) {
13769
14028
  try {
13770
- const size = statSync4(file).size;
14029
+ const size = statSync5(file).size;
13771
14030
  const start = Math.max(0, size - maxBytes);
13772
14031
  const fd = openSync4(file, "r");
13773
14032
  const buf = Buffer.alloc(size - start);
@@ -13809,7 +14068,7 @@ async function run9(argv) {
13809
14068
  };
13810
14069
  const pollLocal = () => {
13811
14070
  const LOCAL_LOG2 = localLogFile();
13812
- if (cloudOnly || !existsSync7(LOCAL_LOG2)) return;
14071
+ if (cloudOnly || !existsSync8(LOCAL_LOG2)) return;
13813
14072
  const rows = [];
13814
14073
  for (const line of tailLocal(LOCAL_LOG2)) {
13815
14074
  try {
@@ -14081,9 +14340,9 @@ __export(logs_server_exports, {
14081
14340
  runLogsServer: () => runLogsServer
14082
14341
  });
14083
14342
  import { createServer } from "http";
14084
- import { readFileSync as readFileSync13, statSync as statSync5 } from "fs";
14085
- import { resolve as resolve7, join as join15, isAbsolute as isAbsolute2 } from "path";
14086
- import { homedir as homedir13 } from "os";
14343
+ import { readFileSync as readFileSync14, statSync as statSync6 } from "fs";
14344
+ import { resolve as resolve7, join as join16, isAbsolute as isAbsolute2 } from "path";
14345
+ import { homedir as homedir14 } from "os";
14087
14346
  import { readdirSync as readdirSync4 } from "fs";
14088
14347
  function allowedOrigins() {
14089
14348
  const base = [
@@ -14100,15 +14359,15 @@ function resolveLocalLogDir(rawPath) {
14100
14359
  const dir = String(rawPath || "").trim().replace(/[\\/]+$/, "");
14101
14360
  if (!dir) return null;
14102
14361
  if (isAbsolute2(dir)) return dir;
14103
- return resolve7(homedir13(), ".solongate", "local-logs");
14362
+ return resolve7(homedir14(), ".solongate", "local-logs");
14104
14363
  }
14105
14364
  async function findLogDir() {
14106
- const base = resolve7(homedir13(), ".solongate");
14365
+ const base = resolve7(homedir14(), ".solongate");
14107
14366
  try {
14108
14367
  const files = readdirSync4(base).filter((f) => f.startsWith(".policy-cache-") && f.endsWith(".json"));
14109
14368
  for (const f of files) {
14110
14369
  try {
14111
- const c2 = JSON.parse(readFileSync13(join15(base, f), "utf-8"));
14370
+ const c2 = JSON.parse(readFileSync14(join16(base, f), "utf-8"));
14112
14371
  const p = c2?.security?.localLogs?.path;
14113
14372
  if (typeof p === "string" && p.trim()) return { dir: resolveLocalLogDir(p), configured: p };
14114
14373
  } catch {
@@ -14117,7 +14376,7 @@ async function findLogDir() {
14117
14376
  } catch {
14118
14377
  }
14119
14378
  try {
14120
- const cfgRaw = readFileSync13(join15(base, "cloud-guard.json"), "utf-8");
14379
+ const cfgRaw = readFileSync14(join16(base, "cloud-guard.json"), "utf-8");
14121
14380
  const { apiKey, apiUrl } = JSON.parse(cfgRaw);
14122
14381
  if (apiKey) {
14123
14382
  const url = `${apiUrl || "https://api.solongate.com"}/api/v1/policies/active`;
@@ -14146,9 +14405,9 @@ function setCors(req, res) {
14146
14405
  }
14147
14406
  function fileInfo(dir) {
14148
14407
  if (!dir) return { file: null, exists: false, size: 0, mtimeMs: 0 };
14149
- const file = join15(dir, LOG_FILENAME);
14408
+ const file = join16(dir, LOG_FILENAME);
14150
14409
  try {
14151
- const st = statSync5(file);
14410
+ const st = statSync6(file);
14152
14411
  return { file, exists: true, size: st.size, mtimeMs: st.mtimeMs };
14153
14412
  } catch {
14154
14413
  return { file, exists: false, size: 0, mtimeMs: 0 };
@@ -14229,7 +14488,7 @@ async function runLogsServer() {
14229
14488
  return;
14230
14489
  }
14231
14490
  try {
14232
- const text = readFileSync13(info.file, "utf-8");
14491
+ const text = readFileSync14(info.file, "utf-8");
14233
14492
  res.writeHead(200, { "Content-Type": "text/plain; charset=utf-8", "Last-Modified": lastMod, "X-Solongate-Exists": "1" });
14234
14493
  res.end(text);
14235
14494
  } catch {
@@ -14282,9 +14541,9 @@ var init_logs_server = __esm({
14282
14541
  });
14283
14542
 
14284
14543
  // src/index.ts
14285
- import { readFileSync as readFileSync14 } from "fs";
14544
+ import { readFileSync as readFileSync15 } from "fs";
14286
14545
  import { fileURLToPath as fileURLToPath4 } from "url";
14287
- import { dirname as dirname4, join as join16 } from "path";
14546
+ import { dirname as dirname4, join as join17 } from "path";
14288
14547
 
14289
14548
  // src/config.ts
14290
14549
  import { readFileSync, existsSync } from "fs";
@@ -15397,9 +15656,9 @@ function extractFilenames(args) {
15397
15656
  if (isUrl) return;
15398
15657
  if (trimmed.includes("/") || trimmed.includes("\\")) {
15399
15658
  const parts = trimmed.split(/[/\\]/);
15400
- const basename = parts[parts.length - 1];
15401
- if (basename && looksLikeFilename(basename)) {
15402
- addFilename(basename);
15659
+ const basename2 = parts[parts.length - 1];
15660
+ if (basename2 && looksLikeFilename(basename2)) {
15661
+ addFilename(basename2);
15403
15662
  }
15404
15663
  }
15405
15664
  const lower = trimmed.toLowerCase();
@@ -15417,9 +15676,9 @@ function extractFilenames(args) {
15417
15676
  }
15418
15677
  if (word.includes("/") || word.includes("\\")) {
15419
15678
  const parts = word.split(/[/\\]/);
15420
- const basename = parts[parts.length - 1];
15421
- if (basename && looksLikeFilename(basename)) {
15422
- addFilename(basename);
15679
+ const basename2 = parts[parts.length - 1];
15680
+ if (basename2 && looksLikeFilename(basename2)) {
15681
+ addFilename(basename2);
15423
15682
  }
15424
15683
  }
15425
15684
  if (word.includes("*") || word.includes("?")) {
@@ -17679,8 +17938,8 @@ if (!IS_HUMAN_CLI) {
17679
17938
  }
17680
17939
  var PKG_VERSION = (() => {
17681
17940
  try {
17682
- const p = join16(dirname4(fileURLToPath4(import.meta.url)), "..", "package.json");
17683
- return JSON.parse(readFileSync14(p, "utf-8")).version || "unknown";
17941
+ const p = join17(dirname4(fileURLToPath4(import.meta.url)), "..", "package.json");
17942
+ return JSON.parse(readFileSync15(p, "utf-8")).version || "unknown";
17684
17943
  } catch {
17685
17944
  return "unknown";
17686
17945
  }