@solongate/proxy 0.68.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 +175 -118
- package/dist/tui/index.js +145 -88
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -7020,12 +7020,12 @@ var init_hooks = __esm({
|
|
|
7020
7020
|
|
|
7021
7021
|
// src/tui/panels/Live.tsx
|
|
7022
7022
|
import { Box as Box2, Text as Text2, useInput } from "ink";
|
|
7023
|
-
import { closeSync, openSync, readSync, statSync } from "fs";
|
|
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 =
|
|
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 ?
|
|
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:
|
|
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,18 +7116,12 @@ 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);
|
|
7115
|
-
const [frozen, setFrozen] = useState2(false);
|
|
7116
|
-
const frozenRef = useRef2(false);
|
|
7117
|
-
frozenRef.current = frozen;
|
|
7118
|
-
useInput(
|
|
7119
|
-
(input) => {
|
|
7120
|
-
if (input === "p") setFrozen((f) => !f);
|
|
7121
|
-
},
|
|
7122
|
-
{ isActive: active2 }
|
|
7123
|
-
);
|
|
7124
7125
|
const pushLog = useCallback2((msg, level = "ok") => {
|
|
7125
7126
|
setLog((prev) => [...prev.slice(-59), { ts: Date.now(), msg, level }]);
|
|
7126
7127
|
}, []);
|
|
@@ -7136,9 +7137,8 @@ function LivePanel({ active: active2 }) {
|
|
|
7136
7137
|
},
|
|
7137
7138
|
[pushLog]
|
|
7138
7139
|
);
|
|
7139
|
-
const paused = () =>
|
|
7140
|
+
const paused = () => Date.now() < pausedUntil.current;
|
|
7140
7141
|
const pollLocal = useCallback2(() => {
|
|
7141
|
-
if (frozenRef.current) return;
|
|
7142
7142
|
const lines = tailLines(LOCAL_LOG);
|
|
7143
7143
|
if (!lines.length) {
|
|
7144
7144
|
setLocalOn((prev) => prev === null ? false : prev);
|
|
@@ -7161,7 +7161,9 @@ function LivePanel({ active: active2 }) {
|
|
|
7161
7161
|
dlp: !!j.dlp,
|
|
7162
7162
|
source: "local",
|
|
7163
7163
|
session: j.session_id,
|
|
7164
|
-
agent: j.agent_name
|
|
7164
|
+
agent: j.agent_name,
|
|
7165
|
+
evalMs: j.evaluation_time_ms,
|
|
7166
|
+
rule: j.matched_rule_id
|
|
7165
7167
|
});
|
|
7166
7168
|
} catch {
|
|
7167
7169
|
}
|
|
@@ -7170,9 +7172,7 @@ function LivePanel({ active: active2 }) {
|
|
|
7170
7172
|
lastLocalTs.current = fresh[fresh.length - 1].at;
|
|
7171
7173
|
setLocalBuf((prev) => [...prev, ...fresh].slice(-400));
|
|
7172
7174
|
const denies = fresh.filter((f) => f.decision !== "ALLOW").length;
|
|
7173
|
-
if (
|
|
7174
|
-
pushLog(`local +${fresh.length} calls${denies ? ` \xB7 ${denies} DENIED` : ""}`, denies ? "bad" : "warn");
|
|
7175
|
-
}
|
|
7175
|
+
if (fresh.length < 10) pushLog(`local +${fresh.length} calls${denies ? ` \xB7 ${denies} DENIED` : ""}`, denies ? "bad" : "warn");
|
|
7176
7176
|
}
|
|
7177
7177
|
const ringLines = tailLines(RING, 8192).slice(-30);
|
|
7178
7178
|
if (ringLines.length) {
|
|
@@ -7209,9 +7209,7 @@ function LivePanel({ active: active2 }) {
|
|
|
7209
7209
|
const fresh = fd.entries.filter((e) => !seenRef.current.has(e.id));
|
|
7210
7210
|
const firstLoad = seenRef.current.size === 0 && fresh.length > 1;
|
|
7211
7211
|
for (const e of fresh) seenRef.current.add(e.id);
|
|
7212
|
-
if (fresh.length)
|
|
7213
|
-
setCloudBuf((prev) => [...prev, ...fresh.map(cloudItem).sort((a, b) => a.at - b.at)].slice(-400));
|
|
7214
|
-
}
|
|
7212
|
+
if (fresh.length) setCloudBuf((prev) => [...prev, ...fresh.map(cloudItem).sort((a, b) => a.at - b.at)].slice(-400));
|
|
7215
7213
|
const denies = fresh.filter((e) => e.decision !== "ALLOW").length;
|
|
7216
7214
|
if (firstLoad) pushLog(`cloud link up \xB7 api ${ms}ms \xB7 ${fresh.length} calls`);
|
|
7217
7215
|
else pushLog(`api ${ms}ms \xB7 +${fresh.length} cloud${denies ? ` \xB7 ${denies} DENIED` : ""}`, denies ? "bad" : fresh.length ? "warn" : "ok");
|
|
@@ -7251,26 +7249,32 @@ function LivePanel({ active: active2 }) {
|
|
|
7251
7249
|
}, [active2, pollFeed, pollMedium, pollSlow]);
|
|
7252
7250
|
const sessions = useLoader(() => api.agents.live({ limit: 30, includeDeactivated: true }));
|
|
7253
7251
|
const insights = useLoader(() => api.stats.securityInsights(7));
|
|
7252
|
+
const guard = useLoader(() => api.settings.getGuardStatus());
|
|
7254
7253
|
usePoll(() => {
|
|
7255
7254
|
if (!paused()) sessions.reload();
|
|
7256
7255
|
}, 1e4, active2);
|
|
7257
7256
|
usePoll(() => {
|
|
7258
7257
|
if (!paused()) insights.reload();
|
|
7259
7258
|
}, 3e4, active2);
|
|
7259
|
+
usePoll(() => {
|
|
7260
|
+
if (!paused()) guard.reload();
|
|
7261
|
+
}, 6e4, active2);
|
|
7260
7262
|
const [tick, setTick] = useState2(0);
|
|
7261
7263
|
useEffect2(() => {
|
|
7262
|
-
if (!active2
|
|
7263
|
-
const t = setInterval(() => setTick((n) => n + 1),
|
|
7264
|
+
if (!active2) return;
|
|
7265
|
+
const t = setInterval(() => setTick((n) => n + 1), 500);
|
|
7264
7266
|
return () => clearInterval(t);
|
|
7265
|
-
}, [active2
|
|
7267
|
+
}, [active2]);
|
|
7266
7268
|
const startRef = useRef2(Date.now());
|
|
7267
7269
|
const cols = process.stdout.columns ?? 100;
|
|
7268
7270
|
const rows = process.stdout.rows ?? 30;
|
|
7269
7271
|
const ins = insights.data ?? {};
|
|
7270
7272
|
const spin = SPIN[tick % SPIN.length];
|
|
7271
|
-
const points = tsData?.timeseries ?? [];
|
|
7272
|
-
const mergedAll = [...cloudBuf, ...localBuf].sort((a, b) => a.at - b.at);
|
|
7273
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);
|
|
7277
|
+
const points = tsData?.timeseries ?? [];
|
|
7274
7278
|
const minuteCounts = new Array(60).fill(0);
|
|
7275
7279
|
const minuteHot = new Array(60).fill(false);
|
|
7276
7280
|
for (const e of mergedAll) {
|
|
@@ -7286,14 +7290,14 @@ function LivePanel({ active: active2 }) {
|
|
|
7286
7290
|
const trafficLabel = localTraffic ? "calls/min \xB7 60m \xB7 local+cloud" : "24h \xB7 cloud";
|
|
7287
7291
|
const rl = ins.layers?.rateLimit;
|
|
7288
7292
|
const dl = ins.layers?.dlp;
|
|
7289
|
-
const
|
|
7293
|
+
const gh = ins.layers?.ghost;
|
|
7294
|
+
const minuteNow = minuteCounts[59] ?? 0;
|
|
7290
7295
|
const dlpBars = (ins.dlpByPattern ?? []).slice(0, 2);
|
|
7291
7296
|
const maxDlpBar = dlpBars[0]?.count ?? 1;
|
|
7292
|
-
const
|
|
7293
|
-
const denials = merged.filter((e) => e.decision !== "ALLOW");
|
|
7297
|
+
const denials = mergedAll.filter((e) => e.decision !== "ALLOW");
|
|
7294
7298
|
const lastDeny = denials[denials.length - 1];
|
|
7295
7299
|
const toolCounts = /* @__PURE__ */ new Map();
|
|
7296
|
-
for (const e of
|
|
7300
|
+
for (const e of mergedAll) toolCounts.set(e.tool, (toolCounts.get(e.tool) ?? 0) + 1);
|
|
7297
7301
|
const topTools = [...toolCounts.entries()].sort((a, b) => b[1] - a[1]).slice(0, 3);
|
|
7298
7302
|
const latNow = lat[lat.length - 1] ?? 0;
|
|
7299
7303
|
const sortedLat = [...lat].sort((a, b) => a - b);
|
|
@@ -7314,19 +7318,53 @@ function LivePanel({ active: active2 }) {
|
|
|
7314
7318
|
}
|
|
7315
7319
|
const localSessList = [...localSess.entries()].sort((a, b) => b[1].lastAt - a[1].lastAt);
|
|
7316
7320
|
const chartH = rows >= 36 ? 6 : 4;
|
|
7317
|
-
const colH = rows >= 32 ?
|
|
7318
|
-
const streamRows = Math.max(4, rows -
|
|
7319
|
-
const tail = merged.slice(-streamRows);
|
|
7321
|
+
const colH = rows >= 32 ? 7 : 5;
|
|
7322
|
+
const streamRows = Math.max(4, rows - 5 - (1 + chartH) - colH);
|
|
7320
7323
|
const innerW = cols - 2;
|
|
7321
7324
|
const leftW = Math.floor(innerW * 0.55);
|
|
7322
7325
|
const rightW = innerW - leftW - 2;
|
|
7323
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
|
+
);
|
|
7324
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
|
+
}
|
|
7325
7362
|
return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", paddingX: 1, children: [
|
|
7326
7363
|
/* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
7327
7364
|
/* @__PURE__ */ jsx2(Text2, { backgroundColor: "#1432A0", color: "#AAC8FA", bold: true, children: " SOLONGATE LIVE " }),
|
|
7328
|
-
/* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", children: ` ${spin} up ${fmtUp(
|
|
7329
|
-
|
|
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
|
|
7330
7368
|
] }),
|
|
7331
7369
|
/* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
7332
7370
|
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "\u2502 calls " }),
|
|
@@ -7336,16 +7374,20 @@ function LivePanel({ active: active2 }) {
|
|
|
7336
7374
|
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502 deny " }),
|
|
7337
7375
|
/* @__PURE__ */ jsx2(Text2, { color: theme.bad, bold: true, children: s ? s.denied : "\xB7\xB7" }),
|
|
7338
7376
|
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502 local " }),
|
|
7339
|
-
localOn ? /* @__PURE__ */ jsx2(Text2, { color: theme.ok, children: "\u2713
|
|
7340
|
-
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502
|
|
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 " }),
|
|
7341
7379
|
/* @__PURE__ */ jsx2(Text2, { color: rl?.mode === "block" ? theme.ok : rl?.mode === "detect" ? theme.warn : theme.dim, children: rl?.mode ?? "?" }),
|
|
7342
7380
|
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502 dlp " }),
|
|
7343
7381
|
/* @__PURE__ */ jsx2(Text2, { color: dl?.mode === "block" ? theme.ok : dl?.mode === "detect" ? theme.warn : theme.dim, children: dl?.mode ?? "?" }),
|
|
7344
|
-
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502
|
|
7345
|
-
/* @__PURE__ */ jsx2(Text2, { color:
|
|
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" }),
|
|
7346
7388
|
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502" })
|
|
7347
7389
|
] }),
|
|
7348
|
-
/* @__PURE__ */ jsxs2(Box2, { children: [
|
|
7390
|
+
/* @__PURE__ */ jsxs2(Box2, { height: 1 + chartH, children: [
|
|
7349
7391
|
/* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", width: leftW, marginRight: 2, children: [
|
|
7350
7392
|
/* @__PURE__ */ jsx2(PaneTitle, { label: "TRAFFIC", extra: `${trafficLabel} \xB7 peak ${Math.max(0, ...traffic)} \xB7 red = denials`, width: leftW }),
|
|
7351
7393
|
/* @__PURE__ */ jsx2(ColumnChart, { series: traffic, hot: trafficHot, height: chartH, width: leftW, color: theme.accent })
|
|
@@ -7355,39 +7397,38 @@ function LivePanel({ active: active2 }) {
|
|
|
7355
7397
|
/* @__PURE__ */ jsx2(ColumnChart, { series: lat, hot: lat.map((v) => v > latHotAt), height: chartH, width: rightW, color: "#82AAF0", hotColor: "#ffb454" })
|
|
7356
7398
|
] })
|
|
7357
7399
|
] }),
|
|
7358
|
-
/* @__PURE__ */ jsxs2(Box2, { children: [
|
|
7359
|
-
/* @__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: [
|
|
7360
7402
|
/* @__PURE__ */ jsx2(PaneTitle, { label: "LAYERS", width: colW }),
|
|
7361
7403
|
/* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
7362
7404
|
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "RATELIMIT ".padEnd(10) }),
|
|
7363
7405
|
/* @__PURE__ */ jsx2(Text2, { color: rl?.mode === "block" ? theme.ok : rl?.mode === "detect" ? theme.warn : theme.dim, children: (rl?.mode ?? "?").padEnd(7) }),
|
|
7364
|
-
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: rl?.perMinute ? `${minuteNow}/${rl.perMinute}
|
|
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" })
|
|
7365
7407
|
] }),
|
|
7366
|
-
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,
|
|
7367
7409
|
/* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
7368
7410
|
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "DLP".padEnd(10) }),
|
|
7369
7411
|
/* @__PURE__ */ jsx2(Text2, { color: dl?.mode === "block" ? theme.ok : dl?.mode === "detect" ? theme.warn : theme.dim, children: (dl?.mode ?? "?").padEnd(7) }),
|
|
7370
|
-
/* @__PURE__ */
|
|
7371
|
-
(dl?.patterns ?? []).length,
|
|
7372
|
-
" patterns armed"
|
|
7373
|
-
] })
|
|
7412
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: `${(dl?.patterns ?? []).length} builtin \xB7 ${(dl?.custom ?? []).length} custom` })
|
|
7374
7413
|
] }),
|
|
7375
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" }),
|
|
7376
|
-
|
|
7415
|
+
/* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
7377
7416
|
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "GUARD".padEnd(10) }),
|
|
7378
|
-
/* @__PURE__ */
|
|
7379
|
-
|
|
7380
|
-
|
|
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
|
+
] })
|
|
7381
7422
|
] }),
|
|
7382
|
-
/* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", width: colW, marginRight: 2, children: [
|
|
7383
|
-
/* @__PURE__ */ jsx2(PaneTitle, { label: "SESSIONS", extra: `${localSessList.length} local \xB7 ${sessCounts?.active ?? 0} cloud
|
|
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 }),
|
|
7384
7425
|
localSessList.length === 0 && sess.length === 0 ? /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "scanning\u2026" }) : null,
|
|
7385
7426
|
localSessList.slice(0, Math.max(1, colH - 2)).map(([id, v]) => {
|
|
7386
|
-
const
|
|
7427
|
+
const freshDot = nowMs - v.lastAt < 9e4;
|
|
7387
7428
|
const isMe = ring?.session === id;
|
|
7388
7429
|
return /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
7389
|
-
/* @__PURE__ */ jsxs2(Text2, { color:
|
|
7390
|
-
|
|
7430
|
+
/* @__PURE__ */ jsxs2(Text2, { color: freshDot ? theme.ok : theme.dim, children: [
|
|
7431
|
+
freshDot ? "\u25CF" : "\u25CB",
|
|
7391
7432
|
" "
|
|
7392
7433
|
] }),
|
|
7393
7434
|
/* @__PURE__ */ jsx2(Text2, { color: theme.ok, children: "LOC " }),
|
|
@@ -7420,12 +7461,12 @@ function LivePanel({ active: active2 }) {
|
|
|
7420
7461
|
String(a.denied_calls).padStart(3),
|
|
7421
7462
|
"d "
|
|
7422
7463
|
] }),
|
|
7423
|
-
/* @__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) })
|
|
7424
7465
|
] }, a.session_id);
|
|
7425
7466
|
})
|
|
7426
7467
|
] }),
|
|
7427
|
-
/* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", width: colW, children: [
|
|
7428
|
-
/* @__PURE__ */ jsx2(PaneTitle, { label: "EVENT LOG", extra: "
|
|
7468
|
+
/* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", width: colW, overflow: "hidden", children: [
|
|
7469
|
+
/* @__PURE__ */ jsx2(PaneTitle, { label: "EVENT LOG", extra: "system heartbeat", width: colW }),
|
|
7429
7470
|
log6.slice(-(colH - 1)).map((l, i) => /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
7430
7471
|
/* @__PURE__ */ jsxs2(Text2, { color: theme.dim, children: [
|
|
7431
7472
|
hhmmss(l.ts),
|
|
@@ -7436,37 +7477,49 @@ function LivePanel({ active: active2 }) {
|
|
|
7436
7477
|
] }, l.ts + ":" + i))
|
|
7437
7478
|
] })
|
|
7438
7479
|
] }),
|
|
7439
|
-
/* @__PURE__ */ jsx2(
|
|
7440
|
-
|
|
7441
|
-
|
|
7442
|
-
|
|
7443
|
-
|
|
7444
|
-
|
|
7445
|
-
|
|
7446
|
-
|
|
7447
|
-
|
|
7448
|
-
|
|
7449
|
-
|
|
7450
|
-
"
|
|
7451
|
-
|
|
7452
|
-
|
|
7453
|
-
|
|
7454
|
-
|
|
7455
|
-
|
|
7456
|
-
/* @__PURE__ */
|
|
7457
|
-
|
|
7458
|
-
|
|
7459
|
-
|
|
7460
|
-
|
|
7461
|
-
|
|
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
|
+
] }),
|
|
7462
7515
|
/* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
7463
7516
|
/* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", bold: true, children: " LIVE " }),
|
|
7464
|
-
/* @__PURE__ */ jsx2(Text2, { backgroundColor: "#0b1530", color: "#4f6db8", children: ` local ${localOn ? "on" : "off"} \xB7 top ${topTools.map(([t, c2]) => `${t}\xD7${c2}`).join(" ") || "\u2014"}
|
|
7465
|
-
/* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", children: "
|
|
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 " })
|
|
7466
7519
|
] })
|
|
7467
7520
|
] });
|
|
7468
7521
|
}
|
|
7469
|
-
var SPIN, BG, LOCAL_LOG, RING, hhmmss, fmtUp;
|
|
7522
|
+
var SPIN, BG, DIM_FLOOR, LOCAL_LOG, RING, DUMP, STREAM_KEEP, hhmmss, fmtUp, FILTERS;
|
|
7470
7523
|
var init_Live = __esm({
|
|
7471
7524
|
"src/tui/panels/Live.tsx"() {
|
|
7472
7525
|
"use strict";
|
|
@@ -7475,8 +7528,11 @@ var init_Live = __esm({
|
|
|
7475
7528
|
init_theme();
|
|
7476
7529
|
SPIN = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
7477
7530
|
BG = "#12234f";
|
|
7531
|
+
DIM_FLOOR = "#233457";
|
|
7478
7532
|
LOCAL_LOG = join5(homedir3(), ".solongate", "local-logs", "solongate-audit.jsonl");
|
|
7479
7533
|
RING = join5(process.cwd(), ".solongate", ".eval-ring.jsonl");
|
|
7534
|
+
DUMP = join5(homedir3(), ".solongate", "live-stream.log");
|
|
7535
|
+
STREAM_KEEP = 100;
|
|
7480
7536
|
hhmmss = (ts) => {
|
|
7481
7537
|
const d = new Date(ts);
|
|
7482
7538
|
return Number.isNaN(d.getTime()) ? "--:--:--" : d.toTimeString().slice(0, 8);
|
|
@@ -7486,6 +7542,7 @@ var init_Live = __esm({
|
|
|
7486
7542
|
const p = (n) => String(n).padStart(2, "0");
|
|
7487
7543
|
return `${p(Math.floor(s / 3600))}:${p(Math.floor(s % 3600 / 60))}:${p(s % 60)}`;
|
|
7488
7544
|
};
|
|
7545
|
+
FILTERS = ["all", "local", "cloud"];
|
|
7489
7546
|
}
|
|
7490
7547
|
});
|
|
7491
7548
|
|
|
@@ -9147,8 +9204,8 @@ __export(global_install_exports, {
|
|
|
9147
9204
|
runGlobalRestore: () => runGlobalRestore,
|
|
9148
9205
|
unlockProtected: () => unlockProtected
|
|
9149
9206
|
});
|
|
9150
|
-
import { readFileSync as readFileSync6, writeFileSync as
|
|
9151
|
-
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";
|
|
9152
9209
|
import { homedir as homedir4 } from "os";
|
|
9153
9210
|
import { fileURLToPath } from "url";
|
|
9154
9211
|
import { createInterface } from "readline";
|
|
@@ -9260,13 +9317,13 @@ function runGlobalRestore() {
|
|
|
9260
9317
|
unlockProtected();
|
|
9261
9318
|
removeClaudeShim();
|
|
9262
9319
|
if (existsSync4(p.backupPath)) {
|
|
9263
|
-
|
|
9320
|
+
writeFileSync4(p.settingsPath, readFileSync6(p.backupPath, "utf-8"));
|
|
9264
9321
|
console.log(` Restored ${p.settingsPath} from backup.`);
|
|
9265
9322
|
} else if (existsSync4(p.settingsPath)) {
|
|
9266
9323
|
try {
|
|
9267
9324
|
const s = JSON.parse(readFileSync6(p.settingsPath, "utf-8"));
|
|
9268
9325
|
delete s.hooks;
|
|
9269
|
-
|
|
9326
|
+
writeFileSync4(p.settingsPath, JSON.stringify(s, null, 2) + "\n");
|
|
9270
9327
|
console.log(` Removed SolonGate hooks from ${p.settingsPath}.`);
|
|
9271
9328
|
} catch {
|
|
9272
9329
|
}
|
|
@@ -9310,8 +9367,8 @@ function writeShimBlock(file, block) {
|
|
|
9310
9367
|
if (content.length && !content.endsWith("\n")) content += "\n";
|
|
9311
9368
|
content += block + "\n";
|
|
9312
9369
|
}
|
|
9313
|
-
|
|
9314
|
-
|
|
9370
|
+
mkdirSync4(dirname2(file), { recursive: true });
|
|
9371
|
+
writeFileSync4(file, content);
|
|
9315
9372
|
}
|
|
9316
9373
|
function installClaudeShim(shieldPath) {
|
|
9317
9374
|
const real = resolveRealClaude();
|
|
@@ -9368,22 +9425,22 @@ async function runGlobalInstall(opts = {}) {
|
|
|
9368
9425
|
process.exit(1);
|
|
9369
9426
|
}
|
|
9370
9427
|
const apiUrl = opts.apiUrl || process.env["SOLONGATE_API_URL"] || "https://api.solongate.com";
|
|
9371
|
-
|
|
9372
|
-
|
|
9428
|
+
mkdirSync4(p.hooksDir, { recursive: true });
|
|
9429
|
+
mkdirSync4(p.claudeDir, { recursive: true });
|
|
9373
9430
|
unlockProtected();
|
|
9374
|
-
|
|
9375
|
-
|
|
9376
|
-
|
|
9377
|
-
|
|
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"));
|
|
9378
9435
|
console.log(` Installed hooks \u2192 ${p.hooksDir}`);
|
|
9379
9436
|
removeClaudeShim();
|
|
9380
|
-
|
|
9437
|
+
writeFileSync4(p.configPath, JSON.stringify({ apiKey, apiUrl }, null, 2) + "\n");
|
|
9381
9438
|
console.log(` Wrote ${p.configPath}`);
|
|
9382
9439
|
let existing = {};
|
|
9383
9440
|
if (existsSync4(p.settingsPath)) {
|
|
9384
9441
|
const raw = readFileSync6(p.settingsPath, "utf-8");
|
|
9385
9442
|
if (!existsSync4(p.backupPath)) {
|
|
9386
|
-
|
|
9443
|
+
writeFileSync4(p.backupPath, raw);
|
|
9387
9444
|
console.log(` Backed up existing settings \u2192 ${p.backupPath}`);
|
|
9388
9445
|
}
|
|
9389
9446
|
try {
|
|
@@ -9404,7 +9461,7 @@ async function runGlobalInstall(opts = {}) {
|
|
|
9404
9461
|
Stop: [{ matcher: "", hooks: [{ type: "command", command: `"${nodeBin}" "${stopAbs}" claude-code "Claude Code"` }] }]
|
|
9405
9462
|
}
|
|
9406
9463
|
};
|
|
9407
|
-
|
|
9464
|
+
writeFileSync4(p.settingsPath, JSON.stringify(merged, null, 2) + "\n");
|
|
9408
9465
|
console.log(` Registered global hooks \u2192 ${p.settingsPath}`);
|
|
9409
9466
|
if (process.env["SOLONGATE_OS_LOCK"] === "1") {
|
|
9410
9467
|
lockProtected();
|
|
@@ -9418,7 +9475,7 @@ var __dirname, HOOKS_DIR, SHIM_BEGIN, SHIM_END;
|
|
|
9418
9475
|
var init_global_install = __esm({
|
|
9419
9476
|
"src/global-install.ts"() {
|
|
9420
9477
|
"use strict";
|
|
9421
|
-
__dirname =
|
|
9478
|
+
__dirname = dirname2(fileURLToPath(import.meta.url));
|
|
9422
9479
|
HOOKS_DIR = resolve4(__dirname, "..", "hooks");
|
|
9423
9480
|
SHIM_BEGIN = "# >>> SolonGate shield (auto secret redaction) >>>";
|
|
9424
9481
|
SHIM_END = "# <<< SolonGate shield <<<";
|
|
@@ -10068,7 +10125,7 @@ var init_logs_server = __esm({
|
|
|
10068
10125
|
|
|
10069
10126
|
// src/inject.ts
|
|
10070
10127
|
var inject_exports = {};
|
|
10071
|
-
import { readFileSync as readFileSync9, writeFileSync as
|
|
10128
|
+
import { readFileSync as readFileSync9, writeFileSync as writeFileSync5, existsSync as existsSync6, copyFileSync } from "fs";
|
|
10072
10129
|
import { resolve as resolve7 } from "path";
|
|
10073
10130
|
import { execSync } from "child_process";
|
|
10074
10131
|
function parseInjectArgs(argv) {
|
|
@@ -10376,7 +10433,7 @@ async function main2() {
|
|
|
10376
10433
|
log3("");
|
|
10377
10434
|
log3(` Backup: ${backupPath}`);
|
|
10378
10435
|
}
|
|
10379
|
-
|
|
10436
|
+
writeFileSync5(entryFile, result.modified);
|
|
10380
10437
|
log3("");
|
|
10381
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");
|
|
10382
10439
|
log3(" \u2502 SolonGate SDK injected successfully! \u2502");
|
|
@@ -10405,7 +10462,7 @@ var init_inject = __esm({
|
|
|
10405
10462
|
|
|
10406
10463
|
// src/create.ts
|
|
10407
10464
|
var create_exports = {};
|
|
10408
|
-
import { mkdirSync as
|
|
10465
|
+
import { mkdirSync as mkdirSync5, writeFileSync as writeFileSync6, existsSync as existsSync7 } from "fs";
|
|
10409
10466
|
import { resolve as resolve8, join as join8 } from "path";
|
|
10410
10467
|
import { execSync as execSync2 } from "child_process";
|
|
10411
10468
|
function withSpinner(message, fn) {
|
|
@@ -10485,7 +10542,7 @@ EXAMPLES
|
|
|
10485
10542
|
`);
|
|
10486
10543
|
}
|
|
10487
10544
|
function createProject(dir, name, _policy) {
|
|
10488
|
-
|
|
10545
|
+
writeFileSync6(
|
|
10489
10546
|
join8(dir, "package.json"),
|
|
10490
10547
|
JSON.stringify(
|
|
10491
10548
|
{
|
|
@@ -10515,7 +10572,7 @@ function createProject(dir, name, _policy) {
|
|
|
10515
10572
|
2
|
|
10516
10573
|
) + "\n"
|
|
10517
10574
|
);
|
|
10518
|
-
|
|
10575
|
+
writeFileSync6(
|
|
10519
10576
|
join8(dir, "tsconfig.json"),
|
|
10520
10577
|
JSON.stringify(
|
|
10521
10578
|
{
|
|
@@ -10536,8 +10593,8 @@ function createProject(dir, name, _policy) {
|
|
|
10536
10593
|
2
|
|
10537
10594
|
) + "\n"
|
|
10538
10595
|
);
|
|
10539
|
-
|
|
10540
|
-
|
|
10596
|
+
mkdirSync5(join8(dir, "src"), { recursive: true });
|
|
10597
|
+
writeFileSync6(
|
|
10541
10598
|
join8(dir, "src", "index.ts"),
|
|
10542
10599
|
`#!/usr/bin/env node
|
|
10543
10600
|
|
|
@@ -10579,7 +10636,7 @@ console.log('');
|
|
|
10579
10636
|
console.log('Press Ctrl+C to stop.');
|
|
10580
10637
|
`
|
|
10581
10638
|
);
|
|
10582
|
-
|
|
10639
|
+
writeFileSync6(
|
|
10583
10640
|
join8(dir, ".mcp.json"),
|
|
10584
10641
|
JSON.stringify(
|
|
10585
10642
|
{
|
|
@@ -10597,12 +10654,12 @@ console.log('Press Ctrl+C to stop.');
|
|
|
10597
10654
|
2
|
|
10598
10655
|
) + "\n"
|
|
10599
10656
|
);
|
|
10600
|
-
|
|
10657
|
+
writeFileSync6(
|
|
10601
10658
|
join8(dir, ".env"),
|
|
10602
10659
|
`SOLONGATE_API_KEY=sg_live_YOUR_KEY_HERE
|
|
10603
10660
|
`
|
|
10604
10661
|
);
|
|
10605
|
-
|
|
10662
|
+
writeFileSync6(
|
|
10606
10663
|
join8(dir, ".gitignore"),
|
|
10607
10664
|
`node_modules/
|
|
10608
10665
|
dist/
|
|
@@ -10622,7 +10679,7 @@ async function main3() {
|
|
|
10622
10679
|
process.exit(1);
|
|
10623
10680
|
}
|
|
10624
10681
|
withSpinner(`Setting up ${opts.name}...`, () => {
|
|
10625
|
-
|
|
10682
|
+
mkdirSync5(dir, { recursive: true });
|
|
10626
10683
|
createProject(dir, opts.name, opts.policy);
|
|
10627
10684
|
});
|
|
10628
10685
|
if (!opts.noInstall) {
|
|
@@ -10696,7 +10753,7 @@ var init_create = __esm({
|
|
|
10696
10753
|
|
|
10697
10754
|
// src/pull-push.ts
|
|
10698
10755
|
var pull_push_exports = {};
|
|
10699
|
-
import { readFileSync as readFileSync10, writeFileSync as
|
|
10756
|
+
import { readFileSync as readFileSync10, writeFileSync as writeFileSync7, existsSync as existsSync8 } from "fs";
|
|
10700
10757
|
import { resolve as resolve9 } from "path";
|
|
10701
10758
|
function loadEnv() {
|
|
10702
10759
|
if (process.env.SOLONGATE_API_KEY) return;
|
|
@@ -10891,7 +10948,7 @@ async function pull(apiKey, file, policyId) {
|
|
|
10891
10948
|
const policy = await fetchCloudPolicy(apiKey, API_URL, policyId);
|
|
10892
10949
|
const { id: _id, ...policyWithoutId } = policy;
|
|
10893
10950
|
const json = JSON.stringify(policyWithoutId, null, 2) + "\n";
|
|
10894
|
-
|
|
10951
|
+
writeFileSync7(file, json, "utf-8");
|
|
10895
10952
|
log5("");
|
|
10896
10953
|
log5(green2(" Saved to: ") + file);
|
|
10897
10954
|
log5(` ${dim2("Name:")} ${policy.name}`);
|
package/dist/tui/index.js
CHANGED
|
@@ -126,9 +126,9 @@ function KeyHints({ hints }) {
|
|
|
126
126
|
|
|
127
127
|
// src/tui/panels/Live.tsx
|
|
128
128
|
import { Box as Box2, Text as Text2, useInput } from "ink";
|
|
129
|
-
import { closeSync, openSync, readSync, statSync } from "fs";
|
|
129
|
+
import { closeSync, mkdirSync, openSync, readSync, statSync, writeFileSync } from "fs";
|
|
130
130
|
import { homedir as homedir2 } from "os";
|
|
131
|
-
import { join as join2 } from "path";
|
|
131
|
+
import { dirname, join as join2 } from "path";
|
|
132
132
|
import { useCallback as useCallback2, useEffect as useEffect2, useRef as useRef2, useState as useState2 } from "react";
|
|
133
133
|
|
|
134
134
|
// src/api-client/client.ts
|
|
@@ -436,8 +436,11 @@ function usePoll(reload, intervalMs, enabled = true) {
|
|
|
436
436
|
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
437
437
|
var SPIN = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
438
438
|
var BG = "#12234f";
|
|
439
|
+
var DIM_FLOOR = "#233457";
|
|
439
440
|
var LOCAL_LOG = join2(homedir2(), ".solongate", "local-logs", "solongate-audit.jsonl");
|
|
440
441
|
var RING = join2(process.cwd(), ".solongate", ".eval-ring.jsonl");
|
|
442
|
+
var DUMP = join2(homedir2(), ".solongate", "live-stream.log");
|
|
443
|
+
var STREAM_KEEP = 100;
|
|
441
444
|
var hhmmss = (ts) => {
|
|
442
445
|
const d = new Date(ts);
|
|
443
446
|
return Number.isNaN(d.getTime()) ? "--:--:--" : d.toTimeString().slice(0, 8);
|
|
@@ -447,7 +450,7 @@ var fmtUp = (ms) => {
|
|
|
447
450
|
const p = (n) => String(n).padStart(2, "0");
|
|
448
451
|
return `${p(Math.floor(s / 3600))}:${p(Math.floor(s % 3600 / 60))}:${p(s % 60)}`;
|
|
449
452
|
};
|
|
450
|
-
function tailLines(file, maxBytes =
|
|
453
|
+
function tailLines(file, maxBytes = 131072) {
|
|
451
454
|
try {
|
|
452
455
|
const size = statSync(file).size;
|
|
453
456
|
const start = Math.max(0, size - maxBytes);
|
|
@@ -462,6 +465,9 @@ function tailLines(file, maxBytes = 65536) {
|
|
|
462
465
|
return [];
|
|
463
466
|
}
|
|
464
467
|
}
|
|
468
|
+
function oscCopy(text) {
|
|
469
|
+
process.stdout.write(`\x1B]52;c;${Buffer.from(text, "utf-8").toString("base64")}\x07`);
|
|
470
|
+
}
|
|
465
471
|
function cloudItem(e) {
|
|
466
472
|
return {
|
|
467
473
|
id: "c:" + e.id,
|
|
@@ -471,7 +477,11 @@ function cloudItem(e) {
|
|
|
471
477
|
permission: (e.permission ?? "").slice(0, 4),
|
|
472
478
|
detail: (e.arguments_summary ? JSON.stringify(e.arguments_summary) : e.reason ?? "").replace(/\s+/g, " "),
|
|
473
479
|
dlp: !!e.dlp_matches?.length,
|
|
474
|
-
source: "cloud"
|
|
480
|
+
source: "cloud",
|
|
481
|
+
session: e.session_id ?? void 0,
|
|
482
|
+
agent: e.agent_name ?? void 0,
|
|
483
|
+
evalMs: e.evaluation_time_ms ?? void 0,
|
|
484
|
+
rule: e.matched_rule_id ?? void 0
|
|
475
485
|
};
|
|
476
486
|
}
|
|
477
487
|
function ColumnChart({ series, hot, height, width, color, hotColor = theme.bad }) {
|
|
@@ -490,7 +500,7 @@ function ColumnChart({ series, hot, height, width, color, hotColor = theme.bad }
|
|
|
490
500
|
else if (frac >= (r - 0.5) / height) ch = "\u2584";
|
|
491
501
|
else if (r === 1) ch = "\u2581";
|
|
492
502
|
else ch = " ";
|
|
493
|
-
const c2 = r === 1 && v === 0 ?
|
|
503
|
+
const c2 = r === 1 && v === 0 ? DIM_FLOOR : hotPad?.[i] ? hotColor : color;
|
|
494
504
|
const last = segs[segs.length - 1];
|
|
495
505
|
if (last && last.color === c2) last.text += ch;
|
|
496
506
|
else segs.push({ text: ch, color: c2 });
|
|
@@ -506,7 +516,7 @@ function HBar({ label, value, max, width, color }) {
|
|
|
506
516
|
return /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
507
517
|
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: label.padEnd(10) }),
|
|
508
518
|
/* @__PURE__ */ jsx2(Text2, { color, children: "\u2588".repeat(Math.min(width, filled)) }),
|
|
509
|
-
/* @__PURE__ */ jsx2(Text2, { color:
|
|
519
|
+
/* @__PURE__ */ jsx2(Text2, { color: DIM_FLOOR, children: "\u2591".repeat(Math.max(0, width - filled)) }),
|
|
510
520
|
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " " + value })
|
|
511
521
|
] });
|
|
512
522
|
}
|
|
@@ -522,6 +532,7 @@ function PaneTitle({ label, extra, width }) {
|
|
|
522
532
|
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: tail + "\u2500".repeat(Math.max(0, width - used)) })
|
|
523
533
|
] });
|
|
524
534
|
}
|
|
535
|
+
var FILTERS = ["all", "local", "cloud"];
|
|
525
536
|
function LivePanel({ active: active2 }) {
|
|
526
537
|
const [s, setS] = useState2(null);
|
|
527
538
|
const [tsData, setTsData] = useState2(null);
|
|
@@ -531,18 +542,12 @@ function LivePanel({ active: active2 }) {
|
|
|
531
542
|
const [localOn, setLocalOn] = useState2(null);
|
|
532
543
|
const [ring, setRing] = useState2(null);
|
|
533
544
|
const [log, setLog] = useState2([]);
|
|
545
|
+
const [filter, setFilter] = useState2("all");
|
|
546
|
+
const [scroll, setScroll] = useState2(0);
|
|
547
|
+
const [toast, setToast] = useState2(null);
|
|
534
548
|
const seenRef = useRef2(/* @__PURE__ */ new Set());
|
|
535
549
|
const lastLocalTs = useRef2(0);
|
|
536
550
|
const pausedUntil = useRef2(0);
|
|
537
|
-
const [frozen, setFrozen] = useState2(false);
|
|
538
|
-
const frozenRef = useRef2(false);
|
|
539
|
-
frozenRef.current = frozen;
|
|
540
|
-
useInput(
|
|
541
|
-
(input) => {
|
|
542
|
-
if (input === "p") setFrozen((f) => !f);
|
|
543
|
-
},
|
|
544
|
-
{ isActive: active2 }
|
|
545
|
-
);
|
|
546
551
|
const pushLog = useCallback2((msg, level = "ok") => {
|
|
547
552
|
setLog((prev) => [...prev.slice(-59), { ts: Date.now(), msg, level }]);
|
|
548
553
|
}, []);
|
|
@@ -558,9 +563,8 @@ function LivePanel({ active: active2 }) {
|
|
|
558
563
|
},
|
|
559
564
|
[pushLog]
|
|
560
565
|
);
|
|
561
|
-
const paused = () =>
|
|
566
|
+
const paused = () => Date.now() < pausedUntil.current;
|
|
562
567
|
const pollLocal = useCallback2(() => {
|
|
563
|
-
if (frozenRef.current) return;
|
|
564
568
|
const lines = tailLines(LOCAL_LOG);
|
|
565
569
|
if (!lines.length) {
|
|
566
570
|
setLocalOn((prev) => prev === null ? false : prev);
|
|
@@ -583,7 +587,9 @@ function LivePanel({ active: active2 }) {
|
|
|
583
587
|
dlp: !!j.dlp,
|
|
584
588
|
source: "local",
|
|
585
589
|
session: j.session_id,
|
|
586
|
-
agent: j.agent_name
|
|
590
|
+
agent: j.agent_name,
|
|
591
|
+
evalMs: j.evaluation_time_ms,
|
|
592
|
+
rule: j.matched_rule_id
|
|
587
593
|
});
|
|
588
594
|
} catch {
|
|
589
595
|
}
|
|
@@ -592,9 +598,7 @@ function LivePanel({ active: active2 }) {
|
|
|
592
598
|
lastLocalTs.current = fresh[fresh.length - 1].at;
|
|
593
599
|
setLocalBuf((prev) => [...prev, ...fresh].slice(-400));
|
|
594
600
|
const denies = fresh.filter((f) => f.decision !== "ALLOW").length;
|
|
595
|
-
if (
|
|
596
|
-
pushLog(`local +${fresh.length} calls${denies ? ` \xB7 ${denies} DENIED` : ""}`, denies ? "bad" : "warn");
|
|
597
|
-
}
|
|
601
|
+
if (fresh.length < 10) pushLog(`local +${fresh.length} calls${denies ? ` \xB7 ${denies} DENIED` : ""}`, denies ? "bad" : "warn");
|
|
598
602
|
}
|
|
599
603
|
const ringLines = tailLines(RING, 8192).slice(-30);
|
|
600
604
|
if (ringLines.length) {
|
|
@@ -631,9 +635,7 @@ function LivePanel({ active: active2 }) {
|
|
|
631
635
|
const fresh = fd.entries.filter((e) => !seenRef.current.has(e.id));
|
|
632
636
|
const firstLoad = seenRef.current.size === 0 && fresh.length > 1;
|
|
633
637
|
for (const e of fresh) seenRef.current.add(e.id);
|
|
634
|
-
if (fresh.length)
|
|
635
|
-
setCloudBuf((prev) => [...prev, ...fresh.map(cloudItem).sort((a, b) => a.at - b.at)].slice(-400));
|
|
636
|
-
}
|
|
638
|
+
if (fresh.length) setCloudBuf((prev) => [...prev, ...fresh.map(cloudItem).sort((a, b) => a.at - b.at)].slice(-400));
|
|
637
639
|
const denies = fresh.filter((e) => e.decision !== "ALLOW").length;
|
|
638
640
|
if (firstLoad) pushLog(`cloud link up \xB7 api ${ms}ms \xB7 ${fresh.length} calls`);
|
|
639
641
|
else pushLog(`api ${ms}ms \xB7 +${fresh.length} cloud${denies ? ` \xB7 ${denies} DENIED` : ""}`, denies ? "bad" : fresh.length ? "warn" : "ok");
|
|
@@ -673,26 +675,32 @@ function LivePanel({ active: active2 }) {
|
|
|
673
675
|
}, [active2, pollFeed, pollMedium, pollSlow]);
|
|
674
676
|
const sessions = useLoader(() => api.agents.live({ limit: 30, includeDeactivated: true }));
|
|
675
677
|
const insights = useLoader(() => api.stats.securityInsights(7));
|
|
678
|
+
const guard = useLoader(() => api.settings.getGuardStatus());
|
|
676
679
|
usePoll(() => {
|
|
677
680
|
if (!paused()) sessions.reload();
|
|
678
681
|
}, 1e4, active2);
|
|
679
682
|
usePoll(() => {
|
|
680
683
|
if (!paused()) insights.reload();
|
|
681
684
|
}, 3e4, active2);
|
|
685
|
+
usePoll(() => {
|
|
686
|
+
if (!paused()) guard.reload();
|
|
687
|
+
}, 6e4, active2);
|
|
682
688
|
const [tick, setTick] = useState2(0);
|
|
683
689
|
useEffect2(() => {
|
|
684
|
-
if (!active2
|
|
685
|
-
const t = setInterval(() => setTick((n) => n + 1),
|
|
690
|
+
if (!active2) return;
|
|
691
|
+
const t = setInterval(() => setTick((n) => n + 1), 500);
|
|
686
692
|
return () => clearInterval(t);
|
|
687
|
-
}, [active2
|
|
693
|
+
}, [active2]);
|
|
688
694
|
const startRef = useRef2(Date.now());
|
|
689
695
|
const cols = process.stdout.columns ?? 100;
|
|
690
696
|
const rows = process.stdout.rows ?? 30;
|
|
691
697
|
const ins = insights.data ?? {};
|
|
692
698
|
const spin = SPIN[tick % SPIN.length];
|
|
693
|
-
const points = tsData?.timeseries ?? [];
|
|
694
|
-
const mergedAll = [...cloudBuf, ...localBuf].sort((a, b) => a.at - b.at);
|
|
695
699
|
const nowMs = Date.now();
|
|
700
|
+
const mergedAll = [...cloudBuf, ...localBuf].sort((a, b) => a.at - b.at);
|
|
701
|
+
const filtered = filter === "all" ? mergedAll : mergedAll.filter((e) => e.source === filter);
|
|
702
|
+
const visible = filtered.slice(-STREAM_KEEP);
|
|
703
|
+
const points = tsData?.timeseries ?? [];
|
|
696
704
|
const minuteCounts = new Array(60).fill(0);
|
|
697
705
|
const minuteHot = new Array(60).fill(false);
|
|
698
706
|
for (const e of mergedAll) {
|
|
@@ -708,14 +716,14 @@ function LivePanel({ active: active2 }) {
|
|
|
708
716
|
const trafficLabel = localTraffic ? "calls/min \xB7 60m \xB7 local+cloud" : "24h \xB7 cloud";
|
|
709
717
|
const rl = ins.layers?.rateLimit;
|
|
710
718
|
const dl = ins.layers?.dlp;
|
|
711
|
-
const
|
|
719
|
+
const gh = ins.layers?.ghost;
|
|
720
|
+
const minuteNow = minuteCounts[59] ?? 0;
|
|
712
721
|
const dlpBars = (ins.dlpByPattern ?? []).slice(0, 2);
|
|
713
722
|
const maxDlpBar = dlpBars[0]?.count ?? 1;
|
|
714
|
-
const
|
|
715
|
-
const denials = merged.filter((e) => e.decision !== "ALLOW");
|
|
723
|
+
const denials = mergedAll.filter((e) => e.decision !== "ALLOW");
|
|
716
724
|
const lastDeny = denials[denials.length - 1];
|
|
717
725
|
const toolCounts = /* @__PURE__ */ new Map();
|
|
718
|
-
for (const e of
|
|
726
|
+
for (const e of mergedAll) toolCounts.set(e.tool, (toolCounts.get(e.tool) ?? 0) + 1);
|
|
719
727
|
const topTools = [...toolCounts.entries()].sort((a, b) => b[1] - a[1]).slice(0, 3);
|
|
720
728
|
const latNow = lat[lat.length - 1] ?? 0;
|
|
721
729
|
const sortedLat = [...lat].sort((a, b) => a - b);
|
|
@@ -736,19 +744,53 @@ function LivePanel({ active: active2 }) {
|
|
|
736
744
|
}
|
|
737
745
|
const localSessList = [...localSess.entries()].sort((a, b) => b[1].lastAt - a[1].lastAt);
|
|
738
746
|
const chartH = rows >= 36 ? 6 : 4;
|
|
739
|
-
const colH = rows >= 32 ?
|
|
740
|
-
const streamRows = Math.max(4, rows -
|
|
741
|
-
const tail = merged.slice(-streamRows);
|
|
747
|
+
const colH = rows >= 32 ? 7 : 5;
|
|
748
|
+
const streamRows = Math.max(4, rows - 5 - (1 + chartH) - colH);
|
|
742
749
|
const innerW = cols - 2;
|
|
743
750
|
const leftW = Math.floor(innerW * 0.55);
|
|
744
751
|
const rightW = innerW - leftW - 2;
|
|
745
752
|
const colW = Math.max(20, Math.floor((innerW - 4) / 3));
|
|
753
|
+
const maxScroll = Math.max(0, visible.length - streamRows);
|
|
754
|
+
const clampedScroll = Math.min(scroll, maxScroll);
|
|
755
|
+
const start = Math.max(0, visible.length - streamRows - clampedScroll);
|
|
756
|
+
const windowed = visible.slice(start, start + streamRows);
|
|
757
|
+
useInput(
|
|
758
|
+
(input, key) => {
|
|
759
|
+
if (input === "f") {
|
|
760
|
+
setFilter((f) => FILTERS[(FILTERS.indexOf(f) + 1) % FILTERS.length]);
|
|
761
|
+
setScroll(0);
|
|
762
|
+
} else if (key.upArrow) setScroll((n) => Math.min(maxScroll, n + 1));
|
|
763
|
+
else if (key.downArrow) setScroll((n) => Math.max(0, n - 1));
|
|
764
|
+
else if (key.pageUp) setScroll((n) => Math.min(maxScroll, n + streamRows));
|
|
765
|
+
else if (key.pageDown) setScroll((n) => Math.max(0, n - streamRows));
|
|
766
|
+
else if (input === "c") {
|
|
767
|
+
const dump = visible.map(
|
|
768
|
+
(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}`
|
|
769
|
+
).join("\n");
|
|
770
|
+
try {
|
|
771
|
+
mkdirSync(dirname(DUMP), { recursive: true });
|
|
772
|
+
writeFileSync(DUMP, dump + "\n");
|
|
773
|
+
} catch {
|
|
774
|
+
}
|
|
775
|
+
oscCopy(dump);
|
|
776
|
+
setToast({ msg: `copied ${visible.length} lines \u2192 clipboard + ${DUMP}`, until: Date.now() + 4e3 });
|
|
777
|
+
}
|
|
778
|
+
},
|
|
779
|
+
{ isActive: active2 }
|
|
780
|
+
);
|
|
746
781
|
const sessionDot = (st) => st === "active" ? { ch: "\u25CF", color: theme.ok } : st === "idle" ? { ch: "\u25CC", color: theme.warn } : { ch: "\u25CB", color: theme.dim };
|
|
782
|
+
if (s === null && localOn === null) {
|
|
783
|
+
return /* @__PURE__ */ jsxs2(Text2, { color: theme.dim, children: [
|
|
784
|
+
spin,
|
|
785
|
+
" connecting\u2026"
|
|
786
|
+
] });
|
|
787
|
+
}
|
|
747
788
|
return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", paddingX: 1, children: [
|
|
748
789
|
/* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
749
790
|
/* @__PURE__ */ jsx2(Text2, { backgroundColor: "#1432A0", color: "#AAC8FA", bold: true, children: " SOLONGATE LIVE " }),
|
|
750
|
-
/* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", children: ` ${spin} up ${fmtUp(
|
|
751
|
-
|
|
791
|
+
/* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", children: ` ${spin} up ${fmtUp(nowMs - startRef.current)} \xB7 ${hhmmss(nowMs)} \xB7 api ${latNow}ms ` }),
|
|
792
|
+
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 " }),
|
|
793
|
+
toast && nowMs < toast.until ? /* @__PURE__ */ jsx2(Text2, { backgroundColor: "#123d1f", color: "#7bd88f", bold: true, children: ` ${toast.msg} ` }) : null
|
|
752
794
|
] }),
|
|
753
795
|
/* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
754
796
|
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "\u2502 calls " }),
|
|
@@ -758,16 +800,20 @@ function LivePanel({ active: active2 }) {
|
|
|
758
800
|
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502 deny " }),
|
|
759
801
|
/* @__PURE__ */ jsx2(Text2, { color: theme.bad, bold: true, children: s ? s.denied : "\xB7\xB7" }),
|
|
760
802
|
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502 local " }),
|
|
761
|
-
localOn ? /* @__PURE__ */ jsx2(Text2, { color: theme.ok, children: "\u2713
|
|
762
|
-
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502
|
|
803
|
+
localOn ? /* @__PURE__ */ jsx2(Text2, { color: theme.ok, children: "\u2713" }) : /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "off" }),
|
|
804
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502 rl " }),
|
|
763
805
|
/* @__PURE__ */ jsx2(Text2, { color: rl?.mode === "block" ? theme.ok : rl?.mode === "detect" ? theme.warn : theme.dim, children: rl?.mode ?? "?" }),
|
|
764
806
|
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502 dlp " }),
|
|
765
807
|
/* @__PURE__ */ jsx2(Text2, { color: dl?.mode === "block" ? theme.ok : dl?.mode === "detect" ? theme.warn : theme.dim, children: dl?.mode ?? "?" }),
|
|
766
|
-
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502
|
|
767
|
-
/* @__PURE__ */ jsx2(Text2, { color:
|
|
808
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502 ghost " }),
|
|
809
|
+
/* @__PURE__ */ jsx2(Text2, { color: gh?.mode === "on" ? theme.ok : theme.dim, children: gh?.mode ?? "?" }),
|
|
810
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502 sess " }),
|
|
811
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.accent, children: `${localSessList.length}loc ${sessCounts?.active ?? 0}\u25B2${sessCounts?.idle ?? 0}\u25CC` }),
|
|
812
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502 hooks " }),
|
|
813
|
+
/* @__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" }),
|
|
768
814
|
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502" })
|
|
769
815
|
] }),
|
|
770
|
-
/* @__PURE__ */ jsxs2(Box2, { children: [
|
|
816
|
+
/* @__PURE__ */ jsxs2(Box2, { height: 1 + chartH, children: [
|
|
771
817
|
/* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", width: leftW, marginRight: 2, children: [
|
|
772
818
|
/* @__PURE__ */ jsx2(PaneTitle, { label: "TRAFFIC", extra: `${trafficLabel} \xB7 peak ${Math.max(0, ...traffic)} \xB7 red = denials`, width: leftW }),
|
|
773
819
|
/* @__PURE__ */ jsx2(ColumnChart, { series: traffic, hot: trafficHot, height: chartH, width: leftW, color: theme.accent })
|
|
@@ -777,39 +823,38 @@ function LivePanel({ active: active2 }) {
|
|
|
777
823
|
/* @__PURE__ */ jsx2(ColumnChart, { series: lat, hot: lat.map((v) => v > latHotAt), height: chartH, width: rightW, color: "#82AAF0", hotColor: "#ffb454" })
|
|
778
824
|
] })
|
|
779
825
|
] }),
|
|
780
|
-
/* @__PURE__ */ jsxs2(Box2, { children: [
|
|
781
|
-
/* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", width: colW, marginRight: 2, children: [
|
|
826
|
+
/* @__PURE__ */ jsxs2(Box2, { height: colH, children: [
|
|
827
|
+
/* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", width: colW, marginRight: 2, overflow: "hidden", children: [
|
|
782
828
|
/* @__PURE__ */ jsx2(PaneTitle, { label: "LAYERS", width: colW }),
|
|
783
829
|
/* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
784
830
|
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "RATELIMIT ".padEnd(10) }),
|
|
785
831
|
/* @__PURE__ */ jsx2(Text2, { color: rl?.mode === "block" ? theme.ok : rl?.mode === "detect" ? theme.warn : theme.dim, children: (rl?.mode ?? "?").padEnd(7) }),
|
|
786
|
-
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: rl?.perMinute ? `${minuteNow}/${rl.perMinute}
|
|
832
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: rl?.perMinute ? `${minuteNow}/${rl.perMinute}m ${rl.perHour || "\u2014"}h ${rl.perDay || "\u2014"}d` : "no limits set" })
|
|
787
833
|
] }),
|
|
788
|
-
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,
|
|
834
|
+
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,
|
|
789
835
|
/* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
790
836
|
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "DLP".padEnd(10) }),
|
|
791
837
|
/* @__PURE__ */ jsx2(Text2, { color: dl?.mode === "block" ? theme.ok : dl?.mode === "detect" ? theme.warn : theme.dim, children: (dl?.mode ?? "?").padEnd(7) }),
|
|
792
|
-
/* @__PURE__ */
|
|
793
|
-
(dl?.patterns ?? []).length,
|
|
794
|
-
" patterns armed"
|
|
795
|
-
] })
|
|
838
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: `${(dl?.patterns ?? []).length} builtin \xB7 ${(dl?.custom ?? []).length} custom` })
|
|
796
839
|
] }),
|
|
797
840
|
dlpBars.length ? dlpBars.map((d) => /* @__PURE__ */ jsx2(HBar, { label: truncate(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" }),
|
|
798
|
-
|
|
841
|
+
/* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
799
842
|
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "GUARD".padEnd(10) }),
|
|
800
|
-
/* @__PURE__ */
|
|
801
|
-
|
|
802
|
-
|
|
843
|
+
ring ? /* @__PURE__ */ jsxs2(Text2, { color: theme.ok, children: [
|
|
844
|
+
"local \u2713 ",
|
|
845
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: `eval avg ${ring.avgMs}ms` })
|
|
846
|
+
] }) : /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "no local ring in cwd" })
|
|
847
|
+
] })
|
|
803
848
|
] }),
|
|
804
|
-
/* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", width: colW, marginRight: 2, children: [
|
|
805
|
-
/* @__PURE__ */ jsx2(PaneTitle, { label: "SESSIONS", extra: `${localSessList.length} local \xB7 ${sessCounts?.active ?? 0} cloud
|
|
849
|
+
/* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", width: colW, marginRight: 2, overflow: "hidden", children: [
|
|
850
|
+
/* @__PURE__ */ jsx2(PaneTitle, { label: "SESSIONS", extra: `${localSessList.length} local \xB7 ${sessCounts?.active ?? 0} cloud`, width: colW }),
|
|
806
851
|
localSessList.length === 0 && sess.length === 0 ? /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "scanning\u2026" }) : null,
|
|
807
852
|
localSessList.slice(0, Math.max(1, colH - 2)).map(([id, v]) => {
|
|
808
|
-
const
|
|
853
|
+
const freshDot = nowMs - v.lastAt < 9e4;
|
|
809
854
|
const isMe = ring?.session === id;
|
|
810
855
|
return /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
811
|
-
/* @__PURE__ */ jsxs2(Text2, { color:
|
|
812
|
-
|
|
856
|
+
/* @__PURE__ */ jsxs2(Text2, { color: freshDot ? theme.ok : theme.dim, children: [
|
|
857
|
+
freshDot ? "\u25CF" : "\u25CB",
|
|
813
858
|
" "
|
|
814
859
|
] }),
|
|
815
860
|
/* @__PURE__ */ jsx2(Text2, { color: theme.ok, children: "LOC " }),
|
|
@@ -842,12 +887,12 @@ function LivePanel({ active: active2 }) {
|
|
|
842
887
|
String(a.denied_calls).padStart(3),
|
|
843
888
|
"d "
|
|
844
889
|
] }),
|
|
845
|
-
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: ago(a.last_seen_at) })
|
|
890
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: `t${a.trust_score} ` + ago(a.last_seen_at) })
|
|
846
891
|
] }, a.session_id);
|
|
847
892
|
})
|
|
848
893
|
] }),
|
|
849
|
-
/* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", width: colW, children: [
|
|
850
|
-
/* @__PURE__ */ jsx2(PaneTitle, { label: "EVENT LOG", extra: "
|
|
894
|
+
/* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", width: colW, overflow: "hidden", children: [
|
|
895
|
+
/* @__PURE__ */ jsx2(PaneTitle, { label: "EVENT LOG", extra: "system heartbeat", width: colW }),
|
|
851
896
|
log.slice(-(colH - 1)).map((l, i) => /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
852
897
|
/* @__PURE__ */ jsxs2(Text2, { color: theme.dim, children: [
|
|
853
898
|
hhmmss(l.ts),
|
|
@@ -858,33 +903,45 @@ function LivePanel({ active: active2 }) {
|
|
|
858
903
|
] }, l.ts + ":" + i))
|
|
859
904
|
] })
|
|
860
905
|
] }),
|
|
861
|
-
/* @__PURE__ */ jsx2(
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
"
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
/* @__PURE__ */
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
906
|
+
/* @__PURE__ */ jsx2(
|
|
907
|
+
PaneTitle,
|
|
908
|
+
{
|
|
909
|
+
label: "TOOL STREAM",
|
|
910
|
+
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`,
|
|
911
|
+
width: innerW
|
|
912
|
+
}
|
|
913
|
+
),
|
|
914
|
+
/* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", height: streamRows, overflow: "hidden", children: [
|
|
915
|
+
localOn === false ? /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
916
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.warn, children: "local logs off" }),
|
|
917
|
+
/* @__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`" })
|
|
918
|
+
] }) : null,
|
|
919
|
+
windowed.length === 0 ? /* @__PURE__ */ jsxs2(Text2, { color: theme.dim, children: [
|
|
920
|
+
spin,
|
|
921
|
+
" awaiting traffic\u2026"
|
|
922
|
+
] }) : null,
|
|
923
|
+
windowed.map((e) => /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
924
|
+
/* @__PURE__ */ jsxs2(Text2, { color: theme.dim, children: [
|
|
925
|
+
"[",
|
|
926
|
+
hhmmss(e.at),
|
|
927
|
+
" "
|
|
928
|
+
] }),
|
|
929
|
+
/* @__PURE__ */ jsx2(Text2, { color: e.source === "local" ? theme.ok : "#4f6db8", children: e.source === "local" ? "LOC" : "CLD" }),
|
|
930
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "] " }),
|
|
931
|
+
/* @__PURE__ */ jsx2(Text2, { color: decisionColor(e.decision), bold: e.decision !== "ALLOW", children: e.decision.padEnd(6) }),
|
|
932
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.accent, children: truncate(e.tool, 12).padEnd(13) }),
|
|
933
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: e.permission.padEnd(5) }),
|
|
934
|
+
/* @__PURE__ */ jsx2(Text2, { color: e.evalMs != null && e.evalMs > 500 ? theme.warn : theme.dim, children: (e.evalMs != null ? `${e.evalMs}ms` : "\u2014").padEnd(7) }),
|
|
935
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: truncate(e.agent ?? "-", 11).padEnd(12) }),
|
|
936
|
+
e.dlp ? /* @__PURE__ */ jsx2(Text2, { color: theme.bad, children: "DLP! " }) : null,
|
|
937
|
+
e.rule && e.decision !== "ALLOW" ? /* @__PURE__ */ jsx2(Text2, { color: theme.bad, children: truncate(e.rule, 14) + " " }) : null,
|
|
938
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: e.detail })
|
|
939
|
+
] }, e.id))
|
|
940
|
+
] }),
|
|
884
941
|
/* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
885
942
|
/* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", bold: true, children: " LIVE " }),
|
|
886
|
-
/* @__PURE__ */ jsx2(Text2, { backgroundColor: "#0b1530", color: "#4f6db8", children: ` local ${localOn ? "on" : "off"} \xB7 top ${topTools.map(([t, c2]) => `${t}\xD7${c2}`).join(" ") || "\u2014"}
|
|
887
|
-
/* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", children: "
|
|
943
|
+
/* @__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"} ` }),
|
|
944
|
+
/* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", children: " f filter \xB7 \u2191\u2193 scroll \xB7 c copy \xB7 esc menu \xB7 q quit " })
|
|
888
945
|
] })
|
|
889
946
|
] });
|
|
890
947
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@solongate/proxy",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.69.0",
|
|
4
4
|
"description": "AI tool security proxy: protect any AI tool server with customizable policies, path/command constraints, rate limiting, and audit logging. No code changes required.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|