@solongate/proxy 0.71.0 → 0.73.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +208 -213
- package/dist/tui/index.js +178 -183
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -7030,12 +7030,11 @@ var init_hooks = __esm({
|
|
|
7030
7030
|
|
|
7031
7031
|
// src/tui/panels/Live.tsx
|
|
7032
7032
|
import { Box as Box2, Text as Text2, useInput } from "ink";
|
|
7033
|
-
import {
|
|
7034
|
-
import { closeSync, mkdirSync as mkdirSync3, openSync, readSync, statSync, writeFileSync as writeFileSync3 } from "fs";
|
|
7033
|
+
import { closeSync, openSync, readSync, statSync } from "fs";
|
|
7035
7034
|
import { homedir as homedir3 } from "os";
|
|
7036
|
-
import {
|
|
7035
|
+
import { join as join5 } from "path";
|
|
7037
7036
|
import { useCallback as useCallback2, useEffect as useEffect2, useRef as useRef2, useState as useState2 } from "react";
|
|
7038
|
-
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
7037
|
+
import { Fragment as Fragment2, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
7039
7038
|
function tailLines(file, maxBytes = 131072) {
|
|
7040
7039
|
try {
|
|
7041
7040
|
const size = statSync(file).size;
|
|
@@ -7051,22 +7050,6 @@ function tailLines(file, maxBytes = 131072) {
|
|
|
7051
7050
|
return [];
|
|
7052
7051
|
}
|
|
7053
7052
|
}
|
|
7054
|
-
function copyToClipboard(text) {
|
|
7055
|
-
const tools = [
|
|
7056
|
-
["wl-copy", []],
|
|
7057
|
-
["xclip", ["-selection", "clipboard"]],
|
|
7058
|
-
["xsel", ["--clipboard", "--input"]]
|
|
7059
|
-
];
|
|
7060
|
-
for (const [cmd, args] of tools) {
|
|
7061
|
-
try {
|
|
7062
|
-
const r = spawnSync(cmd, args, { input: text, timeout: 2e3 });
|
|
7063
|
-
if (r.status === 0) return cmd;
|
|
7064
|
-
} catch {
|
|
7065
|
-
}
|
|
7066
|
-
}
|
|
7067
|
-
process.stdout.write(`\x1B]52;c;${Buffer.from(text, "utf-8").toString("base64")}\x07`);
|
|
7068
|
-
return null;
|
|
7069
|
-
}
|
|
7070
7053
|
function cloudItem(e) {
|
|
7071
7054
|
return {
|
|
7072
7055
|
id: "c:" + e.id,
|
|
@@ -7076,6 +7059,7 @@ function cloudItem(e) {
|
|
|
7076
7059
|
permission: (e.permission ?? "").slice(0, 4),
|
|
7077
7060
|
detail: (e.arguments_summary ? JSON.stringify(e.arguments_summary) : e.reason ?? "").replace(/\s+/g, " "),
|
|
7078
7061
|
dlp: !!e.dlp_matches?.length,
|
|
7062
|
+
burst: !!e.rate_limit_burst,
|
|
7079
7063
|
source: "cloud",
|
|
7080
7064
|
session: e.session_id ?? void 0,
|
|
7081
7065
|
agent: e.agent_name ?? void 0,
|
|
@@ -7131,6 +7115,12 @@ function PaneTitle({ label, extra, width: width2 }) {
|
|
|
7131
7115
|
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: tail + "\u2500".repeat(Math.max(0, width2 - used)) })
|
|
7132
7116
|
] });
|
|
7133
7117
|
}
|
|
7118
|
+
function Stat({ label, value, color }) {
|
|
7119
|
+
return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", marginRight: 3, children: [
|
|
7120
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: label }),
|
|
7121
|
+
/* @__PURE__ */ jsx2(Text2, { bold: true, color, children: String(value) })
|
|
7122
|
+
] });
|
|
7123
|
+
}
|
|
7134
7124
|
function StreamLine({ e, loc }) {
|
|
7135
7125
|
return /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
7136
7126
|
/* @__PURE__ */ jsxs2(Text2, { color: theme.dim, children: [
|
|
@@ -7146,6 +7136,7 @@ function StreamLine({ e, loc }) {
|
|
|
7146
7136
|
/* @__PURE__ */ jsx2(Text2, { color: e.evalMs != null && e.evalMs > 500 ? theme.warn : theme.dim, children: (e.evalMs != null ? `${e.evalMs}ms` : "\u2014").padEnd(7) }),
|
|
7147
7137
|
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: truncate2(e.agent ?? "-", 11).padEnd(12) }),
|
|
7148
7138
|
e.dlp ? /* @__PURE__ */ jsx2(Text2, { color: theme.bad, children: "DLP! " }) : null,
|
|
7139
|
+
e.burst ? /* @__PURE__ */ jsx2(Text2, { color: theme.warn, children: "BURST " }) : null,
|
|
7149
7140
|
e.rule && e.decision !== "ALLOW" ? /* @__PURE__ */ jsx2(Text2, { color: theme.bad, children: truncate2(e.rule, 14) + " " }) : null,
|
|
7150
7141
|
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: e.detail })
|
|
7151
7142
|
] });
|
|
@@ -7161,15 +7152,17 @@ function LivePanel({ active: active2 }) {
|
|
|
7161
7152
|
const [log6, setLog] = useState2([]);
|
|
7162
7153
|
const [filter, setFilter] = useState2("all");
|
|
7163
7154
|
const [scroll, setScroll] = useState2(0);
|
|
7164
|
-
const [toast, setToast] = useState2(null);
|
|
7165
7155
|
const [mode, setMode] = useState2("stream");
|
|
7156
|
+
const [sessFilter, setSessFilter] = useState2("all");
|
|
7166
7157
|
const [pickIdx, setPickIdx] = useState2(0);
|
|
7167
|
-
const [detail, setDetail] = useState2(null);
|
|
7168
7158
|
const [detailCloud, setDetailCloud] = useState2([]);
|
|
7169
|
-
const [
|
|
7159
|
+
const [tlScroll, setTlScroll] = useState2(0);
|
|
7170
7160
|
const seenRef = useRef2(/* @__PURE__ */ new Set());
|
|
7171
7161
|
const lastLocalTs = useRef2(0);
|
|
7172
7162
|
const pausedUntil = useRef2(0);
|
|
7163
|
+
const [frozen, setFrozen] = useState2(false);
|
|
7164
|
+
const frozenRef = useRef2(false);
|
|
7165
|
+
frozenRef.current = frozen;
|
|
7173
7166
|
const pushLog = useCallback2((msg, level = "ok") => {
|
|
7174
7167
|
setLog((prev) => [...prev.slice(-59), { ts: Date.now(), msg, level }]);
|
|
7175
7168
|
}, []);
|
|
@@ -7185,8 +7178,9 @@ function LivePanel({ active: active2 }) {
|
|
|
7185
7178
|
},
|
|
7186
7179
|
[pushLog]
|
|
7187
7180
|
);
|
|
7188
|
-
const paused = () => Date.now() < pausedUntil.current;
|
|
7181
|
+
const paused = () => frozenRef.current || Date.now() < pausedUntil.current;
|
|
7189
7182
|
const pollLocal = useCallback2(() => {
|
|
7183
|
+
if (frozenRef.current) return;
|
|
7190
7184
|
const lines = tailLines(LOCAL_LOG);
|
|
7191
7185
|
if (!lines.length) {
|
|
7192
7186
|
setLocalOn((prev) => prev === null ? false : prev);
|
|
@@ -7207,6 +7201,7 @@ function LivePanel({ active: active2 }) {
|
|
|
7207
7201
|
permission: (j.permission ?? "").slice(0, 4),
|
|
7208
7202
|
detail: (j.arguments ? JSON.stringify(j.arguments) : j.reason ?? "").replace(/\s+/g, " "),
|
|
7209
7203
|
dlp: !!j.dlp,
|
|
7204
|
+
burst: !!j.rate_limit_burst,
|
|
7210
7205
|
source: "local",
|
|
7211
7206
|
session: j.session_id,
|
|
7212
7207
|
agent: j.agent_name,
|
|
@@ -7252,6 +7247,7 @@ function LivePanel({ active: active2 }) {
|
|
|
7252
7247
|
const t0 = Date.now();
|
|
7253
7248
|
try {
|
|
7254
7249
|
const fd = await api.audit.list({ limit: 50 });
|
|
7250
|
+
if (frozenRef.current) return;
|
|
7255
7251
|
const ms = Date.now() - t0;
|
|
7256
7252
|
setLat((l) => [...l, ms].slice(-240));
|
|
7257
7253
|
const fresh = fd.entries.filter((e) => !seenRef.current.has(e.id));
|
|
@@ -7269,7 +7265,8 @@ function LivePanel({ active: active2 }) {
|
|
|
7269
7265
|
const pollMedium = useCallback2(async () => {
|
|
7270
7266
|
if (paused()) return;
|
|
7271
7267
|
try {
|
|
7272
|
-
|
|
7268
|
+
const sd = await api.stats.get();
|
|
7269
|
+
if (!frozenRef.current) setS(sd);
|
|
7273
7270
|
} catch (e) {
|
|
7274
7271
|
onApiError(e);
|
|
7275
7272
|
}
|
|
@@ -7277,7 +7274,8 @@ function LivePanel({ active: active2 }) {
|
|
|
7277
7274
|
const pollSlow = useCallback2(async () => {
|
|
7278
7275
|
if (paused()) return;
|
|
7279
7276
|
try {
|
|
7280
|
-
|
|
7277
|
+
const td = await api.stats.timeseries({ period: "24h" });
|
|
7278
|
+
if (!frozenRef.current) setTsData(td);
|
|
7281
7279
|
} catch (e) {
|
|
7282
7280
|
onApiError(e);
|
|
7283
7281
|
}
|
|
@@ -7308,25 +7306,12 @@ function LivePanel({ active: active2 }) {
|
|
|
7308
7306
|
usePoll(() => {
|
|
7309
7307
|
if (!paused()) guard.reload();
|
|
7310
7308
|
}, 6e4, active2);
|
|
7311
|
-
useEffect2(() => {
|
|
7312
|
-
if (!detail) return;
|
|
7313
|
-
setDetailCloud([]);
|
|
7314
|
-
setDetailScroll(0);
|
|
7315
|
-
let alive = true;
|
|
7316
|
-
api.audit.list({ session_id: detail.id, limit: 100 }).then((r) => {
|
|
7317
|
-
if (alive) setDetailCloud(r.entries.map(cloudItem));
|
|
7318
|
-
}).catch(() => {
|
|
7319
|
-
});
|
|
7320
|
-
return () => {
|
|
7321
|
-
alive = false;
|
|
7322
|
-
};
|
|
7323
|
-
}, [detail]);
|
|
7324
7309
|
const [tick, setTick] = useState2(0);
|
|
7325
7310
|
useEffect2(() => {
|
|
7326
|
-
if (!active2) return;
|
|
7311
|
+
if (!active2 || frozen) return;
|
|
7327
7312
|
const t = setInterval(() => setTick((n) => n + 1), 500);
|
|
7328
7313
|
return () => clearInterval(t);
|
|
7329
|
-
}, [active2]);
|
|
7314
|
+
}, [active2, frozen]);
|
|
7330
7315
|
const startRef = useRef2(Date.now());
|
|
7331
7316
|
const cols = process.stdout.columns ?? 100;
|
|
7332
7317
|
const rows = process.stdout.rows ?? 30;
|
|
@@ -7340,67 +7325,68 @@ function LivePanel({ active: active2 }) {
|
|
|
7340
7325
|
}
|
|
7341
7326
|
const cloudDeduped = cloudBuf.filter((e) => !localKeys.has(`${e.tool}|${e.decision}|${Math.round(e.at / 6e4)}`));
|
|
7342
7327
|
const mergedAll = [...cloudDeduped, ...localBuf].sort((a, b) => a.at - b.at);
|
|
7343
|
-
const points = tsData?.timeseries ?? [];
|
|
7344
|
-
const nowMin = Math.floor(nowMs / 6e4);
|
|
7345
|
-
const minuteCounts = new Array(60).fill(0);
|
|
7346
|
-
const minuteHot = new Array(60).fill(false);
|
|
7347
|
-
for (const e of mergedAll) {
|
|
7348
|
-
const idx = 59 - (nowMin - Math.floor(e.at / 6e4));
|
|
7349
|
-
if (idx >= 0 && idx < 60) {
|
|
7350
|
-
minuteCounts[idx]++;
|
|
7351
|
-
if (e.decision !== "ALLOW") minuteHot[idx] = true;
|
|
7352
|
-
}
|
|
7353
|
-
}
|
|
7354
|
-
const localTraffic = localOn === true && minuteCounts.some((c2) => c2 > 0);
|
|
7355
|
-
const traffic = localTraffic ? minuteCounts : points.map((p) => p.total);
|
|
7356
|
-
const trafficHot = localTraffic ? minuteHot : points.map((p) => p.denied > 0);
|
|
7357
|
-
const trafficLabel = localTraffic ? "calls/min \xB7 60m \xB7 local+cloud" : "24h \xB7 cloud";
|
|
7358
|
-
const rl = ins.layers?.rateLimit;
|
|
7359
|
-
const dl = ins.layers?.dlp;
|
|
7360
|
-
const gh = ins.layers?.ghost;
|
|
7361
|
-
const minuteNow = minuteCounts[59] ?? 0;
|
|
7362
|
-
const dlpBars = (ins.dlpByPattern ?? []).slice(0, 2);
|
|
7363
|
-
const maxDlpBar = dlpBars[0]?.count ?? 1;
|
|
7364
|
-
const denialsAll = mergedAll.filter((e) => e.decision !== "ALLOW");
|
|
7365
|
-
const lastDeny = denialsAll[denialsAll.length - 1];
|
|
7366
|
-
const toolCounts = /* @__PURE__ */ new Map();
|
|
7367
|
-
for (const e of mergedAll) toolCounts.set(e.tool, (toolCounts.get(e.tool) ?? 0) + 1);
|
|
7368
|
-
const topTools = [...toolCounts.entries()].sort((a, b) => b[1] - a[1]).slice(0, 3);
|
|
7369
|
-
const latNow = lat[lat.length - 1] ?? 0;
|
|
7370
|
-
const sortedLat = [...lat].sort((a, b) => a - b);
|
|
7371
|
-
const latMed = sortedLat.length ? sortedLat[Math.floor(sortedLat.length / 2)] : 0;
|
|
7372
|
-
const latHotAt = Math.max(2e3, latMed * 2.5);
|
|
7373
|
-
const backingOff = Date.now() < pausedUntil.current;
|
|
7374
|
-
const sess = (sessions.data?.agents ?? []).slice().sort((a, b) => Date.parse(b.last_seen_at) - Date.parse(a.last_seen_at));
|
|
7375
|
-
const sessCounts = sessions.data?.counts;
|
|
7376
7328
|
const localSess = /* @__PURE__ */ new Map();
|
|
7377
7329
|
for (const e of localBuf) {
|
|
7378
7330
|
if (!e.session) continue;
|
|
7379
|
-
const cur = localSess.get(e.session) ?? { agent: e.agent ?? "local agent", calls: 0, denies: 0, lastAt: 0 };
|
|
7331
|
+
const cur = localSess.get(e.session) ?? { agent: e.agent ?? "local agent", calls: 0, denies: 0, dlp: 0, lastAt: 0 };
|
|
7380
7332
|
cur.calls++;
|
|
7381
7333
|
if (e.decision !== "ALLOW") cur.denies++;
|
|
7334
|
+
if (e.dlp) cur.dlp++;
|
|
7382
7335
|
cur.lastAt = Math.max(cur.lastAt, e.at);
|
|
7383
7336
|
if (e.agent) cur.agent = e.agent;
|
|
7384
7337
|
localSess.set(e.session, cur);
|
|
7385
7338
|
}
|
|
7386
|
-
const
|
|
7387
|
-
...[...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 })),
|
|
7388
|
-
...
|
|
7339
|
+
const combinedSessAll = [
|
|
7340
|
+
...[...localSess.entries()].sort((a, b) => b[1].lastAt - a[1].lastAt).map(([id, v]) => ({ source: "local", id, agent: v.agent, calls: v.calls, denies: v.denies, dlp: v.dlp, lastAt: v.lastAt, isMe: ring?.session === id })),
|
|
7341
|
+
...(sessions.data?.agents ?? []).filter((a) => !localSess.has(a.session_id)).sort((a, b) => Date.parse(b.last_seen_at) - Date.parse(a.last_seen_at)).map((a) => ({
|
|
7389
7342
|
source: "cloud",
|
|
7390
7343
|
id: a.session_id,
|
|
7391
7344
|
agent: a.agent_name ?? a.session_id,
|
|
7392
7345
|
calls: a.total_calls,
|
|
7393
7346
|
denies: a.denied_calls,
|
|
7347
|
+
dlp: a.dlp_events,
|
|
7394
7348
|
lastAt: Date.parse(a.last_seen_at),
|
|
7395
7349
|
trust: a.trust_score,
|
|
7396
7350
|
isMe: false
|
|
7397
7351
|
}))
|
|
7398
7352
|
];
|
|
7353
|
+
const combinedSess = sessFilter === "all" ? combinedSessAll : combinedSessAll.filter((r) => sessStatus(r.lastAt, nowMs) === sessFilter);
|
|
7399
7354
|
const localSessIds = new Set(localSess.keys());
|
|
7400
7355
|
if (ring?.session) localSessIds.add(ring.session);
|
|
7401
7356
|
const isLoc = (e) => e.source === "local" || !!e.session && localSessIds.has(e.session);
|
|
7402
7357
|
const filtered = filter === "all" ? mergedAll : mergedAll.filter((e) => filter === "local" ? isLoc(e) : !isLoc(e));
|
|
7403
7358
|
const visibleDesc = filtered.slice(-STREAM_KEEP).reverse();
|
|
7359
|
+
const points = tsData?.timeseries ?? [];
|
|
7360
|
+
const nowSlot = Math.floor(nowMs / 1e4);
|
|
7361
|
+
const slotCounts = new Array(60).fill(0);
|
|
7362
|
+
const slotHot = new Array(60).fill(false);
|
|
7363
|
+
for (const e of mergedAll) {
|
|
7364
|
+
const idx = 59 - (nowSlot - Math.floor(e.at / 1e4));
|
|
7365
|
+
if (idx >= 0 && idx < 60) {
|
|
7366
|
+
slotCounts[idx]++;
|
|
7367
|
+
if (e.decision !== "ALLOW") slotHot[idx] = true;
|
|
7368
|
+
}
|
|
7369
|
+
}
|
|
7370
|
+
const localTraffic = localOn === true && slotCounts.some((c2) => c2 > 0);
|
|
7371
|
+
const traffic = localTraffic ? slotCounts : points.map((p) => p.total);
|
|
7372
|
+
const trafficHot = localTraffic ? slotHot : points.map((p) => p.denied > 0);
|
|
7373
|
+
const trafficLabel = localTraffic ? "calls/10s \xB7 last 10m" : "24h \xB7 cloud";
|
|
7374
|
+
const rl = ins.layers?.rateLimit;
|
|
7375
|
+
const dl = ins.layers?.dlp;
|
|
7376
|
+
const gh = ins.layers?.ghost;
|
|
7377
|
+
const minuteNow = mergedAll.filter((e) => nowMs - e.at < 6e4).length;
|
|
7378
|
+
const dlpBars = (ins.dlpByPattern ?? []).slice(0, 2);
|
|
7379
|
+
const maxDlpBar = dlpBars[0]?.count ?? 1;
|
|
7380
|
+
const denialsAll = mergedAll.filter((e) => e.decision !== "ALLOW");
|
|
7381
|
+
const lastDeny = denialsAll[denialsAll.length - 1];
|
|
7382
|
+
const toolCounts = /* @__PURE__ */ new Map();
|
|
7383
|
+
for (const e of mergedAll) toolCounts.set(e.tool, (toolCounts.get(e.tool) ?? 0) + 1);
|
|
7384
|
+
const topTools = [...toolCounts.entries()].sort((a, b) => b[1] - a[1]).slice(0, 3);
|
|
7385
|
+
const latNow = lat[lat.length - 1] ?? 0;
|
|
7386
|
+
const sortedLat = [...lat].sort((a, b) => a - b);
|
|
7387
|
+
const latMed = sortedLat.length ? sortedLat[Math.floor(sortedLat.length / 2)] : 0;
|
|
7388
|
+
const latHotAt = Math.max(2e3, latMed * 2.5);
|
|
7389
|
+
const backingOff = Date.now() < pausedUntil.current;
|
|
7404
7390
|
const chartH = rows >= 36 ? 6 : 4;
|
|
7405
7391
|
const colH = rows >= 32 ? 7 : 5;
|
|
7406
7392
|
const streamRows = Math.max(4, rows - 5 - (1 + chartH) - colH);
|
|
@@ -7408,14 +7394,25 @@ function LivePanel({ active: active2 }) {
|
|
|
7408
7394
|
const leftW = Math.floor(innerW * 0.55);
|
|
7409
7395
|
const rightW = innerW - leftW - 2;
|
|
7410
7396
|
const colW = Math.max(20, Math.floor((innerW - 4) / 3));
|
|
7411
|
-
const pickable = combinedSess.slice(0, colH - 1);
|
|
7412
7397
|
const maxScroll = Math.max(0, visibleDesc.length - streamRows);
|
|
7413
7398
|
const clampedScroll = Math.min(scroll, maxScroll);
|
|
7414
7399
|
const windowed = visibleDesc.slice(clampedScroll, clampedScroll + streamRows);
|
|
7415
|
-
const
|
|
7400
|
+
const selIdx = Math.min(pickIdx, Math.max(0, combinedSess.length - 1));
|
|
7401
|
+
const selected = combinedSess[selIdx];
|
|
7402
|
+
useEffect2(() => {
|
|
7403
|
+
if (mode !== "sessions" || !selected?.id) return;
|
|
7404
|
+
setTlScroll(0);
|
|
7405
|
+
const t = setTimeout(() => {
|
|
7406
|
+
api.audit.list({ session_id: selected.id, limit: 100 }).then((r) => {
|
|
7407
|
+
if (!frozenRef.current) setDetailCloud(r.entries.map(cloudItem));
|
|
7408
|
+
}).catch(() => setDetailCloud([]));
|
|
7409
|
+
}, 400);
|
|
7410
|
+
return () => clearTimeout(t);
|
|
7411
|
+
}, [mode, selected?.id]);
|
|
7412
|
+
const detailEntries = selected ? (() => {
|
|
7416
7413
|
const seen = /* @__PURE__ */ new Set();
|
|
7417
7414
|
const all = [];
|
|
7418
|
-
for (const e of [...detailCloud, ...mergedAll.filter((x) => x.session ===
|
|
7415
|
+
for (const e of [...detailCloud, ...mergedAll.filter((x) => x.session === selected.id)]) {
|
|
7419
7416
|
const key = `${e.at}:${e.tool}:${e.decision}`;
|
|
7420
7417
|
if (seen.has(key)) continue;
|
|
7421
7418
|
seen.add(key);
|
|
@@ -7425,27 +7422,22 @@ function LivePanel({ active: active2 }) {
|
|
|
7425
7422
|
})() : [];
|
|
7426
7423
|
useInput(
|
|
7427
7424
|
(input, key) => {
|
|
7428
|
-
if (
|
|
7429
|
-
|
|
7430
|
-
if (key.leftArrow) {
|
|
7431
|
-
setMode("stream");
|
|
7432
|
-
setDetail(null);
|
|
7433
|
-
} else if (key.upArrow) setDetailScroll((n) => Math.max(0, n - 1));
|
|
7434
|
-
else if (key.downArrow) setDetailScroll((n) => Math.min(maxD, n + 1));
|
|
7435
|
-
else if (key.pageUp) setDetailScroll((n) => Math.max(0, n - 10));
|
|
7436
|
-
else if (key.pageDown) setDetailScroll((n) => Math.min(maxD, n + 10));
|
|
7425
|
+
if (input === " ") {
|
|
7426
|
+
setFrozen((f) => !f);
|
|
7437
7427
|
return;
|
|
7438
7428
|
}
|
|
7439
|
-
if (
|
|
7440
|
-
|
|
7441
|
-
|
|
7442
|
-
|
|
7443
|
-
|
|
7444
|
-
|
|
7445
|
-
|
|
7446
|
-
|
|
7447
|
-
|
|
7448
|
-
|
|
7429
|
+
if (frozen) return;
|
|
7430
|
+
if (mode === "sessions") {
|
|
7431
|
+
if (key.leftArrow) {
|
|
7432
|
+
setMode("stream");
|
|
7433
|
+
setDetailCloud([]);
|
|
7434
|
+
} else if (key.upArrow) setPickIdx((n) => Math.max(0, n - 1));
|
|
7435
|
+
else if (key.downArrow) setPickIdx((n) => Math.min(combinedSess.length - 1, n + 1));
|
|
7436
|
+
else if (input === "f") {
|
|
7437
|
+
setSessFilter((f) => SESS_FILTERS[(SESS_FILTERS.indexOf(f) + 1) % SESS_FILTERS.length]);
|
|
7438
|
+
setPickIdx(0);
|
|
7439
|
+
} else if (key.pageUp) setTlScroll((n) => Math.max(0, n - 10));
|
|
7440
|
+
else if (key.pageDown) setTlScroll((n) => n + 10);
|
|
7449
7441
|
return;
|
|
7450
7442
|
}
|
|
7451
7443
|
if (input === "f") {
|
|
@@ -7453,30 +7445,14 @@ function LivePanel({ active: active2 }) {
|
|
|
7453
7445
|
setScroll(0);
|
|
7454
7446
|
} else if (input === "s") {
|
|
7455
7447
|
setPickIdx(0);
|
|
7456
|
-
setMode("
|
|
7448
|
+
setMode("sessions");
|
|
7457
7449
|
} else if (key.downArrow) setScroll((n) => Math.min(maxScroll, n + 1));
|
|
7458
7450
|
else if (key.upArrow) setScroll((n) => Math.max(0, n - 1));
|
|
7459
7451
|
else if (key.pageDown) setScroll((n) => Math.min(maxScroll, n + streamRows));
|
|
7460
7452
|
else if (key.pageUp) setScroll((n) => Math.max(0, n - streamRows));
|
|
7461
|
-
else if (input === "c") {
|
|
7462
|
-
const dump = visibleDesc.map(
|
|
7463
|
-
(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}`
|
|
7464
|
-
).join("\n");
|
|
7465
|
-
try {
|
|
7466
|
-
mkdirSync3(dirname(DUMP), { recursive: true });
|
|
7467
|
-
writeFileSync3(DUMP, dump + "\n");
|
|
7468
|
-
} catch {
|
|
7469
|
-
}
|
|
7470
|
-
const via = copyToClipboard(dump);
|
|
7471
|
-
setToast(
|
|
7472
|
-
via ? { msg: `\u2713 ${visibleDesc.length} lines in clipboard (${via})`, until: Date.now() + 4e3 } : { msg: "\u2717 no clipboard tool \u2014 install wl-clipboard or xclip", until: Date.now() + 6e3 }
|
|
7473
|
-
);
|
|
7474
|
-
}
|
|
7475
7453
|
},
|
|
7476
7454
|
{ isActive: active2 }
|
|
7477
7455
|
);
|
|
7478
|
-
const sessionDot = (st) => st === "active" ? { ch: "\u25CF", color: theme.ok } : st === "idle" ? { ch: "\u25CC", color: theme.warn } : { ch: "\u25CB", color: theme.dim };
|
|
7479
|
-
void sessionDot;
|
|
7480
7456
|
if (s === null && localOn === null) {
|
|
7481
7457
|
return /* @__PURE__ */ jsxs2(Text2, { color: theme.dim, children: [
|
|
7482
7458
|
spin,
|
|
@@ -7486,72 +7462,91 @@ function LivePanel({ active: active2 }) {
|
|
|
7486
7462
|
const titleBar = /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
7487
7463
|
/* @__PURE__ */ jsx2(Text2, { backgroundColor: "#1432A0", color: "#AAC8FA", bold: true, children: " SOLONGATE LIVE " }),
|
|
7488
7464
|
/* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", children: ` ${spin} up ${fmtUp(nowMs - startRef.current)} \xB7 ${hhmmss(nowMs)} \xB7 api ${latNow}ms ` }),
|
|
7489
|
-
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 " })
|
|
7490
|
-
toast && nowMs < toast.until ? /* @__PURE__ */ jsx2(Text2, { backgroundColor: "#123d1f", color: "#7bd88f", bold: true, children: ` ${toast.msg} ` }) : null
|
|
7465
|
+
frozen ? /* @__PURE__ */ jsx2(Text2, { backgroundColor: "#123d1f", color: "#7bd88f", bold: true, children: " \u23F5 COPY MODE \u2014 screen frozen, select & copy freely \xB7 space resume " }) : backingOff ? /* @__PURE__ */ jsx2(Text2, { backgroundColor: "#3d2a12", color: "#ffb454", bold: true, children: " RATE LIMITED \xB7 backing off " }) : lastDeny ? /* @__PURE__ */ jsx2(Text2, { backgroundColor: "#3d1220", color: "#ff6b6b", bold: true, children: ` \u26A0 ${hhmmss(lastDeny.at)} ${lastDeny.tool} DENIED ` }) : /* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#4f6db8", children: " \u2713 clean " })
|
|
7491
7466
|
] });
|
|
7492
|
-
if (mode === "
|
|
7467
|
+
if (mode === "sessions") {
|
|
7468
|
+
const listW = Math.min(44, Math.floor(innerW * 0.38));
|
|
7469
|
+
const detailW = innerW - listW - 2;
|
|
7470
|
+
const bodyH = rows - 4;
|
|
7471
|
+
const listRows = bodyH - 1;
|
|
7493
7472
|
const d = detailEntries;
|
|
7494
7473
|
const allow = d.filter((e) => e.decision === "ALLOW").length;
|
|
7495
7474
|
const deny = d.length - allow;
|
|
7496
7475
|
const dlpN = d.filter((e) => e.dlp).length;
|
|
7476
|
+
const burstN = d.filter((e) => e.burst).length;
|
|
7497
7477
|
const evals = d.filter((e) => e.evalMs != null).map((e) => e.evalMs);
|
|
7498
7478
|
const evalAvg = evals.length ? Math.round(evals.reduce((a, b) => a + b, 0) / evals.length) : null;
|
|
7499
7479
|
const tCounts = /* @__PURE__ */ new Map();
|
|
7500
|
-
const
|
|
7501
|
-
|
|
7502
|
-
tCounts.set(e.tool, (tCounts.get(e.tool) ?? 0) + 1);
|
|
7503
|
-
if (e.permission) pCounts.set(e.permission, (pCounts.get(e.permission) ?? 0) + 1);
|
|
7504
|
-
}
|
|
7505
|
-
const top = [...tCounts.entries()].sort((a, b) => b[1] - a[1]).slice(0, 6);
|
|
7506
|
-
const perms = [...pCounts.entries()].sort((a, b) => b[1] - a[1]);
|
|
7480
|
+
for (const e of d) tCounts.set(e.tool, (tCounts.get(e.tool) ?? 0) + 1);
|
|
7481
|
+
const top = [...tCounts.entries()].sort((a, b) => b[1] - a[1]).slice(0, 5);
|
|
7507
7482
|
const first = d[d.length - 1]?.at;
|
|
7508
7483
|
const last = d[0]?.at;
|
|
7509
|
-
const tlRows = Math.max(
|
|
7510
|
-
const
|
|
7511
|
-
const
|
|
7512
|
-
const tl = d.slice(
|
|
7484
|
+
const tlRows = Math.max(3, bodyH - 8);
|
|
7485
|
+
const maxTl = Math.max(0, d.length - tlRows);
|
|
7486
|
+
const tScroll = Math.min(tlScroll, maxTl);
|
|
7487
|
+
const tl = d.slice(tScroll, tScroll + tlRows);
|
|
7513
7488
|
return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", paddingX: 1, children: [
|
|
7514
7489
|
titleBar,
|
|
7515
|
-
/* @__PURE__ */
|
|
7516
|
-
|
|
7517
|
-
/* @__PURE__ */
|
|
7518
|
-
|
|
7519
|
-
|
|
7520
|
-
|
|
7521
|
-
|
|
7522
|
-
|
|
7523
|
-
|
|
7524
|
-
|
|
7525
|
-
|
|
7526
|
-
|
|
7527
|
-
|
|
7528
|
-
|
|
7529
|
-
|
|
7530
|
-
|
|
7531
|
-
|
|
7532
|
-
|
|
7533
|
-
|
|
7534
|
-
|
|
7535
|
-
|
|
7536
|
-
|
|
7537
|
-
|
|
7538
|
-
|
|
7539
|
-
|
|
7540
|
-
|
|
7541
|
-
|
|
7542
|
-
|
|
7543
|
-
|
|
7544
|
-
|
|
7545
|
-
|
|
7546
|
-
|
|
7547
|
-
|
|
7548
|
-
|
|
7549
|
-
|
|
7490
|
+
/* @__PURE__ */ jsx2(PaneTitle, { label: "SESSIONS", extra: `${combinedSess.length} shown \xB7 filter ${sessFilter} (f) \xB7 \u2191\u2193 select \xB7 PgUp/Dn timeline \xB7 \u2190 back`, width: innerW }),
|
|
7491
|
+
/* @__PURE__ */ jsxs2(Box2, { height: bodyH, children: [
|
|
7492
|
+
/* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", width: listW, marginRight: 2, overflow: "hidden", children: [
|
|
7493
|
+
combinedSess.length === 0 ? /* @__PURE__ */ jsxs2(Text2, { color: theme.dim, children: [
|
|
7494
|
+
"no sessions",
|
|
7495
|
+
sessFilter !== "all" ? ` (${sessFilter})` : ""
|
|
7496
|
+
] }) : null,
|
|
7497
|
+
combinedSess.slice(0, listRows).map((r, i) => {
|
|
7498
|
+
const st = sessStatus(r.lastAt, nowMs);
|
|
7499
|
+
const dot = st === "active" ? { ch: "\u25CF", color: theme.ok } : st === "idle" ? { ch: "\u25CC", color: theme.warn } : { ch: "\u25CB", color: theme.dim };
|
|
7500
|
+
const sel = i === selIdx;
|
|
7501
|
+
return /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", backgroundColor: sel ? "#1c2f63" : void 0, bold: sel, children: [
|
|
7502
|
+
/* @__PURE__ */ jsxs2(Text2, { color: sel ? theme.accentBright : dot.color, children: [
|
|
7503
|
+
sel ? "\u25B8" : dot.ch,
|
|
7504
|
+
" "
|
|
7505
|
+
] }),
|
|
7506
|
+
/* @__PURE__ */ jsx2(Text2, { color: r.source === "local" ? theme.ok : "#4f6db8", children: r.source === "local" ? "LOC " : "CLD " }),
|
|
7507
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.accentBright, children: truncate2(r.isMe ? "this machine" : r.agent, 13).padEnd(14) }),
|
|
7508
|
+
/* @__PURE__ */ jsxs2(Text2, { children: [
|
|
7509
|
+
String(r.calls).padStart(4),
|
|
7510
|
+
"c "
|
|
7511
|
+
] }),
|
|
7512
|
+
/* @__PURE__ */ jsxs2(Text2, { color: r.denies ? theme.bad : theme.dim, children: [
|
|
7513
|
+
String(r.denies).padStart(3),
|
|
7514
|
+
"d "
|
|
7515
|
+
] }),
|
|
7516
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: ago(r.lastAt) })
|
|
7517
|
+
] }, r.id);
|
|
7518
|
+
})
|
|
7519
|
+
] }),
|
|
7520
|
+
/* @__PURE__ */ jsx2(Box2, { flexDirection: "column", width: detailW, overflow: "hidden", children: !selected ? /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "select a session to see its run timeline" }) : /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
7521
|
+
/* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
7522
|
+
/* @__PURE__ */ jsx2(Text2, { color: sessStatus(selected.lastAt, nowMs) === "active" ? theme.ok : theme.dim, children: sessStatus(selected.lastAt, nowMs) === "active" ? "\u25CF " : "\u25CB " }),
|
|
7523
|
+
/* @__PURE__ */ jsx2(Text2, { bold: true, children: truncate2(selected.isMe ? selected.agent + " (this machine)" : selected.agent, 30) }),
|
|
7524
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " " + selected.id })
|
|
7525
|
+
] }),
|
|
7526
|
+
/* @__PURE__ */ jsxs2(Box2, { marginTop: 1, children: [
|
|
7527
|
+
/* @__PURE__ */ jsx2(Stat, { label: "Total", value: d.length }),
|
|
7528
|
+
/* @__PURE__ */ jsx2(Stat, { label: "Allowed", value: allow, color: theme.ok }),
|
|
7529
|
+
/* @__PURE__ */ jsx2(Stat, { label: "Denied", value: deny, color: deny ? theme.bad : void 0 }),
|
|
7530
|
+
/* @__PURE__ */ jsx2(Stat, { label: "DLP", value: dlpN, color: dlpN ? theme.bad : void 0 }),
|
|
7531
|
+
/* @__PURE__ */ jsx2(Stat, { label: "Rate limit", value: burstN, color: burstN ? theme.warn : void 0 }),
|
|
7532
|
+
/* @__PURE__ */ jsx2(Stat, { label: "Avg eval", value: evalAvg != null ? `${evalAvg}ms` : "\u2014" }),
|
|
7533
|
+
selected.trust != null ? /* @__PURE__ */ jsx2(Stat, { label: "Trust", value: `${selected.trust}/100`, color: theme.accent }) : null
|
|
7534
|
+
] }),
|
|
7535
|
+
/* @__PURE__ */ jsx2(Text2, { wrap: "truncate", color: theme.dim, children: `first ${first ? `${hhmmss(first)} (${ago(first)} ago)` : "\u2014"} \xB7 last ${last ? `${hhmmss(last)} (${ago(last)} ago)` : "\u2014"} \xB7 tools ${top.map(([t, c2]) => `${t}\xD7${c2}`).join(" ") || "\u2014"}` }),
|
|
7536
|
+
/* @__PURE__ */ jsx2(PaneTitle, { label: "TIMELINE", extra: `${d.length} events \xB7 newest first${tScroll ? ` \xB7 \u25BC${tScroll}` : ""}`, width: detailW }),
|
|
7537
|
+
/* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", overflow: "hidden", flexGrow: 1, children: [
|
|
7538
|
+
tl.length === 0 ? /* @__PURE__ */ jsxs2(Text2, { color: theme.dim, children: [
|
|
7539
|
+
spin,
|
|
7540
|
+
" loading history\u2026"
|
|
7541
|
+
] }) : null,
|
|
7542
|
+
tl.map((e) => /* @__PURE__ */ jsx2(StreamLine, { e, loc: isLoc(e) }, e.id))
|
|
7543
|
+
] })
|
|
7544
|
+
] }) })
|
|
7550
7545
|
] }),
|
|
7551
7546
|
/* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
7552
|
-
/* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", bold: true, children: "
|
|
7553
|
-
/* @__PURE__ */ jsx2(Text2, { backgroundColor: "#0b1530", color: "#4f6db8", children: ` ${
|
|
7554
|
-
/* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", children: " \u2191\u2193
|
|
7547
|
+
/* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", bold: true, children: " SESSIONS " }),
|
|
7548
|
+
/* @__PURE__ */ jsx2(Text2, { backgroundColor: "#0b1530", color: "#4f6db8", children: ` ${combinedSess.length} sessions \xB7 space copy-mode ` }),
|
|
7549
|
+
/* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", children: " \u2191\u2193 select \xB7 f status \xB7 \u2190 back \xB7 esc menu " })
|
|
7555
7550
|
] })
|
|
7556
7551
|
] });
|
|
7557
7552
|
}
|
|
@@ -7573,7 +7568,7 @@ function LivePanel({ active: active2 }) {
|
|
|
7573
7568
|
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502 ghost " }),
|
|
7574
7569
|
/* @__PURE__ */ jsx2(Text2, { color: gh?.mode === "on" ? theme.ok : theme.dim, children: gh?.mode ?? "?" }),
|
|
7575
7570
|
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502 sess " }),
|
|
7576
|
-
/* @__PURE__ */ jsx2(Text2, { color: theme.accent, children:
|
|
7571
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.accent, children: String(combinedSessAll.length) }),
|
|
7577
7572
|
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502 hooks " }),
|
|
7578
7573
|
/* @__PURE__ */ jsx2(Text2, { color: guard.data?.up_to_date ? theme.ok : theme.warn, children: guard.data ? `v${guard.data.installed ?? "?"}${guard.data.up_to_date ? "" : "\u2192v" + guard.data.latest} ${guard.data.device_count}dev` : "\xB7" }),
|
|
7579
7574
|
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502" })
|
|
@@ -7612,14 +7607,13 @@ function LivePanel({ active: active2 }) {
|
|
|
7612
7607
|
] })
|
|
7613
7608
|
] }),
|
|
7614
7609
|
/* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", width: colW, marginRight: 2, overflow: "hidden", children: [
|
|
7615
|
-
/* @__PURE__ */ jsx2(PaneTitle, { label: "SESSIONS", extra:
|
|
7616
|
-
|
|
7617
|
-
|
|
7618
|
-
const
|
|
7619
|
-
|
|
7620
|
-
|
|
7621
|
-
|
|
7622
|
-
sel ? "\u25B8" : freshDot ? "\u25CF" : "\u25CB",
|
|
7610
|
+
/* @__PURE__ */ jsx2(PaneTitle, { label: "SESSIONS", extra: "press s to inspect", width: colW }),
|
|
7611
|
+
combinedSessAll.slice(0, colH - 1).map((r) => {
|
|
7612
|
+
const st = sessStatus(r.lastAt, nowMs);
|
|
7613
|
+
const dot = st === "active" ? { ch: "\u25CF", color: theme.ok } : st === "idle" ? { ch: "\u25CC", color: theme.warn } : { ch: "\u25CB", color: theme.dim };
|
|
7614
|
+
return /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", bold: r.isMe, children: [
|
|
7615
|
+
/* @__PURE__ */ jsxs2(Text2, { color: dot.color, children: [
|
|
7616
|
+
dot.ch,
|
|
7623
7617
|
" "
|
|
7624
7618
|
] }),
|
|
7625
7619
|
/* @__PURE__ */ jsx2(Text2, { color: r.source === "local" ? theme.ok : "#4f6db8", children: r.source === "local" ? "LOC " : "CLD " }),
|
|
@@ -7632,7 +7626,7 @@ function LivePanel({ active: active2 }) {
|
|
|
7632
7626
|
String(r.denies).padStart(3),
|
|
7633
7627
|
"d "
|
|
7634
7628
|
] }),
|
|
7635
|
-
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children:
|
|
7629
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: ago(r.lastAt) })
|
|
7636
7630
|
] }, r.id);
|
|
7637
7631
|
})
|
|
7638
7632
|
] }),
|
|
@@ -7652,7 +7646,7 @@ function LivePanel({ active: active2 }) {
|
|
|
7652
7646
|
PaneTitle,
|
|
7653
7647
|
{
|
|
7654
7648
|
label: "TOOL STREAM",
|
|
7655
|
-
extra: `newest first \xB7 last ${STREAM_KEEP} \xB7 filter ${filter}${clampedScroll > 0 ? ` \xB7 \u25BC${clampedScroll} older` : ""} \xB7 f filter \xB7 \u2191\u2193 scroll \xB7
|
|
7649
|
+
extra: `newest first \xB7 last ${STREAM_KEEP} \xB7 filter ${filter}${clampedScroll > 0 ? ` \xB7 \u25BC${clampedScroll} older` : ""} \xB7 f filter \xB7 \u2191\u2193 scroll \xB7 s sessions`,
|
|
7656
7650
|
width: innerW
|
|
7657
7651
|
}
|
|
7658
7652
|
),
|
|
@@ -7669,12 +7663,12 @@ function LivePanel({ active: active2 }) {
|
|
|
7669
7663
|
] }),
|
|
7670
7664
|
/* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
7671
7665
|
/* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", bold: true, children: " LIVE " }),
|
|
7672
|
-
/* @__PURE__ */ jsx2(Text2, { backgroundColor: "#0b1530", color: "#4f6db8", children: ` local ${localOn ? "on" : "off"} \xB7 ${localBuf.length} loc/${
|
|
7673
|
-
/* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", children: "
|
|
7666
|
+
/* @__PURE__ */ jsx2(Text2, { backgroundColor: "#0b1530", color: "#4f6db8", children: ` local ${localOn ? "on" : "off"} \xB7 ${localBuf.length} loc/${cloudDeduped.length} cld \xB7 top ${topTools.map(([t, c2]) => `${t}\xD7${c2}`).join(" ") || "\u2014"} ` }),
|
|
7667
|
+
/* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", children: " space copy-mode \xB7 f filter \xB7 s sessions \xB7 esc menu \xB7 q quit " })
|
|
7674
7668
|
] })
|
|
7675
7669
|
] });
|
|
7676
7670
|
}
|
|
7677
|
-
var SPIN, BG, DIM_FLOOR, LOCAL_LOG, RING,
|
|
7671
|
+
var SPIN, BG, DIM_FLOOR, LOCAL_LOG, RING, STREAM_KEEP, hhmmss, fmtUp, FILTERS, SESS_FILTERS, sessStatus;
|
|
7678
7672
|
var init_Live = __esm({
|
|
7679
7673
|
"src/tui/panels/Live.tsx"() {
|
|
7680
7674
|
"use strict";
|
|
@@ -7686,7 +7680,6 @@ var init_Live = __esm({
|
|
|
7686
7680
|
DIM_FLOOR = "#233457";
|
|
7687
7681
|
LOCAL_LOG = join5(homedir3(), ".solongate", "local-logs", "solongate-audit.jsonl");
|
|
7688
7682
|
RING = join5(process.cwd(), ".solongate", ".eval-ring.jsonl");
|
|
7689
|
-
DUMP = join5(homedir3(), ".solongate", "live-stream.log");
|
|
7690
7683
|
STREAM_KEEP = 100;
|
|
7691
7684
|
hhmmss = (ts) => {
|
|
7692
7685
|
const d = new Date(ts);
|
|
@@ -7698,6 +7691,8 @@ var init_Live = __esm({
|
|
|
7698
7691
|
return `${p(Math.floor(s / 3600))}:${p(Math.floor(s % 3600 / 60))}:${p(s % 60)}`;
|
|
7699
7692
|
};
|
|
7700
7693
|
FILTERS = ["all", "local", "cloud"];
|
|
7694
|
+
SESS_FILTERS = ["all", "active", "idle", "ended"];
|
|
7695
|
+
sessStatus = (lastAt, now) => now - lastAt < 9e4 ? "active" : now - lastAt < 3e5 ? "idle" : "ended";
|
|
7701
7696
|
}
|
|
7702
7697
|
});
|
|
7703
7698
|
|
|
@@ -9359,8 +9354,8 @@ __export(global_install_exports, {
|
|
|
9359
9354
|
runGlobalRestore: () => runGlobalRestore,
|
|
9360
9355
|
unlockProtected: () => unlockProtected
|
|
9361
9356
|
});
|
|
9362
|
-
import { readFileSync as readFileSync6, writeFileSync as
|
|
9363
|
-
import { resolve as resolve4, join as join6, dirname
|
|
9357
|
+
import { readFileSync as readFileSync6, writeFileSync as writeFileSync3, existsSync as existsSync4, mkdirSync as mkdirSync3 } from "fs";
|
|
9358
|
+
import { resolve as resolve4, join as join6, dirname } from "path";
|
|
9364
9359
|
import { homedir as homedir4 } from "os";
|
|
9365
9360
|
import { fileURLToPath } from "url";
|
|
9366
9361
|
import { createInterface } from "readline";
|
|
@@ -9472,13 +9467,13 @@ function runGlobalRestore() {
|
|
|
9472
9467
|
unlockProtected();
|
|
9473
9468
|
removeClaudeShim();
|
|
9474
9469
|
if (existsSync4(p.backupPath)) {
|
|
9475
|
-
|
|
9470
|
+
writeFileSync3(p.settingsPath, readFileSync6(p.backupPath, "utf-8"));
|
|
9476
9471
|
console.log(` Restored ${p.settingsPath} from backup.`);
|
|
9477
9472
|
} else if (existsSync4(p.settingsPath)) {
|
|
9478
9473
|
try {
|
|
9479
9474
|
const s = JSON.parse(readFileSync6(p.settingsPath, "utf-8"));
|
|
9480
9475
|
delete s.hooks;
|
|
9481
|
-
|
|
9476
|
+
writeFileSync3(p.settingsPath, JSON.stringify(s, null, 2) + "\n");
|
|
9482
9477
|
console.log(` Removed SolonGate hooks from ${p.settingsPath}.`);
|
|
9483
9478
|
} catch {
|
|
9484
9479
|
}
|
|
@@ -9522,8 +9517,8 @@ function writeShimBlock(file, block) {
|
|
|
9522
9517
|
if (content.length && !content.endsWith("\n")) content += "\n";
|
|
9523
9518
|
content += block + "\n";
|
|
9524
9519
|
}
|
|
9525
|
-
|
|
9526
|
-
|
|
9520
|
+
mkdirSync3(dirname(file), { recursive: true });
|
|
9521
|
+
writeFileSync3(file, content);
|
|
9527
9522
|
}
|
|
9528
9523
|
function installClaudeShim(shieldPath) {
|
|
9529
9524
|
const real = resolveRealClaude();
|
|
@@ -9580,22 +9575,22 @@ async function runGlobalInstall(opts = {}) {
|
|
|
9580
9575
|
process.exit(1);
|
|
9581
9576
|
}
|
|
9582
9577
|
const apiUrl = opts.apiUrl || process.env["SOLONGATE_API_URL"] || "https://api.solongate.com";
|
|
9583
|
-
|
|
9584
|
-
|
|
9578
|
+
mkdirSync3(p.hooksDir, { recursive: true });
|
|
9579
|
+
mkdirSync3(p.claudeDir, { recursive: true });
|
|
9585
9580
|
unlockProtected();
|
|
9586
|
-
|
|
9587
|
-
|
|
9588
|
-
|
|
9589
|
-
|
|
9581
|
+
writeFileSync3(join6(p.hooksDir, "guard.mjs"), readGuard());
|
|
9582
|
+
writeFileSync3(join6(p.hooksDir, "audit.mjs"), readHook("audit.mjs"));
|
|
9583
|
+
writeFileSync3(join6(p.hooksDir, "stop.mjs"), readHook("stop.mjs"));
|
|
9584
|
+
writeFileSync3(join6(p.hooksDir, "shield.mjs"), readHook("shield.mjs"));
|
|
9590
9585
|
console.log(` Installed hooks \u2192 ${p.hooksDir}`);
|
|
9591
9586
|
removeClaudeShim();
|
|
9592
|
-
|
|
9587
|
+
writeFileSync3(p.configPath, JSON.stringify({ apiKey, apiUrl }, null, 2) + "\n");
|
|
9593
9588
|
console.log(` Wrote ${p.configPath}`);
|
|
9594
9589
|
let existing = {};
|
|
9595
9590
|
if (existsSync4(p.settingsPath)) {
|
|
9596
9591
|
const raw = readFileSync6(p.settingsPath, "utf-8");
|
|
9597
9592
|
if (!existsSync4(p.backupPath)) {
|
|
9598
|
-
|
|
9593
|
+
writeFileSync3(p.backupPath, raw);
|
|
9599
9594
|
console.log(` Backed up existing settings \u2192 ${p.backupPath}`);
|
|
9600
9595
|
}
|
|
9601
9596
|
try {
|
|
@@ -9616,7 +9611,7 @@ async function runGlobalInstall(opts = {}) {
|
|
|
9616
9611
|
Stop: [{ matcher: "", hooks: [{ type: "command", command: `"${nodeBin}" "${stopAbs}" claude-code "Claude Code"` }] }]
|
|
9617
9612
|
}
|
|
9618
9613
|
};
|
|
9619
|
-
|
|
9614
|
+
writeFileSync3(p.settingsPath, JSON.stringify(merged, null, 2) + "\n");
|
|
9620
9615
|
console.log(` Registered global hooks \u2192 ${p.settingsPath}`);
|
|
9621
9616
|
if (process.env["SOLONGATE_OS_LOCK"] === "1") {
|
|
9622
9617
|
lockProtected();
|
|
@@ -9630,7 +9625,7 @@ var __dirname, HOOKS_DIR, SHIM_BEGIN, SHIM_END;
|
|
|
9630
9625
|
var init_global_install = __esm({
|
|
9631
9626
|
"src/global-install.ts"() {
|
|
9632
9627
|
"use strict";
|
|
9633
|
-
__dirname =
|
|
9628
|
+
__dirname = dirname(fileURLToPath(import.meta.url));
|
|
9634
9629
|
HOOKS_DIR = resolve4(__dirname, "..", "hooks");
|
|
9635
9630
|
SHIM_BEGIN = "# >>> SolonGate shield (auto secret redaction) >>>";
|
|
9636
9631
|
SHIM_END = "# <<< SolonGate shield <<<";
|
|
@@ -10280,7 +10275,7 @@ var init_logs_server = __esm({
|
|
|
10280
10275
|
|
|
10281
10276
|
// src/inject.ts
|
|
10282
10277
|
var inject_exports = {};
|
|
10283
|
-
import { readFileSync as readFileSync9, writeFileSync as
|
|
10278
|
+
import { readFileSync as readFileSync9, writeFileSync as writeFileSync4, existsSync as existsSync6, copyFileSync } from "fs";
|
|
10284
10279
|
import { resolve as resolve7 } from "path";
|
|
10285
10280
|
import { execSync } from "child_process";
|
|
10286
10281
|
function parseInjectArgs(argv) {
|
|
@@ -10588,7 +10583,7 @@ async function main2() {
|
|
|
10588
10583
|
log3("");
|
|
10589
10584
|
log3(` Backup: ${backupPath}`);
|
|
10590
10585
|
}
|
|
10591
|
-
|
|
10586
|
+
writeFileSync4(entryFile, result.modified);
|
|
10592
10587
|
log3("");
|
|
10593
10588
|
log3(" \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510");
|
|
10594
10589
|
log3(" \u2502 SolonGate SDK injected successfully! \u2502");
|
|
@@ -10617,7 +10612,7 @@ var init_inject = __esm({
|
|
|
10617
10612
|
|
|
10618
10613
|
// src/create.ts
|
|
10619
10614
|
var create_exports = {};
|
|
10620
|
-
import { mkdirSync as
|
|
10615
|
+
import { mkdirSync as mkdirSync4, writeFileSync as writeFileSync5, existsSync as existsSync7 } from "fs";
|
|
10621
10616
|
import { resolve as resolve8, join as join8 } from "path";
|
|
10622
10617
|
import { execSync as execSync2 } from "child_process";
|
|
10623
10618
|
function withSpinner(message, fn) {
|
|
@@ -10697,7 +10692,7 @@ EXAMPLES
|
|
|
10697
10692
|
`);
|
|
10698
10693
|
}
|
|
10699
10694
|
function createProject(dir, name, _policy) {
|
|
10700
|
-
|
|
10695
|
+
writeFileSync5(
|
|
10701
10696
|
join8(dir, "package.json"),
|
|
10702
10697
|
JSON.stringify(
|
|
10703
10698
|
{
|
|
@@ -10727,7 +10722,7 @@ function createProject(dir, name, _policy) {
|
|
|
10727
10722
|
2
|
|
10728
10723
|
) + "\n"
|
|
10729
10724
|
);
|
|
10730
|
-
|
|
10725
|
+
writeFileSync5(
|
|
10731
10726
|
join8(dir, "tsconfig.json"),
|
|
10732
10727
|
JSON.stringify(
|
|
10733
10728
|
{
|
|
@@ -10748,8 +10743,8 @@ function createProject(dir, name, _policy) {
|
|
|
10748
10743
|
2
|
|
10749
10744
|
) + "\n"
|
|
10750
10745
|
);
|
|
10751
|
-
|
|
10752
|
-
|
|
10746
|
+
mkdirSync4(join8(dir, "src"), { recursive: true });
|
|
10747
|
+
writeFileSync5(
|
|
10753
10748
|
join8(dir, "src", "index.ts"),
|
|
10754
10749
|
`#!/usr/bin/env node
|
|
10755
10750
|
|
|
@@ -10791,7 +10786,7 @@ console.log('');
|
|
|
10791
10786
|
console.log('Press Ctrl+C to stop.');
|
|
10792
10787
|
`
|
|
10793
10788
|
);
|
|
10794
|
-
|
|
10789
|
+
writeFileSync5(
|
|
10795
10790
|
join8(dir, ".mcp.json"),
|
|
10796
10791
|
JSON.stringify(
|
|
10797
10792
|
{
|
|
@@ -10809,12 +10804,12 @@ console.log('Press Ctrl+C to stop.');
|
|
|
10809
10804
|
2
|
|
10810
10805
|
) + "\n"
|
|
10811
10806
|
);
|
|
10812
|
-
|
|
10807
|
+
writeFileSync5(
|
|
10813
10808
|
join8(dir, ".env"),
|
|
10814
10809
|
`SOLONGATE_API_KEY=sg_live_YOUR_KEY_HERE
|
|
10815
10810
|
`
|
|
10816
10811
|
);
|
|
10817
|
-
|
|
10812
|
+
writeFileSync5(
|
|
10818
10813
|
join8(dir, ".gitignore"),
|
|
10819
10814
|
`node_modules/
|
|
10820
10815
|
dist/
|
|
@@ -10834,7 +10829,7 @@ async function main3() {
|
|
|
10834
10829
|
process.exit(1);
|
|
10835
10830
|
}
|
|
10836
10831
|
withSpinner(`Setting up ${opts.name}...`, () => {
|
|
10837
|
-
|
|
10832
|
+
mkdirSync4(dir, { recursive: true });
|
|
10838
10833
|
createProject(dir, opts.name, opts.policy);
|
|
10839
10834
|
});
|
|
10840
10835
|
if (!opts.noInstall) {
|
|
@@ -10908,7 +10903,7 @@ var init_create = __esm({
|
|
|
10908
10903
|
|
|
10909
10904
|
// src/pull-push.ts
|
|
10910
10905
|
var pull_push_exports = {};
|
|
10911
|
-
import { readFileSync as readFileSync10, writeFileSync as
|
|
10906
|
+
import { readFileSync as readFileSync10, writeFileSync as writeFileSync6, existsSync as existsSync8 } from "fs";
|
|
10912
10907
|
import { resolve as resolve9 } from "path";
|
|
10913
10908
|
function loadEnv() {
|
|
10914
10909
|
if (process.env.SOLONGATE_API_KEY) return;
|
|
@@ -11103,7 +11098,7 @@ async function pull(apiKey, file, policyId) {
|
|
|
11103
11098
|
const policy = await fetchCloudPolicy(apiKey, API_URL, policyId);
|
|
11104
11099
|
const { id: _id, ...policyWithoutId } = policy;
|
|
11105
11100
|
const json = JSON.stringify(policyWithoutId, null, 2) + "\n";
|
|
11106
|
-
|
|
11101
|
+
writeFileSync6(file, json, "utf-8");
|
|
11107
11102
|
log5("");
|
|
11108
11103
|
log5(green2(" Saved to: ") + file);
|
|
11109
11104
|
log5(` ${dim2("Name:")} ${policy.name}`);
|