@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/tui/index.js
CHANGED
|
@@ -126,9 +126,10 @@ function KeyHints({ hints }) {
|
|
|
126
126
|
|
|
127
127
|
// src/tui/panels/Live.tsx
|
|
128
128
|
import { Box as Box2, Text as Text2, useInput } from "ink";
|
|
129
|
-
import {
|
|
129
|
+
import { spawnSync } from "child_process";
|
|
130
|
+
import { closeSync, mkdirSync, openSync, readSync, statSync, writeFileSync } from "fs";
|
|
130
131
|
import { homedir as homedir2 } from "os";
|
|
131
|
-
import { join as join2 } from "path";
|
|
132
|
+
import { dirname, join as join2 } from "path";
|
|
132
133
|
import { useCallback as useCallback2, useEffect as useEffect2, useRef as useRef2, useState as useState2 } from "react";
|
|
133
134
|
|
|
134
135
|
// src/api-client/client.ts
|
|
@@ -436,8 +437,11 @@ function usePoll(reload, intervalMs, enabled = true) {
|
|
|
436
437
|
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
437
438
|
var SPIN = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
438
439
|
var BG = "#12234f";
|
|
440
|
+
var DIM_FLOOR = "#233457";
|
|
439
441
|
var LOCAL_LOG = join2(homedir2(), ".solongate", "local-logs", "solongate-audit.jsonl");
|
|
440
442
|
var RING = join2(process.cwd(), ".solongate", ".eval-ring.jsonl");
|
|
443
|
+
var DUMP = join2(homedir2(), ".solongate", "live-stream.log");
|
|
444
|
+
var STREAM_KEEP = 100;
|
|
441
445
|
var hhmmss = (ts) => {
|
|
442
446
|
const d = new Date(ts);
|
|
443
447
|
return Number.isNaN(d.getTime()) ? "--:--:--" : d.toTimeString().slice(0, 8);
|
|
@@ -447,7 +451,7 @@ var fmtUp = (ms) => {
|
|
|
447
451
|
const p = (n) => String(n).padStart(2, "0");
|
|
448
452
|
return `${p(Math.floor(s / 3600))}:${p(Math.floor(s % 3600 / 60))}:${p(s % 60)}`;
|
|
449
453
|
};
|
|
450
|
-
function tailLines(file, maxBytes =
|
|
454
|
+
function tailLines(file, maxBytes = 131072) {
|
|
451
455
|
try {
|
|
452
456
|
const size = statSync(file).size;
|
|
453
457
|
const start = Math.max(0, size - maxBytes);
|
|
@@ -462,6 +466,22 @@ function tailLines(file, maxBytes = 65536) {
|
|
|
462
466
|
return [];
|
|
463
467
|
}
|
|
464
468
|
}
|
|
469
|
+
function copyToClipboard(text) {
|
|
470
|
+
const tools = [
|
|
471
|
+
["wl-copy", []],
|
|
472
|
+
["xclip", ["-selection", "clipboard"]],
|
|
473
|
+
["xsel", ["--clipboard", "--input"]]
|
|
474
|
+
];
|
|
475
|
+
for (const [cmd, args] of tools) {
|
|
476
|
+
try {
|
|
477
|
+
const r = spawnSync(cmd, args, { input: text, timeout: 2e3 });
|
|
478
|
+
if (r.status === 0) return cmd;
|
|
479
|
+
} catch {
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
process.stdout.write(`\x1B]52;c;${Buffer.from(text, "utf-8").toString("base64")}\x07`);
|
|
483
|
+
return "osc52";
|
|
484
|
+
}
|
|
465
485
|
function cloudItem(e) {
|
|
466
486
|
return {
|
|
467
487
|
id: "c:" + e.id,
|
|
@@ -471,7 +491,11 @@ function cloudItem(e) {
|
|
|
471
491
|
permission: (e.permission ?? "").slice(0, 4),
|
|
472
492
|
detail: (e.arguments_summary ? JSON.stringify(e.arguments_summary) : e.reason ?? "").replace(/\s+/g, " "),
|
|
473
493
|
dlp: !!e.dlp_matches?.length,
|
|
474
|
-
source: "cloud"
|
|
494
|
+
source: "cloud",
|
|
495
|
+
session: e.session_id ?? void 0,
|
|
496
|
+
agent: e.agent_name ?? void 0,
|
|
497
|
+
evalMs: e.evaluation_time_ms ?? void 0,
|
|
498
|
+
rule: e.matched_rule_id ?? void 0
|
|
475
499
|
};
|
|
476
500
|
}
|
|
477
501
|
function ColumnChart({ series, hot, height, width, color, hotColor = theme.bad }) {
|
|
@@ -490,7 +514,7 @@ function ColumnChart({ series, hot, height, width, color, hotColor = theme.bad }
|
|
|
490
514
|
else if (frac >= (r - 0.5) / height) ch = "\u2584";
|
|
491
515
|
else if (r === 1) ch = "\u2581";
|
|
492
516
|
else ch = " ";
|
|
493
|
-
const c2 = r === 1 && v === 0 ?
|
|
517
|
+
const c2 = r === 1 && v === 0 ? DIM_FLOOR : hotPad?.[i] ? hotColor : color;
|
|
494
518
|
const last = segs[segs.length - 1];
|
|
495
519
|
if (last && last.color === c2) last.text += ch;
|
|
496
520
|
else segs.push({ text: ch, color: c2 });
|
|
@@ -506,7 +530,7 @@ function HBar({ label, value, max, width, color }) {
|
|
|
506
530
|
return /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
507
531
|
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: label.padEnd(10) }),
|
|
508
532
|
/* @__PURE__ */ jsx2(Text2, { color, children: "\u2588".repeat(Math.min(width, filled)) }),
|
|
509
|
-
/* @__PURE__ */ jsx2(Text2, { color:
|
|
533
|
+
/* @__PURE__ */ jsx2(Text2, { color: DIM_FLOOR, children: "\u2591".repeat(Math.max(0, width - filled)) }),
|
|
510
534
|
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " " + value })
|
|
511
535
|
] });
|
|
512
536
|
}
|
|
@@ -522,6 +546,26 @@ function PaneTitle({ label, extra, width }) {
|
|
|
522
546
|
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: tail + "\u2500".repeat(Math.max(0, width - used)) })
|
|
523
547
|
] });
|
|
524
548
|
}
|
|
549
|
+
function StreamLine({ e }) {
|
|
550
|
+
return /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
551
|
+
/* @__PURE__ */ jsxs2(Text2, { color: theme.dim, children: [
|
|
552
|
+
"[",
|
|
553
|
+
hhmmss(e.at),
|
|
554
|
+
" "
|
|
555
|
+
] }),
|
|
556
|
+
/* @__PURE__ */ jsx2(Text2, { color: e.source === "local" ? theme.ok : "#4f6db8", children: e.source === "local" ? "LOC" : "CLD" }),
|
|
557
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "] " }),
|
|
558
|
+
/* @__PURE__ */ jsx2(Text2, { color: decisionColor(e.decision), bold: e.decision !== "ALLOW", children: e.decision.padEnd(6) }),
|
|
559
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.accent, children: truncate(e.tool, 12).padEnd(13) }),
|
|
560
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: e.permission.padEnd(5) }),
|
|
561
|
+
/* @__PURE__ */ jsx2(Text2, { color: e.evalMs != null && e.evalMs > 500 ? theme.warn : theme.dim, children: (e.evalMs != null ? `${e.evalMs}ms` : "\u2014").padEnd(7) }),
|
|
562
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: truncate(e.agent ?? "-", 11).padEnd(12) }),
|
|
563
|
+
e.dlp ? /* @__PURE__ */ jsx2(Text2, { color: theme.bad, children: "DLP! " }) : null,
|
|
564
|
+
e.rule && e.decision !== "ALLOW" ? /* @__PURE__ */ jsx2(Text2, { color: theme.bad, children: truncate(e.rule, 14) + " " }) : null,
|
|
565
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: e.detail })
|
|
566
|
+
] });
|
|
567
|
+
}
|
|
568
|
+
var FILTERS = ["all", "local", "cloud"];
|
|
525
569
|
function LivePanel({ active: active2 }) {
|
|
526
570
|
const [s, setS] = useState2(null);
|
|
527
571
|
const [tsData, setTsData] = useState2(null);
|
|
@@ -531,18 +575,17 @@ function LivePanel({ active: active2 }) {
|
|
|
531
575
|
const [localOn, setLocalOn] = useState2(null);
|
|
532
576
|
const [ring, setRing] = useState2(null);
|
|
533
577
|
const [log, setLog] = useState2([]);
|
|
578
|
+
const [filter, setFilter] = useState2("all");
|
|
579
|
+
const [scroll, setScroll] = useState2(0);
|
|
580
|
+
const [toast, setToast] = useState2(null);
|
|
581
|
+
const [mode, setMode] = useState2("stream");
|
|
582
|
+
const [pickIdx, setPickIdx] = useState2(0);
|
|
583
|
+
const [detail, setDetail] = useState2(null);
|
|
584
|
+
const [detailCloud, setDetailCloud] = useState2([]);
|
|
585
|
+
const [detailScroll, setDetailScroll] = useState2(0);
|
|
534
586
|
const seenRef = useRef2(/* @__PURE__ */ new Set());
|
|
535
587
|
const lastLocalTs = useRef2(0);
|
|
536
588
|
const pausedUntil = useRef2(0);
|
|
537
|
-
const [frozen, setFrozen] = useState2(false);
|
|
538
|
-
const frozenRef = useRef2(false);
|
|
539
|
-
frozenRef.current = frozen;
|
|
540
|
-
useInput(
|
|
541
|
-
(input) => {
|
|
542
|
-
if (input === "p") setFrozen((f) => !f);
|
|
543
|
-
},
|
|
544
|
-
{ isActive: active2 }
|
|
545
|
-
);
|
|
546
589
|
const pushLog = useCallback2((msg, level = "ok") => {
|
|
547
590
|
setLog((prev) => [...prev.slice(-59), { ts: Date.now(), msg, level }]);
|
|
548
591
|
}, []);
|
|
@@ -558,9 +601,8 @@ function LivePanel({ active: active2 }) {
|
|
|
558
601
|
},
|
|
559
602
|
[pushLog]
|
|
560
603
|
);
|
|
561
|
-
const paused = () =>
|
|
604
|
+
const paused = () => Date.now() < pausedUntil.current;
|
|
562
605
|
const pollLocal = useCallback2(() => {
|
|
563
|
-
if (frozenRef.current) return;
|
|
564
606
|
const lines = tailLines(LOCAL_LOG);
|
|
565
607
|
if (!lines.length) {
|
|
566
608
|
setLocalOn((prev) => prev === null ? false : prev);
|
|
@@ -583,7 +625,9 @@ function LivePanel({ active: active2 }) {
|
|
|
583
625
|
dlp: !!j.dlp,
|
|
584
626
|
source: "local",
|
|
585
627
|
session: j.session_id,
|
|
586
|
-
agent: j.agent_name
|
|
628
|
+
agent: j.agent_name,
|
|
629
|
+
evalMs: j.evaluation_time_ms,
|
|
630
|
+
rule: j.matched_rule_id
|
|
587
631
|
});
|
|
588
632
|
} catch {
|
|
589
633
|
}
|
|
@@ -592,9 +636,7 @@ function LivePanel({ active: active2 }) {
|
|
|
592
636
|
lastLocalTs.current = fresh[fresh.length - 1].at;
|
|
593
637
|
setLocalBuf((prev) => [...prev, ...fresh].slice(-400));
|
|
594
638
|
const denies = fresh.filter((f) => f.decision !== "ALLOW").length;
|
|
595
|
-
if (
|
|
596
|
-
pushLog(`local +${fresh.length} calls${denies ? ` \xB7 ${denies} DENIED` : ""}`, denies ? "bad" : "warn");
|
|
597
|
-
}
|
|
639
|
+
if (fresh.length < 10) pushLog(`local +${fresh.length} calls${denies ? ` \xB7 ${denies} DENIED` : ""}`, denies ? "bad" : "warn");
|
|
598
640
|
}
|
|
599
641
|
const ringLines = tailLines(RING, 8192).slice(-30);
|
|
600
642
|
if (ringLines.length) {
|
|
@@ -631,12 +673,11 @@ function LivePanel({ active: active2 }) {
|
|
|
631
673
|
const fresh = fd.entries.filter((e) => !seenRef.current.has(e.id));
|
|
632
674
|
const firstLoad = seenRef.current.size === 0 && fresh.length > 1;
|
|
633
675
|
for (const e of fresh) seenRef.current.add(e.id);
|
|
634
|
-
if (fresh.length)
|
|
635
|
-
setCloudBuf((prev) => [...prev, ...fresh.map(cloudItem).sort((a, b) => a.at - b.at)].slice(-400));
|
|
636
|
-
}
|
|
676
|
+
if (fresh.length) setCloudBuf((prev) => [...prev, ...fresh.map(cloudItem).sort((a, b) => a.at - b.at)].slice(-400));
|
|
637
677
|
const denies = fresh.filter((e) => e.decision !== "ALLOW").length;
|
|
638
678
|
if (firstLoad) pushLog(`cloud link up \xB7 api ${ms}ms \xB7 ${fresh.length} calls`);
|
|
639
|
-
else pushLog(`api ${ms}ms \xB7 +${fresh.length} cloud${denies ? ` \xB7 ${denies} DENIED` : ""}`, denies ? "bad" :
|
|
679
|
+
else if (fresh.length) pushLog(`api ${ms}ms \xB7 +${fresh.length} cloud${denies ? ` \xB7 ${denies} DENIED` : ""}`, denies ? "bad" : "warn");
|
|
680
|
+
else pushLog(`api ${ms}ms \xB7 idle`, "ok");
|
|
640
681
|
} catch (e) {
|
|
641
682
|
onApiError(e);
|
|
642
683
|
}
|
|
@@ -673,30 +714,50 @@ function LivePanel({ active: active2 }) {
|
|
|
673
714
|
}, [active2, pollFeed, pollMedium, pollSlow]);
|
|
674
715
|
const sessions = useLoader(() => api.agents.live({ limit: 30, includeDeactivated: true }));
|
|
675
716
|
const insights = useLoader(() => api.stats.securityInsights(7));
|
|
717
|
+
const guard = useLoader(() => api.settings.getGuardStatus());
|
|
676
718
|
usePoll(() => {
|
|
677
719
|
if (!paused()) sessions.reload();
|
|
678
720
|
}, 1e4, active2);
|
|
679
721
|
usePoll(() => {
|
|
680
722
|
if (!paused()) insights.reload();
|
|
681
723
|
}, 3e4, active2);
|
|
724
|
+
usePoll(() => {
|
|
725
|
+
if (!paused()) guard.reload();
|
|
726
|
+
}, 6e4, active2);
|
|
727
|
+
useEffect2(() => {
|
|
728
|
+
if (!detail) return;
|
|
729
|
+
setDetailCloud([]);
|
|
730
|
+
setDetailScroll(0);
|
|
731
|
+
let alive = true;
|
|
732
|
+
api.audit.list({ session_id: detail.id, limit: 100 }).then((r) => {
|
|
733
|
+
if (alive) setDetailCloud(r.entries.map(cloudItem));
|
|
734
|
+
}).catch(() => {
|
|
735
|
+
});
|
|
736
|
+
return () => {
|
|
737
|
+
alive = false;
|
|
738
|
+
};
|
|
739
|
+
}, [detail]);
|
|
682
740
|
const [tick, setTick] = useState2(0);
|
|
683
741
|
useEffect2(() => {
|
|
684
|
-
if (!active2
|
|
685
|
-
const t = setInterval(() => setTick((n) => n + 1),
|
|
742
|
+
if (!active2) return;
|
|
743
|
+
const t = setInterval(() => setTick((n) => n + 1), 500);
|
|
686
744
|
return () => clearInterval(t);
|
|
687
|
-
}, [active2
|
|
745
|
+
}, [active2]);
|
|
688
746
|
const startRef = useRef2(Date.now());
|
|
689
747
|
const cols = process.stdout.columns ?? 100;
|
|
690
748
|
const rows = process.stdout.rows ?? 30;
|
|
691
749
|
const ins = insights.data ?? {};
|
|
692
750
|
const spin = SPIN[tick % SPIN.length];
|
|
693
|
-
const points = tsData?.timeseries ?? [];
|
|
694
|
-
const mergedAll = [...cloudBuf, ...localBuf].sort((a, b) => a.at - b.at);
|
|
695
751
|
const nowMs = Date.now();
|
|
752
|
+
const mergedAll = [...cloudBuf, ...localBuf].sort((a, b) => a.at - b.at);
|
|
753
|
+
const filtered = filter === "all" ? mergedAll : mergedAll.filter((e) => e.source === filter);
|
|
754
|
+
const visibleDesc = filtered.slice(-STREAM_KEEP).reverse();
|
|
755
|
+
const points = tsData?.timeseries ?? [];
|
|
756
|
+
const nowMin = Math.floor(nowMs / 6e4);
|
|
696
757
|
const minuteCounts = new Array(60).fill(0);
|
|
697
758
|
const minuteHot = new Array(60).fill(false);
|
|
698
759
|
for (const e of mergedAll) {
|
|
699
|
-
const idx = 59 - Math.floor(
|
|
760
|
+
const idx = 59 - (nowMin - Math.floor(e.at / 6e4));
|
|
700
761
|
if (idx >= 0 && idx < 60) {
|
|
701
762
|
minuteCounts[idx]++;
|
|
702
763
|
if (e.decision !== "ALLOW") minuteHot[idx] = true;
|
|
@@ -708,14 +769,14 @@ function LivePanel({ active: active2 }) {
|
|
|
708
769
|
const trafficLabel = localTraffic ? "calls/min \xB7 60m \xB7 local+cloud" : "24h \xB7 cloud";
|
|
709
770
|
const rl = ins.layers?.rateLimit;
|
|
710
771
|
const dl = ins.layers?.dlp;
|
|
711
|
-
const
|
|
772
|
+
const gh = ins.layers?.ghost;
|
|
773
|
+
const minuteNow = minuteCounts[59] ?? 0;
|
|
712
774
|
const dlpBars = (ins.dlpByPattern ?? []).slice(0, 2);
|
|
713
775
|
const maxDlpBar = dlpBars[0]?.count ?? 1;
|
|
714
|
-
const
|
|
715
|
-
const
|
|
716
|
-
const lastDeny = denials[denials.length - 1];
|
|
776
|
+
const denialsAll = mergedAll.filter((e) => e.decision !== "ALLOW");
|
|
777
|
+
const lastDeny = denialsAll[denialsAll.length - 1];
|
|
717
778
|
const toolCounts = /* @__PURE__ */ new Map();
|
|
718
|
-
for (const e of
|
|
779
|
+
for (const e of mergedAll) toolCounts.set(e.tool, (toolCounts.get(e.tool) ?? 0) + 1);
|
|
719
780
|
const topTools = [...toolCounts.entries()].sort((a, b) => b[1] - a[1]).slice(0, 3);
|
|
720
781
|
const latNow = lat[lat.length - 1] ?? 0;
|
|
721
782
|
const sortedLat = [...lat].sort((a, b) => a - b);
|
|
@@ -734,22 +795,174 @@ function LivePanel({ active: active2 }) {
|
|
|
734
795
|
if (e.agent) cur.agent = e.agent;
|
|
735
796
|
localSess.set(e.session, cur);
|
|
736
797
|
}
|
|
737
|
-
const
|
|
798
|
+
const combinedSess = [
|
|
799
|
+
...[...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 })),
|
|
800
|
+
...sess.filter((a) => !localSess.has(a.session_id)).map((a) => ({
|
|
801
|
+
source: "cloud",
|
|
802
|
+
id: a.session_id,
|
|
803
|
+
agent: a.agent_name ?? a.session_id,
|
|
804
|
+
calls: a.total_calls,
|
|
805
|
+
denies: a.denied_calls,
|
|
806
|
+
lastAt: Date.parse(a.last_seen_at),
|
|
807
|
+
trust: a.trust_score,
|
|
808
|
+
isMe: false
|
|
809
|
+
}))
|
|
810
|
+
];
|
|
738
811
|
const chartH = rows >= 36 ? 6 : 4;
|
|
739
|
-
const colH = rows >= 32 ?
|
|
740
|
-
const streamRows = Math.max(4, rows -
|
|
741
|
-
const tail = merged.slice(-streamRows);
|
|
812
|
+
const colH = rows >= 32 ? 7 : 5;
|
|
813
|
+
const streamRows = Math.max(4, rows - 5 - (1 + chartH) - colH);
|
|
742
814
|
const innerW = cols - 2;
|
|
743
815
|
const leftW = Math.floor(innerW * 0.55);
|
|
744
816
|
const rightW = innerW - leftW - 2;
|
|
745
817
|
const colW = Math.max(20, Math.floor((innerW - 4) / 3));
|
|
818
|
+
const pickable = combinedSess.slice(0, colH - 1);
|
|
819
|
+
const maxScroll = Math.max(0, visibleDesc.length - streamRows);
|
|
820
|
+
const clampedScroll = Math.min(scroll, maxScroll);
|
|
821
|
+
const windowed = visibleDesc.slice(clampedScroll, clampedScroll + streamRows);
|
|
822
|
+
const detailEntries = detail ? (() => {
|
|
823
|
+
const seen = /* @__PURE__ */ new Set();
|
|
824
|
+
const all = [];
|
|
825
|
+
for (const e of [...detailCloud, ...mergedAll.filter((x) => x.session === detail.id)]) {
|
|
826
|
+
const key = `${e.at}:${e.tool}:${e.decision}`;
|
|
827
|
+
if (seen.has(key)) continue;
|
|
828
|
+
seen.add(key);
|
|
829
|
+
all.push(e);
|
|
830
|
+
}
|
|
831
|
+
return all.sort((a, b) => b.at - a.at);
|
|
832
|
+
})() : [];
|
|
833
|
+
useInput(
|
|
834
|
+
(input, key) => {
|
|
835
|
+
if (mode === "detail") {
|
|
836
|
+
const maxD = Math.max(0, detailEntries.length - (rows - 10));
|
|
837
|
+
if (key.leftArrow) {
|
|
838
|
+
setMode("stream");
|
|
839
|
+
setDetail(null);
|
|
840
|
+
} else if (key.upArrow) setDetailScroll((n) => Math.max(0, n - 1));
|
|
841
|
+
else if (key.downArrow) setDetailScroll((n) => Math.min(maxD, n + 1));
|
|
842
|
+
else if (key.pageUp) setDetailScroll((n) => Math.max(0, n - 10));
|
|
843
|
+
else if (key.pageDown) setDetailScroll((n) => Math.min(maxD, n + 10));
|
|
844
|
+
return;
|
|
845
|
+
}
|
|
846
|
+
if (mode === "pick") {
|
|
847
|
+
if (key.upArrow) setPickIdx((n) => Math.max(0, n - 1));
|
|
848
|
+
else if (key.downArrow) setPickIdx((n) => Math.min(pickable.length - 1, n + 1));
|
|
849
|
+
else if (key.return) {
|
|
850
|
+
const row = pickable[pickIdx];
|
|
851
|
+
if (row) {
|
|
852
|
+
setDetail(row);
|
|
853
|
+
setMode("detail");
|
|
854
|
+
}
|
|
855
|
+
} else if (input === "s" || key.leftArrow) setMode("stream");
|
|
856
|
+
return;
|
|
857
|
+
}
|
|
858
|
+
if (input === "f") {
|
|
859
|
+
setFilter((f) => FILTERS[(FILTERS.indexOf(f) + 1) % FILTERS.length]);
|
|
860
|
+
setScroll(0);
|
|
861
|
+
} else if (input === "s") {
|
|
862
|
+
setPickIdx(0);
|
|
863
|
+
setMode("pick");
|
|
864
|
+
} else if (key.downArrow) setScroll((n) => Math.min(maxScroll, n + 1));
|
|
865
|
+
else if (key.upArrow) setScroll((n) => Math.max(0, n - 1));
|
|
866
|
+
else if (key.pageDown) setScroll((n) => Math.min(maxScroll, n + streamRows));
|
|
867
|
+
else if (key.pageUp) setScroll((n) => Math.max(0, n - streamRows));
|
|
868
|
+
else if (input === "c") {
|
|
869
|
+
const dump = visibleDesc.map(
|
|
870
|
+
(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}`
|
|
871
|
+
).join("\n");
|
|
872
|
+
let via = "file";
|
|
873
|
+
try {
|
|
874
|
+
mkdirSync(dirname(DUMP), { recursive: true });
|
|
875
|
+
writeFileSync(DUMP, dump + "\n");
|
|
876
|
+
} catch {
|
|
877
|
+
}
|
|
878
|
+
via = copyToClipboard(dump);
|
|
879
|
+
setToast({ msg: `copied ${visibleDesc.length} lines via ${via} + ${DUMP}`, until: Date.now() + 5e3 });
|
|
880
|
+
}
|
|
881
|
+
},
|
|
882
|
+
{ isActive: active2 }
|
|
883
|
+
);
|
|
746
884
|
const sessionDot = (st) => st === "active" ? { ch: "\u25CF", color: theme.ok } : st === "idle" ? { ch: "\u25CC", color: theme.warn } : { ch: "\u25CB", color: theme.dim };
|
|
885
|
+
void sessionDot;
|
|
886
|
+
if (s === null && localOn === null) {
|
|
887
|
+
return /* @__PURE__ */ jsxs2(Text2, { color: theme.dim, children: [
|
|
888
|
+
spin,
|
|
889
|
+
" connecting\u2026"
|
|
890
|
+
] });
|
|
891
|
+
}
|
|
892
|
+
const titleBar = /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
893
|
+
/* @__PURE__ */ jsx2(Text2, { backgroundColor: "#1432A0", color: "#AAC8FA", bold: true, children: " SOLONGATE LIVE " }),
|
|
894
|
+
/* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", children: ` ${spin} up ${fmtUp(nowMs - startRef.current)} \xB7 ${hhmmss(nowMs)} \xB7 api ${latNow}ms ` }),
|
|
895
|
+
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 " }),
|
|
896
|
+
toast && nowMs < toast.until ? /* @__PURE__ */ jsx2(Text2, { backgroundColor: "#123d1f", color: "#7bd88f", bold: true, children: ` ${toast.msg} ` }) : null
|
|
897
|
+
] });
|
|
898
|
+
if (mode === "detail" && detail) {
|
|
899
|
+
const d = detailEntries;
|
|
900
|
+
const allow = d.filter((e) => e.decision === "ALLOW").length;
|
|
901
|
+
const deny = d.length - allow;
|
|
902
|
+
const dlpN = d.filter((e) => e.dlp).length;
|
|
903
|
+
const evals = d.filter((e) => e.evalMs != null).map((e) => e.evalMs);
|
|
904
|
+
const evalAvg = evals.length ? Math.round(evals.reduce((a, b) => a + b, 0) / evals.length) : null;
|
|
905
|
+
const tCounts = /* @__PURE__ */ new Map();
|
|
906
|
+
const pCounts = /* @__PURE__ */ new Map();
|
|
907
|
+
for (const e of d) {
|
|
908
|
+
tCounts.set(e.tool, (tCounts.get(e.tool) ?? 0) + 1);
|
|
909
|
+
if (e.permission) pCounts.set(e.permission, (pCounts.get(e.permission) ?? 0) + 1);
|
|
910
|
+
}
|
|
911
|
+
const top = [...tCounts.entries()].sort((a, b) => b[1] - a[1]).slice(0, 6);
|
|
912
|
+
const perms = [...pCounts.entries()].sort((a, b) => b[1] - a[1]);
|
|
913
|
+
const first = d[d.length - 1]?.at;
|
|
914
|
+
const last = d[0]?.at;
|
|
915
|
+
const tlRows = Math.max(4, rows - 10);
|
|
916
|
+
const maxD = Math.max(0, d.length - tlRows);
|
|
917
|
+
const dScroll = Math.min(detailScroll, maxD);
|
|
918
|
+
const tl = d.slice(dScroll, dScroll + tlRows);
|
|
919
|
+
return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", paddingX: 1, children: [
|
|
920
|
+
titleBar,
|
|
921
|
+
/* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
922
|
+
/* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#AAC8FA", bold: true, children: ` SESSION ${detail.id.slice(0, 8)} ` }),
|
|
923
|
+
/* @__PURE__ */ jsx2(Text2, { color: detail.source === "local" ? theme.ok : "#4f6db8", children: " " + detail.source.toUpperCase() }),
|
|
924
|
+
/* @__PURE__ */ jsx2(Text2, { bold: true, children: " " + truncate(detail.isMe ? detail.agent + " (this machine)" : detail.agent, 34) }),
|
|
925
|
+
detail.trust != null ? /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: ` trust ${detail.trust}/100` }) : null,
|
|
926
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2190 back" })
|
|
927
|
+
] }),
|
|
928
|
+
/* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
929
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "\u2502 calls " }),
|
|
930
|
+
/* @__PURE__ */ jsx2(Text2, { bold: true, children: d.length }),
|
|
931
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502 allow " }),
|
|
932
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.ok, children: allow }),
|
|
933
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502 deny " }),
|
|
934
|
+
/* @__PURE__ */ jsx2(Text2, { color: deny ? theme.bad : theme.dim, bold: deny > 0, children: deny }),
|
|
935
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502 dlp " }),
|
|
936
|
+
/* @__PURE__ */ jsx2(Text2, { color: dlpN ? theme.bad : theme.dim, children: dlpN }),
|
|
937
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502 avg eval " }),
|
|
938
|
+
/* @__PURE__ */ jsx2(Text2, { children: evalAvg != null ? `${evalAvg}ms` : "\u2014" }),
|
|
939
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502 first " }),
|
|
940
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: first ? `${hhmmss(first)} (${ago(first)} ago)` : "\u2014" }),
|
|
941
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502 last " }),
|
|
942
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: last ? `${hhmmss(last)} (${ago(last)} ago)` : "\u2014" }),
|
|
943
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502" })
|
|
944
|
+
] }),
|
|
945
|
+
/* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
946
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "\u2502 tools " }),
|
|
947
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.accent, children: top.map(([t, c2]) => `${t}\xD7${c2}`).join(" ") || "\u2014" }),
|
|
948
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502 perms " }),
|
|
949
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: perms.map(([p, c2]) => `${p}\xD7${c2}`).join(" ") || "\u2014" }),
|
|
950
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502" })
|
|
951
|
+
] }),
|
|
952
|
+
/* @__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 }),
|
|
953
|
+
/* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", height: tlRows, overflow: "hidden", children: [
|
|
954
|
+
tl.length === 0 ? /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: detailCloud.length === 0 ? spin + " loading history\u2026" : "no entries" }) : null,
|
|
955
|
+
tl.map((e) => /* @__PURE__ */ jsx2(StreamLine, { e }, e.id))
|
|
956
|
+
] }),
|
|
957
|
+
/* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
958
|
+
/* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", bold: true, children: " SESSION " }),
|
|
959
|
+
/* @__PURE__ */ jsx2(Text2, { backgroundColor: "#0b1530", color: "#4f6db8", children: ` ${detail.id} ` }),
|
|
960
|
+
/* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", children: " \u2191\u2193 scroll \xB7 \u2190 back \xB7 esc menu " })
|
|
961
|
+
] })
|
|
962
|
+
] });
|
|
963
|
+
}
|
|
747
964
|
return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", paddingX: 1, children: [
|
|
748
|
-
|
|
749
|
-
/* @__PURE__ */ jsx2(Text2, { backgroundColor: "#1432A0", color: "#AAC8FA", bold: true, children: " SOLONGATE LIVE " }),
|
|
750
|
-
/* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", children: ` ${spin} up ${fmtUp(Date.now() - startRef.current)} \xB7 ${hhmmss(Date.now())} \xB7 api ${latNow}ms ` }),
|
|
751
|
-
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 " })
|
|
752
|
-
] }),
|
|
965
|
+
titleBar,
|
|
753
966
|
/* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
754
967
|
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "\u2502 calls " }),
|
|
755
968
|
/* @__PURE__ */ jsx2(Text2, { bold: true, children: s ? s.total_calls : "\xB7\xB7\xB7\xB7" }),
|
|
@@ -758,16 +971,20 @@ function LivePanel({ active: active2 }) {
|
|
|
758
971
|
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502 deny " }),
|
|
759
972
|
/* @__PURE__ */ jsx2(Text2, { color: theme.bad, bold: true, children: s ? s.denied : "\xB7\xB7" }),
|
|
760
973
|
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502 local " }),
|
|
761
|
-
localOn ? /* @__PURE__ */ jsx2(Text2, { color: theme.ok, children: "\u2713
|
|
762
|
-
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502
|
|
974
|
+
localOn ? /* @__PURE__ */ jsx2(Text2, { color: theme.ok, children: "\u2713" }) : /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "off" }),
|
|
975
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502 rl " }),
|
|
763
976
|
/* @__PURE__ */ jsx2(Text2, { color: rl?.mode === "block" ? theme.ok : rl?.mode === "detect" ? theme.warn : theme.dim, children: rl?.mode ?? "?" }),
|
|
764
977
|
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502 dlp " }),
|
|
765
978
|
/* @__PURE__ */ jsx2(Text2, { color: dl?.mode === "block" ? theme.ok : dl?.mode === "detect" ? theme.warn : theme.dim, children: dl?.mode ?? "?" }),
|
|
766
|
-
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502
|
|
767
|
-
/* @__PURE__ */ jsx2(Text2, { color:
|
|
979
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502 ghost " }),
|
|
980
|
+
/* @__PURE__ */ jsx2(Text2, { color: gh?.mode === "on" ? theme.ok : theme.dim, children: gh?.mode ?? "?" }),
|
|
981
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502 sess " }),
|
|
982
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.accent, children: `${combinedSess.length} (${sessCounts?.active ?? 0} live)` }),
|
|
983
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502 hooks " }),
|
|
984
|
+
/* @__PURE__ */ jsx2(Text2, { color: guard.data?.up_to_date ? theme.ok : theme.warn, children: guard.data ? `v${guard.data.installed ?? "?"}${guard.data.up_to_date ? "" : "\u2192v" + guard.data.latest} ${guard.data.device_count}dev` : "\xB7" }),
|
|
768
985
|
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502" })
|
|
769
986
|
] }),
|
|
770
|
-
/* @__PURE__ */ jsxs2(Box2, { children: [
|
|
987
|
+
/* @__PURE__ */ jsxs2(Box2, { height: 1 + chartH, children: [
|
|
771
988
|
/* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", width: leftW, marginRight: 2, children: [
|
|
772
989
|
/* @__PURE__ */ jsx2(PaneTitle, { label: "TRAFFIC", extra: `${trafficLabel} \xB7 peak ${Math.max(0, ...traffic)} \xB7 red = denials`, width: leftW }),
|
|
773
990
|
/* @__PURE__ */ jsx2(ColumnChart, { series: traffic, hot: trafficHot, height: chartH, width: leftW, color: theme.accent })
|
|
@@ -777,77 +994,56 @@ function LivePanel({ active: active2 }) {
|
|
|
777
994
|
/* @__PURE__ */ jsx2(ColumnChart, { series: lat, hot: lat.map((v) => v > latHotAt), height: chartH, width: rightW, color: "#82AAF0", hotColor: "#ffb454" })
|
|
778
995
|
] })
|
|
779
996
|
] }),
|
|
780
|
-
/* @__PURE__ */ jsxs2(Box2, { children: [
|
|
781
|
-
/* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", width: colW, marginRight: 2, children: [
|
|
997
|
+
/* @__PURE__ */ jsxs2(Box2, { height: colH, children: [
|
|
998
|
+
/* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", width: colW, marginRight: 2, overflow: "hidden", children: [
|
|
782
999
|
/* @__PURE__ */ jsx2(PaneTitle, { label: "LAYERS", width: colW }),
|
|
783
1000
|
/* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
784
1001
|
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "RATELIMIT ".padEnd(10) }),
|
|
785
1002
|
/* @__PURE__ */ jsx2(Text2, { color: rl?.mode === "block" ? theme.ok : rl?.mode === "detect" ? theme.warn : theme.dim, children: (rl?.mode ?? "?").padEnd(7) }),
|
|
786
|
-
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: rl?.perMinute ? `${minuteNow}/${rl.perMinute}
|
|
1003
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: rl?.perMinute ? `${minuteNow}/${rl.perMinute}m ${rl.perHour || "\u2014"}h ${rl.perDay || "\u2014"}d` : "no limits set" })
|
|
787
1004
|
] }),
|
|
788
|
-
rl?.perMinute ? /* @__PURE__ */ jsx2(HBar, { label: "load", value: minuteNow, max: rl.perMinute, width: Math.max(6, colW - 16), color: minuteNow > rl.perMinute ? theme.bad : theme.accent }) : null,
|
|
1005
|
+
rl?.perMinute ? /* @__PURE__ */ jsx2(HBar, { label: "load/min", value: minuteNow, max: rl.perMinute, width: Math.max(6, colW - 16), color: minuteNow > rl.perMinute ? theme.bad : theme.accent }) : null,
|
|
789
1006
|
/* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
790
1007
|
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "DLP".padEnd(10) }),
|
|
791
1008
|
/* @__PURE__ */ jsx2(Text2, { color: dl?.mode === "block" ? theme.ok : dl?.mode === "detect" ? theme.warn : theme.dim, children: (dl?.mode ?? "?").padEnd(7) }),
|
|
792
|
-
/* @__PURE__ */
|
|
793
|
-
(dl?.patterns ?? []).length,
|
|
794
|
-
" patterns armed"
|
|
795
|
-
] })
|
|
1009
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: `${(dl?.patterns ?? []).length} builtin \xB7 ${(dl?.custom ?? []).length} custom` })
|
|
796
1010
|
] }),
|
|
797
|
-
dlpBars.length ? dlpBars.map((
|
|
798
|
-
|
|
1011
|
+
dlpBars.length ? dlpBars.map((d2) => /* @__PURE__ */ jsx2(HBar, { label: truncate(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" }),
|
|
1012
|
+
/* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
799
1013
|
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "GUARD".padEnd(10) }),
|
|
800
|
-
/* @__PURE__ */
|
|
801
|
-
|
|
802
|
-
|
|
1014
|
+
ring ? /* @__PURE__ */ jsxs2(Text2, { color: theme.ok, children: [
|
|
1015
|
+
"local \u2713 ",
|
|
1016
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: `eval avg ${ring.avgMs}ms` })
|
|
1017
|
+
] }) : /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "no local ring in cwd" })
|
|
1018
|
+
] })
|
|
803
1019
|
] }),
|
|
804
|
-
/* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", width: colW, marginRight: 2, children: [
|
|
805
|
-
/* @__PURE__ */ jsx2(PaneTitle, { label: "SESSIONS", extra: `${
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
const
|
|
809
|
-
const
|
|
810
|
-
return /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
811
|
-
/* @__PURE__ */ jsxs2(Text2, { color:
|
|
812
|
-
|
|
813
|
-
" "
|
|
814
|
-
] }),
|
|
815
|
-
/* @__PURE__ */ jsx2(Text2, { color: theme.ok, children: "LOC " }),
|
|
816
|
-
/* @__PURE__ */ jsx2(Text2, { color: theme.accentBright, bold: isMe, children: truncate(isMe ? "this machine" : v.agent, 12).padEnd(13) }),
|
|
817
|
-
/* @__PURE__ */ jsxs2(Text2, { children: [
|
|
818
|
-
String(v.calls).padStart(4),
|
|
819
|
-
"c "
|
|
820
|
-
] }),
|
|
821
|
-
/* @__PURE__ */ jsxs2(Text2, { color: v.denies ? theme.bad : theme.dim, children: [
|
|
822
|
-
String(v.denies).padStart(3),
|
|
823
|
-
"d "
|
|
824
|
-
] }),
|
|
825
|
-
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: ago(v.lastAt) })
|
|
826
|
-
] }, id);
|
|
827
|
-
}),
|
|
828
|
-
sess.slice(0, Math.max(0, colH - 1 - Math.min(localSessList.length, Math.max(1, colH - 2)))).map((a) => {
|
|
829
|
-
const dot = sessionDot(a.status);
|
|
830
|
-
return /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
831
|
-
/* @__PURE__ */ jsxs2(Text2, { color: dot.color, children: [
|
|
832
|
-
dot.ch,
|
|
1020
|
+
/* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", width: colW, marginRight: 2, overflow: "hidden", children: [
|
|
1021
|
+
/* @__PURE__ */ jsx2(PaneTitle, { label: "SESSIONS", extra: mode === "pick" ? "\u2191\u2193 pick \xB7 enter open" : `${combinedSess.length} \xB7 s = inspect`, width: colW }),
|
|
1022
|
+
pickable.length === 0 ? /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "scanning\u2026" }) : null,
|
|
1023
|
+
pickable.map((r, i) => {
|
|
1024
|
+
const freshDot = nowMs - r.lastAt < 9e4;
|
|
1025
|
+
const sel = mode === "pick" && i === pickIdx;
|
|
1026
|
+
return /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", backgroundColor: sel ? "#1c2f63" : void 0, bold: sel || r.isMe, children: [
|
|
1027
|
+
/* @__PURE__ */ jsxs2(Text2, { color: sel ? theme.accentBright : freshDot ? theme.ok : theme.dim, children: [
|
|
1028
|
+
sel ? "\u25B8" : freshDot ? "\u25CF" : "\u25CB",
|
|
833
1029
|
" "
|
|
834
1030
|
] }),
|
|
835
|
-
/* @__PURE__ */ jsx2(Text2, { color: "#4f6db8", children: "CLD " }),
|
|
836
|
-
/* @__PURE__ */ jsx2(Text2, { color: theme.
|
|
1031
|
+
/* @__PURE__ */ jsx2(Text2, { color: r.source === "local" ? theme.ok : "#4f6db8", children: r.source === "local" ? "LOC " : "CLD " }),
|
|
1032
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.accentBright, children: truncate(r.isMe ? "this machine" : r.agent, 12).padEnd(13) }),
|
|
837
1033
|
/* @__PURE__ */ jsxs2(Text2, { children: [
|
|
838
|
-
String(
|
|
1034
|
+
String(r.calls).padStart(4),
|
|
839
1035
|
"c "
|
|
840
1036
|
] }),
|
|
841
|
-
/* @__PURE__ */ jsxs2(Text2, { color:
|
|
842
|
-
String(
|
|
1037
|
+
/* @__PURE__ */ jsxs2(Text2, { color: r.denies ? theme.bad : theme.dim, children: [
|
|
1038
|
+
String(r.denies).padStart(3),
|
|
843
1039
|
"d "
|
|
844
1040
|
] }),
|
|
845
|
-
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: ago(
|
|
846
|
-
] },
|
|
1041
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: (r.trust != null ? `t${r.trust} ` : "") + ago(r.lastAt) })
|
|
1042
|
+
] }, r.id);
|
|
847
1043
|
})
|
|
848
1044
|
] }),
|
|
849
|
-
/* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", width: colW, children: [
|
|
850
|
-
/* @__PURE__ */ jsx2(PaneTitle, { label: "EVENT LOG", extra: "
|
|
1045
|
+
/* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", width: colW, overflow: "hidden", children: [
|
|
1046
|
+
/* @__PURE__ */ jsx2(PaneTitle, { label: "EVENT LOG", extra: "system heartbeat", width: colW }),
|
|
851
1047
|
log.slice(-(colH - 1)).map((l, i) => /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
852
1048
|
/* @__PURE__ */ jsxs2(Text2, { color: theme.dim, children: [
|
|
853
1049
|
hhmmss(l.ts),
|
|
@@ -858,33 +1054,29 @@ function LivePanel({ active: active2 }) {
|
|
|
858
1054
|
] }, l.ts + ":" + i))
|
|
859
1055
|
] })
|
|
860
1056
|
] }),
|
|
861
|
-
/* @__PURE__ */ jsx2(
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
"
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
/* @__PURE__ */ jsx2(
|
|
879
|
-
|
|
880
|
-
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: e.permission.padEnd(5) }),
|
|
881
|
-
e.dlp ? /* @__PURE__ */ jsx2(Text2, { color: theme.bad, children: "DLP! " }) : null,
|
|
882
|
-
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: e.detail })
|
|
883
|
-
] }, e.id)),
|
|
1057
|
+
/* @__PURE__ */ jsx2(
|
|
1058
|
+
PaneTitle,
|
|
1059
|
+
{
|
|
1060
|
+
label: "TOOL STREAM",
|
|
1061
|
+
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`,
|
|
1062
|
+
width: innerW
|
|
1063
|
+
}
|
|
1064
|
+
),
|
|
1065
|
+
/* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", height: streamRows, overflow: "hidden", children: [
|
|
1066
|
+
localOn === false ? /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
1067
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.warn, children: "local logs off" }),
|
|
1068
|
+
/* @__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`" })
|
|
1069
|
+
] }) : null,
|
|
1070
|
+
windowed.length === 0 ? /* @__PURE__ */ jsxs2(Text2, { color: theme.dim, children: [
|
|
1071
|
+
spin,
|
|
1072
|
+
" awaiting traffic\u2026"
|
|
1073
|
+
] }) : null,
|
|
1074
|
+
windowed.map((e) => /* @__PURE__ */ jsx2(StreamLine, { e }, e.id))
|
|
1075
|
+
] }),
|
|
884
1076
|
/* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
885
1077
|
/* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", bold: true, children: " LIVE " }),
|
|
886
|
-
/* @__PURE__ */ jsx2(Text2, { backgroundColor: "#0b1530", color: "#4f6db8", children: ` local ${localOn ? "on" : "off"} \xB7 top ${topTools.map(([t, c2]) => `${t}\xD7${c2}`).join(" ") || "\u2014"}
|
|
887
|
-
/* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", children: "
|
|
1078
|
+
/* @__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"} ` }),
|
|
1079
|
+
/* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", children: " f filter \xB7 s sessions \xB7 c copy \xB7 esc menu \xB7 q quit " })
|
|
888
1080
|
] })
|
|
889
1081
|
] });
|
|
890
1082
|
}
|