@solongate/proxy 0.72.0 → 0.73.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.
Files changed (3) hide show
  1. package/dist/index.js +195 -212
  2. package/dist/tui/index.js +165 -182
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -7030,12 +7030,11 @@ var init_hooks = __esm({
7030
7030
 
7031
7031
  // src/tui/panels/Live.tsx
7032
7032
  import { Box as Box2, Text as Text2, useInput } from "ink";
7033
- import { spawnSync } from "child_process";
7034
- import { closeSync, mkdirSync as mkdirSync3, openSync, readSync, statSync, writeFileSync as writeFileSync3 } from "fs";
7033
+ import { closeSync, openSync, readSync, statSync } from "fs";
7035
7034
  import { homedir as homedir3 } from "os";
7036
- import { dirname, join as join5 } from "path";
7035
+ import { join as join5 } from "path";
7037
7036
  import { useCallback as useCallback2, useEffect as useEffect2, useRef as useRef2, useState as useState2 } from "react";
7038
- import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
7037
+ import { Fragment as Fragment2, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
7039
7038
  function tailLines(file, maxBytes = 131072) {
7040
7039
  try {
7041
7040
  const size = statSync(file).size;
@@ -7051,22 +7050,6 @@ function tailLines(file, maxBytes = 131072) {
7051
7050
  return [];
7052
7051
  }
7053
7052
  }
7054
- function copyToClipboard(text) {
7055
- const tools = [
7056
- ["wl-copy", []],
7057
- ["xclip", ["-selection", "clipboard"]],
7058
- ["xsel", ["--clipboard", "--input"]]
7059
- ];
7060
- for (const [cmd, args] of tools) {
7061
- try {
7062
- const r = spawnSync(cmd, args, { input: text, timeout: 2e3 });
7063
- if (r.status === 0) return cmd;
7064
- } catch {
7065
- }
7066
- }
7067
- process.stdout.write(`\x1B]52;c;${Buffer.from(text, "utf-8").toString("base64")}\x07`);
7068
- return null;
7069
- }
7070
7053
  function cloudItem(e) {
7071
7054
  return {
7072
7055
  id: "c:" + e.id,
@@ -7076,6 +7059,7 @@ function cloudItem(e) {
7076
7059
  permission: (e.permission ?? "").slice(0, 4),
7077
7060
  detail: (e.arguments_summary ? JSON.stringify(e.arguments_summary) : e.reason ?? "").replace(/\s+/g, " "),
7078
7061
  dlp: !!e.dlp_matches?.length,
7062
+ burst: !!e.rate_limit_burst,
7079
7063
  source: "cloud",
7080
7064
  session: e.session_id ?? void 0,
7081
7065
  agent: e.agent_name ?? void 0,
@@ -7131,6 +7115,12 @@ function PaneTitle({ label, extra, width: width2 }) {
7131
7115
  /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: tail + "\u2500".repeat(Math.max(0, width2 - used)) })
7132
7116
  ] });
7133
7117
  }
7118
+ function Stat({ label, value, color }) {
7119
+ return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", marginRight: 3, children: [
7120
+ /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: label }),
7121
+ /* @__PURE__ */ jsx2(Text2, { bold: true, color, children: String(value) })
7122
+ ] });
7123
+ }
7134
7124
  function StreamLine({ e, loc }) {
7135
7125
  return /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
7136
7126
  /* @__PURE__ */ jsxs2(Text2, { color: theme.dim, children: [
@@ -7146,6 +7136,7 @@ function StreamLine({ e, loc }) {
7146
7136
  /* @__PURE__ */ jsx2(Text2, { color: e.evalMs != null && e.evalMs > 500 ? theme.warn : theme.dim, children: (e.evalMs != null ? `${e.evalMs}ms` : "\u2014").padEnd(7) }),
7147
7137
  /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: truncate2(e.agent ?? "-", 11).padEnd(12) }),
7148
7138
  e.dlp ? /* @__PURE__ */ jsx2(Text2, { color: theme.bad, children: "DLP! " }) : null,
7139
+ e.burst ? /* @__PURE__ */ jsx2(Text2, { color: theme.warn, children: "BURST " }) : null,
7149
7140
  e.rule && e.decision !== "ALLOW" ? /* @__PURE__ */ jsx2(Text2, { color: theme.bad, children: truncate2(e.rule, 14) + " " }) : null,
7150
7141
  /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: e.detail })
7151
7142
  ] });
@@ -7161,12 +7152,11 @@ function LivePanel({ active: active2 }) {
7161
7152
  const [log6, setLog] = useState2([]);
7162
7153
  const [filter, setFilter] = useState2("all");
7163
7154
  const [scroll, setScroll] = useState2(0);
7164
- const [toast, setToast] = useState2(null);
7165
7155
  const [mode, setMode] = useState2("stream");
7156
+ const [sessFilter, setSessFilter] = useState2("all");
7166
7157
  const [pickIdx, setPickIdx] = useState2(0);
7167
- const [detail, setDetail] = useState2(null);
7168
7158
  const [detailCloud, setDetailCloud] = useState2([]);
7169
- const [detailScroll, setDetailScroll] = useState2(0);
7159
+ const [tlScroll, setTlScroll] = useState2(0);
7170
7160
  const seenRef = useRef2(/* @__PURE__ */ new Set());
7171
7161
  const lastLocalTs = useRef2(0);
7172
7162
  const pausedUntil = useRef2(0);
@@ -7211,6 +7201,7 @@ function LivePanel({ active: active2 }) {
7211
7201
  permission: (j.permission ?? "").slice(0, 4),
7212
7202
  detail: (j.arguments ? JSON.stringify(j.arguments) : j.reason ?? "").replace(/\s+/g, " "),
7213
7203
  dlp: !!j.dlp,
7204
+ burst: !!j.rate_limit_burst,
7214
7205
  source: "local",
7215
7206
  session: j.session_id,
7216
7207
  agent: j.agent_name,
@@ -7315,19 +7306,6 @@ function LivePanel({ active: active2 }) {
7315
7306
  usePoll(() => {
7316
7307
  if (!paused()) guard.reload();
7317
7308
  }, 6e4, active2);
7318
- useEffect2(() => {
7319
- if (!detail) return;
7320
- setDetailCloud([]);
7321
- setDetailScroll(0);
7322
- let alive = true;
7323
- api.audit.list({ session_id: detail.id, limit: 100 }).then((r) => {
7324
- if (alive) setDetailCloud(r.entries.map(cloudItem));
7325
- }).catch(() => {
7326
- });
7327
- return () => {
7328
- alive = false;
7329
- };
7330
- }, [detail]);
7331
7309
  const [tick, setTick] = useState2(0);
7332
7310
  useEffect2(() => {
7333
7311
  if (!active2 || frozen) return;
@@ -7347,67 +7325,68 @@ function LivePanel({ active: active2 }) {
7347
7325
  }
7348
7326
  const cloudDeduped = cloudBuf.filter((e) => !localKeys.has(`${e.tool}|${e.decision}|${Math.round(e.at / 6e4)}`));
7349
7327
  const mergedAll = [...cloudDeduped, ...localBuf].sort((a, b) => a.at - b.at);
7350
- const points = tsData?.timeseries ?? [];
7351
- const nowMin = Math.floor(nowMs / 6e4);
7352
- const minuteCounts = new Array(60).fill(0);
7353
- const minuteHot = new Array(60).fill(false);
7354
- for (const e of mergedAll) {
7355
- const idx = 59 - (nowMin - Math.floor(e.at / 6e4));
7356
- if (idx >= 0 && idx < 60) {
7357
- minuteCounts[idx]++;
7358
- if (e.decision !== "ALLOW") minuteHot[idx] = true;
7359
- }
7360
- }
7361
- const localTraffic = localOn === true && minuteCounts.some((c2) => c2 > 0);
7362
- const traffic = localTraffic ? minuteCounts : points.map((p) => p.total);
7363
- const trafficHot = localTraffic ? minuteHot : points.map((p) => p.denied > 0);
7364
- const trafficLabel = localTraffic ? "calls/min \xB7 60m \xB7 local+cloud" : "24h \xB7 cloud";
7365
- const rl = ins.layers?.rateLimit;
7366
- const dl = ins.layers?.dlp;
7367
- const gh = ins.layers?.ghost;
7368
- const minuteNow = minuteCounts[59] ?? 0;
7369
- const dlpBars = (ins.dlpByPattern ?? []).slice(0, 2);
7370
- const maxDlpBar = dlpBars[0]?.count ?? 1;
7371
- const denialsAll = mergedAll.filter((e) => e.decision !== "ALLOW");
7372
- const lastDeny = denialsAll[denialsAll.length - 1];
7373
- const toolCounts = /* @__PURE__ */ new Map();
7374
- for (const e of mergedAll) toolCounts.set(e.tool, (toolCounts.get(e.tool) ?? 0) + 1);
7375
- const topTools = [...toolCounts.entries()].sort((a, b) => b[1] - a[1]).slice(0, 3);
7376
- const latNow = lat[lat.length - 1] ?? 0;
7377
- const sortedLat = [...lat].sort((a, b) => a - b);
7378
- const latMed = sortedLat.length ? sortedLat[Math.floor(sortedLat.length / 2)] : 0;
7379
- const latHotAt = Math.max(2e3, latMed * 2.5);
7380
- const backingOff = Date.now() < pausedUntil.current;
7381
- const sess = (sessions.data?.agents ?? []).slice().sort((a, b) => Date.parse(b.last_seen_at) - Date.parse(a.last_seen_at));
7382
- const sessCounts = sessions.data?.counts;
7383
7328
  const localSess = /* @__PURE__ */ new Map();
7384
7329
  for (const e of localBuf) {
7385
7330
  if (!e.session) continue;
7386
- const cur = localSess.get(e.session) ?? { agent: e.agent ?? "local agent", calls: 0, denies: 0, lastAt: 0 };
7331
+ const cur = localSess.get(e.session) ?? { agent: e.agent ?? "local agent", calls: 0, denies: 0, dlp: 0, lastAt: 0 };
7387
7332
  cur.calls++;
7388
7333
  if (e.decision !== "ALLOW") cur.denies++;
7334
+ if (e.dlp) cur.dlp++;
7389
7335
  cur.lastAt = Math.max(cur.lastAt, e.at);
7390
7336
  if (e.agent) cur.agent = e.agent;
7391
7337
  localSess.set(e.session, cur);
7392
7338
  }
7393
- const combinedSess = [
7394
- ...[...localSess.entries()].sort((a, b) => b[1].lastAt - a[1].lastAt).map(([id, v]) => ({ source: "local", id, agent: v.agent, calls: v.calls, denies: v.denies, lastAt: v.lastAt, isMe: ring?.session === id })),
7395
- ...sess.filter((a) => !localSess.has(a.session_id)).map((a) => ({
7339
+ const combinedSessAll = [
7340
+ ...[...localSess.entries()].sort((a, b) => b[1].lastAt - a[1].lastAt).map(([id, v]) => ({ source: "local", id, agent: v.agent, calls: v.calls, denies: v.denies, dlp: v.dlp, lastAt: v.lastAt, isMe: ring?.session === id })),
7341
+ ...(sessions.data?.agents ?? []).filter((a) => !localSess.has(a.session_id)).sort((a, b) => Date.parse(b.last_seen_at) - Date.parse(a.last_seen_at)).map((a) => ({
7396
7342
  source: "cloud",
7397
7343
  id: a.session_id,
7398
7344
  agent: a.agent_name ?? a.session_id,
7399
7345
  calls: a.total_calls,
7400
7346
  denies: a.denied_calls,
7347
+ dlp: a.dlp_events,
7401
7348
  lastAt: Date.parse(a.last_seen_at),
7402
7349
  trust: a.trust_score,
7403
7350
  isMe: false
7404
7351
  }))
7405
7352
  ];
7353
+ const combinedSess = sessFilter === "all" ? combinedSessAll : combinedSessAll.filter((r) => sessStatus(r.lastAt, nowMs) === sessFilter);
7406
7354
  const localSessIds = new Set(localSess.keys());
7407
7355
  if (ring?.session) localSessIds.add(ring.session);
7408
7356
  const isLoc = (e) => e.source === "local" || !!e.session && localSessIds.has(e.session);
7409
7357
  const filtered = filter === "all" ? mergedAll : mergedAll.filter((e) => filter === "local" ? isLoc(e) : !isLoc(e));
7410
7358
  const visibleDesc = filtered.slice(-STREAM_KEEP).reverse();
7359
+ const points = tsData?.timeseries ?? [];
7360
+ const nowSlot = Math.floor(nowMs / 1e4);
7361
+ const slotCounts = new Array(60).fill(0);
7362
+ const slotHot = new Array(60).fill(false);
7363
+ for (const e of mergedAll) {
7364
+ const idx = 59 - (nowSlot - Math.floor(e.at / 1e4));
7365
+ if (idx >= 0 && idx < 60) {
7366
+ slotCounts[idx]++;
7367
+ if (e.decision !== "ALLOW") slotHot[idx] = true;
7368
+ }
7369
+ }
7370
+ const localTraffic = localOn === true && slotCounts.some((c2) => c2 > 0);
7371
+ const traffic = localTraffic ? slotCounts : points.map((p) => p.total);
7372
+ const trafficHot = localTraffic ? slotHot : points.map((p) => p.denied > 0);
7373
+ const trafficLabel = localTraffic ? "calls/10s \xB7 last 10m" : "24h \xB7 cloud";
7374
+ const rl = ins.layers?.rateLimit;
7375
+ const dl = ins.layers?.dlp;
7376
+ const gh = ins.layers?.ghost;
7377
+ const minuteNow = mergedAll.filter((e) => nowMs - e.at < 6e4).length;
7378
+ const dlpBars = (ins.dlpByPattern ?? []).slice(0, 2);
7379
+ const maxDlpBar = dlpBars[0]?.count ?? 1;
7380
+ const denialsAll = mergedAll.filter((e) => e.decision !== "ALLOW");
7381
+ const lastDeny = denialsAll[denialsAll.length - 1];
7382
+ const toolCounts = /* @__PURE__ */ new Map();
7383
+ for (const e of mergedAll) toolCounts.set(e.tool, (toolCounts.get(e.tool) ?? 0) + 1);
7384
+ const topTools = [...toolCounts.entries()].sort((a, b) => b[1] - a[1]).slice(0, 3);
7385
+ const latNow = lat[lat.length - 1] ?? 0;
7386
+ const sortedLat = [...lat].sort((a, b) => a - b);
7387
+ const latMed = sortedLat.length ? sortedLat[Math.floor(sortedLat.length / 2)] : 0;
7388
+ const latHotAt = Math.max(2e3, latMed * 2.5);
7389
+ const backingOff = Date.now() < pausedUntil.current;
7411
7390
  const chartH = rows >= 36 ? 6 : 4;
7412
7391
  const colH = rows >= 32 ? 7 : 5;
7413
7392
  const streamRows = Math.max(4, rows - 5 - (1 + chartH) - colH);
@@ -7415,14 +7394,25 @@ function LivePanel({ active: active2 }) {
7415
7394
  const leftW = Math.floor(innerW * 0.55);
7416
7395
  const rightW = innerW - leftW - 2;
7417
7396
  const colW = Math.max(20, Math.floor((innerW - 4) / 3));
7418
- const pickable = combinedSess.slice(0, colH - 1);
7419
7397
  const maxScroll = Math.max(0, visibleDesc.length - streamRows);
7420
7398
  const clampedScroll = Math.min(scroll, maxScroll);
7421
7399
  const windowed = visibleDesc.slice(clampedScroll, clampedScroll + streamRows);
7422
- const detailEntries = detail ? (() => {
7400
+ const selIdx = Math.min(pickIdx, Math.max(0, combinedSess.length - 1));
7401
+ const selected = combinedSess[selIdx];
7402
+ useEffect2(() => {
7403
+ if (mode !== "sessions" || !selected?.id) return;
7404
+ setTlScroll(0);
7405
+ const t = setTimeout(() => {
7406
+ api.audit.list({ session_id: selected.id, limit: 100 }).then((r) => {
7407
+ if (!frozenRef.current) setDetailCloud(r.entries.map(cloudItem));
7408
+ }).catch(() => setDetailCloud([]));
7409
+ }, 400);
7410
+ return () => clearTimeout(t);
7411
+ }, [mode, selected?.id]);
7412
+ const detailEntries = selected ? (() => {
7423
7413
  const seen = /* @__PURE__ */ new Set();
7424
7414
  const all = [];
7425
- for (const e of [...detailCloud, ...mergedAll.filter((x) => x.session === detail.id)]) {
7415
+ for (const e of [...detailCloud, ...mergedAll.filter((x) => x.session === selected.id)]) {
7426
7416
  const key = `${e.at}:${e.tool}:${e.decision}`;
7427
7417
  if (seen.has(key)) continue;
7428
7418
  seen.add(key);
@@ -7432,63 +7422,37 @@ function LivePanel({ active: active2 }) {
7432
7422
  })() : [];
7433
7423
  useInput(
7434
7424
  (input, key) => {
7435
- if (mode === "detail") {
7436
- const maxD = Math.max(0, detailEntries.length - (rows - 10));
7437
- if (key.leftArrow) {
7438
- setMode("stream");
7439
- setDetail(null);
7440
- } else if (key.upArrow) setDetailScroll((n) => Math.max(0, n - 1));
7441
- else if (key.downArrow) setDetailScroll((n) => Math.min(maxD, n + 1));
7442
- else if (key.pageUp) setDetailScroll((n) => Math.max(0, n - 10));
7443
- else if (key.pageDown) setDetailScroll((n) => Math.min(maxD, n + 10));
7444
- return;
7445
- }
7446
- if (mode === "pick") {
7447
- if (key.upArrow) setPickIdx((n) => Math.max(0, n - 1));
7448
- else if (key.downArrow) setPickIdx((n) => Math.min(pickable.length - 1, n + 1));
7449
- else if (key.return) {
7450
- const row = pickable[pickIdx];
7451
- if (row) {
7452
- setDetail(row);
7453
- setMode("detail");
7454
- }
7455
- } else if (input === "s" || key.leftArrow) setMode("stream");
7456
- return;
7457
- }
7458
7425
  if (input === " ") {
7459
7426
  setFrozen((f) => !f);
7460
7427
  return;
7461
7428
  }
7462
7429
  if (frozen) return;
7430
+ if (mode === "sessions") {
7431
+ if (key.leftArrow) {
7432
+ setMode("stream");
7433
+ setDetailCloud([]);
7434
+ } else if (key.upArrow) setPickIdx((n) => Math.max(0, n - 1));
7435
+ else if (key.downArrow) setPickIdx((n) => Math.min(combinedSess.length - 1, n + 1));
7436
+ else if (input === "f") {
7437
+ setSessFilter((f) => SESS_FILTERS[(SESS_FILTERS.indexOf(f) + 1) % SESS_FILTERS.length]);
7438
+ setPickIdx(0);
7439
+ } else if (key.pageUp) setTlScroll((n) => Math.max(0, n - 10));
7440
+ else if (key.pageDown) setTlScroll((n) => n + 10);
7441
+ return;
7442
+ }
7463
7443
  if (input === "f") {
7464
7444
  setFilter((f) => FILTERS[(FILTERS.indexOf(f) + 1) % FILTERS.length]);
7465
7445
  setScroll(0);
7466
7446
  } else if (input === "s") {
7467
7447
  setPickIdx(0);
7468
- setMode("pick");
7448
+ setMode("sessions");
7469
7449
  } else if (key.downArrow) setScroll((n) => Math.min(maxScroll, n + 1));
7470
7450
  else if (key.upArrow) setScroll((n) => Math.max(0, n - 1));
7471
7451
  else if (key.pageDown) setScroll((n) => Math.min(maxScroll, n + streamRows));
7472
7452
  else if (key.pageUp) setScroll((n) => Math.max(0, n - streamRows));
7473
- else if (input === "c") {
7474
- const dump = visibleDesc.map(
7475
- (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}`
7476
- ).join("\n");
7477
- try {
7478
- mkdirSync3(dirname(DUMP), { recursive: true });
7479
- writeFileSync3(DUMP, dump + "\n");
7480
- } catch {
7481
- }
7482
- const via = copyToClipboard(dump);
7483
- setToast(
7484
- via ? { msg: `\u2713 ${visibleDesc.length} lines in clipboard (${via})`, until: Date.now() + 4e3 } : { msg: "\u2717 no clipboard tool \u2014 install wl-clipboard or xclip", until: Date.now() + 6e3 }
7485
- );
7486
- }
7487
7453
  },
7488
7454
  { isActive: active2 }
7489
7455
  );
7490
- const sessionDot = (st) => st === "active" ? { ch: "\u25CF", color: theme.ok } : st === "idle" ? { ch: "\u25CC", color: theme.warn } : { ch: "\u25CB", color: theme.dim };
7491
- void sessionDot;
7492
7456
  if (s === null && localOn === null) {
7493
7457
  return /* @__PURE__ */ jsxs2(Text2, { color: theme.dim, children: [
7494
7458
  spin,
@@ -7498,72 +7462,91 @@ function LivePanel({ active: active2 }) {
7498
7462
  const titleBar = /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
7499
7463
  /* @__PURE__ */ jsx2(Text2, { backgroundColor: "#1432A0", color: "#AAC8FA", bold: true, children: " SOLONGATE LIVE " }),
7500
7464
  /* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", children: ` ${spin} up ${fmtUp(nowMs - startRef.current)} \xB7 ${hhmmss(nowMs)} \xB7 api ${latNow}ms ` }),
7501
- frozen ? /* @__PURE__ */ jsx2(Text2, { backgroundColor: "#123d1f", color: "#7bd88f", bold: true, children: " \u23F5 COPY MODE \u2014 screen frozen, select & copy freely \xB7 space resume " }) : 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 " }),
7502
- toast && nowMs < toast.until ? /* @__PURE__ */ jsx2(Text2, { backgroundColor: "#123d1f", color: "#7bd88f", bold: true, children: ` ${toast.msg} ` }) : null
7465
+ frozen ? /* @__PURE__ */ jsx2(Text2, { backgroundColor: "#123d1f", color: "#7bd88f", bold: true, children: " \u23F5 COPY MODE \u2014 screen frozen, select & copy freely \xB7 space resume " }) : 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 " })
7503
7466
  ] });
7504
- if (mode === "detail" && detail) {
7467
+ if (mode === "sessions") {
7468
+ const listW = Math.min(44, Math.floor(innerW * 0.38));
7469
+ const detailW = innerW - listW - 2;
7470
+ const bodyH = rows - 4;
7471
+ const listRows = bodyH - 1;
7505
7472
  const d = detailEntries;
7506
7473
  const allow = d.filter((e) => e.decision === "ALLOW").length;
7507
7474
  const deny = d.length - allow;
7508
7475
  const dlpN = d.filter((e) => e.dlp).length;
7476
+ const burstN = d.filter((e) => e.burst).length;
7509
7477
  const evals = d.filter((e) => e.evalMs != null).map((e) => e.evalMs);
7510
7478
  const evalAvg = evals.length ? Math.round(evals.reduce((a, b) => a + b, 0) / evals.length) : null;
7511
7479
  const tCounts = /* @__PURE__ */ new Map();
7512
- const pCounts = /* @__PURE__ */ new Map();
7513
- for (const e of d) {
7514
- tCounts.set(e.tool, (tCounts.get(e.tool) ?? 0) + 1);
7515
- if (e.permission) pCounts.set(e.permission, (pCounts.get(e.permission) ?? 0) + 1);
7516
- }
7517
- const top = [...tCounts.entries()].sort((a, b) => b[1] - a[1]).slice(0, 6);
7518
- const perms = [...pCounts.entries()].sort((a, b) => b[1] - a[1]);
7480
+ for (const e of d) tCounts.set(e.tool, (tCounts.get(e.tool) ?? 0) + 1);
7481
+ const top = [...tCounts.entries()].sort((a, b) => b[1] - a[1]).slice(0, 5);
7519
7482
  const first = d[d.length - 1]?.at;
7520
7483
  const last = d[0]?.at;
7521
- const tlRows = Math.max(4, rows - 10);
7522
- const maxD = Math.max(0, d.length - tlRows);
7523
- const dScroll = Math.min(detailScroll, maxD);
7524
- const tl = d.slice(dScroll, dScroll + tlRows);
7484
+ const tlRows = Math.max(3, bodyH - 8);
7485
+ const maxTl = Math.max(0, d.length - tlRows);
7486
+ const tScroll = Math.min(tlScroll, maxTl);
7487
+ const tl = d.slice(tScroll, tScroll + tlRows);
7525
7488
  return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", paddingX: 1, children: [
7526
7489
  titleBar,
7527
- /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
7528
- /* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#AAC8FA", bold: true, children: ` SESSION ${detail.id.slice(0, 8)} ` }),
7529
- /* @__PURE__ */ jsx2(Text2, { color: detail.source === "local" ? theme.ok : "#4f6db8", children: " " + detail.source.toUpperCase() }),
7530
- /* @__PURE__ */ jsx2(Text2, { bold: true, children: " " + truncate2(detail.isMe ? detail.agent + " (this machine)" : detail.agent, 34) }),
7531
- detail.trust != null ? /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: ` trust ${detail.trust}/100` }) : null,
7532
- /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2190 back" })
7533
- ] }),
7534
- /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
7535
- /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "\u2502 calls " }),
7536
- /* @__PURE__ */ jsx2(Text2, { bold: true, children: d.length }),
7537
- /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502 allow " }),
7538
- /* @__PURE__ */ jsx2(Text2, { color: theme.ok, children: allow }),
7539
- /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502 deny " }),
7540
- /* @__PURE__ */ jsx2(Text2, { color: deny ? theme.bad : theme.dim, bold: deny > 0, children: deny }),
7541
- /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502 dlp " }),
7542
- /* @__PURE__ */ jsx2(Text2, { color: dlpN ? theme.bad : theme.dim, children: dlpN }),
7543
- /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502 avg eval " }),
7544
- /* @__PURE__ */ jsx2(Text2, { children: evalAvg != null ? `${evalAvg}ms` : "\u2014" }),
7545
- /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502 first " }),
7546
- /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: first ? `${hhmmss(first)} (${ago(first)} ago)` : "\u2014" }),
7547
- /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502 last " }),
7548
- /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: last ? `${hhmmss(last)} (${ago(last)} ago)` : "\u2014" }),
7549
- /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502" })
7550
- ] }),
7551
- /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
7552
- /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "\u2502 tools " }),
7553
- /* @__PURE__ */ jsx2(Text2, { color: theme.accent, children: top.map(([t, c2]) => `${t}\xD7${c2}`).join(" ") || "\u2014" }),
7554
- /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502 perms " }),
7555
- /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: perms.map(([p, c2]) => `${p}\xD7${c2}`).join(" ") || "\u2014" }),
7556
- /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502" })
7557
- ] }),
7558
- /* @__PURE__ */ jsx2(PaneTitle, { label: "TIMELINE", extra: `${d.length} calls \xB7 newest first${dScroll ? ` \xB7 \u25BC${dScroll} older` : ""} \xB7 \u2191\u2193 scroll \xB7 \u2190 back`, width: innerW }),
7559
- /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", height: tlRows, overflow: "hidden", children: [
7560
- tl.length === 0 ? /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: detailCloud.length === 0 ? spin + " loading history\u2026" : "no entries" }) : null,
7561
- tl.map((e) => /* @__PURE__ */ jsx2(StreamLine, { e, loc: isLoc(e) }, e.id))
7490
+ /* @__PURE__ */ jsx2(PaneTitle, { label: "SESSIONS", extra: `${combinedSess.length} shown \xB7 filter ${sessFilter} (f) \xB7 \u2191\u2193 select \xB7 PgUp/Dn timeline \xB7 \u2190 back`, width: innerW }),
7491
+ /* @__PURE__ */ jsxs2(Box2, { height: bodyH, children: [
7492
+ /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", width: listW, marginRight: 2, overflow: "hidden", children: [
7493
+ combinedSess.length === 0 ? /* @__PURE__ */ jsxs2(Text2, { color: theme.dim, children: [
7494
+ "no sessions",
7495
+ sessFilter !== "all" ? ` (${sessFilter})` : ""
7496
+ ] }) : null,
7497
+ combinedSess.slice(0, listRows).map((r, i) => {
7498
+ const st = sessStatus(r.lastAt, nowMs);
7499
+ const dot = st === "active" ? { ch: "\u25CF", color: theme.ok } : st === "idle" ? { ch: "\u25CC", color: theme.warn } : { ch: "\u25CB", color: theme.dim };
7500
+ const sel = i === selIdx;
7501
+ return /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", backgroundColor: sel ? "#1c2f63" : void 0, bold: sel, children: [
7502
+ /* @__PURE__ */ jsxs2(Text2, { color: sel ? theme.accentBright : dot.color, children: [
7503
+ sel ? "\u25B8" : dot.ch,
7504
+ " "
7505
+ ] }),
7506
+ /* @__PURE__ */ jsx2(Text2, { color: r.source === "local" ? theme.ok : "#4f6db8", children: r.source === "local" ? "LOC " : "CLD " }),
7507
+ /* @__PURE__ */ jsx2(Text2, { color: theme.accentBright, children: truncate2(r.isMe ? "this machine" : r.agent, 13).padEnd(14) }),
7508
+ /* @__PURE__ */ jsxs2(Text2, { children: [
7509
+ String(r.calls).padStart(4),
7510
+ "c "
7511
+ ] }),
7512
+ /* @__PURE__ */ jsxs2(Text2, { color: r.denies ? theme.bad : theme.dim, children: [
7513
+ String(r.denies).padStart(3),
7514
+ "d "
7515
+ ] }),
7516
+ /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: ago(r.lastAt) })
7517
+ ] }, r.id);
7518
+ })
7519
+ ] }),
7520
+ /* @__PURE__ */ jsx2(Box2, { flexDirection: "column", width: detailW, overflow: "hidden", children: !selected ? /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "select a session to see its run timeline" }) : /* @__PURE__ */ jsxs2(Fragment2, { children: [
7521
+ /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
7522
+ /* @__PURE__ */ jsx2(Text2, { color: sessStatus(selected.lastAt, nowMs) === "active" ? theme.ok : theme.dim, children: sessStatus(selected.lastAt, nowMs) === "active" ? "\u25CF " : "\u25CB " }),
7523
+ /* @__PURE__ */ jsx2(Text2, { bold: true, children: truncate2(selected.isMe ? selected.agent + " (this machine)" : selected.agent, 30) }),
7524
+ /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " " + selected.id })
7525
+ ] }),
7526
+ /* @__PURE__ */ jsxs2(Box2, { marginTop: 1, children: [
7527
+ /* @__PURE__ */ jsx2(Stat, { label: "Total", value: d.length }),
7528
+ /* @__PURE__ */ jsx2(Stat, { label: "Allowed", value: allow, color: theme.ok }),
7529
+ /* @__PURE__ */ jsx2(Stat, { label: "Denied", value: deny, color: deny ? theme.bad : void 0 }),
7530
+ /* @__PURE__ */ jsx2(Stat, { label: "DLP", value: dlpN, color: dlpN ? theme.bad : void 0 }),
7531
+ /* @__PURE__ */ jsx2(Stat, { label: "Rate limit", value: burstN, color: burstN ? theme.warn : void 0 }),
7532
+ /* @__PURE__ */ jsx2(Stat, { label: "Avg eval", value: evalAvg != null ? `${evalAvg}ms` : "\u2014" }),
7533
+ selected.trust != null ? /* @__PURE__ */ jsx2(Stat, { label: "Trust", value: `${selected.trust}/100`, color: theme.accent }) : null
7534
+ ] }),
7535
+ /* @__PURE__ */ jsx2(Text2, { wrap: "truncate", color: theme.dim, children: `first ${first ? `${hhmmss(first)} (${ago(first)} ago)` : "\u2014"} \xB7 last ${last ? `${hhmmss(last)} (${ago(last)} ago)` : "\u2014"} \xB7 tools ${top.map(([t, c2]) => `${t}\xD7${c2}`).join(" ") || "\u2014"}` }),
7536
+ /* @__PURE__ */ jsx2(PaneTitle, { label: "TIMELINE", extra: `${d.length} events \xB7 newest first${tScroll ? ` \xB7 \u25BC${tScroll}` : ""}`, width: detailW }),
7537
+ /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", overflow: "hidden", flexGrow: 1, children: [
7538
+ tl.length === 0 ? /* @__PURE__ */ jsxs2(Text2, { color: theme.dim, children: [
7539
+ spin,
7540
+ " loading history\u2026"
7541
+ ] }) : null,
7542
+ tl.map((e) => /* @__PURE__ */ jsx2(StreamLine, { e, loc: isLoc(e) }, e.id))
7543
+ ] })
7544
+ ] }) })
7562
7545
  ] }),
7563
7546
  /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
7564
- /* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", bold: true, children: " SESSION " }),
7565
- /* @__PURE__ */ jsx2(Text2, { backgroundColor: "#0b1530", color: "#4f6db8", children: ` ${detail.id} ` }),
7566
- /* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", children: " \u2191\u2193 scroll \xB7 \u2190 back \xB7 esc menu " })
7547
+ /* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", bold: true, children: " SESSIONS " }),
7548
+ /* @__PURE__ */ jsx2(Text2, { backgroundColor: "#0b1530", color: "#4f6db8", children: ` ${combinedSess.length} sessions \xB7 space copy-mode ` }),
7549
+ /* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", children: " \u2191\u2193 select \xB7 f status \xB7 \u2190 back \xB7 esc menu " })
7567
7550
  ] })
7568
7551
  ] });
7569
7552
  }
@@ -7585,7 +7568,7 @@ function LivePanel({ active: active2 }) {
7585
7568
  /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502 ghost " }),
7586
7569
  /* @__PURE__ */ jsx2(Text2, { color: gh?.mode === "on" ? theme.ok : theme.dim, children: gh?.mode ?? "?" }),
7587
7570
  /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502 sess " }),
7588
- /* @__PURE__ */ jsx2(Text2, { color: theme.accent, children: `${combinedSess.length} (${sessCounts?.active ?? 0} live)` }),
7571
+ /* @__PURE__ */ jsx2(Text2, { color: theme.accent, children: String(combinedSessAll.length) }),
7589
7572
  /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502 hooks " }),
7590
7573
  /* @__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" }),
7591
7574
  /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502" })
@@ -7624,14 +7607,13 @@ function LivePanel({ active: active2 }) {
7624
7607
  ] })
7625
7608
  ] }),
7626
7609
  /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", width: colW, marginRight: 2, overflow: "hidden", children: [
7627
- /* @__PURE__ */ jsx2(PaneTitle, { label: "SESSIONS", extra: mode === "pick" ? "\u2191\u2193 pick \xB7 enter open" : `${combinedSess.length} \xB7 s = inspect`, width: colW }),
7628
- pickable.length === 0 ? /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "scanning\u2026" }) : null,
7629
- pickable.map((r, i) => {
7630
- const freshDot = nowMs - r.lastAt < 9e4;
7631
- const sel = mode === "pick" && i === pickIdx;
7632
- return /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", backgroundColor: sel ? "#1c2f63" : void 0, bold: sel || r.isMe, children: [
7633
- /* @__PURE__ */ jsxs2(Text2, { color: sel ? theme.accentBright : freshDot ? theme.ok : theme.dim, children: [
7634
- sel ? "\u25B8" : freshDot ? "\u25CF" : "\u25CB",
7610
+ /* @__PURE__ */ jsx2(PaneTitle, { label: "SESSIONS", extra: "press s to inspect", width: colW }),
7611
+ combinedSessAll.slice(0, colH - 1).map((r) => {
7612
+ const st = sessStatus(r.lastAt, nowMs);
7613
+ const dot = st === "active" ? { ch: "\u25CF", color: theme.ok } : st === "idle" ? { ch: "\u25CC", color: theme.warn } : { ch: "\u25CB", color: theme.dim };
7614
+ return /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", bold: r.isMe, children: [
7615
+ /* @__PURE__ */ jsxs2(Text2, { color: dot.color, children: [
7616
+ dot.ch,
7635
7617
  " "
7636
7618
  ] }),
7637
7619
  /* @__PURE__ */ jsx2(Text2, { color: r.source === "local" ? theme.ok : "#4f6db8", children: r.source === "local" ? "LOC " : "CLD " }),
@@ -7644,7 +7626,7 @@ function LivePanel({ active: active2 }) {
7644
7626
  String(r.denies).padStart(3),
7645
7627
  "d "
7646
7628
  ] }),
7647
- /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: (r.trust != null ? `t${r.trust} ` : "") + ago(r.lastAt) })
7629
+ /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: ago(r.lastAt) })
7648
7630
  ] }, r.id);
7649
7631
  })
7650
7632
  ] }),
@@ -7664,7 +7646,7 @@ function LivePanel({ active: active2 }) {
7664
7646
  PaneTitle,
7665
7647
  {
7666
7648
  label: "TOOL STREAM",
7667
- extra: `newest first \xB7 last ${STREAM_KEEP} \xB7 filter ${filter}${clampedScroll > 0 ? ` \xB7 \u25BC${clampedScroll} older` : ""} \xB7 f filter \xB7 \u2191\u2193 scroll \xB7 c copy \xB7 s sessions`,
7649
+ extra: `newest first \xB7 last ${STREAM_KEEP} \xB7 filter ${filter}${clampedScroll > 0 ? ` \xB7 \u25BC${clampedScroll} older` : ""} \xB7 f filter \xB7 \u2191\u2193 scroll \xB7 s sessions`,
7668
7650
  width: innerW
7669
7651
  }
7670
7652
  ),
@@ -7681,12 +7663,12 @@ function LivePanel({ active: active2 }) {
7681
7663
  ] }),
7682
7664
  /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
7683
7665
  /* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", bold: true, children: " LIVE " }),
7684
- /* @__PURE__ */ jsx2(Text2, { backgroundColor: "#0b1530", color: "#4f6db8", children: ` local ${localOn ? "on" : "off"} \xB7 ${localBuf.length} loc/${cloudBuf.length} cld \xB7 top ${topTools.map(([t, c2]) => `${t}\xD7${c2}`).join(" ") || "\u2014"} ` }),
7685
- /* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", children: " space copy-mode \xB7 f filter \xB7 s sessions \xB7 c quick-copy \xB7 esc menu \xB7 q quit " })
7666
+ /* @__PURE__ */ jsx2(Text2, { backgroundColor: "#0b1530", color: "#4f6db8", children: ` local ${localOn ? "on" : "off"} \xB7 ${localBuf.length} loc/${cloudDeduped.length} cld \xB7 top ${topTools.map(([t, c2]) => `${t}\xD7${c2}`).join(" ") || "\u2014"} ` }),
7667
+ /* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", children: " space copy-mode \xB7 f filter \xB7 s sessions \xB7 esc menu \xB7 q quit " })
7686
7668
  ] })
7687
7669
  ] });
7688
7670
  }
7689
- var SPIN, BG, DIM_FLOOR, LOCAL_LOG, RING, DUMP, STREAM_KEEP, hhmmss, fmtUp, FILTERS;
7671
+ var SPIN, BG, DIM_FLOOR, LOCAL_LOG, RING, STREAM_KEEP, hhmmss, fmtUp, FILTERS, SESS_FILTERS, sessStatus;
7690
7672
  var init_Live = __esm({
7691
7673
  "src/tui/panels/Live.tsx"() {
7692
7674
  "use strict";
@@ -7698,7 +7680,6 @@ var init_Live = __esm({
7698
7680
  DIM_FLOOR = "#233457";
7699
7681
  LOCAL_LOG = join5(homedir3(), ".solongate", "local-logs", "solongate-audit.jsonl");
7700
7682
  RING = join5(process.cwd(), ".solongate", ".eval-ring.jsonl");
7701
- DUMP = join5(homedir3(), ".solongate", "live-stream.log");
7702
7683
  STREAM_KEEP = 100;
7703
7684
  hhmmss = (ts) => {
7704
7685
  const d = new Date(ts);
@@ -7710,6 +7691,8 @@ var init_Live = __esm({
7710
7691
  return `${p(Math.floor(s / 3600))}:${p(Math.floor(s % 3600 / 60))}:${p(s % 60)}`;
7711
7692
  };
7712
7693
  FILTERS = ["all", "local", "cloud"];
7694
+ SESS_FILTERS = ["all", "active", "idle", "ended"];
7695
+ sessStatus = (lastAt, now) => now - lastAt < 9e4 ? "active" : now - lastAt < 3e5 ? "idle" : "ended";
7713
7696
  }
7714
7697
  });
7715
7698
 
@@ -9371,8 +9354,8 @@ __export(global_install_exports, {
9371
9354
  runGlobalRestore: () => runGlobalRestore,
9372
9355
  unlockProtected: () => unlockProtected
9373
9356
  });
9374
- import { readFileSync as readFileSync6, writeFileSync as writeFileSync4, existsSync as existsSync4, mkdirSync as mkdirSync4 } from "fs";
9375
- import { resolve as resolve4, join as join6, dirname as dirname2 } from "path";
9357
+ import { readFileSync as readFileSync6, writeFileSync as writeFileSync3, existsSync as existsSync4, mkdirSync as mkdirSync3 } from "fs";
9358
+ import { resolve as resolve4, join as join6, dirname } from "path";
9376
9359
  import { homedir as homedir4 } from "os";
9377
9360
  import { fileURLToPath } from "url";
9378
9361
  import { createInterface } from "readline";
@@ -9484,13 +9467,13 @@ function runGlobalRestore() {
9484
9467
  unlockProtected();
9485
9468
  removeClaudeShim();
9486
9469
  if (existsSync4(p.backupPath)) {
9487
- writeFileSync4(p.settingsPath, readFileSync6(p.backupPath, "utf-8"));
9470
+ writeFileSync3(p.settingsPath, readFileSync6(p.backupPath, "utf-8"));
9488
9471
  console.log(` Restored ${p.settingsPath} from backup.`);
9489
9472
  } else if (existsSync4(p.settingsPath)) {
9490
9473
  try {
9491
9474
  const s = JSON.parse(readFileSync6(p.settingsPath, "utf-8"));
9492
9475
  delete s.hooks;
9493
- writeFileSync4(p.settingsPath, JSON.stringify(s, null, 2) + "\n");
9476
+ writeFileSync3(p.settingsPath, JSON.stringify(s, null, 2) + "\n");
9494
9477
  console.log(` Removed SolonGate hooks from ${p.settingsPath}.`);
9495
9478
  } catch {
9496
9479
  }
@@ -9534,8 +9517,8 @@ function writeShimBlock(file, block) {
9534
9517
  if (content.length && !content.endsWith("\n")) content += "\n";
9535
9518
  content += block + "\n";
9536
9519
  }
9537
- mkdirSync4(dirname2(file), { recursive: true });
9538
- writeFileSync4(file, content);
9520
+ mkdirSync3(dirname(file), { recursive: true });
9521
+ writeFileSync3(file, content);
9539
9522
  }
9540
9523
  function installClaudeShim(shieldPath) {
9541
9524
  const real = resolveRealClaude();
@@ -9592,22 +9575,22 @@ async function runGlobalInstall(opts = {}) {
9592
9575
  process.exit(1);
9593
9576
  }
9594
9577
  const apiUrl = opts.apiUrl || process.env["SOLONGATE_API_URL"] || "https://api.solongate.com";
9595
- mkdirSync4(p.hooksDir, { recursive: true });
9596
- mkdirSync4(p.claudeDir, { recursive: true });
9578
+ mkdirSync3(p.hooksDir, { recursive: true });
9579
+ mkdirSync3(p.claudeDir, { recursive: true });
9597
9580
  unlockProtected();
9598
- writeFileSync4(join6(p.hooksDir, "guard.mjs"), readGuard());
9599
- writeFileSync4(join6(p.hooksDir, "audit.mjs"), readHook("audit.mjs"));
9600
- writeFileSync4(join6(p.hooksDir, "stop.mjs"), readHook("stop.mjs"));
9601
- writeFileSync4(join6(p.hooksDir, "shield.mjs"), readHook("shield.mjs"));
9581
+ writeFileSync3(join6(p.hooksDir, "guard.mjs"), readGuard());
9582
+ writeFileSync3(join6(p.hooksDir, "audit.mjs"), readHook("audit.mjs"));
9583
+ writeFileSync3(join6(p.hooksDir, "stop.mjs"), readHook("stop.mjs"));
9584
+ writeFileSync3(join6(p.hooksDir, "shield.mjs"), readHook("shield.mjs"));
9602
9585
  console.log(` Installed hooks \u2192 ${p.hooksDir}`);
9603
9586
  removeClaudeShim();
9604
- writeFileSync4(p.configPath, JSON.stringify({ apiKey, apiUrl }, null, 2) + "\n");
9587
+ writeFileSync3(p.configPath, JSON.stringify({ apiKey, apiUrl }, null, 2) + "\n");
9605
9588
  console.log(` Wrote ${p.configPath}`);
9606
9589
  let existing = {};
9607
9590
  if (existsSync4(p.settingsPath)) {
9608
9591
  const raw = readFileSync6(p.settingsPath, "utf-8");
9609
9592
  if (!existsSync4(p.backupPath)) {
9610
- writeFileSync4(p.backupPath, raw);
9593
+ writeFileSync3(p.backupPath, raw);
9611
9594
  console.log(` Backed up existing settings \u2192 ${p.backupPath}`);
9612
9595
  }
9613
9596
  try {
@@ -9628,7 +9611,7 @@ async function runGlobalInstall(opts = {}) {
9628
9611
  Stop: [{ matcher: "", hooks: [{ type: "command", command: `"${nodeBin}" "${stopAbs}" claude-code "Claude Code"` }] }]
9629
9612
  }
9630
9613
  };
9631
- writeFileSync4(p.settingsPath, JSON.stringify(merged, null, 2) + "\n");
9614
+ writeFileSync3(p.settingsPath, JSON.stringify(merged, null, 2) + "\n");
9632
9615
  console.log(` Registered global hooks \u2192 ${p.settingsPath}`);
9633
9616
  if (process.env["SOLONGATE_OS_LOCK"] === "1") {
9634
9617
  lockProtected();
@@ -9642,7 +9625,7 @@ var __dirname, HOOKS_DIR, SHIM_BEGIN, SHIM_END;
9642
9625
  var init_global_install = __esm({
9643
9626
  "src/global-install.ts"() {
9644
9627
  "use strict";
9645
- __dirname = dirname2(fileURLToPath(import.meta.url));
9628
+ __dirname = dirname(fileURLToPath(import.meta.url));
9646
9629
  HOOKS_DIR = resolve4(__dirname, "..", "hooks");
9647
9630
  SHIM_BEGIN = "# >>> SolonGate shield (auto secret redaction) >>>";
9648
9631
  SHIM_END = "# <<< SolonGate shield <<<";
@@ -10292,7 +10275,7 @@ var init_logs_server = __esm({
10292
10275
 
10293
10276
  // src/inject.ts
10294
10277
  var inject_exports = {};
10295
- import { readFileSync as readFileSync9, writeFileSync as writeFileSync5, existsSync as existsSync6, copyFileSync } from "fs";
10278
+ import { readFileSync as readFileSync9, writeFileSync as writeFileSync4, existsSync as existsSync6, copyFileSync } from "fs";
10296
10279
  import { resolve as resolve7 } from "path";
10297
10280
  import { execSync } from "child_process";
10298
10281
  function parseInjectArgs(argv) {
@@ -10600,7 +10583,7 @@ async function main2() {
10600
10583
  log3("");
10601
10584
  log3(` Backup: ${backupPath}`);
10602
10585
  }
10603
- writeFileSync5(entryFile, result.modified);
10586
+ writeFileSync4(entryFile, result.modified);
10604
10587
  log3("");
10605
10588
  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");
10606
10589
  log3(" \u2502 SolonGate SDK injected successfully! \u2502");
@@ -10629,7 +10612,7 @@ var init_inject = __esm({
10629
10612
 
10630
10613
  // src/create.ts
10631
10614
  var create_exports = {};
10632
- import { mkdirSync as mkdirSync5, writeFileSync as writeFileSync6, existsSync as existsSync7 } from "fs";
10615
+ import { mkdirSync as mkdirSync4, writeFileSync as writeFileSync5, existsSync as existsSync7 } from "fs";
10633
10616
  import { resolve as resolve8, join as join8 } from "path";
10634
10617
  import { execSync as execSync2 } from "child_process";
10635
10618
  function withSpinner(message, fn) {
@@ -10709,7 +10692,7 @@ EXAMPLES
10709
10692
  `);
10710
10693
  }
10711
10694
  function createProject(dir, name, _policy) {
10712
- writeFileSync6(
10695
+ writeFileSync5(
10713
10696
  join8(dir, "package.json"),
10714
10697
  JSON.stringify(
10715
10698
  {
@@ -10739,7 +10722,7 @@ function createProject(dir, name, _policy) {
10739
10722
  2
10740
10723
  ) + "\n"
10741
10724
  );
10742
- writeFileSync6(
10725
+ writeFileSync5(
10743
10726
  join8(dir, "tsconfig.json"),
10744
10727
  JSON.stringify(
10745
10728
  {
@@ -10760,8 +10743,8 @@ function createProject(dir, name, _policy) {
10760
10743
  2
10761
10744
  ) + "\n"
10762
10745
  );
10763
- mkdirSync5(join8(dir, "src"), { recursive: true });
10764
- writeFileSync6(
10746
+ mkdirSync4(join8(dir, "src"), { recursive: true });
10747
+ writeFileSync5(
10765
10748
  join8(dir, "src", "index.ts"),
10766
10749
  `#!/usr/bin/env node
10767
10750
 
@@ -10803,7 +10786,7 @@ console.log('');
10803
10786
  console.log('Press Ctrl+C to stop.');
10804
10787
  `
10805
10788
  );
10806
- writeFileSync6(
10789
+ writeFileSync5(
10807
10790
  join8(dir, ".mcp.json"),
10808
10791
  JSON.stringify(
10809
10792
  {
@@ -10821,12 +10804,12 @@ console.log('Press Ctrl+C to stop.');
10821
10804
  2
10822
10805
  ) + "\n"
10823
10806
  );
10824
- writeFileSync6(
10807
+ writeFileSync5(
10825
10808
  join8(dir, ".env"),
10826
10809
  `SOLONGATE_API_KEY=sg_live_YOUR_KEY_HERE
10827
10810
  `
10828
10811
  );
10829
- writeFileSync6(
10812
+ writeFileSync5(
10830
10813
  join8(dir, ".gitignore"),
10831
10814
  `node_modules/
10832
10815
  dist/
@@ -10846,7 +10829,7 @@ async function main3() {
10846
10829
  process.exit(1);
10847
10830
  }
10848
10831
  withSpinner(`Setting up ${opts.name}...`, () => {
10849
- mkdirSync5(dir, { recursive: true });
10832
+ mkdirSync4(dir, { recursive: true });
10850
10833
  createProject(dir, opts.name, opts.policy);
10851
10834
  });
10852
10835
  if (!opts.noInstall) {
@@ -10920,7 +10903,7 @@ var init_create = __esm({
10920
10903
 
10921
10904
  // src/pull-push.ts
10922
10905
  var pull_push_exports = {};
10923
- import { readFileSync as readFileSync10, writeFileSync as writeFileSync7, existsSync as existsSync8 } from "fs";
10906
+ import { readFileSync as readFileSync10, writeFileSync as writeFileSync6, existsSync as existsSync8 } from "fs";
10924
10907
  import { resolve as resolve9 } from "path";
10925
10908
  function loadEnv() {
10926
10909
  if (process.env.SOLONGATE_API_KEY) return;
@@ -11115,7 +11098,7 @@ async function pull(apiKey, file, policyId) {
11115
11098
  const policy = await fetchCloudPolicy(apiKey, API_URL, policyId);
11116
11099
  const { id: _id, ...policyWithoutId } = policy;
11117
11100
  const json = JSON.stringify(policyWithoutId, null, 2) + "\n";
11118
- writeFileSync7(file, json, "utf-8");
11101
+ writeFileSync6(file, json, "utf-8");
11119
11102
  log5("");
11120
11103
  log5(green2(" Saved to: ") + file);
11121
11104
  log5(` ${dim2("Name:")} ${policy.name}`);