@solongate/proxy 0.81.50 → 0.81.52

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" }));
@@ -9985,6 +10085,11 @@ function SettingsPanel({
9985
10085
  const abort = useRef3(false);
9986
10086
  const refreshAccounts = () => setAccounts(listAccounts());
9987
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
+ }, []);
9988
10093
  useEffect6(() => {
9989
10094
  if (!login || login.phase === "done" || login.phase === "error") return;
9990
10095
  const t = setInterval(() => setTick((n) => n + 1), 120);
@@ -10002,6 +10107,7 @@ function SettingsPanel({
10002
10107
  ...locked ? [] : [
10003
10108
  { kind: "ll-enabled" },
10004
10109
  { kind: "ll-path" },
10110
+ { kind: "ll-server" },
10005
10111
  ...webhooks.map((wh) => ({ kind: "wh", wh })),
10006
10112
  { kind: "wh-add" },
10007
10113
  ...alerts.map((rule) => ({ kind: "alert", rule })),
@@ -10077,6 +10183,12 @@ function SettingsPanel({
10077
10183
  } else if (r.kind === "ll-path") {
10078
10184
  setInput(local?.path ?? "");
10079
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
+ );
10080
10192
  } else if (r.kind === "wh") {
10081
10193
  run12(r.wh.enabled ? "webhook disabled" : "webhook enabled", () => api.settings.updateWebhook(r.wh.id, { enabled: !r.wh.enabled }), whQ.reload);
10082
10194
  } else if (r.kind === "wh-add") {
@@ -10220,7 +10332,7 @@ function SettingsPanel({
10220
10332
  ] }) : null
10221
10333
  ] }),
10222
10334
  locked ? null : /* @__PURE__ */ jsxs7(Fragment5, { children: [
10223
- inWindow({ kind: "ll-enabled" }) || inWindow({ kind: "ll-path" }) ? /* @__PURE__ */ jsxs7(Box7, { marginTop: 1, flexDirection: "column", children: [
10335
+ inWindow({ kind: "ll-enabled" }) || inWindow({ kind: "ll-path" }) || inWindow({ kind: "ll-server" }) ? /* @__PURE__ */ jsxs7(Box7, { marginTop: 1, flexDirection: "column", children: [
10224
10336
  /* @__PURE__ */ jsxs7(Text7, { bold: true, color: theme.accentBright, children: [
10225
10337
  "LOCAL LOGS ",
10226
10338
  /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "\u2014 hooks mirror every decision to a file on the agent machine" })
@@ -10235,6 +10347,12 @@ function SettingsPanel({
10235
10347
  /* @__PURE__ */ jsx7(Text7, { color: keyOf(cur) === "ll-path" && focused ? theme.accentBright : theme.dim, children: mark({ kind: "ll-path" }) }),
10236
10348
  /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "path ".padEnd(10) }),
10237
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" })
10238
10356
  ] })
10239
10357
  ] }) : null,
10240
10358
  /* @__PURE__ */ jsxs7(Box7, { marginTop: 1, flexDirection: "column", children: [
@@ -10288,6 +10406,7 @@ var init_Settings = __esm({
10288
10406
  init_api_client();
10289
10407
  init_client();
10290
10408
  init_device_login();
10409
+ init_logs_server_daemon();
10291
10410
  init_components();
10292
10411
  init_hooks();
10293
10412
  init_theme();
@@ -10486,9 +10605,9 @@ var tui_exports = {};
10486
10605
  __export(tui_exports, {
10487
10606
  launchTui: () => launchTui
10488
10607
  });
10489
- import { appendFileSync as appendFileSync2, mkdirSync as mkdirSync7 } from "fs";
10490
- import { homedir as homedir8 } from "os";
10491
- 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";
10492
10611
  import { render } from "ink";
10493
10612
  import { jsx as jsx9 } from "react/jsx-runtime";
10494
10613
  async function launchTui() {
@@ -10499,11 +10618,11 @@ async function launchTui() {
10499
10618
  return;
10500
10619
  }
10501
10620
  process.stdout.write("\x1B[?1049h\x1B[H");
10502
- const debugLog = join10(homedir8(), ".solongate", "dataroom-debug.log");
10621
+ const debugLog = join11(homedir9(), ".solongate", "dataroom-debug.log");
10503
10622
  const saved = { log: console.log, warn: console.warn, error: console.error, info: console.info, debug: console.debug };
10504
10623
  const toFile = (level) => (...args) => {
10505
10624
  try {
10506
- mkdirSync7(join10(homedir8(), ".solongate"), { recursive: true });
10625
+ mkdirSync8(join11(homedir9(), ".solongate"), { recursive: true });
10507
10626
  appendFileSync2(debugLog, `${(/* @__PURE__ */ new Date()).toISOString()} [${level}] ${args.map((a) => typeof a === "string" ? a : JSON.stringify(a)).join(" ")}
10508
10627
  `);
10509
10628
  } catch {
@@ -10627,7 +10746,7 @@ var init_args = __esm({
10627
10746
  });
10628
10747
 
10629
10748
  // src/commands/policy.ts
10630
- import { readFileSync as readFileSync8 } from "fs";
10749
+ import { readFileSync as readFileSync9 } from "fs";
10631
10750
  async function run(argv) {
10632
10751
  const { positionals, flags } = parse(argv);
10633
10752
  const sub = positionals[0];
@@ -10802,7 +10921,7 @@ function printRules(rules) {
10802
10921
  }
10803
10922
  async function resolveRules(target) {
10804
10923
  if (target.endsWith(".json")) {
10805
- const parsed = JSON.parse(readFileSync8(target, "utf-8"));
10924
+ const parsed = JSON.parse(readFileSync9(target, "utf-8"));
10806
10925
  return parsed.rules ?? [];
10807
10926
  }
10808
10927
  const p = await api.policies.get(target);
@@ -11218,8 +11337,8 @@ var init_agents2 = __esm({
11218
11337
 
11219
11338
  // src/commands/doctor.ts
11220
11339
  import { existsSync as existsSync4, statSync as statSync2 } from "fs";
11221
- import { homedir as homedir9 } from "os";
11222
- import { join as join11 } from "path";
11340
+ import { homedir as homedir10 } from "os";
11341
+ import { join as join12 } from "path";
11223
11342
  async function run6(argv) {
11224
11343
  const { flags } = parse(argv);
11225
11344
  const json = flagBool(flags, "json");
@@ -11279,19 +11398,19 @@ var init_doctor = __esm({
11279
11398
  init_api_client();
11280
11399
  init_format();
11281
11400
  init_args();
11282
- LOCAL_LOG2 = join11(homedir9(), ".solongate", "local-logs", "solongate-audit.jsonl");
11401
+ LOCAL_LOG2 = join12(homedir10(), ".solongate", "local-logs", "solongate-audit.jsonl");
11283
11402
  }
11284
11403
  });
11285
11404
 
11286
11405
  // src/commands/watch.ts
11287
- import { closeSync as closeSync2, existsSync as existsSync5, openSync as openSync3, readSync as readSync2, statSync as statSync3 } from "fs";
11288
- import { homedir as homedir10 } from "os";
11289
- 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";
11290
11409
  function tailLocal(file, maxBytes = 131072) {
11291
11410
  try {
11292
11411
  const size = statSync3(file).size;
11293
11412
  const start = Math.max(0, size - maxBytes);
11294
- const fd = openSync3(file, "r");
11413
+ const fd = openSync4(file, "r");
11295
11414
  const buf = Buffer.alloc(size - start);
11296
11415
  readSync2(fd, buf, 0, buf.length, start);
11297
11416
  closeSync2(fd);
@@ -11393,7 +11512,7 @@ var init_watch = __esm({
11393
11512
  init_cli_utils();
11394
11513
  init_args();
11395
11514
  init_format();
11396
- LOCAL_LOG3 = join12(homedir10(), ".solongate", "local-logs", "solongate-audit.jsonl");
11515
+ LOCAL_LOG3 = join13(homedir11(), ".solongate", "local-logs", "solongate-audit.jsonl");
11397
11516
  trunc = (s, n) => s.length <= n ? s : s.slice(0, n - 1) + "\u2026";
11398
11517
  time = (ms) => new Date(ms).toTimeString().slice(0, 8);
11399
11518
  }
@@ -11684,10 +11803,10 @@ var init_commands = __esm({
11684
11803
  });
11685
11804
 
11686
11805
  // src/global-install.ts
11687
- import { readFileSync as readFileSync9, writeFileSync as writeFileSync8, existsSync as existsSync6, mkdirSync as mkdirSync8 } from "fs";
11688
- import { resolve as resolve4, join as join13, dirname as dirname2 } from "path";
11689
- import { homedir as homedir11 } from "os";
11690
- 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";
11691
11810
  import { createInterface } from "readline";
11692
11811
  import { execFileSync as execFileSync2 } from "child_process";
11693
11812
  function lockFile(file) {
@@ -11749,10 +11868,10 @@ function unlockFile(file) {
11749
11868
  function protectedTargets() {
11750
11869
  const p = globalPaths();
11751
11870
  return [
11752
- join13(p.hooksDir, "guard.mjs"),
11753
- join13(p.hooksDir, "audit.mjs"),
11754
- join13(p.hooksDir, "stop.mjs"),
11755
- 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"),
11756
11875
  p.configPath,
11757
11876
  p.settingsPath
11758
11877
  ];
@@ -11764,26 +11883,26 @@ function unlockProtected() {
11764
11883
  for (const f of protectedTargets()) unlockFile(f);
11765
11884
  }
11766
11885
  function globalPaths() {
11767
- const home = homedir11();
11768
- const sgDir = join13(home, ".solongate");
11769
- const hooksDir = join13(sgDir, "hooks");
11770
- 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");
11771
11890
  return {
11772
11891
  home,
11773
11892
  sgDir,
11774
11893
  hooksDir,
11775
11894
  claudeDir,
11776
- settingsPath: join13(claudeDir, "settings.json"),
11777
- backupPath: join13(claudeDir, "settings.solongate.bak"),
11778
- 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")
11779
11898
  };
11780
11899
  }
11781
11900
  function readHook(filename) {
11782
- return readFileSync9(join13(HOOKS_DIR, filename), "utf-8");
11901
+ return readFileSync10(join14(HOOKS_DIR, filename), "utf-8");
11783
11902
  }
11784
11903
  function readGuard() {
11785
- const bundled = join13(HOOKS_DIR, "guard.bundled.mjs");
11786
- 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");
11787
11906
  }
11788
11907
  function ask(question) {
11789
11908
  const rl = createInterface({ input: process.stdin, output: process.stderr });
@@ -11817,18 +11936,18 @@ function shimTargets() {
11817
11936
  return [];
11818
11937
  }
11819
11938
  }
11820
- 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));
11821
11940
  }
11822
11941
  function writeShimBlock(file, block2) {
11823
11942
  const re = new RegExp(escapeRe(SHIM_BEGIN) + "[\\s\\S]*?" + escapeRe(SHIM_END) + "\\r?\\n?", "g");
11824
- let content = existsSync6(file) ? readFileSync9(file, "utf-8") : "";
11943
+ let content = existsSync6(file) ? readFileSync10(file, "utf-8") : "";
11825
11944
  content = content.replace(re, "");
11826
11945
  if (block2) {
11827
11946
  if (content.length && !content.endsWith("\n")) content += "\n";
11828
11947
  content += block2 + "\n";
11829
11948
  }
11830
- mkdirSync8(dirname2(file), { recursive: true });
11831
- writeFileSync8(file, content);
11949
+ mkdirSync9(dirname3(file), { recursive: true });
11950
+ writeFileSync9(file, content);
11832
11951
  }
11833
11952
  function installClaudeShim(shieldPath) {
11834
11953
  const real = resolveRealClaude();
@@ -11858,7 +11977,7 @@ async function runGlobalInstall2(opts = {}) {
11858
11977
  let apiKey = opts.apiKey || process.env["SOLONGATE_API_KEY"] || "";
11859
11978
  if (!apiKey || apiKey === "sg_live_your_key_here") {
11860
11979
  try {
11861
- const cfg = JSON.parse(readFileSync9(p.configPath, "utf-8"));
11980
+ const cfg = JSON.parse(readFileSync10(p.configPath, "utf-8"));
11862
11981
  if (cfg && typeof cfg.apiKey === "string") apiKey = cfg.apiKey;
11863
11982
  } catch {
11864
11983
  }
@@ -11871,22 +11990,22 @@ async function runGlobalInstall2(opts = {}) {
11871
11990
  process.exit(1);
11872
11991
  }
11873
11992
  const apiUrl = opts.apiUrl || process.env["SOLONGATE_API_URL"] || "https://api.solongate.com";
11874
- mkdirSync8(p.hooksDir, { recursive: true });
11875
- mkdirSync8(p.claudeDir, { recursive: true });
11993
+ mkdirSync9(p.hooksDir, { recursive: true });
11994
+ mkdirSync9(p.claudeDir, { recursive: true });
11876
11995
  unlockProtected();
11877
- writeFileSync8(join13(p.hooksDir, "guard.mjs"), readGuard());
11878
- writeFileSync8(join13(p.hooksDir, "audit.mjs"), readHook("audit.mjs"));
11879
- writeFileSync8(join13(p.hooksDir, "stop.mjs"), readHook("stop.mjs"));
11880
- 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"));
11881
12000
  console.log(` Installed hooks \u2192 ${p.hooksDir}`);
11882
- installClaudeShim(join13(p.hooksDir, "shield.mjs"));
11883
- 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");
11884
12003
  console.log(` Wrote ${p.configPath}`);
11885
12004
  let existing = {};
11886
12005
  if (existsSync6(p.settingsPath)) {
11887
- const raw = readFileSync9(p.settingsPath, "utf-8");
12006
+ const raw = readFileSync10(p.settingsPath, "utf-8");
11888
12007
  if (!existsSync6(p.backupPath)) {
11889
- writeFileSync8(p.backupPath, raw);
12008
+ writeFileSync9(p.backupPath, raw);
11890
12009
  console.log(` Backed up existing settings \u2192 ${p.backupPath}`);
11891
12010
  }
11892
12011
  try {
@@ -11895,9 +12014,9 @@ async function runGlobalInstall2(opts = {}) {
11895
12014
  existing = {};
11896
12015
  }
11897
12016
  }
11898
- const guardAbs = join13(p.hooksDir, "guard.mjs").replace(/\\/g, "/");
11899
- const auditAbs = join13(p.hooksDir, "audit.mjs").replace(/\\/g, "/");
11900
- 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, "/");
11901
12020
  const nodeBin = process.execPath.replace(/\\/g, "/");
11902
12021
  const call = process.platform === "win32" ? "& " : "";
11903
12022
  const hookCmd = (script) => `${call}"${nodeBin}" "${script}" claude-code "Claude Code"`;
@@ -11909,7 +12028,7 @@ async function runGlobalInstall2(opts = {}) {
11909
12028
  Stop: [{ matcher: "", hooks: [{ type: "command", command: hookCmd(stopAbs) }] }]
11910
12029
  }
11911
12030
  };
11912
- writeFileSync8(p.settingsPath, JSON.stringify(merged, null, 2) + "\n");
12031
+ writeFileSync9(p.settingsPath, JSON.stringify(merged, null, 2) + "\n");
11913
12032
  console.log(` Registered global hooks \u2192 ${p.settingsPath}`);
11914
12033
  if (process.env["SOLONGATE_OS_LOCK"] === "1") {
11915
12034
  lockProtected();
@@ -11920,7 +12039,7 @@ var __dirname, HOOKS_DIR, SHIM_BEGIN, SHIM_END;
11920
12039
  var init_global_install = __esm({
11921
12040
  "src/global-install.ts"() {
11922
12041
  "use strict";
11923
- __dirname = dirname2(fileURLToPath2(import.meta.url));
12042
+ __dirname = dirname3(fileURLToPath3(import.meta.url));
11924
12043
  HOOKS_DIR = resolve4(__dirname, "..", "hooks");
11925
12044
  SHIM_BEGIN = "# >>> SolonGate shield (auto secret redaction) >>>";
11926
12045
  SHIM_END = "# <<< SolonGate shield <<<";
@@ -11929,7 +12048,7 @@ var init_global_install = __esm({
11929
12048
 
11930
12049
  // src/login.ts
11931
12050
  var login_exports = {};
11932
- import { spawn as spawn4 } from "child_process";
12051
+ import { spawn as spawn5 } from "child_process";
11933
12052
  function startSpinner(text) {
11934
12053
  if (!process.stderr.isTTY) {
11935
12054
  process.stderr.write(` ${text}
@@ -11965,7 +12084,7 @@ function openBrowser2(url) {
11965
12084
  try {
11966
12085
  const cmd = process.platform === "win32" ? "cmd" : process.platform === "darwin" ? "open" : "xdg-open";
11967
12086
  const args = process.platform === "win32" ? ["/c", "start", '""', url] : [url];
11968
- const child = spawn4(cmd, args, { stdio: "ignore", detached: true });
12087
+ const child = spawn5(cmd, args, { stdio: "ignore", detached: true });
11969
12088
  child.on("error", () => {
11970
12089
  });
11971
12090
  child.unref();
@@ -12085,13 +12204,13 @@ __export(shield_exports, {
12085
12204
  });
12086
12205
  import { createServer, request as httpRequest } from "http";
12087
12206
  import { request as httpsRequest } from "https";
12088
- import { spawn as spawn5 } from "child_process";
12207
+ import { spawn as spawn6 } from "child_process";
12089
12208
  import { URL as URL2 } from "url";
12090
- 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";
12091
12210
  import { resolve as resolve5 } from "path";
12092
- import { homedir as homedir12 } from "os";
12211
+ import { homedir as homedir13 } from "os";
12093
12212
  function findCacheFile() {
12094
- const dir = resolve5(homedir12(), ".solongate");
12213
+ const dir = resolve5(homedir13(), ".solongate");
12095
12214
  const envSel = process.env.SOLONGATE_AGENT_ID;
12096
12215
  if (envSel) {
12097
12216
  const f = resolve5(dir, ".policy-cache-" + envSel.replace(/[^a-zA-Z0-9_-]/g, "_") + ".json");
@@ -12117,7 +12236,7 @@ function loadCfg() {
12117
12236
  try {
12118
12237
  const f = findCacheFile();
12119
12238
  if (f && existsSync7(f)) {
12120
- const c2 = JSON.parse(readFileSync10(f, "utf-8"));
12239
+ const c2 = JSON.parse(readFileSync11(f, "utf-8"));
12121
12240
  const d = c2?.security?.dlpRedact;
12122
12241
  const g = c2?.security?.ghost;
12123
12242
  const ghost = g && Array.isArray(g.patterns) ? g.patterns : [];
@@ -12345,7 +12464,7 @@ async function runShield() {
12345
12464
  const upstream = pickUpstream();
12346
12465
  const { port, close } = await startProxy(upstream);
12347
12466
  log4(`redacting secrets on the LLM path \u2192 masking before ${upstream.host} (127.0.0.1:${port})`);
12348
- const child = spawn5(cmd[0], cmd.slice(1), {
12467
+ const child = spawn6(cmd[0], cmd.slice(1), {
12349
12468
  stdio: "inherit",
12350
12469
  env: { ...process.env, ANTHROPIC_BASE_URL: `http://127.0.0.1:${port}` },
12351
12470
  shell: process.platform === "win32"
@@ -12405,9 +12524,9 @@ __export(logs_server_exports, {
12405
12524
  runLogsServer: () => runLogsServer
12406
12525
  });
12407
12526
  import { createServer as createServer2 } from "http";
12408
- import { readFileSync as readFileSync11, statSync as statSync5 } from "fs";
12409
- import { resolve as resolve6, join as join14, isAbsolute } from "path";
12410
- 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";
12411
12530
  import { readdirSync as readdirSync2 } from "fs";
12412
12531
  function allowedOrigins() {
12413
12532
  const base = [
@@ -12424,15 +12543,15 @@ function resolveLocalLogDir(rawPath) {
12424
12543
  const dir = String(rawPath || "").trim().replace(/[\\/]+$/, "");
12425
12544
  if (!dir) return null;
12426
12545
  if (isAbsolute(dir)) return dir;
12427
- return resolve6(homedir13(), ".solongate", "local-logs");
12546
+ return resolve6(homedir14(), ".solongate", "local-logs");
12428
12547
  }
12429
12548
  async function findLogDir() {
12430
- const base = resolve6(homedir13(), ".solongate");
12549
+ const base = resolve6(homedir14(), ".solongate");
12431
12550
  try {
12432
12551
  const files = readdirSync2(base).filter((f) => f.startsWith(".policy-cache-") && f.endsWith(".json"));
12433
12552
  for (const f of files) {
12434
12553
  try {
12435
- const c2 = JSON.parse(readFileSync11(join14(base, f), "utf-8"));
12554
+ const c2 = JSON.parse(readFileSync12(join15(base, f), "utf-8"));
12436
12555
  const p = c2?.security?.localLogs?.path;
12437
12556
  if (typeof p === "string" && p.trim()) return { dir: resolveLocalLogDir(p), configured: p };
12438
12557
  } catch {
@@ -12441,7 +12560,7 @@ async function findLogDir() {
12441
12560
  } catch {
12442
12561
  }
12443
12562
  try {
12444
- const cfgRaw = readFileSync11(join14(base, "cloud-guard.json"), "utf-8");
12563
+ const cfgRaw = readFileSync12(join15(base, "cloud-guard.json"), "utf-8");
12445
12564
  const { apiKey, apiUrl } = JSON.parse(cfgRaw);
12446
12565
  if (apiKey) {
12447
12566
  const url = `${apiUrl || "https://api.solongate.com"}/api/v1/policies/active`;
@@ -12470,7 +12589,7 @@ function setCors(req, res) {
12470
12589
  }
12471
12590
  function fileInfo(dir) {
12472
12591
  if (!dir) return { file: null, exists: false, size: 0, mtimeMs: 0 };
12473
- const file = join14(dir, LOG_FILENAME);
12592
+ const file = join15(dir, LOG_FILENAME);
12474
12593
  try {
12475
12594
  const st = statSync5(file);
12476
12595
  return { file, exists: true, size: st.size, mtimeMs: st.mtimeMs };
@@ -12480,6 +12599,28 @@ function fileInfo(dir) {
12480
12599
  }
12481
12600
  async function runLogsServer() {
12482
12601
  const argv = process.argv.slice(3);
12602
+ const verb = argv[0];
12603
+ if (verb === "start" || verb === "stop" || verb === "status") {
12604
+ const d = await Promise.resolve().then(() => (init_logs_server_daemon(), logs_server_daemon_exports));
12605
+ if (verb === "start") {
12606
+ d.startLogsServerDaemon();
12607
+ await new Promise((r) => setTimeout(r, 800));
12608
+ const st = d.logsServerStatus();
12609
+ process.stdout.write(
12610
+ st.running ? `[SolonGate] Local logs service running on http://127.0.0.1:${st.port} \u2014 background service, survives closing this terminal. Disable: solongate logs-server stop
12611
+ ` : `[SolonGate] Could not start the local logs service \u2014 see ~/.solongate/logs-server.log
12612
+ `
12613
+ );
12614
+ } else if (verb === "stop") {
12615
+ d.stopLogsServerDaemon();
12616
+ process.stdout.write("[SolonGate] Local logs service stopped and disabled (re-enable from the dataroom Settings or with `solongate logs-server start`).\n");
12617
+ } else {
12618
+ const st = d.logsServerStatus();
12619
+ process.stdout.write(`[SolonGate] Local logs service: ${st.running ? `running on http://127.0.0.1:${st.port} (pid ${st.pid})` : "stopped"} \xB7 desired ${st.desired}
12620
+ `);
12621
+ }
12622
+ return;
12623
+ }
12483
12624
  const portArg = argv[argv.indexOf("--port") + 1];
12484
12625
  const port = Number(process.env.SOLONGATE_LOGS_PORT || (argv.includes("--port") ? portArg : "") || DEFAULT_PORT) || DEFAULT_PORT;
12485
12626
  const server = createServer2(async (req, res) => {
@@ -12531,7 +12672,7 @@ async function runLogsServer() {
12531
12672
  return;
12532
12673
  }
12533
12674
  try {
12534
- const text = readFileSync11(info.file, "utf-8");
12675
+ const text = readFileSync12(info.file, "utf-8");
12535
12676
  res.writeHead(200, { "Content-Type": "text/plain; charset=utf-8", "Last-Modified": lastMod, "X-Solongate-Exists": "1" });
12536
12677
  res.end(text);
12537
12678
  } catch {
@@ -12544,6 +12685,8 @@ async function runLogsServer() {
12544
12685
  res.end("not found");
12545
12686
  });
12546
12687
  server.listen(port, "127.0.0.1", async () => {
12688
+ const { recordLogsServerStarted: recordLogsServerStarted2 } = await Promise.resolve().then(() => (init_logs_server_daemon(), logs_server_daemon_exports));
12689
+ recordLogsServerStarted2(port);
12547
12690
  const { dir, configured } = await findLogDir();
12548
12691
  process.stdout.write(`[SolonGate] Local logs agent listening on http://127.0.0.1:${port}
12549
12692
  `);
@@ -12583,7 +12726,7 @@ var init_logs_server = __esm({
12583
12726
 
12584
12727
  // src/inject.ts
12585
12728
  var inject_exports = {};
12586
- import { readFileSync as readFileSync12, writeFileSync as writeFileSync9, existsSync as existsSync8, copyFileSync } from "fs";
12729
+ import { readFileSync as readFileSync13, writeFileSync as writeFileSync10, existsSync as existsSync8, copyFileSync } from "fs";
12587
12730
  import { resolve as resolve7 } from "path";
12588
12731
  import { execSync } from "child_process";
12589
12732
  function parseInjectArgs(argv) {
@@ -12643,7 +12786,7 @@ WHAT IT DOES
12643
12786
  function detectProject() {
12644
12787
  if (!existsSync8(resolve7("package.json"))) return false;
12645
12788
  try {
12646
- const pkg = JSON.parse(readFileSync12(resolve7("package.json"), "utf-8"));
12789
+ const pkg = JSON.parse(readFileSync13(resolve7("package.json"), "utf-8"));
12647
12790
  const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
12648
12791
  return !!(allDeps["@modelcontextprotocol/sdk"] || allDeps["@modelcontextprotocol/server"]);
12649
12792
  } catch {
@@ -12652,7 +12795,7 @@ function detectProject() {
12652
12795
  }
12653
12796
  function findTsEntryFile() {
12654
12797
  try {
12655
- const pkg = JSON.parse(readFileSync12(resolve7("package.json"), "utf-8"));
12798
+ const pkg = JSON.parse(readFileSync13(resolve7("package.json"), "utf-8"));
12656
12799
  if (pkg.bin) {
12657
12800
  const binPath = typeof pkg.bin === "string" ? pkg.bin : Object.values(pkg.bin)[0];
12658
12801
  if (typeof binPath === "string") {
@@ -12679,7 +12822,7 @@ function findTsEntryFile() {
12679
12822
  const full = resolve7(c2);
12680
12823
  if (existsSync8(full)) {
12681
12824
  try {
12682
- const content = readFileSync12(full, "utf-8");
12825
+ const content = readFileSync13(full, "utf-8");
12683
12826
  if (content.includes("McpServer") || content.includes("McpServer")) {
12684
12827
  return full;
12685
12828
  }
@@ -12699,7 +12842,7 @@ function detectPackageManager() {
12699
12842
  }
12700
12843
  function installSdk() {
12701
12844
  try {
12702
- const pkg = JSON.parse(readFileSync12(resolve7("package.json"), "utf-8"));
12845
+ const pkg = JSON.parse(readFileSync13(resolve7("package.json"), "utf-8"));
12703
12846
  const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
12704
12847
  if (allDeps["@solongate/proxy"]) {
12705
12848
  log3(" @solongate/proxy already installed");
@@ -12720,7 +12863,7 @@ function installSdk() {
12720
12863
  }
12721
12864
  }
12722
12865
  function injectTypeScript(filePath) {
12723
- const original = readFileSync12(filePath, "utf-8");
12866
+ const original = readFileSync13(filePath, "utf-8");
12724
12867
  const changes = [];
12725
12868
  let modified = original;
12726
12869
  if (modified.includes("SecureMcpServer")) {
@@ -12891,7 +13034,7 @@ async function main2() {
12891
13034
  log3("");
12892
13035
  log3(` Backup: ${backupPath}`);
12893
13036
  }
12894
- writeFileSync9(entryFile, result.modified);
13037
+ writeFileSync10(entryFile, result.modified);
12895
13038
  log3("");
12896
13039
  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");
12897
13040
  log3(" \u2502 SolonGate SDK injected successfully! \u2502");
@@ -12920,8 +13063,8 @@ var init_inject = __esm({
12920
13063
 
12921
13064
  // src/create.ts
12922
13065
  var create_exports = {};
12923
- import { mkdirSync as mkdirSync9, writeFileSync as writeFileSync10, existsSync as existsSync9 } from "fs";
12924
- import { resolve as resolve8, join as join15 } from "path";
13066
+ import { mkdirSync as mkdirSync10, writeFileSync as writeFileSync11, existsSync as existsSync9 } from "fs";
13067
+ import { resolve as resolve8, join as join16 } from "path";
12925
13068
  import { execSync as execSync2 } from "child_process";
12926
13069
  function withSpinner(message, fn) {
12927
13070
  const frames = ["\u28FE", "\u28FD", "\u28FB", "\u28BF", "\u287F", "\u28DF", "\u28EF", "\u28F7"];
@@ -13000,8 +13143,8 @@ EXAMPLES
13000
13143
  `);
13001
13144
  }
13002
13145
  function createProject(dir, name, _policy) {
13003
- writeFileSync10(
13004
- join15(dir, "package.json"),
13146
+ writeFileSync11(
13147
+ join16(dir, "package.json"),
13005
13148
  JSON.stringify(
13006
13149
  {
13007
13150
  name,
@@ -13030,8 +13173,8 @@ function createProject(dir, name, _policy) {
13030
13173
  2
13031
13174
  ) + "\n"
13032
13175
  );
13033
- writeFileSync10(
13034
- join15(dir, "tsconfig.json"),
13176
+ writeFileSync11(
13177
+ join16(dir, "tsconfig.json"),
13035
13178
  JSON.stringify(
13036
13179
  {
13037
13180
  compilerOptions: {
@@ -13051,9 +13194,9 @@ function createProject(dir, name, _policy) {
13051
13194
  2
13052
13195
  ) + "\n"
13053
13196
  );
13054
- mkdirSync9(join15(dir, "src"), { recursive: true });
13055
- writeFileSync10(
13056
- join15(dir, "src", "index.ts"),
13197
+ mkdirSync10(join16(dir, "src"), { recursive: true });
13198
+ writeFileSync11(
13199
+ join16(dir, "src", "index.ts"),
13057
13200
  `#!/usr/bin/env node
13058
13201
 
13059
13202
  console.log = (...args: unknown[]) => {
@@ -13094,8 +13237,8 @@ console.log('');
13094
13237
  console.log('Press Ctrl+C to stop.');
13095
13238
  `
13096
13239
  );
13097
- writeFileSync10(
13098
- join15(dir, ".mcp.json"),
13240
+ writeFileSync11(
13241
+ join16(dir, ".mcp.json"),
13099
13242
  JSON.stringify(
13100
13243
  {
13101
13244
  mcpServers: {
@@ -13112,13 +13255,13 @@ console.log('Press Ctrl+C to stop.');
13112
13255
  2
13113
13256
  ) + "\n"
13114
13257
  );
13115
- writeFileSync10(
13116
- join15(dir, ".env"),
13258
+ writeFileSync11(
13259
+ join16(dir, ".env"),
13117
13260
  `SOLONGATE_API_KEY=sg_live_YOUR_KEY_HERE
13118
13261
  `
13119
13262
  );
13120
- writeFileSync10(
13121
- join15(dir, ".gitignore"),
13263
+ writeFileSync11(
13264
+ join16(dir, ".gitignore"),
13122
13265
  `node_modules/
13123
13266
  dist/
13124
13267
  *.solongate-backup
@@ -13137,7 +13280,7 @@ async function main3() {
13137
13280
  process.exit(1);
13138
13281
  }
13139
13282
  withSpinner(`Setting up ${opts.name}...`, () => {
13140
- mkdirSync9(dir, { recursive: true });
13283
+ mkdirSync10(dir, { recursive: true });
13141
13284
  createProject(dir, opts.name, opts.policy);
13142
13285
  });
13143
13286
  if (!opts.noInstall) {
@@ -13211,14 +13354,14 @@ var init_create = __esm({
13211
13354
 
13212
13355
  // src/pull-push.ts
13213
13356
  var pull_push_exports = {};
13214
- import { readFileSync as readFileSync13, writeFileSync as writeFileSync11, existsSync as existsSync10 } from "fs";
13357
+ import { readFileSync as readFileSync14, writeFileSync as writeFileSync12, existsSync as existsSync10 } from "fs";
13215
13358
  import { resolve as resolve9 } from "path";
13216
13359
  function loadEnv() {
13217
13360
  if (process.env.SOLONGATE_API_KEY) return;
13218
13361
  const envPath = resolve9(".env");
13219
13362
  if (!existsSync10(envPath)) return;
13220
13363
  try {
13221
- const content = readFileSync13(envPath, "utf-8");
13364
+ const content = readFileSync14(envPath, "utf-8");
13222
13365
  for (const line of content.split("\n")) {
13223
13366
  const trimmed = line.trim();
13224
13367
  if (!trimmed || trimmed.startsWith("#")) continue;
@@ -13406,7 +13549,7 @@ async function pull(apiKey, file, policyId) {
13406
13549
  const policy = await fetchCloudPolicy(apiKey, API_URL, policyId);
13407
13550
  const { id: _id, ...policyWithoutId } = policy;
13408
13551
  const json = JSON.stringify(policyWithoutId, null, 2) + "\n";
13409
- writeFileSync11(file, json, "utf-8");
13552
+ writeFileSync12(file, json, "utf-8");
13410
13553
  log5("");
13411
13554
  log5(green2(" Saved to: ") + file);
13412
13555
  log5(` ${dim2("Name:")} ${policy.name}`);
@@ -13435,7 +13578,7 @@ async function push(apiKey, file, policyId) {
13435
13578
  log5(" solongate-proxy list");
13436
13579
  process.exit(1);
13437
13580
  }
13438
- const content = readFileSync13(file, "utf-8");
13581
+ const content = readFileSync14(file, "utf-8");
13439
13582
  let policy;
13440
13583
  try {
13441
13584
  policy = JSON.parse(content);
@@ -16591,6 +16734,10 @@ async function main5() {
16591
16734
  const { maybeSelfUpdate: maybeSelfUpdate2 } = await Promise.resolve().then(() => (init_self_update(), self_update_exports));
16592
16735
  maybeSelfUpdate2();
16593
16736
  }
16737
+ if (subcommand !== "logs-server" && subcommand !== "local-logs") {
16738
+ const { ensureLogsServerDaemon: ensureLogsServerDaemon2 } = await Promise.resolve().then(() => (init_logs_server_daemon(), logs_server_daemon_exports));
16739
+ ensureLogsServerDaemon2();
16740
+ }
16594
16741
  }
16595
16742
  if (process.argv.length <= 2) {
16596
16743
  if (process.stdout.isTTY && process.stdin.isTTY) {