@solongate/proxy 0.80.0 → 0.81.0

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
@@ -6702,6 +6702,34 @@ var init_client = __esm({
6702
6702
  }
6703
6703
  });
6704
6704
 
6705
+ // src/tui/config.ts
6706
+ import { readFileSync as readFileSync5 } from "fs";
6707
+ import { homedir as homedir3 } from "os";
6708
+ import { join as join5 } from "path";
6709
+ function loadConfig() {
6710
+ if (cached2) return cached2;
6711
+ const defaults = { notifications: true };
6712
+ try {
6713
+ const raw = readFileSync5(join5(homedir3(), ".solongate", "tui-config.json"), "utf-8");
6714
+ const j = JSON.parse(raw);
6715
+ cached2 = {
6716
+ notifications: j.notifications !== false,
6717
+ accent: typeof j.accent === "string" ? j.accent : void 0,
6718
+ pollMs: typeof j.pollMs === "number" ? j.pollMs : void 0
6719
+ };
6720
+ } catch {
6721
+ cached2 = defaults;
6722
+ }
6723
+ return cached2;
6724
+ }
6725
+ var cached2;
6726
+ var init_config2 = __esm({
6727
+ "src/tui/config.ts"() {
6728
+ "use strict";
6729
+ cached2 = null;
6730
+ }
6731
+ });
6732
+
6705
6733
  // src/tui/theme.ts
6706
6734
  function decisionColor(decision) {
6707
6735
  const d = (decision || "").toUpperCase();
@@ -6735,13 +6763,15 @@ function ago(ts) {
6735
6763
  if (s < 86400) return `${Math.floor(s / 3600)}h`;
6736
6764
  return `${Math.floor(s / 86400)}d`;
6737
6765
  }
6738
- var theme, BLOCKS;
6766
+ var accent, theme, BLOCKS;
6739
6767
  var init_theme = __esm({
6740
6768
  "src/tui/theme.ts"() {
6741
6769
  "use strict";
6770
+ init_config2();
6771
+ accent = loadConfig().accent;
6742
6772
  theme = {
6743
- accent: "cyan",
6744
- accentBright: "#5a8ce6",
6773
+ accent: accent || "cyan",
6774
+ accentBright: accent || "#5a8ce6",
6745
6775
  ok: "green",
6746
6776
  warn: "yellow",
6747
6777
  bad: "red",
@@ -7108,9 +7138,9 @@ var init_hooks = __esm({
7108
7138
  import { Box as Box2, Text as Text2, useInput } from "ink";
7109
7139
  import TextInput from "ink-text-input";
7110
7140
  import { spawn } from "child_process";
7111
- import { closeSync, openSync, readSync, statSync } from "fs";
7112
- import { homedir as homedir3 } from "os";
7113
- import { join as join5 } from "path";
7141
+ import { closeSync, mkdirSync as mkdirSync3, openSync, readSync, statSync, writeFileSync as writeFileSync3 } from "fs";
7142
+ import { homedir as homedir4 } from "os";
7143
+ import { join as join6 } from "path";
7114
7144
  import { useCallback as useCallback2, useEffect as useEffect2, useRef as useRef2, useState as useState2 } from "react";
7115
7145
  import { Fragment as Fragment2, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
7116
7146
  function tailLines(file, maxBytes = 131072) {
@@ -7420,6 +7450,7 @@ function LivePanel({ active: active2 }) {
7420
7450
  (id, title, msg, level = "warn") => {
7421
7451
  pushLog(`${level === "bad" ? "\u26D4" : "\u23F8"} ${msg}`, level);
7422
7452
  setAlerts((a) => [...a.filter((x) => x.id !== id), { id, msg, level, until: Date.now() + 15e3 }].slice(-4));
7453
+ if (!CONFIG.notifications) return;
7423
7454
  try {
7424
7455
  process.stdout.write("\x07");
7425
7456
  } catch {
@@ -7647,7 +7678,16 @@ function LivePanel({ active: active2 }) {
7647
7678
  else if (input === "d") toggleSignal("deny");
7648
7679
  else if (input === "x") toggleSignal("dlp");
7649
7680
  else if (input === "r") toggleSignal("ratelimit");
7650
- else if (key.downArrow) setSel((n) => Math.min(visibleDesc.length - 1, n + 1));
7681
+ else if (input === "e") {
7682
+ const file = join6(homedir4(), ".solongate", "live-export.jsonl");
7683
+ try {
7684
+ mkdirSync3(join6(homedir4(), ".solongate"), { recursive: true });
7685
+ writeFileSync3(file, visibleDesc.map((x) => JSON.stringify(x)).join("\n") + "\n");
7686
+ setActionMsg({ text: `\u2713 exported ${visibleDesc.length} lines \u2192 ${file}`, level: "ok", until: Date.now() + 6e3 });
7687
+ } catch (err2) {
7688
+ setActionMsg({ text: "\u2717 export failed: " + (err2 instanceof Error ? err2.message : String(err2)), level: "bad", until: Date.now() + 6e3 });
7689
+ }
7690
+ } else if (key.downArrow) setSel((n) => Math.min(visibleDesc.length - 1, n + 1));
7651
7691
  else if (key.upArrow) setSel((n) => Math.max(0, n - 1));
7652
7692
  else if (key.pageDown) setSel((n) => Math.min(visibleDesc.length - 1, n + streamBodyRows));
7653
7693
  else if (key.pageUp) setSel((n) => Math.max(0, n - streamBodyRows));
@@ -7896,18 +7936,20 @@ function LivePanel({ active: active2 }) {
7896
7936
  ] })
7897
7937
  ] });
7898
7938
  }
7899
- var SPIN, BG, DIM_FLOOR, LOCAL_LOG, RING, hhmmss, fmtUp, FILTERS, sessStatus, STATUS_STYLE;
7939
+ var CONFIG, SPIN, BG, DIM_FLOOR, LOCAL_LOG, RING, hhmmss, fmtUp, FILTERS, sessStatus, STATUS_STYLE;
7900
7940
  var init_Live = __esm({
7901
7941
  "src/tui/panels/Live.tsx"() {
7902
7942
  "use strict";
7903
7943
  init_api_client();
7944
+ init_config2();
7904
7945
  init_hooks();
7905
7946
  init_theme();
7947
+ CONFIG = loadConfig();
7906
7948
  SPIN = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
7907
7949
  BG = "#12234f";
7908
7950
  DIM_FLOOR = "#233457";
7909
- LOCAL_LOG = join5(homedir3(), ".solongate", "local-logs", "solongate-audit.jsonl");
7910
- RING = join5(process.cwd(), ".solongate", ".eval-ring.jsonl");
7951
+ LOCAL_LOG = join6(homedir4(), ".solongate", "local-logs", "solongate-audit.jsonl");
7952
+ RING = join6(process.cwd(), ".solongate", ".eval-ring.jsonl");
7911
7953
  hhmmss = (ts) => {
7912
7954
  const d = new Date(ts);
7913
7955
  return Number.isNaN(d.getTime()) ? "--:--:--" : d.toTimeString().slice(0, 8);
@@ -7931,7 +7973,7 @@ var init_Live = __esm({
7931
7973
  import { Box as Box3, Text as Text3, useInput as useInput2 } from "ink";
7932
7974
  import TextInput2 from "ink-text-input";
7933
7975
  import { useEffect as useEffect3, useState as useState3 } from "react";
7934
- import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
7976
+ import { Fragment as Fragment3, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
7935
7977
  function ruleSummary(r) {
7936
7978
  const bits = [];
7937
7979
  for (const [g, tag] of [["commandConstraints", "cmd"], ["pathConstraints", "path"], ["filenameConstraints", "file"], ["urlConstraints", "url"]]) {
@@ -7961,6 +8003,11 @@ function PoliciesPanel({ focused }) {
7961
8003
  () => view === "versions" && selected ? api.policies.versions(selected.id, { limit: 50 }) : Promise.resolve(null),
7962
8004
  [view, selected?.id]
7963
8005
  );
8006
+ const diffVer = versionsQ.data?.versions[vi]?.version;
8007
+ const diffQ = useLoader(
8008
+ () => view === "versions" && selected && diffVer !== void 0 ? api.policies.get(selected.id, diffVer) : Promise.resolve(null),
8009
+ [view, selected?.id, diffVer]
8010
+ );
7964
8011
  useEffect3(() => {
7965
8012
  if (detail.data) {
7966
8013
  setRules(detail.data.rules);
@@ -8164,6 +8211,23 @@ function PoliciesPanel({ focused }) {
8164
8211
  ])
8165
8212
  }
8166
8213
  ) }),
8214
+ /* @__PURE__ */ jsxs3(Box3, { marginTop: 1, flexDirection: "column", children: [
8215
+ /* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: `Diff v${diffVer ?? "?"} vs current draft` }),
8216
+ (() => {
8217
+ const old = diffQ.data?.rules ?? [];
8218
+ const cur = rules;
8219
+ const oldIds = new Set(old.map((r) => r.id));
8220
+ const curIds = new Set(cur.map((r) => r.id));
8221
+ const added = cur.filter((r) => !oldIds.has(r.id));
8222
+ const removed = old.filter((r) => !curIds.has(r.id));
8223
+ if (diffQ.loading && !diffQ.data) return /* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: " loading\u2026" });
8224
+ if (!added.length && !removed.length) return /* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: " identical rule set" });
8225
+ return /* @__PURE__ */ jsxs3(Fragment3, { children: [
8226
+ added.slice(0, 4).map((r) => /* @__PURE__ */ jsx3(Text3, { wrap: "truncate", color: theme.ok, children: ` + ${r.effect} ${truncate2(r.toolPattern, 18)} ${truncate2(r.description || r.id, 30)}` }, "a" + r.id)),
8227
+ removed.slice(0, 4).map((r) => /* @__PURE__ */ jsx3(Text3, { wrap: "truncate", color: theme.bad, children: ` - ${r.effect} ${truncate2(r.toolPattern, 18)} ${truncate2(r.description || r.id, 30)}` }, "r" + r.id))
8228
+ ] });
8229
+ })()
8230
+ ] }),
8167
8231
  status ? /* @__PURE__ */ jsx3(Text3, { color: status.startsWith("\u2717") ? theme.bad : theme.ok, children: status }) : null
8168
8232
  ] }) });
8169
8233
  }
@@ -8308,6 +8372,20 @@ function RateLimitPanel({ focused }) {
8308
8372
  /* @__PURE__ */ jsx4(FieldRow, { label: "Per hour", active: focused && fi === 2, children: /* @__PURE__ */ jsx4(Text4, { bold: true, children: draft.perHour === 0 ? "off" : draft.perHour }) }),
8309
8373
  /* @__PURE__ */ jsx4(FieldRow, { label: "Per day", active: focused && fi === 3, children: /* @__PURE__ */ jsx4(Text4, { bold: true, children: draft.perDay === 0 ? "off" : draft.perDay }) })
8310
8374
  ] }),
8375
+ draft.perMinute > 0 ? (() => {
8376
+ const now = minuteSeries.slice(-1)[0] ?? 0;
8377
+ const pct = Math.min(100, Math.round(now / draft.perMinute * 100));
8378
+ const width2 = 30;
8379
+ const filled = Math.min(width2, Math.round(now / draft.perMinute * width2));
8380
+ const col = pct >= 100 ? theme.bad : pct >= 80 ? theme.warn : theme.ok;
8381
+ return /* @__PURE__ */ jsxs4(Box4, { marginTop: 1, children: [
8382
+ /* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: "load " }),
8383
+ /* @__PURE__ */ jsx4(Text4, { color: col, children: "\u2588".repeat(filled) }),
8384
+ /* @__PURE__ */ jsx4(Text4, { color: "#233457", children: "\u2591".repeat(Math.max(0, width2 - filled)) }),
8385
+ /* @__PURE__ */ jsx4(Text4, { color: col, children: ` ${now}/${draft.perMinute} ` }),
8386
+ /* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: `(${pct}% this min)` })
8387
+ ] });
8388
+ })() : null,
8311
8389
  dirty || status ? /* @__PURE__ */ jsxs4(Box4, { marginTop: 1, children: [
8312
8390
  dirty ? /* @__PURE__ */ jsx4(Text4, { color: theme.warn, children: "\u25CF unsaved \u2014 press s to apply " }) : null,
8313
8391
  status ? /* @__PURE__ */ jsx4(Text4, { color: status.startsWith("\u2717") ? theme.bad : theme.ok, children: status }) : null
@@ -8532,10 +8610,27 @@ function DlpPanel({ focused }) {
8532
8610
  }
8533
8611
  )
8534
8612
  ] }) : null,
8613
+ adding === "re" ? /* @__PURE__ */ jsx5(RegexTest, { re: newRe }) : null,
8535
8614
  status ? /* @__PURE__ */ jsx5(Box5, { marginTop: 1, children: /* @__PURE__ */ jsx5(Text5, { color: status.startsWith("\u2717") ? theme.bad : theme.ok, children: status }) }) : null
8536
8615
  ] }) : null });
8537
8616
  }
8538
- var MODES2;
8617
+ function RegexTest({ re }) {
8618
+ if (!re.trim()) return /* @__PURE__ */ jsx5(Text5, { color: theme.dim, children: " regex: type a pattern\u2026" });
8619
+ let rx = null;
8620
+ let err2 = "";
8621
+ try {
8622
+ rx = new RegExp(re);
8623
+ } catch (e) {
8624
+ err2 = e instanceof Error ? e.message : String(e);
8625
+ }
8626
+ if (!rx) return /* @__PURE__ */ jsx5(Text5, { color: theme.bad, children: ` \u2717 invalid: ${err2.slice(0, 50)}` });
8627
+ const hits = SAMPLES.filter((s) => rx.test(s));
8628
+ return /* @__PURE__ */ jsxs5(Text5, { wrap: "truncate", children: [
8629
+ /* @__PURE__ */ jsx5(Text5, { color: theme.ok, children: " \u2713 valid" }),
8630
+ /* @__PURE__ */ jsx5(Text5, { color: theme.dim, children: hits.length ? ` matches ${hits.length}/${SAMPLES.length} samples: ${hits.map((h) => h.slice(0, 8)).join(", ")}` : " (no sample match \u2014 will only catch your custom secrets)" })
8631
+ ] });
8632
+ }
8633
+ var MODES2, SAMPLES;
8539
8634
  var init_Dlp = __esm({
8540
8635
  "src/tui/panels/Dlp.tsx"() {
8541
8636
  "use strict";
@@ -8544,6 +8639,7 @@ var init_Dlp = __esm({
8544
8639
  init_hooks();
8545
8640
  init_theme();
8546
8641
  MODES2 = ["off", "detect", "block"];
8642
+ SAMPLES = ["AKIA1234567890ABCD00", "sk-ant-api03-xxxxxxxx", "ghp_16chars0000000000000000000000000000", "password=hunter2", "Bearer eyJhbGciOi"];
8547
8643
  }
8548
8644
  });
8549
8645
 
@@ -8839,18 +8935,114 @@ var init_Audit = __esm({
8839
8935
  }
8840
8936
  });
8841
8937
 
8842
- // src/tui/App.tsx
8843
- import { Box as Box8, Text as Text8, useApp, useInput as useInput6 } from "ink";
8938
+ // src/tui/panels/Agents.tsx
8939
+ import { Box as Box8, Text as Text8, useInput as useInput6 } from "ink";
8844
8940
  import { useState as useState7 } from "react";
8845
- import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
8941
+ import { Fragment as Fragment4, jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
8942
+ function Bar({ label, value, max = 100, width: width2 = 16, color = theme.accent }) {
8943
+ const filled = max > 0 ? Math.round(Math.min(value, max) / max * width2) : 0;
8944
+ return /* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", children: [
8945
+ /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: label.padEnd(9) }),
8946
+ /* @__PURE__ */ jsx8(Text8, { color, children: "\u2588".repeat(filled) }),
8947
+ /* @__PURE__ */ jsx8(Text8, { color: "#233457", children: "\u2591".repeat(Math.max(0, width2 - filled)) }),
8948
+ /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: " " + value })
8949
+ ] });
8950
+ }
8951
+ function AgentsPanel({ focused }) {
8952
+ const live2 = useLoader(() => api.agents.live({ limit: 30, includeDeactivated: true }));
8953
+ usePoll(live2.reload, 6e3, focused ? false : true);
8954
+ const [sel, setSel] = useState7(0);
8955
+ const agents = (live2.data?.agents ?? []).filter((a) => a.agent_id);
8956
+ const selected = agents[Math.min(sel, Math.max(0, agents.length - 1))];
8957
+ const detail = useLoader(() => selected?.agent_id ? api.agents.get(selected.agent_id) : Promise.resolve(null), [selected?.agent_id]);
8958
+ useInput6(
8959
+ (_input, key) => {
8960
+ if (key.upArrow) setSel((n) => Math.max(0, n - 1));
8961
+ else if (key.downArrow) setSel((n) => Math.min(agents.length - 1, n + 1));
8962
+ },
8963
+ { isActive: focused }
8964
+ );
8965
+ const d = detail.data;
8966
+ const base = d?.baseline;
8967
+ const radar = base?.radar;
8968
+ const anomalies2 = d?.anomalies ?? [];
8969
+ const tmap = d?.trust_map;
8970
+ const tools = tmap?.tools ?? [];
8971
+ const resources = tmap?.resources ?? [];
8972
+ const listW = 30;
8973
+ return /* @__PURE__ */ jsx8(DataView, { loading: live2.loading && !live2.data, error: live2.error, empty: !!live2.data && agents.length === 0, emptyText: "No identified agents yet.", children: /* @__PURE__ */ jsxs8(Box8, { children: [
8974
+ /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", width: listW, marginRight: 2, overflow: "hidden", children: [
8975
+ /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: focused ? "\u2191\u2193 select agent" : "press \u2192 to browse" }),
8976
+ agents.slice(0, 16).map((a, i) => /* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", backgroundColor: focused && i === sel ? "#1c2f63" : void 0, bold: i === sel, children: [
8977
+ /* @__PURE__ */ jsxs8(Text8, { color: statusColor(a.status), children: [
8978
+ a.status === "active" ? "\u25CF" : a.status === "idle" ? "\u25D0" : "\u25CB",
8979
+ " "
8980
+ ] }),
8981
+ /* @__PURE__ */ jsx8(Text8, { color: theme.accent, children: truncate2(a.agent_name ?? a.agent_id ?? "?", 16).padEnd(17) }),
8982
+ /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: `t${a.trust_score}` })
8983
+ ] }, a.session_id))
8984
+ ] }),
8985
+ /* @__PURE__ */ jsx8(Box8, { flexDirection: "column", flexGrow: 1, overflow: "hidden", children: !selected ? /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "select an agent" }) : detail.loading && !d ? /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "loading profile\u2026" }) : !d ? /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "no profile (agent has no calls yet)" }) : /* @__PURE__ */ jsxs8(Fragment4, { children: [
8986
+ /* @__PURE__ */ jsxs8(Box8, { children: [
8987
+ /* @__PURE__ */ jsx8(Text8, { bold: true, color: theme.accentBright, children: truncate2(selected.agent_name ?? selected.agent_id ?? "?", 22) }),
8988
+ /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: ` trust ${base?.trustScore ?? "\u2014"}/100 \xB7 ${base?.character ?? ""}` })
8989
+ ] }),
8990
+ base?.characterBlurb ? /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: truncate2(String(base.characterBlurb), 70) }) : null,
8991
+ radar ? /* @__PURE__ */ jsxs8(Box8, { marginTop: 1, flexDirection: "column", children: [
8992
+ /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "Behaviour radar (0\u2013100)" }),
8993
+ /* @__PURE__ */ jsx8(Bar, { label: "read", value: Math.round((radar.read ?? 0) * 100) }),
8994
+ /* @__PURE__ */ jsx8(Bar, { label: "write", value: Math.round((radar.write ?? 0) * 100), color: theme.warn }),
8995
+ /* @__PURE__ */ jsx8(Bar, { label: "execute", value: Math.round((radar.execute ?? 0) * 100), color: theme.warn }),
8996
+ /* @__PURE__ */ jsx8(Bar, { label: "network", value: Math.round((radar.network ?? 0) * 100) }),
8997
+ /* @__PURE__ */ jsx8(Bar, { label: "complian.", value: Math.round((radar.compliance ?? 0) * 100), color: theme.ok })
8998
+ ] }) : null,
8999
+ /* @__PURE__ */ jsxs8(Box8, { marginTop: 1, flexDirection: "column", children: [
9000
+ /* @__PURE__ */ jsxs8(Text8, { color: theme.dim, children: [
9001
+ "Anomalies ",
9002
+ anomalies2.length ? `(${anomalies2.length})` : ""
9003
+ ] }),
9004
+ anomalies2.length === 0 ? /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: " none" }) : anomalies2.slice(0, 4).map((an, i) => /* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", children: [
9005
+ /* @__PURE__ */ jsx8(Text8, { color: sevColor(String(an.severity)), children: ` ${String(an.severity).toUpperCase().slice(0, 4).padEnd(5)}` }),
9006
+ /* @__PURE__ */ jsx8(Text8, { color: theme.accent, children: String(an.kind).padEnd(12) }),
9007
+ /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: truncate2(String(an.description ?? ""), 44) })
9008
+ ] }, i))
9009
+ ] }),
9010
+ /* @__PURE__ */ jsxs8(Box8, { marginTop: 1, flexDirection: "column", children: [
9011
+ /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "Trust map \xB7 top tools" }),
9012
+ tools.slice(0, 4).map((t, i) => /* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", children: [
9013
+ /* @__PURE__ */ jsx8(Text8, { color: t.anomalous ? theme.bad : theme.accent, children: ` ${truncate2(String(t.name), 16).padEnd(17)}` }),
9014
+ /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: `${t.count}\xD7 ${t.permission ?? ""}` })
9015
+ ] }, i)),
9016
+ resources.slice(0, 3).map((r, i) => /* @__PURE__ */ jsx8(Text8, { wrap: "truncate", color: r.anomalous ? theme.bad : theme.dim, children: ` ${r.type === "domain" ? "\u{1F310}" : "\u{1F4C1}"} ${truncate2(String(r.value), 40)} ${r.count}\xD7` }, "r" + i))
9017
+ ] })
9018
+ ] }) })
9019
+ ] }) });
9020
+ }
9021
+ var statusColor, sevColor;
9022
+ var init_Agents = __esm({
9023
+ "src/tui/panels/Agents.tsx"() {
9024
+ "use strict";
9025
+ init_api_client();
9026
+ init_components();
9027
+ init_hooks();
9028
+ init_theme();
9029
+ statusColor = (s) => s === "active" ? theme.ok : s === "idle" ? theme.warn : theme.dim;
9030
+ sevColor = (s) => s === "high" ? theme.bad : s === "medium" ? theme.warn : theme.dim;
9031
+ }
9032
+ });
9033
+
9034
+ // src/tui/App.tsx
9035
+ import { Box as Box9, Text as Text9, useApp, useInput as useInput7 } from "ink";
9036
+ import { useState as useState8 } from "react";
9037
+ import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
8846
9038
  function LiveHint() {
8847
- return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
8848
- /* @__PURE__ */ jsx8(Text8, { color: theme.accentBright, bold: true, children: "\u25B6 REALTIME CONSOLE" }),
8849
- /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "Fullscreen live monitor \u2014 streaming tool calls, active charts," }),
8850
- /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "counters, DLP hits and denial alerts. Updates every 2s." }),
8851
- /* @__PURE__ */ jsx8(Box8, { marginTop: 1, children: /* @__PURE__ */ jsxs8(Text8, { children: [
9039
+ return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", children: [
9040
+ /* @__PURE__ */ jsx9(Text9, { color: theme.accentBright, bold: true, children: "\u25B6 REALTIME CONSOLE" }),
9041
+ /* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: "Fullscreen live monitor \u2014 streaming tool calls, active charts," }),
9042
+ /* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: "counters, DLP hits and denial alerts. Updates every 2s." }),
9043
+ /* @__PURE__ */ jsx9(Box9, { marginTop: 1, children: /* @__PURE__ */ jsxs9(Text9, { children: [
8852
9044
  "press ",
8853
- /* @__PURE__ */ jsx8(Text8, { color: theme.accent, children: "enter" }),
9045
+ /* @__PURE__ */ jsx9(Text9, { color: theme.accent, children: "enter" }),
8854
9046
  " to go live"
8855
9047
  ] }) })
8856
9048
  ] });
@@ -8858,22 +9050,22 @@ function LiveHint() {
8858
9050
  function Banner() {
8859
9051
  const wide = (process.stdout.columns ?? 80) >= 82;
8860
9052
  if (!wide) {
8861
- return /* @__PURE__ */ jsxs8(Box8, { children: [
8862
- /* @__PURE__ */ jsx8(Text8, { bold: true, color: theme.accentBright, children: "SolonGate" }),
8863
- /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: " \u2014 security control center" })
9053
+ return /* @__PURE__ */ jsxs9(Box9, { children: [
9054
+ /* @__PURE__ */ jsx9(Text9, { bold: true, color: theme.accentBright, children: "SolonGate" }),
9055
+ /* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: " \u2014 security control center" })
8864
9056
  ] });
8865
9057
  }
8866
- return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
8867
- BANNER_FULL.map((line, i) => /* @__PURE__ */ jsx8(Text8, { bold: true, color: BANNER_HEX[i], children: line }, i)),
8868
- /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: " security control center \xB7 manage policies, rate limits, DLP & more" })
9058
+ return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", children: [
9059
+ BANNER_FULL.map((line, i) => /* @__PURE__ */ jsx9(Text9, { bold: true, color: BANNER_HEX[i], children: line }, i)),
9060
+ /* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: " security control center \xB7 manage policies, rate limits, DLP & more" })
8869
9061
  ] });
8870
9062
  }
8871
9063
  function App() {
8872
9064
  const { exit } = useApp();
8873
- const [section, setSection] = useState7(0);
8874
- const [focus, setFocus] = useState7("nav");
8875
- const [help, setHelp] = useState7(false);
8876
- useInput6((input, key) => {
9065
+ const [section, setSection] = useState8(0);
9066
+ const [focus, setFocus] = useState8("nav");
9067
+ const [help, setHelp] = useState8(false);
9068
+ useInput7((input, key) => {
8877
9069
  if (help) {
8878
9070
  setHelp(false);
8879
9071
  return;
@@ -8895,31 +9087,31 @@ function App() {
8895
9087
  const cols = process.stdout.columns ?? 100;
8896
9088
  const rows = process.stdout.rows ?? 30;
8897
9089
  const current = SECTIONS[section];
8898
- if (help) return /* @__PURE__ */ jsx8(HelpOverlay, { cols, rows });
9090
+ if (help) return /* @__PURE__ */ jsx9(HelpOverlay, { cols, rows });
8899
9091
  if (current.label === "Live" && focus === "panel") {
8900
- return /* @__PURE__ */ jsx8(Box8, { flexDirection: "column", width: cols, height: rows, children: /* @__PURE__ */ jsx8(LivePanel, { active: true, focused: true }) });
9092
+ return /* @__PURE__ */ jsx9(Box9, { flexDirection: "column", width: cols, height: rows, children: /* @__PURE__ */ jsx9(LivePanel, { active: true, focused: true }) });
8901
9093
  }
8902
9094
  const Panel = current.Panel;
8903
- return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", width: cols, height: rows, paddingX: 1, paddingTop: 1, children: [
8904
- /* @__PURE__ */ jsx8(Banner, {}),
8905
- /* @__PURE__ */ jsxs8(Box8, { marginTop: 1, flexGrow: 1, children: [
8906
- /* @__PURE__ */ jsx8(Box8, { flexDirection: "column", width: 16, borderStyle: "round", borderColor: focus === "nav" ? theme.accent : "gray", paddingX: 1, children: SECTIONS.map((s, i) => /* @__PURE__ */ jsx8(Text8, { color: i === section ? theme.accentBright : void 0, bold: i === section, children: (i === section ? "\u25B8 " : " ") + s.label }, s.label)) }),
8907
- /* @__PURE__ */ jsx8(Box8, { flexGrow: 1, borderStyle: "round", borderColor: focus === "panel" ? theme.accent : "gray", paddingX: 1, paddingY: 0, children: /* @__PURE__ */ jsx8(Panel, { active: focus === "panel" || current.label !== "Live", focused: focus === "panel" }) })
9095
+ return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", width: cols, height: rows, paddingX: 1, paddingTop: 1, children: [
9096
+ /* @__PURE__ */ jsx9(Banner, {}),
9097
+ /* @__PURE__ */ jsxs9(Box9, { marginTop: 1, flexGrow: 1, children: [
9098
+ /* @__PURE__ */ jsx9(Box9, { flexDirection: "column", width: 16, borderStyle: "round", borderColor: focus === "nav" ? theme.accent : "gray", paddingX: 1, children: SECTIONS.map((s, i) => /* @__PURE__ */ jsx9(Text9, { color: i === section ? theme.accentBright : void 0, bold: i === section, children: (i === section ? "\u25B8 " : " ") + s.label }, s.label)) }),
9099
+ /* @__PURE__ */ jsx9(Box9, { flexGrow: 1, borderStyle: "round", borderColor: focus === "panel" ? theme.accent : "gray", paddingX: 1, paddingY: 0, children: /* @__PURE__ */ jsx9(Panel, { active: focus === "panel" || current.label !== "Live", focused: focus === "panel" }) })
8908
9100
  ] }),
8909
- /* @__PURE__ */ jsx8(Box8, { children: focus === "nav" ? /* @__PURE__ */ jsx8(KeyHints, { hints: [["\u2191\u2193", "section"], ["\u2192/enter", "open"], ["?", "help"], ["q", "quit"]] }) : /* @__PURE__ */ jsx8(KeyHints, { hints: [["\u2190/esc", "back"], ["\u2191\u2193", "in-panel"], ["space/s", "act"]] }) })
9101
+ /* @__PURE__ */ jsx9(Box9, { children: focus === "nav" ? /* @__PURE__ */ jsx9(KeyHints, { hints: [["\u2191\u2193", "section"], ["\u2192/enter", "open"], ["?", "help"], ["q", "quit"]] }) : /* @__PURE__ */ jsx9(KeyHints, { hints: [["\u2190/esc", "back"], ["\u2191\u2193", "in-panel"], ["space/s", "act"]] }) })
8910
9102
  ] });
8911
9103
  }
8912
9104
  function HelpOverlay({ cols, rows }) {
8913
- return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", width: cols, height: rows, paddingX: 2, paddingTop: 1, children: [
8914
- /* @__PURE__ */ jsx8(Text8, { bold: true, color: theme.accentBright, children: "SolonGate \u2014 keyboard shortcuts" }),
8915
- /* @__PURE__ */ jsx8(Box8, { marginTop: 1, flexDirection: "column", children: HELP.map(([group, keys]) => /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", marginBottom: 1, children: [
8916
- /* @__PURE__ */ jsx8(Text8, { bold: true, color: theme.accent, children: group }),
8917
- keys.map(([k, desc]) => /* @__PURE__ */ jsxs8(Text8, { children: [
8918
- /* @__PURE__ */ jsx8(Text8, { color: theme.accentBright, children: (" " + k).padEnd(16) }),
8919
- /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: desc })
9105
+ return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", width: cols, height: rows, paddingX: 2, paddingTop: 1, children: [
9106
+ /* @__PURE__ */ jsx9(Text9, { bold: true, color: theme.accentBright, children: "SolonGate \u2014 keyboard shortcuts" }),
9107
+ /* @__PURE__ */ jsx9(Box9, { marginTop: 1, flexDirection: "column", children: HELP.map(([group, keys]) => /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", marginBottom: 1, children: [
9108
+ /* @__PURE__ */ jsx9(Text9, { bold: true, color: theme.accent, children: group }),
9109
+ keys.map(([k, desc]) => /* @__PURE__ */ jsxs9(Text9, { children: [
9110
+ /* @__PURE__ */ jsx9(Text9, { color: theme.accentBright, children: (" " + k).padEnd(16) }),
9111
+ /* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: desc })
8920
9112
  ] }, k))
8921
9113
  ] }, group)) }),
8922
- /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "press any key to close" })
9114
+ /* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: "press any key to close" })
8923
9115
  ] });
8924
9116
  }
8925
9117
  var SECTIONS, BANNER_HEX, HELP;
@@ -8935,8 +9127,10 @@ var init_App = __esm({
8935
9127
  init_Dlp();
8936
9128
  init_Stats();
8937
9129
  init_Audit();
9130
+ init_Agents();
8938
9131
  SECTIONS = [
8939
9132
  { label: "Live", Panel: LiveHint },
9133
+ { label: "Agents", Panel: AgentsPanel },
8940
9134
  { label: "Policies", Panel: PoliciesPanel },
8941
9135
  { label: "Rate Limit", Panel: RateLimitPanel },
8942
9136
  { label: "DLP", Panel: DlpPanel },
@@ -8959,7 +9153,7 @@ __export(tui_exports, {
8959
9153
  launchTui: () => launchTui
8960
9154
  });
8961
9155
  import { render } from "ink";
8962
- import { jsx as jsx9 } from "react/jsx-runtime";
9156
+ import { jsx as jsx10 } from "react/jsx-runtime";
8963
9157
  async function launchTui() {
8964
9158
  if (!process.stdout.isTTY || !process.stdin.isTTY) {
8965
9159
  process.stderr.write(
@@ -8973,7 +9167,7 @@ async function launchTui() {
8973
9167
  }
8974
9168
  process.stdout.write("\x1B[?1049h\x1B[H");
8975
9169
  try {
8976
- const { waitUntilExit } = render(/* @__PURE__ */ jsx9(App, {}));
9170
+ const { waitUntilExit } = render(/* @__PURE__ */ jsx10(App, {}));
8977
9171
  await waitUntilExit();
8978
9172
  } finally {
8979
9173
  process.stdout.write("\x1B[?1049l");
@@ -9085,7 +9279,7 @@ var init_args = __esm({
9085
9279
  });
9086
9280
 
9087
9281
  // src/commands/policy.ts
9088
- import { readFileSync as readFileSync5 } from "fs";
9282
+ import { readFileSync as readFileSync6 } from "fs";
9089
9283
  async function run(argv) {
9090
9284
  const { positionals, flags } = parse(argv);
9091
9285
  const sub = positionals[0];
@@ -9260,7 +9454,7 @@ function printRules(rules) {
9260
9454
  }
9261
9455
  async function resolveRules(target) {
9262
9456
  if (target.endsWith(".json")) {
9263
- const parsed = JSON.parse(readFileSync5(target, "utf-8"));
9457
+ const parsed = JSON.parse(readFileSync6(target, "utf-8"));
9264
9458
  return parsed.rules ?? [];
9265
9459
  }
9266
9460
  const p = await api.policies.get(target);
@@ -9624,7 +9818,7 @@ async function runAgents(argv) {
9624
9818
  table(
9625
9819
  ["STATUS", "AGENT", "CALLS", "DENY", "DLP", "TRUST", "CHARACTER"],
9626
9820
  res.agents.map((a) => [
9627
- statusColor(a.status),
9821
+ statusColor2(a.status),
9628
9822
  cyan(truncate3(a.agent_name ?? a.agent_id ?? a.session_id, 20)),
9629
9823
  String(a.total_calls),
9630
9824
  a.denied_calls ? red(String(a.denied_calls)) : dim("0"),
@@ -9643,7 +9837,7 @@ async function runAgent(argv) {
9643
9837
  const a = await api.agents.get(id);
9644
9838
  if (json) return printJson(a), 0;
9645
9839
  err("");
9646
- err(` ${bold(a.agent_id)} status: ${statusColor(String(a.status))}`);
9840
+ err(` ${bold(a.agent_id)} status: ${statusColor2(String(a.status))}`);
9647
9841
  const base = a.baseline;
9648
9842
  if (base) {
9649
9843
  err(` ${dim(base.character ?? "")} trust ${bold(String(base.trustScore ?? "\u2014"))}/100 deny-rate ${(Number(base.denyRate ?? 0) * 100).toFixed(0)}%`);
@@ -9663,21 +9857,21 @@ async function runAgent(argv) {
9663
9857
  }
9664
9858
  return 0;
9665
9859
  }
9666
- var statusColor;
9860
+ var statusColor2;
9667
9861
  var init_agents2 = __esm({
9668
9862
  "src/commands/agents.ts"() {
9669
9863
  "use strict";
9670
9864
  init_api_client();
9671
9865
  init_args();
9672
9866
  init_format();
9673
- statusColor = (s) => s === "active" ? green(s) : s === "idle" ? yellow(s) : dim(s);
9867
+ statusColor2 = (s) => s === "active" ? green(s) : s === "idle" ? yellow(s) : dim(s);
9674
9868
  }
9675
9869
  });
9676
9870
 
9677
9871
  // src/commands/doctor.ts
9678
9872
  import { existsSync as existsSync4, statSync as statSync2 } from "fs";
9679
- import { homedir as homedir4 } from "os";
9680
- import { join as join6 } from "path";
9873
+ import { homedir as homedir5 } from "os";
9874
+ import { join as join7 } from "path";
9681
9875
  async function run6(argv) {
9682
9876
  const { flags } = parse(argv);
9683
9877
  const json = flagBool(flags, "json");
@@ -9737,14 +9931,14 @@ var init_doctor = __esm({
9737
9931
  init_api_client();
9738
9932
  init_format();
9739
9933
  init_args();
9740
- LOCAL_LOG2 = join6(homedir4(), ".solongate", "local-logs", "solongate-audit.jsonl");
9934
+ LOCAL_LOG2 = join7(homedir5(), ".solongate", "local-logs", "solongate-audit.jsonl");
9741
9935
  }
9742
9936
  });
9743
9937
 
9744
9938
  // src/commands/watch.ts
9745
9939
  import { closeSync as closeSync2, existsSync as existsSync5, openSync as openSync2, readSync as readSync2, statSync as statSync3 } from "fs";
9746
- import { homedir as homedir5 } from "os";
9747
- import { join as join7 } from "path";
9940
+ import { homedir as homedir6 } from "os";
9941
+ import { join as join8 } from "path";
9748
9942
  function tailLocal(file, maxBytes = 131072) {
9749
9943
  try {
9750
9944
  const size = statSync3(file).size;
@@ -9851,7 +10045,7 @@ var init_watch = __esm({
9851
10045
  init_cli_utils();
9852
10046
  init_args();
9853
10047
  init_format();
9854
- LOCAL_LOG3 = join7(homedir5(), ".solongate", "local-logs", "solongate-audit.jsonl");
10048
+ LOCAL_LOG3 = join8(homedir6(), ".solongate", "local-logs", "solongate-audit.jsonl");
9855
10049
  trunc = (s, n) => s.length <= n ? s : s.slice(0, n - 1) + "\u2026";
9856
10050
  time = (ms) => new Date(ms).toTimeString().slice(0, 8);
9857
10051
  }
@@ -10153,9 +10347,9 @@ __export(global_install_exports, {
10153
10347
  runGlobalRestore: () => runGlobalRestore,
10154
10348
  unlockProtected: () => unlockProtected
10155
10349
  });
10156
- import { readFileSync as readFileSync6, writeFileSync as writeFileSync3, existsSync as existsSync6, mkdirSync as mkdirSync3 } from "fs";
10157
- import { resolve as resolve4, join as join8, dirname } from "path";
10158
- import { homedir as homedir6 } from "os";
10350
+ import { readFileSync as readFileSync7, writeFileSync as writeFileSync4, existsSync as existsSync6, mkdirSync as mkdirSync4 } from "fs";
10351
+ import { resolve as resolve4, join as join9, dirname } from "path";
10352
+ import { homedir as homedir7 } from "os";
10159
10353
  import { fileURLToPath } from "url";
10160
10354
  import { createInterface } from "readline";
10161
10355
  import { execFileSync as execFileSync2 } from "child_process";
@@ -10218,10 +10412,10 @@ function unlockFile(file) {
10218
10412
  function protectedTargets() {
10219
10413
  const p = globalPaths();
10220
10414
  return [
10221
- join8(p.hooksDir, "guard.mjs"),
10222
- join8(p.hooksDir, "audit.mjs"),
10223
- join8(p.hooksDir, "stop.mjs"),
10224
- join8(p.hooksDir, "shield.mjs"),
10415
+ join9(p.hooksDir, "guard.mjs"),
10416
+ join9(p.hooksDir, "audit.mjs"),
10417
+ join9(p.hooksDir, "stop.mjs"),
10418
+ join9(p.hooksDir, "shield.mjs"),
10225
10419
  p.configPath,
10226
10420
  p.settingsPath
10227
10421
  ];
@@ -10233,26 +10427,26 @@ function unlockProtected() {
10233
10427
  for (const f of protectedTargets()) unlockFile(f);
10234
10428
  }
10235
10429
  function globalPaths() {
10236
- const home = homedir6();
10237
- const sgDir = join8(home, ".solongate");
10238
- const hooksDir = join8(sgDir, "hooks");
10239
- const claudeDir = join8(home, ".claude");
10430
+ const home = homedir7();
10431
+ const sgDir = join9(home, ".solongate");
10432
+ const hooksDir = join9(sgDir, "hooks");
10433
+ const claudeDir = join9(home, ".claude");
10240
10434
  return {
10241
10435
  home,
10242
10436
  sgDir,
10243
10437
  hooksDir,
10244
10438
  claudeDir,
10245
- settingsPath: join8(claudeDir, "settings.json"),
10246
- backupPath: join8(claudeDir, "settings.solongate.bak"),
10247
- configPath: join8(sgDir, "cloud-guard.json")
10439
+ settingsPath: join9(claudeDir, "settings.json"),
10440
+ backupPath: join9(claudeDir, "settings.solongate.bak"),
10441
+ configPath: join9(sgDir, "cloud-guard.json")
10248
10442
  };
10249
10443
  }
10250
10444
  function readHook(filename) {
10251
- return readFileSync6(join8(HOOKS_DIR, filename), "utf-8");
10445
+ return readFileSync7(join9(HOOKS_DIR, filename), "utf-8");
10252
10446
  }
10253
10447
  function readGuard() {
10254
- const bundled = join8(HOOKS_DIR, "guard.bundled.mjs");
10255
- return existsSync6(bundled) ? readFileSync6(bundled, "utf-8") : readHook("guard.mjs");
10448
+ const bundled = join9(HOOKS_DIR, "guard.bundled.mjs");
10449
+ return existsSync6(bundled) ? readFileSync7(bundled, "utf-8") : readHook("guard.mjs");
10256
10450
  }
10257
10451
  function ask(question) {
10258
10452
  const rl = createInterface({ input: process.stdin, output: process.stderr });
@@ -10266,13 +10460,13 @@ function runGlobalRestore() {
10266
10460
  unlockProtected();
10267
10461
  removeClaudeShim();
10268
10462
  if (existsSync6(p.backupPath)) {
10269
- writeFileSync3(p.settingsPath, readFileSync6(p.backupPath, "utf-8"));
10463
+ writeFileSync4(p.settingsPath, readFileSync7(p.backupPath, "utf-8"));
10270
10464
  console.log(` Restored ${p.settingsPath} from backup.`);
10271
10465
  } else if (existsSync6(p.settingsPath)) {
10272
10466
  try {
10273
- const s = JSON.parse(readFileSync6(p.settingsPath, "utf-8"));
10467
+ const s = JSON.parse(readFileSync7(p.settingsPath, "utf-8"));
10274
10468
  delete s.hooks;
10275
- writeFileSync3(p.settingsPath, JSON.stringify(s, null, 2) + "\n");
10469
+ writeFileSync4(p.settingsPath, JSON.stringify(s, null, 2) + "\n");
10276
10470
  console.log(` Removed SolonGate hooks from ${p.settingsPath}.`);
10277
10471
  } catch {
10278
10472
  }
@@ -10306,18 +10500,18 @@ function shimTargets() {
10306
10500
  return [];
10307
10501
  }
10308
10502
  }
10309
- return [".bashrc", ".zshrc", ".profile"].map((f) => join8(homedir6(), f)).filter((f) => existsSync6(f));
10503
+ return [".bashrc", ".zshrc", ".profile"].map((f) => join9(homedir7(), f)).filter((f) => existsSync6(f));
10310
10504
  }
10311
10505
  function writeShimBlock(file, block2) {
10312
10506
  const re = new RegExp(escapeRe(SHIM_BEGIN) + "[\\s\\S]*?" + escapeRe(SHIM_END) + "\\r?\\n?", "g");
10313
- let content = existsSync6(file) ? readFileSync6(file, "utf-8") : "";
10507
+ let content = existsSync6(file) ? readFileSync7(file, "utf-8") : "";
10314
10508
  content = content.replace(re, "");
10315
10509
  if (block2) {
10316
10510
  if (content.length && !content.endsWith("\n")) content += "\n";
10317
10511
  content += block2 + "\n";
10318
10512
  }
10319
- mkdirSync3(dirname(file), { recursive: true });
10320
- writeFileSync3(file, content);
10513
+ mkdirSync4(dirname(file), { recursive: true });
10514
+ writeFileSync4(file, content);
10321
10515
  }
10322
10516
  function installClaudeShim(shieldPath) {
10323
10517
  const real = resolveRealClaude();
@@ -10361,7 +10555,7 @@ async function runGlobalInstall(opts = {}) {
10361
10555
  let apiKey = opts.apiKey || process.env["SOLONGATE_API_KEY"] || "";
10362
10556
  if (!apiKey || apiKey === "sg_live_your_key_here") {
10363
10557
  try {
10364
- const cfg = JSON.parse(readFileSync6(p.configPath, "utf-8"));
10558
+ const cfg = JSON.parse(readFileSync7(p.configPath, "utf-8"));
10365
10559
  if (cfg && typeof cfg.apiKey === "string") apiKey = cfg.apiKey;
10366
10560
  } catch {
10367
10561
  }
@@ -10374,22 +10568,22 @@ async function runGlobalInstall(opts = {}) {
10374
10568
  process.exit(1);
10375
10569
  }
10376
10570
  const apiUrl = opts.apiUrl || process.env["SOLONGATE_API_URL"] || "https://api.solongate.com";
10377
- mkdirSync3(p.hooksDir, { recursive: true });
10378
- mkdirSync3(p.claudeDir, { recursive: true });
10571
+ mkdirSync4(p.hooksDir, { recursive: true });
10572
+ mkdirSync4(p.claudeDir, { recursive: true });
10379
10573
  unlockProtected();
10380
- writeFileSync3(join8(p.hooksDir, "guard.mjs"), readGuard());
10381
- writeFileSync3(join8(p.hooksDir, "audit.mjs"), readHook("audit.mjs"));
10382
- writeFileSync3(join8(p.hooksDir, "stop.mjs"), readHook("stop.mjs"));
10383
- writeFileSync3(join8(p.hooksDir, "shield.mjs"), readHook("shield.mjs"));
10574
+ writeFileSync4(join9(p.hooksDir, "guard.mjs"), readGuard());
10575
+ writeFileSync4(join9(p.hooksDir, "audit.mjs"), readHook("audit.mjs"));
10576
+ writeFileSync4(join9(p.hooksDir, "stop.mjs"), readHook("stop.mjs"));
10577
+ writeFileSync4(join9(p.hooksDir, "shield.mjs"), readHook("shield.mjs"));
10384
10578
  console.log(` Installed hooks \u2192 ${p.hooksDir}`);
10385
10579
  removeClaudeShim();
10386
- writeFileSync3(p.configPath, JSON.stringify({ apiKey, apiUrl }, null, 2) + "\n");
10580
+ writeFileSync4(p.configPath, JSON.stringify({ apiKey, apiUrl }, null, 2) + "\n");
10387
10581
  console.log(` Wrote ${p.configPath}`);
10388
10582
  let existing = {};
10389
10583
  if (existsSync6(p.settingsPath)) {
10390
- const raw = readFileSync6(p.settingsPath, "utf-8");
10584
+ const raw = readFileSync7(p.settingsPath, "utf-8");
10391
10585
  if (!existsSync6(p.backupPath)) {
10392
- writeFileSync3(p.backupPath, raw);
10586
+ writeFileSync4(p.backupPath, raw);
10393
10587
  console.log(` Backed up existing settings \u2192 ${p.backupPath}`);
10394
10588
  }
10395
10589
  try {
@@ -10398,9 +10592,9 @@ async function runGlobalInstall(opts = {}) {
10398
10592
  existing = {};
10399
10593
  }
10400
10594
  }
10401
- const guardAbs = join8(p.hooksDir, "guard.mjs").replace(/\\/g, "/");
10402
- const auditAbs = join8(p.hooksDir, "audit.mjs").replace(/\\/g, "/");
10403
- const stopAbs = join8(p.hooksDir, "stop.mjs").replace(/\\/g, "/");
10595
+ const guardAbs = join9(p.hooksDir, "guard.mjs").replace(/\\/g, "/");
10596
+ const auditAbs = join9(p.hooksDir, "audit.mjs").replace(/\\/g, "/");
10597
+ const stopAbs = join9(p.hooksDir, "stop.mjs").replace(/\\/g, "/");
10404
10598
  const nodeBin = process.execPath.replace(/\\/g, "/");
10405
10599
  const merged = {
10406
10600
  ...existing,
@@ -10410,7 +10604,7 @@ async function runGlobalInstall(opts = {}) {
10410
10604
  Stop: [{ matcher: "", hooks: [{ type: "command", command: `"${nodeBin}" "${stopAbs}" claude-code "Claude Code"` }] }]
10411
10605
  }
10412
10606
  };
10413
- writeFileSync3(p.settingsPath, JSON.stringify(merged, null, 2) + "\n");
10607
+ writeFileSync4(p.settingsPath, JSON.stringify(merged, null, 2) + "\n");
10414
10608
  console.log(` Registered global hooks \u2192 ${p.settingsPath}`);
10415
10609
  if (process.env["SOLONGATE_OS_LOCK"] === "1") {
10416
10610
  lockProtected();
@@ -10590,11 +10784,11 @@ import { createServer, request as httpRequest } from "http";
10590
10784
  import { request as httpsRequest } from "https";
10591
10785
  import { spawn as spawn3 } from "child_process";
10592
10786
  import { URL as URL2 } from "url";
10593
- import { readFileSync as readFileSync7, existsSync as existsSync7, readdirSync, statSync as statSync4 } from "fs";
10787
+ import { readFileSync as readFileSync8, existsSync as existsSync7, readdirSync, statSync as statSync4 } from "fs";
10594
10788
  import { resolve as resolve5 } from "path";
10595
- import { homedir as homedir7 } from "os";
10789
+ import { homedir as homedir8 } from "os";
10596
10790
  function findCacheFile() {
10597
- const dir = resolve5(homedir7(), ".solongate");
10791
+ const dir = resolve5(homedir8(), ".solongate");
10598
10792
  const envSel = process.env.SOLONGATE_AGENT_ID;
10599
10793
  if (envSel) {
10600
10794
  const f = resolve5(dir, ".policy-cache-" + envSel.replace(/[^a-zA-Z0-9_-]/g, "_") + ".json");
@@ -10620,7 +10814,7 @@ function loadCfg() {
10620
10814
  try {
10621
10815
  const f = findCacheFile();
10622
10816
  if (f && existsSync7(f)) {
10623
- const c2 = JSON.parse(readFileSync7(f, "utf-8"));
10817
+ const c2 = JSON.parse(readFileSync8(f, "utf-8"));
10624
10818
  const d = c2?.security?.dlpRedact;
10625
10819
  const g = c2?.security?.ghost;
10626
10820
  const ghost = g && Array.isArray(g.patterns) ? g.patterns : [];
@@ -10896,9 +11090,9 @@ __export(logs_server_exports, {
10896
11090
  runLogsServer: () => runLogsServer
10897
11091
  });
10898
11092
  import { createServer as createServer2 } from "http";
10899
- import { readFileSync as readFileSync8, statSync as statSync5 } from "fs";
10900
- import { resolve as resolve6, join as join9, isAbsolute } from "path";
10901
- import { homedir as homedir8 } from "os";
11093
+ import { readFileSync as readFileSync9, statSync as statSync5 } from "fs";
11094
+ import { resolve as resolve6, join as join10, isAbsolute } from "path";
11095
+ import { homedir as homedir9 } from "os";
10902
11096
  import { readdirSync as readdirSync2 } from "fs";
10903
11097
  function allowedOrigins() {
10904
11098
  const base = [
@@ -10915,15 +11109,15 @@ function resolveLocalLogDir(rawPath) {
10915
11109
  const dir = String(rawPath || "").trim().replace(/[\\/]+$/, "");
10916
11110
  if (!dir) return null;
10917
11111
  if (isAbsolute(dir)) return dir;
10918
- return resolve6(homedir8(), ".solongate", "local-logs");
11112
+ return resolve6(homedir9(), ".solongate", "local-logs");
10919
11113
  }
10920
11114
  async function findLogDir() {
10921
- const base = resolve6(homedir8(), ".solongate");
11115
+ const base = resolve6(homedir9(), ".solongate");
10922
11116
  try {
10923
11117
  const files = readdirSync2(base).filter((f) => f.startsWith(".policy-cache-") && f.endsWith(".json"));
10924
11118
  for (const f of files) {
10925
11119
  try {
10926
- const c2 = JSON.parse(readFileSync8(join9(base, f), "utf-8"));
11120
+ const c2 = JSON.parse(readFileSync9(join10(base, f), "utf-8"));
10927
11121
  const p = c2?.security?.localLogs?.path;
10928
11122
  if (typeof p === "string" && p.trim()) return { dir: resolveLocalLogDir(p), configured: p };
10929
11123
  } catch {
@@ -10932,7 +11126,7 @@ async function findLogDir() {
10932
11126
  } catch {
10933
11127
  }
10934
11128
  try {
10935
- const cfgRaw = readFileSync8(join9(base, "cloud-guard.json"), "utf-8");
11129
+ const cfgRaw = readFileSync9(join10(base, "cloud-guard.json"), "utf-8");
10936
11130
  const { apiKey, apiUrl } = JSON.parse(cfgRaw);
10937
11131
  if (apiKey) {
10938
11132
  const url = `${apiUrl || "https://api.solongate.com"}/api/v1/policies/active`;
@@ -10961,7 +11155,7 @@ function setCors(req, res) {
10961
11155
  }
10962
11156
  function fileInfo(dir) {
10963
11157
  if (!dir) return { file: null, exists: false, size: 0, mtimeMs: 0 };
10964
- const file = join9(dir, LOG_FILENAME);
11158
+ const file = join10(dir, LOG_FILENAME);
10965
11159
  try {
10966
11160
  const st = statSync5(file);
10967
11161
  return { file, exists: true, size: st.size, mtimeMs: st.mtimeMs };
@@ -11022,7 +11216,7 @@ async function runLogsServer() {
11022
11216
  return;
11023
11217
  }
11024
11218
  try {
11025
- const text = readFileSync8(info.file, "utf-8");
11219
+ const text = readFileSync9(info.file, "utf-8");
11026
11220
  res.writeHead(200, { "Content-Type": "text/plain; charset=utf-8", "Last-Modified": lastMod, "X-Solongate-Exists": "1" });
11027
11221
  res.end(text);
11028
11222
  } catch {
@@ -11074,7 +11268,7 @@ var init_logs_server = __esm({
11074
11268
 
11075
11269
  // src/inject.ts
11076
11270
  var inject_exports = {};
11077
- import { readFileSync as readFileSync9, writeFileSync as writeFileSync4, existsSync as existsSync8, copyFileSync } from "fs";
11271
+ import { readFileSync as readFileSync10, writeFileSync as writeFileSync5, existsSync as existsSync8, copyFileSync } from "fs";
11078
11272
  import { resolve as resolve7 } from "path";
11079
11273
  import { execSync } from "child_process";
11080
11274
  function parseInjectArgs(argv) {
@@ -11134,7 +11328,7 @@ WHAT IT DOES
11134
11328
  function detectProject() {
11135
11329
  if (!existsSync8(resolve7("package.json"))) return false;
11136
11330
  try {
11137
- const pkg = JSON.parse(readFileSync9(resolve7("package.json"), "utf-8"));
11331
+ const pkg = JSON.parse(readFileSync10(resolve7("package.json"), "utf-8"));
11138
11332
  const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
11139
11333
  return !!(allDeps["@modelcontextprotocol/sdk"] || allDeps["@modelcontextprotocol/server"]);
11140
11334
  } catch {
@@ -11143,7 +11337,7 @@ function detectProject() {
11143
11337
  }
11144
11338
  function findTsEntryFile() {
11145
11339
  try {
11146
- const pkg = JSON.parse(readFileSync9(resolve7("package.json"), "utf-8"));
11340
+ const pkg = JSON.parse(readFileSync10(resolve7("package.json"), "utf-8"));
11147
11341
  if (pkg.bin) {
11148
11342
  const binPath = typeof pkg.bin === "string" ? pkg.bin : Object.values(pkg.bin)[0];
11149
11343
  if (typeof binPath === "string") {
@@ -11170,7 +11364,7 @@ function findTsEntryFile() {
11170
11364
  const full = resolve7(c2);
11171
11365
  if (existsSync8(full)) {
11172
11366
  try {
11173
- const content = readFileSync9(full, "utf-8");
11367
+ const content = readFileSync10(full, "utf-8");
11174
11368
  if (content.includes("McpServer") || content.includes("McpServer")) {
11175
11369
  return full;
11176
11370
  }
@@ -11190,7 +11384,7 @@ function detectPackageManager() {
11190
11384
  }
11191
11385
  function installSdk() {
11192
11386
  try {
11193
- const pkg = JSON.parse(readFileSync9(resolve7("package.json"), "utf-8"));
11387
+ const pkg = JSON.parse(readFileSync10(resolve7("package.json"), "utf-8"));
11194
11388
  const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
11195
11389
  if (allDeps["@solongate/proxy"]) {
11196
11390
  log3(" @solongate/proxy already installed");
@@ -11211,7 +11405,7 @@ function installSdk() {
11211
11405
  }
11212
11406
  }
11213
11407
  function injectTypeScript(filePath) {
11214
- const original = readFileSync9(filePath, "utf-8");
11408
+ const original = readFileSync10(filePath, "utf-8");
11215
11409
  const changes = [];
11216
11410
  let modified = original;
11217
11411
  if (modified.includes("SecureMcpServer")) {
@@ -11382,7 +11576,7 @@ async function main2() {
11382
11576
  log3("");
11383
11577
  log3(` Backup: ${backupPath}`);
11384
11578
  }
11385
- writeFileSync4(entryFile, result.modified);
11579
+ writeFileSync5(entryFile, result.modified);
11386
11580
  log3("");
11387
11581
  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");
11388
11582
  log3(" \u2502 SolonGate SDK injected successfully! \u2502");
@@ -11411,8 +11605,8 @@ var init_inject = __esm({
11411
11605
 
11412
11606
  // src/create.ts
11413
11607
  var create_exports = {};
11414
- import { mkdirSync as mkdirSync4, writeFileSync as writeFileSync5, existsSync as existsSync9 } from "fs";
11415
- import { resolve as resolve8, join as join10 } from "path";
11608
+ import { mkdirSync as mkdirSync5, writeFileSync as writeFileSync6, existsSync as existsSync9 } from "fs";
11609
+ import { resolve as resolve8, join as join11 } from "path";
11416
11610
  import { execSync as execSync2 } from "child_process";
11417
11611
  function withSpinner(message, fn) {
11418
11612
  const frames = ["\u28FE", "\u28FD", "\u28FB", "\u28BF", "\u287F", "\u28DF", "\u28EF", "\u28F7"];
@@ -11491,8 +11685,8 @@ EXAMPLES
11491
11685
  `);
11492
11686
  }
11493
11687
  function createProject(dir, name, _policy) {
11494
- writeFileSync5(
11495
- join10(dir, "package.json"),
11688
+ writeFileSync6(
11689
+ join11(dir, "package.json"),
11496
11690
  JSON.stringify(
11497
11691
  {
11498
11692
  name,
@@ -11521,8 +11715,8 @@ function createProject(dir, name, _policy) {
11521
11715
  2
11522
11716
  ) + "\n"
11523
11717
  );
11524
- writeFileSync5(
11525
- join10(dir, "tsconfig.json"),
11718
+ writeFileSync6(
11719
+ join11(dir, "tsconfig.json"),
11526
11720
  JSON.stringify(
11527
11721
  {
11528
11722
  compilerOptions: {
@@ -11542,9 +11736,9 @@ function createProject(dir, name, _policy) {
11542
11736
  2
11543
11737
  ) + "\n"
11544
11738
  );
11545
- mkdirSync4(join10(dir, "src"), { recursive: true });
11546
- writeFileSync5(
11547
- join10(dir, "src", "index.ts"),
11739
+ mkdirSync5(join11(dir, "src"), { recursive: true });
11740
+ writeFileSync6(
11741
+ join11(dir, "src", "index.ts"),
11548
11742
  `#!/usr/bin/env node
11549
11743
 
11550
11744
  console.log = (...args: unknown[]) => {
@@ -11585,8 +11779,8 @@ console.log('');
11585
11779
  console.log('Press Ctrl+C to stop.');
11586
11780
  `
11587
11781
  );
11588
- writeFileSync5(
11589
- join10(dir, ".mcp.json"),
11782
+ writeFileSync6(
11783
+ join11(dir, ".mcp.json"),
11590
11784
  JSON.stringify(
11591
11785
  {
11592
11786
  mcpServers: {
@@ -11603,13 +11797,13 @@ console.log('Press Ctrl+C to stop.');
11603
11797
  2
11604
11798
  ) + "\n"
11605
11799
  );
11606
- writeFileSync5(
11607
- join10(dir, ".env"),
11800
+ writeFileSync6(
11801
+ join11(dir, ".env"),
11608
11802
  `SOLONGATE_API_KEY=sg_live_YOUR_KEY_HERE
11609
11803
  `
11610
11804
  );
11611
- writeFileSync5(
11612
- join10(dir, ".gitignore"),
11805
+ writeFileSync6(
11806
+ join11(dir, ".gitignore"),
11613
11807
  `node_modules/
11614
11808
  dist/
11615
11809
  *.solongate-backup
@@ -11628,7 +11822,7 @@ async function main3() {
11628
11822
  process.exit(1);
11629
11823
  }
11630
11824
  withSpinner(`Setting up ${opts.name}...`, () => {
11631
- mkdirSync4(dir, { recursive: true });
11825
+ mkdirSync5(dir, { recursive: true });
11632
11826
  createProject(dir, opts.name, opts.policy);
11633
11827
  });
11634
11828
  if (!opts.noInstall) {
@@ -11702,14 +11896,14 @@ var init_create = __esm({
11702
11896
 
11703
11897
  // src/pull-push.ts
11704
11898
  var pull_push_exports = {};
11705
- import { readFileSync as readFileSync10, writeFileSync as writeFileSync6, existsSync as existsSync10 } from "fs";
11899
+ import { readFileSync as readFileSync11, writeFileSync as writeFileSync7, existsSync as existsSync10 } from "fs";
11706
11900
  import { resolve as resolve9 } from "path";
11707
11901
  function loadEnv() {
11708
11902
  if (process.env.SOLONGATE_API_KEY) return;
11709
11903
  const envPath = resolve9(".env");
11710
11904
  if (!existsSync10(envPath)) return;
11711
11905
  try {
11712
- const content = readFileSync10(envPath, "utf-8");
11906
+ const content = readFileSync11(envPath, "utf-8");
11713
11907
  for (const line of content.split("\n")) {
11714
11908
  const trimmed = line.trim();
11715
11909
  if (!trimmed || trimmed.startsWith("#")) continue;
@@ -11897,7 +12091,7 @@ async function pull(apiKey, file, policyId) {
11897
12091
  const policy = await fetchCloudPolicy(apiKey, API_URL, policyId);
11898
12092
  const { id: _id, ...policyWithoutId } = policy;
11899
12093
  const json = JSON.stringify(policyWithoutId, null, 2) + "\n";
11900
- writeFileSync6(file, json, "utf-8");
12094
+ writeFileSync7(file, json, "utf-8");
11901
12095
  log5("");
11902
12096
  log5(green2(" Saved to: ") + file);
11903
12097
  log5(` ${dim2("Name:")} ${policy.name}`);
@@ -11926,7 +12120,7 @@ async function push(apiKey, file, policyId) {
11926
12120
  log5(" solongate-proxy list");
11927
12121
  process.exit(1);
11928
12122
  }
11929
- const content = readFileSync10(file, "utf-8");
12123
+ const content = readFileSync11(file, "utf-8");
11930
12124
  let policy;
11931
12125
  try {
11932
12126
  policy = JSON.parse(content);