@solongate/proxy 0.67.0 → 0.69.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
@@ -7019,13 +7019,13 @@ var init_hooks = __esm({
7019
7019
  });
7020
7020
 
7021
7021
  // src/tui/panels/Live.tsx
7022
- import { Box as Box2, Text as Text2 } from "ink";
7023
- import { closeSync, openSync, readSync, statSync } from "fs";
7022
+ import { Box as Box2, Text as Text2, useInput } from "ink";
7023
+ import { closeSync, mkdirSync as mkdirSync3, openSync, readSync, statSync, writeFileSync as writeFileSync3 } from "fs";
7024
7024
  import { homedir as homedir3 } from "os";
7025
- import { join as join5 } from "path";
7025
+ import { dirname, join as join5 } from "path";
7026
7026
  import { useCallback as useCallback2, useEffect as useEffect2, useRef as useRef2, useState as useState2 } from "react";
7027
7027
  import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
7028
- function tailLines(file, maxBytes = 65536) {
7028
+ function tailLines(file, maxBytes = 131072) {
7029
7029
  try {
7030
7030
  const size = statSync(file).size;
7031
7031
  const start = Math.max(0, size - maxBytes);
@@ -7040,6 +7040,9 @@ function tailLines(file, maxBytes = 65536) {
7040
7040
  return [];
7041
7041
  }
7042
7042
  }
7043
+ function oscCopy(text) {
7044
+ process.stdout.write(`\x1B]52;c;${Buffer.from(text, "utf-8").toString("base64")}\x07`);
7045
+ }
7043
7046
  function cloudItem(e) {
7044
7047
  return {
7045
7048
  id: "c:" + e.id,
@@ -7049,7 +7052,11 @@ function cloudItem(e) {
7049
7052
  permission: (e.permission ?? "").slice(0, 4),
7050
7053
  detail: (e.arguments_summary ? JSON.stringify(e.arguments_summary) : e.reason ?? "").replace(/\s+/g, " "),
7051
7054
  dlp: !!e.dlp_matches?.length,
7052
- source: "cloud"
7055
+ source: "cloud",
7056
+ session: e.session_id ?? void 0,
7057
+ agent: e.agent_name ?? void 0,
7058
+ evalMs: e.evaluation_time_ms ?? void 0,
7059
+ rule: e.matched_rule_id ?? void 0
7053
7060
  };
7054
7061
  }
7055
7062
  function ColumnChart({ series, hot, height, width: width2, color, hotColor = theme.bad }) {
@@ -7068,7 +7075,7 @@ function ColumnChart({ series, hot, height, width: width2, color, hotColor = the
7068
7075
  else if (frac >= (r - 0.5) / height) ch = "\u2584";
7069
7076
  else if (r === 1) ch = "\u2581";
7070
7077
  else ch = " ";
7071
- const c2 = r === 1 && v === 0 ? "#233457" : hotPad?.[i] ? hotColor : color;
7078
+ const c2 = r === 1 && v === 0 ? DIM_FLOOR : hotPad?.[i] ? hotColor : color;
7072
7079
  const last = segs[segs.length - 1];
7073
7080
  if (last && last.color === c2) last.text += ch;
7074
7081
  else segs.push({ text: ch, color: c2 });
@@ -7084,7 +7091,7 @@ function HBar({ label, value, max, width: width2, color }) {
7084
7091
  return /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
7085
7092
  /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: label.padEnd(10) }),
7086
7093
  /* @__PURE__ */ jsx2(Text2, { color, children: "\u2588".repeat(Math.min(width2, filled)) }),
7087
- /* @__PURE__ */ jsx2(Text2, { color: "#233457", children: "\u2591".repeat(Math.max(0, width2 - filled)) }),
7094
+ /* @__PURE__ */ jsx2(Text2, { color: DIM_FLOOR, children: "\u2591".repeat(Math.max(0, width2 - filled)) }),
7088
7095
  /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " " + value })
7089
7096
  ] });
7090
7097
  }
@@ -7109,6 +7116,9 @@ function LivePanel({ active: active2 }) {
7109
7116
  const [localOn, setLocalOn] = useState2(null);
7110
7117
  const [ring, setRing] = useState2(null);
7111
7118
  const [log6, setLog] = useState2([]);
7119
+ const [filter, setFilter] = useState2("all");
7120
+ const [scroll, setScroll] = useState2(0);
7121
+ const [toast, setToast] = useState2(null);
7112
7122
  const seenRef = useRef2(/* @__PURE__ */ new Set());
7113
7123
  const lastLocalTs = useRef2(0);
7114
7124
  const pausedUntil = useRef2(0);
@@ -7146,10 +7156,14 @@ function LivePanel({ active: active2 }) {
7146
7156
  at,
7147
7157
  tool: j.tool ?? "?",
7148
7158
  decision: j.decision ?? "ALLOW",
7149
- permission: "",
7159
+ permission: (j.permission ?? "").slice(0, 4),
7150
7160
  detail: (j.arguments ? JSON.stringify(j.arguments) : j.reason ?? "").replace(/\s+/g, " "),
7151
7161
  dlp: !!j.dlp,
7152
- source: "local"
7162
+ source: "local",
7163
+ session: j.session_id,
7164
+ agent: j.agent_name,
7165
+ evalMs: j.evaluation_time_ms,
7166
+ rule: j.matched_rule_id
7153
7167
  });
7154
7168
  } catch {
7155
7169
  }
@@ -7158,9 +7172,7 @@ function LivePanel({ active: active2 }) {
7158
7172
  lastLocalTs.current = fresh[fresh.length - 1].at;
7159
7173
  setLocalBuf((prev) => [...prev, ...fresh].slice(-400));
7160
7174
  const denies = fresh.filter((f) => f.decision !== "ALLOW").length;
7161
- if (lastLocalTs.current !== fresh[0].at || fresh.length < 10) {
7162
- pushLog(`local +${fresh.length} calls${denies ? ` \xB7 ${denies} DENIED` : ""}`, denies ? "bad" : "warn");
7163
- }
7175
+ if (fresh.length < 10) pushLog(`local +${fresh.length} calls${denies ? ` \xB7 ${denies} DENIED` : ""}`, denies ? "bad" : "warn");
7164
7176
  }
7165
7177
  const ringLines = tailLines(RING, 8192).slice(-30);
7166
7178
  if (ringLines.length) {
@@ -7197,9 +7209,7 @@ function LivePanel({ active: active2 }) {
7197
7209
  const fresh = fd.entries.filter((e) => !seenRef.current.has(e.id));
7198
7210
  const firstLoad = seenRef.current.size === 0 && fresh.length > 1;
7199
7211
  for (const e of fresh) seenRef.current.add(e.id);
7200
- if (fresh.length) {
7201
- setCloudBuf((prev) => [...prev, ...fresh.map(cloudItem).sort((a, b) => a.at - b.at)].slice(-400));
7202
- }
7212
+ if (fresh.length) setCloudBuf((prev) => [...prev, ...fresh.map(cloudItem).sort((a, b) => a.at - b.at)].slice(-400));
7203
7213
  const denies = fresh.filter((e) => e.decision !== "ALLOW").length;
7204
7214
  if (firstLoad) pushLog(`cloud link up \xB7 api ${ms}ms \xB7 ${fresh.length} calls`);
7205
7215
  else pushLog(`api ${ms}ms \xB7 +${fresh.length} cloud${denies ? ` \xB7 ${denies} DENIED` : ""}`, denies ? "bad" : fresh.length ? "warn" : "ok");
@@ -7239,16 +7249,20 @@ function LivePanel({ active: active2 }) {
7239
7249
  }, [active2, pollFeed, pollMedium, pollSlow]);
7240
7250
  const sessions = useLoader(() => api.agents.live({ limit: 30, includeDeactivated: true }));
7241
7251
  const insights = useLoader(() => api.stats.securityInsights(7));
7252
+ const guard = useLoader(() => api.settings.getGuardStatus());
7242
7253
  usePoll(() => {
7243
7254
  if (!paused()) sessions.reload();
7244
7255
  }, 1e4, active2);
7245
7256
  usePoll(() => {
7246
7257
  if (!paused()) insights.reload();
7247
7258
  }, 3e4, active2);
7259
+ usePoll(() => {
7260
+ if (!paused()) guard.reload();
7261
+ }, 6e4, active2);
7248
7262
  const [tick, setTick] = useState2(0);
7249
7263
  useEffect2(() => {
7250
7264
  if (!active2) return;
7251
- const t = setInterval(() => setTick((n) => n + 1), 200);
7265
+ const t = setInterval(() => setTick((n) => n + 1), 500);
7252
7266
  return () => clearInterval(t);
7253
7267
  }, [active2]);
7254
7268
  const startRef = useRef2(Date.now());
@@ -7256,19 +7270,34 @@ function LivePanel({ active: active2 }) {
7256
7270
  const rows = process.stdout.rows ?? 30;
7257
7271
  const ins = insights.data ?? {};
7258
7272
  const spin = SPIN[tick % SPIN.length];
7273
+ const nowMs = Date.now();
7274
+ const mergedAll = [...cloudBuf, ...localBuf].sort((a, b) => a.at - b.at);
7275
+ const filtered = filter === "all" ? mergedAll : mergedAll.filter((e) => e.source === filter);
7276
+ const visible = filtered.slice(-STREAM_KEEP);
7259
7277
  const points = tsData?.timeseries ?? [];
7260
- const traffic = points.map((p) => p.total);
7261
- const trafficHot = points.map((p) => p.denied > 0);
7278
+ const minuteCounts = new Array(60).fill(0);
7279
+ const minuteHot = new Array(60).fill(false);
7280
+ for (const e of mergedAll) {
7281
+ const idx = 59 - Math.floor((nowMs - e.at) / 6e4);
7282
+ if (idx >= 0 && idx < 60) {
7283
+ minuteCounts[idx]++;
7284
+ if (e.decision !== "ALLOW") minuteHot[idx] = true;
7285
+ }
7286
+ }
7287
+ const localTraffic = localOn === true && minuteCounts.some((c2) => c2 > 0);
7288
+ const traffic = localTraffic ? minuteCounts : points.map((p) => p.total);
7289
+ const trafficHot = localTraffic ? minuteHot : points.map((p) => p.denied > 0);
7290
+ const trafficLabel = localTraffic ? "calls/min \xB7 60m \xB7 local+cloud" : "24h \xB7 cloud";
7262
7291
  const rl = ins.layers?.rateLimit;
7263
7292
  const dl = ins.layers?.dlp;
7264
- const minuteNow = (ins.activity?.minute ?? []).slice(-1)[0]?.count ?? 0;
7293
+ const gh = ins.layers?.ghost;
7294
+ const minuteNow = minuteCounts[59] ?? 0;
7265
7295
  const dlpBars = (ins.dlpByPattern ?? []).slice(0, 2);
7266
7296
  const maxDlpBar = dlpBars[0]?.count ?? 1;
7267
- const merged = [...cloudBuf, ...localBuf].sort((a, b) => a.at - b.at);
7268
- const denials = merged.filter((e) => e.decision !== "ALLOW");
7297
+ const denials = mergedAll.filter((e) => e.decision !== "ALLOW");
7269
7298
  const lastDeny = denials[denials.length - 1];
7270
7299
  const toolCounts = /* @__PURE__ */ new Map();
7271
- for (const e of merged) toolCounts.set(e.tool, (toolCounts.get(e.tool) ?? 0) + 1);
7300
+ for (const e of mergedAll) toolCounts.set(e.tool, (toolCounts.get(e.tool) ?? 0) + 1);
7272
7301
  const topTools = [...toolCounts.entries()].sort((a, b) => b[1] - a[1]).slice(0, 3);
7273
7302
  const latNow = lat[lat.length - 1] ?? 0;
7274
7303
  const sortedLat = [...lat].sort((a, b) => a - b);
@@ -7277,20 +7306,65 @@ function LivePanel({ active: active2 }) {
7277
7306
  const backingOff = Date.now() < pausedUntil.current;
7278
7307
  const sess = (sessions.data?.agents ?? []).slice().sort((a, b) => Date.parse(b.last_seen_at) - Date.parse(a.last_seen_at));
7279
7308
  const sessCounts = sessions.data?.counts;
7309
+ const localSess = /* @__PURE__ */ new Map();
7310
+ for (const e of localBuf) {
7311
+ if (!e.session) continue;
7312
+ const cur = localSess.get(e.session) ?? { agent: e.agent ?? "local agent", calls: 0, denies: 0, lastAt: 0 };
7313
+ cur.calls++;
7314
+ if (e.decision !== "ALLOW") cur.denies++;
7315
+ cur.lastAt = Math.max(cur.lastAt, e.at);
7316
+ if (e.agent) cur.agent = e.agent;
7317
+ localSess.set(e.session, cur);
7318
+ }
7319
+ const localSessList = [...localSess.entries()].sort((a, b) => b[1].lastAt - a[1].lastAt);
7280
7320
  const chartH = rows >= 36 ? 6 : 4;
7281
- const colH = rows >= 32 ? 6 : 5;
7282
- const streamRows = Math.max(4, rows - 6 - chartH - colH - (localOn === false ? 1 : 0));
7283
- const tail = merged.slice(-streamRows);
7321
+ const colH = rows >= 32 ? 7 : 5;
7322
+ const streamRows = Math.max(4, rows - 5 - (1 + chartH) - colH);
7284
7323
  const innerW = cols - 2;
7285
7324
  const leftW = Math.floor(innerW * 0.55);
7286
7325
  const rightW = innerW - leftW - 2;
7287
7326
  const colW = Math.max(20, Math.floor((innerW - 4) / 3));
7327
+ const maxScroll = Math.max(0, visible.length - streamRows);
7328
+ const clampedScroll = Math.min(scroll, maxScroll);
7329
+ const start = Math.max(0, visible.length - streamRows - clampedScroll);
7330
+ const windowed = visible.slice(start, start + streamRows);
7331
+ useInput(
7332
+ (input, key) => {
7333
+ if (input === "f") {
7334
+ setFilter((f) => FILTERS[(FILTERS.indexOf(f) + 1) % FILTERS.length]);
7335
+ setScroll(0);
7336
+ } else if (key.upArrow) setScroll((n) => Math.min(maxScroll, n + 1));
7337
+ else if (key.downArrow) setScroll((n) => Math.max(0, n - 1));
7338
+ else if (key.pageUp) setScroll((n) => Math.min(maxScroll, n + streamRows));
7339
+ else if (key.pageDown) setScroll((n) => Math.max(0, n - streamRows));
7340
+ else if (input === "c") {
7341
+ const dump = visible.map(
7342
+ (e) => `[${new Date(e.at).toISOString()}] ${e.source.toUpperCase().padEnd(5)} ${e.decision.padEnd(6)} ${e.tool.padEnd(16)} ${e.permission.padEnd(5)} ${e.evalMs != null ? String(e.evalMs).padStart(5) + "ms " : " "}${(e.agent ?? "-").padEnd(14)} ${e.session ? e.session.slice(0, 8) : "- "} ${e.detail}`
7343
+ ).join("\n");
7344
+ try {
7345
+ mkdirSync3(dirname(DUMP), { recursive: true });
7346
+ writeFileSync3(DUMP, dump + "\n");
7347
+ } catch {
7348
+ }
7349
+ oscCopy(dump);
7350
+ setToast({ msg: `copied ${visible.length} lines \u2192 clipboard + ${DUMP}`, until: Date.now() + 4e3 });
7351
+ }
7352
+ },
7353
+ { isActive: active2 }
7354
+ );
7288
7355
  const sessionDot = (st) => st === "active" ? { ch: "\u25CF", color: theme.ok } : st === "idle" ? { ch: "\u25CC", color: theme.warn } : { ch: "\u25CB", color: theme.dim };
7356
+ if (s === null && localOn === null) {
7357
+ return /* @__PURE__ */ jsxs2(Text2, { color: theme.dim, children: [
7358
+ spin,
7359
+ " connecting\u2026"
7360
+ ] });
7361
+ }
7289
7362
  return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", paddingX: 1, children: [
7290
7363
  /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
7291
7364
  /* @__PURE__ */ jsx2(Text2, { backgroundColor: "#1432A0", color: "#AAC8FA", bold: true, children: " SOLONGATE LIVE " }),
7292
- /* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", children: ` ${spin} up ${fmtUp(Date.now() - startRef.current)} \xB7 ${hhmmss(Date.now())} \xB7 api ${latNow}ms ` }),
7293
- backingOff ? /* @__PURE__ */ jsx2(Text2, { backgroundColor: "#3d2a12", color: "#ffb454", bold: true, children: " RATE LIMITED \xB7 backing off " }) : lastDeny ? /* @__PURE__ */ jsx2(Text2, { backgroundColor: "#3d1220", color: "#ff6b6b", bold: true, children: ` \u26A0 ${hhmmss(lastDeny.at)} ${lastDeny.tool} DENIED ` }) : /* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#4f6db8", children: " \u2713 clean " })
7365
+ /* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", children: ` ${spin} up ${fmtUp(nowMs - startRef.current)} \xB7 ${hhmmss(nowMs)} \xB7 api ${latNow}ms ` }),
7366
+ backingOff ? /* @__PURE__ */ jsx2(Text2, { backgroundColor: "#3d2a12", color: "#ffb454", bold: true, children: " RATE LIMITED \xB7 backing off " }) : lastDeny ? /* @__PURE__ */ jsx2(Text2, { backgroundColor: "#3d1220", color: "#ff6b6b", bold: true, children: ` \u26A0 ${hhmmss(lastDeny.at)} ${lastDeny.tool} DENIED ` }) : /* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#4f6db8", children: " \u2713 clean " }),
7367
+ toast && nowMs < toast.until ? /* @__PURE__ */ jsx2(Text2, { backgroundColor: "#123d1f", color: "#7bd88f", bold: true, children: ` ${toast.msg} ` }) : null
7294
7368
  ] }),
7295
7369
  /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
7296
7370
  /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "\u2502 calls " }),
@@ -7300,18 +7374,22 @@ function LivePanel({ active: active2 }) {
7300
7374
  /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502 deny " }),
7301
7375
  /* @__PURE__ */ jsx2(Text2, { color: theme.bad, bold: true, children: s ? s.denied : "\xB7\xB7" }),
7302
7376
  /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502 local " }),
7303
- localOn ? /* @__PURE__ */ jsx2(Text2, { color: theme.ok, children: "\u2713 streaming" }) : /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "off" }),
7304
- /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502 ratelimit " }),
7377
+ localOn ? /* @__PURE__ */ jsx2(Text2, { color: theme.ok, children: "\u2713" }) : /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "off" }),
7378
+ /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502 rl " }),
7305
7379
  /* @__PURE__ */ jsx2(Text2, { color: rl?.mode === "block" ? theme.ok : rl?.mode === "detect" ? theme.warn : theme.dim, children: rl?.mode ?? "?" }),
7306
7380
  /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502 dlp " }),
7307
7381
  /* @__PURE__ */ jsx2(Text2, { color: dl?.mode === "block" ? theme.ok : dl?.mode === "detect" ? theme.warn : theme.dim, children: dl?.mode ?? "?" }),
7308
- /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502 sessions " }),
7309
- /* @__PURE__ */ jsx2(Text2, { color: theme.accent, children: sessCounts ? `${sessCounts.active}\u25B2 ${sessCounts.idle}\u25CC ${sessCounts.deactivated}\u25CB` : "\xB7" }),
7382
+ /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502 ghost " }),
7383
+ /* @__PURE__ */ jsx2(Text2, { color: gh?.mode === "on" ? theme.ok : theme.dim, children: gh?.mode ?? "?" }),
7384
+ /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502 sess " }),
7385
+ /* @__PURE__ */ jsx2(Text2, { color: theme.accent, children: `${localSessList.length}loc ${sessCounts?.active ?? 0}\u25B2${sessCounts?.idle ?? 0}\u25CC` }),
7386
+ /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502 hooks " }),
7387
+ /* @__PURE__ */ jsx2(Text2, { color: guard.data?.up_to_date ? theme.ok : theme.warn, children: guard.data ? `v${guard.data.installed ?? "?"}${guard.data.up_to_date ? "" : "\u2192v" + guard.data.latest} ${guard.data.device_count}dev` : "\xB7" }),
7310
7388
  /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502" })
7311
7389
  ] }),
7312
- /* @__PURE__ */ jsxs2(Box2, { children: [
7390
+ /* @__PURE__ */ jsxs2(Box2, { height: 1 + chartH, children: [
7313
7391
  /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", width: leftW, marginRight: 2, children: [
7314
- /* @__PURE__ */ jsx2(PaneTitle, { label: "TRAFFIC", extra: `24h \xB7 peak ${Math.max(0, ...traffic)} \xB7 red = had denials`, width: leftW }),
7392
+ /* @__PURE__ */ jsx2(PaneTitle, { label: "TRAFFIC", extra: `${trafficLabel} \xB7 peak ${Math.max(0, ...traffic)} \xB7 red = denials`, width: leftW }),
7315
7393
  /* @__PURE__ */ jsx2(ColumnChart, { series: traffic, hot: trafficHot, height: chartH, width: leftW, color: theme.accent })
7316
7394
  ] }),
7317
7395
  /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", width: rightW, children: [
@@ -7319,45 +7397,61 @@ function LivePanel({ active: active2 }) {
7319
7397
  /* @__PURE__ */ jsx2(ColumnChart, { series: lat, hot: lat.map((v) => v > latHotAt), height: chartH, width: rightW, color: "#82AAF0", hotColor: "#ffb454" })
7320
7398
  ] })
7321
7399
  ] }),
7322
- /* @__PURE__ */ jsxs2(Box2, { children: [
7323
- /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", width: colW, marginRight: 2, children: [
7400
+ /* @__PURE__ */ jsxs2(Box2, { height: colH, children: [
7401
+ /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", width: colW, marginRight: 2, overflow: "hidden", children: [
7324
7402
  /* @__PURE__ */ jsx2(PaneTitle, { label: "LAYERS", width: colW }),
7325
7403
  /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
7326
7404
  /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "RATELIMIT ".padEnd(10) }),
7327
7405
  /* @__PURE__ */ jsx2(Text2, { color: rl?.mode === "block" ? theme.ok : rl?.mode === "detect" ? theme.warn : theme.dim, children: (rl?.mode ?? "?").padEnd(7) }),
7328
- /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: rl?.perMinute ? `${minuteNow}/${rl.perMinute} per min` : "no limit set" })
7406
+ /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: rl?.perMinute ? `${minuteNow}/${rl.perMinute}m ${rl.perHour || "\u2014"}h ${rl.perDay || "\u2014"}d` : "no limits set" })
7329
7407
  ] }),
7330
- rl?.perMinute ? /* @__PURE__ */ jsx2(HBar, { label: "load", value: minuteNow, max: rl.perMinute, width: Math.max(6, colW - 16), color: minuteNow > rl.perMinute ? theme.bad : theme.accent }) : null,
7408
+ rl?.perMinute ? /* @__PURE__ */ jsx2(HBar, { label: "load/min", value: minuteNow, max: rl.perMinute, width: Math.max(6, colW - 16), color: minuteNow > rl.perMinute ? theme.bad : theme.accent }) : null,
7331
7409
  /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
7332
7410
  /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "DLP".padEnd(10) }),
7333
7411
  /* @__PURE__ */ jsx2(Text2, { color: dl?.mode === "block" ? theme.ok : dl?.mode === "detect" ? theme.warn : theme.dim, children: (dl?.mode ?? "?").padEnd(7) }),
7334
- /* @__PURE__ */ jsxs2(Text2, { color: theme.dim, children: [
7335
- (dl?.patterns ?? []).length,
7336
- " patterns armed"
7337
- ] })
7412
+ /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: `${(dl?.patterns ?? []).length} builtin \xB7 ${(dl?.custom ?? []).length} custom` })
7338
7413
  ] }),
7339
- dlpBars.length ? dlpBars.map((d) => /* @__PURE__ */ jsx2(HBar, { label: truncate2(d.pattern, 10), value: d.count, max: maxDlpBar, width: Math.max(6, colW - 16), color: theme.bad }, d.pattern)) : /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "hits 7d none \u2014 clean" }),
7340
- ring ? /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
7414
+ dlpBars.length ? dlpBars.map((d) => /* @__PURE__ */ jsx2(HBar, { label: truncate2(d.pattern, 10), value: d.count, max: maxDlpBar, width: Math.max(6, colW - 16), color: theme.bad }, d.pattern)) : /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " no dlp hits in last 7 days" }),
7415
+ /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
7341
7416
  /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "GUARD".padEnd(10) }),
7342
- /* @__PURE__ */ jsx2(Text2, { color: theme.ok, children: "local \u2713" }),
7343
- /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: ` eval avg ${ring.avgMs}ms \xB7 ${ring.count} recent` })
7344
- ] }) : null
7417
+ ring ? /* @__PURE__ */ jsxs2(Text2, { color: theme.ok, children: [
7418
+ "local \u2713 ",
7419
+ /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: `eval avg ${ring.avgMs}ms` })
7420
+ ] }) : /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "no local ring in cwd" })
7421
+ ] })
7345
7422
  ] }),
7346
- /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", width: colW, marginRight: 2, children: [
7347
- /* @__PURE__ */ jsx2(PaneTitle, { label: "SESSIONS", extra: sessCounts ? `${sessCounts.active} live` : "", width: colW }),
7348
- ring?.session ? /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
7349
- /* @__PURE__ */ jsx2(Text2, { color: theme.ok, children: "\u25CF " }),
7350
- /* @__PURE__ */ jsx2(Text2, { color: theme.accentBright, bold: true, children: "this machine" }),
7351
- /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " " + truncate2(ring.session, 12) + " \xB7 guarded" })
7352
- ] }) : null,
7353
- sess.length === 0 && !ring ? /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "scanning\u2026" }) : null,
7354
- sess.slice(0, colH - 1 - (ring ? 1 : 0)).map((a) => {
7423
+ /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", width: colW, marginRight: 2, overflow: "hidden", children: [
7424
+ /* @__PURE__ */ jsx2(PaneTitle, { label: "SESSIONS", extra: `${localSessList.length} local \xB7 ${sessCounts?.active ?? 0} cloud`, width: colW }),
7425
+ localSessList.length === 0 && sess.length === 0 ? /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "scanning\u2026" }) : null,
7426
+ localSessList.slice(0, Math.max(1, colH - 2)).map(([id, v]) => {
7427
+ const freshDot = nowMs - v.lastAt < 9e4;
7428
+ const isMe = ring?.session === id;
7429
+ return /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
7430
+ /* @__PURE__ */ jsxs2(Text2, { color: freshDot ? theme.ok : theme.dim, children: [
7431
+ freshDot ? "\u25CF" : "\u25CB",
7432
+ " "
7433
+ ] }),
7434
+ /* @__PURE__ */ jsx2(Text2, { color: theme.ok, children: "LOC " }),
7435
+ /* @__PURE__ */ jsx2(Text2, { color: theme.accentBright, bold: isMe, children: truncate2(isMe ? "this machine" : v.agent, 12).padEnd(13) }),
7436
+ /* @__PURE__ */ jsxs2(Text2, { children: [
7437
+ String(v.calls).padStart(4),
7438
+ "c "
7439
+ ] }),
7440
+ /* @__PURE__ */ jsxs2(Text2, { color: v.denies ? theme.bad : theme.dim, children: [
7441
+ String(v.denies).padStart(3),
7442
+ "d "
7443
+ ] }),
7444
+ /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: ago(v.lastAt) })
7445
+ ] }, id);
7446
+ }),
7447
+ sess.slice(0, Math.max(0, colH - 1 - Math.min(localSessList.length, Math.max(1, colH - 2)))).map((a) => {
7355
7448
  const dot = sessionDot(a.status);
7356
7449
  return /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
7357
7450
  /* @__PURE__ */ jsxs2(Text2, { color: dot.color, children: [
7358
7451
  dot.ch,
7359
7452
  " "
7360
7453
  ] }),
7454
+ /* @__PURE__ */ jsx2(Text2, { color: "#4f6db8", children: "CLD " }),
7361
7455
  /* @__PURE__ */ jsx2(Text2, { color: theme.accent, children: truncate2(a.agent_name ?? a.session_id, 12).padEnd(13) }),
7362
7456
  /* @__PURE__ */ jsxs2(Text2, { children: [
7363
7457
  String(a.total_calls).padStart(4),
@@ -7367,12 +7461,12 @@ function LivePanel({ active: active2 }) {
7367
7461
  String(a.denied_calls).padStart(3),
7368
7462
  "d "
7369
7463
  ] }),
7370
- /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: ago(a.last_seen_at) })
7464
+ /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: `t${a.trust_score} ` + ago(a.last_seen_at) })
7371
7465
  ] }, a.session_id);
7372
7466
  })
7373
7467
  ] }),
7374
- /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", width: colW, children: [
7375
- /* @__PURE__ */ jsx2(PaneTitle, { label: "EVENT LOG", extra: "streaming", width: colW }),
7468
+ /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", width: colW, overflow: "hidden", children: [
7469
+ /* @__PURE__ */ jsx2(PaneTitle, { label: "EVENT LOG", extra: "system heartbeat", width: colW }),
7376
7470
  log6.slice(-(colH - 1)).map((l, i) => /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
7377
7471
  /* @__PURE__ */ jsxs2(Text2, { color: theme.dim, children: [
7378
7472
  hhmmss(l.ts),
@@ -7383,37 +7477,49 @@ function LivePanel({ active: active2 }) {
7383
7477
  ] }, l.ts + ":" + i))
7384
7478
  ] })
7385
7479
  ] }),
7386
- /* @__PURE__ */ jsx2(PaneTitle, { label: "TOOL STREAM", extra: `local+cloud tail \xB7 ${merged.length} buffered`, width: innerW }),
7387
- localOn === false ? /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
7388
- /* @__PURE__ */ jsx2(Text2, { color: theme.warn, children: "local logs off" }),
7389
- /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2014 enable in dashboard \u2192 Settings \u2192 Local logs; hooks then write ~/.solongate/local-logs (view them there with `solongate logs-server`)" })
7390
- ] }) : null,
7391
- tail.length === 0 ? /* @__PURE__ */ jsxs2(Text2, { color: theme.dim, children: [
7392
- spin,
7393
- " awaiting traffic\u2026"
7394
- ] }) : null,
7395
- tail.map((e) => /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
7396
- /* @__PURE__ */ jsxs2(Text2, { color: theme.dim, children: [
7397
- "[",
7398
- hhmmss(e.at),
7399
- " "
7400
- ] }),
7401
- /* @__PURE__ */ jsx2(Text2, { color: e.source === "local" ? theme.ok : "#4f6db8", children: e.source === "local" ? "LOC" : "CLD" }),
7402
- /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "] " }),
7403
- /* @__PURE__ */ jsx2(Text2, { color: decisionColor(e.decision), bold: e.decision !== "ALLOW", children: e.decision.padEnd(6) }),
7404
- /* @__PURE__ */ jsx2(Text2, { color: theme.accent, children: truncate2(e.tool, 14).padEnd(15) }),
7405
- /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: e.permission.padEnd(5) }),
7406
- e.dlp ? /* @__PURE__ */ jsx2(Text2, { color: theme.bad, children: "DLP! " }) : null,
7407
- /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: e.detail })
7408
- ] }, e.id)),
7480
+ /* @__PURE__ */ jsx2(
7481
+ PaneTitle,
7482
+ {
7483
+ label: "TOOL STREAM",
7484
+ extra: `last ${STREAM_KEEP} \xB7 filter ${filter}${clampedScroll > 0 ? ` \xB7 \u25B2${clampedScroll} scrolled` : " \xB7 following"} \xB7 f filter \xB7 \u2191\u2193 scroll \xB7 c copy`,
7485
+ width: innerW
7486
+ }
7487
+ ),
7488
+ /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", height: streamRows, overflow: "hidden", children: [
7489
+ localOn === false ? /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
7490
+ /* @__PURE__ */ jsx2(Text2, { color: theme.warn, children: "local logs off" }),
7491
+ /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2014 enable: dashboard \u2192 Settings \u2192 Local logs \xB7 hooks write ~/.solongate/local-logs \xB7 view: `solongate logs-server`" })
7492
+ ] }) : null,
7493
+ windowed.length === 0 ? /* @__PURE__ */ jsxs2(Text2, { color: theme.dim, children: [
7494
+ spin,
7495
+ " awaiting traffic\u2026"
7496
+ ] }) : null,
7497
+ windowed.map((e) => /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
7498
+ /* @__PURE__ */ jsxs2(Text2, { color: theme.dim, children: [
7499
+ "[",
7500
+ hhmmss(e.at),
7501
+ " "
7502
+ ] }),
7503
+ /* @__PURE__ */ jsx2(Text2, { color: e.source === "local" ? theme.ok : "#4f6db8", children: e.source === "local" ? "LOC" : "CLD" }),
7504
+ /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "] " }),
7505
+ /* @__PURE__ */ jsx2(Text2, { color: decisionColor(e.decision), bold: e.decision !== "ALLOW", children: e.decision.padEnd(6) }),
7506
+ /* @__PURE__ */ jsx2(Text2, { color: theme.accent, children: truncate2(e.tool, 12).padEnd(13) }),
7507
+ /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: e.permission.padEnd(5) }),
7508
+ /* @__PURE__ */ jsx2(Text2, { color: e.evalMs != null && e.evalMs > 500 ? theme.warn : theme.dim, children: (e.evalMs != null ? `${e.evalMs}ms` : "\u2014").padEnd(7) }),
7509
+ /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: truncate2(e.agent ?? "-", 11).padEnd(12) }),
7510
+ e.dlp ? /* @__PURE__ */ jsx2(Text2, { color: theme.bad, children: "DLP! " }) : null,
7511
+ e.rule && e.decision !== "ALLOW" ? /* @__PURE__ */ jsx2(Text2, { color: theme.bad, children: truncate2(e.rule, 14) + " " }) : null,
7512
+ /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: e.detail })
7513
+ ] }, e.id))
7514
+ ] }),
7409
7515
  /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
7410
7516
  /* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", bold: true, children: " LIVE " }),
7411
- /* @__PURE__ */ jsx2(Text2, { backgroundColor: "#0b1530", color: "#4f6db8", children: ` local ${localOn ? "on" : "off"} \xB7 top ${topTools.map(([t, c2]) => `${t}\xD7${c2}`).join(" ") || "\u2014"} \xB7 buf ${merged.length} ` }),
7412
- /* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", children: " esc menu \xB7 q quit " })
7517
+ /* @__PURE__ */ jsx2(Text2, { backgroundColor: "#0b1530", color: "#4f6db8", children: ` local ${localOn ? "on" : "off"} \xB7 ${localBuf.length} loc/${cloudBuf.length} cld buffered \xB7 top ${topTools.map(([t, c2]) => `${t}\xD7${c2}`).join(" ") || "\u2014"} ` }),
7518
+ /* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", children: " f filter \xB7 \u2191\u2193 scroll \xB7 c copy \xB7 esc menu \xB7 q quit " })
7413
7519
  ] })
7414
7520
  ] });
7415
7521
  }
7416
- var SPIN, BG, LOCAL_LOG, RING, hhmmss, fmtUp;
7522
+ var SPIN, BG, DIM_FLOOR, LOCAL_LOG, RING, DUMP, STREAM_KEEP, hhmmss, fmtUp, FILTERS;
7417
7523
  var init_Live = __esm({
7418
7524
  "src/tui/panels/Live.tsx"() {
7419
7525
  "use strict";
@@ -7422,8 +7528,11 @@ var init_Live = __esm({
7422
7528
  init_theme();
7423
7529
  SPIN = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
7424
7530
  BG = "#12234f";
7531
+ DIM_FLOOR = "#233457";
7425
7532
  LOCAL_LOG = join5(homedir3(), ".solongate", "local-logs", "solongate-audit.jsonl");
7426
7533
  RING = join5(process.cwd(), ".solongate", ".eval-ring.jsonl");
7534
+ DUMP = join5(homedir3(), ".solongate", "live-stream.log");
7535
+ STREAM_KEEP = 100;
7427
7536
  hhmmss = (ts) => {
7428
7537
  const d = new Date(ts);
7429
7538
  return Number.isNaN(d.getTime()) ? "--:--:--" : d.toTimeString().slice(0, 8);
@@ -7433,11 +7542,12 @@ var init_Live = __esm({
7433
7542
  const p = (n) => String(n).padStart(2, "0");
7434
7543
  return `${p(Math.floor(s / 3600))}:${p(Math.floor(s % 3600 / 60))}:${p(s % 60)}`;
7435
7544
  };
7545
+ FILTERS = ["all", "local", "cloud"];
7436
7546
  }
7437
7547
  });
7438
7548
 
7439
7549
  // src/tui/panels/Policies.tsx
7440
- import { Box as Box3, Text as Text3, useInput } from "ink";
7550
+ import { Box as Box3, Text as Text3, useInput as useInput2 } from "ink";
7441
7551
  import TextInput from "ink-text-input";
7442
7552
  import { useEffect as useEffect3, useState as useState3 } from "react";
7443
7553
  import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
@@ -7507,7 +7617,7 @@ function PoliciesPanel({ focused }) {
7507
7617
  setDirty(false);
7508
7618
  setStatus("discarded");
7509
7619
  };
7510
- useInput(
7620
+ useInput2(
7511
7621
  (input, key) => {
7512
7622
  if (view === "list") {
7513
7623
  if (key.upArrow) setPi((n) => Math.max(0, n - 1));
@@ -7682,7 +7792,7 @@ var init_Policies = __esm({
7682
7792
  });
7683
7793
 
7684
7794
  // src/tui/panels/RateLimit.tsx
7685
- import { Box as Box4, Text as Text4, useInput as useInput2 } from "ink";
7795
+ import { Box as Box4, Text as Text4, useInput as useInput3 } from "ink";
7686
7796
  import { useEffect as useEffect4, useState as useState4 } from "react";
7687
7797
  import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
7688
7798
  function ColoredSpark({ values, limit, width: width2 = 60 }) {
@@ -7730,7 +7840,7 @@ function RateLimitPanel({ focused }) {
7730
7840
  setStatus("\u2717 " + (e instanceof Error ? e.message : String(e)));
7731
7841
  }
7732
7842
  };
7733
- useInput2(
7843
+ useInput3(
7734
7844
  (input, key) => {
7735
7845
  const step = key.shift ? 10 : 1;
7736
7846
  if (key.upArrow) setFi((n) => (n - 1 + FIELDS2.length) % FIELDS2.length);
@@ -7822,7 +7932,7 @@ var init_RateLimit = __esm({
7822
7932
  });
7823
7933
 
7824
7934
  // src/tui/panels/Dlp.tsx
7825
- import { Box as Box5, Text as Text5, useInput as useInput3 } from "ink";
7935
+ import { Box as Box5, Text as Text5, useInput as useInput4 } from "ink";
7826
7936
  import TextInput2 from "ink-text-input";
7827
7937
  import { useEffect as useEffect5, useState as useState5 } from "react";
7828
7938
  import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
@@ -7866,7 +7976,7 @@ function DlpPanel({ focused }) {
7866
7976
  };
7867
7977
  const customCount = dlp?.custom.length ?? 0;
7868
7978
  const total = available.length + customCount;
7869
- useInput3(
7979
+ useInput4(
7870
7980
  (input, key) => {
7871
7981
  if (!dlp) return;
7872
7982
  if (key.upArrow) setSel((n) => Math.max(0, n - 1));
@@ -8048,7 +8158,7 @@ var init_Stats = __esm({
8048
8158
  });
8049
8159
 
8050
8160
  // src/tui/panels/Audit.tsx
8051
- import { Box as Box7, Text as Text7, useInput as useInput4 } from "ink";
8161
+ import { Box as Box7, Text as Text7, useInput as useInput5 } from "ink";
8052
8162
  import TextInput3 from "ink-text-input";
8053
8163
  import { useState as useState6 } from "react";
8054
8164
  import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
@@ -8077,7 +8187,7 @@ function AuditPanel({ active: active2, focused }) {
8077
8187
  () => view === "detail" && current?.session_id ? api.audit.list({ session_id: current.session_id, limit: 40 }) : Promise.resolve(null),
8078
8188
  [view, current?.session_id]
8079
8189
  );
8080
- useInput4(
8190
+ useInput5(
8081
8191
  (input, key) => {
8082
8192
  if (view === "detail") {
8083
8193
  if (key.leftArrow || key.escape) setView("list");
@@ -8227,7 +8337,7 @@ var init_Audit = __esm({
8227
8337
  });
8228
8338
 
8229
8339
  // src/tui/App.tsx
8230
- import { Box as Box8, Text as Text8, useApp, useInput as useInput5 } from "ink";
8340
+ import { Box as Box8, Text as Text8, useApp, useInput as useInput6 } from "ink";
8231
8341
  import { useState as useState7 } from "react";
8232
8342
  import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
8233
8343
  function LiveHint() {
@@ -8259,7 +8369,7 @@ function App() {
8259
8369
  const { exit } = useApp();
8260
8370
  const [section, setSection] = useState7(0);
8261
8371
  const [focus, setFocus] = useState7("nav");
8262
- useInput5((input, key) => {
8372
+ useInput6((input, key) => {
8263
8373
  if (focus === "nav") {
8264
8374
  if (key.upArrow) setSection((n) => (n - 1 + SECTIONS.length) % SECTIONS.length);
8265
8375
  else if (key.downArrow) setSection((n) => (n + 1) % SECTIONS.length);
@@ -9094,8 +9204,8 @@ __export(global_install_exports, {
9094
9204
  runGlobalRestore: () => runGlobalRestore,
9095
9205
  unlockProtected: () => unlockProtected
9096
9206
  });
9097
- import { readFileSync as readFileSync6, writeFileSync as writeFileSync3, existsSync as existsSync4, mkdirSync as mkdirSync3 } from "fs";
9098
- import { resolve as resolve4, join as join6, dirname } from "path";
9207
+ import { readFileSync as readFileSync6, writeFileSync as writeFileSync4, existsSync as existsSync4, mkdirSync as mkdirSync4 } from "fs";
9208
+ import { resolve as resolve4, join as join6, dirname as dirname2 } from "path";
9099
9209
  import { homedir as homedir4 } from "os";
9100
9210
  import { fileURLToPath } from "url";
9101
9211
  import { createInterface } from "readline";
@@ -9207,13 +9317,13 @@ function runGlobalRestore() {
9207
9317
  unlockProtected();
9208
9318
  removeClaudeShim();
9209
9319
  if (existsSync4(p.backupPath)) {
9210
- writeFileSync3(p.settingsPath, readFileSync6(p.backupPath, "utf-8"));
9320
+ writeFileSync4(p.settingsPath, readFileSync6(p.backupPath, "utf-8"));
9211
9321
  console.log(` Restored ${p.settingsPath} from backup.`);
9212
9322
  } else if (existsSync4(p.settingsPath)) {
9213
9323
  try {
9214
9324
  const s = JSON.parse(readFileSync6(p.settingsPath, "utf-8"));
9215
9325
  delete s.hooks;
9216
- writeFileSync3(p.settingsPath, JSON.stringify(s, null, 2) + "\n");
9326
+ writeFileSync4(p.settingsPath, JSON.stringify(s, null, 2) + "\n");
9217
9327
  console.log(` Removed SolonGate hooks from ${p.settingsPath}.`);
9218
9328
  } catch {
9219
9329
  }
@@ -9257,8 +9367,8 @@ function writeShimBlock(file, block) {
9257
9367
  if (content.length && !content.endsWith("\n")) content += "\n";
9258
9368
  content += block + "\n";
9259
9369
  }
9260
- mkdirSync3(dirname(file), { recursive: true });
9261
- writeFileSync3(file, content);
9370
+ mkdirSync4(dirname2(file), { recursive: true });
9371
+ writeFileSync4(file, content);
9262
9372
  }
9263
9373
  function installClaudeShim(shieldPath) {
9264
9374
  const real = resolveRealClaude();
@@ -9315,22 +9425,22 @@ async function runGlobalInstall(opts = {}) {
9315
9425
  process.exit(1);
9316
9426
  }
9317
9427
  const apiUrl = opts.apiUrl || process.env["SOLONGATE_API_URL"] || "https://api.solongate.com";
9318
- mkdirSync3(p.hooksDir, { recursive: true });
9319
- mkdirSync3(p.claudeDir, { recursive: true });
9428
+ mkdirSync4(p.hooksDir, { recursive: true });
9429
+ mkdirSync4(p.claudeDir, { recursive: true });
9320
9430
  unlockProtected();
9321
- writeFileSync3(join6(p.hooksDir, "guard.mjs"), readGuard());
9322
- writeFileSync3(join6(p.hooksDir, "audit.mjs"), readHook("audit.mjs"));
9323
- writeFileSync3(join6(p.hooksDir, "stop.mjs"), readHook("stop.mjs"));
9324
- writeFileSync3(join6(p.hooksDir, "shield.mjs"), readHook("shield.mjs"));
9431
+ writeFileSync4(join6(p.hooksDir, "guard.mjs"), readGuard());
9432
+ writeFileSync4(join6(p.hooksDir, "audit.mjs"), readHook("audit.mjs"));
9433
+ writeFileSync4(join6(p.hooksDir, "stop.mjs"), readHook("stop.mjs"));
9434
+ writeFileSync4(join6(p.hooksDir, "shield.mjs"), readHook("shield.mjs"));
9325
9435
  console.log(` Installed hooks \u2192 ${p.hooksDir}`);
9326
9436
  removeClaudeShim();
9327
- writeFileSync3(p.configPath, JSON.stringify({ apiKey, apiUrl }, null, 2) + "\n");
9437
+ writeFileSync4(p.configPath, JSON.stringify({ apiKey, apiUrl }, null, 2) + "\n");
9328
9438
  console.log(` Wrote ${p.configPath}`);
9329
9439
  let existing = {};
9330
9440
  if (existsSync4(p.settingsPath)) {
9331
9441
  const raw = readFileSync6(p.settingsPath, "utf-8");
9332
9442
  if (!existsSync4(p.backupPath)) {
9333
- writeFileSync3(p.backupPath, raw);
9443
+ writeFileSync4(p.backupPath, raw);
9334
9444
  console.log(` Backed up existing settings \u2192 ${p.backupPath}`);
9335
9445
  }
9336
9446
  try {
@@ -9351,7 +9461,7 @@ async function runGlobalInstall(opts = {}) {
9351
9461
  Stop: [{ matcher: "", hooks: [{ type: "command", command: `"${nodeBin}" "${stopAbs}" claude-code "Claude Code"` }] }]
9352
9462
  }
9353
9463
  };
9354
- writeFileSync3(p.settingsPath, JSON.stringify(merged, null, 2) + "\n");
9464
+ writeFileSync4(p.settingsPath, JSON.stringify(merged, null, 2) + "\n");
9355
9465
  console.log(` Registered global hooks \u2192 ${p.settingsPath}`);
9356
9466
  if (process.env["SOLONGATE_OS_LOCK"] === "1") {
9357
9467
  lockProtected();
@@ -9365,7 +9475,7 @@ var __dirname, HOOKS_DIR, SHIM_BEGIN, SHIM_END;
9365
9475
  var init_global_install = __esm({
9366
9476
  "src/global-install.ts"() {
9367
9477
  "use strict";
9368
- __dirname = dirname(fileURLToPath(import.meta.url));
9478
+ __dirname = dirname2(fileURLToPath(import.meta.url));
9369
9479
  HOOKS_DIR = resolve4(__dirname, "..", "hooks");
9370
9480
  SHIM_BEGIN = "# >>> SolonGate shield (auto secret redaction) >>>";
9371
9481
  SHIM_END = "# <<< SolonGate shield <<<";
@@ -10015,7 +10125,7 @@ var init_logs_server = __esm({
10015
10125
 
10016
10126
  // src/inject.ts
10017
10127
  var inject_exports = {};
10018
- import { readFileSync as readFileSync9, writeFileSync as writeFileSync4, existsSync as existsSync6, copyFileSync } from "fs";
10128
+ import { readFileSync as readFileSync9, writeFileSync as writeFileSync5, existsSync as existsSync6, copyFileSync } from "fs";
10019
10129
  import { resolve as resolve7 } from "path";
10020
10130
  import { execSync } from "child_process";
10021
10131
  function parseInjectArgs(argv) {
@@ -10323,7 +10433,7 @@ async function main2() {
10323
10433
  log3("");
10324
10434
  log3(` Backup: ${backupPath}`);
10325
10435
  }
10326
- writeFileSync4(entryFile, result.modified);
10436
+ writeFileSync5(entryFile, result.modified);
10327
10437
  log3("");
10328
10438
  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");
10329
10439
  log3(" \u2502 SolonGate SDK injected successfully! \u2502");
@@ -10352,7 +10462,7 @@ var init_inject = __esm({
10352
10462
 
10353
10463
  // src/create.ts
10354
10464
  var create_exports = {};
10355
- import { mkdirSync as mkdirSync4, writeFileSync as writeFileSync5, existsSync as existsSync7 } from "fs";
10465
+ import { mkdirSync as mkdirSync5, writeFileSync as writeFileSync6, existsSync as existsSync7 } from "fs";
10356
10466
  import { resolve as resolve8, join as join8 } from "path";
10357
10467
  import { execSync as execSync2 } from "child_process";
10358
10468
  function withSpinner(message, fn) {
@@ -10432,7 +10542,7 @@ EXAMPLES
10432
10542
  `);
10433
10543
  }
10434
10544
  function createProject(dir, name, _policy) {
10435
- writeFileSync5(
10545
+ writeFileSync6(
10436
10546
  join8(dir, "package.json"),
10437
10547
  JSON.stringify(
10438
10548
  {
@@ -10462,7 +10572,7 @@ function createProject(dir, name, _policy) {
10462
10572
  2
10463
10573
  ) + "\n"
10464
10574
  );
10465
- writeFileSync5(
10575
+ writeFileSync6(
10466
10576
  join8(dir, "tsconfig.json"),
10467
10577
  JSON.stringify(
10468
10578
  {
@@ -10483,8 +10593,8 @@ function createProject(dir, name, _policy) {
10483
10593
  2
10484
10594
  ) + "\n"
10485
10595
  );
10486
- mkdirSync4(join8(dir, "src"), { recursive: true });
10487
- writeFileSync5(
10596
+ mkdirSync5(join8(dir, "src"), { recursive: true });
10597
+ writeFileSync6(
10488
10598
  join8(dir, "src", "index.ts"),
10489
10599
  `#!/usr/bin/env node
10490
10600
 
@@ -10526,7 +10636,7 @@ console.log('');
10526
10636
  console.log('Press Ctrl+C to stop.');
10527
10637
  `
10528
10638
  );
10529
- writeFileSync5(
10639
+ writeFileSync6(
10530
10640
  join8(dir, ".mcp.json"),
10531
10641
  JSON.stringify(
10532
10642
  {
@@ -10544,12 +10654,12 @@ console.log('Press Ctrl+C to stop.');
10544
10654
  2
10545
10655
  ) + "\n"
10546
10656
  );
10547
- writeFileSync5(
10657
+ writeFileSync6(
10548
10658
  join8(dir, ".env"),
10549
10659
  `SOLONGATE_API_KEY=sg_live_YOUR_KEY_HERE
10550
10660
  `
10551
10661
  );
10552
- writeFileSync5(
10662
+ writeFileSync6(
10553
10663
  join8(dir, ".gitignore"),
10554
10664
  `node_modules/
10555
10665
  dist/
@@ -10569,7 +10679,7 @@ async function main3() {
10569
10679
  process.exit(1);
10570
10680
  }
10571
10681
  withSpinner(`Setting up ${opts.name}...`, () => {
10572
- mkdirSync4(dir, { recursive: true });
10682
+ mkdirSync5(dir, { recursive: true });
10573
10683
  createProject(dir, opts.name, opts.policy);
10574
10684
  });
10575
10685
  if (!opts.noInstall) {
@@ -10643,7 +10753,7 @@ var init_create = __esm({
10643
10753
 
10644
10754
  // src/pull-push.ts
10645
10755
  var pull_push_exports = {};
10646
- import { readFileSync as readFileSync10, writeFileSync as writeFileSync6, existsSync as existsSync8 } from "fs";
10756
+ import { readFileSync as readFileSync10, writeFileSync as writeFileSync7, existsSync as existsSync8 } from "fs";
10647
10757
  import { resolve as resolve9 } from "path";
10648
10758
  function loadEnv() {
10649
10759
  if (process.env.SOLONGATE_API_KEY) return;
@@ -10838,7 +10948,7 @@ async function pull(apiKey, file, policyId) {
10838
10948
  const policy = await fetchCloudPolicy(apiKey, API_URL, policyId);
10839
10949
  const { id: _id, ...policyWithoutId } = policy;
10840
10950
  const json = JSON.stringify(policyWithoutId, null, 2) + "\n";
10841
- writeFileSync6(file, json, "utf-8");
10951
+ writeFileSync7(file, json, "utf-8");
10842
10952
  log5("");
10843
10953
  log5(green2(" Saved to: ") + file);
10844
10954
  log5(` ${dim2("Name:")} ${policy.name}`);