@solongate/proxy 0.81.19 → 0.81.20
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/api-client/settings.d.ts +16 -0
- package/dist/commands/index.js +17 -1
- package/dist/index.js +476 -91
- package/dist/tui/hooks.d.ts +14 -0
- package/dist/tui/index.js +464 -91
- package/dist/tui/panels/Settings.d.ts +4 -0
- package/dist/tui/theme.d.ts +4 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -6750,6 +6750,25 @@ function sparkline(values, width2) {
|
|
|
6750
6750
|
if (max === 0) return BLOCKS[0].repeat(v.length);
|
|
6751
6751
|
return v.map((n) => BLOCKS[Math.min(BLOCKS.length - 1, Math.round(n / max * (BLOCKS.length - 1)))]).join("");
|
|
6752
6752
|
}
|
|
6753
|
+
function prettyJson(s) {
|
|
6754
|
+
try {
|
|
6755
|
+
return JSON.stringify(JSON.parse(s), null, 2);
|
|
6756
|
+
} catch {
|
|
6757
|
+
return s;
|
|
6758
|
+
}
|
|
6759
|
+
}
|
|
6760
|
+
function wrapLines(s, width2) {
|
|
6761
|
+
const w = Math.max(8, width2);
|
|
6762
|
+
const out2 = [];
|
|
6763
|
+
for (const raw of (s ?? "").split("\n")) {
|
|
6764
|
+
if (raw.length <= w) {
|
|
6765
|
+
out2.push(raw);
|
|
6766
|
+
continue;
|
|
6767
|
+
}
|
|
6768
|
+
for (let i = 0; i < raw.length; i += w) out2.push(raw.slice(i, i + w));
|
|
6769
|
+
}
|
|
6770
|
+
return out2;
|
|
6771
|
+
}
|
|
6753
6772
|
function truncate2(s, n) {
|
|
6754
6773
|
if (!s) return "";
|
|
6755
6774
|
return s.length <= n ? s : s.slice(0, Math.max(0, n - 1)) + "\u2026";
|
|
@@ -6903,12 +6922,16 @@ __export(settings_exports, {
|
|
|
6903
6922
|
deleteWebhook: () => deleteWebhook,
|
|
6904
6923
|
getAlerts: () => getAlerts,
|
|
6905
6924
|
getGuardStatus: () => getGuardStatus,
|
|
6925
|
+
getLocalLogs: () => getLocalLogs,
|
|
6906
6926
|
getRateLimitHistory: () => getRateLimitHistory,
|
|
6907
6927
|
getSecurityLayers: () => getSecurityLayers,
|
|
6908
6928
|
getSelfProtection: () => getSelfProtection,
|
|
6909
6929
|
getWebhooks: () => getWebhooks,
|
|
6930
|
+
setAlertEnabled: () => setAlertEnabled,
|
|
6931
|
+
setLocalLogs: () => setLocalLogs,
|
|
6910
6932
|
setSecurityLayers: () => setSecurityLayers,
|
|
6911
|
-
setSelfProtection: () => setSelfProtection
|
|
6933
|
+
setSelfProtection: () => setSelfProtection,
|
|
6934
|
+
updateWebhook: () => updateWebhook
|
|
6912
6935
|
});
|
|
6913
6936
|
function getSecurityLayers() {
|
|
6914
6937
|
return request("GET", "/settings/security-layers");
|
|
@@ -6931,6 +6954,12 @@ function getSelfProtection() {
|
|
|
6931
6954
|
function setSelfProtection(enabled) {
|
|
6932
6955
|
return request("PUT", "/settings/self-protection", { body: { enabled } });
|
|
6933
6956
|
}
|
|
6957
|
+
function getLocalLogs() {
|
|
6958
|
+
return request("GET", "/settings/local-logs");
|
|
6959
|
+
}
|
|
6960
|
+
function setLocalLogs(cfg) {
|
|
6961
|
+
return request("PUT", "/settings/local-logs", { body: cfg });
|
|
6962
|
+
}
|
|
6934
6963
|
function getAlerts() {
|
|
6935
6964
|
return request("GET", "/settings/denial-alerts");
|
|
6936
6965
|
}
|
|
@@ -6940,6 +6969,9 @@ function createAlert(body) {
|
|
|
6940
6969
|
function deleteAlert(id) {
|
|
6941
6970
|
return request("DELETE", "/settings/denial-alerts", { query: { id } });
|
|
6942
6971
|
}
|
|
6972
|
+
function setAlertEnabled(id, enabled) {
|
|
6973
|
+
return request("PATCH", "/settings/denial-alerts", { query: { id }, body: { enabled } });
|
|
6974
|
+
}
|
|
6943
6975
|
function getWebhooks() {
|
|
6944
6976
|
return request("GET", "/settings/denial-webhook");
|
|
6945
6977
|
}
|
|
@@ -6949,6 +6981,9 @@ function createWebhook(body) {
|
|
|
6949
6981
|
function deleteWebhook(id) {
|
|
6950
6982
|
return request("DELETE", "/settings/denial-webhook", { query: { id } });
|
|
6951
6983
|
}
|
|
6984
|
+
function updateWebhook(id, patch) {
|
|
6985
|
+
return request("PATCH", "/settings/denial-webhook", { body: { id, ...patch } });
|
|
6986
|
+
}
|
|
6952
6987
|
var init_settings = __esm({
|
|
6953
6988
|
"src/api-client/settings.ts"() {
|
|
6954
6989
|
"use strict";
|
|
@@ -7160,6 +7195,24 @@ function usePoll(reload, intervalMs, enabled = true) {
|
|
|
7160
7195
|
return () => clearInterval(t);
|
|
7161
7196
|
}, [reload, intervalMs, enabled]);
|
|
7162
7197
|
}
|
|
7198
|
+
function useTermSize() {
|
|
7199
|
+
const read = () => ({ cols: process.stdout.columns ?? 100, rows: process.stdout.rows ?? 30 });
|
|
7200
|
+
const [size, setSize] = useState(read);
|
|
7201
|
+
useEffect(() => {
|
|
7202
|
+
const onResize = () => setSize(read());
|
|
7203
|
+
process.stdout.on("resize", onResize);
|
|
7204
|
+
return () => {
|
|
7205
|
+
process.stdout.off("resize", onResize);
|
|
7206
|
+
};
|
|
7207
|
+
}, []);
|
|
7208
|
+
return size;
|
|
7209
|
+
}
|
|
7210
|
+
function usePanelSize() {
|
|
7211
|
+
const { cols, rows } = useTermSize();
|
|
7212
|
+
const wide = cols >= 82;
|
|
7213
|
+
const shellRows = wide ? 12 : 7;
|
|
7214
|
+
return { cols: Math.max(30, cols - 22), rows: Math.max(8, rows - shellRows) };
|
|
7215
|
+
}
|
|
7163
7216
|
var init_hooks = __esm({
|
|
7164
7217
|
"src/tui/hooks.ts"() {
|
|
7165
7218
|
"use strict";
|
|
@@ -7309,6 +7362,9 @@ function LivePanel({ active: active2 }) {
|
|
|
7309
7362
|
const [detail, setDetail] = useState2(null);
|
|
7310
7363
|
const [detailCloud, setDetailCloud] = useState2([]);
|
|
7311
7364
|
const [detailScroll, setDetailScroll] = useState2(0);
|
|
7365
|
+
const [inspect, setInspect] = useState2(null);
|
|
7366
|
+
const [inspectScroll, setInspectScroll] = useState2(0);
|
|
7367
|
+
const inspectFromRef = useRef2("stream");
|
|
7312
7368
|
const seenRef = useRef2(/* @__PURE__ */ new Set());
|
|
7313
7369
|
const lastLocalTs = useRef2(0);
|
|
7314
7370
|
const pausedUntil = useRef2(0);
|
|
@@ -7514,8 +7570,7 @@ function LivePanel({ active: active2 }) {
|
|
|
7514
7570
|
else if (e.burst) fireAlert("sec:" + e.id, "Rate-limit burst", `BURST ${e.tool}${who}`, "warn");
|
|
7515
7571
|
}
|
|
7516
7572
|
}, [tick, active2, fireAlert]);
|
|
7517
|
-
const cols
|
|
7518
|
-
const rows = process.stdout.rows ?? 30;
|
|
7573
|
+
const { cols, rows } = useTermSize();
|
|
7519
7574
|
const ins = insights.data ?? {};
|
|
7520
7575
|
const spin = SPIN[tick % SPIN.length];
|
|
7521
7576
|
const nowMs = Date.now();
|
|
@@ -7661,8 +7716,18 @@ function LivePanel({ active: active2 }) {
|
|
|
7661
7716
|
setEditingSearch(true);
|
|
7662
7717
|
return;
|
|
7663
7718
|
}
|
|
7719
|
+
if (mode === "inspect") {
|
|
7720
|
+
if (key.leftArrow) {
|
|
7721
|
+
setMode(inspectFromRef.current);
|
|
7722
|
+
setInspect(null);
|
|
7723
|
+
} else if (key.upArrow) setInspectScroll((n) => Math.max(0, n - 1));
|
|
7724
|
+
else if (key.downArrow) setInspectScroll((n) => n + 1);
|
|
7725
|
+
else if (key.pageUp) setInspectScroll((n) => Math.max(0, n - 10));
|
|
7726
|
+
else if (key.pageDown) setInspectScroll((n) => n + 10);
|
|
7727
|
+
return;
|
|
7728
|
+
}
|
|
7664
7729
|
if (mode === "detail") {
|
|
7665
|
-
const maxD = Math.max(0, detailEntries.length -
|
|
7730
|
+
const maxD = Math.max(0, detailEntries.length - 1);
|
|
7666
7731
|
if (key.leftArrow) {
|
|
7667
7732
|
setMode("stream");
|
|
7668
7733
|
setDetail(null);
|
|
@@ -7670,6 +7735,15 @@ function LivePanel({ active: active2 }) {
|
|
|
7670
7735
|
else if (key.downArrow) setDetailScroll((n) => Math.min(maxD, n + 1));
|
|
7671
7736
|
else if (key.pageUp) setDetailScroll((n) => Math.max(0, n - 10));
|
|
7672
7737
|
else if (key.pageDown) setDetailScroll((n) => Math.min(maxD, n + 10));
|
|
7738
|
+
else if (key.return) {
|
|
7739
|
+
const e = detailEntries[Math.min(detailScroll, maxD)];
|
|
7740
|
+
if (e) {
|
|
7741
|
+
inspectFromRef.current = "detail";
|
|
7742
|
+
setInspect(e);
|
|
7743
|
+
setInspectScroll(0);
|
|
7744
|
+
setMode("inspect");
|
|
7745
|
+
}
|
|
7746
|
+
}
|
|
7673
7747
|
return;
|
|
7674
7748
|
}
|
|
7675
7749
|
if (mode === "pick") {
|
|
@@ -7691,6 +7765,13 @@ function LivePanel({ active: active2 }) {
|
|
|
7691
7765
|
if (input === "f") {
|
|
7692
7766
|
setFilter((f) => FILTERS[(FILTERS.indexOf(f) + 1) % FILTERS.length]);
|
|
7693
7767
|
setSel(0);
|
|
7768
|
+
} else if (key.return) {
|
|
7769
|
+
if (selEntry) {
|
|
7770
|
+
inspectFromRef.current = "stream";
|
|
7771
|
+
setInspect(selEntry);
|
|
7772
|
+
setInspectScroll(0);
|
|
7773
|
+
setMode("inspect");
|
|
7774
|
+
}
|
|
7694
7775
|
} else if (input === "s") {
|
|
7695
7776
|
setPickIdx(0);
|
|
7696
7777
|
setMode("pick");
|
|
@@ -7753,6 +7834,52 @@ function LivePanel({ active: active2 }) {
|
|
|
7753
7834
|
/* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", children: ` ${spin} up ${fmtUp(nowMs - startRef.current)} \xB7 ${hhmmss(nowMs)} \xB7 api ${latNow}ms ` }),
|
|
7754
7835
|
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 " })
|
|
7755
7836
|
] });
|
|
7837
|
+
if (mode === "inspect" && inspect) {
|
|
7838
|
+
const e = inspect;
|
|
7839
|
+
const bodyW = Math.max(20, cols - 4);
|
|
7840
|
+
const lines = wrapLines(prettyJson(e.detail || "(no arguments / reason recorded)"), bodyW);
|
|
7841
|
+
const bodyRows = Math.max(4, rows - 7);
|
|
7842
|
+
const maxScroll2 = Math.max(0, lines.length - bodyRows);
|
|
7843
|
+
const off = Math.min(inspectScroll, maxScroll2);
|
|
7844
|
+
const win = lines.slice(off, off + bodyRows);
|
|
7845
|
+
return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", paddingX: 1, children: [
|
|
7846
|
+
titleBar,
|
|
7847
|
+
/* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
7848
|
+
/* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#AAC8FA", bold: true, children: " ENTRY " }),
|
|
7849
|
+
/* @__PURE__ */ jsx2(Text2, { color: decisionColor(e.decision), bold: true, children: " " + e.decision }),
|
|
7850
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.accent, bold: true, children: " " + e.tool }),
|
|
7851
|
+
/* @__PURE__ */ jsx2(Text2, { color: isLoc(e) ? theme.ok : "#4f6db8", children: " " + (isLoc(e) ? "LOC" : "CLD") }),
|
|
7852
|
+
e.dlp ? /* @__PURE__ */ jsx2(Text2, { color: theme.bad, children: " DLP!" }) : null,
|
|
7853
|
+
e.burst ? /* @__PURE__ */ jsx2(Text2, { color: theme.warn, children: " BURST" }) : null,
|
|
7854
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2190 back" })
|
|
7855
|
+
] }),
|
|
7856
|
+
/* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
7857
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "\u2502 when " }),
|
|
7858
|
+
/* @__PURE__ */ jsx2(Text2, { children: new Date(e.at).toLocaleString() }),
|
|
7859
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502 perm " }),
|
|
7860
|
+
/* @__PURE__ */ jsx2(Text2, { children: e.permission || "\u2014" }),
|
|
7861
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502 eval " }),
|
|
7862
|
+
/* @__PURE__ */ jsx2(Text2, { color: e.evalMs != null && e.evalMs > 500 ? theme.warn : void 0, children: e.evalMs != null ? `${e.evalMs}ms` : "\u2014" }),
|
|
7863
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502 agent " }),
|
|
7864
|
+
/* @__PURE__ */ jsx2(Text2, { children: e.agent ?? "\u2014" }),
|
|
7865
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502" })
|
|
7866
|
+
] }),
|
|
7867
|
+
/* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
7868
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "\u2502 session " }),
|
|
7869
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: e.session ?? "\u2014" }),
|
|
7870
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502 rule " }),
|
|
7871
|
+
/* @__PURE__ */ jsx2(Text2, { color: e.rule && e.decision !== "ALLOW" ? theme.bad : theme.dim, children: e.rule ?? "\u2014" }),
|
|
7872
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502" })
|
|
7873
|
+
] }),
|
|
7874
|
+
/* @__PURE__ */ jsx2(PaneTitle, { label: "FULL CONTENT", extra: `${lines.length} lines${maxScroll2 ? ` \xB7 \u25BC${maxScroll2 - off} more \xB7 \u2191\u2193 scroll` : ""} \xB7 space copy \xB7 \u2190 back`, width: innerW }),
|
|
7875
|
+
/* @__PURE__ */ jsx2(Box2, { flexDirection: "column", height: bodyRows, overflow: "hidden", children: win.map((l, i) => /* @__PURE__ */ jsx2(Text2, { wrap: "truncate", children: l || " " }, off + i)) }),
|
|
7876
|
+
/* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
7877
|
+
/* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", bold: true, children: " ENTRY " }),
|
|
7878
|
+
/* @__PURE__ */ jsx2(Text2, { backgroundColor: "#0b1530", color: "#4f6db8", children: ` ${e.id} ` }),
|
|
7879
|
+
/* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", children: " \u2191\u2193 scroll \xB7 space copy mode \xB7 \u2190 back \xB7 esc menu " })
|
|
7880
|
+
] })
|
|
7881
|
+
] });
|
|
7882
|
+
}
|
|
7756
7883
|
if (mode === "detail" && detail) {
|
|
7757
7884
|
const d = detailEntries;
|
|
7758
7885
|
const allow = d.filter((e) => e.decision === "ALLOW").length;
|
|
@@ -7772,9 +7899,10 @@ function LivePanel({ active: active2 }) {
|
|
|
7772
7899
|
const last = d[0]?.at;
|
|
7773
7900
|
const tlRows = Math.max(4, rows - 10);
|
|
7774
7901
|
const tlBody = Math.max(3, tlRows - 1);
|
|
7775
|
-
const
|
|
7776
|
-
const
|
|
7777
|
-
const
|
|
7902
|
+
const dSel = Math.min(detailScroll, Math.max(0, d.length - 1));
|
|
7903
|
+
const maxStart = Math.max(0, d.length - tlBody);
|
|
7904
|
+
const start = Math.min(Math.max(0, dSel - Math.floor((tlBody - 1) / 2)), maxStart);
|
|
7905
|
+
const tl = d.slice(start, start + tlBody);
|
|
7778
7906
|
return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", paddingX: 1, children: [
|
|
7779
7907
|
titleBar,
|
|
7780
7908
|
/* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
@@ -7812,16 +7940,16 @@ function LivePanel({ active: active2 }) {
|
|
|
7812
7940
|
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: perms.map(([p, c2]) => `${p}\xD7${c2}`).join(" ") || "\u2014" }),
|
|
7813
7941
|
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502" })
|
|
7814
7942
|
] }),
|
|
7815
|
-
/* @__PURE__ */ jsx2(PaneTitle, { label: "TIMELINE", extra: `${d.length}
|
|
7943
|
+
/* @__PURE__ */ jsx2(PaneTitle, { label: "TIMELINE", extra: `${dSel + 1}/${d.length} \xB7 newest first \xB7 \u2191\u2193 select \xB7 enter full entry \xB7 / search \xB7 \u2190 back`, width: innerW }),
|
|
7816
7944
|
/* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", height: tlRows, overflow: "hidden", children: [
|
|
7817
7945
|
searchRow,
|
|
7818
7946
|
tl.length === 0 ? /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: detailCloud.length === 0 ? spin + " loading history\u2026" : "no entries" }) : null,
|
|
7819
|
-
tl.map((e) => /* @__PURE__ */ jsx2(StreamLine, { e, loc: isLoc(e) }, e.id))
|
|
7947
|
+
tl.map((e, i) => /* @__PURE__ */ jsx2(StreamLine, { e, loc: isLoc(e), selected: start + i === dSel }, e.id))
|
|
7820
7948
|
] }),
|
|
7821
7949
|
/* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
7822
7950
|
/* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", bold: true, children: " SESSION " }),
|
|
7823
7951
|
/* @__PURE__ */ jsx2(Text2, { backgroundColor: "#0b1530", color: "#4f6db8", children: ` ${detail.id} ` }),
|
|
7824
|
-
/* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", children: " \u2191\u2193
|
|
7952
|
+
/* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", children: " \u2191\u2193 select \xB7 enter full entry \xB7 \u2190 back \xB7 esc menu " })
|
|
7825
7953
|
] })
|
|
7826
7954
|
] });
|
|
7827
7955
|
}
|
|
@@ -7934,7 +8062,7 @@ function LivePanel({ active: active2 }) {
|
|
|
7934
8062
|
PaneTitle,
|
|
7935
8063
|
{
|
|
7936
8064
|
label: "TOOL STREAM",
|
|
7937
|
-
extra: `${selClamped + 1}/${visibleDesc.length}${signal !== "none" ? ` \xB7 ${signal}` : ""}${q ? " \xB7 search" : ""} \xB7 \u2191\u2193 select \xB7 w allow \xB7 b block \xB7 d/x/r ${filter} \xB7 s`,
|
|
8065
|
+
extra: `${selClamped + 1}/${visibleDesc.length}${signal !== "none" ? ` \xB7 ${signal}` : ""}${q ? " \xB7 search" : ""} \xB7 \u2191\u2193 select \xB7 enter full \xB7 w allow \xB7 b block \xB7 d/x/r ${filter} \xB7 s`,
|
|
7938
8066
|
width: innerW
|
|
7939
8067
|
}
|
|
7940
8068
|
),
|
|
@@ -7942,7 +8070,7 @@ function LivePanel({ active: active2 }) {
|
|
|
7942
8070
|
searchRow,
|
|
7943
8071
|
localOn === false ? /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
7944
8072
|
/* @__PURE__ */ jsx2(Text2, { color: theme.warn, children: "local logs off" }),
|
|
7945
|
-
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2014 enable:
|
|
8073
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2014 enable: dataroom \u2192 Settings (local logs) or dashboard \u2192 Settings \xB7 hooks write ~/.solongate/local-logs" })
|
|
7946
8074
|
] }) : null,
|
|
7947
8075
|
windowed.length === 0 ? /* @__PURE__ */ jsxs2(Text2, { color: theme.dim, children: [
|
|
7948
8076
|
spin,
|
|
@@ -7953,7 +8081,7 @@ function LivePanel({ active: active2 }) {
|
|
|
7953
8081
|
/* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
7954
8082
|
/* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", bold: true, children: " LIVE " }),
|
|
7955
8083
|
/* @__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"} ` }),
|
|
7956
|
-
/* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", children: " \u2191\u2193 select \xB7 w allow \xB7 b block \xB7 d/x/r \xB7 / search \xB7 f \xB7 s \xB7 space copy \xB7 esc \xB7 q " })
|
|
8084
|
+
/* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", children: " \u2191\u2193 select \xB7 enter full \xB7 w allow \xB7 b block \xB7 d/x/r \xB7 / search \xB7 f \xB7 s \xB7 space copy \xB7 esc \xB7 q " })
|
|
7957
8085
|
] })
|
|
7958
8086
|
] });
|
|
7959
8087
|
}
|
|
@@ -8782,8 +8910,9 @@ var init_Stats = __esm({
|
|
|
8782
8910
|
import { Box as Box7, Text as Text7, useInput as useInput5 } from "ink";
|
|
8783
8911
|
import TextInput4 from "ink-text-input";
|
|
8784
8912
|
import { useState as useState6 } from "react";
|
|
8785
|
-
import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
8913
|
+
import { Fragment as Fragment4, jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
8786
8914
|
function AuditPanel({ active: active2, focused }) {
|
|
8915
|
+
const { cols, rows } = usePanelSize();
|
|
8787
8916
|
const [di, setDi] = useState6(0);
|
|
8788
8917
|
const [gi, setGi] = useState6(0);
|
|
8789
8918
|
const [tool, setTool] = useState6("");
|
|
@@ -8791,6 +8920,7 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
8791
8920
|
const [search, setSearch] = useState6("");
|
|
8792
8921
|
const [sel, setSel] = useState6(0);
|
|
8793
8922
|
const [view, setView] = useState6("list");
|
|
8923
|
+
const [detailScroll, setDetailScroll] = useState6(0);
|
|
8794
8924
|
const [editing, setEditing] = useState6(null);
|
|
8795
8925
|
const query = {
|
|
8796
8926
|
filter: DECISIONS[di],
|
|
@@ -8798,7 +8928,7 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
8798
8928
|
tool: tool || void 0,
|
|
8799
8929
|
agent_name: agent || void 0,
|
|
8800
8930
|
search: search || void 0,
|
|
8801
|
-
limit:
|
|
8931
|
+
limit: FETCH_LIMIT
|
|
8802
8932
|
};
|
|
8803
8933
|
const auditQ = useLoader(() => api.audit.list(query), [di, gi, tool, agent, search]);
|
|
8804
8934
|
usePoll(auditQ.reload, 6e3, active2 && view === "list" && !editing);
|
|
@@ -8812,15 +8942,29 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
8812
8942
|
(input, key) => {
|
|
8813
8943
|
if (view === "detail") {
|
|
8814
8944
|
if (key.leftArrow || key.escape) setView("list");
|
|
8945
|
+
else if (key.upArrow) setDetailScroll((n) => Math.max(0, n - 1));
|
|
8946
|
+
else if (key.downArrow) setDetailScroll((n) => n + 1);
|
|
8947
|
+
else if (key.pageUp) setDetailScroll((n) => Math.max(0, n - 10));
|
|
8948
|
+
else if (key.pageDown) setDetailScroll((n) => n + 10);
|
|
8815
8949
|
return;
|
|
8816
8950
|
}
|
|
8951
|
+
const clearSel = () => setSel(0);
|
|
8817
8952
|
if (key.upArrow) setSel((n) => Math.max(0, n - 1));
|
|
8818
8953
|
else if (key.downArrow) setSel((n) => Math.min(entries.length - 1, n + 1));
|
|
8954
|
+
else if (key.pageUp) setSel((n) => Math.max(0, n - 10));
|
|
8955
|
+
else if (key.pageDown) setSel((n) => Math.min(entries.length - 1, n + 10));
|
|
8819
8956
|
else if (key.return || key.rightArrow) {
|
|
8820
|
-
if (current)
|
|
8821
|
-
|
|
8822
|
-
|
|
8823
|
-
|
|
8957
|
+
if (current) {
|
|
8958
|
+
setDetailScroll(0);
|
|
8959
|
+
setView("detail");
|
|
8960
|
+
}
|
|
8961
|
+
} else if (input === "f") {
|
|
8962
|
+
setDi((n) => (n + 1) % DECISIONS.length);
|
|
8963
|
+
clearSel();
|
|
8964
|
+
} else if (input === "g") {
|
|
8965
|
+
setGi((n) => (n + 1) % SIGNALS.length);
|
|
8966
|
+
clearSel();
|
|
8967
|
+
} else if (input === "t") setEditing("tool");
|
|
8824
8968
|
else if (input === "n") setEditing("agent");
|
|
8825
8969
|
else if (input === "/") setEditing("search");
|
|
8826
8970
|
else if (input === "c") {
|
|
@@ -8829,49 +8973,64 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
8829
8973
|
setTool("");
|
|
8830
8974
|
setAgent("");
|
|
8831
8975
|
setSearch("");
|
|
8976
|
+
clearSel();
|
|
8832
8977
|
}
|
|
8833
8978
|
},
|
|
8834
8979
|
{ isActive: focused && !editing }
|
|
8835
8980
|
);
|
|
8836
8981
|
if (view === "detail" && current) {
|
|
8837
8982
|
const sessionCalls = sessionQ.data?.entries ?? [];
|
|
8983
|
+
const bodyW = Math.max(20, cols - 2);
|
|
8984
|
+
const reasonLines = wrapLines("reason: " + (current.reason ?? "\u2014"), bodyW);
|
|
8985
|
+
const argLines = current.arguments_summary ? wrapLines(prettyJson(JSON.stringify(current.arguments_summary)), bodyW) : ["(no arguments recorded)"];
|
|
8986
|
+
const sessionRows = current.session_id ? Math.min(4, sessionCalls.length) + 2 : 1;
|
|
8987
|
+
const reasonShown = reasonLines.slice(0, 4);
|
|
8988
|
+
const argBudget = Math.max(3, rows - 2 - 5 - reasonShown.length - 1 - sessionRows - 1);
|
|
8989
|
+
const maxScroll = Math.max(0, argLines.length - argBudget);
|
|
8990
|
+
const off = Math.min(detailScroll, maxScroll);
|
|
8991
|
+
const argWin = argLines.slice(off, off + argBudget);
|
|
8838
8992
|
return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
|
|
8839
8993
|
/* @__PURE__ */ jsxs7(Box7, { children: [
|
|
8840
8994
|
/* @__PURE__ */ jsx7(Text7, { color: decisionColor(current.decision), bold: true, children: current.decision }),
|
|
8841
8995
|
/* @__PURE__ */ jsx7(Text7, { color: theme.accent, children: " " + current.tool_name }),
|
|
8842
8996
|
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: " " + current.permission + " \xB7 " + current.trust_level })
|
|
8843
8997
|
] }),
|
|
8844
|
-
/* @__PURE__ */ jsx7(
|
|
8998
|
+
reasonShown.map((l, i) => /* @__PURE__ */ jsx7(Text7, { wrap: "truncate", children: i === 0 ? /* @__PURE__ */ jsxs7(Fragment4, { children: [
|
|
8999
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "reason " }),
|
|
9000
|
+
/* @__PURE__ */ jsx7(Text7, { children: l.slice("reason: ".length) })
|
|
9001
|
+
] }) : /* @__PURE__ */ jsx7(Text7, { children: " " + l }) }, "r" + i)),
|
|
8845
9002
|
/* @__PURE__ */ jsx7(Detail, { label: "rule", value: current.matched_rule_id ?? "\u2014" }),
|
|
8846
9003
|
/* @__PURE__ */ jsx7(Detail, { label: "agent", value: current.agent_name ?? "\u2014" }),
|
|
8847
9004
|
/* @__PURE__ */ jsx7(Detail, { label: "session", value: current.session_id ?? "\u2014" }),
|
|
8848
9005
|
/* @__PURE__ */ jsx7(Detail, { label: "dlp", value: current.dlp_matches?.length ? current.dlp_matches.join(", ") : "none", color: current.dlp_matches?.length ? theme.bad : void 0 }),
|
|
8849
|
-
/* @__PURE__ */ jsx7(Detail, { label: "when", value: new Date(current.created_at).toLocaleString() }),
|
|
8850
|
-
|
|
8851
|
-
/* @__PURE__ */
|
|
9006
|
+
/* @__PURE__ */ jsx7(Detail, { label: "when", value: new Date(current.created_at).toLocaleString() + (current.evaluation_time_ms != null ? ` \xB7 eval ${current.evaluation_time_ms}ms` : "") }),
|
|
9007
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: `arguments \u2014 full \xB7 ${argLines.length} lines${maxScroll ? ` \xB7 \u25BC${maxScroll - off} more \xB7 \u2191\u2193 scroll` : ""}` }),
|
|
9008
|
+
/* @__PURE__ */ jsx7(Box7, { flexDirection: "column", height: argBudget, overflow: "hidden", children: argWin.map((l, i) => /* @__PURE__ */ jsx7(Text7, { wrap: "truncate", children: l || " " }, off + i)) }),
|
|
9009
|
+
current.session_id ? /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
|
|
8852
9010
|
/* @__PURE__ */ jsxs7(Text7, { color: theme.dim, children: [
|
|
8853
|
-
"Session ",
|
|
8854
|
-
|
|
9011
|
+
"Session \xB7 ",
|
|
9012
|
+
sessionCalls.length,
|
|
9013
|
+
" calls"
|
|
8855
9014
|
] }),
|
|
8856
|
-
|
|
9015
|
+
/* @__PURE__ */ jsx7(
|
|
8857
9016
|
Table,
|
|
8858
9017
|
{
|
|
8859
9018
|
columns: [
|
|
8860
9019
|
{ header: "DECISION", width: 9 },
|
|
8861
9020
|
{ header: "TOOL", width: 20 },
|
|
8862
|
-
{ header: "REASON", width:
|
|
9021
|
+
{ header: "REASON", width: Math.max(16, cols - 48) },
|
|
8863
9022
|
{ header: "WHEN", width: 6 }
|
|
8864
9023
|
],
|
|
8865
|
-
rows: sessionCalls.slice(0,
|
|
9024
|
+
rows: sessionCalls.slice(0, Math.max(1, sessionRows - 2)).map((e) => [
|
|
8866
9025
|
{ value: e.decision, color: decisionColor(e.decision) },
|
|
8867
9026
|
{ value: truncate2(e.tool_name, 20), color: theme.accent },
|
|
8868
|
-
{ value: truncate2(e.reason ?? "\u2014",
|
|
9027
|
+
{ value: truncate2(e.reason ?? "\u2014", Math.max(16, cols - 48)) },
|
|
8869
9028
|
{ value: ago(e.created_at), dim: true }
|
|
8870
9029
|
])
|
|
8871
9030
|
}
|
|
8872
|
-
)
|
|
8873
|
-
] }),
|
|
8874
|
-
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "\u2190 back to list" })
|
|
9031
|
+
)
|
|
9032
|
+
] }) : /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "(no session id)" }),
|
|
9033
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "\u2191\u2193 scroll arguments \xB7 \u2190/esc back to list" })
|
|
8875
9034
|
] });
|
|
8876
9035
|
}
|
|
8877
9036
|
const chip = (label, val, on) => /* @__PURE__ */ jsxs7(Text7, { children: [
|
|
@@ -8882,6 +9041,13 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
8882
9041
|
/* @__PURE__ */ jsx7(Text7, { color: on ? theme.accentBright : theme.dim, children: val }),
|
|
8883
9042
|
/* @__PURE__ */ jsx7(Text7, { children: " " })
|
|
8884
9043
|
] });
|
|
9044
|
+
const headerRows = 4 + (editing ? 1 : 0);
|
|
9045
|
+
const listRows = Math.max(4, rows - headerRows);
|
|
9046
|
+
const selClamped = Math.min(sel, Math.max(0, entries.length - 1));
|
|
9047
|
+
const maxStart = Math.max(0, entries.length - listRows);
|
|
9048
|
+
const start = Math.min(Math.max(0, selClamped - Math.floor((listRows - 1) / 2)), maxStart);
|
|
9049
|
+
const windowed = entries.slice(start, start + listRows);
|
|
9050
|
+
const reasonW = Math.min(60, Math.max(12, cols - 67));
|
|
8885
9051
|
return /* @__PURE__ */ jsx7(DataView, { loading: auditQ.loading && !auditQ.data, error: auditQ.error, children: /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
|
|
8886
9052
|
/* @__PURE__ */ jsxs7(Box7, { children: [
|
|
8887
9053
|
chip("dec", DECISIONS[di] ?? "all", di !== 0),
|
|
@@ -8890,8 +9056,8 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
8890
9056
|
chip("agent", agent || "\xB7", !!agent),
|
|
8891
9057
|
chip("search", search || "\xB7", !!search)
|
|
8892
9058
|
] }),
|
|
8893
|
-
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: focused ? "\u2191\u2193 \xB7 enter
|
|
8894
|
-
editing ? /* @__PURE__ */ jsxs7(Box7, {
|
|
9059
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, wrap: "truncate", children: focused ? "\u2191\u2193 select \xB7 enter full entry \xB7 f dec \xB7 g sig \xB7 t tool \xB7 n agent \xB7 / search \xB7 c clear" : "press \u2192 to browse" }),
|
|
9060
|
+
editing ? /* @__PURE__ */ jsxs7(Box7, { children: [
|
|
8895
9061
|
/* @__PURE__ */ jsxs7(Text7, { color: theme.warn, children: [
|
|
8896
9062
|
editing,
|
|
8897
9063
|
": "
|
|
@@ -8900,16 +9066,15 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
8900
9066
|
TextInput4,
|
|
8901
9067
|
{
|
|
8902
9068
|
value: editing === "tool" ? tool : editing === "agent" ? agent : search,
|
|
8903
|
-
onChange:
|
|
9069
|
+
onChange: (v) => {
|
|
9070
|
+
(editing === "tool" ? setTool : editing === "agent" ? setAgent : setSearch)(v);
|
|
9071
|
+
setSel(0);
|
|
9072
|
+
},
|
|
8904
9073
|
onSubmit: () => setEditing(null)
|
|
8905
9074
|
}
|
|
8906
9075
|
)
|
|
8907
9076
|
] }) : null,
|
|
8908
|
-
/* @__PURE__ */ jsx7(
|
|
8909
|
-
auditQ.data?.total ?? 0,
|
|
8910
|
-
" matched \xB7 showing ",
|
|
8911
|
-
Math.min(entries.length, 12)
|
|
8912
|
-
] }) }),
|
|
9077
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, wrap: "truncate", children: `${auditQ.data?.total ?? 0} matched \xB7 ${entries.length} loaded \xB7 ${selClamped + 1}/${entries.length}${start ? ` \xB7 \u25B2${start} newer` : ""}${start + listRows < entries.length ? ` \xB7 \u25BC${entries.length - start - listRows} older` : ""}` }),
|
|
8913
9078
|
/* @__PURE__ */ jsx7(
|
|
8914
9079
|
Table,
|
|
8915
9080
|
{
|
|
@@ -8918,22 +9083,22 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
8918
9083
|
{ header: "DECISION", width: 9 },
|
|
8919
9084
|
{ header: "TOOL", width: 18 },
|
|
8920
9085
|
{ header: "AGENT", width: 14 },
|
|
8921
|
-
{ header: "REASON", width:
|
|
9086
|
+
{ header: "REASON", width: reasonW },
|
|
8922
9087
|
{ header: "DLP", width: 4 },
|
|
8923
9088
|
{ header: "WHEN", width: 6 }
|
|
8924
9089
|
],
|
|
8925
|
-
rows:
|
|
9090
|
+
rows: windowed.map((e, i) => rowFor(e, start + i === selClamped && focused, reasonW))
|
|
8926
9091
|
}
|
|
8927
9092
|
)
|
|
8928
9093
|
] }) });
|
|
8929
9094
|
}
|
|
8930
|
-
function rowFor(e, active2) {
|
|
9095
|
+
function rowFor(e, active2, reasonW) {
|
|
8931
9096
|
return [
|
|
8932
9097
|
{ value: active2 ? "\u25B8" : "", color: theme.accentBright },
|
|
8933
9098
|
{ value: e.decision, color: decisionColor(e.decision) },
|
|
8934
9099
|
{ value: truncate2(e.tool_name, 18), color: theme.accent },
|
|
8935
9100
|
{ value: truncate2(e.agent_name ?? "\u2014", 14), dim: true },
|
|
8936
|
-
{ value: truncate2(e.reason ?? "\u2014",
|
|
9101
|
+
{ value: truncate2(e.reason ?? "\u2014", reasonW) },
|
|
8937
9102
|
{ value: e.dlp_matches?.length ? String(e.dlp_matches.length) : "0", color: e.dlp_matches?.length ? theme.bad : void 0, dim: !e.dlp_matches?.length },
|
|
8938
9103
|
{ value: ago(e.created_at), dim: true }
|
|
8939
9104
|
];
|
|
@@ -8941,10 +9106,10 @@ function rowFor(e, active2) {
|
|
|
8941
9106
|
function Detail({ label, value, color }) {
|
|
8942
9107
|
return /* @__PURE__ */ jsxs7(Box7, { children: [
|
|
8943
9108
|
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: label.padEnd(9) }),
|
|
8944
|
-
/* @__PURE__ */ jsx7(Text7, { color, children: value })
|
|
9109
|
+
/* @__PURE__ */ jsx7(Text7, { color, wrap: "truncate", children: value })
|
|
8945
9110
|
] });
|
|
8946
9111
|
}
|
|
8947
|
-
var DECISIONS, SIGNALS;
|
|
9112
|
+
var DECISIONS, SIGNALS, FETCH_LIMIT;
|
|
8948
9113
|
var init_Audit = __esm({
|
|
8949
9114
|
"src/tui/panels/Audit.tsx"() {
|
|
8950
9115
|
"use strict";
|
|
@@ -8954,13 +9119,14 @@ var init_Audit = __esm({
|
|
|
8954
9119
|
init_theme();
|
|
8955
9120
|
DECISIONS = [void 0, "DENY", "ALLOW"];
|
|
8956
9121
|
SIGNALS = [void 0, "dlp", "ratelimit"];
|
|
9122
|
+
FETCH_LIMIT = 500;
|
|
8957
9123
|
}
|
|
8958
9124
|
});
|
|
8959
9125
|
|
|
8960
9126
|
// src/tui/panels/Agents.tsx
|
|
8961
9127
|
import { Box as Box8, Text as Text8, useInput as useInput6 } from "ink";
|
|
8962
9128
|
import { useState as useState7 } from "react";
|
|
8963
|
-
import { Fragment as
|
|
9129
|
+
import { Fragment as Fragment5, jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
8964
9130
|
function Bar({ label, value, max = 100, width: width2 = 16, color = theme.accent }) {
|
|
8965
9131
|
const filled = max > 0 ? Math.round(Math.min(value, max) / max * width2) : 0;
|
|
8966
9132
|
return /* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", children: [
|
|
@@ -9004,7 +9170,7 @@ function AgentsPanel({ focused }) {
|
|
|
9004
9170
|
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: `t${a.trust_score}` })
|
|
9005
9171
|
] }, a.session_id))
|
|
9006
9172
|
] }),
|
|
9007
|
-
/* @__PURE__ */ jsx8(Box8, { flexDirection: "column", flexGrow: 1, overflow: "hidden", children: !selected ? /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "select an agent" }) : detail.loading && !d ? /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "loading profile\u2026" }) : !d ? /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "no profile (agent has no calls yet)" }) : /* @__PURE__ */ jsxs8(
|
|
9173
|
+
/* @__PURE__ */ jsx8(Box8, { flexDirection: "column", flexGrow: 1, overflow: "hidden", children: !selected ? /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "select an agent" }) : detail.loading && !d ? /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "loading profile\u2026" }) : !d ? /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "no profile (agent has no calls yet)" }) : /* @__PURE__ */ jsxs8(Fragment5, { children: [
|
|
9008
9174
|
/* @__PURE__ */ jsxs8(Box8, { children: [
|
|
9009
9175
|
/* @__PURE__ */ jsx8(Text8, { bold: true, color: theme.accentBright, children: truncate2(selected.agent_name ?? selected.agent_id ?? "?", 22) }),
|
|
9010
9176
|
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: ` trust ${base?.trustScore ?? "\u2014"}/100 \xB7 ${base?.character ?? ""}` })
|
|
@@ -9053,41 +9219,256 @@ var init_Agents = __esm({
|
|
|
9053
9219
|
}
|
|
9054
9220
|
});
|
|
9055
9221
|
|
|
9056
|
-
// src/tui/
|
|
9057
|
-
import { Box as Box9, Text as Text9,
|
|
9222
|
+
// src/tui/panels/Settings.tsx
|
|
9223
|
+
import { Box as Box9, Text as Text9, useInput as useInput7 } from "ink";
|
|
9224
|
+
import TextInput5 from "ink-text-input";
|
|
9058
9225
|
import { useState as useState8 } from "react";
|
|
9059
9226
|
import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
9227
|
+
function alertBodyFor(channel) {
|
|
9228
|
+
const c2 = channel.trim();
|
|
9229
|
+
const base = { name: "dataroom alert", threshold: 5, windowSeconds: 60, signal: "any" };
|
|
9230
|
+
if (/^https?:\/\//i.test(c2)) return { ...base, slackUrl: c2 };
|
|
9231
|
+
if (c2.includes("@")) return { ...base, emails: [c2] };
|
|
9232
|
+
return { ...base, telegram: [c2] };
|
|
9233
|
+
}
|
|
9234
|
+
function SettingsPanel({ active: active2, focused }) {
|
|
9235
|
+
void active2;
|
|
9236
|
+
const { cols, rows } = usePanelSize();
|
|
9237
|
+
const [sel, setSel] = useState8(0);
|
|
9238
|
+
const [editing, setEditing] = useState8(null);
|
|
9239
|
+
const [input, setInput] = useState8("");
|
|
9240
|
+
const [confirmDel, setConfirmDel] = useState8(null);
|
|
9241
|
+
const [msg, setMsg] = useState8(null);
|
|
9242
|
+
const [busy, setBusy] = useState8(false);
|
|
9243
|
+
const localQ = useLoader(() => api.settings.getLocalLogs());
|
|
9244
|
+
const whQ = useLoader(() => api.settings.getWebhooks());
|
|
9245
|
+
const alertQ = useLoader(() => api.settings.getAlerts());
|
|
9246
|
+
const local = localQ.data;
|
|
9247
|
+
const webhooks = whQ.data?.webhooks ?? [];
|
|
9248
|
+
const alerts = alertQ.data?.rules ?? [];
|
|
9249
|
+
const rowsAll = [
|
|
9250
|
+
{ kind: "ll-enabled" },
|
|
9251
|
+
{ kind: "ll-path" },
|
|
9252
|
+
...webhooks.map((wh) => ({ kind: "wh", wh })),
|
|
9253
|
+
{ kind: "wh-add" },
|
|
9254
|
+
...alerts.map((rule) => ({ kind: "alert", rule })),
|
|
9255
|
+
{ kind: "alert-add" }
|
|
9256
|
+
];
|
|
9257
|
+
const selClamped = Math.min(sel, rowsAll.length - 1);
|
|
9258
|
+
const cur = rowsAll[selClamped];
|
|
9259
|
+
const keyOf = (r) => r.kind === "wh" ? "wh:" + r.wh.id : r.kind === "alert" ? "alert:" + r.rule.id : r.kind;
|
|
9260
|
+
const reloadAll = () => {
|
|
9261
|
+
localQ.reload();
|
|
9262
|
+
whQ.reload();
|
|
9263
|
+
alertQ.reload();
|
|
9264
|
+
};
|
|
9265
|
+
const run12 = (label, fn, reload) => {
|
|
9266
|
+
if (busy) return;
|
|
9267
|
+
setBusy(true);
|
|
9268
|
+
setMsg({ text: label + "\u2026", level: "ok" });
|
|
9269
|
+
fn().then(() => {
|
|
9270
|
+
setMsg({ text: "\u2713 " + label, level: "ok" });
|
|
9271
|
+
reload();
|
|
9272
|
+
}).catch((e) => setMsg({ text: "\u2717 " + (e instanceof Error ? e.message : String(e)), level: "bad" })).finally(() => setBusy(false));
|
|
9273
|
+
};
|
|
9274
|
+
const activate = (r) => {
|
|
9275
|
+
if (r.kind === "ll-enabled") {
|
|
9276
|
+
if (!local) return;
|
|
9277
|
+
if (!local.enabled && !local.path.trim()) {
|
|
9278
|
+
setMsg({ text: "set a path first (\u2193 then enter)", level: "bad" });
|
|
9279
|
+
return;
|
|
9280
|
+
}
|
|
9281
|
+
run12(local.enabled ? "local logs disabled" : "local logs enabled", () => api.settings.setLocalLogs({ enabled: !local.enabled, path: local.path }), localQ.reload);
|
|
9282
|
+
} else if (r.kind === "ll-path") {
|
|
9283
|
+
setInput(local?.path ?? "");
|
|
9284
|
+
setEditing("path");
|
|
9285
|
+
} else if (r.kind === "wh") {
|
|
9286
|
+
run12(r.wh.enabled ? "webhook disabled" : "webhook enabled", () => api.settings.updateWebhook(r.wh.id, { enabled: !r.wh.enabled }), whQ.reload);
|
|
9287
|
+
} else if (r.kind === "wh-add") {
|
|
9288
|
+
setInput("");
|
|
9289
|
+
setEditing("wh-url");
|
|
9290
|
+
} else if (r.kind === "alert") {
|
|
9291
|
+
run12(r.rule.enabled ? "alert disabled" : "alert enabled", () => api.settings.setAlertEnabled(r.rule.id, !r.rule.enabled), alertQ.reload);
|
|
9292
|
+
} else {
|
|
9293
|
+
setInput("");
|
|
9294
|
+
setEditing("alert-channel");
|
|
9295
|
+
}
|
|
9296
|
+
};
|
|
9297
|
+
const submitInput = () => {
|
|
9298
|
+
const v = input.trim();
|
|
9299
|
+
const which = editing;
|
|
9300
|
+
setEditing(null);
|
|
9301
|
+
if (which === "path") {
|
|
9302
|
+
const enabled = (local?.enabled ?? false) && v.length > 0;
|
|
9303
|
+
run12(v ? `path saved${enabled ? "" : " (press enter on enabled to turn on)"}` : "path cleared (local logs off)", () => api.settings.setLocalLogs({ enabled, path: v }), localQ.reload);
|
|
9304
|
+
} else if (which === "wh-url") {
|
|
9305
|
+
if (!v) return;
|
|
9306
|
+
run12("webhook added", () => api.settings.createWebhook({ url: v, events: "denials" }), whQ.reload);
|
|
9307
|
+
} else if (which === "alert-channel") {
|
|
9308
|
+
if (!v) return;
|
|
9309
|
+
run12("alert rule added", () => api.settings.createAlert(alertBodyFor(v)), alertQ.reload);
|
|
9310
|
+
}
|
|
9311
|
+
};
|
|
9312
|
+
useInput7(
|
|
9313
|
+
(inp, key) => {
|
|
9314
|
+
setMsg(null);
|
|
9315
|
+
if (key.upArrow) {
|
|
9316
|
+
setSel((n) => Math.max(0, n - 1));
|
|
9317
|
+
setConfirmDel(null);
|
|
9318
|
+
} else if (key.downArrow) {
|
|
9319
|
+
setSel((n) => Math.min(rowsAll.length - 1, n + 1));
|
|
9320
|
+
setConfirmDel(null);
|
|
9321
|
+
} else if (key.return || inp === " ") activate(cur);
|
|
9322
|
+
else if (inp === "e" && cur.kind === "wh") {
|
|
9323
|
+
const next = EVENTS[(EVENTS.indexOf(cur.wh.events) + 1) % EVENTS.length];
|
|
9324
|
+
run12(`webhook events \u2192 ${next}`, () => api.settings.updateWebhook(cur.wh.id, { events: next }), whQ.reload);
|
|
9325
|
+
} else if (inp === "e" && cur.kind === "ll-path") activate(cur);
|
|
9326
|
+
else if (inp === "a") {
|
|
9327
|
+
if (cur.kind === "wh" || cur.kind === "wh-add") {
|
|
9328
|
+
setInput("");
|
|
9329
|
+
setEditing("wh-url");
|
|
9330
|
+
} else if (cur.kind === "alert" || cur.kind === "alert-add") {
|
|
9331
|
+
setInput("");
|
|
9332
|
+
setEditing("alert-channel");
|
|
9333
|
+
}
|
|
9334
|
+
} else if (inp === "d" && (cur.kind === "wh" || cur.kind === "alert")) {
|
|
9335
|
+
const k = keyOf(cur);
|
|
9336
|
+
if (confirmDel !== k) {
|
|
9337
|
+
setConfirmDel(k);
|
|
9338
|
+
setMsg({ text: "press d again to delete", level: "bad" });
|
|
9339
|
+
return;
|
|
9340
|
+
}
|
|
9341
|
+
setConfirmDel(null);
|
|
9342
|
+
if (cur.kind === "wh") run12("webhook deleted", () => api.settings.deleteWebhook(cur.wh.id), whQ.reload);
|
|
9343
|
+
else run12("alert deleted", () => api.settings.deleteAlert(cur.rule.id), alertQ.reload);
|
|
9344
|
+
} else if (inp === "r") reloadAll();
|
|
9345
|
+
},
|
|
9346
|
+
{ isActive: focused && !editing }
|
|
9347
|
+
);
|
|
9348
|
+
const loading = localQ.loading && !localQ.data || whQ.loading && !whQ.data || alertQ.loading && !alertQ.data;
|
|
9349
|
+
const error = localQ.error ?? whQ.error ?? alertQ.error;
|
|
9350
|
+
const mark = (r) => keyOf(r) === keyOf(cur) && focused ? "\u25B8 " : " ";
|
|
9351
|
+
const onOff = (on) => on ? /* @__PURE__ */ jsx9(Text9, { color: theme.ok, children: "on " }) : /* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: "off" });
|
|
9352
|
+
const chanOf = (rule) => [...(rule.slackUrls ?? []).map((u) => "slack " + u), ...rule.emails ?? [], ...(rule.telegram ?? []).map((t) => "tg " + t)].join(", ") || "\u2014";
|
|
9353
|
+
const listBudget = Math.max(4, rows - 8);
|
|
9354
|
+
const start = Math.min(Math.max(0, selClamped - Math.floor(listBudget / 2)), Math.max(0, rowsAll.length - listBudget));
|
|
9355
|
+
const inWindow = (r) => {
|
|
9356
|
+
const i = rowsAll.findIndex((x) => keyOf(x) === keyOf(r));
|
|
9357
|
+
return i >= start && i < start + listBudget;
|
|
9358
|
+
};
|
|
9359
|
+
return /* @__PURE__ */ jsx9(DataView, { loading, error, children: /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", children: [
|
|
9360
|
+
/* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: focused ? "\u2191\u2193 move \xB7 enter/space toggle-edit-add \xB7 e events \xB7 d delete \xB7 r refresh" : "press \u2192 to configure" }),
|
|
9361
|
+
editing ? /* @__PURE__ */ jsxs9(Box9, { children: [
|
|
9362
|
+
/* @__PURE__ */ jsx9(Text9, { color: theme.warn, children: editing === "path" ? "local log path: " : editing === "wh-url" ? "webhook url: " : "channel (slack url / email / telegram id): " }),
|
|
9363
|
+
/* @__PURE__ */ jsx9(TextInput5, { value: input, onChange: setInput, onSubmit: submitInput })
|
|
9364
|
+
] }) : msg ? /* @__PURE__ */ jsx9(Text9, { color: msg.level === "bad" ? theme.bad : theme.ok, children: truncate2(msg.text, cols) }) : /* @__PURE__ */ jsx9(Text9, { children: " " }),
|
|
9365
|
+
inWindow(rowsAll[0]) || inWindow(rowsAll[1]) ? /* @__PURE__ */ jsxs9(Box9, { marginTop: 1, flexDirection: "column", children: [
|
|
9366
|
+
/* @__PURE__ */ jsxs9(Text9, { bold: true, color: theme.accentBright, children: [
|
|
9367
|
+
"LOCAL LOGS ",
|
|
9368
|
+
/* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: "\u2014 hooks mirror every decision to a file on the agent machine" })
|
|
9369
|
+
] }),
|
|
9370
|
+
/* @__PURE__ */ jsxs9(Text9, { wrap: "truncate", children: [
|
|
9371
|
+
/* @__PURE__ */ jsx9(Text9, { color: keyOf(cur) === "ll-enabled" && focused ? theme.accentBright : theme.dim, children: mark(rowsAll[0]) }),
|
|
9372
|
+
/* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: "enabled ".padEnd(10) }),
|
|
9373
|
+
onOff(!!local?.enabled),
|
|
9374
|
+
/* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: " enter toggles" })
|
|
9375
|
+
] }),
|
|
9376
|
+
/* @__PURE__ */ jsxs9(Text9, { wrap: "truncate", children: [
|
|
9377
|
+
/* @__PURE__ */ jsx9(Text9, { color: keyOf(cur) === "ll-path" && focused ? theme.accentBright : theme.dim, children: mark(rowsAll[1]) }),
|
|
9378
|
+
/* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: "path ".padEnd(10) }),
|
|
9379
|
+
local?.path ? /* @__PURE__ */ jsx9(Text9, { color: theme.accent, children: truncate2(local.path, cols - 14) }) : /* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: "not set \u2014 enter to edit" })
|
|
9380
|
+
] })
|
|
9381
|
+
] }) : null,
|
|
9382
|
+
/* @__PURE__ */ jsxs9(Box9, { marginTop: 1, flexDirection: "column", children: [
|
|
9383
|
+
/* @__PURE__ */ jsxs9(Text9, { bold: true, color: theme.accentBright, children: [
|
|
9384
|
+
"WEBHOOKS ",
|
|
9385
|
+
/* @__PURE__ */ jsxs9(Text9, { color: theme.dim, children: [
|
|
9386
|
+
"\u2014 POST every matching event to your endpoint (",
|
|
9387
|
+
webhooks.length,
|
|
9388
|
+
")"
|
|
9389
|
+
] })
|
|
9390
|
+
] }),
|
|
9391
|
+
webhooks.filter((wh) => inWindow({ kind: "wh", wh })).map((wh) => /* @__PURE__ */ jsxs9(Text9, { wrap: "truncate", children: [
|
|
9392
|
+
/* @__PURE__ */ jsx9(Text9, { color: keyOf(cur) === "wh:" + wh.id && focused ? theme.accentBright : theme.dim, children: mark({ kind: "wh", wh }) }),
|
|
9393
|
+
onOff(wh.enabled),
|
|
9394
|
+
/* @__PURE__ */ jsx9(Text9, { color: theme.warn, children: (" " + wh.events).padEnd(9) }),
|
|
9395
|
+
/* @__PURE__ */ jsx9(Text9, { color: theme.accent, children: truncate2(wh.url, cols - 16) })
|
|
9396
|
+
] }, wh.id)),
|
|
9397
|
+
inWindow(rowsAll.find((r) => r.kind === "wh-add")) ? /* @__PURE__ */ jsxs9(Text9, { children: [
|
|
9398
|
+
/* @__PURE__ */ jsx9(Text9, { color: cur.kind === "wh-add" && focused ? theme.accentBright : theme.dim, children: mark({ kind: "wh-add" }) }),
|
|
9399
|
+
/* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: "+ add webhook (enter)" })
|
|
9400
|
+
] }) : null
|
|
9401
|
+
] }),
|
|
9402
|
+
/* @__PURE__ */ jsxs9(Box9, { marginTop: 1, flexDirection: "column", children: [
|
|
9403
|
+
/* @__PURE__ */ jsxs9(Text9, { bold: true, color: theme.accentBright, children: [
|
|
9404
|
+
"ALERTS ",
|
|
9405
|
+
/* @__PURE__ */ jsxs9(Text9, { color: theme.dim, children: [
|
|
9406
|
+
"\u2014 notify on a signal spike (",
|
|
9407
|
+
alerts.length,
|
|
9408
|
+
")"
|
|
9409
|
+
] })
|
|
9410
|
+
] }),
|
|
9411
|
+
alerts.filter((rule) => inWindow({ kind: "alert", rule })).map((rule) => /* @__PURE__ */ jsxs9(Text9, { wrap: "truncate", children: [
|
|
9412
|
+
/* @__PURE__ */ jsx9(Text9, { color: keyOf(cur) === "alert:" + rule.id && focused ? theme.accentBright : theme.dim, children: mark({ kind: "alert", rule }) }),
|
|
9413
|
+
onOff(rule.enabled),
|
|
9414
|
+
/* @__PURE__ */ jsx9(Text9, { color: theme.warn, children: (" " + rule.signal).padEnd(11) }),
|
|
9415
|
+
/* @__PURE__ */ jsx9(Text9, { children: `\u2265${rule.threshold}/${rule.windowSeconds}s ` }),
|
|
9416
|
+
/* @__PURE__ */ jsx9(Text9, { color: theme.accent, children: truncate2(chanOf(rule), cols - 26) })
|
|
9417
|
+
] }, rule.id)),
|
|
9418
|
+
inWindow(rowsAll[rowsAll.length - 1]) ? /* @__PURE__ */ jsxs9(Text9, { children: [
|
|
9419
|
+
/* @__PURE__ */ jsx9(Text9, { color: cur.kind === "alert-add" && focused ? theme.accentBright : theme.dim, children: mark({ kind: "alert-add" }) }),
|
|
9420
|
+
/* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: "+ add alert (enter \u2014 one channel: slack url, email or telegram chat id)" })
|
|
9421
|
+
] }) : null
|
|
9422
|
+
] })
|
|
9423
|
+
] }) });
|
|
9424
|
+
}
|
|
9425
|
+
var EVENTS;
|
|
9426
|
+
var init_Settings = __esm({
|
|
9427
|
+
"src/tui/panels/Settings.tsx"() {
|
|
9428
|
+
"use strict";
|
|
9429
|
+
init_api_client();
|
|
9430
|
+
init_components();
|
|
9431
|
+
init_hooks();
|
|
9432
|
+
init_theme();
|
|
9433
|
+
EVENTS = ["denials", "allowed", "all"];
|
|
9434
|
+
}
|
|
9435
|
+
});
|
|
9436
|
+
|
|
9437
|
+
// src/tui/App.tsx
|
|
9438
|
+
import { Box as Box10, Text as Text10, useApp, useInput as useInput8 } from "ink";
|
|
9439
|
+
import { useState as useState9 } from "react";
|
|
9440
|
+
import { jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
9060
9441
|
function LiveHint() {
|
|
9061
|
-
return /* @__PURE__ */
|
|
9062
|
-
/* @__PURE__ */
|
|
9063
|
-
/* @__PURE__ */
|
|
9064
|
-
/* @__PURE__ */
|
|
9065
|
-
/* @__PURE__ */
|
|
9442
|
+
return /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", children: [
|
|
9443
|
+
/* @__PURE__ */ jsx10(Text10, { color: theme.accentBright, bold: true, children: "\u25B6 REALTIME CONSOLE" }),
|
|
9444
|
+
/* @__PURE__ */ jsx10(Text10, { color: theme.dim, children: "Fullscreen live monitor \u2014 streaming tool calls, active charts," }),
|
|
9445
|
+
/* @__PURE__ */ jsx10(Text10, { color: theme.dim, children: "counters, DLP hits and denial alerts. Updates every 2s." }),
|
|
9446
|
+
/* @__PURE__ */ jsx10(Box10, { marginTop: 1, children: /* @__PURE__ */ jsxs10(Text10, { children: [
|
|
9066
9447
|
"press ",
|
|
9067
|
-
/* @__PURE__ */
|
|
9448
|
+
/* @__PURE__ */ jsx10(Text10, { color: theme.accent, children: "enter" }),
|
|
9068
9449
|
" to go live"
|
|
9069
9450
|
] }) })
|
|
9070
9451
|
] });
|
|
9071
9452
|
}
|
|
9072
|
-
function Banner() {
|
|
9073
|
-
const wide =
|
|
9453
|
+
function Banner({ cols }) {
|
|
9454
|
+
const wide = cols >= 82;
|
|
9074
9455
|
if (!wide) {
|
|
9075
|
-
return /* @__PURE__ */
|
|
9076
|
-
/* @__PURE__ */
|
|
9077
|
-
/* @__PURE__ */
|
|
9456
|
+
return /* @__PURE__ */ jsxs10(Box10, { children: [
|
|
9457
|
+
/* @__PURE__ */ jsx10(Text10, { bold: true, color: theme.accentBright, children: "SolonGate" }),
|
|
9458
|
+
/* @__PURE__ */ jsx10(Text10, { color: theme.dim, children: " \u2014 security control center" })
|
|
9078
9459
|
] });
|
|
9079
9460
|
}
|
|
9080
|
-
return /* @__PURE__ */
|
|
9081
|
-
BANNER_FULL.map((line, i) => /* @__PURE__ */
|
|
9082
|
-
/* @__PURE__ */
|
|
9461
|
+
return /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", children: [
|
|
9462
|
+
BANNER_FULL.map((line, i) => /* @__PURE__ */ jsx10(Text10, { bold: true, color: BANNER_HEX[i], children: line }, i)),
|
|
9463
|
+
/* @__PURE__ */ jsx10(Text10, { color: theme.dim, children: " security control center \xB7 manage policies, rate limits, DLP & more" })
|
|
9083
9464
|
] });
|
|
9084
9465
|
}
|
|
9085
9466
|
function App() {
|
|
9086
9467
|
const { exit } = useApp();
|
|
9087
|
-
const [section, setSection] =
|
|
9088
|
-
const [focus, setFocus] =
|
|
9089
|
-
const [help, setHelp] =
|
|
9090
|
-
|
|
9468
|
+
const [section, setSection] = useState9(0);
|
|
9469
|
+
const [focus, setFocus] = useState9("nav");
|
|
9470
|
+
const [help, setHelp] = useState9(false);
|
|
9471
|
+
useInput8((input, key) => {
|
|
9091
9472
|
if (help) {
|
|
9092
9473
|
setHelp(false);
|
|
9093
9474
|
return;
|
|
@@ -9106,34 +9487,33 @@ function App() {
|
|
|
9106
9487
|
else if (input === "q" && SECTIONS[section].label === "Live") exit();
|
|
9107
9488
|
}
|
|
9108
9489
|
});
|
|
9109
|
-
const cols
|
|
9110
|
-
const rows = process.stdout.rows ?? 30;
|
|
9490
|
+
const { cols, rows } = useTermSize();
|
|
9111
9491
|
const current = SECTIONS[section];
|
|
9112
|
-
if (help) return /* @__PURE__ */
|
|
9492
|
+
if (help) return /* @__PURE__ */ jsx10(HelpOverlay, { cols, rows });
|
|
9113
9493
|
if (current.label === "Live" && focus === "panel") {
|
|
9114
|
-
return /* @__PURE__ */
|
|
9494
|
+
return /* @__PURE__ */ jsx10(Box10, { flexDirection: "column", width: cols, height: rows, children: /* @__PURE__ */ jsx10(LivePanel, { active: true, focused: true }) });
|
|
9115
9495
|
}
|
|
9116
9496
|
const Panel = current.Panel;
|
|
9117
|
-
return /* @__PURE__ */
|
|
9118
|
-
/* @__PURE__ */
|
|
9119
|
-
/* @__PURE__ */
|
|
9120
|
-
/* @__PURE__ */
|
|
9121
|
-
/* @__PURE__ */
|
|
9497
|
+
return /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", width: cols, height: rows, paddingX: 1, paddingTop: 1, children: [
|
|
9498
|
+
/* @__PURE__ */ jsx10(Banner, { cols }),
|
|
9499
|
+
/* @__PURE__ */ jsxs10(Box10, { marginTop: 1, flexGrow: 1, children: [
|
|
9500
|
+
/* @__PURE__ */ jsx10(Box10, { flexDirection: "column", width: 16, borderStyle: "round", borderColor: focus === "nav" ? theme.accent : "gray", paddingX: 1, children: SECTIONS.map((s, i) => /* @__PURE__ */ jsx10(Text10, { color: i === section ? theme.accentBright : void 0, bold: i === section, children: (i === section ? "\u25B8 " : " ") + s.label }, s.label)) }),
|
|
9501
|
+
/* @__PURE__ */ jsx10(Box10, { flexGrow: 1, borderStyle: "round", borderColor: focus === "panel" ? theme.accent : "gray", paddingX: 1, paddingY: 0, children: /* @__PURE__ */ jsx10(Panel, { active: focus === "panel" || current.label !== "Live", focused: focus === "panel" }) })
|
|
9122
9502
|
] }),
|
|
9123
|
-
/* @__PURE__ */
|
|
9503
|
+
/* @__PURE__ */ jsx10(Box10, { children: focus === "nav" ? /* @__PURE__ */ jsx10(KeyHints, { hints: [["\u2191\u2193", "section"], ["\u2192/enter", "open"], ["?", "help"], ["q", "quit"]] }) : /* @__PURE__ */ jsx10(KeyHints, { hints: [["\u2190/esc", "back"], ["\u2191\u2193", "in-panel"], ["space/s", "act"]] }) })
|
|
9124
9504
|
] });
|
|
9125
9505
|
}
|
|
9126
9506
|
function HelpOverlay({ cols, rows }) {
|
|
9127
|
-
return /* @__PURE__ */
|
|
9128
|
-
/* @__PURE__ */
|
|
9129
|
-
/* @__PURE__ */
|
|
9130
|
-
/* @__PURE__ */
|
|
9131
|
-
keys.map(([k, desc]) => /* @__PURE__ */
|
|
9132
|
-
/* @__PURE__ */
|
|
9133
|
-
/* @__PURE__ */
|
|
9507
|
+
return /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", width: cols, height: rows, paddingX: 2, paddingTop: 1, children: [
|
|
9508
|
+
/* @__PURE__ */ jsx10(Text10, { bold: true, color: theme.accentBright, children: "SolonGate \u2014 keyboard shortcuts" }),
|
|
9509
|
+
/* @__PURE__ */ jsx10(Box10, { marginTop: 1, flexDirection: "column", children: HELP.map(([group, keys]) => /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", marginBottom: 1, children: [
|
|
9510
|
+
/* @__PURE__ */ jsx10(Text10, { bold: true, color: theme.accent, children: group }),
|
|
9511
|
+
keys.map(([k, desc]) => /* @__PURE__ */ jsxs10(Text10, { children: [
|
|
9512
|
+
/* @__PURE__ */ jsx10(Text10, { color: theme.accentBright, children: (" " + k).padEnd(16) }),
|
|
9513
|
+
/* @__PURE__ */ jsx10(Text10, { color: theme.dim, children: desc })
|
|
9134
9514
|
] }, k))
|
|
9135
9515
|
] }, group)) }),
|
|
9136
|
-
/* @__PURE__ */
|
|
9516
|
+
/* @__PURE__ */ jsx10(Text10, { color: theme.dim, children: "press any key to close" })
|
|
9137
9517
|
] });
|
|
9138
9518
|
}
|
|
9139
9519
|
var SECTIONS, BANNER_HEX, HELP;
|
|
@@ -9150,6 +9530,8 @@ var init_App = __esm({
|
|
|
9150
9530
|
init_Stats();
|
|
9151
9531
|
init_Audit();
|
|
9152
9532
|
init_Agents();
|
|
9533
|
+
init_Settings();
|
|
9534
|
+
init_hooks();
|
|
9153
9535
|
SECTIONS = [
|
|
9154
9536
|
{ label: "Live", Panel: LiveHint },
|
|
9155
9537
|
{ label: "Agents", Panel: AgentsPanel },
|
|
@@ -9157,14 +9539,17 @@ var init_App = __esm({
|
|
|
9157
9539
|
{ label: "Rate Limit", Panel: RateLimitPanel },
|
|
9158
9540
|
{ label: "DLP", Panel: DlpPanel },
|
|
9159
9541
|
{ label: "Stats", Panel: StatsPanel },
|
|
9160
|
-
{ label: "Audit", Panel: AuditPanel }
|
|
9542
|
+
{ label: "Audit", Panel: AuditPanel },
|
|
9543
|
+
{ label: "Settings", Panel: SettingsPanel }
|
|
9161
9544
|
];
|
|
9162
9545
|
BANNER_HEX = ["#1432A0", "#2850BE", "#3C6ED7", "#5A8CE6", "#82AAF0", "#AAC8FA"];
|
|
9163
9546
|
HELP = [
|
|
9164
9547
|
["Global", [["\u2191\u2193", "move between sections"], ["\u2192 / enter", "open a section"], ["\u2190 / esc", "back to the menu"], ["?", "this help"], ["q", "quit"]]],
|
|
9165
|
-
["Live", [["\u2191\u2193", "select a stream row"], ["w", "whitelist the selected DENY"], ["b", "block the selected ALLOW"], ["d / x / r", "filter denies / dlp / rate-limit"], ["f", "local / cloud filter"], ["/", "search"], ["s", "sessions (\u2191\u2193 pick, enter open)"], ["space", "copy mode (freeze)"]]],
|
|
9548
|
+
["Live", [["\u2191\u2193", "select a stream row"], ["enter", "full entry content"], ["w", "whitelist the selected DENY"], ["b", "block the selected ALLOW"], ["d / x / r", "filter denies / dlp / rate-limit"], ["f", "local / cloud filter"], ["/", "search"], ["s", "sessions (\u2191\u2193 pick, enter open)"], ["space", "copy mode (freeze)"]]],
|
|
9166
9549
|
["Policies", [["\u2191\u2193", "browse / select"], ["enter", "open rules \u2192 open a rule"], ["space", "toggle a rule on/off"], ["e", "flip effect"], ["n", "new rule"], ["d", "delete rule"], ["m", "flip mode"], ["D", "dry-run the draft"], ["v", "versions / rollback"], ["s", "save"], ["x", "discard"]]],
|
|
9167
|
-
["Rate limit / DLP", [["\u2191\u2193", "field / pattern"], ["\u2190\u2192", "adjust (shift = \xB110)"], ["space", "toggle pattern"], ["m", "mode"], ["a / d", "add / remove custom"], ["g", "ghost mode"], ["P", "self-protection"], ["s", "save"]]]
|
|
9550
|
+
["Rate limit / DLP", [["\u2191\u2193", "field / pattern"], ["\u2190\u2192", "adjust (shift = \xB110)"], ["space", "toggle pattern"], ["m", "mode"], ["a / d", "add / remove custom"], ["g", "ghost mode"], ["P", "self-protection"], ["s", "save"]]],
|
|
9551
|
+
["Audit", [["\u2191\u2193", "select (list scrolls)"], ["enter", "full entry detail"], ["f / g", "decision / signal filter"], ["t / n / /", "tool / agent / search"], ["c", "clear filters"]]],
|
|
9552
|
+
["Settings", [["\u2191\u2193", "move"], ["enter / space", "toggle \xB7 edit \xB7 add"], ["e", "webhook events"], ["d d", "delete"], ["r", "refresh"]]]
|
|
9168
9553
|
];
|
|
9169
9554
|
}
|
|
9170
9555
|
});
|
|
@@ -9175,7 +9560,7 @@ __export(tui_exports, {
|
|
|
9175
9560
|
launchTui: () => launchTui
|
|
9176
9561
|
});
|
|
9177
9562
|
import { render } from "ink";
|
|
9178
|
-
import { jsx as
|
|
9563
|
+
import { jsx as jsx11 } from "react/jsx-runtime";
|
|
9179
9564
|
async function launchTui() {
|
|
9180
9565
|
if (!process.stdout.isTTY || !process.stdin.isTTY) {
|
|
9181
9566
|
process.stderr.write(
|
|
@@ -9189,7 +9574,7 @@ async function launchTui() {
|
|
|
9189
9574
|
}
|
|
9190
9575
|
process.stdout.write("\x1B[?1049h\x1B[H");
|
|
9191
9576
|
try {
|
|
9192
|
-
const { waitUntilExit } = render(/* @__PURE__ */
|
|
9577
|
+
const { waitUntilExit } = render(/* @__PURE__ */ jsx11(App, {}));
|
|
9193
9578
|
await waitUntilExit();
|
|
9194
9579
|
} finally {
|
|
9195
9580
|
process.stdout.write("\x1B[?1049l");
|