@solongate/proxy 0.81.49 → 0.81.51

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
@@ -6736,15 +6736,115 @@ var init_self_update = __esm({
6736
6736
  }
6737
6737
  });
6738
6738
 
6739
- // src/tui/config.ts
6740
- import { readFileSync as readFileSync5 } from "fs";
6739
+ // src/logs-server-daemon.ts
6740
+ var logs_server_daemon_exports = {};
6741
+ __export(logs_server_daemon_exports, {
6742
+ LOGS_SERVER_PORT: () => LOGS_SERVER_PORT,
6743
+ ensureLogsServerDaemon: () => ensureLogsServerDaemon,
6744
+ logsServerStatus: () => logsServerStatus,
6745
+ recordLogsServerStarted: () => recordLogsServerStarted,
6746
+ startLogsServerDaemon: () => startLogsServerDaemon,
6747
+ stopLogsServerDaemon: () => stopLogsServerDaemon
6748
+ });
6749
+ import { spawn as spawn2 } from "child_process";
6750
+ import { mkdirSync as mkdirSync4, openSync as openSync2, readFileSync as readFileSync5, writeFileSync as writeFileSync4 } from "fs";
6741
6751
  import { homedir as homedir3 } from "os";
6742
- import { join as join5 } from "path";
6752
+ import { dirname as dirname2, join as join5 } from "path";
6753
+ import { fileURLToPath as fileURLToPath2 } from "url";
6754
+ function readState2() {
6755
+ try {
6756
+ const s = JSON.parse(readFileSync5(STATE_FILE2, "utf-8"));
6757
+ return s && typeof s === "object" ? s : {};
6758
+ } catch {
6759
+ return {};
6760
+ }
6761
+ }
6762
+ function writeState2(s) {
6763
+ try {
6764
+ mkdirSync4(DIR, { recursive: true });
6765
+ writeFileSync4(STATE_FILE2, JSON.stringify(s));
6766
+ } catch {
6767
+ }
6768
+ }
6769
+ function pidAlive(pid) {
6770
+ if (!pid || pid <= 0) return false;
6771
+ try {
6772
+ process.kill(pid, 0);
6773
+ return true;
6774
+ } catch (e) {
6775
+ return e.code === "EPERM";
6776
+ }
6777
+ }
6778
+ function logsServerStatus() {
6779
+ const s = readState2();
6780
+ const running = pidAlive(s.pid);
6781
+ return { desired: s.desired === "on" ? "on" : "off", running, pid: running ? s.pid : void 0, port: s.port || LOGS_SERVER_PORT };
6782
+ }
6783
+ function recordLogsServerStarted(port) {
6784
+ writeState2({ desired: "on", pid: process.pid, port, startedAt: Date.now() });
6785
+ }
6786
+ function startLogsServerDaemon() {
6787
+ const cur = logsServerStatus();
6788
+ if (cur.running) {
6789
+ writeState2({ ...readState2(), desired: "on" });
6790
+ return { ...cur, desired: "on" };
6791
+ }
6792
+ try {
6793
+ mkdirSync4(DIR, { recursive: true });
6794
+ const log6 = openSync2(LOG_FILE2, "a");
6795
+ const cli = join5(dirname2(fileURLToPath2(import.meta.url)), "index.js");
6796
+ const p = spawn2(process.execPath, [cli, "logs-server"], {
6797
+ detached: true,
6798
+ stdio: ["ignore", log6, log6],
6799
+ windowsHide: true
6800
+ });
6801
+ p.on("error", () => {
6802
+ });
6803
+ p.unref();
6804
+ writeState2({ desired: "on", pid: p.pid, port: LOGS_SERVER_PORT, startedAt: Date.now() });
6805
+ return { desired: "on", running: true, pid: p.pid, port: LOGS_SERVER_PORT };
6806
+ } catch {
6807
+ return { ...cur, desired: "on", running: false };
6808
+ }
6809
+ }
6810
+ function stopLogsServerDaemon() {
6811
+ const s = readState2();
6812
+ if (pidAlive(s.pid)) {
6813
+ try {
6814
+ process.kill(s.pid);
6815
+ } catch {
6816
+ }
6817
+ }
6818
+ writeState2({ desired: "off", port: s.port });
6819
+ return { desired: "off", running: false, port: s.port || LOGS_SERVER_PORT };
6820
+ }
6821
+ function ensureLogsServerDaemon() {
6822
+ try {
6823
+ const s = logsServerStatus();
6824
+ if (s.desired === "on" && !s.running) startLogsServerDaemon();
6825
+ } catch {
6826
+ }
6827
+ }
6828
+ var DIR, STATE_FILE2, LOG_FILE2, LOGS_SERVER_PORT;
6829
+ var init_logs_server_daemon = __esm({
6830
+ "src/logs-server-daemon.ts"() {
6831
+ "use strict";
6832
+ DIR = join5(homedir3(), ".solongate");
6833
+ STATE_FILE2 = join5(DIR, ".logs-server.json");
6834
+ LOG_FILE2 = join5(DIR, "logs-server.log");
6835
+ LOGS_SERVER_PORT = 8788;
6836
+ }
6837
+ });
6838
+
6839
+ // src/tui/config.ts
6840
+ import { readFileSync as readFileSync6 } from "fs";
6841
+ import { homedir as homedir4 } from "os";
6842
+ import { join as join6 } from "path";
6743
6843
  function loadConfig() {
6744
6844
  if (cached) return cached;
6745
6845
  const defaults = { notifications: true };
6746
6846
  try {
6747
- const raw = readFileSync5(join5(homedir3(), ".solongate", "tui-config.json"), "utf-8");
6847
+ const raw = readFileSync6(join6(homedir4(), ".solongate", "tui-config.json"), "utf-8");
6748
6848
  const j = JSON.parse(raw);
6749
6849
  cached = {
6750
6850
  notifications: j.notifications !== false,
@@ -6870,14 +6970,14 @@ var init_components = __esm({
6870
6970
  });
6871
6971
 
6872
6972
  // src/tui/local-log.ts
6873
- import { closeSync, openSync as openSync2, readFileSync as readFileSync6, readSync, statSync, writeFileSync as writeFileSync4 } from "fs";
6874
- import { homedir as homedir4 } from "os";
6875
- import { join as join6 } from "path";
6973
+ import { closeSync, openSync as openSync3, readFileSync as readFileSync7, readSync, statSync, writeFileSync as writeFileSync5 } from "fs";
6974
+ import { homedir as homedir5 } from "os";
6975
+ import { join as join7 } from "path";
6876
6976
  function tailLines(file, maxBytes = 131072) {
6877
6977
  try {
6878
6978
  const size = statSync(file).size;
6879
6979
  const start = Math.max(0, size - maxBytes);
6880
- const fd = openSync2(file, "r");
6980
+ const fd = openSync3(file, "r");
6881
6981
  const buf = Buffer.alloc(size - start);
6882
6982
  readSync(fd, buf, 0, buf.length, start);
6883
6983
  closeSync(fd);
@@ -6890,7 +6990,7 @@ function tailLines(file, maxBytes = 131072) {
6890
6990
  }
6891
6991
  function deleteLocalEntry(at, tool, session) {
6892
6992
  try {
6893
- const lines = readFileSync6(LOCAL_LOG, "utf-8").split("\n");
6993
+ const lines = readFileSync7(LOCAL_LOG, "utf-8").split("\n");
6894
6994
  let removed = 0;
6895
6995
  const kept = lines.filter((line) => {
6896
6996
  if (!line.trim()) return false;
@@ -6906,7 +7006,7 @@ function deleteLocalEntry(at, tool, session) {
6906
7006
  }
6907
7007
  return true;
6908
7008
  });
6909
- if (removed) writeFileSync4(LOCAL_LOG, kept.length ? kept.join("\n") + "\n" : "");
7009
+ if (removed) writeFileSync5(LOCAL_LOG, kept.length ? kept.join("\n") + "\n" : "");
6910
7010
  return removed;
6911
7011
  } catch {
6912
7012
  return 0;
@@ -6914,8 +7014,8 @@ function deleteLocalEntry(at, tool, session) {
6914
7014
  }
6915
7015
  function clearLocalLog() {
6916
7016
  try {
6917
- const n = readFileSync6(LOCAL_LOG, "utf-8").split("\n").filter(Boolean).length;
6918
- writeFileSync4(LOCAL_LOG, "");
7017
+ const n = readFileSync7(LOCAL_LOG, "utf-8").split("\n").filter(Boolean).length;
7018
+ writeFileSync5(LOCAL_LOG, "");
6919
7019
  return n;
6920
7020
  } catch {
6921
7021
  return 0;
@@ -6946,20 +7046,20 @@ var LOCAL_LOG, DLP_REASON, RL_REASON;
6946
7046
  var init_local_log = __esm({
6947
7047
  "src/tui/local-log.ts"() {
6948
7048
  "use strict";
6949
- LOCAL_LOG = join6(homedir4(), ".solongate", "local-logs", "solongate-audit.jsonl");
7049
+ LOCAL_LOG = join7(homedir5(), ".solongate", "local-logs", "solongate-audit.jsonl");
6950
7050
  DLP_REASON = /security layer \(dlp\)/i;
6951
7051
  RL_REASON = /security layer \(rate limit\)|rate[- ]?limit(?:ed)?\b.*exceed|exceeded \d+ calls/i;
6952
7052
  }
6953
7053
  });
6954
7054
 
6955
7055
  // src/api-client/client.ts
6956
- import { readFileSync as readFileSync7, writeFileSync as writeFileSync5, mkdirSync as mkdirSync4, existsSync as existsSync3 } from "fs";
6957
- import { resolve as resolve3, join as join7 } from "path";
6958
- import { homedir as homedir5 } from "os";
7056
+ import { readFileSync as readFileSync8, writeFileSync as writeFileSync6, mkdirSync as mkdirSync5, existsSync as existsSync3 } from "fs";
7057
+ import { resolve as resolve3, join as join8 } from "path";
7058
+ import { homedir as homedir6 } from "os";
6959
7059
  function listAccounts() {
6960
7060
  let list6 = [];
6961
7061
  try {
6962
- const raw = JSON.parse(readFileSync7(accountsFile(), "utf-8"));
7062
+ const raw = JSON.parse(readFileSync8(accountsFile(), "utf-8"));
6963
7063
  if (Array.isArray(raw)) list6 = raw.filter((a) => a && typeof a.apiKey === "string");
6964
7064
  } catch {
6965
7065
  }
@@ -6973,7 +7073,7 @@ function saveAccount(acc) {
6973
7073
  try {
6974
7074
  const list6 = (() => {
6975
7075
  try {
6976
- const raw = JSON.parse(readFileSync7(accountsFile(), "utf-8"));
7076
+ const raw = JSON.parse(readFileSync8(accountsFile(), "utf-8"));
6977
7077
  return Array.isArray(raw) ? raw.filter((a) => a && a.apiKey) : [];
6978
7078
  } catch {
6979
7079
  return [];
@@ -6981,8 +7081,8 @@ function saveAccount(acc) {
6981
7081
  })();
6982
7082
  const next = list6.filter((a) => a.apiKey !== acc.apiKey);
6983
7083
  next.unshift({ ...acc, addedAt: acc.addedAt ?? Date.now() });
6984
- mkdirSync4(join7(homedir5(), ".solongate"), { recursive: true });
6985
- writeFileSync5(accountsFile(), JSON.stringify(next, null, 2));
7084
+ mkdirSync5(join8(homedir6(), ".solongate"), { recursive: true });
7085
+ writeFileSync6(accountsFile(), JSON.stringify(next, null, 2));
6986
7086
  } catch {
6987
7087
  }
6988
7088
  }
@@ -6995,15 +7095,15 @@ function isActiveAccount(apiKey) {
6995
7095
  }
6996
7096
  function setActiveAccount(creds) {
6997
7097
  try {
6998
- const dir = join7(homedir5(), ".solongate");
6999
- mkdirSync4(dir, { recursive: true });
7000
- const p = join7(dir, ["cloud", "guard.json"].join("-"));
7098
+ const dir = join8(homedir6(), ".solongate");
7099
+ mkdirSync5(dir, { recursive: true });
7100
+ const p = join8(dir, ["cloud", "guard.json"].join("-"));
7001
7101
  let existing = {};
7002
7102
  try {
7003
- existing = JSON.parse(readFileSync7(p, "utf-8"));
7103
+ existing = JSON.parse(readFileSync8(p, "utf-8"));
7004
7104
  } catch {
7005
7105
  }
7006
- writeFileSync5(p, JSON.stringify({ ...existing, apiKey: creds.apiKey, apiUrl: creds.apiUrl }, null, 2));
7106
+ writeFileSync6(p, JSON.stringify({ ...existing, apiKey: creds.apiKey, apiUrl: creds.apiUrl }, null, 2));
7007
7107
  cached2 = null;
7008
7108
  return true;
7009
7109
  } catch {
@@ -7012,9 +7112,9 @@ function setActiveAccount(creds) {
7012
7112
  }
7013
7113
  function loginCredentialFile() {
7014
7114
  try {
7015
- const p = join7(homedir5(), ".solongate", "cloud-guard.json");
7115
+ const p = join8(homedir6(), ".solongate", "cloud-guard.json");
7016
7116
  if (!existsSync3(p)) return {};
7017
- const c2 = JSON.parse(readFileSync7(p, "utf-8"));
7117
+ const c2 = JSON.parse(readFileSync8(p, "utf-8"));
7018
7118
  return c2 && typeof c2 === "object" ? c2 : {};
7019
7119
  } catch {
7020
7120
  return {};
@@ -7024,7 +7124,7 @@ function dotenvApiKey() {
7024
7124
  try {
7025
7125
  const envPath = resolve3(".env");
7026
7126
  if (!existsSync3(envPath)) return void 0;
7027
- for (const line of readFileSync7(envPath, "utf-8").split("\n")) {
7127
+ for (const line of readFileSync8(envPath, "utf-8").split("\n")) {
7028
7128
  const trimmed = line.trim();
7029
7129
  if (!trimmed || trimmed.startsWith("#")) continue;
7030
7130
  const eq = trimmed.indexOf("=");
@@ -7126,7 +7226,7 @@ var init_client = __esm({
7126
7226
  "src/api-client/client.ts"() {
7127
7227
  "use strict";
7128
7228
  DEFAULT_API_URL2 = "https://api.solongate.com";
7129
- accountsFile = () => join7(homedir5(), ".solongate", "accounts.json");
7229
+ accountsFile = () => join8(homedir6(), ".solongate", "accounts.json");
7130
7230
  viewOverride = null;
7131
7231
  ApiError = class extends Error {
7132
7232
  status;
@@ -7156,12 +7256,12 @@ var init_types = __esm({
7156
7256
  });
7157
7257
 
7158
7258
  // src/api-client/device-login.ts
7159
- import { spawn as spawn2 } from "child_process";
7259
+ import { spawn as spawn3 } from "child_process";
7160
7260
  function openBrowser(url) {
7161
7261
  try {
7162
7262
  const cmd = process.platform === "win32" ? "cmd" : process.platform === "darwin" ? "open" : "xdg-open";
7163
7263
  const args = process.platform === "win32" ? ["/c", "start", '""', url] : [url];
7164
- const child = spawn2(cmd, args, { stdio: "ignore", detached: true });
7264
+ const child = spawn3(cmd, args, { stdio: "ignore", detached: true });
7165
7265
  child.on("error", () => {
7166
7266
  });
7167
7267
  child.unref();
@@ -7502,24 +7602,24 @@ var init_api_client = __esm({
7502
7602
  });
7503
7603
 
7504
7604
  // src/tui/notify.ts
7505
- import { spawn as spawn3 } from "child_process";
7605
+ import { spawn as spawn4 } from "child_process";
7506
7606
  function desktopNotify(title, msg) {
7507
7607
  try {
7508
7608
  if (process.platform === "linux") {
7509
- const p = spawn3("notify-send", ["-a", "SolonGate", title, msg], { stdio: "ignore", detached: true });
7609
+ const p = spawn4("notify-send", ["-a", "SolonGate", title, msg], { stdio: "ignore", detached: true });
7510
7610
  p.on("error", () => {
7511
7611
  });
7512
7612
  p.unref();
7513
7613
  } else if (process.platform === "win32") {
7514
7614
  const q = (s) => s.replace(/'/g, "''");
7515
7615
  const ps = `Add-Type -AssemblyName System.Windows.Forms;Add-Type -AssemblyName System.Drawing;$n=New-Object System.Windows.Forms.NotifyIcon;$n.Icon=[System.Drawing.SystemIcons]::Information;$n.Visible=$true;$n.ShowBalloonTip(6000,'${q(title)}','${q(msg)}',[System.Windows.Forms.ToolTipIcon]::Warning);Start-Sleep -Milliseconds 6500;$n.Dispose()`;
7516
- const p = spawn3("powershell", ["-NoProfile", "-NonInteractive", "-Command", ps], { stdio: "ignore", detached: true, windowsHide: true });
7616
+ const p = spawn4("powershell", ["-NoProfile", "-NonInteractive", "-Command", ps], { stdio: "ignore", detached: true, windowsHide: true });
7517
7617
  p.on("error", () => {
7518
7618
  });
7519
7619
  p.unref();
7520
7620
  } else if (process.platform === "darwin") {
7521
7621
  const esc = (s) => s.replace(/"/g, '\\"');
7522
- const p = spawn3("osascript", ["-e", `display notification "${esc(msg)}" with title "${esc(title)}"`], { stdio: "ignore", detached: true });
7622
+ const p = spawn4("osascript", ["-e", `display notification "${esc(msg)}" with title "${esc(title)}"`], { stdio: "ignore", detached: true });
7523
7623
  p.on("error", () => {
7524
7624
  });
7525
7625
  p.unref();
@@ -7605,9 +7705,9 @@ var init_hooks = __esm({
7605
7705
  // src/tui/panels/Live.tsx
7606
7706
  import { Box as Box2, Text as Text2, useInput } from "ink";
7607
7707
  import TextInput from "ink-text-input";
7608
- import { mkdirSync as mkdirSync5, writeFileSync as writeFileSync6 } from "fs";
7609
- import { homedir as homedir6 } from "os";
7610
- import { join as join8 } from "path";
7708
+ import { mkdirSync as mkdirSync6, writeFileSync as writeFileSync7 } from "fs";
7709
+ import { homedir as homedir7 } from "os";
7710
+ import { join as join9 } from "path";
7611
7711
  import { useCallback as useCallback2, useEffect as useEffect2, useRef as useRef2, useState as useState2 } from "react";
7612
7712
  import { Fragment as Fragment2, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
7613
7713
  function extractTarget(detail) {
@@ -8198,10 +8298,10 @@ function LivePanel({ active: active2 }) {
8198
8298
  else if (input === "x") toggleSignal("dlp");
8199
8299
  else if (input === "r") toggleSignal("ratelimit");
8200
8300
  else if (input === "e") {
8201
- const file = join8(homedir6(), ".solongate", "live-export.jsonl");
8301
+ const file = join9(homedir7(), ".solongate", "live-export.jsonl");
8202
8302
  try {
8203
- mkdirSync5(join8(homedir6(), ".solongate"), { recursive: true });
8204
- writeFileSync6(file, visibleDesc.map((x) => JSON.stringify(x)).join("\n") + "\n");
8303
+ mkdirSync6(join9(homedir7(), ".solongate"), { recursive: true });
8304
+ writeFileSync7(file, visibleDesc.map((x) => JSON.stringify(x)).join("\n") + "\n");
8205
8305
  setActionMsg({ text: `\u2713 exported ${visibleDesc.length} lines \u2192 ${file}`, level: "ok", until: Date.now() + 6e3 });
8206
8306
  } catch (err2) {
8207
8307
  setActionMsg({ text: "\u2717 export failed: " + (err2 instanceof Error ? err2.message : String(err2)), level: "bad", until: Date.now() + 6e3 });
@@ -8611,7 +8711,7 @@ var init_Live = __esm({
8611
8711
  SPIN = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
8612
8712
  BG = "#12234f";
8613
8713
  DIM_FLOOR = "#233457";
8614
- RING = join8(process.cwd(), ".solongate", ".eval-ring.jsonl");
8714
+ RING = join9(process.cwd(), ".solongate", ".eval-ring.jsonl");
8615
8715
  hhmmss = (ts) => {
8616
8716
  const d = new Date(ts);
8617
8717
  return Number.isNaN(d.getTime()) ? "--:--:--" : d.toTimeString().slice(0, 8);
@@ -9301,9 +9401,9 @@ var init_Dlp = __esm({
9301
9401
  // src/tui/panels/Audit.tsx
9302
9402
  import { Box as Box6, Text as Text6, useInput as useInput5 } from "ink";
9303
9403
  import TextInput4 from "ink-text-input";
9304
- import { mkdirSync as mkdirSync6, writeFileSync as writeFileSync7 } from "fs";
9305
- import { homedir as homedir7 } from "os";
9306
- import { join as join9 } from "path";
9404
+ import { mkdirSync as mkdirSync7, writeFileSync as writeFileSync8 } from "fs";
9405
+ import { homedir as homedir8 } from "os";
9406
+ import { join as join10 } from "path";
9307
9407
  import { useState as useState6 } from "react";
9308
9408
  import { Fragment as Fragment4, jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
9309
9409
  function loadLocalRows() {
@@ -9457,16 +9557,16 @@ function AuditPanel({ active: active2, focused }) {
9457
9557
  const doExport = (kind) => {
9458
9558
  setMsg({ text: "exporting\u2026", level: "ok" });
9459
9559
  const run12 = async () => {
9460
- const dir = join9(homedir7(), ".solongate");
9461
- const file = join9(dir, `audit-export-${source}.jsonl`);
9560
+ const dir = join10(homedir8(), ".solongate");
9561
+ const file = join10(dir, `audit-export-${source}.jsonl`);
9462
9562
  let rows2;
9463
9563
  if (kind === "page") rows2 = pageRows;
9464
9564
  else if (source === "cloud") {
9465
9565
  const r = await api.audit.list({ ...query, limit: 1e4, offset: 0 });
9466
9566
  rows2 = r.entries.map(cloudRow).sort((a, b) => b.at - a.at);
9467
9567
  } else rows2 = localFiltered;
9468
- mkdirSync6(dir, { recursive: true });
9469
- writeFileSync7(file, rows2.map((x) => JSON.stringify(x)).join("\n") + (rows2.length ? "\n" : ""));
9568
+ mkdirSync7(dir, { recursive: true });
9569
+ writeFileSync8(file, rows2.map((x) => JSON.stringify(x)).join("\n") + (rows2.length ? "\n" : ""));
9470
9570
  return { n: rows2.length, file };
9471
9571
  };
9472
9572
  run12().then(({ n, file }) => setMsg({ text: `\u2713 exported ${n} rows \u2192 ${file}`, level: "ok" })).catch((e) => setMsg({ text: "\u2717 export failed: " + (e instanceof Error ? e.message : String(e)), level: "bad" }));
@@ -9956,8 +10056,8 @@ var init_Audit = __esm({
9956
10056
  // src/tui/panels/Settings.tsx
9957
10057
  import { Box as Box7, Text as Text7, useInput as useInput6 } from "ink";
9958
10058
  import TextInput5 from "ink-text-input";
9959
- import { useState as useState7 } from "react";
9960
- import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
10059
+ import { useEffect as useEffect6, useRef as useRef3, useState as useState7 } from "react";
10060
+ import { Fragment as Fragment5, jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
9961
10061
  function alertBodyFor(channel) {
9962
10062
  const c2 = channel.trim();
9963
10063
  const base = { name: "dataroom alert", threshold: 5, windowSeconds: 60, signal: "any" };
@@ -9965,7 +10065,12 @@ function alertBodyFor(channel) {
9965
10065
  if (c2.includes("@")) return { ...base, emails: [c2] };
9966
10066
  return { ...base, telegram: [c2] };
9967
10067
  }
9968
- function SettingsPanel({ active: active2, focused }) {
10068
+ function SettingsPanel({
10069
+ active: active2,
10070
+ focused,
10071
+ viewApiKey,
10072
+ onView
10073
+ }) {
9969
10074
  void active2;
9970
10075
  const { cols, rows } = usePanelSize();
9971
10076
  const [sel, setSel] = useState7(0);
@@ -9974,24 +10079,46 @@ function SettingsPanel({ active: active2, focused }) {
9974
10079
  const [confirmDel, setConfirmDel] = useState7(null);
9975
10080
  const [msg, setMsg] = useState7(null);
9976
10081
  const [busy, setBusy] = useState7(false);
9977
- const localQ = useLoader(() => api.settings.getLocalLogs());
9978
- const whQ = useLoader(() => api.settings.getWebhooks());
9979
- const alertQ = useLoader(() => api.settings.getAlerts());
10082
+ const [accounts, setAccounts] = useState7(() => listAccounts());
10083
+ const [login, setLogin] = useState7(null);
10084
+ const [tick, setTick] = useState7(0);
10085
+ const abort = useRef3(false);
10086
+ const refreshAccounts = () => setAccounts(listAccounts());
10087
+ const locked = accounts.length === 0;
10088
+ const [srv, setSrv] = useState7(() => logsServerStatus());
10089
+ useEffect6(() => {
10090
+ const t = setInterval(() => setSrv(logsServerStatus()), 3e3);
10091
+ return () => clearInterval(t);
10092
+ }, []);
10093
+ useEffect6(() => {
10094
+ if (!login || login.phase === "done" || login.phase === "error") return;
10095
+ const t = setInterval(() => setTick((n) => n + 1), 120);
10096
+ return () => clearInterval(t);
10097
+ }, [login]);
10098
+ const localQ = useLoader(() => listAccounts().length ? api.settings.getLocalLogs() : Promise.resolve(null));
10099
+ const whQ = useLoader(() => listAccounts().length ? api.settings.getWebhooks() : Promise.resolve(null));
10100
+ const alertQ = useLoader(() => listAccounts().length ? api.settings.getAlerts() : Promise.resolve(null));
9980
10101
  const local = localQ.data;
9981
10102
  const webhooks = whQ.data?.webhooks ?? [];
9982
10103
  const alerts = alertQ.data?.rules ?? [];
9983
10104
  const rowsAll = [
9984
- { kind: "ll-enabled" },
9985
- { kind: "ll-path" },
9986
- ...webhooks.map((wh) => ({ kind: "wh", wh })),
9987
- { kind: "wh-add" },
9988
- ...alerts.map((rule) => ({ kind: "alert", rule })),
9989
- { kind: "alert-add" }
10105
+ ...accounts.map((acc) => ({ kind: "acct", acc })),
10106
+ { kind: "acct-add" },
10107
+ ...locked ? [] : [
10108
+ { kind: "ll-enabled" },
10109
+ { kind: "ll-path" },
10110
+ { kind: "ll-server" },
10111
+ ...webhooks.map((wh) => ({ kind: "wh", wh })),
10112
+ { kind: "wh-add" },
10113
+ ...alerts.map((rule) => ({ kind: "alert", rule })),
10114
+ { kind: "alert-add" }
10115
+ ]
9990
10116
  ];
9991
10117
  const selClamped = Math.min(sel, rowsAll.length - 1);
9992
10118
  const cur = rowsAll[selClamped];
9993
- const keyOf = (r) => r.kind === "wh" ? "wh:" + r.wh.id : r.kind === "alert" ? "alert:" + r.rule.id : r.kind;
10119
+ const keyOf = (r) => r.kind === "acct" ? "acct:" + r.acc.apiKey : r.kind === "wh" ? "wh:" + r.wh.id : r.kind === "alert" ? "alert:" + r.rule.id : r.kind;
9994
10120
  const reloadAll = () => {
10121
+ refreshAccounts();
9995
10122
  localQ.reload();
9996
10123
  whQ.reload();
9997
10124
  alertQ.reload();
@@ -10005,8 +10132,48 @@ function SettingsPanel({ active: active2, focused }) {
10005
10132
  reload();
10006
10133
  }).catch((e) => setMsg({ text: "\u2717 " + (e instanceof Error ? e.message : String(e)), level: "bad" })).finally(() => setBusy(false));
10007
10134
  };
10135
+ const beginLogin = () => {
10136
+ if (login && (login.phase === "starting" || login.phase === "waiting")) return;
10137
+ abort.current = false;
10138
+ setLogin({ phase: "starting" });
10139
+ void (async () => {
10140
+ let start2;
10141
+ try {
10142
+ start2 = await startDeviceLogin(DEFAULT_API_URL2);
10143
+ } catch (e) {
10144
+ setLogin({ phase: "error", msg: "could not reach SolonGate: " + (e instanceof Error ? e.message : String(e)) });
10145
+ return;
10146
+ }
10147
+ setLogin({ phase: "waiting", url: start2.verifyUrl });
10148
+ openBrowser(start2.verifyUrl);
10149
+ while (Date.now() < start2.expiresAt && !abort.current) {
10150
+ await new Promise((r) => setTimeout(r, start2.intervalMs));
10151
+ if (abort.current) return;
10152
+ const res = await pollDeviceLogin(DEFAULT_API_URL2, start2.deviceCode);
10153
+ if (res.status === "approved" && res.apiKey) {
10154
+ saveAccount({ apiKey: res.apiKey, apiUrl: DEFAULT_API_URL2, project: res.project, user: res.user, email: res.email });
10155
+ setLogin({ phase: "done", msg: `\u2713 added ${res.email || res.user || res.project || "account"}` });
10156
+ setViewCredentials({ apiKey: res.apiKey, apiUrl: DEFAULT_API_URL2 });
10157
+ onView?.({ apiKey: res.apiKey, apiUrl: DEFAULT_API_URL2, project: res.project, user: res.user, email: res.email });
10158
+ reloadAll();
10159
+ return;
10160
+ }
10161
+ if (res.status === "expired" || res.status === "not_found") {
10162
+ setLogin({ phase: "error", msg: "code expired \u2014 press n to retry" });
10163
+ return;
10164
+ }
10165
+ }
10166
+ if (!abort.current) setLogin({ phase: "error", msg: "timed out \u2014 press n to retry" });
10167
+ })();
10168
+ };
10008
10169
  const activate = (r) => {
10009
- if (r.kind === "ll-enabled") {
10170
+ if (r.kind === "acct") {
10171
+ setViewCredentials({ apiKey: r.acc.apiKey, apiUrl: r.acc.apiUrl });
10172
+ onView?.(r.acc);
10173
+ setMsg({ text: `viewing ${acctLabel(r.acc)}`, level: "ok" });
10174
+ } else if (r.kind === "acct-add") {
10175
+ beginLogin();
10176
+ } else if (r.kind === "ll-enabled") {
10010
10177
  if (!local) return;
10011
10178
  if (!local.enabled && !local.path.trim()) {
10012
10179
  setMsg({ text: "set a path first (\u2193 then enter)", level: "bad" });
@@ -10016,6 +10183,12 @@ function SettingsPanel({ active: active2, focused }) {
10016
10183
  } else if (r.kind === "ll-path") {
10017
10184
  setInput(local?.path ?? "");
10018
10185
  setEditing("path");
10186
+ } else if (r.kind === "ll-server") {
10187
+ const next = srv.running ? stopLogsServerDaemon() : startLogsServerDaemon();
10188
+ setSrv(next);
10189
+ setMsg(
10190
+ next.running ? { text: `\u2713 dashboard link running on 127.0.0.1:${next.port} \u2014 keeps running after you close the dataroom`, level: "ok" } : { text: "\u2713 dashboard link stopped (disabled until you start it again)", level: "ok" }
10191
+ );
10019
10192
  } else if (r.kind === "wh") {
10020
10193
  run12(r.wh.enabled ? "webhook disabled" : "webhook enabled", () => api.settings.updateWebhook(r.wh.id, { enabled: !r.wh.enabled }), whQ.reload);
10021
10194
  } else if (r.kind === "wh-add") {
@@ -10045,6 +10218,13 @@ function SettingsPanel({ active: active2, focused }) {
10045
10218
  };
10046
10219
  useInput6(
10047
10220
  (inp, key) => {
10221
+ if (login && (login.phase === "starting" || login.phase === "waiting")) {
10222
+ if (key.escape) {
10223
+ abort.current = true;
10224
+ setLogin(null);
10225
+ }
10226
+ return;
10227
+ }
10048
10228
  setMsg(null);
10049
10229
  if (key.upArrow) {
10050
10230
  setSel((n) => Math.max(0, n - 1));
@@ -10053,6 +10233,11 @@ function SettingsPanel({ active: active2, focused }) {
10053
10233
  setSel((n) => Math.min(rowsAll.length - 1, n + 1));
10054
10234
  setConfirmDel(null);
10055
10235
  } else if (key.return || inp === " ") activate(cur);
10236
+ else if (inp === "m" && cur.kind === "acct") {
10237
+ const ok = setActiveAccount({ apiKey: cur.acc.apiKey, apiUrl: cur.acc.apiUrl });
10238
+ setMsg(ok ? { text: `\u2713 ${acctLabel(cur.acc)} is now the ACTIVE key (guard + logging)`, level: "ok" } : { text: "\u2717 could not set active", level: "bad" });
10239
+ refreshAccounts();
10240
+ } else if (inp === "n") beginLogin();
10056
10241
  else if (inp === "e" && cur.kind === "wh") {
10057
10242
  const next = EVENTS[(EVENTS.indexOf(cur.wh.events) + 1) % EVENTS.length];
10058
10243
  run12(`webhook events \u2192 ${next}`, () => api.settings.updateWebhook(cur.wh.id, { events: next }), whQ.reload);
@@ -10079,247 +10264,170 @@ function SettingsPanel({ active: active2, focused }) {
10079
10264
  },
10080
10265
  { isActive: focused && !editing }
10081
10266
  );
10082
- const loading = localQ.loading && !localQ.data || whQ.loading && !whQ.data || alertQ.loading && !alertQ.data;
10083
- const error = localQ.error ?? whQ.error ?? alertQ.error;
10267
+ const spin = SPIN2[tick % SPIN2.length];
10268
+ if (login && (login.phase === "starting" || login.phase === "waiting")) {
10269
+ return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
10270
+ /* @__PURE__ */ jsx7(Text7, { bold: true, color: theme.accentBright, children: "Add an account" }),
10271
+ login.phase === "starting" ? /* @__PURE__ */ jsxs7(Text7, { color: theme.dim, children: [
10272
+ spin,
10273
+ " starting device pairing\u2026"
10274
+ ] }) : /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", marginTop: 1, children: [
10275
+ /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "Opening your browser to authorize. If it didn't open, visit:" }),
10276
+ /* @__PURE__ */ jsx7(Text7, { color: theme.accentBright, bold: true, wrap: "truncate", children: login.url }),
10277
+ /* @__PURE__ */ jsxs7(Box7, { marginTop: 1, children: [
10278
+ /* @__PURE__ */ jsxs7(Text7, { color: theme.warn, children: [
10279
+ spin,
10280
+ " waiting for authorization\u2026 "
10281
+ ] }),
10282
+ /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "esc to cancel" })
10283
+ ] })
10284
+ ] })
10285
+ ] });
10286
+ }
10287
+ const loading = !locked && (localQ.loading && !localQ.data || whQ.loading && !whQ.data || alertQ.loading && !alertQ.data);
10288
+ const error = locked ? null : localQ.error ?? whQ.error ?? alertQ.error;
10084
10289
  const mark = (r) => keyOf(r) === keyOf(cur) && focused ? "\u25B8 " : " ";
10085
10290
  const onOff = (on) => on ? /* @__PURE__ */ jsx7(Text7, { color: theme.ok, children: "on " }) : /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "off" });
10086
10291
  const chanOf = (rule) => [...(rule.slackUrls ?? []).map((u) => "slack " + u), ...rule.emails ?? [], ...(rule.telegram ?? []).map((t) => "tg " + t)].join(", ") || "\u2014";
10087
- const listBudget = Math.max(4, rows - 8);
10292
+ const listBudget = Math.max(4, rows - 10);
10088
10293
  const start = Math.min(Math.max(0, selClamped - Math.floor(listBudget / 2)), Math.max(0, rowsAll.length - listBudget));
10089
10294
  const inWindow = (r) => {
10090
10295
  const i = rowsAll.findIndex((x) => keyOf(x) === keyOf(r));
10091
10296
  return i >= start && i < start + listBudget;
10092
10297
  };
10093
10298
  return /* @__PURE__ */ jsx7(DataView, { loading, error, children: /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
10094
- /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: focused ? "\u2191\u2193 move \xB7 enter/space toggle-edit-add \xB7 e events \xB7 d delete \xB7 r refresh" : "press \u2192 to configure" }),
10299
+ /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: focused ? "\u2191\u2193 move \xB7 enter view-toggle-edit \xB7 m make active \xB7 n add account \xB7 e events \xB7 d delete \xB7 r refresh" : "press \u2192 to configure" }),
10095
10300
  editing ? /* @__PURE__ */ jsxs7(Box7, { children: [
10096
10301
  /* @__PURE__ */ jsx7(Text7, { color: theme.warn, children: editing === "path" ? "local log path: " : editing === "wh-url" ? "webhook url: " : "channel (slack url / email / telegram id): " }),
10097
10302
  /* @__PURE__ */ jsx7(TextInput5, { value: input, onChange: setInput, onSubmit: submitInput })
10098
- ] }) : msg ? /* @__PURE__ */ jsx7(Text7, { color: msg.level === "bad" ? theme.bad : theme.ok, children: truncate2(msg.text, cols) }) : /* @__PURE__ */ jsx7(Text7, { children: " " }),
10099
- inWindow(rowsAll[0]) || inWindow(rowsAll[1]) ? /* @__PURE__ */ jsxs7(Box7, { marginTop: 1, flexDirection: "column", children: [
10100
- /* @__PURE__ */ jsxs7(Text7, { bold: true, color: theme.accentBright, children: [
10101
- "LOCAL LOGS ",
10102
- /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "\u2014 hooks mirror every decision to a file on the agent machine" })
10103
- ] }),
10104
- /* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
10105
- /* @__PURE__ */ jsx7(Text7, { color: keyOf(cur) === "ll-enabled" && focused ? theme.accentBright : theme.dim, children: mark(rowsAll[0]) }),
10106
- /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "enabled ".padEnd(10) }),
10107
- onOff(!!local?.enabled),
10108
- /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: " enter toggles" })
10109
- ] }),
10110
- /* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
10111
- /* @__PURE__ */ jsx7(Text7, { color: keyOf(cur) === "ll-path" && focused ? theme.accentBright : theme.dim, children: mark(rowsAll[1]) }),
10112
- /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "path ".padEnd(10) }),
10113
- local?.path ? /* @__PURE__ */ jsx7(Text7, { color: theme.accent, children: truncate2(local.path, cols - 14) }) : /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "not set \u2014 enter to edit" })
10114
- ] })
10115
- ] }) : null,
10303
+ ] }) : msg ? /* @__PURE__ */ jsx7(Text7, { color: msg.level === "bad" ? theme.bad : theme.ok, children: truncate2(msg.text, cols) }) : login?.msg ? /* @__PURE__ */ jsx7(Text7, { color: login.phase === "error" ? theme.bad : theme.ok, children: login.msg }) : /* @__PURE__ */ jsx7(Text7, { children: " " }),
10116
10304
  /* @__PURE__ */ jsxs7(Box7, { marginTop: 1, flexDirection: "column", children: [
10117
10305
  /* @__PURE__ */ jsxs7(Text7, { bold: true, color: theme.accentBright, children: [
10118
- "WEBHOOKS ",
10306
+ "ACCOUNTS ",
10119
10307
  /* @__PURE__ */ jsxs7(Text7, { color: theme.dim, children: [
10120
- "\u2014 POST every matching event to your endpoint (",
10121
- webhooks.length,
10122
- ")"
10308
+ "\u2014 logged in on this device (",
10309
+ accounts.length,
10310
+ ") \xB7 \u25CF viewing = shown here \xB7 ACTIVE = key the guard uses"
10123
10311
  ] })
10124
10312
  ] }),
10125
- webhooks.filter((wh) => inWindow({ kind: "wh", wh })).map((wh) => /* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
10126
- /* @__PURE__ */ jsx7(Text7, { color: keyOf(cur) === "wh:" + wh.id && focused ? theme.accentBright : theme.dim, children: mark({ kind: "wh", wh }) }),
10127
- onOff(wh.enabled),
10128
- /* @__PURE__ */ jsx7(Text7, { color: theme.warn, children: (" " + wh.events).padEnd(9) }),
10129
- /* @__PURE__ */ jsx7(Text7, { color: theme.accent, children: truncate2(wh.url, cols - 16) })
10130
- ] }, wh.id)),
10131
- inWindow(rowsAll.find((r) => r.kind === "wh-add")) ? /* @__PURE__ */ jsxs7(Text7, { children: [
10132
- /* @__PURE__ */ jsx7(Text7, { color: cur.kind === "wh-add" && focused ? theme.accentBright : theme.dim, children: mark({ kind: "wh-add" }) }),
10133
- /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "+ add webhook (enter)" })
10313
+ accounts.length === 0 ? /* @__PURE__ */ jsxs7(Text7, { children: [
10314
+ /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: " no accounts yet \u2014 " }),
10315
+ /* @__PURE__ */ jsx7(Text7, { color: theme.accent, children: "n" }),
10316
+ /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: " (or enter) logs in, pairs this device and unlocks the dataroom" })
10317
+ ] }) : null,
10318
+ accounts.filter((acc) => inWindow({ kind: "acct", acc })).map((a) => {
10319
+ const isView = viewApiKey ? a.apiKey === viewApiKey : accounts[0]?.apiKey === a.apiKey;
10320
+ const isActive = isActiveAccount(a.apiKey);
10321
+ return /* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
10322
+ /* @__PURE__ */ jsx7(Text7, { color: keyOf(cur) === "acct:" + a.apiKey && focused ? theme.accentBright : theme.dim, children: mark({ kind: "acct", acc: a }) }),
10323
+ /* @__PURE__ */ jsx7(Text7, { color: theme.accent, children: truncate2(acctLabel(a), 30).padEnd(31) }),
10324
+ isView ? /* @__PURE__ */ jsx7(Text7, { color: theme.ok, children: "\u25CF viewing " }) : /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: " " }),
10325
+ isActive ? /* @__PURE__ */ jsx7(Text7, { color: theme.warn, children: "ACTIVE " }) : /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: " " }),
10326
+ /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: a.project ? truncate2(a.project, 24) : "" })
10327
+ ] }, a.apiKey);
10328
+ }),
10329
+ inWindow({ kind: "acct-add" }) ? /* @__PURE__ */ jsxs7(Text7, { children: [
10330
+ /* @__PURE__ */ jsx7(Text7, { color: cur.kind === "acct-add" && focused ? theme.accentBright : theme.dim, children: mark({ kind: "acct-add" }) }),
10331
+ /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "+ add account (enter \u2014 device login in the browser)" })
10134
10332
  ] }) : null
10135
10333
  ] }),
10136
- /* @__PURE__ */ jsxs7(Box7, { marginTop: 1, flexDirection: "column", children: [
10137
- /* @__PURE__ */ jsxs7(Text7, { bold: true, color: theme.accentBright, children: [
10138
- "ALERTS ",
10139
- /* @__PURE__ */ jsxs7(Text7, { color: theme.dim, children: [
10140
- "\u2014 notify on a signal spike (",
10141
- alerts.length,
10142
- ")"
10334
+ locked ? null : /* @__PURE__ */ jsxs7(Fragment5, { children: [
10335
+ inWindow({ kind: "ll-enabled" }) || inWindow({ kind: "ll-path" }) || inWindow({ kind: "ll-server" }) ? /* @__PURE__ */ jsxs7(Box7, { marginTop: 1, flexDirection: "column", children: [
10336
+ /* @__PURE__ */ jsxs7(Text7, { bold: true, color: theme.accentBright, children: [
10337
+ "LOCAL LOGS ",
10338
+ /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "\u2014 hooks mirror every decision to a file on the agent machine" })
10339
+ ] }),
10340
+ /* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
10341
+ /* @__PURE__ */ jsx7(Text7, { color: keyOf(cur) === "ll-enabled" && focused ? theme.accentBright : theme.dim, children: mark({ kind: "ll-enabled" }) }),
10342
+ /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "enabled ".padEnd(10) }),
10343
+ onOff(!!local?.enabled),
10344
+ /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: " enter toggles" })
10345
+ ] }),
10346
+ /* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
10347
+ /* @__PURE__ */ jsx7(Text7, { color: keyOf(cur) === "ll-path" && focused ? theme.accentBright : theme.dim, children: mark({ kind: "ll-path" }) }),
10348
+ /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "path ".padEnd(10) }),
10349
+ local?.path ? /* @__PURE__ */ jsx7(Text7, { color: theme.accent, children: truncate2(local.path, cols - 14) }) : /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "not set \u2014 enter to edit" })
10350
+ ] }),
10351
+ /* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
10352
+ /* @__PURE__ */ jsx7(Text7, { color: keyOf(cur) === "ll-server" && focused ? theme.accentBright : theme.dim, children: mark({ kind: "ll-server" }) }),
10353
+ /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "dashboard".padEnd(10) }),
10354
+ srv.running ? /* @__PURE__ */ jsx7(Text7, { color: theme.ok, children: `running 127.0.0.1:${srv.port}` }) : /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "stopped" }),
10355
+ /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: srv.running ? " serves local logs to the dashboard \xB7 survives closing the dataroom \xB7 enter stops" : " enter starts the local-logs link for the dashboard" })
10143
10356
  ] })
10357
+ ] }) : null,
10358
+ /* @__PURE__ */ jsxs7(Box7, { marginTop: 1, flexDirection: "column", children: [
10359
+ /* @__PURE__ */ jsxs7(Text7, { bold: true, color: theme.accentBright, children: [
10360
+ "WEBHOOKS ",
10361
+ /* @__PURE__ */ jsxs7(Text7, { color: theme.dim, children: [
10362
+ "\u2014 POST every matching event to your endpoint (",
10363
+ webhooks.length,
10364
+ ")"
10365
+ ] })
10366
+ ] }),
10367
+ webhooks.filter((wh) => inWindow({ kind: "wh", wh })).map((wh) => /* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
10368
+ /* @__PURE__ */ jsx7(Text7, { color: keyOf(cur) === "wh:" + wh.id && focused ? theme.accentBright : theme.dim, children: mark({ kind: "wh", wh }) }),
10369
+ onOff(wh.enabled),
10370
+ /* @__PURE__ */ jsx7(Text7, { color: theme.warn, children: (" " + wh.events).padEnd(9) }),
10371
+ /* @__PURE__ */ jsx7(Text7, { color: theme.accent, children: truncate2(wh.url, cols - 16) })
10372
+ ] }, wh.id)),
10373
+ inWindow({ kind: "wh-add" }) ? /* @__PURE__ */ jsxs7(Text7, { children: [
10374
+ /* @__PURE__ */ jsx7(Text7, { color: cur.kind === "wh-add" && focused ? theme.accentBright : theme.dim, children: mark({ kind: "wh-add" }) }),
10375
+ /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "+ add webhook (enter)" })
10376
+ ] }) : null
10144
10377
  ] }),
10145
- alerts.filter((rule) => inWindow({ kind: "alert", rule })).map((rule) => /* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
10146
- /* @__PURE__ */ jsx7(Text7, { color: keyOf(cur) === "alert:" + rule.id && focused ? theme.accentBright : theme.dim, children: mark({ kind: "alert", rule }) }),
10147
- onOff(rule.enabled),
10148
- /* @__PURE__ */ jsx7(Text7, { color: theme.warn, children: (" " + rule.signal).padEnd(11) }),
10149
- /* @__PURE__ */ jsx7(Text7, { children: `\u2265${rule.threshold}/${rule.windowSeconds}s ` }),
10150
- /* @__PURE__ */ jsx7(Text7, { color: theme.accent, children: truncate2(chanOf(rule), cols - 26) })
10151
- ] }, rule.id)),
10152
- inWindow(rowsAll[rowsAll.length - 1]) ? /* @__PURE__ */ jsxs7(Text7, { children: [
10153
- /* @__PURE__ */ jsx7(Text7, { color: cur.kind === "alert-add" && focused ? theme.accentBright : theme.dim, children: mark({ kind: "alert-add" }) }),
10154
- /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "+ add alert (enter \u2014 one channel: slack url, email or telegram chat id)" })
10155
- ] }) : null
10378
+ /* @__PURE__ */ jsxs7(Box7, { marginTop: 1, flexDirection: "column", children: [
10379
+ /* @__PURE__ */ jsxs7(Text7, { bold: true, color: theme.accentBright, children: [
10380
+ "ALERTS ",
10381
+ /* @__PURE__ */ jsxs7(Text7, { color: theme.dim, children: [
10382
+ "\u2014 notify on a signal spike (",
10383
+ alerts.length,
10384
+ ")"
10385
+ ] })
10386
+ ] }),
10387
+ alerts.filter((rule) => inWindow({ kind: "alert", rule })).map((rule) => /* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
10388
+ /* @__PURE__ */ jsx7(Text7, { color: keyOf(cur) === "alert:" + rule.id && focused ? theme.accentBright : theme.dim, children: mark({ kind: "alert", rule }) }),
10389
+ onOff(rule.enabled),
10390
+ /* @__PURE__ */ jsx7(Text7, { color: theme.warn, children: (" " + rule.signal).padEnd(11) }),
10391
+ /* @__PURE__ */ jsx7(Text7, { children: `\u2265${rule.threshold}/${rule.windowSeconds}s ` }),
10392
+ /* @__PURE__ */ jsx7(Text7, { color: theme.accent, children: truncate2(chanOf(rule), cols - 26) })
10393
+ ] }, rule.id)),
10394
+ inWindow({ kind: "alert-add" }) ? /* @__PURE__ */ jsxs7(Text7, { children: [
10395
+ /* @__PURE__ */ jsx7(Text7, { color: cur.kind === "alert-add" && focused ? theme.accentBright : theme.dim, children: mark({ kind: "alert-add" }) }),
10396
+ /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "+ add alert (enter \u2014 one channel: slack url, email or telegram chat id)" })
10397
+ ] }) : null
10398
+ ] })
10156
10399
  ] })
10157
10400
  ] }) });
10158
10401
  }
10159
- var EVENTS;
10402
+ var EVENTS, SPIN2, acctLabel;
10160
10403
  var init_Settings = __esm({
10161
10404
  "src/tui/panels/Settings.tsx"() {
10162
10405
  "use strict";
10163
10406
  init_api_client();
10407
+ init_client();
10408
+ init_device_login();
10409
+ init_logs_server_daemon();
10164
10410
  init_components();
10165
10411
  init_hooks();
10166
10412
  init_theme();
10167
10413
  EVENTS = ["denials", "allowed", "all"];
10168
- }
10169
- });
10170
-
10171
- // src/tui/panels/Accounts.tsx
10172
- import { Box as Box8, Text as Text8, useInput as useInput7 } from "ink";
10173
- import { useEffect as useEffect6, useRef as useRef3, useState as useState8 } from "react";
10174
- import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
10175
- function AccountsPanel({
10176
- focused,
10177
- viewApiKey,
10178
- onView
10179
- }) {
10180
- const [accounts, setAccounts] = useState8(() => listAccounts());
10181
- const [sel, setSel] = useState8(0);
10182
- const [msg, setMsg] = useState8(null);
10183
- const [login, setLogin] = useState8(null);
10184
- const [tick, setTick] = useState8(0);
10185
- const abort = useRef3(false);
10186
- const refresh = () => setAccounts(listAccounts());
10187
- useEffect6(() => {
10188
- if (!login || login.phase === "done" || login.phase === "error") return;
10189
- const t = setInterval(() => setTick((n) => n + 1), 120);
10190
- return () => clearInterval(t);
10191
- }, [login]);
10192
- const beginLogin = () => {
10193
- if (login && (login.phase === "starting" || login.phase === "waiting")) return;
10194
- abort.current = false;
10195
- setLogin({ phase: "starting" });
10196
- void (async () => {
10197
- let start;
10198
- try {
10199
- start = await startDeviceLogin(DEFAULT_API_URL2);
10200
- } catch (e) {
10201
- setLogin({ phase: "error", msg: "could not reach SolonGate: " + (e instanceof Error ? e.message : String(e)) });
10202
- return;
10203
- }
10204
- setLogin({ phase: "waiting", url: start.verifyUrl });
10205
- openBrowser(start.verifyUrl);
10206
- while (Date.now() < start.expiresAt && !abort.current) {
10207
- await new Promise((r) => setTimeout(r, start.intervalMs));
10208
- if (abort.current) return;
10209
- const res = await pollDeviceLogin(DEFAULT_API_URL2, start.deviceCode);
10210
- if (res.status === "approved" && res.apiKey) {
10211
- saveAccount({ apiKey: res.apiKey, apiUrl: DEFAULT_API_URL2, project: res.project, user: res.user, email: res.email });
10212
- setLogin({ phase: "done", msg: `\u2713 added ${res.email || res.user || res.project || "account"}` });
10213
- refresh();
10214
- setViewCredentials({ apiKey: res.apiKey, apiUrl: DEFAULT_API_URL2 });
10215
- onView?.({ apiKey: res.apiKey, apiUrl: DEFAULT_API_URL2, project: res.project, user: res.user, email: res.email });
10216
- return;
10217
- }
10218
- if (res.status === "expired" || res.status === "not_found") {
10219
- setLogin({ phase: "error", msg: "code expired \u2014 press n to retry" });
10220
- return;
10221
- }
10222
- }
10223
- if (!abort.current) setLogin({ phase: "error", msg: "timed out \u2014 press n to retry" });
10224
- })();
10225
- };
10226
- useInput7(
10227
- (input, key) => {
10228
- if (login && (login.phase === "starting" || login.phase === "waiting")) {
10229
- if (key.escape) {
10230
- abort.current = true;
10231
- setLogin(null);
10232
- }
10233
- return;
10234
- }
10235
- if (key.upArrow) setSel((n) => Math.max(0, n - 1));
10236
- else if (key.downArrow) setSel((n) => Math.min(accounts.length - 1, n + 1));
10237
- else if (key.return) {
10238
- const a = accounts[sel];
10239
- if (a) {
10240
- setViewCredentials({ apiKey: a.apiKey, apiUrl: a.apiUrl });
10241
- onView?.(a);
10242
- setMsg({ text: `viewing ${a.email || a.user || a.project || "account \u2026" + a.apiKey.slice(-4)}`, level: "ok" });
10243
- }
10244
- } else if (input === "m") {
10245
- const a = accounts[sel];
10246
- if (a) {
10247
- const ok = setActiveAccount({ apiKey: a.apiKey, apiUrl: a.apiUrl });
10248
- setMsg(ok ? { text: `\u2713 ${a.email || a.user || a.project || "account"} is now the ACTIVE key (guard + logging)`, level: "ok" } : { text: "\u2717 could not set active", level: "bad" });
10249
- refresh();
10250
- }
10251
- } else if (input === "n") beginLogin();
10252
- else if (input === "r") refresh();
10253
- },
10254
- { isActive: focused }
10255
- );
10256
- const spin = SPIN2[tick % SPIN2.length];
10257
- if (login && (login.phase === "starting" || login.phase === "waiting")) {
10258
- return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
10259
- /* @__PURE__ */ jsx8(Text8, { bold: true, color: theme.accentBright, children: "Add an account" }),
10260
- login.phase === "starting" ? /* @__PURE__ */ jsxs8(Text8, { color: theme.dim, children: [
10261
- spin,
10262
- " starting device pairing\u2026"
10263
- ] }) : /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", marginTop: 1, children: [
10264
- /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "Opening your browser to authorize. If it didn't open, visit:" }),
10265
- /* @__PURE__ */ jsx8(Text8, { color: theme.accentBright, bold: true, wrap: "truncate", children: login.url }),
10266
- /* @__PURE__ */ jsxs8(Box8, { marginTop: 1, children: [
10267
- /* @__PURE__ */ jsxs8(Text8, { color: theme.warn, children: [
10268
- spin,
10269
- " waiting for authorization\u2026 "
10270
- ] }),
10271
- /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "esc to cancel" })
10272
- ] })
10273
- ] })
10274
- ] });
10275
- }
10276
- return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
10277
- /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: focused ? "\u2191\u2193 select \xB7 enter view \xB7 m make active \xB7 n add account \xB7 r refresh" : "press \u2192 to manage accounts" }),
10278
- msg ? /* @__PURE__ */ jsx8(Text8, { color: msg.level === "bad" ? theme.bad : theme.ok, children: truncate2(msg.text, 70) }) : login?.msg ? /* @__PURE__ */ jsx8(Text8, { color: login.phase === "error" ? theme.bad : theme.ok, children: login.msg }) : /* @__PURE__ */ jsx8(Text8, { children: " " }),
10279
- /* @__PURE__ */ jsx8(Box8, { marginTop: 1, flexDirection: "column", children: accounts.length === 0 ? /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
10280
- /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "No accounts on this device yet." }),
10281
- /* @__PURE__ */ jsxs8(Text8, { children: [
10282
- /* @__PURE__ */ jsx8(Text8, { color: theme.accent, children: "n" }),
10283
- /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: " to log in \u2014 pairs this device and starts protecting your Claude Code sessions." })
10284
- ] })
10285
- ] }) : accounts.map((a, i) => {
10286
- const isSel = i === sel && focused;
10287
- const isView = viewApiKey ? a.apiKey === viewApiKey : i === 0;
10288
- const isActive = isActiveAccount(a.apiKey);
10289
- return /* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", backgroundColor: isSel ? "#333333" : void 0, bold: isSel, children: [
10290
- /* @__PURE__ */ jsx8(Text8, { color: isSel ? theme.accentBright : theme.dim, children: isSel ? "\u25B8 " : " " }),
10291
- /* @__PURE__ */ jsx8(Text8, { color: theme.accent, children: truncate2(a.email || a.user || "account \u2026" + a.apiKey.slice(-4), 30).padEnd(31) }),
10292
- isView ? /* @__PURE__ */ jsx8(Text8, { color: theme.ok, children: "\u25CF viewing " }) : /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: " " }),
10293
- isActive ? /* @__PURE__ */ jsx8(Text8, { color: theme.warn, children: "ACTIVE " }) : /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: " " }),
10294
- /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: a.project ? truncate2(a.project, 24) : "" })
10295
- ] }, a.apiKey);
10296
- }) }),
10297
- /* @__PURE__ */ jsx8(Box8, { marginTop: 1, flexDirection: "column", children: /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "\u25CF viewing = the account the dataroom is showing \xB7 ACTIVE = the key the guard hooks + logging use" }) })
10298
- ] });
10299
- }
10300
- var SPIN2;
10301
- var init_Accounts = __esm({
10302
- "src/tui/panels/Accounts.tsx"() {
10303
- "use strict";
10304
- init_client();
10305
- init_device_login();
10306
- init_theme();
10307
10414
  SPIN2 = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
10415
+ acctLabel = (a) => a.email || a.user || "account \u2026" + a.apiKey.slice(-4);
10308
10416
  }
10309
10417
  });
10310
10418
 
10311
10419
  // src/tui/App.tsx
10312
- import { Box as Box9, Text as Text9, useApp, useInput as useInput8 } from "ink";
10313
- import { useEffect as useEffect7, useState as useState9 } from "react";
10314
- import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
10420
+ import { Box as Box8, Text as Text8, useApp, useInput as useInput7 } from "ink";
10421
+ import { useEffect as useEffect7, useState as useState8 } from "react";
10422
+ import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
10315
10423
  function LiveHint() {
10316
- return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", children: [
10317
- /* @__PURE__ */ jsx9(Text9, { color: theme.accentBright, bold: true, children: "\u25B6 REALTIME CONSOLE" }),
10318
- /* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: "Fullscreen live monitor \u2014 streaming tool calls, active charts," }),
10319
- /* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: "counters, DLP hits and denial alerts. Updates every 2s." }),
10320
- /* @__PURE__ */ jsx9(Box9, { marginTop: 1, children: /* @__PURE__ */ jsxs9(Text9, { children: [
10424
+ return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
10425
+ /* @__PURE__ */ jsx8(Text8, { color: theme.accentBright, bold: true, children: "\u25B6 REALTIME CONSOLE" }),
10426
+ /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "Fullscreen live monitor \u2014 streaming tool calls, active charts," }),
10427
+ /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "counters, DLP hits and denial alerts. Updates every 2s." }),
10428
+ /* @__PURE__ */ jsx8(Box8, { marginTop: 1, children: /* @__PURE__ */ jsxs8(Text8, { children: [
10321
10429
  "press ",
10322
- /* @__PURE__ */ jsx9(Text9, { color: theme.accent, children: "enter" }),
10430
+ /* @__PURE__ */ jsx8(Text8, { color: theme.accent, children: "enter" }),
10323
10431
  " to go live"
10324
10432
  ] }) })
10325
10433
  ] });
@@ -10327,25 +10435,25 @@ function LiveHint() {
10327
10435
  function Banner({ cols }) {
10328
10436
  const wide = cols >= 82;
10329
10437
  if (!wide) {
10330
- return /* @__PURE__ */ jsxs9(Box9, { children: [
10331
- /* @__PURE__ */ jsx9(Text9, { bold: true, color: theme.accentBright, children: "SolonGate" }),
10332
- /* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: " \u2014 security control center" })
10438
+ return /* @__PURE__ */ jsxs8(Box8, { children: [
10439
+ /* @__PURE__ */ jsx8(Text8, { bold: true, color: theme.accentBright, children: "SolonGate" }),
10440
+ /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: " \u2014 security control center" })
10333
10441
  ] });
10334
10442
  }
10335
- return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", children: [
10336
- BANNER_FULL.map((line, i) => /* @__PURE__ */ jsx9(Text9, { bold: true, color: BANNER_HEX[i], children: line }, i)),
10337
- /* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: " security control center \xB7 manage policies, rate limits, DLP & more" })
10443
+ return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
10444
+ BANNER_FULL.map((line, i) => /* @__PURE__ */ jsx8(Text8, { bold: true, color: BANNER_HEX[i], children: line }, i)),
10445
+ /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: " security control center \xB7 manage policies, rate limits, DLP & more" })
10338
10446
  ] });
10339
10447
  }
10340
10448
  function App() {
10341
10449
  const { exit } = useApp();
10342
- const [accounts, setAccounts] = useState9(() => listAccounts());
10343
- const [viewKey, setViewKey] = useState9(() => accounts[0]?.apiKey);
10344
- const [viewNonce, setViewNonce] = useState9(0);
10345
- const [section, setSection] = useState9(accounts.length === 0 ? ACCOUNTS_SECTION : 0);
10346
- const [focus, setFocus] = useState9("nav");
10347
- const [help, setHelp] = useState9(false);
10348
- const [update2, setUpdate] = useState9({ kind: "idle" });
10450
+ const [accounts, setAccounts] = useState8(() => listAccounts());
10451
+ const [viewKey, setViewKey] = useState8(() => accounts[0]?.apiKey);
10452
+ const [viewNonce, setViewNonce] = useState8(0);
10453
+ const [section, setSection] = useState8(accounts.length === 0 ? SETTINGS_SECTION : 0);
10454
+ const [focus, setFocus] = useState8("nav");
10455
+ const [help, setHelp] = useState8(false);
10456
+ const [update2, setUpdate] = useState8({ kind: "idle" });
10349
10457
  useEffect7(() => {
10350
10458
  let alive = true;
10351
10459
  const run12 = () => void tuiUpdateFlow((s) => alive && setUpdate(s));
@@ -10358,7 +10466,7 @@ function App() {
10358
10466
  }, []);
10359
10467
  const acctIdx = Math.max(0, accounts.findIndex((a) => a.apiKey === viewKey));
10360
10468
  const cur = accounts[acctIdx];
10361
- const acctLabel = cur ? cur.email || cur.user || cur.project || `account \u2026${cur.apiKey.slice(-4)}` : "not logged in";
10469
+ const acctLabel2 = cur ? cur.email || cur.user || cur.project || `account \u2026${cur.apiKey.slice(-4)}` : "not logged in";
10362
10470
  useEffect7(() => {
10363
10471
  if (!cur || cur.email) return;
10364
10472
  let alive = true;
@@ -10386,8 +10494,8 @@ function App() {
10386
10494
  viewAccount(accounts[(acctIdx + 1) % accounts.length]);
10387
10495
  };
10388
10496
  const locked = accounts.length === 0;
10389
- const effectiveSection = locked ? ACCOUNTS_SECTION : section;
10390
- useInput8((input, key) => {
10497
+ const effectiveSection = locked ? SETTINGS_SECTION : section;
10498
+ useInput7((input, key) => {
10391
10499
  if (help) {
10392
10500
  setHelp(false);
10393
10501
  return;
@@ -10415,45 +10523,45 @@ function App() {
10415
10523
  });
10416
10524
  const { cols, rows } = useTermSize();
10417
10525
  const current = SECTIONS[effectiveSection];
10418
- if (help) return /* @__PURE__ */ jsx9(HelpOverlay, { cols, rows });
10526
+ if (help) return /* @__PURE__ */ jsx8(HelpOverlay, { cols, rows });
10419
10527
  if (current.label === "Live" && focus === "panel") {
10420
- return /* @__PURE__ */ jsx9(Box9, { flexDirection: "column", width: cols, height: rows - 1, overflow: "hidden", children: /* @__PURE__ */ jsx9(LivePanel, { active: true, focused: true }, viewNonce) });
10528
+ return /* @__PURE__ */ jsx8(Box8, { flexDirection: "column", width: cols, height: rows - 1, overflow: "hidden", children: /* @__PURE__ */ jsx8(LivePanel, { active: true, focused: true }, viewNonce) });
10421
10529
  }
10422
10530
  const Panel = current.Panel;
10423
- const panelBody = current.label === "Accounts" ? /* @__PURE__ */ jsx9(AccountsPanel, { active: true, focused: focus === "panel", viewApiKey: viewKey, onView: viewAccount }) : /* @__PURE__ */ jsx9(Panel, { active: focus === "panel" || current.label !== "Live", focused: focus === "panel" });
10424
- return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", width: cols, height: rows, paddingX: 1, paddingTop: 1, children: [
10425
- /* @__PURE__ */ jsx9(Banner, { cols }),
10426
- /* @__PURE__ */ jsxs9(Text9, { wrap: "truncate", children: [
10427
- /* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: "account: " }),
10428
- /* @__PURE__ */ jsx9(Text9, { color: locked ? theme.warn : theme.accentBright, bold: true, children: acctLabel }),
10429
- locked ? /* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: " \xB7 log in from Accounts to unlock the dataroom" }) : accounts.length > 1 ? /* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: ` (${acctIdx + 1}/${accounts.length} \xB7 a switch \xB7 Accounts to manage)` }) : /* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: " \xB7 Accounts to add another" }),
10430
- update2.kind === "updating" ? /* @__PURE__ */ jsx9(Text9, { color: theme.warn, children: ` \u2191 updating to v${update2.version}\u2026` }) : update2.kind === "updated" ? /* @__PURE__ */ jsx9(Text9, { color: theme.ok, bold: true, children: ` \u2191 v${update2.version} installed \u2014 restart (q, then solongate) to apply` }) : update2.kind === "manual" ? /* @__PURE__ */ jsx9(Text9, { color: theme.warn, children: ` \u2191 v${update2.version} available \u2014 npm i -g @solongate/proxy@latest` }) : null
10531
+ const panelBody = current.label === "Settings" ? /* @__PURE__ */ jsx8(SettingsPanel, { active: true, focused: focus === "panel", viewApiKey: viewKey, onView: viewAccount }) : /* @__PURE__ */ jsx8(Panel, { active: focus === "panel" || current.label !== "Live", focused: focus === "panel" });
10532
+ return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", width: cols, height: rows, paddingX: 1, paddingTop: 1, children: [
10533
+ /* @__PURE__ */ jsx8(Banner, { cols }),
10534
+ /* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", children: [
10535
+ /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "account: " }),
10536
+ /* @__PURE__ */ jsx8(Text8, { color: locked ? theme.warn : theme.accentBright, bold: true, children: acctLabel2 }),
10537
+ locked ? /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: " \xB7 log in from Settings to unlock the dataroom" }) : accounts.length > 1 ? /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: ` (${acctIdx + 1}/${accounts.length} \xB7 a switch \xB7 Settings to manage)` }) : /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: " \xB7 Settings to add another" }),
10538
+ update2.kind === "updating" ? /* @__PURE__ */ jsx8(Text8, { color: theme.warn, children: ` \u2191 updating to v${update2.version}\u2026` }) : update2.kind === "updated" ? /* @__PURE__ */ jsx8(Text8, { color: theme.ok, bold: true, children: ` \u2191 v${update2.version} installed \u2014 restart (q, then solongate) to apply` }) : update2.kind === "manual" ? /* @__PURE__ */ jsx8(Text8, { color: theme.warn, children: ` \u2191 v${update2.version} available \u2014 npm i -g @solongate/proxy@latest` }) : null
10431
10539
  ] }),
10432
- /* @__PURE__ */ jsxs9(Box9, { marginTop: 1, flexGrow: 1, children: [
10433
- /* @__PURE__ */ jsx9(Box9, { flexDirection: "column", width: 16, borderStyle: "round", borderColor: focus === "nav" ? theme.accent : "gray", paddingX: 1, children: SECTIONS.map((s, i) => {
10540
+ /* @__PURE__ */ jsxs8(Box8, { marginTop: 1, flexGrow: 1, children: [
10541
+ /* @__PURE__ */ jsx8(Box8, { flexDirection: "column", width: 16, borderStyle: "round", borderColor: focus === "nav" ? theme.accent : "gray", paddingX: 1, children: SECTIONS.map((s, i) => {
10434
10542
  const isCur = i === effectiveSection;
10435
- const disabled = locked && s.label !== "Accounts";
10436
- return /* @__PURE__ */ jsx9(Text9, { color: isCur ? theme.accentBright : disabled ? theme.dim : void 0, bold: isCur, dimColor: disabled, children: (isCur ? "\u25B8 " : disabled ? "\u2298 " : " ") + s.label }, s.label);
10543
+ const disabled = locked && s.label !== "Settings";
10544
+ return /* @__PURE__ */ jsx8(Text8, { color: isCur ? theme.accentBright : disabled ? theme.dim : void 0, bold: isCur, dimColor: disabled, children: (isCur ? "\u25B8 " : disabled ? "\u2298 " : " ") + s.label }, s.label);
10437
10545
  }) }),
10438
- /* @__PURE__ */ jsx9(Box9, { flexGrow: 1, borderStyle: "round", borderColor: focus === "panel" ? theme.accent : "gray", paddingX: 1, paddingY: 0, children: panelBody })
10546
+ /* @__PURE__ */ jsx8(Box8, { flexGrow: 1, borderStyle: "round", borderColor: focus === "panel" ? theme.accent : "gray", paddingX: 1, paddingY: 0, children: panelBody })
10439
10547
  ] }, viewNonce),
10440
- /* @__PURE__ */ jsx9(Box9, { children: locked ? /* @__PURE__ */ jsx9(KeyHints, { hints: [["\u2192/enter", "open Accounts"], ["n", "log in"], ["q", "quit"]] }) : focus === "nav" ? /* @__PURE__ */ jsx9(KeyHints, { hints: [["\u2191\u2193", "section"], ["\u2192/enter", "open"], ...accounts.length > 1 ? [["a", "account"]] : [], ["?", "help"], ["q", "quit"]] }) : /* @__PURE__ */ jsx9(KeyHints, { hints: [["\u2190/esc", "back"], ["\u2191\u2193", "in-panel"], ["space/s", "act"]] }) })
10548
+ /* @__PURE__ */ jsx8(Box8, { children: locked ? /* @__PURE__ */ jsx8(KeyHints, { hints: [["\u2192/enter", "open Settings"], ["n", "log in"], ["q", "quit"]] }) : focus === "nav" ? /* @__PURE__ */ jsx8(KeyHints, { hints: [["\u2191\u2193", "section"], ["\u2192/enter", "open"], ...accounts.length > 1 ? [["a", "account"]] : [], ["?", "help"], ["q", "quit"]] }) : /* @__PURE__ */ jsx8(KeyHints, { hints: [["\u2190/esc", "back"], ["\u2191\u2193", "in-panel"], ["space/s", "act"]] }) })
10441
10549
  ] });
10442
10550
  }
10443
10551
  function HelpOverlay({ cols, rows }) {
10444
- return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", width: cols, height: rows, paddingX: 2, paddingTop: 1, children: [
10445
- /* @__PURE__ */ jsx9(Text9, { bold: true, color: theme.accentBright, children: "SolonGate \u2014 keyboard shortcuts" }),
10446
- /* @__PURE__ */ jsx9(Box9, { marginTop: 1, flexDirection: "column", children: HELP.map(([group, keys]) => /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", marginBottom: 1, children: [
10447
- /* @__PURE__ */ jsx9(Text9, { bold: true, color: theme.accent, children: group }),
10448
- keys.map(([k, desc]) => /* @__PURE__ */ jsxs9(Text9, { children: [
10449
- /* @__PURE__ */ jsx9(Text9, { color: theme.accentBright, children: (" " + k).padEnd(16) }),
10450
- /* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: desc })
10552
+ return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", width: cols, height: rows, paddingX: 2, paddingTop: 1, children: [
10553
+ /* @__PURE__ */ jsx8(Text8, { bold: true, color: theme.accentBright, children: "SolonGate \u2014 keyboard shortcuts" }),
10554
+ /* @__PURE__ */ jsx8(Box8, { marginTop: 1, flexDirection: "column", children: HELP.map(([group, keys]) => /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", marginBottom: 1, children: [
10555
+ /* @__PURE__ */ jsx8(Text8, { bold: true, color: theme.accent, children: group }),
10556
+ keys.map(([k, desc]) => /* @__PURE__ */ jsxs8(Text8, { children: [
10557
+ /* @__PURE__ */ jsx8(Text8, { color: theme.accentBright, children: (" " + k).padEnd(16) }),
10558
+ /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: desc })
10451
10559
  ] }, k))
10452
10560
  ] }, group)) }),
10453
- /* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: "press any key to close" })
10561
+ /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "press any key to close" })
10454
10562
  ] });
10455
10563
  }
10456
- var SECTIONS, BANNER_HEX, ACCOUNTS_SECTION, HELP;
10564
+ var SECTIONS, BANNER_HEX, SETTINGS_SECTION, HELP;
10457
10565
  var init_App = __esm({
10458
10566
  "src/tui/App.tsx"() {
10459
10567
  "use strict";
@@ -10466,7 +10574,6 @@ var init_App = __esm({
10466
10574
  init_Dlp();
10467
10575
  init_Audit();
10468
10576
  init_Settings();
10469
- init_Accounts();
10470
10577
  init_hooks();
10471
10578
  init_client();
10472
10579
  init_api_client();
@@ -10477,11 +10584,10 @@ var init_App = __esm({
10477
10584
  { label: "Rate Limit", Panel: RateLimitPanel },
10478
10585
  { label: "DLP", Panel: DlpPanel },
10479
10586
  { label: "Audit", Panel: AuditPanel },
10480
- { label: "Settings", Panel: SettingsPanel },
10481
- { label: "Accounts", Panel: AccountsPanel }
10587
+ { label: "Settings", Panel: SettingsPanel }
10482
10588
  ];
10483
10589
  BANNER_HEX = ["white", "white", "white", "white", "white", "white"];
10484
- ACCOUNTS_SECTION = SECTIONS.findIndex((s) => s.label === "Accounts");
10590
+ SETTINGS_SECTION = SECTIONS.findIndex((s) => s.label === "Settings");
10485
10591
  HELP = [
10486
10592
  ["Global", [["\u2191\u2193", "move between sections"], ["\u2192 / enter", "open a section"], ["\u2190 / esc", "back to the menu"], ["?", "this help"], ["q", "quit"]]],
10487
10593
  ["Live", [["\u2191\u2193", "select a stream row"], ["enter", "full entry content"], ["w", "whitelist the selected DENY"], ["b", "block the selected ALLOW"], ["d / x / r", "filter denies / dlp / rate-limit"], ["f", "local / cloud filter"], ["/", "search"], ["s", "sessions (\u2191\u2193 pick, enter open)"], ["space", "copy mode (freeze)"]]],
@@ -10499,11 +10605,11 @@ var tui_exports = {};
10499
10605
  __export(tui_exports, {
10500
10606
  launchTui: () => launchTui
10501
10607
  });
10502
- import { appendFileSync as appendFileSync2, mkdirSync as mkdirSync7 } from "fs";
10503
- import { homedir as homedir8 } from "os";
10504
- import { join as join10 } from "path";
10608
+ import { appendFileSync as appendFileSync2, mkdirSync as mkdirSync8 } from "fs";
10609
+ import { homedir as homedir9 } from "os";
10610
+ import { join as join11 } from "path";
10505
10611
  import { render } from "ink";
10506
- import { jsx as jsx10 } from "react/jsx-runtime";
10612
+ import { jsx as jsx9 } from "react/jsx-runtime";
10507
10613
  async function launchTui() {
10508
10614
  if (!process.stdout.isTTY || !process.stdin.isTTY) {
10509
10615
  process.stderr.write(
@@ -10512,11 +10618,11 @@ async function launchTui() {
10512
10618
  return;
10513
10619
  }
10514
10620
  process.stdout.write("\x1B[?1049h\x1B[H");
10515
- const debugLog = join10(homedir8(), ".solongate", "dataroom-debug.log");
10621
+ const debugLog = join11(homedir9(), ".solongate", "dataroom-debug.log");
10516
10622
  const saved = { log: console.log, warn: console.warn, error: console.error, info: console.info, debug: console.debug };
10517
10623
  const toFile = (level) => (...args) => {
10518
10624
  try {
10519
- mkdirSync7(join10(homedir8(), ".solongate"), { recursive: true });
10625
+ mkdirSync8(join11(homedir9(), ".solongate"), { recursive: true });
10520
10626
  appendFileSync2(debugLog, `${(/* @__PURE__ */ new Date()).toISOString()} [${level}] ${args.map((a) => typeof a === "string" ? a : JSON.stringify(a)).join(" ")}
10521
10627
  `);
10522
10628
  } catch {
@@ -10528,7 +10634,7 @@ async function launchTui() {
10528
10634
  console.info = toFile("info");
10529
10635
  console.debug = toFile("debug");
10530
10636
  try {
10531
- const { waitUntilExit } = render(/* @__PURE__ */ jsx10(App, {}), { patchConsole: false });
10637
+ const { waitUntilExit } = render(/* @__PURE__ */ jsx9(App, {}), { patchConsole: false });
10532
10638
  await waitUntilExit();
10533
10639
  } finally {
10534
10640
  Object.assign(console, saved);
@@ -10640,7 +10746,7 @@ var init_args = __esm({
10640
10746
  });
10641
10747
 
10642
10748
  // src/commands/policy.ts
10643
- import { readFileSync as readFileSync8 } from "fs";
10749
+ import { readFileSync as readFileSync9 } from "fs";
10644
10750
  async function run(argv) {
10645
10751
  const { positionals, flags } = parse(argv);
10646
10752
  const sub = positionals[0];
@@ -10815,7 +10921,7 @@ function printRules(rules) {
10815
10921
  }
10816
10922
  async function resolveRules(target) {
10817
10923
  if (target.endsWith(".json")) {
10818
- const parsed = JSON.parse(readFileSync8(target, "utf-8"));
10924
+ const parsed = JSON.parse(readFileSync9(target, "utf-8"));
10819
10925
  return parsed.rules ?? [];
10820
10926
  }
10821
10927
  const p = await api.policies.get(target);
@@ -11231,8 +11337,8 @@ var init_agents2 = __esm({
11231
11337
 
11232
11338
  // src/commands/doctor.ts
11233
11339
  import { existsSync as existsSync4, statSync as statSync2 } from "fs";
11234
- import { homedir as homedir9 } from "os";
11235
- import { join as join11 } from "path";
11340
+ import { homedir as homedir10 } from "os";
11341
+ import { join as join12 } from "path";
11236
11342
  async function run6(argv) {
11237
11343
  const { flags } = parse(argv);
11238
11344
  const json = flagBool(flags, "json");
@@ -11292,19 +11398,19 @@ var init_doctor = __esm({
11292
11398
  init_api_client();
11293
11399
  init_format();
11294
11400
  init_args();
11295
- LOCAL_LOG2 = join11(homedir9(), ".solongate", "local-logs", "solongate-audit.jsonl");
11401
+ LOCAL_LOG2 = join12(homedir10(), ".solongate", "local-logs", "solongate-audit.jsonl");
11296
11402
  }
11297
11403
  });
11298
11404
 
11299
11405
  // src/commands/watch.ts
11300
- import { closeSync as closeSync2, existsSync as existsSync5, openSync as openSync3, readSync as readSync2, statSync as statSync3 } from "fs";
11301
- import { homedir as homedir10 } from "os";
11302
- import { join as join12 } from "path";
11406
+ import { closeSync as closeSync2, existsSync as existsSync5, openSync as openSync4, readSync as readSync2, statSync as statSync3 } from "fs";
11407
+ import { homedir as homedir11 } from "os";
11408
+ import { join as join13 } from "path";
11303
11409
  function tailLocal(file, maxBytes = 131072) {
11304
11410
  try {
11305
11411
  const size = statSync3(file).size;
11306
11412
  const start = Math.max(0, size - maxBytes);
11307
- const fd = openSync3(file, "r");
11413
+ const fd = openSync4(file, "r");
11308
11414
  const buf = Buffer.alloc(size - start);
11309
11415
  readSync2(fd, buf, 0, buf.length, start);
11310
11416
  closeSync2(fd);
@@ -11406,7 +11512,7 @@ var init_watch = __esm({
11406
11512
  init_cli_utils();
11407
11513
  init_args();
11408
11514
  init_format();
11409
- LOCAL_LOG3 = join12(homedir10(), ".solongate", "local-logs", "solongate-audit.jsonl");
11515
+ LOCAL_LOG3 = join13(homedir11(), ".solongate", "local-logs", "solongate-audit.jsonl");
11410
11516
  trunc = (s, n) => s.length <= n ? s : s.slice(0, n - 1) + "\u2026";
11411
11517
  time = (ms) => new Date(ms).toTimeString().slice(0, 8);
11412
11518
  }
@@ -11697,10 +11803,10 @@ var init_commands = __esm({
11697
11803
  });
11698
11804
 
11699
11805
  // src/global-install.ts
11700
- import { readFileSync as readFileSync9, writeFileSync as writeFileSync8, existsSync as existsSync6, mkdirSync as mkdirSync8 } from "fs";
11701
- import { resolve as resolve4, join as join13, dirname as dirname2 } from "path";
11702
- import { homedir as homedir11 } from "os";
11703
- import { fileURLToPath as fileURLToPath2 } from "url";
11806
+ import { readFileSync as readFileSync10, writeFileSync as writeFileSync9, existsSync as existsSync6, mkdirSync as mkdirSync9 } from "fs";
11807
+ import { resolve as resolve4, join as join14, dirname as dirname3 } from "path";
11808
+ import { homedir as homedir12 } from "os";
11809
+ import { fileURLToPath as fileURLToPath3 } from "url";
11704
11810
  import { createInterface } from "readline";
11705
11811
  import { execFileSync as execFileSync2 } from "child_process";
11706
11812
  function lockFile(file) {
@@ -11762,10 +11868,10 @@ function unlockFile(file) {
11762
11868
  function protectedTargets() {
11763
11869
  const p = globalPaths();
11764
11870
  return [
11765
- join13(p.hooksDir, "guard.mjs"),
11766
- join13(p.hooksDir, "audit.mjs"),
11767
- join13(p.hooksDir, "stop.mjs"),
11768
- join13(p.hooksDir, "shield.mjs"),
11871
+ join14(p.hooksDir, "guard.mjs"),
11872
+ join14(p.hooksDir, "audit.mjs"),
11873
+ join14(p.hooksDir, "stop.mjs"),
11874
+ join14(p.hooksDir, "shield.mjs"),
11769
11875
  p.configPath,
11770
11876
  p.settingsPath
11771
11877
  ];
@@ -11777,26 +11883,26 @@ function unlockProtected() {
11777
11883
  for (const f of protectedTargets()) unlockFile(f);
11778
11884
  }
11779
11885
  function globalPaths() {
11780
- const home = homedir11();
11781
- const sgDir = join13(home, ".solongate");
11782
- const hooksDir = join13(sgDir, "hooks");
11783
- const claudeDir = join13(home, ".claude");
11886
+ const home = homedir12();
11887
+ const sgDir = join14(home, ".solongate");
11888
+ const hooksDir = join14(sgDir, "hooks");
11889
+ const claudeDir = join14(home, ".claude");
11784
11890
  return {
11785
11891
  home,
11786
11892
  sgDir,
11787
11893
  hooksDir,
11788
11894
  claudeDir,
11789
- settingsPath: join13(claudeDir, "settings.json"),
11790
- backupPath: join13(claudeDir, "settings.solongate.bak"),
11791
- configPath: join13(sgDir, "cloud-guard.json")
11895
+ settingsPath: join14(claudeDir, "settings.json"),
11896
+ backupPath: join14(claudeDir, "settings.solongate.bak"),
11897
+ configPath: join14(sgDir, "cloud-guard.json")
11792
11898
  };
11793
11899
  }
11794
11900
  function readHook(filename) {
11795
- return readFileSync9(join13(HOOKS_DIR, filename), "utf-8");
11901
+ return readFileSync10(join14(HOOKS_DIR, filename), "utf-8");
11796
11902
  }
11797
11903
  function readGuard() {
11798
- const bundled = join13(HOOKS_DIR, "guard.bundled.mjs");
11799
- return existsSync6(bundled) ? readFileSync9(bundled, "utf-8") : readHook("guard.mjs");
11904
+ const bundled = join14(HOOKS_DIR, "guard.bundled.mjs");
11905
+ return existsSync6(bundled) ? readFileSync10(bundled, "utf-8") : readHook("guard.mjs");
11800
11906
  }
11801
11907
  function ask(question) {
11802
11908
  const rl = createInterface({ input: process.stdin, output: process.stderr });
@@ -11830,18 +11936,18 @@ function shimTargets() {
11830
11936
  return [];
11831
11937
  }
11832
11938
  }
11833
- return [".bashrc", ".zshrc", ".profile"].map((f) => join13(homedir11(), f)).filter((f) => existsSync6(f));
11939
+ return [".bashrc", ".zshrc", ".profile"].map((f) => join14(homedir12(), f)).filter((f) => existsSync6(f));
11834
11940
  }
11835
11941
  function writeShimBlock(file, block2) {
11836
11942
  const re = new RegExp(escapeRe(SHIM_BEGIN) + "[\\s\\S]*?" + escapeRe(SHIM_END) + "\\r?\\n?", "g");
11837
- let content = existsSync6(file) ? readFileSync9(file, "utf-8") : "";
11943
+ let content = existsSync6(file) ? readFileSync10(file, "utf-8") : "";
11838
11944
  content = content.replace(re, "");
11839
11945
  if (block2) {
11840
11946
  if (content.length && !content.endsWith("\n")) content += "\n";
11841
11947
  content += block2 + "\n";
11842
11948
  }
11843
- mkdirSync8(dirname2(file), { recursive: true });
11844
- writeFileSync8(file, content);
11949
+ mkdirSync9(dirname3(file), { recursive: true });
11950
+ writeFileSync9(file, content);
11845
11951
  }
11846
11952
  function installClaudeShim(shieldPath) {
11847
11953
  const real = resolveRealClaude();
@@ -11871,7 +11977,7 @@ async function runGlobalInstall2(opts = {}) {
11871
11977
  let apiKey = opts.apiKey || process.env["SOLONGATE_API_KEY"] || "";
11872
11978
  if (!apiKey || apiKey === "sg_live_your_key_here") {
11873
11979
  try {
11874
- const cfg = JSON.parse(readFileSync9(p.configPath, "utf-8"));
11980
+ const cfg = JSON.parse(readFileSync10(p.configPath, "utf-8"));
11875
11981
  if (cfg && typeof cfg.apiKey === "string") apiKey = cfg.apiKey;
11876
11982
  } catch {
11877
11983
  }
@@ -11884,22 +11990,22 @@ async function runGlobalInstall2(opts = {}) {
11884
11990
  process.exit(1);
11885
11991
  }
11886
11992
  const apiUrl = opts.apiUrl || process.env["SOLONGATE_API_URL"] || "https://api.solongate.com";
11887
- mkdirSync8(p.hooksDir, { recursive: true });
11888
- mkdirSync8(p.claudeDir, { recursive: true });
11993
+ mkdirSync9(p.hooksDir, { recursive: true });
11994
+ mkdirSync9(p.claudeDir, { recursive: true });
11889
11995
  unlockProtected();
11890
- writeFileSync8(join13(p.hooksDir, "guard.mjs"), readGuard());
11891
- writeFileSync8(join13(p.hooksDir, "audit.mjs"), readHook("audit.mjs"));
11892
- writeFileSync8(join13(p.hooksDir, "stop.mjs"), readHook("stop.mjs"));
11893
- writeFileSync8(join13(p.hooksDir, "shield.mjs"), readHook("shield.mjs"));
11996
+ writeFileSync9(join14(p.hooksDir, "guard.mjs"), readGuard());
11997
+ writeFileSync9(join14(p.hooksDir, "audit.mjs"), readHook("audit.mjs"));
11998
+ writeFileSync9(join14(p.hooksDir, "stop.mjs"), readHook("stop.mjs"));
11999
+ writeFileSync9(join14(p.hooksDir, "shield.mjs"), readHook("shield.mjs"));
11894
12000
  console.log(` Installed hooks \u2192 ${p.hooksDir}`);
11895
- installClaudeShim(join13(p.hooksDir, "shield.mjs"));
11896
- writeFileSync8(p.configPath, JSON.stringify({ apiKey, apiUrl }, null, 2) + "\n");
12001
+ installClaudeShim(join14(p.hooksDir, "shield.mjs"));
12002
+ writeFileSync9(p.configPath, JSON.stringify({ apiKey, apiUrl }, null, 2) + "\n");
11897
12003
  console.log(` Wrote ${p.configPath}`);
11898
12004
  let existing = {};
11899
12005
  if (existsSync6(p.settingsPath)) {
11900
- const raw = readFileSync9(p.settingsPath, "utf-8");
12006
+ const raw = readFileSync10(p.settingsPath, "utf-8");
11901
12007
  if (!existsSync6(p.backupPath)) {
11902
- writeFileSync8(p.backupPath, raw);
12008
+ writeFileSync9(p.backupPath, raw);
11903
12009
  console.log(` Backed up existing settings \u2192 ${p.backupPath}`);
11904
12010
  }
11905
12011
  try {
@@ -11908,9 +12014,9 @@ async function runGlobalInstall2(opts = {}) {
11908
12014
  existing = {};
11909
12015
  }
11910
12016
  }
11911
- const guardAbs = join13(p.hooksDir, "guard.mjs").replace(/\\/g, "/");
11912
- const auditAbs = join13(p.hooksDir, "audit.mjs").replace(/\\/g, "/");
11913
- const stopAbs = join13(p.hooksDir, "stop.mjs").replace(/\\/g, "/");
12017
+ const guardAbs = join14(p.hooksDir, "guard.mjs").replace(/\\/g, "/");
12018
+ const auditAbs = join14(p.hooksDir, "audit.mjs").replace(/\\/g, "/");
12019
+ const stopAbs = join14(p.hooksDir, "stop.mjs").replace(/\\/g, "/");
11914
12020
  const nodeBin = process.execPath.replace(/\\/g, "/");
11915
12021
  const call = process.platform === "win32" ? "& " : "";
11916
12022
  const hookCmd = (script) => `${call}"${nodeBin}" "${script}" claude-code "Claude Code"`;
@@ -11922,7 +12028,7 @@ async function runGlobalInstall2(opts = {}) {
11922
12028
  Stop: [{ matcher: "", hooks: [{ type: "command", command: hookCmd(stopAbs) }] }]
11923
12029
  }
11924
12030
  };
11925
- writeFileSync8(p.settingsPath, JSON.stringify(merged, null, 2) + "\n");
12031
+ writeFileSync9(p.settingsPath, JSON.stringify(merged, null, 2) + "\n");
11926
12032
  console.log(` Registered global hooks \u2192 ${p.settingsPath}`);
11927
12033
  if (process.env["SOLONGATE_OS_LOCK"] === "1") {
11928
12034
  lockProtected();
@@ -11933,7 +12039,7 @@ var __dirname, HOOKS_DIR, SHIM_BEGIN, SHIM_END;
11933
12039
  var init_global_install = __esm({
11934
12040
  "src/global-install.ts"() {
11935
12041
  "use strict";
11936
- __dirname = dirname2(fileURLToPath2(import.meta.url));
12042
+ __dirname = dirname3(fileURLToPath3(import.meta.url));
11937
12043
  HOOKS_DIR = resolve4(__dirname, "..", "hooks");
11938
12044
  SHIM_BEGIN = "# >>> SolonGate shield (auto secret redaction) >>>";
11939
12045
  SHIM_END = "# <<< SolonGate shield <<<";
@@ -11942,7 +12048,7 @@ var init_global_install = __esm({
11942
12048
 
11943
12049
  // src/login.ts
11944
12050
  var login_exports = {};
11945
- import { spawn as spawn4 } from "child_process";
12051
+ import { spawn as spawn5 } from "child_process";
11946
12052
  function startSpinner(text) {
11947
12053
  if (!process.stderr.isTTY) {
11948
12054
  process.stderr.write(` ${text}
@@ -11978,7 +12084,7 @@ function openBrowser2(url) {
11978
12084
  try {
11979
12085
  const cmd = process.platform === "win32" ? "cmd" : process.platform === "darwin" ? "open" : "xdg-open";
11980
12086
  const args = process.platform === "win32" ? ["/c", "start", '""', url] : [url];
11981
- const child = spawn4(cmd, args, { stdio: "ignore", detached: true });
12087
+ const child = spawn5(cmd, args, { stdio: "ignore", detached: true });
11982
12088
  child.on("error", () => {
11983
12089
  });
11984
12090
  child.unref();
@@ -12098,13 +12204,13 @@ __export(shield_exports, {
12098
12204
  });
12099
12205
  import { createServer, request as httpRequest } from "http";
12100
12206
  import { request as httpsRequest } from "https";
12101
- import { spawn as spawn5 } from "child_process";
12207
+ import { spawn as spawn6 } from "child_process";
12102
12208
  import { URL as URL2 } from "url";
12103
- import { readFileSync as readFileSync10, existsSync as existsSync7, readdirSync, statSync as statSync4 } from "fs";
12209
+ import { readFileSync as readFileSync11, existsSync as existsSync7, readdirSync, statSync as statSync4 } from "fs";
12104
12210
  import { resolve as resolve5 } from "path";
12105
- import { homedir as homedir12 } from "os";
12211
+ import { homedir as homedir13 } from "os";
12106
12212
  function findCacheFile() {
12107
- const dir = resolve5(homedir12(), ".solongate");
12213
+ const dir = resolve5(homedir13(), ".solongate");
12108
12214
  const envSel = process.env.SOLONGATE_AGENT_ID;
12109
12215
  if (envSel) {
12110
12216
  const f = resolve5(dir, ".policy-cache-" + envSel.replace(/[^a-zA-Z0-9_-]/g, "_") + ".json");
@@ -12130,7 +12236,7 @@ function loadCfg() {
12130
12236
  try {
12131
12237
  const f = findCacheFile();
12132
12238
  if (f && existsSync7(f)) {
12133
- const c2 = JSON.parse(readFileSync10(f, "utf-8"));
12239
+ const c2 = JSON.parse(readFileSync11(f, "utf-8"));
12134
12240
  const d = c2?.security?.dlpRedact;
12135
12241
  const g = c2?.security?.ghost;
12136
12242
  const ghost = g && Array.isArray(g.patterns) ? g.patterns : [];
@@ -12358,7 +12464,7 @@ async function runShield() {
12358
12464
  const upstream = pickUpstream();
12359
12465
  const { port, close } = await startProxy(upstream);
12360
12466
  log4(`redacting secrets on the LLM path \u2192 masking before ${upstream.host} (127.0.0.1:${port})`);
12361
- const child = spawn5(cmd[0], cmd.slice(1), {
12467
+ const child = spawn6(cmd[0], cmd.slice(1), {
12362
12468
  stdio: "inherit",
12363
12469
  env: { ...process.env, ANTHROPIC_BASE_URL: `http://127.0.0.1:${port}` },
12364
12470
  shell: process.platform === "win32"
@@ -12418,9 +12524,9 @@ __export(logs_server_exports, {
12418
12524
  runLogsServer: () => runLogsServer
12419
12525
  });
12420
12526
  import { createServer as createServer2 } from "http";
12421
- import { readFileSync as readFileSync11, statSync as statSync5 } from "fs";
12422
- import { resolve as resolve6, join as join14, isAbsolute } from "path";
12423
- import { homedir as homedir13 } from "os";
12527
+ import { readFileSync as readFileSync12, statSync as statSync5 } from "fs";
12528
+ import { resolve as resolve6, join as join15, isAbsolute } from "path";
12529
+ import { homedir as homedir14 } from "os";
12424
12530
  import { readdirSync as readdirSync2 } from "fs";
12425
12531
  function allowedOrigins() {
12426
12532
  const base = [
@@ -12437,15 +12543,15 @@ function resolveLocalLogDir(rawPath) {
12437
12543
  const dir = String(rawPath || "").trim().replace(/[\\/]+$/, "");
12438
12544
  if (!dir) return null;
12439
12545
  if (isAbsolute(dir)) return dir;
12440
- return resolve6(homedir13(), ".solongate", "local-logs");
12546
+ return resolve6(homedir14(), ".solongate", "local-logs");
12441
12547
  }
12442
12548
  async function findLogDir() {
12443
- const base = resolve6(homedir13(), ".solongate");
12549
+ const base = resolve6(homedir14(), ".solongate");
12444
12550
  try {
12445
12551
  const files = readdirSync2(base).filter((f) => f.startsWith(".policy-cache-") && f.endsWith(".json"));
12446
12552
  for (const f of files) {
12447
12553
  try {
12448
- const c2 = JSON.parse(readFileSync11(join14(base, f), "utf-8"));
12554
+ const c2 = JSON.parse(readFileSync12(join15(base, f), "utf-8"));
12449
12555
  const p = c2?.security?.localLogs?.path;
12450
12556
  if (typeof p === "string" && p.trim()) return { dir: resolveLocalLogDir(p), configured: p };
12451
12557
  } catch {
@@ -12454,7 +12560,7 @@ async function findLogDir() {
12454
12560
  } catch {
12455
12561
  }
12456
12562
  try {
12457
- const cfgRaw = readFileSync11(join14(base, "cloud-guard.json"), "utf-8");
12563
+ const cfgRaw = readFileSync12(join15(base, "cloud-guard.json"), "utf-8");
12458
12564
  const { apiKey, apiUrl } = JSON.parse(cfgRaw);
12459
12565
  if (apiKey) {
12460
12566
  const url = `${apiUrl || "https://api.solongate.com"}/api/v1/policies/active`;
@@ -12483,7 +12589,7 @@ function setCors(req, res) {
12483
12589
  }
12484
12590
  function fileInfo(dir) {
12485
12591
  if (!dir) return { file: null, exists: false, size: 0, mtimeMs: 0 };
12486
- const file = join14(dir, LOG_FILENAME);
12592
+ const file = join15(dir, LOG_FILENAME);
12487
12593
  try {
12488
12594
  const st = statSync5(file);
12489
12595
  return { file, exists: true, size: st.size, mtimeMs: st.mtimeMs };
@@ -12544,7 +12650,7 @@ async function runLogsServer() {
12544
12650
  return;
12545
12651
  }
12546
12652
  try {
12547
- const text = readFileSync11(info.file, "utf-8");
12653
+ const text = readFileSync12(info.file, "utf-8");
12548
12654
  res.writeHead(200, { "Content-Type": "text/plain; charset=utf-8", "Last-Modified": lastMod, "X-Solongate-Exists": "1" });
12549
12655
  res.end(text);
12550
12656
  } catch {
@@ -12557,6 +12663,8 @@ async function runLogsServer() {
12557
12663
  res.end("not found");
12558
12664
  });
12559
12665
  server.listen(port, "127.0.0.1", async () => {
12666
+ const { recordLogsServerStarted: recordLogsServerStarted2 } = await Promise.resolve().then(() => (init_logs_server_daemon(), logs_server_daemon_exports));
12667
+ recordLogsServerStarted2(port);
12560
12668
  const { dir, configured } = await findLogDir();
12561
12669
  process.stdout.write(`[SolonGate] Local logs agent listening on http://127.0.0.1:${port}
12562
12670
  `);
@@ -12596,7 +12704,7 @@ var init_logs_server = __esm({
12596
12704
 
12597
12705
  // src/inject.ts
12598
12706
  var inject_exports = {};
12599
- import { readFileSync as readFileSync12, writeFileSync as writeFileSync9, existsSync as existsSync8, copyFileSync } from "fs";
12707
+ import { readFileSync as readFileSync13, writeFileSync as writeFileSync10, existsSync as existsSync8, copyFileSync } from "fs";
12600
12708
  import { resolve as resolve7 } from "path";
12601
12709
  import { execSync } from "child_process";
12602
12710
  function parseInjectArgs(argv) {
@@ -12656,7 +12764,7 @@ WHAT IT DOES
12656
12764
  function detectProject() {
12657
12765
  if (!existsSync8(resolve7("package.json"))) return false;
12658
12766
  try {
12659
- const pkg = JSON.parse(readFileSync12(resolve7("package.json"), "utf-8"));
12767
+ const pkg = JSON.parse(readFileSync13(resolve7("package.json"), "utf-8"));
12660
12768
  const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
12661
12769
  return !!(allDeps["@modelcontextprotocol/sdk"] || allDeps["@modelcontextprotocol/server"]);
12662
12770
  } catch {
@@ -12665,7 +12773,7 @@ function detectProject() {
12665
12773
  }
12666
12774
  function findTsEntryFile() {
12667
12775
  try {
12668
- const pkg = JSON.parse(readFileSync12(resolve7("package.json"), "utf-8"));
12776
+ const pkg = JSON.parse(readFileSync13(resolve7("package.json"), "utf-8"));
12669
12777
  if (pkg.bin) {
12670
12778
  const binPath = typeof pkg.bin === "string" ? pkg.bin : Object.values(pkg.bin)[0];
12671
12779
  if (typeof binPath === "string") {
@@ -12692,7 +12800,7 @@ function findTsEntryFile() {
12692
12800
  const full = resolve7(c2);
12693
12801
  if (existsSync8(full)) {
12694
12802
  try {
12695
- const content = readFileSync12(full, "utf-8");
12803
+ const content = readFileSync13(full, "utf-8");
12696
12804
  if (content.includes("McpServer") || content.includes("McpServer")) {
12697
12805
  return full;
12698
12806
  }
@@ -12712,7 +12820,7 @@ function detectPackageManager() {
12712
12820
  }
12713
12821
  function installSdk() {
12714
12822
  try {
12715
- const pkg = JSON.parse(readFileSync12(resolve7("package.json"), "utf-8"));
12823
+ const pkg = JSON.parse(readFileSync13(resolve7("package.json"), "utf-8"));
12716
12824
  const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
12717
12825
  if (allDeps["@solongate/proxy"]) {
12718
12826
  log3(" @solongate/proxy already installed");
@@ -12733,7 +12841,7 @@ function installSdk() {
12733
12841
  }
12734
12842
  }
12735
12843
  function injectTypeScript(filePath) {
12736
- const original = readFileSync12(filePath, "utf-8");
12844
+ const original = readFileSync13(filePath, "utf-8");
12737
12845
  const changes = [];
12738
12846
  let modified = original;
12739
12847
  if (modified.includes("SecureMcpServer")) {
@@ -12904,7 +13012,7 @@ async function main2() {
12904
13012
  log3("");
12905
13013
  log3(` Backup: ${backupPath}`);
12906
13014
  }
12907
- writeFileSync9(entryFile, result.modified);
13015
+ writeFileSync10(entryFile, result.modified);
12908
13016
  log3("");
12909
13017
  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");
12910
13018
  log3(" \u2502 SolonGate SDK injected successfully! \u2502");
@@ -12933,8 +13041,8 @@ var init_inject = __esm({
12933
13041
 
12934
13042
  // src/create.ts
12935
13043
  var create_exports = {};
12936
- import { mkdirSync as mkdirSync9, writeFileSync as writeFileSync10, existsSync as existsSync9 } from "fs";
12937
- import { resolve as resolve8, join as join15 } from "path";
13044
+ import { mkdirSync as mkdirSync10, writeFileSync as writeFileSync11, existsSync as existsSync9 } from "fs";
13045
+ import { resolve as resolve8, join as join16 } from "path";
12938
13046
  import { execSync as execSync2 } from "child_process";
12939
13047
  function withSpinner(message, fn) {
12940
13048
  const frames = ["\u28FE", "\u28FD", "\u28FB", "\u28BF", "\u287F", "\u28DF", "\u28EF", "\u28F7"];
@@ -13013,8 +13121,8 @@ EXAMPLES
13013
13121
  `);
13014
13122
  }
13015
13123
  function createProject(dir, name, _policy) {
13016
- writeFileSync10(
13017
- join15(dir, "package.json"),
13124
+ writeFileSync11(
13125
+ join16(dir, "package.json"),
13018
13126
  JSON.stringify(
13019
13127
  {
13020
13128
  name,
@@ -13043,8 +13151,8 @@ function createProject(dir, name, _policy) {
13043
13151
  2
13044
13152
  ) + "\n"
13045
13153
  );
13046
- writeFileSync10(
13047
- join15(dir, "tsconfig.json"),
13154
+ writeFileSync11(
13155
+ join16(dir, "tsconfig.json"),
13048
13156
  JSON.stringify(
13049
13157
  {
13050
13158
  compilerOptions: {
@@ -13064,9 +13172,9 @@ function createProject(dir, name, _policy) {
13064
13172
  2
13065
13173
  ) + "\n"
13066
13174
  );
13067
- mkdirSync9(join15(dir, "src"), { recursive: true });
13068
- writeFileSync10(
13069
- join15(dir, "src", "index.ts"),
13175
+ mkdirSync10(join16(dir, "src"), { recursive: true });
13176
+ writeFileSync11(
13177
+ join16(dir, "src", "index.ts"),
13070
13178
  `#!/usr/bin/env node
13071
13179
 
13072
13180
  console.log = (...args: unknown[]) => {
@@ -13107,8 +13215,8 @@ console.log('');
13107
13215
  console.log('Press Ctrl+C to stop.');
13108
13216
  `
13109
13217
  );
13110
- writeFileSync10(
13111
- join15(dir, ".mcp.json"),
13218
+ writeFileSync11(
13219
+ join16(dir, ".mcp.json"),
13112
13220
  JSON.stringify(
13113
13221
  {
13114
13222
  mcpServers: {
@@ -13125,13 +13233,13 @@ console.log('Press Ctrl+C to stop.');
13125
13233
  2
13126
13234
  ) + "\n"
13127
13235
  );
13128
- writeFileSync10(
13129
- join15(dir, ".env"),
13236
+ writeFileSync11(
13237
+ join16(dir, ".env"),
13130
13238
  `SOLONGATE_API_KEY=sg_live_YOUR_KEY_HERE
13131
13239
  `
13132
13240
  );
13133
- writeFileSync10(
13134
- join15(dir, ".gitignore"),
13241
+ writeFileSync11(
13242
+ join16(dir, ".gitignore"),
13135
13243
  `node_modules/
13136
13244
  dist/
13137
13245
  *.solongate-backup
@@ -13150,7 +13258,7 @@ async function main3() {
13150
13258
  process.exit(1);
13151
13259
  }
13152
13260
  withSpinner(`Setting up ${opts.name}...`, () => {
13153
- mkdirSync9(dir, { recursive: true });
13261
+ mkdirSync10(dir, { recursive: true });
13154
13262
  createProject(dir, opts.name, opts.policy);
13155
13263
  });
13156
13264
  if (!opts.noInstall) {
@@ -13224,14 +13332,14 @@ var init_create = __esm({
13224
13332
 
13225
13333
  // src/pull-push.ts
13226
13334
  var pull_push_exports = {};
13227
- import { readFileSync as readFileSync13, writeFileSync as writeFileSync11, existsSync as existsSync10 } from "fs";
13335
+ import { readFileSync as readFileSync14, writeFileSync as writeFileSync12, existsSync as existsSync10 } from "fs";
13228
13336
  import { resolve as resolve9 } from "path";
13229
13337
  function loadEnv() {
13230
13338
  if (process.env.SOLONGATE_API_KEY) return;
13231
13339
  const envPath = resolve9(".env");
13232
13340
  if (!existsSync10(envPath)) return;
13233
13341
  try {
13234
- const content = readFileSync13(envPath, "utf-8");
13342
+ const content = readFileSync14(envPath, "utf-8");
13235
13343
  for (const line of content.split("\n")) {
13236
13344
  const trimmed = line.trim();
13237
13345
  if (!trimmed || trimmed.startsWith("#")) continue;
@@ -13419,7 +13527,7 @@ async function pull(apiKey, file, policyId) {
13419
13527
  const policy = await fetchCloudPolicy(apiKey, API_URL, policyId);
13420
13528
  const { id: _id, ...policyWithoutId } = policy;
13421
13529
  const json = JSON.stringify(policyWithoutId, null, 2) + "\n";
13422
- writeFileSync11(file, json, "utf-8");
13530
+ writeFileSync12(file, json, "utf-8");
13423
13531
  log5("");
13424
13532
  log5(green2(" Saved to: ") + file);
13425
13533
  log5(` ${dim2("Name:")} ${policy.name}`);
@@ -13448,7 +13556,7 @@ async function push(apiKey, file, policyId) {
13448
13556
  log5(" solongate-proxy list");
13449
13557
  process.exit(1);
13450
13558
  }
13451
- const content = readFileSync13(file, "utf-8");
13559
+ const content = readFileSync14(file, "utf-8");
13452
13560
  let policy;
13453
13561
  try {
13454
13562
  policy = JSON.parse(content);
@@ -16604,6 +16712,10 @@ async function main5() {
16604
16712
  const { maybeSelfUpdate: maybeSelfUpdate2 } = await Promise.resolve().then(() => (init_self_update(), self_update_exports));
16605
16713
  maybeSelfUpdate2();
16606
16714
  }
16715
+ if (subcommand !== "logs-server" && subcommand !== "local-logs") {
16716
+ const { ensureLogsServerDaemon: ensureLogsServerDaemon2 } = await Promise.resolve().then(() => (init_logs_server_daemon(), logs_server_daemon_exports));
16717
+ ensureLogsServerDaemon2();
16718
+ }
16607
16719
  }
16608
16720
  if (process.argv.length <= 2) {
16609
16721
  if (process.stdout.isTTY && process.stdin.isTTY) {