@solongate/proxy 0.81.16 → 0.81.18

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
@@ -7089,6 +7089,149 @@ var init_api_client = __esm({
7089
7089
  }
7090
7090
  });
7091
7091
 
7092
+ // src/tui/notify.ts
7093
+ import { spawn, execFileSync as execFileSync2 } from "child_process";
7094
+ import { writeFileSync as writeFileSync3, existsSync as existsSync4 } from "fs";
7095
+ import { join as join6 } from "path";
7096
+ import { tmpdir as tmpdir2 } from "os";
7097
+ function captureFocusTarget() {
7098
+ try {
7099
+ if (process.platform === "linux") {
7100
+ focusToken = (process.env.WINDOWID || "").trim() || null;
7101
+ if (!focusToken) {
7102
+ try {
7103
+ focusToken = execFileSync2("xdotool", ["getactivewindow"], { encoding: "utf-8", timeout: 1500, stdio: ["ignore", "pipe", "ignore"] }).trim() || null;
7104
+ } catch {
7105
+ focusToken = null;
7106
+ }
7107
+ }
7108
+ } else if (process.platform === "win32") {
7109
+ const ps = `Add-Type -Name W -Namespace N -MemberDefinition '[DllImport("user32.dll")]public static extern System.IntPtr GetForegroundWindow();' | Out-Null; [N.W]::GetForegroundWindow().ToInt64()`;
7110
+ try {
7111
+ focusToken = execFileSync2("powershell", ["-NoProfile", "-NonInteractive", "-Command", ps], { encoding: "utf-8", timeout: 4e3, stdio: ["ignore", "pipe", "ignore"] }).trim() || null;
7112
+ } catch {
7113
+ focusToken = null;
7114
+ }
7115
+ }
7116
+ } catch {
7117
+ focusToken = null;
7118
+ }
7119
+ }
7120
+ function desktopNotify(title, msg) {
7121
+ try {
7122
+ if (process.platform === "linux") linuxNotify(title, msg);
7123
+ else if (process.platform === "win32") winNotify(title, msg);
7124
+ else if (process.platform === "darwin") macNotify(title, msg);
7125
+ } catch {
7126
+ }
7127
+ }
7128
+ function linuxNotify(title, msg) {
7129
+ let p;
7130
+ try {
7131
+ p = spawn("notify-send", ["--wait", "--action=default=Open", "-a", "SolonGate", title, msg], { stdio: ["ignore", "pipe", "ignore"] });
7132
+ } catch {
7133
+ return;
7134
+ }
7135
+ p.on("error", () => {
7136
+ });
7137
+ p.stdout?.on("data", (d) => {
7138
+ if (String(d).trim() === "default") raiseLinuxWindow();
7139
+ });
7140
+ p.unref();
7141
+ }
7142
+ function raiseLinuxWindow() {
7143
+ try {
7144
+ process.stdout.write("\x1B[5t");
7145
+ } catch {
7146
+ }
7147
+ if (!focusToken) return;
7148
+ try {
7149
+ const x = spawn("xdotool", ["windowactivate", focusToken], { stdio: "ignore" });
7150
+ x.on("error", () => {
7151
+ try {
7152
+ const hex = "0x" + Number(focusToken).toString(16);
7153
+ const w = spawn("wmctrl", ["-ia", hex], { stdio: "ignore" });
7154
+ w.on("error", () => {
7155
+ });
7156
+ w.unref();
7157
+ } catch {
7158
+ }
7159
+ });
7160
+ x.unref();
7161
+ } catch {
7162
+ }
7163
+ }
7164
+ function ensureWinScript() {
7165
+ if (winScriptPath && existsSync4(winScriptPath)) return winScriptPath;
7166
+ const p = join6(tmpdir2(), "solongate-toast.ps1");
7167
+ const script = [
7168
+ "param([string]$Title,[string]$Msg,[string]$Hwnd)",
7169
+ "Add-Type -AssemblyName System.Windows.Forms",
7170
+ "Add-Type -AssemblyName System.Drawing",
7171
+ `Add-Type -Name Win -Namespace Sg -MemberDefinition '[DllImport("user32.dll")]public static extern bool SetForegroundWindow(System.IntPtr h);[DllImport("user32.dll")]public static extern bool ShowWindow(System.IntPtr h,int c);'`,
7172
+ "$ni=New-Object System.Windows.Forms.NotifyIcon",
7173
+ "$ni.Icon=[System.Drawing.SystemIcons]::Information",
7174
+ "$ni.Visible=$true",
7175
+ "$script:clicked=$false",
7176
+ "$ni.add_BalloonTipClicked({$script:clicked=$true})",
7177
+ "$ni.ShowBalloonTip(8000,$Title,$Msg,[System.Windows.Forms.ToolTipIcon]::Warning)",
7178
+ "$sw=[System.Diagnostics.Stopwatch]::StartNew()",
7179
+ "while($sw.Elapsed.TotalSeconds -lt 9 -and -not $script:clicked){[System.Windows.Forms.Application]::DoEvents();Start-Sleep -Milliseconds 100}",
7180
+ "if($script:clicked -and $Hwnd){try{$h=[System.IntPtr][int64]$Hwnd;[Sg.Win]::ShowWindow($h,9)|Out-Null;[Sg.Win]::SetForegroundWindow($h)|Out-Null}catch{}}",
7181
+ "$ni.Visible=$false;$ni.Dispose()"
7182
+ ].join("\n");
7183
+ try {
7184
+ writeFileSync3(p, script);
7185
+ winScriptPath = p;
7186
+ return p;
7187
+ } catch {
7188
+ return null;
7189
+ }
7190
+ }
7191
+ function winNotify(title, msg) {
7192
+ const script = ensureWinScript();
7193
+ if (!script) return;
7194
+ try {
7195
+ const p = spawn("powershell", ["-NoProfile", "-NonInteractive", "-ExecutionPolicy", "Bypass", "-File", script, "-Title", title, "-Msg", msg, "-Hwnd", focusToken || ""], { stdio: "ignore", detached: true, windowsHide: true });
7196
+ p.on("error", () => {
7197
+ });
7198
+ p.unref();
7199
+ } catch {
7200
+ }
7201
+ }
7202
+ function macBundleId() {
7203
+ const prog = (process.env.TERM_PROGRAM || "").toLowerCase();
7204
+ if (prog.includes("iterm")) return "com.googlecode.iterm2";
7205
+ if (prog.includes("apple_terminal")) return "com.apple.Terminal";
7206
+ if (prog.includes("vscode")) return "com.microsoft.VSCode";
7207
+ return "com.apple.Terminal";
7208
+ }
7209
+ function macNotify(title, msg) {
7210
+ try {
7211
+ const p = spawn("terminal-notifier", ["-title", title, "-message", msg, "-activate", macBundleId(), "-sender", macBundleId()], { stdio: "ignore", detached: true });
7212
+ p.on("error", () => {
7213
+ try {
7214
+ const esc = (s) => s.replace(/"/g, '\\"');
7215
+ const a = spawn("osascript", ["-e", `display notification "${esc(msg)}" with title "${esc(title)}"`], { stdio: "ignore", detached: true });
7216
+ a.on("error", () => {
7217
+ });
7218
+ a.unref();
7219
+ } catch {
7220
+ }
7221
+ });
7222
+ p.unref();
7223
+ } catch {
7224
+ }
7225
+ }
7226
+ var focusToken, winScriptPath;
7227
+ var init_notify = __esm({
7228
+ "src/tui/notify.ts"() {
7229
+ "use strict";
7230
+ focusToken = null;
7231
+ winScriptPath = null;
7232
+ }
7233
+ });
7234
+
7092
7235
  // src/tui/hooks.ts
7093
7236
  import { useCallback, useEffect, useRef, useState } from "react";
7094
7237
  function useLoader(fn, deps = []) {
@@ -7137,10 +7280,9 @@ var init_hooks = __esm({
7137
7280
  // src/tui/panels/Live.tsx
7138
7281
  import { Box as Box2, Text as Text2, useInput } from "ink";
7139
7282
  import TextInput from "ink-text-input";
7140
- import { spawn } from "child_process";
7141
- import { closeSync, mkdirSync as mkdirSync3, openSync, readSync, statSync, writeFileSync as writeFileSync3 } from "fs";
7283
+ import { closeSync, mkdirSync as mkdirSync3, openSync, readSync, statSync, writeFileSync as writeFileSync4 } from "fs";
7142
7284
  import { homedir as homedir4 } from "os";
7143
- import { join as join6 } from "path";
7285
+ import { join as join7 } from "path";
7144
7286
  import { useCallback as useCallback2, useEffect as useEffect2, useRef as useRef2, useState as useState2 } from "react";
7145
7287
  import { Fragment as Fragment2, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
7146
7288
  function tailLines(file, maxBytes = 131072) {
@@ -7455,13 +7597,7 @@ function LivePanel({ active: active2 }) {
7455
7597
  process.stdout.write("\x07");
7456
7598
  } catch {
7457
7599
  }
7458
- try {
7459
- const child = spawn("notify-send", ["-a", "SolonGate", title, msg], { stdio: "ignore", detached: true });
7460
- child.on("error", () => {
7461
- });
7462
- child.unref();
7463
- } catch {
7464
- }
7600
+ desktopNotify(title, msg);
7465
7601
  },
7466
7602
  [pushLog]
7467
7603
  );
@@ -7675,10 +7811,10 @@ function LivePanel({ active: active2 }) {
7675
7811
  else if (input === "x") toggleSignal("dlp");
7676
7812
  else if (input === "r") toggleSignal("ratelimit");
7677
7813
  else if (input === "e") {
7678
- const file = join6(homedir4(), ".solongate", "live-export.jsonl");
7814
+ const file = join7(homedir4(), ".solongate", "live-export.jsonl");
7679
7815
  try {
7680
- mkdirSync3(join6(homedir4(), ".solongate"), { recursive: true });
7681
- writeFileSync3(file, visibleDesc.map((x) => JSON.stringify(x)).join("\n") + "\n");
7816
+ mkdirSync3(join7(homedir4(), ".solongate"), { recursive: true });
7817
+ writeFileSync4(file, visibleDesc.map((x) => JSON.stringify(x)).join("\n") + "\n");
7682
7818
  setActionMsg({ text: `\u2713 exported ${visibleDesc.length} lines \u2192 ${file}`, level: "ok", until: Date.now() + 6e3 });
7683
7819
  } catch (err2) {
7684
7820
  setActionMsg({ text: "\u2717 export failed: " + (err2 instanceof Error ? err2.message : String(err2)), level: "bad", until: Date.now() + 6e3 });
@@ -7938,14 +8074,15 @@ var init_Live = __esm({
7938
8074
  "use strict";
7939
8075
  init_api_client();
7940
8076
  init_config2();
8077
+ init_notify();
7941
8078
  init_hooks();
7942
8079
  init_theme();
7943
8080
  CONFIG = loadConfig();
7944
8081
  SPIN = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
7945
8082
  BG = "#12234f";
7946
8083
  DIM_FLOOR = "#233457";
7947
- LOCAL_LOG = join6(homedir4(), ".solongate", "local-logs", "solongate-audit.jsonl");
7948
- RING = join6(process.cwd(), ".solongate", ".eval-ring.jsonl");
8084
+ LOCAL_LOG = join7(homedir4(), ".solongate", "local-logs", "solongate-audit.jsonl");
8085
+ RING = join7(process.cwd(), ".solongate", ".eval-ring.jsonl");
7949
8086
  hhmmss = (ts) => {
7950
8087
  const d = new Date(ts);
7951
8088
  return Number.isNaN(d.getTime()) ? "--:--:--" : d.toTimeString().slice(0, 8);
@@ -9161,6 +9298,7 @@ async function launchTui() {
9161
9298
  process.stderr.write("Not logged in. Run `solongate login` first.\n");
9162
9299
  return;
9163
9300
  }
9301
+ captureFocusTarget();
9164
9302
  process.stdout.write("\x1B[?1049h\x1B[H");
9165
9303
  try {
9166
9304
  const { waitUntilExit } = render(/* @__PURE__ */ jsx10(App, {}));
@@ -9174,6 +9312,7 @@ var init_tui = __esm({
9174
9312
  "use strict";
9175
9313
  init_App();
9176
9314
  init_client();
9315
+ init_notify();
9177
9316
  }
9178
9317
  });
9179
9318
 
@@ -9865,9 +10004,9 @@ var init_agents2 = __esm({
9865
10004
  });
9866
10005
 
9867
10006
  // src/commands/doctor.ts
9868
- import { existsSync as existsSync4, statSync as statSync2 } from "fs";
10007
+ import { existsSync as existsSync5, statSync as statSync2 } from "fs";
9869
10008
  import { homedir as homedir5 } from "os";
9870
- import { join as join7 } from "path";
10009
+ import { join as join8 } from "path";
9871
10010
  async function run6(argv) {
9872
10011
  const { flags } = parse(argv);
9873
10012
  const json = flagBool(flags, "json");
@@ -9897,7 +10036,7 @@ async function run6(argv) {
9897
10036
  } catch {
9898
10037
  }
9899
10038
  }
9900
- if (existsSync4(LOCAL_LOG2)) {
10039
+ if (existsSync5(LOCAL_LOG2)) {
9901
10040
  const st = statSync2(LOCAL_LOG2);
9902
10041
  const ageMin = (Date.now() - st.mtimeMs) / 6e4;
9903
10042
  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"}` });
@@ -9927,14 +10066,14 @@ var init_doctor = __esm({
9927
10066
  init_api_client();
9928
10067
  init_format();
9929
10068
  init_args();
9930
- LOCAL_LOG2 = join7(homedir5(), ".solongate", "local-logs", "solongate-audit.jsonl");
10069
+ LOCAL_LOG2 = join8(homedir5(), ".solongate", "local-logs", "solongate-audit.jsonl");
9931
10070
  }
9932
10071
  });
9933
10072
 
9934
10073
  // src/commands/watch.ts
9935
- import { closeSync as closeSync2, existsSync as existsSync5, openSync as openSync2, readSync as readSync2, statSync as statSync3 } from "fs";
10074
+ import { closeSync as closeSync2, existsSync as existsSync6, openSync as openSync2, readSync as readSync2, statSync as statSync3 } from "fs";
9936
10075
  import { homedir as homedir6 } from "os";
9937
- import { join as join8 } from "path";
10076
+ import { join as join9 } from "path";
9938
10077
  function tailLocal(file, maxBytes = 131072) {
9939
10078
  try {
9940
10079
  const size = statSync3(file).size;
@@ -9978,7 +10117,7 @@ async function run7(argv) {
9978
10117
  for (const r of rows) if (keep(r)) print(r, json);
9979
10118
  };
9980
10119
  const pollLocal = () => {
9981
- if (cloudOnly || !existsSync5(LOCAL_LOG3)) return;
10120
+ if (cloudOnly || !existsSync6(LOCAL_LOG3)) return;
9982
10121
  const rows = [];
9983
10122
  for (const line of tailLocal(LOCAL_LOG3)) {
9984
10123
  try {
@@ -10041,7 +10180,7 @@ var init_watch = __esm({
10041
10180
  init_cli_utils();
10042
10181
  init_args();
10043
10182
  init_format();
10044
- LOCAL_LOG3 = join8(homedir6(), ".solongate", "local-logs", "solongate-audit.jsonl");
10183
+ LOCAL_LOG3 = join9(homedir6(), ".solongate", "local-logs", "solongate-audit.jsonl");
10045
10184
  trunc = (s, n) => s.length <= n ? s : s.slice(0, n - 1) + "\u2026";
10046
10185
  time = (ms) => new Date(ms).toTimeString().slice(0, 8);
10047
10186
  }
@@ -10343,32 +10482,32 @@ __export(global_install_exports, {
10343
10482
  runGlobalRestore: () => runGlobalRestore,
10344
10483
  unlockProtected: () => unlockProtected
10345
10484
  });
10346
- import { readFileSync as readFileSync7, writeFileSync as writeFileSync4, existsSync as existsSync6, mkdirSync as mkdirSync4 } from "fs";
10347
- import { resolve as resolve4, join as join9, dirname } from "path";
10485
+ import { readFileSync as readFileSync7, writeFileSync as writeFileSync5, existsSync as existsSync7, mkdirSync as mkdirSync4 } from "fs";
10486
+ import { resolve as resolve4, join as join10, dirname } from "path";
10348
10487
  import { homedir as homedir7 } from "os";
10349
10488
  import { fileURLToPath } from "url";
10350
10489
  import { createInterface } from "readline";
10351
- import { execFileSync as execFileSync2 } from "child_process";
10490
+ import { execFileSync as execFileSync3 } from "child_process";
10352
10491
  function lockFile(file) {
10353
- if (!existsSync6(file)) return;
10492
+ if (!existsSync7(file)) return;
10354
10493
  try {
10355
10494
  if (process.platform === "win32") {
10356
10495
  try {
10357
- execFileSync2("icacls", [file, "/deny", "*S-1-1-0:(WD,AD,DC,DE)"], { stdio: "ignore" });
10496
+ execFileSync3("icacls", [file, "/deny", "*S-1-1-0:(WD,AD,DC,DE)"], { stdio: "ignore" });
10358
10497
  } catch {
10359
10498
  }
10360
10499
  try {
10361
- execFileSync2("attrib", ["+R", file], { stdio: "ignore" });
10500
+ execFileSync3("attrib", ["+R", file], { stdio: "ignore" });
10362
10501
  } catch {
10363
10502
  }
10364
10503
  } else if (process.platform === "darwin") {
10365
10504
  try {
10366
- execFileSync2("chflags", ["uchg", file], { stdio: "ignore" });
10505
+ execFileSync3("chflags", ["uchg", file], { stdio: "ignore" });
10367
10506
  } catch {
10368
10507
  }
10369
10508
  } else {
10370
10509
  try {
10371
- execFileSync2("chattr", ["+i", file], { stdio: "ignore" });
10510
+ execFileSync3("chattr", ["+i", file], { stdio: "ignore" });
10372
10511
  } catch {
10373
10512
  }
10374
10513
  }
@@ -10376,29 +10515,29 @@ function lockFile(file) {
10376
10515
  }
10377
10516
  }
10378
10517
  function unlockFile(file) {
10379
- if (!existsSync6(file)) return;
10518
+ if (!existsSync7(file)) return;
10380
10519
  try {
10381
10520
  if (process.platform === "win32") {
10382
10521
  try {
10383
- execFileSync2("icacls", [file, "/remove:d", "*S-1-1-0"], { stdio: "ignore" });
10522
+ execFileSync3("icacls", [file, "/remove:d", "*S-1-1-0"], { stdio: "ignore" });
10384
10523
  } catch {
10385
10524
  }
10386
10525
  try {
10387
- execFileSync2("icacls", [file, "/reset"], { stdio: "ignore" });
10526
+ execFileSync3("icacls", [file, "/reset"], { stdio: "ignore" });
10388
10527
  } catch {
10389
10528
  }
10390
10529
  try {
10391
- execFileSync2("attrib", ["-R", file], { stdio: "ignore" });
10530
+ execFileSync3("attrib", ["-R", file], { stdio: "ignore" });
10392
10531
  } catch {
10393
10532
  }
10394
10533
  } else if (process.platform === "darwin") {
10395
10534
  try {
10396
- execFileSync2("chflags", ["nouchg", file], { stdio: "ignore" });
10535
+ execFileSync3("chflags", ["nouchg", file], { stdio: "ignore" });
10397
10536
  } catch {
10398
10537
  }
10399
10538
  } else {
10400
10539
  try {
10401
- execFileSync2("chattr", ["-i", file], { stdio: "ignore" });
10540
+ execFileSync3("chattr", ["-i", file], { stdio: "ignore" });
10402
10541
  } catch {
10403
10542
  }
10404
10543
  }
@@ -10408,10 +10547,10 @@ function unlockFile(file) {
10408
10547
  function protectedTargets() {
10409
10548
  const p = globalPaths();
10410
10549
  return [
10411
- join9(p.hooksDir, "guard.mjs"),
10412
- join9(p.hooksDir, "audit.mjs"),
10413
- join9(p.hooksDir, "stop.mjs"),
10414
- join9(p.hooksDir, "shield.mjs"),
10550
+ join10(p.hooksDir, "guard.mjs"),
10551
+ join10(p.hooksDir, "audit.mjs"),
10552
+ join10(p.hooksDir, "stop.mjs"),
10553
+ join10(p.hooksDir, "shield.mjs"),
10415
10554
  p.configPath,
10416
10555
  p.settingsPath
10417
10556
  ];
@@ -10424,25 +10563,25 @@ function unlockProtected() {
10424
10563
  }
10425
10564
  function globalPaths() {
10426
10565
  const home = homedir7();
10427
- const sgDir = join9(home, ".solongate");
10428
- const hooksDir = join9(sgDir, "hooks");
10429
- const claudeDir = join9(home, ".claude");
10566
+ const sgDir = join10(home, ".solongate");
10567
+ const hooksDir = join10(sgDir, "hooks");
10568
+ const claudeDir = join10(home, ".claude");
10430
10569
  return {
10431
10570
  home,
10432
10571
  sgDir,
10433
10572
  hooksDir,
10434
10573
  claudeDir,
10435
- settingsPath: join9(claudeDir, "settings.json"),
10436
- backupPath: join9(claudeDir, "settings.solongate.bak"),
10437
- configPath: join9(sgDir, "cloud-guard.json")
10574
+ settingsPath: join10(claudeDir, "settings.json"),
10575
+ backupPath: join10(claudeDir, "settings.solongate.bak"),
10576
+ configPath: join10(sgDir, "cloud-guard.json")
10438
10577
  };
10439
10578
  }
10440
10579
  function readHook(filename) {
10441
- return readFileSync7(join9(HOOKS_DIR, filename), "utf-8");
10580
+ return readFileSync7(join10(HOOKS_DIR, filename), "utf-8");
10442
10581
  }
10443
10582
  function readGuard() {
10444
- const bundled = join9(HOOKS_DIR, "guard.bundled.mjs");
10445
- return existsSync6(bundled) ? readFileSync7(bundled, "utf-8") : readHook("guard.mjs");
10583
+ const bundled = join10(HOOKS_DIR, "guard.bundled.mjs");
10584
+ return existsSync7(bundled) ? readFileSync7(bundled, "utf-8") : readHook("guard.mjs");
10446
10585
  }
10447
10586
  function ask(question) {
10448
10587
  const rl = createInterface({ input: process.stdin, output: process.stderr });
@@ -10455,14 +10594,14 @@ function runGlobalRestore() {
10455
10594
  const p = globalPaths();
10456
10595
  unlockProtected();
10457
10596
  removeClaudeShim();
10458
- if (existsSync6(p.backupPath)) {
10459
- writeFileSync4(p.settingsPath, readFileSync7(p.backupPath, "utf-8"));
10597
+ if (existsSync7(p.backupPath)) {
10598
+ writeFileSync5(p.settingsPath, readFileSync7(p.backupPath, "utf-8"));
10460
10599
  console.log(` Restored ${p.settingsPath} from backup.`);
10461
- } else if (existsSync6(p.settingsPath)) {
10600
+ } else if (existsSync7(p.settingsPath)) {
10462
10601
  try {
10463
10602
  const s = JSON.parse(readFileSync7(p.settingsPath, "utf-8"));
10464
10603
  delete s.hooks;
10465
- writeFileSync4(p.settingsPath, JSON.stringify(s, null, 2) + "\n");
10604
+ writeFileSync5(p.settingsPath, JSON.stringify(s, null, 2) + "\n");
10466
10605
  console.log(` Removed SolonGate hooks from ${p.settingsPath}.`);
10467
10606
  } catch {
10468
10607
  }
@@ -10477,7 +10616,7 @@ function escapeRe(s) {
10477
10616
  function resolveRealClaude() {
10478
10617
  try {
10479
10618
  const finder = process.platform === "win32" ? "where" : "which";
10480
- const out2 = execFileSync2(finder, ["claude"], { encoding: "utf-8" }).split(/\r?\n/).map((s) => s.trim()).filter(Boolean);
10619
+ const out2 = execFileSync3(finder, ["claude"], { encoding: "utf-8" }).split(/\r?\n/).map((s) => s.trim()).filter(Boolean);
10481
10620
  if (process.platform === "win32") {
10482
10621
  const low = (s) => s.toLowerCase();
10483
10622
  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;
@@ -10490,24 +10629,24 @@ function resolveRealClaude() {
10490
10629
  function shimTargets() {
10491
10630
  if (process.platform === "win32") {
10492
10631
  try {
10493
- const prof = execFileSync2("powershell", ["-NoProfile", "-Command", "$PROFILE.CurrentUserAllHosts"], { encoding: "utf-8" }).trim();
10632
+ const prof = execFileSync3("powershell", ["-NoProfile", "-Command", "$PROFILE.CurrentUserAllHosts"], { encoding: "utf-8" }).trim();
10494
10633
  return prof ? [prof] : [];
10495
10634
  } catch {
10496
10635
  return [];
10497
10636
  }
10498
10637
  }
10499
- return [".bashrc", ".zshrc", ".profile"].map((f) => join9(homedir7(), f)).filter((f) => existsSync6(f));
10638
+ return [".bashrc", ".zshrc", ".profile"].map((f) => join10(homedir7(), f)).filter((f) => existsSync7(f));
10500
10639
  }
10501
10640
  function writeShimBlock(file, block2) {
10502
10641
  const re = new RegExp(escapeRe(SHIM_BEGIN) + "[\\s\\S]*?" + escapeRe(SHIM_END) + "\\r?\\n?", "g");
10503
- let content = existsSync6(file) ? readFileSync7(file, "utf-8") : "";
10642
+ let content = existsSync7(file) ? readFileSync7(file, "utf-8") : "";
10504
10643
  content = content.replace(re, "");
10505
10644
  if (block2) {
10506
10645
  if (content.length && !content.endsWith("\n")) content += "\n";
10507
10646
  content += block2 + "\n";
10508
10647
  }
10509
10648
  mkdirSync4(dirname(file), { recursive: true });
10510
- writeFileSync4(file, content);
10649
+ writeFileSync5(file, content);
10511
10650
  }
10512
10651
  function installClaudeShim(shieldPath) {
10513
10652
  const real = resolveRealClaude();
@@ -10561,19 +10700,19 @@ async function runGlobalInstall(opts = {}) {
10561
10700
  mkdirSync4(p.hooksDir, { recursive: true });
10562
10701
  mkdirSync4(p.claudeDir, { recursive: true });
10563
10702
  unlockProtected();
10564
- writeFileSync4(join9(p.hooksDir, "guard.mjs"), readGuard());
10565
- writeFileSync4(join9(p.hooksDir, "audit.mjs"), readHook("audit.mjs"));
10566
- writeFileSync4(join9(p.hooksDir, "stop.mjs"), readHook("stop.mjs"));
10567
- writeFileSync4(join9(p.hooksDir, "shield.mjs"), readHook("shield.mjs"));
10703
+ writeFileSync5(join10(p.hooksDir, "guard.mjs"), readGuard());
10704
+ writeFileSync5(join10(p.hooksDir, "audit.mjs"), readHook("audit.mjs"));
10705
+ writeFileSync5(join10(p.hooksDir, "stop.mjs"), readHook("stop.mjs"));
10706
+ writeFileSync5(join10(p.hooksDir, "shield.mjs"), readHook("shield.mjs"));
10568
10707
  console.log(` Installed hooks \u2192 ${p.hooksDir}`);
10569
- installClaudeShim(join9(p.hooksDir, "shield.mjs"));
10570
- writeFileSync4(p.configPath, JSON.stringify({ apiKey, apiUrl }, null, 2) + "\n");
10708
+ installClaudeShim(join10(p.hooksDir, "shield.mjs"));
10709
+ writeFileSync5(p.configPath, JSON.stringify({ apiKey, apiUrl }, null, 2) + "\n");
10571
10710
  console.log(` Wrote ${p.configPath}`);
10572
10711
  let existing = {};
10573
- if (existsSync6(p.settingsPath)) {
10712
+ if (existsSync7(p.settingsPath)) {
10574
10713
  const raw = readFileSync7(p.settingsPath, "utf-8");
10575
- if (!existsSync6(p.backupPath)) {
10576
- writeFileSync4(p.backupPath, raw);
10714
+ if (!existsSync7(p.backupPath)) {
10715
+ writeFileSync5(p.backupPath, raw);
10577
10716
  console.log(` Backed up existing settings \u2192 ${p.backupPath}`);
10578
10717
  }
10579
10718
  try {
@@ -10582,9 +10721,9 @@ async function runGlobalInstall(opts = {}) {
10582
10721
  existing = {};
10583
10722
  }
10584
10723
  }
10585
- const guardAbs = join9(p.hooksDir, "guard.mjs").replace(/\\/g, "/");
10586
- const auditAbs = join9(p.hooksDir, "audit.mjs").replace(/\\/g, "/");
10587
- const stopAbs = join9(p.hooksDir, "stop.mjs").replace(/\\/g, "/");
10724
+ const guardAbs = join10(p.hooksDir, "guard.mjs").replace(/\\/g, "/");
10725
+ const auditAbs = join10(p.hooksDir, "audit.mjs").replace(/\\/g, "/");
10726
+ const stopAbs = join10(p.hooksDir, "stop.mjs").replace(/\\/g, "/");
10588
10727
  const nodeBin = process.execPath.replace(/\\/g, "/");
10589
10728
  const call = process.platform === "win32" ? "& " : "";
10590
10729
  const hookCmd = (script) => `${call}"${nodeBin}" "${script}" claude-code "Claude Code"`;
@@ -10596,7 +10735,7 @@ async function runGlobalInstall(opts = {}) {
10596
10735
  Stop: [{ matcher: "", hooks: [{ type: "command", command: hookCmd(stopAbs) }] }]
10597
10736
  }
10598
10737
  };
10599
- writeFileSync4(p.settingsPath, JSON.stringify(merged, null, 2) + "\n");
10738
+ writeFileSync5(p.settingsPath, JSON.stringify(merged, null, 2) + "\n");
10600
10739
  console.log(` Registered global hooks \u2192 ${p.settingsPath}`);
10601
10740
  if (process.env["SOLONGATE_OS_LOCK"] === "1") {
10602
10741
  lockProtected();
@@ -10776,7 +10915,7 @@ import { createServer, request as httpRequest } from "http";
10776
10915
  import { request as httpsRequest } from "https";
10777
10916
  import { spawn as spawn3 } from "child_process";
10778
10917
  import { URL as URL2 } from "url";
10779
- import { readFileSync as readFileSync8, existsSync as existsSync7, readdirSync, statSync as statSync4 } from "fs";
10918
+ import { readFileSync as readFileSync8, existsSync as existsSync8, readdirSync, statSync as statSync4 } from "fs";
10780
10919
  import { resolve as resolve5 } from "path";
10781
10920
  import { homedir as homedir8 } from "os";
10782
10921
  function findCacheFile() {
@@ -10784,7 +10923,7 @@ function findCacheFile() {
10784
10923
  const envSel = process.env.SOLONGATE_AGENT_ID;
10785
10924
  if (envSel) {
10786
10925
  const f = resolve5(dir, ".policy-cache-" + envSel.replace(/[^a-zA-Z0-9_-]/g, "_") + ".json");
10787
- if (existsSync7(f)) return f;
10926
+ if (existsSync8(f)) return f;
10788
10927
  }
10789
10928
  let best = null, bestTs = -1;
10790
10929
  try {
@@ -10805,7 +10944,7 @@ function findCacheFile() {
10805
10944
  function loadCfg() {
10806
10945
  try {
10807
10946
  const f = findCacheFile();
10808
- if (f && existsSync7(f)) {
10947
+ if (f && existsSync8(f)) {
10809
10948
  const c2 = JSON.parse(readFileSync8(f, "utf-8"));
10810
10949
  const d = c2?.security?.dlpRedact;
10811
10950
  const g = c2?.security?.ghost;
@@ -11095,7 +11234,7 @@ __export(logs_server_exports, {
11095
11234
  });
11096
11235
  import { createServer as createServer2 } from "http";
11097
11236
  import { readFileSync as readFileSync9, statSync as statSync5 } from "fs";
11098
- import { resolve as resolve6, join as join10, isAbsolute } from "path";
11237
+ import { resolve as resolve6, join as join11, isAbsolute } from "path";
11099
11238
  import { homedir as homedir9 } from "os";
11100
11239
  import { readdirSync as readdirSync2 } from "fs";
11101
11240
  function allowedOrigins() {
@@ -11121,7 +11260,7 @@ async function findLogDir() {
11121
11260
  const files = readdirSync2(base).filter((f) => f.startsWith(".policy-cache-") && f.endsWith(".json"));
11122
11261
  for (const f of files) {
11123
11262
  try {
11124
- const c2 = JSON.parse(readFileSync9(join10(base, f), "utf-8"));
11263
+ const c2 = JSON.parse(readFileSync9(join11(base, f), "utf-8"));
11125
11264
  const p = c2?.security?.localLogs?.path;
11126
11265
  if (typeof p === "string" && p.trim()) return { dir: resolveLocalLogDir(p), configured: p };
11127
11266
  } catch {
@@ -11130,7 +11269,7 @@ async function findLogDir() {
11130
11269
  } catch {
11131
11270
  }
11132
11271
  try {
11133
- const cfgRaw = readFileSync9(join10(base, "cloud-guard.json"), "utf-8");
11272
+ const cfgRaw = readFileSync9(join11(base, "cloud-guard.json"), "utf-8");
11134
11273
  const { apiKey, apiUrl } = JSON.parse(cfgRaw);
11135
11274
  if (apiKey) {
11136
11275
  const url = `${apiUrl || "https://api.solongate.com"}/api/v1/policies/active`;
@@ -11159,7 +11298,7 @@ function setCors(req, res) {
11159
11298
  }
11160
11299
  function fileInfo(dir) {
11161
11300
  if (!dir) return { file: null, exists: false, size: 0, mtimeMs: 0 };
11162
- const file = join10(dir, LOG_FILENAME);
11301
+ const file = join11(dir, LOG_FILENAME);
11163
11302
  try {
11164
11303
  const st = statSync5(file);
11165
11304
  return { file, exists: true, size: st.size, mtimeMs: st.mtimeMs };
@@ -11272,7 +11411,7 @@ var init_logs_server = __esm({
11272
11411
 
11273
11412
  // src/inject.ts
11274
11413
  var inject_exports = {};
11275
- import { readFileSync as readFileSync10, writeFileSync as writeFileSync5, existsSync as existsSync8, copyFileSync } from "fs";
11414
+ import { readFileSync as readFileSync10, writeFileSync as writeFileSync6, existsSync as existsSync9, copyFileSync } from "fs";
11276
11415
  import { resolve as resolve7 } from "path";
11277
11416
  import { execSync } from "child_process";
11278
11417
  function parseInjectArgs(argv) {
@@ -11330,7 +11469,7 @@ WHAT IT DOES
11330
11469
  `);
11331
11470
  }
11332
11471
  function detectProject() {
11333
- if (!existsSync8(resolve7("package.json"))) return false;
11472
+ if (!existsSync9(resolve7("package.json"))) return false;
11334
11473
  try {
11335
11474
  const pkg = JSON.parse(readFileSync10(resolve7("package.json"), "utf-8"));
11336
11475
  const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
@@ -11346,13 +11485,13 @@ function findTsEntryFile() {
11346
11485
  const binPath = typeof pkg.bin === "string" ? pkg.bin : Object.values(pkg.bin)[0];
11347
11486
  if (typeof binPath === "string") {
11348
11487
  const srcPath = binPath.replace(/^\.\/dist\//, "./src/").replace(/\.js$/, ".ts");
11349
- if (existsSync8(resolve7(srcPath))) return resolve7(srcPath);
11350
- if (existsSync8(resolve7(binPath))) return resolve7(binPath);
11488
+ if (existsSync9(resolve7(srcPath))) return resolve7(srcPath);
11489
+ if (existsSync9(resolve7(binPath))) return resolve7(binPath);
11351
11490
  }
11352
11491
  }
11353
11492
  if (pkg.main) {
11354
11493
  const srcPath = pkg.main.replace(/^\.\/dist\//, "./src/").replace(/\.js$/, ".ts");
11355
- if (existsSync8(resolve7(srcPath))) return resolve7(srcPath);
11494
+ if (existsSync9(resolve7(srcPath))) return resolve7(srcPath);
11356
11495
  }
11357
11496
  } catch {
11358
11497
  }
@@ -11366,7 +11505,7 @@ function findTsEntryFile() {
11366
11505
  ];
11367
11506
  for (const c2 of candidates) {
11368
11507
  const full = resolve7(c2);
11369
- if (existsSync8(full)) {
11508
+ if (existsSync9(full)) {
11370
11509
  try {
11371
11510
  const content = readFileSync10(full, "utf-8");
11372
11511
  if (content.includes("McpServer") || content.includes("McpServer")) {
@@ -11377,13 +11516,13 @@ function findTsEntryFile() {
11377
11516
  }
11378
11517
  }
11379
11518
  for (const c2 of candidates) {
11380
- if (existsSync8(resolve7(c2))) return resolve7(c2);
11519
+ if (existsSync9(resolve7(c2))) return resolve7(c2);
11381
11520
  }
11382
11521
  return null;
11383
11522
  }
11384
11523
  function detectPackageManager() {
11385
- if (existsSync8(resolve7("pnpm-lock.yaml"))) return "pnpm";
11386
- if (existsSync8(resolve7("yarn.lock"))) return "yarn";
11524
+ if (existsSync9(resolve7("pnpm-lock.yaml"))) return "pnpm";
11525
+ if (existsSync9(resolve7("yarn.lock"))) return "yarn";
11387
11526
  return "npm";
11388
11527
  }
11389
11528
  function installSdk() {
@@ -11526,7 +11665,7 @@ async function main2() {
11526
11665
  }
11527
11666
  log3(" Language: TypeScript");
11528
11667
  const entryFile = opts.file ? resolve7(opts.file) : findTsEntryFile();
11529
- if (!entryFile || !existsSync8(entryFile)) {
11668
+ if (!entryFile || !existsSync9(entryFile)) {
11530
11669
  log3(` Could not find entry file.${opts.file ? ` File not found: ${opts.file}` : ""}`);
11531
11670
  log3("");
11532
11671
  log3(" Specify it manually: --file <path>");
@@ -11539,7 +11678,7 @@ async function main2() {
11539
11678
  log3("");
11540
11679
  const backupPath = entryFile + ".solongate-backup";
11541
11680
  if (opts.restore) {
11542
- if (!existsSync8(backupPath)) {
11681
+ if (!existsSync9(backupPath)) {
11543
11682
  log3(" No backup found. Nothing to restore.");
11544
11683
  process.exit(1);
11545
11684
  }
@@ -11575,12 +11714,12 @@ async function main2() {
11575
11714
  log3(" To apply: npx @solongate/proxy inject");
11576
11715
  process.exit(0);
11577
11716
  }
11578
- if (!existsSync8(backupPath)) {
11717
+ if (!existsSync9(backupPath)) {
11579
11718
  copyFileSync(entryFile, backupPath);
11580
11719
  log3("");
11581
11720
  log3(` Backup: ${backupPath}`);
11582
11721
  }
11583
- writeFileSync5(entryFile, result.modified);
11722
+ writeFileSync6(entryFile, result.modified);
11584
11723
  log3("");
11585
11724
  log3(" \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510");
11586
11725
  log3(" \u2502 SolonGate SDK injected successfully! \u2502");
@@ -11609,8 +11748,8 @@ var init_inject = __esm({
11609
11748
 
11610
11749
  // src/create.ts
11611
11750
  var create_exports = {};
11612
- import { mkdirSync as mkdirSync5, writeFileSync as writeFileSync6, existsSync as existsSync9 } from "fs";
11613
- import { resolve as resolve8, join as join11 } from "path";
11751
+ import { mkdirSync as mkdirSync5, writeFileSync as writeFileSync7, existsSync as existsSync10 } from "fs";
11752
+ import { resolve as resolve8, join as join12 } from "path";
11614
11753
  import { execSync as execSync2 } from "child_process";
11615
11754
  function withSpinner(message, fn) {
11616
11755
  const frames = ["\u28FE", "\u28FD", "\u28FB", "\u28BF", "\u287F", "\u28DF", "\u28EF", "\u28F7"];
@@ -11689,8 +11828,8 @@ EXAMPLES
11689
11828
  `);
11690
11829
  }
11691
11830
  function createProject(dir, name, _policy) {
11692
- writeFileSync6(
11693
- join11(dir, "package.json"),
11831
+ writeFileSync7(
11832
+ join12(dir, "package.json"),
11694
11833
  JSON.stringify(
11695
11834
  {
11696
11835
  name,
@@ -11719,8 +11858,8 @@ function createProject(dir, name, _policy) {
11719
11858
  2
11720
11859
  ) + "\n"
11721
11860
  );
11722
- writeFileSync6(
11723
- join11(dir, "tsconfig.json"),
11861
+ writeFileSync7(
11862
+ join12(dir, "tsconfig.json"),
11724
11863
  JSON.stringify(
11725
11864
  {
11726
11865
  compilerOptions: {
@@ -11740,9 +11879,9 @@ function createProject(dir, name, _policy) {
11740
11879
  2
11741
11880
  ) + "\n"
11742
11881
  );
11743
- mkdirSync5(join11(dir, "src"), { recursive: true });
11744
- writeFileSync6(
11745
- join11(dir, "src", "index.ts"),
11882
+ mkdirSync5(join12(dir, "src"), { recursive: true });
11883
+ writeFileSync7(
11884
+ join12(dir, "src", "index.ts"),
11746
11885
  `#!/usr/bin/env node
11747
11886
 
11748
11887
  console.log = (...args: unknown[]) => {
@@ -11783,8 +11922,8 @@ console.log('');
11783
11922
  console.log('Press Ctrl+C to stop.');
11784
11923
  `
11785
11924
  );
11786
- writeFileSync6(
11787
- join11(dir, ".mcp.json"),
11925
+ writeFileSync7(
11926
+ join12(dir, ".mcp.json"),
11788
11927
  JSON.stringify(
11789
11928
  {
11790
11929
  mcpServers: {
@@ -11801,13 +11940,13 @@ console.log('Press Ctrl+C to stop.');
11801
11940
  2
11802
11941
  ) + "\n"
11803
11942
  );
11804
- writeFileSync6(
11805
- join11(dir, ".env"),
11943
+ writeFileSync7(
11944
+ join12(dir, ".env"),
11806
11945
  `SOLONGATE_API_KEY=sg_live_YOUR_KEY_HERE
11807
11946
  `
11808
11947
  );
11809
- writeFileSync6(
11810
- join11(dir, ".gitignore"),
11948
+ writeFileSync7(
11949
+ join12(dir, ".gitignore"),
11811
11950
  `node_modules/
11812
11951
  dist/
11813
11952
  *.solongate-backup
@@ -11821,7 +11960,7 @@ async function main3() {
11821
11960
  const opts = parseCreateArgs(process.argv);
11822
11961
  const dir = resolve8(opts.name);
11823
11962
  printBanner("Create MCP Server");
11824
- if (existsSync9(dir)) {
11963
+ if (existsSync10(dir)) {
11825
11964
  log3(` ${c.red}Error:${c.reset} Directory "${opts.name}" already exists.`);
11826
11965
  process.exit(1);
11827
11966
  }
@@ -11900,12 +12039,12 @@ var init_create = __esm({
11900
12039
 
11901
12040
  // src/pull-push.ts
11902
12041
  var pull_push_exports = {};
11903
- import { readFileSync as readFileSync11, writeFileSync as writeFileSync7, existsSync as existsSync10 } from "fs";
12042
+ import { readFileSync as readFileSync11, writeFileSync as writeFileSync8, existsSync as existsSync11 } from "fs";
11904
12043
  import { resolve as resolve9 } from "path";
11905
12044
  function loadEnv() {
11906
12045
  if (process.env.SOLONGATE_API_KEY) return;
11907
12046
  const envPath = resolve9(".env");
11908
- if (!existsSync10(envPath)) return;
12047
+ if (!existsSync11(envPath)) return;
11909
12048
  try {
11910
12049
  const content = readFileSync11(envPath, "utf-8");
11911
12050
  for (const line of content.split("\n")) {
@@ -12095,7 +12234,7 @@ async function pull(apiKey, file, policyId) {
12095
12234
  const policy = await fetchCloudPolicy(apiKey, API_URL, policyId);
12096
12235
  const { id: _id, ...policyWithoutId } = policy;
12097
12236
  const json = JSON.stringify(policyWithoutId, null, 2) + "\n";
12098
- writeFileSync7(file, json, "utf-8");
12237
+ writeFileSync8(file, json, "utf-8");
12099
12238
  log5("");
12100
12239
  log5(green2(" Saved to: ") + file);
12101
12240
  log5(` ${dim2("Name:")} ${policy.name}`);
@@ -12107,7 +12246,7 @@ async function pull(apiKey, file, policyId) {
12107
12246
  log5("");
12108
12247
  }
12109
12248
  async function push(apiKey, file, policyId) {
12110
- if (!existsSync10(file)) {
12249
+ if (!existsSync11(file)) {
12111
12250
  log5(red2(`ERROR: File not found: ${file}`));
12112
12251
  process.exit(1);
12113
12252
  }
package/dist/tui/index.js CHANGED
@@ -150,10 +150,9 @@ function KeyHints({ hints }) {
150
150
  // src/tui/panels/Live.tsx
151
151
  import { Box as Box2, Text as Text2, useInput } from "ink";
152
152
  import TextInput from "ink-text-input";
153
- import { spawn } from "child_process";
154
- import { closeSync, mkdirSync, openSync, readSync, statSync, writeFileSync } from "fs";
153
+ import { closeSync, mkdirSync, openSync, readSync, statSync, writeFileSync as writeFileSync2 } from "fs";
155
154
  import { homedir as homedir3 } from "os";
156
- import { join as join3 } from "path";
155
+ import { join as join4 } from "path";
157
156
  import { useCallback as useCallback2, useEffect as useEffect2, useRef as useRef2, useState as useState2 } from "react";
158
157
 
159
158
  // src/api-client/client.ts
@@ -489,6 +488,143 @@ function list4() {
489
488
  // src/api-client/index.ts
490
489
  var api = { policies: policies_exports, settings: settings_exports, stats: stats_exports, audit: audit_exports, agents: agents_exports, keys: keys_exports, mcp: mcp_exports };
491
490
 
491
+ // src/tui/notify.ts
492
+ import { spawn, execFileSync } from "child_process";
493
+ import { writeFileSync, existsSync as existsSync2 } from "fs";
494
+ import { join as join3 } from "path";
495
+ import { tmpdir } from "os";
496
+ var focusToken = null;
497
+ function captureFocusTarget() {
498
+ try {
499
+ if (process.platform === "linux") {
500
+ focusToken = (process.env.WINDOWID || "").trim() || null;
501
+ if (!focusToken) {
502
+ try {
503
+ focusToken = execFileSync("xdotool", ["getactivewindow"], { encoding: "utf-8", timeout: 1500, stdio: ["ignore", "pipe", "ignore"] }).trim() || null;
504
+ } catch {
505
+ focusToken = null;
506
+ }
507
+ }
508
+ } else if (process.platform === "win32") {
509
+ const ps = `Add-Type -Name W -Namespace N -MemberDefinition '[DllImport("user32.dll")]public static extern System.IntPtr GetForegroundWindow();' | Out-Null; [N.W]::GetForegroundWindow().ToInt64()`;
510
+ try {
511
+ focusToken = execFileSync("powershell", ["-NoProfile", "-NonInteractive", "-Command", ps], { encoding: "utf-8", timeout: 4e3, stdio: ["ignore", "pipe", "ignore"] }).trim() || null;
512
+ } catch {
513
+ focusToken = null;
514
+ }
515
+ }
516
+ } catch {
517
+ focusToken = null;
518
+ }
519
+ }
520
+ function desktopNotify(title, msg) {
521
+ try {
522
+ if (process.platform === "linux") linuxNotify(title, msg);
523
+ else if (process.platform === "win32") winNotify(title, msg);
524
+ else if (process.platform === "darwin") macNotify(title, msg);
525
+ } catch {
526
+ }
527
+ }
528
+ function linuxNotify(title, msg) {
529
+ let p;
530
+ try {
531
+ p = spawn("notify-send", ["--wait", "--action=default=Open", "-a", "SolonGate", title, msg], { stdio: ["ignore", "pipe", "ignore"] });
532
+ } catch {
533
+ return;
534
+ }
535
+ p.on("error", () => {
536
+ });
537
+ p.stdout?.on("data", (d) => {
538
+ if (String(d).trim() === "default") raiseLinuxWindow();
539
+ });
540
+ p.unref();
541
+ }
542
+ function raiseLinuxWindow() {
543
+ try {
544
+ process.stdout.write("\x1B[5t");
545
+ } catch {
546
+ }
547
+ if (!focusToken) return;
548
+ try {
549
+ const x = spawn("xdotool", ["windowactivate", focusToken], { stdio: "ignore" });
550
+ x.on("error", () => {
551
+ try {
552
+ const hex = "0x" + Number(focusToken).toString(16);
553
+ const w = spawn("wmctrl", ["-ia", hex], { stdio: "ignore" });
554
+ w.on("error", () => {
555
+ });
556
+ w.unref();
557
+ } catch {
558
+ }
559
+ });
560
+ x.unref();
561
+ } catch {
562
+ }
563
+ }
564
+ var winScriptPath = null;
565
+ function ensureWinScript() {
566
+ if (winScriptPath && existsSync2(winScriptPath)) return winScriptPath;
567
+ const p = join3(tmpdir(), "solongate-toast.ps1");
568
+ const script = [
569
+ "param([string]$Title,[string]$Msg,[string]$Hwnd)",
570
+ "Add-Type -AssemblyName System.Windows.Forms",
571
+ "Add-Type -AssemblyName System.Drawing",
572
+ `Add-Type -Name Win -Namespace Sg -MemberDefinition '[DllImport("user32.dll")]public static extern bool SetForegroundWindow(System.IntPtr h);[DllImport("user32.dll")]public static extern bool ShowWindow(System.IntPtr h,int c);'`,
573
+ "$ni=New-Object System.Windows.Forms.NotifyIcon",
574
+ "$ni.Icon=[System.Drawing.SystemIcons]::Information",
575
+ "$ni.Visible=$true",
576
+ "$script:clicked=$false",
577
+ "$ni.add_BalloonTipClicked({$script:clicked=$true})",
578
+ "$ni.ShowBalloonTip(8000,$Title,$Msg,[System.Windows.Forms.ToolTipIcon]::Warning)",
579
+ "$sw=[System.Diagnostics.Stopwatch]::StartNew()",
580
+ "while($sw.Elapsed.TotalSeconds -lt 9 -and -not $script:clicked){[System.Windows.Forms.Application]::DoEvents();Start-Sleep -Milliseconds 100}",
581
+ "if($script:clicked -and $Hwnd){try{$h=[System.IntPtr][int64]$Hwnd;[Sg.Win]::ShowWindow($h,9)|Out-Null;[Sg.Win]::SetForegroundWindow($h)|Out-Null}catch{}}",
582
+ "$ni.Visible=$false;$ni.Dispose()"
583
+ ].join("\n");
584
+ try {
585
+ writeFileSync(p, script);
586
+ winScriptPath = p;
587
+ return p;
588
+ } catch {
589
+ return null;
590
+ }
591
+ }
592
+ function winNotify(title, msg) {
593
+ const script = ensureWinScript();
594
+ if (!script) return;
595
+ try {
596
+ const p = spawn("powershell", ["-NoProfile", "-NonInteractive", "-ExecutionPolicy", "Bypass", "-File", script, "-Title", title, "-Msg", msg, "-Hwnd", focusToken || ""], { stdio: "ignore", detached: true, windowsHide: true });
597
+ p.on("error", () => {
598
+ });
599
+ p.unref();
600
+ } catch {
601
+ }
602
+ }
603
+ function macBundleId() {
604
+ const prog = (process.env.TERM_PROGRAM || "").toLowerCase();
605
+ if (prog.includes("iterm")) return "com.googlecode.iterm2";
606
+ if (prog.includes("apple_terminal")) return "com.apple.Terminal";
607
+ if (prog.includes("vscode")) return "com.microsoft.VSCode";
608
+ return "com.apple.Terminal";
609
+ }
610
+ function macNotify(title, msg) {
611
+ try {
612
+ const p = spawn("terminal-notifier", ["-title", title, "-message", msg, "-activate", macBundleId(), "-sender", macBundleId()], { stdio: "ignore", detached: true });
613
+ p.on("error", () => {
614
+ try {
615
+ const esc = (s) => s.replace(/"/g, '\\"');
616
+ const a = spawn("osascript", ["-e", `display notification "${esc(msg)}" with title "${esc(title)}"`], { stdio: "ignore", detached: true });
617
+ a.on("error", () => {
618
+ });
619
+ a.unref();
620
+ } catch {
621
+ }
622
+ });
623
+ p.unref();
624
+ } catch {
625
+ }
626
+ }
627
+
492
628
  // src/tui/hooks.ts
493
629
  import { useCallback, useEffect, useRef, useState } from "react";
494
630
  function useLoader(fn, deps = []) {
@@ -535,8 +671,8 @@ var CONFIG = loadConfig();
535
671
  var SPIN = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
536
672
  var BG = "#12234f";
537
673
  var DIM_FLOOR = "#233457";
538
- var LOCAL_LOG = join3(homedir3(), ".solongate", "local-logs", "solongate-audit.jsonl");
539
- var RING = join3(process.cwd(), ".solongate", ".eval-ring.jsonl");
674
+ var LOCAL_LOG = join4(homedir3(), ".solongate", "local-logs", "solongate-audit.jsonl");
675
+ var RING = join4(process.cwd(), ".solongate", ".eval-ring.jsonl");
540
676
  var hhmmss = (ts) => {
541
677
  const d = new Date(ts);
542
678
  return Number.isNaN(d.getTime()) ? "--:--:--" : d.toTimeString().slice(0, 8);
@@ -865,13 +1001,7 @@ function LivePanel({ active: active2 }) {
865
1001
  process.stdout.write("\x07");
866
1002
  } catch {
867
1003
  }
868
- try {
869
- const child = spawn("notify-send", ["-a", "SolonGate", title, msg], { stdio: "ignore", detached: true });
870
- child.on("error", () => {
871
- });
872
- child.unref();
873
- } catch {
874
- }
1004
+ desktopNotify(title, msg);
875
1005
  },
876
1006
  [pushLog]
877
1007
  );
@@ -1085,10 +1215,10 @@ function LivePanel({ active: active2 }) {
1085
1215
  else if (input === "x") toggleSignal("dlp");
1086
1216
  else if (input === "r") toggleSignal("ratelimit");
1087
1217
  else if (input === "e") {
1088
- const file = join3(homedir3(), ".solongate", "live-export.jsonl");
1218
+ const file = join4(homedir3(), ".solongate", "live-export.jsonl");
1089
1219
  try {
1090
- mkdirSync(join3(homedir3(), ".solongate"), { recursive: true });
1091
- writeFileSync(file, visibleDesc.map((x) => JSON.stringify(x)).join("\n") + "\n");
1220
+ mkdirSync(join4(homedir3(), ".solongate"), { recursive: true });
1221
+ writeFileSync2(file, visibleDesc.map((x) => JSON.stringify(x)).join("\n") + "\n");
1092
1222
  setActionMsg({ text: `\u2713 exported ${visibleDesc.length} lines \u2192 ${file}`, level: "ok", until: Date.now() + 6e3 });
1093
1223
  } catch (err) {
1094
1224
  setActionMsg({ text: "\u2717 export failed: " + (err instanceof Error ? err.message : String(err)), level: "bad", until: Date.now() + 6e3 });
@@ -2457,6 +2587,7 @@ async function launchTui() {
2457
2587
  process.stderr.write("Not logged in. Run `solongate login` first.\n");
2458
2588
  return;
2459
2589
  }
2590
+ captureFocusTarget();
2460
2591
  process.stdout.write("\x1B[?1049h\x1B[H");
2461
2592
  try {
2462
2593
  const { waitUntilExit } = render(/* @__PURE__ */ jsx10(App, {}));
@@ -0,0 +1,4 @@
1
+ /** Capture the current terminal window once, at TUI startup. Cheap + best-effort. */
2
+ export declare function captureFocusTarget(): void;
3
+ /** Fire a desktop toast; clicking it raises the dataroom terminal. */
4
+ export declare function desktopNotify(title: string, msg: string): void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solongate/proxy",
3
- "version": "0.81.16",
3
+ "version": "0.81.18",
4
4
  "description": "AI tool security proxy: protect any AI tool server with customizable policies, path/command constraints, rate limiting, and audit logging. No code changes required.",
5
5
  "type": "module",
6
6
  "bin": {