@solongate/proxy 0.68.0 → 0.70.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 +348 -156
- package/dist/tui/index.js +318 -126
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -7020,12 +7020,13 @@ 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 {
|
|
7023
|
+
import { spawnSync } from "child_process";
|
|
7024
|
+
import { closeSync, mkdirSync as mkdirSync3, openSync, readSync, statSync, writeFileSync as writeFileSync3 } from "fs";
|
|
7024
7025
|
import { homedir as homedir3 } from "os";
|
|
7025
|
-
import { join as join5 } from "path";
|
|
7026
|
+
import { dirname, join as join5 } from "path";
|
|
7026
7027
|
import { useCallback as useCallback2, useEffect as useEffect2, useRef as useRef2, useState as useState2 } from "react";
|
|
7027
7028
|
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
7028
|
-
function tailLines(file, maxBytes =
|
|
7029
|
+
function tailLines(file, maxBytes = 131072) {
|
|
7029
7030
|
try {
|
|
7030
7031
|
const size = statSync(file).size;
|
|
7031
7032
|
const start = Math.max(0, size - maxBytes);
|
|
@@ -7040,6 +7041,22 @@ function tailLines(file, maxBytes = 65536) {
|
|
|
7040
7041
|
return [];
|
|
7041
7042
|
}
|
|
7042
7043
|
}
|
|
7044
|
+
function copyToClipboard(text) {
|
|
7045
|
+
const tools = [
|
|
7046
|
+
["wl-copy", []],
|
|
7047
|
+
["xclip", ["-selection", "clipboard"]],
|
|
7048
|
+
["xsel", ["--clipboard", "--input"]]
|
|
7049
|
+
];
|
|
7050
|
+
for (const [cmd, args] of tools) {
|
|
7051
|
+
try {
|
|
7052
|
+
const r = spawnSync(cmd, args, { input: text, timeout: 2e3 });
|
|
7053
|
+
if (r.status === 0) return cmd;
|
|
7054
|
+
} catch {
|
|
7055
|
+
}
|
|
7056
|
+
}
|
|
7057
|
+
process.stdout.write(`\x1B]52;c;${Buffer.from(text, "utf-8").toString("base64")}\x07`);
|
|
7058
|
+
return "osc52";
|
|
7059
|
+
}
|
|
7043
7060
|
function cloudItem(e) {
|
|
7044
7061
|
return {
|
|
7045
7062
|
id: "c:" + e.id,
|
|
@@ -7049,7 +7066,11 @@ function cloudItem(e) {
|
|
|
7049
7066
|
permission: (e.permission ?? "").slice(0, 4),
|
|
7050
7067
|
detail: (e.arguments_summary ? JSON.stringify(e.arguments_summary) : e.reason ?? "").replace(/\s+/g, " "),
|
|
7051
7068
|
dlp: !!e.dlp_matches?.length,
|
|
7052
|
-
source: "cloud"
|
|
7069
|
+
source: "cloud",
|
|
7070
|
+
session: e.session_id ?? void 0,
|
|
7071
|
+
agent: e.agent_name ?? void 0,
|
|
7072
|
+
evalMs: e.evaluation_time_ms ?? void 0,
|
|
7073
|
+
rule: e.matched_rule_id ?? void 0
|
|
7053
7074
|
};
|
|
7054
7075
|
}
|
|
7055
7076
|
function ColumnChart({ series, hot, height, width: width2, color, hotColor = theme.bad }) {
|
|
@@ -7068,7 +7089,7 @@ function ColumnChart({ series, hot, height, width: width2, color, hotColor = the
|
|
|
7068
7089
|
else if (frac >= (r - 0.5) / height) ch = "\u2584";
|
|
7069
7090
|
else if (r === 1) ch = "\u2581";
|
|
7070
7091
|
else ch = " ";
|
|
7071
|
-
const c2 = r === 1 && v === 0 ?
|
|
7092
|
+
const c2 = r === 1 && v === 0 ? DIM_FLOOR : hotPad?.[i] ? hotColor : color;
|
|
7072
7093
|
const last = segs[segs.length - 1];
|
|
7073
7094
|
if (last && last.color === c2) last.text += ch;
|
|
7074
7095
|
else segs.push({ text: ch, color: c2 });
|
|
@@ -7084,7 +7105,7 @@ function HBar({ label, value, max, width: width2, color }) {
|
|
|
7084
7105
|
return /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
7085
7106
|
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: label.padEnd(10) }),
|
|
7086
7107
|
/* @__PURE__ */ jsx2(Text2, { color, children: "\u2588".repeat(Math.min(width2, filled)) }),
|
|
7087
|
-
/* @__PURE__ */ jsx2(Text2, { color:
|
|
7108
|
+
/* @__PURE__ */ jsx2(Text2, { color: DIM_FLOOR, children: "\u2591".repeat(Math.max(0, width2 - filled)) }),
|
|
7088
7109
|
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " " + value })
|
|
7089
7110
|
] });
|
|
7090
7111
|
}
|
|
@@ -7100,6 +7121,25 @@ function PaneTitle({ label, extra, width: width2 }) {
|
|
|
7100
7121
|
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: tail + "\u2500".repeat(Math.max(0, width2 - used)) })
|
|
7101
7122
|
] });
|
|
7102
7123
|
}
|
|
7124
|
+
function StreamLine({ e }) {
|
|
7125
|
+
return /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
7126
|
+
/* @__PURE__ */ jsxs2(Text2, { color: theme.dim, children: [
|
|
7127
|
+
"[",
|
|
7128
|
+
hhmmss(e.at),
|
|
7129
|
+
" "
|
|
7130
|
+
] }),
|
|
7131
|
+
/* @__PURE__ */ jsx2(Text2, { color: e.source === "local" ? theme.ok : "#4f6db8", children: e.source === "local" ? "LOC" : "CLD" }),
|
|
7132
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "] " }),
|
|
7133
|
+
/* @__PURE__ */ jsx2(Text2, { color: decisionColor(e.decision), bold: e.decision !== "ALLOW", children: e.decision.padEnd(6) }),
|
|
7134
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.accent, children: truncate2(e.tool, 12).padEnd(13) }),
|
|
7135
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: e.permission.padEnd(5) }),
|
|
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) }),
|
|
7137
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: truncate2(e.agent ?? "-", 11).padEnd(12) }),
|
|
7138
|
+
e.dlp ? /* @__PURE__ */ jsx2(Text2, { color: theme.bad, children: "DLP! " }) : null,
|
|
7139
|
+
e.rule && e.decision !== "ALLOW" ? /* @__PURE__ */ jsx2(Text2, { color: theme.bad, children: truncate2(e.rule, 14) + " " }) : null,
|
|
7140
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: e.detail })
|
|
7141
|
+
] });
|
|
7142
|
+
}
|
|
7103
7143
|
function LivePanel({ active: active2 }) {
|
|
7104
7144
|
const [s, setS] = useState2(null);
|
|
7105
7145
|
const [tsData, setTsData] = useState2(null);
|
|
@@ -7109,18 +7149,17 @@ function LivePanel({ active: active2 }) {
|
|
|
7109
7149
|
const [localOn, setLocalOn] = useState2(null);
|
|
7110
7150
|
const [ring, setRing] = useState2(null);
|
|
7111
7151
|
const [log6, setLog] = useState2([]);
|
|
7152
|
+
const [filter, setFilter] = useState2("all");
|
|
7153
|
+
const [scroll, setScroll] = useState2(0);
|
|
7154
|
+
const [toast, setToast] = useState2(null);
|
|
7155
|
+
const [mode, setMode] = useState2("stream");
|
|
7156
|
+
const [pickIdx, setPickIdx] = useState2(0);
|
|
7157
|
+
const [detail, setDetail] = useState2(null);
|
|
7158
|
+
const [detailCloud, setDetailCloud] = useState2([]);
|
|
7159
|
+
const [detailScroll, setDetailScroll] = useState2(0);
|
|
7112
7160
|
const seenRef = useRef2(/* @__PURE__ */ new Set());
|
|
7113
7161
|
const lastLocalTs = useRef2(0);
|
|
7114
7162
|
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
7163
|
const pushLog = useCallback2((msg, level = "ok") => {
|
|
7125
7164
|
setLog((prev) => [...prev.slice(-59), { ts: Date.now(), msg, level }]);
|
|
7126
7165
|
}, []);
|
|
@@ -7136,9 +7175,8 @@ function LivePanel({ active: active2 }) {
|
|
|
7136
7175
|
},
|
|
7137
7176
|
[pushLog]
|
|
7138
7177
|
);
|
|
7139
|
-
const paused = () =>
|
|
7178
|
+
const paused = () => Date.now() < pausedUntil.current;
|
|
7140
7179
|
const pollLocal = useCallback2(() => {
|
|
7141
|
-
if (frozenRef.current) return;
|
|
7142
7180
|
const lines = tailLines(LOCAL_LOG);
|
|
7143
7181
|
if (!lines.length) {
|
|
7144
7182
|
setLocalOn((prev) => prev === null ? false : prev);
|
|
@@ -7161,7 +7199,9 @@ function LivePanel({ active: active2 }) {
|
|
|
7161
7199
|
dlp: !!j.dlp,
|
|
7162
7200
|
source: "local",
|
|
7163
7201
|
session: j.session_id,
|
|
7164
|
-
agent: j.agent_name
|
|
7202
|
+
agent: j.agent_name,
|
|
7203
|
+
evalMs: j.evaluation_time_ms,
|
|
7204
|
+
rule: j.matched_rule_id
|
|
7165
7205
|
});
|
|
7166
7206
|
} catch {
|
|
7167
7207
|
}
|
|
@@ -7170,9 +7210,7 @@ function LivePanel({ active: active2 }) {
|
|
|
7170
7210
|
lastLocalTs.current = fresh[fresh.length - 1].at;
|
|
7171
7211
|
setLocalBuf((prev) => [...prev, ...fresh].slice(-400));
|
|
7172
7212
|
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
|
-
}
|
|
7213
|
+
if (fresh.length < 10) pushLog(`local +${fresh.length} calls${denies ? ` \xB7 ${denies} DENIED` : ""}`, denies ? "bad" : "warn");
|
|
7176
7214
|
}
|
|
7177
7215
|
const ringLines = tailLines(RING, 8192).slice(-30);
|
|
7178
7216
|
if (ringLines.length) {
|
|
@@ -7209,12 +7247,11 @@ function LivePanel({ active: active2 }) {
|
|
|
7209
7247
|
const fresh = fd.entries.filter((e) => !seenRef.current.has(e.id));
|
|
7210
7248
|
const firstLoad = seenRef.current.size === 0 && fresh.length > 1;
|
|
7211
7249
|
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
|
-
}
|
|
7250
|
+
if (fresh.length) setCloudBuf((prev) => [...prev, ...fresh.map(cloudItem).sort((a, b) => a.at - b.at)].slice(-400));
|
|
7215
7251
|
const denies = fresh.filter((e) => e.decision !== "ALLOW").length;
|
|
7216
7252
|
if (firstLoad) pushLog(`cloud link up \xB7 api ${ms}ms \xB7 ${fresh.length} calls`);
|
|
7217
|
-
else pushLog(`api ${ms}ms \xB7 +${fresh.length} cloud${denies ? ` \xB7 ${denies} DENIED` : ""}`, denies ? "bad" :
|
|
7253
|
+
else if (fresh.length) pushLog(`api ${ms}ms \xB7 +${fresh.length} cloud${denies ? ` \xB7 ${denies} DENIED` : ""}`, denies ? "bad" : "warn");
|
|
7254
|
+
else pushLog(`api ${ms}ms \xB7 idle`, "ok");
|
|
7218
7255
|
} catch (e) {
|
|
7219
7256
|
onApiError(e);
|
|
7220
7257
|
}
|
|
@@ -7251,30 +7288,50 @@ function LivePanel({ active: active2 }) {
|
|
|
7251
7288
|
}, [active2, pollFeed, pollMedium, pollSlow]);
|
|
7252
7289
|
const sessions = useLoader(() => api.agents.live({ limit: 30, includeDeactivated: true }));
|
|
7253
7290
|
const insights = useLoader(() => api.stats.securityInsights(7));
|
|
7291
|
+
const guard = useLoader(() => api.settings.getGuardStatus());
|
|
7254
7292
|
usePoll(() => {
|
|
7255
7293
|
if (!paused()) sessions.reload();
|
|
7256
7294
|
}, 1e4, active2);
|
|
7257
7295
|
usePoll(() => {
|
|
7258
7296
|
if (!paused()) insights.reload();
|
|
7259
7297
|
}, 3e4, active2);
|
|
7298
|
+
usePoll(() => {
|
|
7299
|
+
if (!paused()) guard.reload();
|
|
7300
|
+
}, 6e4, active2);
|
|
7301
|
+
useEffect2(() => {
|
|
7302
|
+
if (!detail) return;
|
|
7303
|
+
setDetailCloud([]);
|
|
7304
|
+
setDetailScroll(0);
|
|
7305
|
+
let alive = true;
|
|
7306
|
+
api.audit.list({ session_id: detail.id, limit: 100 }).then((r) => {
|
|
7307
|
+
if (alive) setDetailCloud(r.entries.map(cloudItem));
|
|
7308
|
+
}).catch(() => {
|
|
7309
|
+
});
|
|
7310
|
+
return () => {
|
|
7311
|
+
alive = false;
|
|
7312
|
+
};
|
|
7313
|
+
}, [detail]);
|
|
7260
7314
|
const [tick, setTick] = useState2(0);
|
|
7261
7315
|
useEffect2(() => {
|
|
7262
|
-
if (!active2
|
|
7263
|
-
const t = setInterval(() => setTick((n) => n + 1),
|
|
7316
|
+
if (!active2) return;
|
|
7317
|
+
const t = setInterval(() => setTick((n) => n + 1), 500);
|
|
7264
7318
|
return () => clearInterval(t);
|
|
7265
|
-
}, [active2
|
|
7319
|
+
}, [active2]);
|
|
7266
7320
|
const startRef = useRef2(Date.now());
|
|
7267
7321
|
const cols = process.stdout.columns ?? 100;
|
|
7268
7322
|
const rows = process.stdout.rows ?? 30;
|
|
7269
7323
|
const ins = insights.data ?? {};
|
|
7270
7324
|
const spin = SPIN[tick % SPIN.length];
|
|
7271
|
-
const points = tsData?.timeseries ?? [];
|
|
7272
|
-
const mergedAll = [...cloudBuf, ...localBuf].sort((a, b) => a.at - b.at);
|
|
7273
7325
|
const nowMs = Date.now();
|
|
7326
|
+
const mergedAll = [...cloudBuf, ...localBuf].sort((a, b) => a.at - b.at);
|
|
7327
|
+
const filtered = filter === "all" ? mergedAll : mergedAll.filter((e) => e.source === filter);
|
|
7328
|
+
const visibleDesc = filtered.slice(-STREAM_KEEP).reverse();
|
|
7329
|
+
const points = tsData?.timeseries ?? [];
|
|
7330
|
+
const nowMin = Math.floor(nowMs / 6e4);
|
|
7274
7331
|
const minuteCounts = new Array(60).fill(0);
|
|
7275
7332
|
const minuteHot = new Array(60).fill(false);
|
|
7276
7333
|
for (const e of mergedAll) {
|
|
7277
|
-
const idx = 59 - Math.floor(
|
|
7334
|
+
const idx = 59 - (nowMin - Math.floor(e.at / 6e4));
|
|
7278
7335
|
if (idx >= 0 && idx < 60) {
|
|
7279
7336
|
minuteCounts[idx]++;
|
|
7280
7337
|
if (e.decision !== "ALLOW") minuteHot[idx] = true;
|
|
@@ -7286,14 +7343,14 @@ function LivePanel({ active: active2 }) {
|
|
|
7286
7343
|
const trafficLabel = localTraffic ? "calls/min \xB7 60m \xB7 local+cloud" : "24h \xB7 cloud";
|
|
7287
7344
|
const rl = ins.layers?.rateLimit;
|
|
7288
7345
|
const dl = ins.layers?.dlp;
|
|
7289
|
-
const
|
|
7346
|
+
const gh = ins.layers?.ghost;
|
|
7347
|
+
const minuteNow = minuteCounts[59] ?? 0;
|
|
7290
7348
|
const dlpBars = (ins.dlpByPattern ?? []).slice(0, 2);
|
|
7291
7349
|
const maxDlpBar = dlpBars[0]?.count ?? 1;
|
|
7292
|
-
const
|
|
7293
|
-
const
|
|
7294
|
-
const lastDeny = denials[denials.length - 1];
|
|
7350
|
+
const denialsAll = mergedAll.filter((e) => e.decision !== "ALLOW");
|
|
7351
|
+
const lastDeny = denialsAll[denialsAll.length - 1];
|
|
7295
7352
|
const toolCounts = /* @__PURE__ */ new Map();
|
|
7296
|
-
for (const e of
|
|
7353
|
+
for (const e of mergedAll) toolCounts.set(e.tool, (toolCounts.get(e.tool) ?? 0) + 1);
|
|
7297
7354
|
const topTools = [...toolCounts.entries()].sort((a, b) => b[1] - a[1]).slice(0, 3);
|
|
7298
7355
|
const latNow = lat[lat.length - 1] ?? 0;
|
|
7299
7356
|
const sortedLat = [...lat].sort((a, b) => a - b);
|
|
@@ -7312,22 +7369,174 @@ function LivePanel({ active: active2 }) {
|
|
|
7312
7369
|
if (e.agent) cur.agent = e.agent;
|
|
7313
7370
|
localSess.set(e.session, cur);
|
|
7314
7371
|
}
|
|
7315
|
-
const
|
|
7372
|
+
const combinedSess = [
|
|
7373
|
+
...[...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 })),
|
|
7374
|
+
...sess.filter((a) => !localSess.has(a.session_id)).map((a) => ({
|
|
7375
|
+
source: "cloud",
|
|
7376
|
+
id: a.session_id,
|
|
7377
|
+
agent: a.agent_name ?? a.session_id,
|
|
7378
|
+
calls: a.total_calls,
|
|
7379
|
+
denies: a.denied_calls,
|
|
7380
|
+
lastAt: Date.parse(a.last_seen_at),
|
|
7381
|
+
trust: a.trust_score,
|
|
7382
|
+
isMe: false
|
|
7383
|
+
}))
|
|
7384
|
+
];
|
|
7316
7385
|
const chartH = rows >= 36 ? 6 : 4;
|
|
7317
|
-
const colH = rows >= 32 ?
|
|
7318
|
-
const streamRows = Math.max(4, rows -
|
|
7319
|
-
const tail = merged.slice(-streamRows);
|
|
7386
|
+
const colH = rows >= 32 ? 7 : 5;
|
|
7387
|
+
const streamRows = Math.max(4, rows - 5 - (1 + chartH) - colH);
|
|
7320
7388
|
const innerW = cols - 2;
|
|
7321
7389
|
const leftW = Math.floor(innerW * 0.55);
|
|
7322
7390
|
const rightW = innerW - leftW - 2;
|
|
7323
7391
|
const colW = Math.max(20, Math.floor((innerW - 4) / 3));
|
|
7392
|
+
const pickable = combinedSess.slice(0, colH - 1);
|
|
7393
|
+
const maxScroll = Math.max(0, visibleDesc.length - streamRows);
|
|
7394
|
+
const clampedScroll = Math.min(scroll, maxScroll);
|
|
7395
|
+
const windowed = visibleDesc.slice(clampedScroll, clampedScroll + streamRows);
|
|
7396
|
+
const detailEntries = detail ? (() => {
|
|
7397
|
+
const seen = /* @__PURE__ */ new Set();
|
|
7398
|
+
const all = [];
|
|
7399
|
+
for (const e of [...detailCloud, ...mergedAll.filter((x) => x.session === detail.id)]) {
|
|
7400
|
+
const key = `${e.at}:${e.tool}:${e.decision}`;
|
|
7401
|
+
if (seen.has(key)) continue;
|
|
7402
|
+
seen.add(key);
|
|
7403
|
+
all.push(e);
|
|
7404
|
+
}
|
|
7405
|
+
return all.sort((a, b) => b.at - a.at);
|
|
7406
|
+
})() : [];
|
|
7407
|
+
useInput(
|
|
7408
|
+
(input, key) => {
|
|
7409
|
+
if (mode === "detail") {
|
|
7410
|
+
const maxD = Math.max(0, detailEntries.length - (rows - 10));
|
|
7411
|
+
if (key.leftArrow) {
|
|
7412
|
+
setMode("stream");
|
|
7413
|
+
setDetail(null);
|
|
7414
|
+
} else if (key.upArrow) setDetailScroll((n) => Math.max(0, n - 1));
|
|
7415
|
+
else if (key.downArrow) setDetailScroll((n) => Math.min(maxD, n + 1));
|
|
7416
|
+
else if (key.pageUp) setDetailScroll((n) => Math.max(0, n - 10));
|
|
7417
|
+
else if (key.pageDown) setDetailScroll((n) => Math.min(maxD, n + 10));
|
|
7418
|
+
return;
|
|
7419
|
+
}
|
|
7420
|
+
if (mode === "pick") {
|
|
7421
|
+
if (key.upArrow) setPickIdx((n) => Math.max(0, n - 1));
|
|
7422
|
+
else if (key.downArrow) setPickIdx((n) => Math.min(pickable.length - 1, n + 1));
|
|
7423
|
+
else if (key.return) {
|
|
7424
|
+
const row = pickable[pickIdx];
|
|
7425
|
+
if (row) {
|
|
7426
|
+
setDetail(row);
|
|
7427
|
+
setMode("detail");
|
|
7428
|
+
}
|
|
7429
|
+
} else if (input === "s" || key.leftArrow) setMode("stream");
|
|
7430
|
+
return;
|
|
7431
|
+
}
|
|
7432
|
+
if (input === "f") {
|
|
7433
|
+
setFilter((f) => FILTERS[(FILTERS.indexOf(f) + 1) % FILTERS.length]);
|
|
7434
|
+
setScroll(0);
|
|
7435
|
+
} else if (input === "s") {
|
|
7436
|
+
setPickIdx(0);
|
|
7437
|
+
setMode("pick");
|
|
7438
|
+
} else if (key.downArrow) setScroll((n) => Math.min(maxScroll, n + 1));
|
|
7439
|
+
else if (key.upArrow) setScroll((n) => Math.max(0, n - 1));
|
|
7440
|
+
else if (key.pageDown) setScroll((n) => Math.min(maxScroll, n + streamRows));
|
|
7441
|
+
else if (key.pageUp) setScroll((n) => Math.max(0, n - streamRows));
|
|
7442
|
+
else if (input === "c") {
|
|
7443
|
+
const dump = visibleDesc.map(
|
|
7444
|
+
(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}`
|
|
7445
|
+
).join("\n");
|
|
7446
|
+
let via = "file";
|
|
7447
|
+
try {
|
|
7448
|
+
mkdirSync3(dirname(DUMP), { recursive: true });
|
|
7449
|
+
writeFileSync3(DUMP, dump + "\n");
|
|
7450
|
+
} catch {
|
|
7451
|
+
}
|
|
7452
|
+
via = copyToClipboard(dump);
|
|
7453
|
+
setToast({ msg: `copied ${visibleDesc.length} lines via ${via} + ${DUMP}`, until: Date.now() + 5e3 });
|
|
7454
|
+
}
|
|
7455
|
+
},
|
|
7456
|
+
{ isActive: active2 }
|
|
7457
|
+
);
|
|
7324
7458
|
const sessionDot = (st) => st === "active" ? { ch: "\u25CF", color: theme.ok } : st === "idle" ? { ch: "\u25CC", color: theme.warn } : { ch: "\u25CB", color: theme.dim };
|
|
7459
|
+
void sessionDot;
|
|
7460
|
+
if (s === null && localOn === null) {
|
|
7461
|
+
return /* @__PURE__ */ jsxs2(Text2, { color: theme.dim, children: [
|
|
7462
|
+
spin,
|
|
7463
|
+
" connecting\u2026"
|
|
7464
|
+
] });
|
|
7465
|
+
}
|
|
7466
|
+
const titleBar = /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
7467
|
+
/* @__PURE__ */ jsx2(Text2, { backgroundColor: "#1432A0", color: "#AAC8FA", bold: true, children: " SOLONGATE LIVE " }),
|
|
7468
|
+
/* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", children: ` ${spin} up ${fmtUp(nowMs - startRef.current)} \xB7 ${hhmmss(nowMs)} \xB7 api ${latNow}ms ` }),
|
|
7469
|
+
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 " }),
|
|
7470
|
+
toast && nowMs < toast.until ? /* @__PURE__ */ jsx2(Text2, { backgroundColor: "#123d1f", color: "#7bd88f", bold: true, children: ` ${toast.msg} ` }) : null
|
|
7471
|
+
] });
|
|
7472
|
+
if (mode === "detail" && detail) {
|
|
7473
|
+
const d = detailEntries;
|
|
7474
|
+
const allow = d.filter((e) => e.decision === "ALLOW").length;
|
|
7475
|
+
const deny = d.length - allow;
|
|
7476
|
+
const dlpN = d.filter((e) => e.dlp).length;
|
|
7477
|
+
const evals = d.filter((e) => e.evalMs != null).map((e) => e.evalMs);
|
|
7478
|
+
const evalAvg = evals.length ? Math.round(evals.reduce((a, b) => a + b, 0) / evals.length) : null;
|
|
7479
|
+
const tCounts = /* @__PURE__ */ new Map();
|
|
7480
|
+
const pCounts = /* @__PURE__ */ new Map();
|
|
7481
|
+
for (const e of d) {
|
|
7482
|
+
tCounts.set(e.tool, (tCounts.get(e.tool) ?? 0) + 1);
|
|
7483
|
+
if (e.permission) pCounts.set(e.permission, (pCounts.get(e.permission) ?? 0) + 1);
|
|
7484
|
+
}
|
|
7485
|
+
const top = [...tCounts.entries()].sort((a, b) => b[1] - a[1]).slice(0, 6);
|
|
7486
|
+
const perms = [...pCounts.entries()].sort((a, b) => b[1] - a[1]);
|
|
7487
|
+
const first = d[d.length - 1]?.at;
|
|
7488
|
+
const last = d[0]?.at;
|
|
7489
|
+
const tlRows = Math.max(4, rows - 10);
|
|
7490
|
+
const maxD = Math.max(0, d.length - tlRows);
|
|
7491
|
+
const dScroll = Math.min(detailScroll, maxD);
|
|
7492
|
+
const tl = d.slice(dScroll, dScroll + tlRows);
|
|
7493
|
+
return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", paddingX: 1, children: [
|
|
7494
|
+
titleBar,
|
|
7495
|
+
/* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
7496
|
+
/* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#AAC8FA", bold: true, children: ` SESSION ${detail.id.slice(0, 8)} ` }),
|
|
7497
|
+
/* @__PURE__ */ jsx2(Text2, { color: detail.source === "local" ? theme.ok : "#4f6db8", children: " " + detail.source.toUpperCase() }),
|
|
7498
|
+
/* @__PURE__ */ jsx2(Text2, { bold: true, children: " " + truncate2(detail.isMe ? detail.agent + " (this machine)" : detail.agent, 34) }),
|
|
7499
|
+
detail.trust != null ? /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: ` trust ${detail.trust}/100` }) : null,
|
|
7500
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2190 back" })
|
|
7501
|
+
] }),
|
|
7502
|
+
/* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
7503
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "\u2502 calls " }),
|
|
7504
|
+
/* @__PURE__ */ jsx2(Text2, { bold: true, children: d.length }),
|
|
7505
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502 allow " }),
|
|
7506
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.ok, children: allow }),
|
|
7507
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502 deny " }),
|
|
7508
|
+
/* @__PURE__ */ jsx2(Text2, { color: deny ? theme.bad : theme.dim, bold: deny > 0, children: deny }),
|
|
7509
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502 dlp " }),
|
|
7510
|
+
/* @__PURE__ */ jsx2(Text2, { color: dlpN ? theme.bad : theme.dim, children: dlpN }),
|
|
7511
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502 avg eval " }),
|
|
7512
|
+
/* @__PURE__ */ jsx2(Text2, { children: evalAvg != null ? `${evalAvg}ms` : "\u2014" }),
|
|
7513
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502 first " }),
|
|
7514
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: first ? `${hhmmss(first)} (${ago(first)} ago)` : "\u2014" }),
|
|
7515
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502 last " }),
|
|
7516
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: last ? `${hhmmss(last)} (${ago(last)} ago)` : "\u2014" }),
|
|
7517
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502" })
|
|
7518
|
+
] }),
|
|
7519
|
+
/* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
7520
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "\u2502 tools " }),
|
|
7521
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.accent, children: top.map(([t, c2]) => `${t}\xD7${c2}`).join(" ") || "\u2014" }),
|
|
7522
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502 perms " }),
|
|
7523
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: perms.map(([p, c2]) => `${p}\xD7${c2}`).join(" ") || "\u2014" }),
|
|
7524
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502" })
|
|
7525
|
+
] }),
|
|
7526
|
+
/* @__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 }),
|
|
7527
|
+
/* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", height: tlRows, overflow: "hidden", children: [
|
|
7528
|
+
tl.length === 0 ? /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: detailCloud.length === 0 ? spin + " loading history\u2026" : "no entries" }) : null,
|
|
7529
|
+
tl.map((e) => /* @__PURE__ */ jsx2(StreamLine, { e }, e.id))
|
|
7530
|
+
] }),
|
|
7531
|
+
/* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
7532
|
+
/* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", bold: true, children: " SESSION " }),
|
|
7533
|
+
/* @__PURE__ */ jsx2(Text2, { backgroundColor: "#0b1530", color: "#4f6db8", children: ` ${detail.id} ` }),
|
|
7534
|
+
/* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", children: " \u2191\u2193 scroll \xB7 \u2190 back \xB7 esc menu " })
|
|
7535
|
+
] })
|
|
7536
|
+
] });
|
|
7537
|
+
}
|
|
7325
7538
|
return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", paddingX: 1, children: [
|
|
7326
|
-
|
|
7327
|
-
/* @__PURE__ */ jsx2(Text2, { backgroundColor: "#1432A0", color: "#AAC8FA", bold: true, children: " SOLONGATE LIVE " }),
|
|
7328
|
-
/* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", children: ` ${spin} up ${fmtUp(Date.now() - startRef.current)} \xB7 ${hhmmss(Date.now())} \xB7 api ${latNow}ms ` }),
|
|
7329
|
-
frozen ? /* @__PURE__ */ jsx2(Text2, { backgroundColor: "#3d2a12", color: "#ffb454", bold: true, children: " PAUSED \xB7 copy freely \xB7 p 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 " })
|
|
7330
|
-
] }),
|
|
7539
|
+
titleBar,
|
|
7331
7540
|
/* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
7332
7541
|
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "\u2502 calls " }),
|
|
7333
7542
|
/* @__PURE__ */ jsx2(Text2, { bold: true, children: s ? s.total_calls : "\xB7\xB7\xB7\xB7" }),
|
|
@@ -7336,16 +7545,20 @@ function LivePanel({ active: active2 }) {
|
|
|
7336
7545
|
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502 deny " }),
|
|
7337
7546
|
/* @__PURE__ */ jsx2(Text2, { color: theme.bad, bold: true, children: s ? s.denied : "\xB7\xB7" }),
|
|
7338
7547
|
/* @__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
|
|
7548
|
+
localOn ? /* @__PURE__ */ jsx2(Text2, { color: theme.ok, children: "\u2713" }) : /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "off" }),
|
|
7549
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502 rl " }),
|
|
7341
7550
|
/* @__PURE__ */ jsx2(Text2, { color: rl?.mode === "block" ? theme.ok : rl?.mode === "detect" ? theme.warn : theme.dim, children: rl?.mode ?? "?" }),
|
|
7342
7551
|
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502 dlp " }),
|
|
7343
7552
|
/* @__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:
|
|
7553
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502 ghost " }),
|
|
7554
|
+
/* @__PURE__ */ jsx2(Text2, { color: gh?.mode === "on" ? theme.ok : theme.dim, children: gh?.mode ?? "?" }),
|
|
7555
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502 sess " }),
|
|
7556
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.accent, children: `${combinedSess.length} (${sessCounts?.active ?? 0} live)` }),
|
|
7557
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502 hooks " }),
|
|
7558
|
+
/* @__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
7559
|
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502" })
|
|
7347
7560
|
] }),
|
|
7348
|
-
/* @__PURE__ */ jsxs2(Box2, { children: [
|
|
7561
|
+
/* @__PURE__ */ jsxs2(Box2, { height: 1 + chartH, children: [
|
|
7349
7562
|
/* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", width: leftW, marginRight: 2, children: [
|
|
7350
7563
|
/* @__PURE__ */ jsx2(PaneTitle, { label: "TRAFFIC", extra: `${trafficLabel} \xB7 peak ${Math.max(0, ...traffic)} \xB7 red = denials`, width: leftW }),
|
|
7351
7564
|
/* @__PURE__ */ jsx2(ColumnChart, { series: traffic, hot: trafficHot, height: chartH, width: leftW, color: theme.accent })
|
|
@@ -7355,77 +7568,56 @@ function LivePanel({ active: active2 }) {
|
|
|
7355
7568
|
/* @__PURE__ */ jsx2(ColumnChart, { series: lat, hot: lat.map((v) => v > latHotAt), height: chartH, width: rightW, color: "#82AAF0", hotColor: "#ffb454" })
|
|
7356
7569
|
] })
|
|
7357
7570
|
] }),
|
|
7358
|
-
/* @__PURE__ */ jsxs2(Box2, { children: [
|
|
7359
|
-
/* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", width: colW, marginRight: 2, children: [
|
|
7571
|
+
/* @__PURE__ */ jsxs2(Box2, { height: colH, children: [
|
|
7572
|
+
/* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", width: colW, marginRight: 2, overflow: "hidden", children: [
|
|
7360
7573
|
/* @__PURE__ */ jsx2(PaneTitle, { label: "LAYERS", width: colW }),
|
|
7361
7574
|
/* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
7362
7575
|
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "RATELIMIT ".padEnd(10) }),
|
|
7363
7576
|
/* @__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}
|
|
7577
|
+
/* @__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
7578
|
] }),
|
|
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,
|
|
7579
|
+
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
7580
|
/* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
7368
7581
|
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "DLP".padEnd(10) }),
|
|
7369
7582
|
/* @__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
|
-
] })
|
|
7583
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: `${(dl?.patterns ?? []).length} builtin \xB7 ${(dl?.custom ?? []).length} custom` })
|
|
7374
7584
|
] }),
|
|
7375
|
-
dlpBars.length ? dlpBars.map((
|
|
7376
|
-
|
|
7585
|
+
dlpBars.length ? dlpBars.map((d2) => /* @__PURE__ */ jsx2(HBar, { label: truncate2(d2.pattern, 10), value: d2.count, max: maxDlpBar, width: Math.max(6, colW - 16), color: theme.bad }, d2.pattern)) : /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " no dlp hits in last 7 days" }),
|
|
7586
|
+
/* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
7377
7587
|
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "GUARD".padEnd(10) }),
|
|
7378
|
-
/* @__PURE__ */
|
|
7379
|
-
|
|
7380
|
-
|
|
7588
|
+
ring ? /* @__PURE__ */ jsxs2(Text2, { color: theme.ok, children: [
|
|
7589
|
+
"local \u2713 ",
|
|
7590
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: `eval avg ${ring.avgMs}ms` })
|
|
7591
|
+
] }) : /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "no local ring in cwd" })
|
|
7592
|
+
] })
|
|
7381
7593
|
] }),
|
|
7382
|
-
/* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", width: colW, marginRight: 2, children: [
|
|
7383
|
-
/* @__PURE__ */ jsx2(PaneTitle, { label: "SESSIONS", extra: `${
|
|
7384
|
-
|
|
7385
|
-
|
|
7386
|
-
const
|
|
7387
|
-
const
|
|
7388
|
-
return /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
7389
|
-
/* @__PURE__ */ jsxs2(Text2, { color:
|
|
7390
|
-
|
|
7391
|
-
" "
|
|
7392
|
-
] }),
|
|
7393
|
-
/* @__PURE__ */ jsx2(Text2, { color: theme.ok, children: "LOC " }),
|
|
7394
|
-
/* @__PURE__ */ jsx2(Text2, { color: theme.accentBright, bold: isMe, children: truncate2(isMe ? "this machine" : v.agent, 12).padEnd(13) }),
|
|
7395
|
-
/* @__PURE__ */ jsxs2(Text2, { children: [
|
|
7396
|
-
String(v.calls).padStart(4),
|
|
7397
|
-
"c "
|
|
7398
|
-
] }),
|
|
7399
|
-
/* @__PURE__ */ jsxs2(Text2, { color: v.denies ? theme.bad : theme.dim, children: [
|
|
7400
|
-
String(v.denies).padStart(3),
|
|
7401
|
-
"d "
|
|
7402
|
-
] }),
|
|
7403
|
-
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: ago(v.lastAt) })
|
|
7404
|
-
] }, id);
|
|
7405
|
-
}),
|
|
7406
|
-
sess.slice(0, Math.max(0, colH - 1 - Math.min(localSessList.length, Math.max(1, colH - 2)))).map((a) => {
|
|
7407
|
-
const dot = sessionDot(a.status);
|
|
7408
|
-
return /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
7409
|
-
/* @__PURE__ */ jsxs2(Text2, { color: dot.color, children: [
|
|
7410
|
-
dot.ch,
|
|
7594
|
+
/* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", width: colW, marginRight: 2, overflow: "hidden", children: [
|
|
7595
|
+
/* @__PURE__ */ jsx2(PaneTitle, { label: "SESSIONS", extra: mode === "pick" ? "\u2191\u2193 pick \xB7 enter open" : `${combinedSess.length} \xB7 s = inspect`, width: colW }),
|
|
7596
|
+
pickable.length === 0 ? /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "scanning\u2026" }) : null,
|
|
7597
|
+
pickable.map((r, i) => {
|
|
7598
|
+
const freshDot = nowMs - r.lastAt < 9e4;
|
|
7599
|
+
const sel = mode === "pick" && i === pickIdx;
|
|
7600
|
+
return /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", backgroundColor: sel ? "#1c2f63" : void 0, bold: sel || r.isMe, children: [
|
|
7601
|
+
/* @__PURE__ */ jsxs2(Text2, { color: sel ? theme.accentBright : freshDot ? theme.ok : theme.dim, children: [
|
|
7602
|
+
sel ? "\u25B8" : freshDot ? "\u25CF" : "\u25CB",
|
|
7411
7603
|
" "
|
|
7412
7604
|
] }),
|
|
7413
|
-
/* @__PURE__ */ jsx2(Text2, { color: "#4f6db8", children: "CLD " }),
|
|
7414
|
-
/* @__PURE__ */ jsx2(Text2, { color: theme.
|
|
7605
|
+
/* @__PURE__ */ jsx2(Text2, { color: r.source === "local" ? theme.ok : "#4f6db8", children: r.source === "local" ? "LOC " : "CLD " }),
|
|
7606
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.accentBright, children: truncate2(r.isMe ? "this machine" : r.agent, 12).padEnd(13) }),
|
|
7415
7607
|
/* @__PURE__ */ jsxs2(Text2, { children: [
|
|
7416
|
-
String(
|
|
7608
|
+
String(r.calls).padStart(4),
|
|
7417
7609
|
"c "
|
|
7418
7610
|
] }),
|
|
7419
|
-
/* @__PURE__ */ jsxs2(Text2, { color:
|
|
7420
|
-
String(
|
|
7611
|
+
/* @__PURE__ */ jsxs2(Text2, { color: r.denies ? theme.bad : theme.dim, children: [
|
|
7612
|
+
String(r.denies).padStart(3),
|
|
7421
7613
|
"d "
|
|
7422
7614
|
] }),
|
|
7423
|
-
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: ago(
|
|
7424
|
-
] },
|
|
7615
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: (r.trust != null ? `t${r.trust} ` : "") + ago(r.lastAt) })
|
|
7616
|
+
] }, r.id);
|
|
7425
7617
|
})
|
|
7426
7618
|
] }),
|
|
7427
|
-
/* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", width: colW, children: [
|
|
7428
|
-
/* @__PURE__ */ jsx2(PaneTitle, { label: "EVENT LOG", extra: "
|
|
7619
|
+
/* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", width: colW, overflow: "hidden", children: [
|
|
7620
|
+
/* @__PURE__ */ jsx2(PaneTitle, { label: "EVENT LOG", extra: "system heartbeat", width: colW }),
|
|
7429
7621
|
log6.slice(-(colH - 1)).map((l, i) => /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
7430
7622
|
/* @__PURE__ */ jsxs2(Text2, { color: theme.dim, children: [
|
|
7431
7623
|
hhmmss(l.ts),
|
|
@@ -7436,37 +7628,33 @@ function LivePanel({ active: active2 }) {
|
|
|
7436
7628
|
] }, l.ts + ":" + i))
|
|
7437
7629
|
] })
|
|
7438
7630
|
] }),
|
|
7439
|
-
/* @__PURE__ */ jsx2(
|
|
7440
|
-
|
|
7441
|
-
|
|
7442
|
-
|
|
7443
|
-
|
|
7444
|
-
|
|
7445
|
-
|
|
7446
|
-
|
|
7447
|
-
|
|
7448
|
-
|
|
7449
|
-
|
|
7450
|
-
"
|
|
7451
|
-
|
|
7452
|
-
|
|
7453
|
-
|
|
7454
|
-
|
|
7455
|
-
|
|
7456
|
-
/* @__PURE__ */ jsx2(
|
|
7457
|
-
|
|
7458
|
-
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: e.permission.padEnd(5) }),
|
|
7459
|
-
e.dlp ? /* @__PURE__ */ jsx2(Text2, { color: theme.bad, children: "DLP! " }) : null,
|
|
7460
|
-
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: e.detail })
|
|
7461
|
-
] }, e.id)),
|
|
7631
|
+
/* @__PURE__ */ jsx2(
|
|
7632
|
+
PaneTitle,
|
|
7633
|
+
{
|
|
7634
|
+
label: "TOOL STREAM",
|
|
7635
|
+
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`,
|
|
7636
|
+
width: innerW
|
|
7637
|
+
}
|
|
7638
|
+
),
|
|
7639
|
+
/* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", height: streamRows, overflow: "hidden", children: [
|
|
7640
|
+
localOn === false ? /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
7641
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.warn, children: "local logs off" }),
|
|
7642
|
+
/* @__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`" })
|
|
7643
|
+
] }) : null,
|
|
7644
|
+
windowed.length === 0 ? /* @__PURE__ */ jsxs2(Text2, { color: theme.dim, children: [
|
|
7645
|
+
spin,
|
|
7646
|
+
" awaiting traffic\u2026"
|
|
7647
|
+
] }) : null,
|
|
7648
|
+
windowed.map((e) => /* @__PURE__ */ jsx2(StreamLine, { e }, e.id))
|
|
7649
|
+
] }),
|
|
7462
7650
|
/* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
7463
7651
|
/* @__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: "
|
|
7652
|
+
/* @__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"} ` }),
|
|
7653
|
+
/* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", children: " f filter \xB7 s sessions \xB7 c copy \xB7 esc menu \xB7 q quit " })
|
|
7466
7654
|
] })
|
|
7467
7655
|
] });
|
|
7468
7656
|
}
|
|
7469
|
-
var SPIN, BG, LOCAL_LOG, RING, hhmmss, fmtUp;
|
|
7657
|
+
var SPIN, BG, DIM_FLOOR, LOCAL_LOG, RING, DUMP, STREAM_KEEP, hhmmss, fmtUp, FILTERS;
|
|
7470
7658
|
var init_Live = __esm({
|
|
7471
7659
|
"src/tui/panels/Live.tsx"() {
|
|
7472
7660
|
"use strict";
|
|
@@ -7475,8 +7663,11 @@ var init_Live = __esm({
|
|
|
7475
7663
|
init_theme();
|
|
7476
7664
|
SPIN = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
7477
7665
|
BG = "#12234f";
|
|
7666
|
+
DIM_FLOOR = "#233457";
|
|
7478
7667
|
LOCAL_LOG = join5(homedir3(), ".solongate", "local-logs", "solongate-audit.jsonl");
|
|
7479
7668
|
RING = join5(process.cwd(), ".solongate", ".eval-ring.jsonl");
|
|
7669
|
+
DUMP = join5(homedir3(), ".solongate", "live-stream.log");
|
|
7670
|
+
STREAM_KEEP = 100;
|
|
7480
7671
|
hhmmss = (ts) => {
|
|
7481
7672
|
const d = new Date(ts);
|
|
7482
7673
|
return Number.isNaN(d.getTime()) ? "--:--:--" : d.toTimeString().slice(0, 8);
|
|
@@ -7486,6 +7677,7 @@ var init_Live = __esm({
|
|
|
7486
7677
|
const p = (n) => String(n).padStart(2, "0");
|
|
7487
7678
|
return `${p(Math.floor(s / 3600))}:${p(Math.floor(s % 3600 / 60))}:${p(s % 60)}`;
|
|
7488
7679
|
};
|
|
7680
|
+
FILTERS = ["all", "local", "cloud"];
|
|
7489
7681
|
}
|
|
7490
7682
|
});
|
|
7491
7683
|
|
|
@@ -9147,8 +9339,8 @@ __export(global_install_exports, {
|
|
|
9147
9339
|
runGlobalRestore: () => runGlobalRestore,
|
|
9148
9340
|
unlockProtected: () => unlockProtected
|
|
9149
9341
|
});
|
|
9150
|
-
import { readFileSync as readFileSync6, writeFileSync as
|
|
9151
|
-
import { resolve as resolve4, join as join6, dirname } from "path";
|
|
9342
|
+
import { readFileSync as readFileSync6, writeFileSync as writeFileSync4, existsSync as existsSync4, mkdirSync as mkdirSync4 } from "fs";
|
|
9343
|
+
import { resolve as resolve4, join as join6, dirname as dirname2 } from "path";
|
|
9152
9344
|
import { homedir as homedir4 } from "os";
|
|
9153
9345
|
import { fileURLToPath } from "url";
|
|
9154
9346
|
import { createInterface } from "readline";
|
|
@@ -9260,13 +9452,13 @@ function runGlobalRestore() {
|
|
|
9260
9452
|
unlockProtected();
|
|
9261
9453
|
removeClaudeShim();
|
|
9262
9454
|
if (existsSync4(p.backupPath)) {
|
|
9263
|
-
|
|
9455
|
+
writeFileSync4(p.settingsPath, readFileSync6(p.backupPath, "utf-8"));
|
|
9264
9456
|
console.log(` Restored ${p.settingsPath} from backup.`);
|
|
9265
9457
|
} else if (existsSync4(p.settingsPath)) {
|
|
9266
9458
|
try {
|
|
9267
9459
|
const s = JSON.parse(readFileSync6(p.settingsPath, "utf-8"));
|
|
9268
9460
|
delete s.hooks;
|
|
9269
|
-
|
|
9461
|
+
writeFileSync4(p.settingsPath, JSON.stringify(s, null, 2) + "\n");
|
|
9270
9462
|
console.log(` Removed SolonGate hooks from ${p.settingsPath}.`);
|
|
9271
9463
|
} catch {
|
|
9272
9464
|
}
|
|
@@ -9310,8 +9502,8 @@ function writeShimBlock(file, block) {
|
|
|
9310
9502
|
if (content.length && !content.endsWith("\n")) content += "\n";
|
|
9311
9503
|
content += block + "\n";
|
|
9312
9504
|
}
|
|
9313
|
-
|
|
9314
|
-
|
|
9505
|
+
mkdirSync4(dirname2(file), { recursive: true });
|
|
9506
|
+
writeFileSync4(file, content);
|
|
9315
9507
|
}
|
|
9316
9508
|
function installClaudeShim(shieldPath) {
|
|
9317
9509
|
const real = resolveRealClaude();
|
|
@@ -9368,22 +9560,22 @@ async function runGlobalInstall(opts = {}) {
|
|
|
9368
9560
|
process.exit(1);
|
|
9369
9561
|
}
|
|
9370
9562
|
const apiUrl = opts.apiUrl || process.env["SOLONGATE_API_URL"] || "https://api.solongate.com";
|
|
9371
|
-
|
|
9372
|
-
|
|
9563
|
+
mkdirSync4(p.hooksDir, { recursive: true });
|
|
9564
|
+
mkdirSync4(p.claudeDir, { recursive: true });
|
|
9373
9565
|
unlockProtected();
|
|
9374
|
-
|
|
9375
|
-
|
|
9376
|
-
|
|
9377
|
-
|
|
9566
|
+
writeFileSync4(join6(p.hooksDir, "guard.mjs"), readGuard());
|
|
9567
|
+
writeFileSync4(join6(p.hooksDir, "audit.mjs"), readHook("audit.mjs"));
|
|
9568
|
+
writeFileSync4(join6(p.hooksDir, "stop.mjs"), readHook("stop.mjs"));
|
|
9569
|
+
writeFileSync4(join6(p.hooksDir, "shield.mjs"), readHook("shield.mjs"));
|
|
9378
9570
|
console.log(` Installed hooks \u2192 ${p.hooksDir}`);
|
|
9379
9571
|
removeClaudeShim();
|
|
9380
|
-
|
|
9572
|
+
writeFileSync4(p.configPath, JSON.stringify({ apiKey, apiUrl }, null, 2) + "\n");
|
|
9381
9573
|
console.log(` Wrote ${p.configPath}`);
|
|
9382
9574
|
let existing = {};
|
|
9383
9575
|
if (existsSync4(p.settingsPath)) {
|
|
9384
9576
|
const raw = readFileSync6(p.settingsPath, "utf-8");
|
|
9385
9577
|
if (!existsSync4(p.backupPath)) {
|
|
9386
|
-
|
|
9578
|
+
writeFileSync4(p.backupPath, raw);
|
|
9387
9579
|
console.log(` Backed up existing settings \u2192 ${p.backupPath}`);
|
|
9388
9580
|
}
|
|
9389
9581
|
try {
|
|
@@ -9404,7 +9596,7 @@ async function runGlobalInstall(opts = {}) {
|
|
|
9404
9596
|
Stop: [{ matcher: "", hooks: [{ type: "command", command: `"${nodeBin}" "${stopAbs}" claude-code "Claude Code"` }] }]
|
|
9405
9597
|
}
|
|
9406
9598
|
};
|
|
9407
|
-
|
|
9599
|
+
writeFileSync4(p.settingsPath, JSON.stringify(merged, null, 2) + "\n");
|
|
9408
9600
|
console.log(` Registered global hooks \u2192 ${p.settingsPath}`);
|
|
9409
9601
|
if (process.env["SOLONGATE_OS_LOCK"] === "1") {
|
|
9410
9602
|
lockProtected();
|
|
@@ -9418,7 +9610,7 @@ var __dirname, HOOKS_DIR, SHIM_BEGIN, SHIM_END;
|
|
|
9418
9610
|
var init_global_install = __esm({
|
|
9419
9611
|
"src/global-install.ts"() {
|
|
9420
9612
|
"use strict";
|
|
9421
|
-
__dirname =
|
|
9613
|
+
__dirname = dirname2(fileURLToPath(import.meta.url));
|
|
9422
9614
|
HOOKS_DIR = resolve4(__dirname, "..", "hooks");
|
|
9423
9615
|
SHIM_BEGIN = "# >>> SolonGate shield (auto secret redaction) >>>";
|
|
9424
9616
|
SHIM_END = "# <<< SolonGate shield <<<";
|
|
@@ -10068,7 +10260,7 @@ var init_logs_server = __esm({
|
|
|
10068
10260
|
|
|
10069
10261
|
// src/inject.ts
|
|
10070
10262
|
var inject_exports = {};
|
|
10071
|
-
import { readFileSync as readFileSync9, writeFileSync as
|
|
10263
|
+
import { readFileSync as readFileSync9, writeFileSync as writeFileSync5, existsSync as existsSync6, copyFileSync } from "fs";
|
|
10072
10264
|
import { resolve as resolve7 } from "path";
|
|
10073
10265
|
import { execSync } from "child_process";
|
|
10074
10266
|
function parseInjectArgs(argv) {
|
|
@@ -10376,7 +10568,7 @@ async function main2() {
|
|
|
10376
10568
|
log3("");
|
|
10377
10569
|
log3(` Backup: ${backupPath}`);
|
|
10378
10570
|
}
|
|
10379
|
-
|
|
10571
|
+
writeFileSync5(entryFile, result.modified);
|
|
10380
10572
|
log3("");
|
|
10381
10573
|
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
10574
|
log3(" \u2502 SolonGate SDK injected successfully! \u2502");
|
|
@@ -10405,7 +10597,7 @@ var init_inject = __esm({
|
|
|
10405
10597
|
|
|
10406
10598
|
// src/create.ts
|
|
10407
10599
|
var create_exports = {};
|
|
10408
|
-
import { mkdirSync as
|
|
10600
|
+
import { mkdirSync as mkdirSync5, writeFileSync as writeFileSync6, existsSync as existsSync7 } from "fs";
|
|
10409
10601
|
import { resolve as resolve8, join as join8 } from "path";
|
|
10410
10602
|
import { execSync as execSync2 } from "child_process";
|
|
10411
10603
|
function withSpinner(message, fn) {
|
|
@@ -10485,7 +10677,7 @@ EXAMPLES
|
|
|
10485
10677
|
`);
|
|
10486
10678
|
}
|
|
10487
10679
|
function createProject(dir, name, _policy) {
|
|
10488
|
-
|
|
10680
|
+
writeFileSync6(
|
|
10489
10681
|
join8(dir, "package.json"),
|
|
10490
10682
|
JSON.stringify(
|
|
10491
10683
|
{
|
|
@@ -10515,7 +10707,7 @@ function createProject(dir, name, _policy) {
|
|
|
10515
10707
|
2
|
|
10516
10708
|
) + "\n"
|
|
10517
10709
|
);
|
|
10518
|
-
|
|
10710
|
+
writeFileSync6(
|
|
10519
10711
|
join8(dir, "tsconfig.json"),
|
|
10520
10712
|
JSON.stringify(
|
|
10521
10713
|
{
|
|
@@ -10536,8 +10728,8 @@ function createProject(dir, name, _policy) {
|
|
|
10536
10728
|
2
|
|
10537
10729
|
) + "\n"
|
|
10538
10730
|
);
|
|
10539
|
-
|
|
10540
|
-
|
|
10731
|
+
mkdirSync5(join8(dir, "src"), { recursive: true });
|
|
10732
|
+
writeFileSync6(
|
|
10541
10733
|
join8(dir, "src", "index.ts"),
|
|
10542
10734
|
`#!/usr/bin/env node
|
|
10543
10735
|
|
|
@@ -10579,7 +10771,7 @@ console.log('');
|
|
|
10579
10771
|
console.log('Press Ctrl+C to stop.');
|
|
10580
10772
|
`
|
|
10581
10773
|
);
|
|
10582
|
-
|
|
10774
|
+
writeFileSync6(
|
|
10583
10775
|
join8(dir, ".mcp.json"),
|
|
10584
10776
|
JSON.stringify(
|
|
10585
10777
|
{
|
|
@@ -10597,12 +10789,12 @@ console.log('Press Ctrl+C to stop.');
|
|
|
10597
10789
|
2
|
|
10598
10790
|
) + "\n"
|
|
10599
10791
|
);
|
|
10600
|
-
|
|
10792
|
+
writeFileSync6(
|
|
10601
10793
|
join8(dir, ".env"),
|
|
10602
10794
|
`SOLONGATE_API_KEY=sg_live_YOUR_KEY_HERE
|
|
10603
10795
|
`
|
|
10604
10796
|
);
|
|
10605
|
-
|
|
10797
|
+
writeFileSync6(
|
|
10606
10798
|
join8(dir, ".gitignore"),
|
|
10607
10799
|
`node_modules/
|
|
10608
10800
|
dist/
|
|
@@ -10622,7 +10814,7 @@ async function main3() {
|
|
|
10622
10814
|
process.exit(1);
|
|
10623
10815
|
}
|
|
10624
10816
|
withSpinner(`Setting up ${opts.name}...`, () => {
|
|
10625
|
-
|
|
10817
|
+
mkdirSync5(dir, { recursive: true });
|
|
10626
10818
|
createProject(dir, opts.name, opts.policy);
|
|
10627
10819
|
});
|
|
10628
10820
|
if (!opts.noInstall) {
|
|
@@ -10696,7 +10888,7 @@ var init_create = __esm({
|
|
|
10696
10888
|
|
|
10697
10889
|
// src/pull-push.ts
|
|
10698
10890
|
var pull_push_exports = {};
|
|
10699
|
-
import { readFileSync as readFileSync10, writeFileSync as
|
|
10891
|
+
import { readFileSync as readFileSync10, writeFileSync as writeFileSync7, existsSync as existsSync8 } from "fs";
|
|
10700
10892
|
import { resolve as resolve9 } from "path";
|
|
10701
10893
|
function loadEnv() {
|
|
10702
10894
|
if (process.env.SOLONGATE_API_KEY) return;
|
|
@@ -10891,7 +11083,7 @@ async function pull(apiKey, file, policyId) {
|
|
|
10891
11083
|
const policy = await fetchCloudPolicy(apiKey, API_URL, policyId);
|
|
10892
11084
|
const { id: _id, ...policyWithoutId } = policy;
|
|
10893
11085
|
const json = JSON.stringify(policyWithoutId, null, 2) + "\n";
|
|
10894
|
-
|
|
11086
|
+
writeFileSync7(file, json, "utf-8");
|
|
10895
11087
|
log5("");
|
|
10896
11088
|
log5(green2(" Saved to: ") + file);
|
|
10897
11089
|
log5(` ${dim2("Name:")} ${policy.name}`);
|