@solongate/proxy 0.82.30 → 0.82.32
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/policies.d.ts +63 -0
- package/dist/commands/index.js +4 -0
- package/dist/index.js +598 -438
- package/dist/tui/index.js +586 -435
- package/dist/tui/panels/DryRun.d.ts +5 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -7374,6 +7374,7 @@ var policies_exports = {};
|
|
|
7374
7374
|
__export(policies_exports, {
|
|
7375
7375
|
active: () => active,
|
|
7376
7376
|
addRule: () => addRule,
|
|
7377
|
+
backtest: () => backtest,
|
|
7377
7378
|
create: () => create,
|
|
7378
7379
|
dryRun: () => dryRun,
|
|
7379
7380
|
get: () => get,
|
|
@@ -7423,6 +7424,9 @@ function setActive(policyId) {
|
|
|
7423
7424
|
function dryRun(body) {
|
|
7424
7425
|
return request("POST", "/policies/dry-run", { body });
|
|
7425
7426
|
}
|
|
7427
|
+
function backtest(body) {
|
|
7428
|
+
return request("POST", "/policies/backtest", { body });
|
|
7429
|
+
}
|
|
7426
7430
|
var init_policies = __esm({
|
|
7427
7431
|
"src/api-client/policies.ts"() {
|
|
7428
7432
|
"use strict";
|
|
@@ -8794,11 +8798,176 @@ var init_Live = __esm({
|
|
|
8794
8798
|
}
|
|
8795
8799
|
});
|
|
8796
8800
|
|
|
8797
|
-
// src/tui/panels/
|
|
8801
|
+
// src/tui/panels/DryRun.tsx
|
|
8798
8802
|
import { Box as Box3, Text as Text3, useInput as useInput2 } from "ink";
|
|
8799
|
-
import TextInput2 from "ink-text-input";
|
|
8800
8803
|
import { useEffect as useEffect3, useState as useState3 } from "react";
|
|
8801
|
-
import {
|
|
8804
|
+
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
8805
|
+
function requestDryRun(policyId) {
|
|
8806
|
+
pendingPolicyId = policyId;
|
|
8807
|
+
}
|
|
8808
|
+
function DryRunPanel({ focused }) {
|
|
8809
|
+
const list6 = useLoader(() => api.policies.list());
|
|
8810
|
+
const policies = list6.data?.policies ?? [];
|
|
8811
|
+
const [pi, setPi] = useState3(0);
|
|
8812
|
+
const [si, setSi] = useState3(3);
|
|
8813
|
+
const [res, setRes] = useState3(null);
|
|
8814
|
+
const [running, setRunning] = useState3(false);
|
|
8815
|
+
const [err2, setErr] = useState3(null);
|
|
8816
|
+
const [off, setOff] = useState3(0);
|
|
8817
|
+
const { cols, rows } = usePanelSize();
|
|
8818
|
+
const selected = policies[Math.min(pi, Math.max(0, policies.length - 1))];
|
|
8819
|
+
function run10(policyIdx = pi, sampleIdx = si) {
|
|
8820
|
+
const p = policies[policyIdx];
|
|
8821
|
+
if (!p) return;
|
|
8822
|
+
setRunning(true);
|
|
8823
|
+
setErr(null);
|
|
8824
|
+
setRes(null);
|
|
8825
|
+
setOff(0);
|
|
8826
|
+
api.policies.backtest({ rules: p.rules ?? [], mode: p.mode, limit: SAMPLES[sampleIdx] }).then((r) => setRes(r)).catch((e) => setErr(e instanceof Error ? e.message : String(e))).finally(() => setRunning(false));
|
|
8827
|
+
}
|
|
8828
|
+
useEffect3(() => {
|
|
8829
|
+
if (policies.length === 0 || res || running || err2) return;
|
|
8830
|
+
let idx = 0;
|
|
8831
|
+
if (pendingPolicyId) {
|
|
8832
|
+
const found = policies.findIndex((p) => p.id === pendingPolicyId);
|
|
8833
|
+
if (found >= 0) idx = found;
|
|
8834
|
+
pendingPolicyId = null;
|
|
8835
|
+
}
|
|
8836
|
+
setPi(idx);
|
|
8837
|
+
run10(idx, si);
|
|
8838
|
+
}, [policies.length]);
|
|
8839
|
+
useInput2((input, key) => {
|
|
8840
|
+
if (!focused) return;
|
|
8841
|
+
if (key.upArrow) setOff((n) => Math.max(0, n - 1));
|
|
8842
|
+
else if (key.downArrow) setOff((n) => n + 1);
|
|
8843
|
+
else if (input === "p") {
|
|
8844
|
+
const n = policies.length ? (pi + 1) % policies.length : 0;
|
|
8845
|
+
setPi(n);
|
|
8846
|
+
run10(n, si);
|
|
8847
|
+
} else if (input === "n") {
|
|
8848
|
+
const n = (si + 1) % SAMPLES.length;
|
|
8849
|
+
setSi(n);
|
|
8850
|
+
run10(pi, n);
|
|
8851
|
+
} else if (input === "r") run10(pi, si);
|
|
8852
|
+
});
|
|
8853
|
+
const w = Math.max(40, cols);
|
|
8854
|
+
const lines = [];
|
|
8855
|
+
const head = (t) => lines.push(/* @__PURE__ */ jsx3(Text3, { bold: true, color: theme.accentBright, children: t }, `h${lines.length}`));
|
|
8856
|
+
const dim3 = (t) => lines.push(/* @__PURE__ */ jsx3(Text3, { color: theme.dim, wrap: "truncate", children: t }, `d${lines.length}`));
|
|
8857
|
+
const row = (t) => lines.push(/* @__PURE__ */ jsx3(Text3, { wrap: "truncate", children: t }, `r${lines.length}`));
|
|
8858
|
+
const blank = () => lines.push(/* @__PURE__ */ jsx3(Text3, { children: " " }, `b${lines.length}`));
|
|
8859
|
+
if (res) {
|
|
8860
|
+
const s = res.summary;
|
|
8861
|
+
const denyAfter = s.would_deny;
|
|
8862
|
+
const denyBefore = s.would_deny - s.newly_blocked + s.newly_allowed;
|
|
8863
|
+
const before = pct(denyBefore, s.evaluated);
|
|
8864
|
+
const after = pct(denyAfter, s.evaluated);
|
|
8865
|
+
const ppShift = s.evaluated ? ((denyAfter - denyBefore) / s.evaluated * 100).toFixed(1) : "0.0";
|
|
8866
|
+
head("Summary");
|
|
8867
|
+
row(` evaluated ${s.evaluated} would allow ${s.would_allow} would deny ${s.would_deny}`);
|
|
8868
|
+
lines.push(
|
|
8869
|
+
/* @__PURE__ */ jsxs3(Text3, { wrap: "truncate", children: [
|
|
8870
|
+
" newly blocked ",
|
|
8871
|
+
/* @__PURE__ */ jsx3(Text3, { color: theme.bad, bold: true, children: String(s.newly_blocked) }),
|
|
8872
|
+
" newly allowed ",
|
|
8873
|
+
/* @__PURE__ */ jsx3(Text3, { color: theme.ok, bold: true, children: String(s.newly_allowed) }),
|
|
8874
|
+
" unchanged ",
|
|
8875
|
+
/* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: String(s.unchanged) })
|
|
8876
|
+
] }, `sum${lines.length}`)
|
|
8877
|
+
);
|
|
8878
|
+
row(` deny rate ${before} -> ${after} (${Number(ppShift) > 0 ? "+" : ""}${ppShift}pp)`);
|
|
8879
|
+
blank();
|
|
8880
|
+
if (res.per_rule.length) {
|
|
8881
|
+
head("Per-rule impact");
|
|
8882
|
+
dim3(` ${"RULE".padEnd(38)}${"MATCHED".padEnd(9)}${"%".padEnd(8)}${"NEW-BLK".padEnd(9)}NEW-ALW`);
|
|
8883
|
+
for (const r of res.per_rule.slice(0, 30)) {
|
|
8884
|
+
row(` ${truncate2(r.rule_id, 36).padEnd(38)}${String(r.matched).padEnd(9)}${pct(r.matched, s.evaluated).padEnd(8)}${String(r.newly_blocked).padEnd(9)}${r.newly_allowed}`);
|
|
8885
|
+
}
|
|
8886
|
+
blank();
|
|
8887
|
+
}
|
|
8888
|
+
if (res.per_agent.length) {
|
|
8889
|
+
head("Per-agent impact");
|
|
8890
|
+
dim3(` ${"AGENT".padEnd(24)}${"EVALUATED".padEnd(11)}${"CHANGED".padEnd(9)}${"NEW-BLK".padEnd(9)}NEW-ALW`);
|
|
8891
|
+
for (const a of res.per_agent) {
|
|
8892
|
+
row(` ${truncate2(a.agent || "-", 22).padEnd(24)}${String(a.evaluated).padEnd(11)}${String(a.changed).padEnd(9)}${String(a.newly_blocked).padEnd(9)}${a.newly_allowed}`);
|
|
8893
|
+
}
|
|
8894
|
+
blank();
|
|
8895
|
+
}
|
|
8896
|
+
if (res.per_tool.length) {
|
|
8897
|
+
head("Per-tool breakdown");
|
|
8898
|
+
dim3(` ${"TOOL".padEnd(24)}${"EVALUATED".padEnd(11)}${"CHANGED".padEnd(9)}${"NEW-BLK".padEnd(9)}NEW-ALW`);
|
|
8899
|
+
for (const t of res.per_tool) {
|
|
8900
|
+
row(` ${truncate2(t.tool || "-", 22).padEnd(24)}${String(t.evaluated).padEnd(11)}${String(t.changed).padEnd(9)}${String(t.newly_blocked).padEnd(9)}${t.newly_allowed}`);
|
|
8901
|
+
}
|
|
8902
|
+
blank();
|
|
8903
|
+
}
|
|
8904
|
+
if (res.samples.length) {
|
|
8905
|
+
head(`Changed calls (${res.samples.length})`);
|
|
8906
|
+
for (const c2 of res.samples) {
|
|
8907
|
+
const flip = `${c2.original}->${c2.predicted}`;
|
|
8908
|
+
const newlyAllowed = c2.predicted === "ALLOW";
|
|
8909
|
+
lines.push(
|
|
8910
|
+
/* @__PURE__ */ jsxs3(Text3, { wrap: "truncate", children: [
|
|
8911
|
+
" ",
|
|
8912
|
+
/* @__PURE__ */ jsx3(Text3, { color: theme.accent, children: truncate2(c2.tool, 16).padEnd(17) }),
|
|
8913
|
+
/* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: truncate2(c2.agent || "-", 14).padEnd(15) }),
|
|
8914
|
+
/* @__PURE__ */ jsx3(Text3, { color: newlyAllowed ? theme.ok : theme.bad, children: flip.padEnd(14) }),
|
|
8915
|
+
/* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: truncate2(c2.preview.replace(/\s+/g, " "), Math.max(10, w - 50)) })
|
|
8916
|
+
] }, `c${lines.length}`)
|
|
8917
|
+
);
|
|
8918
|
+
}
|
|
8919
|
+
}
|
|
8920
|
+
}
|
|
8921
|
+
const headerRows = 3;
|
|
8922
|
+
const budget = Math.max(3, rows - headerRows);
|
|
8923
|
+
const maxOff = Math.max(0, lines.length - budget);
|
|
8924
|
+
const start = Math.min(off, maxOff);
|
|
8925
|
+
const win = lines.slice(start, start + budget);
|
|
8926
|
+
const above = start;
|
|
8927
|
+
const below = Math.max(0, lines.length - (start + budget));
|
|
8928
|
+
const sampleLabel = `${SAMPLES[si]}${res?.sampled != null ? ` (ran ${res.sampled})` : ""}`;
|
|
8929
|
+
return /* @__PURE__ */ jsx3(DataView, { loading: list6.loading && !list6.data, error: list6.error, children: /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", children: [
|
|
8930
|
+
/* @__PURE__ */ jsxs3(Box3, { children: [
|
|
8931
|
+
/* @__PURE__ */ jsx3(Text3, { bold: true, color: theme.accentBright, children: "Policy Dry Run" }),
|
|
8932
|
+
/* @__PURE__ */ jsxs3(Text3, { color: theme.dim, children: [
|
|
8933
|
+
" ",
|
|
8934
|
+
truncate2(selected?.name ?? "no policy", 26)
|
|
8935
|
+
] }),
|
|
8936
|
+
/* @__PURE__ */ jsxs3(Text3, { color: theme.dim, children: [
|
|
8937
|
+
" mode: ",
|
|
8938
|
+
selected?.mode ?? "-"
|
|
8939
|
+
] }),
|
|
8940
|
+
/* @__PURE__ */ jsxs3(Text3, { color: theme.dim, children: [
|
|
8941
|
+
" sample: ",
|
|
8942
|
+
sampleLabel
|
|
8943
|
+
] })
|
|
8944
|
+
] }),
|
|
8945
|
+
/* @__PURE__ */ jsx3(Text3, { color: theme.dim, wrap: "truncate", children: focused ? `\u2191\u2193 scroll \xB7 p policy \xB7 n sample \xB7 r re-run${above ? ` \xB7 \u25B2${above}` : ""}${below ? ` \xB7 \u25BC${below}` : ""}` : "press \u2192 to open" }),
|
|
8946
|
+
running ? /* @__PURE__ */ jsx3(Text3, { color: theme.warn, children: "replaying recent traffic\u2026" }) : null,
|
|
8947
|
+
err2 ? /* @__PURE__ */ jsx3(Text3, { color: theme.bad, wrap: "truncate", children: "\u2717 " + err2 }) : null,
|
|
8948
|
+
!running && !err2 && !res ? /* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: "no result yet \u2014 press r to run" }) : null,
|
|
8949
|
+
/* @__PURE__ */ jsx3(Box3, { marginTop: 1, flexDirection: "column", children: win })
|
|
8950
|
+
] }) });
|
|
8951
|
+
}
|
|
8952
|
+
var SAMPLES, pendingPolicyId, pct;
|
|
8953
|
+
var init_DryRun = __esm({
|
|
8954
|
+
"src/tui/panels/DryRun.tsx"() {
|
|
8955
|
+
"use strict";
|
|
8956
|
+
init_api_client();
|
|
8957
|
+
init_components();
|
|
8958
|
+
init_hooks();
|
|
8959
|
+
init_theme();
|
|
8960
|
+
SAMPLES = [100, 250, 500, 1e3, 2500, 5e3];
|
|
8961
|
+
pendingPolicyId = null;
|
|
8962
|
+
pct = (n, d) => d ? (n / d * 100).toFixed(1) + "%" : "0%";
|
|
8963
|
+
}
|
|
8964
|
+
});
|
|
8965
|
+
|
|
8966
|
+
// src/tui/panels/Policies.tsx
|
|
8967
|
+
import { Box as Box4, Text as Text4, useInput as useInput3 } from "ink";
|
|
8968
|
+
import TextInput2 from "ink-text-input";
|
|
8969
|
+
import { useEffect as useEffect4, useState as useState4 } from "react";
|
|
8970
|
+
import { Fragment as Fragment3, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
8802
8971
|
function ruleSummary(r) {
|
|
8803
8972
|
const bits = [];
|
|
8804
8973
|
for (const [g, tag] of [["commandConstraints", "cmd"], ["pathConstraints", "path"], ["filenameConstraints", "file"], ["urlConstraints", "url"]]) {
|
|
@@ -8815,19 +8984,19 @@ function PoliciesPanel({ focused }) {
|
|
|
8815
8984
|
const activeId = activeQ.data?.policy?.id ?? null;
|
|
8816
8985
|
const activeBy = activeQ.data?.matched_by;
|
|
8817
8986
|
const { rows: panelRows } = usePanelSize();
|
|
8818
|
-
const [view, setView] =
|
|
8819
|
-
const [pi, setPi] =
|
|
8820
|
-
const [ri, setRi] =
|
|
8821
|
-
const [fi, setFi] =
|
|
8822
|
-
const [rules, setRules] =
|
|
8823
|
-
const [mode, setMode] =
|
|
8824
|
-
const [dirty, setDirty] =
|
|
8825
|
-
const [editing, setEditing] =
|
|
8826
|
-
const [editVal, setEditVal] =
|
|
8827
|
-
const [status, setStatus] =
|
|
8987
|
+
const [view, setView] = useState4("list");
|
|
8988
|
+
const [pi, setPi] = useState4(0);
|
|
8989
|
+
const [ri, setRi] = useState4(0);
|
|
8990
|
+
const [fi, setFi] = useState4(0);
|
|
8991
|
+
const [rules, setRules] = useState4([]);
|
|
8992
|
+
const [mode, setMode] = useState4("denylist");
|
|
8993
|
+
const [dirty, setDirty] = useState4(false);
|
|
8994
|
+
const [editing, setEditing] = useState4(false);
|
|
8995
|
+
const [editVal, setEditVal] = useState4("");
|
|
8996
|
+
const [status, setStatus] = useState4(null);
|
|
8828
8997
|
const selected = policies[Math.min(pi, Math.max(0, policies.length - 1))];
|
|
8829
8998
|
const detail = useLoader(() => selected ? api.policies.get(selected.id) : Promise.resolve(null), [selected?.id]);
|
|
8830
|
-
|
|
8999
|
+
useEffect4(() => {
|
|
8831
9000
|
if (detail.data) {
|
|
8832
9001
|
setRules(detail.data.rules);
|
|
8833
9002
|
setMode(detail.data.mode ?? "denylist");
|
|
@@ -8873,7 +9042,7 @@ function PoliciesPanel({ focused }) {
|
|
|
8873
9042
|
setDirty(false);
|
|
8874
9043
|
setStatus("discarded");
|
|
8875
9044
|
};
|
|
8876
|
-
|
|
9045
|
+
useInput3(
|
|
8877
9046
|
(input, key) => {
|
|
8878
9047
|
if (key.ctrl && input === "r" && !editing) {
|
|
8879
9048
|
list6.reload();
|
|
@@ -8906,13 +9075,6 @@ function PoliciesPanel({ focused }) {
|
|
|
8906
9075
|
return;
|
|
8907
9076
|
}
|
|
8908
9077
|
if (view === "rules") {
|
|
8909
|
-
if (key.ctrl && input === "d") {
|
|
8910
|
-
if (selected) {
|
|
8911
|
-
openBrowser(`${DASHBOARD_URL}/playground?policy=${encodeURIComponent(selected.id)}`);
|
|
8912
|
-
setStatus("Opened the dry-run playground in your browser.");
|
|
8913
|
-
}
|
|
8914
|
-
return;
|
|
8915
|
-
}
|
|
8916
9078
|
if (key.leftArrow) return setView("list"), void setStatus(null);
|
|
8917
9079
|
if (key.upArrow) setRi((n) => Math.max(0, n - 1));
|
|
8918
9080
|
else if (key.downArrow) setRi((n) => Math.min(rules.length - 1, n + 1));
|
|
@@ -8940,13 +9102,10 @@ function PoliciesPanel({ focused }) {
|
|
|
8940
9102
|
setFi(0);
|
|
8941
9103
|
setView("rule");
|
|
8942
9104
|
} else if (input === "D") {
|
|
8943
|
-
|
|
8944
|
-
|
|
8945
|
-
|
|
8946
|
-
|
|
8947
|
-
newly allowed ${res.newly_allowed} newly blocked ${res.newly_blocked} unchanged ${res.unchanged}` + (res.sample_newly_blocked?.length ? `
|
|
8948
|
-
now blocked e.g.: ${res.sample_newly_blocked.slice(0, 3).map((s) => truncate2(s.tool, 24)).join(", ")}` : "")
|
|
8949
|
-
)).catch((e) => setStatus("\u2717 " + (e instanceof Error ? e.message : String(e))));
|
|
9105
|
+
if (selected) {
|
|
9106
|
+
requestDryRun(selected.id);
|
|
9107
|
+
setStatus('Sent to Dry Run - open the "Dry Run" section in the left nav for the full report.');
|
|
9108
|
+
}
|
|
8950
9109
|
} else if (input === "s") void save();
|
|
8951
9110
|
else if (input === "x") discard();
|
|
8952
9111
|
return;
|
|
@@ -8979,35 +9138,35 @@ function PoliciesPanel({ focused }) {
|
|
|
8979
9138
|
const lWin = policies.slice(lStart, lStart + lBudget);
|
|
8980
9139
|
const lAbove = lStart;
|
|
8981
9140
|
const lBelow = Math.max(0, policies.length - (lStart + lBudget));
|
|
8982
|
-
return /* @__PURE__ */
|
|
8983
|
-
/* @__PURE__ */
|
|
8984
|
-
/* @__PURE__ */
|
|
8985
|
-
activeQ.loading && !activeQ.data ? /* @__PURE__ */
|
|
8986
|
-
/* @__PURE__ */
|
|
9141
|
+
return /* @__PURE__ */ jsx4(DataView, { loading: list6.loading && !list6.data, error: list6.error, empty: !!list6.data && policies.length === 0, emptyText: "No policies.", children: /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", children: [
|
|
9142
|
+
/* @__PURE__ */ jsxs4(Box4, { children: [
|
|
9143
|
+
/* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: "active: " }),
|
|
9144
|
+
activeQ.loading && !activeQ.data ? /* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: "\u2026" }) : activeName ? /* @__PURE__ */ jsxs4(Fragment3, { children: [
|
|
9145
|
+
/* @__PURE__ */ jsxs4(Text4, { color: theme.ok, bold: true, children: [
|
|
8987
9146
|
"\u25CF ",
|
|
8988
9147
|
truncate2(activeName, 28)
|
|
8989
9148
|
] }),
|
|
8990
|
-
/* @__PURE__ */
|
|
8991
|
-
] }) : /* @__PURE__ */
|
|
9149
|
+
/* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: activeBy ? ` (${activeBy})` : "" })
|
|
9150
|
+
] }) : /* @__PURE__ */ jsx4(Text4, { color: theme.bad, bold: true, children: "\u25CB NONE \u2014 nothing enforced, grants refused" })
|
|
8992
9151
|
] }),
|
|
8993
|
-
/* @__PURE__ */
|
|
8994
|
-
/* @__PURE__ */
|
|
9152
|
+
/* @__PURE__ */ jsx4(Text4, { color: theme.dim, wrap: "truncate", children: focused ? `\u2191\u2193 select \xB7 enter open \xB7 a activate \xB7 x deactivate \xB7 ^R refresh${lAbove ? ` \xB7 \u25B2${lAbove}` : ""}${lBelow ? ` \xB7 \u25BC${lBelow}` : ""}` : "press \u2192 to browse" }),
|
|
9153
|
+
/* @__PURE__ */ jsx4(Box4, { marginTop: 1, flexDirection: "column", children: lWin.map((p, wi) => {
|
|
8995
9154
|
const i = lStart + wi;
|
|
8996
|
-
return /* @__PURE__ */
|
|
9155
|
+
return /* @__PURE__ */ jsxs4(Text4, { color: i === pi ? theme.accentBright : void 0, bold: i === pi, children: [
|
|
8997
9156
|
(i === pi ? "\u25B8 " : " ") + truncate2(p.name, 26).padEnd(27),
|
|
8998
|
-
/* @__PURE__ */
|
|
9157
|
+
/* @__PURE__ */ jsxs4(Text4, { color: theme.dim, children: [
|
|
8999
9158
|
p.mode.padEnd(10),
|
|
9000
9159
|
" ",
|
|
9001
9160
|
p.rules.length,
|
|
9002
9161
|
" rules"
|
|
9003
9162
|
] }),
|
|
9004
|
-
p.id === activeId ? /* @__PURE__ */
|
|
9163
|
+
p.id === activeId ? /* @__PURE__ */ jsx4(Text4, { color: theme.ok, bold: true, children: " \u25CF ACTIVE" }) : null
|
|
9005
9164
|
] }, p.id);
|
|
9006
9165
|
}) }),
|
|
9007
|
-
status ? /* @__PURE__ */
|
|
9166
|
+
status ? /* @__PURE__ */ jsx4(Text4, { color: status.startsWith("\u2717") ? theme.bad : theme.ok, children: status }) : null
|
|
9008
9167
|
] }) });
|
|
9009
9168
|
}
|
|
9010
|
-
const dirtyTag = dirty ? /* @__PURE__ */
|
|
9169
|
+
const dirtyTag = dirty ? /* @__PURE__ */ jsx4(Text4, { color: theme.warn, children: " \u25CF unsaved (s save \xB7 x discard)" }) : null;
|
|
9011
9170
|
if (view === "rules") {
|
|
9012
9171
|
const rStatusLines = status ? status.split("\n").length : 0;
|
|
9013
9172
|
const rHead = 4 + rStatusLines;
|
|
@@ -9017,16 +9176,16 @@ function PoliciesPanel({ focused }) {
|
|
|
9017
9176
|
const rWin = rules.slice(rStart, rStart + rBudget);
|
|
9018
9177
|
const rAbove = rStart;
|
|
9019
9178
|
const rBelow = Math.max(0, rules.length - (rStart + rBudget));
|
|
9020
|
-
return /* @__PURE__ */
|
|
9021
|
-
/* @__PURE__ */
|
|
9022
|
-
/* @__PURE__ */
|
|
9023
|
-
/* @__PURE__ */
|
|
9024
|
-
/* @__PURE__ */
|
|
9025
|
-
/* @__PURE__ */
|
|
9179
|
+
return /* @__PURE__ */ jsx4(DataView, { loading: detail.loading && !detail.data, error: detail.error, children: /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", children: [
|
|
9180
|
+
/* @__PURE__ */ jsxs4(Box4, { children: [
|
|
9181
|
+
/* @__PURE__ */ jsx4(Text4, { bold: true, color: theme.accentBright, children: truncate2(selected?.name ?? "", 28) }),
|
|
9182
|
+
/* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: " mode: " }),
|
|
9183
|
+
/* @__PURE__ */ jsx4(Text4, { color: mode === "whitelist" ? theme.warn : void 0, children: mode }),
|
|
9184
|
+
/* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: ` ${rules.length} rules` }),
|
|
9026
9185
|
dirtyTag
|
|
9027
9186
|
] }),
|
|
9028
|
-
/* @__PURE__ */
|
|
9029
|
-
/* @__PURE__ */
|
|
9187
|
+
/* @__PURE__ */ jsx4(Text4, { color: theme.dim, wrap: "truncate", children: `\u2191\u2193 \xB7 enter edit \xB7 space on/off \xB7 e effect \xB7 n new \xB7 d del \xB7 m mode \xB7 D dry-run \xB7 s save \xB7 \u2190 back${rAbove ? ` \xB7 \u25B2${rAbove}` : ""}${rBelow ? ` \xB7 \u25BC${rBelow}` : ""}` }),
|
|
9188
|
+
/* @__PURE__ */ jsx4(Box4, { marginTop: 1, children: /* @__PURE__ */ jsx4(
|
|
9030
9189
|
Table,
|
|
9031
9190
|
{
|
|
9032
9191
|
columns: [
|
|
@@ -9052,24 +9211,24 @@ function PoliciesPanel({ focused }) {
|
|
|
9052
9211
|
})
|
|
9053
9212
|
}
|
|
9054
9213
|
) }),
|
|
9055
|
-
rules.length === 0 ? /* @__PURE__ */
|
|
9056
|
-
status ? /* @__PURE__ */
|
|
9214
|
+
rules.length === 0 ? /* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: "(no rules)" }) : null,
|
|
9215
|
+
status ? /* @__PURE__ */ jsx4(Text4, { color: status.startsWith("\u2717") ? theme.bad : theme.ok, children: status }) : null
|
|
9057
9216
|
] }) });
|
|
9058
9217
|
}
|
|
9059
9218
|
const rule = rules[ri];
|
|
9060
|
-
return /* @__PURE__ */
|
|
9061
|
-
/* @__PURE__ */
|
|
9062
|
-
/* @__PURE__ */
|
|
9063
|
-
/* @__PURE__ */
|
|
9219
|
+
return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", children: [
|
|
9220
|
+
/* @__PURE__ */ jsxs4(Box4, { children: [
|
|
9221
|
+
/* @__PURE__ */ jsx4(Text4, { bold: true, color: theme.accentBright, children: "Rule " }),
|
|
9222
|
+
/* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: rule?.id ?? "" }),
|
|
9064
9223
|
dirtyTag
|
|
9065
9224
|
] }),
|
|
9066
|
-
/* @__PURE__ */
|
|
9067
|
-
/* @__PURE__ */
|
|
9225
|
+
/* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: "\u2191\u2193 field \xB7 enter edit text \xB7 space/\u2192 toggle \xB7 s save \xB7 \u2190 back" }),
|
|
9226
|
+
/* @__PURE__ */ jsx4(Box4, { marginTop: 1, flexDirection: "column", children: FIELDS.map((f, i) => {
|
|
9068
9227
|
const val = rule ? f.get(rule) : "";
|
|
9069
9228
|
const active2 = i === fi;
|
|
9070
|
-
return /* @__PURE__ */
|
|
9071
|
-
/* @__PURE__ */
|
|
9072
|
-
active2 && editing && f.kind === "text" ? /* @__PURE__ */
|
|
9229
|
+
return /* @__PURE__ */ jsxs4(Box4, { children: [
|
|
9230
|
+
/* @__PURE__ */ jsx4(Text4, { color: active2 ? theme.accentBright : void 0, children: (active2 ? "\u25B8 " : " ") + f.label.padEnd(13) }),
|
|
9231
|
+
active2 && editing && f.kind === "text" ? /* @__PURE__ */ jsx4(
|
|
9073
9232
|
TextInput2,
|
|
9074
9233
|
{
|
|
9075
9234
|
value: editVal,
|
|
@@ -9079,8 +9238,8 @@ function PoliciesPanel({ focused }) {
|
|
|
9079
9238
|
setEditing(false);
|
|
9080
9239
|
}
|
|
9081
9240
|
}
|
|
9082
|
-
) : /* @__PURE__ */
|
|
9083
|
-
|
|
9241
|
+
) : /* @__PURE__ */ jsx4(
|
|
9242
|
+
Text4,
|
|
9084
9243
|
{
|
|
9085
9244
|
color: f.kind === "effect" ? val === "ALLOW" ? theme.ok : theme.bad : void 0,
|
|
9086
9245
|
dimColor: !val,
|
|
@@ -9089,19 +9248,18 @@ function PoliciesPanel({ focused }) {
|
|
|
9089
9248
|
)
|
|
9090
9249
|
] }, f.label);
|
|
9091
9250
|
}) }),
|
|
9092
|
-
status ? /* @__PURE__ */
|
|
9251
|
+
status ? /* @__PURE__ */ jsx4(Text4, { color: status.startsWith("\u2717") ? theme.bad : theme.ok, children: status }) : null
|
|
9093
9252
|
] });
|
|
9094
9253
|
}
|
|
9095
|
-
var
|
|
9254
|
+
var constr, setConstr, FIELDS;
|
|
9096
9255
|
var init_Policies = __esm({
|
|
9097
9256
|
"src/tui/panels/Policies.tsx"() {
|
|
9098
9257
|
"use strict";
|
|
9099
9258
|
init_api_client();
|
|
9100
|
-
|
|
9259
|
+
init_DryRun();
|
|
9101
9260
|
init_components();
|
|
9102
9261
|
init_hooks();
|
|
9103
9262
|
init_theme();
|
|
9104
|
-
DASHBOARD_URL = "https://dashboard.solongate.com";
|
|
9105
9263
|
constr = (r, g, side) => (r[g]?.[side] ?? []).join(", ");
|
|
9106
9264
|
setConstr = (r, g, side, val) => {
|
|
9107
9265
|
const arr = val.split(",").map((s) => s.trim()).filter(Boolean);
|
|
@@ -9127,19 +9285,19 @@ var init_Policies = __esm({
|
|
|
9127
9285
|
});
|
|
9128
9286
|
|
|
9129
9287
|
// src/tui/panels/RateLimit.tsx
|
|
9130
|
-
import { Box as
|
|
9131
|
-
import { useEffect as
|
|
9132
|
-
import { Fragment as Fragment4, jsx as
|
|
9288
|
+
import { Box as Box5, Text as Text5, useInput as useInput4 } from "ink";
|
|
9289
|
+
import { useEffect as useEffect5, useState as useState5 } from "react";
|
|
9290
|
+
import { Fragment as Fragment4, jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
9133
9291
|
function RateLimitPanel({ focused }) {
|
|
9134
9292
|
const { cols, rows } = usePanelSize();
|
|
9135
9293
|
const layersQ = useLoader(() => api.settings.getSecurityLayers());
|
|
9136
9294
|
const historyQ = useLoader(() => api.settings.getRateLimitHistory());
|
|
9137
9295
|
const insightsQ = useLoader(() => api.stats.securityInsights(7));
|
|
9138
|
-
const [draft, setDraft] =
|
|
9139
|
-
const [dirty, setDirty] =
|
|
9140
|
-
const [sel, setSel] =
|
|
9141
|
-
const [status, setStatus] =
|
|
9142
|
-
|
|
9296
|
+
const [draft, setDraft] = useState5(null);
|
|
9297
|
+
const [dirty, setDirty] = useState5(false);
|
|
9298
|
+
const [sel, setSel] = useState5(0);
|
|
9299
|
+
const [status, setStatus] = useState5(null);
|
|
9300
|
+
useEffect5(() => {
|
|
9143
9301
|
if (layersQ.data && !dirty) setDraft({ ...layersQ.data.layers.rateLimit });
|
|
9144
9302
|
}, [layersQ.data]);
|
|
9145
9303
|
usePoll(() => {
|
|
@@ -9187,7 +9345,7 @@ function RateLimitPanel({ focused }) {
|
|
|
9187
9345
|
const fi = onField ? selC : -1;
|
|
9188
9346
|
const bcur = onField ? -1 : selC - 4;
|
|
9189
9347
|
const off = bcur < 0 ? 0 : Math.min(Math.max(0, bcur - Math.floor(burstBudget / 2)), maxOff);
|
|
9190
|
-
|
|
9348
|
+
useInput4(
|
|
9191
9349
|
(input, key) => {
|
|
9192
9350
|
const step = key.shift ? 10 : 1;
|
|
9193
9351
|
if (key.upArrow) setSel((n) => Math.max(0, n - 1));
|
|
@@ -9206,48 +9364,48 @@ function RateLimitPanel({ focused }) {
|
|
|
9206
9364
|
},
|
|
9207
9365
|
{ isActive: focused }
|
|
9208
9366
|
);
|
|
9209
|
-
return /* @__PURE__ */
|
|
9367
|
+
return /* @__PURE__ */ jsx5(DataView, { loading: layersQ.loading && !draft, error: layersQ.error, children: draft ? (() => {
|
|
9210
9368
|
const lim = draft.perMinute;
|
|
9211
9369
|
const now = insightsQ.data ? insightsQ.data["activity"]?.minute?.slice(-1)[0]?.count ?? 0 : 0;
|
|
9212
9370
|
const loadPct = lim > 0 ? Math.min(100, Math.round(now / lim * 100)) : 0;
|
|
9213
9371
|
const last24h = (insightsQ.data?.["activity"]?.hour ?? []).reduce((s, b) => s + b.count, 0);
|
|
9214
9372
|
const shown = anomalies2.slice(off, off + burstBudget);
|
|
9215
9373
|
const bw = Math.max(10, cols - 30);
|
|
9216
|
-
return /* @__PURE__ */
|
|
9217
|
-
/* @__PURE__ */
|
|
9218
|
-
/* @__PURE__ */
|
|
9219
|
-
/* @__PURE__ */
|
|
9220
|
-
/* @__PURE__ */
|
|
9374
|
+
return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", height: rows, overflow: "hidden", children: [
|
|
9375
|
+
/* @__PURE__ */ jsx5(Text5, { color: theme.dim, wrap: "truncate", children: focused ? "\u2191\u2193 move (fields + bursts) \xB7 \u2190\u2192 \xB11 \xB7 shift+\u2190\u2192 \xB110 \xB7 s save \xB7 ^R refresh" : "press \u2192 to edit" }),
|
|
9376
|
+
/* @__PURE__ */ jsxs5(FieldRow, { label: "Mode", active: focused && fi === 0, children: [
|
|
9377
|
+
/* @__PURE__ */ jsx5(Text5, { color: modeColor(draft.mode), bold: true, children: draft.mode }),
|
|
9378
|
+
/* @__PURE__ */ jsx5(Text5, { color: theme.dim, children: draft.mode === "off" ? " no limit" : draft.mode === "detect" ? " flag bursts, never block" : " DENY calls over the limit" })
|
|
9221
9379
|
] }),
|
|
9222
|
-
/* @__PURE__ */
|
|
9223
|
-
/* @__PURE__ */
|
|
9224
|
-
/* @__PURE__ */
|
|
9225
|
-
showExtras && /* @__PURE__ */
|
|
9226
|
-
hasLoad ? /* @__PURE__ */
|
|
9227
|
-
/* @__PURE__ */
|
|
9228
|
-
/* @__PURE__ */
|
|
9229
|
-
/* @__PURE__ */
|
|
9230
|
-
/* @__PURE__ */
|
|
9380
|
+
/* @__PURE__ */ jsx5(FieldRow, { label: "Per minute", active: focused && fi === 1, children: /* @__PURE__ */ jsx5(Text5, { bold: true, children: draft.perMinute || "off" }) }),
|
|
9381
|
+
/* @__PURE__ */ jsx5(FieldRow, { label: "Per hour", active: focused && fi === 2, children: /* @__PURE__ */ jsx5(Text5, { bold: true, children: draft.perHour || "off" }) }),
|
|
9382
|
+
/* @__PURE__ */ jsx5(FieldRow, { label: "Per day", active: focused && fi === 3, children: /* @__PURE__ */ jsx5(Text5, { bold: true, children: draft.perDay || "off" }) }),
|
|
9383
|
+
showExtras && /* @__PURE__ */ jsxs5(Fragment4, { children: [
|
|
9384
|
+
hasLoad ? /* @__PURE__ */ jsxs5(Text5, { wrap: "truncate", children: [
|
|
9385
|
+
/* @__PURE__ */ jsx5(Text5, { color: theme.dim, children: "load now".padEnd(13) }),
|
|
9386
|
+
/* @__PURE__ */ jsx5(Text5, { color: loadPct >= 100 ? theme.bad : loadPct >= 80 ? theme.warn : theme.ok, children: "\u2588".repeat(Math.min(18, Math.round(now / lim * 18))) }),
|
|
9387
|
+
/* @__PURE__ */ jsx5(Text5, { color: "#233457", children: "\u2591".repeat(Math.max(0, 18 - Math.round(now / lim * 18))) }),
|
|
9388
|
+
/* @__PURE__ */ jsx5(Text5, { color: theme.dim, children: ` ${now}/${lim} this minute (${loadPct}%)` })
|
|
9231
9389
|
] }) : null,
|
|
9232
|
-
/* @__PURE__ */
|
|
9390
|
+
/* @__PURE__ */ jsxs5(Text5, { color: theme.accentBright, bold: true, wrap: "truncate", children: [
|
|
9233
9391
|
"Busiest 7d",
|
|
9234
|
-
/* @__PURE__ */
|
|
9392
|
+
/* @__PURE__ */ jsx5(Text5, { color: theme.dim, children: " most calls in one window vs your limit" })
|
|
9235
9393
|
] }),
|
|
9236
|
-
/* @__PURE__ */
|
|
9237
|
-
/* @__PURE__ */
|
|
9238
|
-
/* @__PURE__ */
|
|
9239
|
-
/* @__PURE__ */
|
|
9394
|
+
/* @__PURE__ */ jsx5(BusiestRow, { label: "minute", peak: peaks.minute, limit: draft.perMinute }),
|
|
9395
|
+
/* @__PURE__ */ jsx5(BusiestRow, { label: "hour", peak: peaks.hour, limit: draft.perHour }),
|
|
9396
|
+
/* @__PURE__ */ jsx5(BusiestRow, { label: "day", peak: peaks.day, limit: draft.perDay }),
|
|
9397
|
+
/* @__PURE__ */ jsx5(Text5, { color: theme.dim, wrap: "truncate", children: `activity`.padEnd(11) + ` last 24h \xB7 ${last24h} calls \xB7 busiest hour ${peaks.hour}/hr` })
|
|
9240
9398
|
] }),
|
|
9241
|
-
/* @__PURE__ */
|
|
9242
|
-
/* @__PURE__ */
|
|
9399
|
+
/* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", children: [
|
|
9400
|
+
/* @__PURE__ */ jsxs5(Text5, { color: theme.accentBright, bold: true, wrap: "truncate", children: [
|
|
9243
9401
|
`Recent bursts 7d${anomalies2.length ? ` (${anomalies2.length})` : ""}`,
|
|
9244
|
-
maxOff > 0 ? /* @__PURE__ */
|
|
9245
|
-
/* @__PURE__ */
|
|
9402
|
+
maxOff > 0 ? /* @__PURE__ */ jsx5(Text5, { color: theme.warn, children: ` ${off + 1}-${Math.min(off + burstBudget, anomalies2.length)}/${anomalies2.length}` }) : null,
|
|
9403
|
+
/* @__PURE__ */ jsx5(Text5, { color: theme.dim, children: " over the per-minute limit \xB7 Bypassed = detect (not blocked)" })
|
|
9246
9404
|
] }),
|
|
9247
|
-
anomalies2.length === 0 ? /* @__PURE__ */
|
|
9405
|
+
anomalies2.length === 0 ? /* @__PURE__ */ jsxs5(Text5, { color: theme.dim, children: [
|
|
9248
9406
|
" ",
|
|
9249
9407
|
insightsQ.loading ? "loading\u2026" : insightsQ.error ? `couldn't load bursts: ${String(insightsQ.error).slice(0, 60)}` : "no bursts in the last 7 days"
|
|
9250
|
-
] }) : /* @__PURE__ */
|
|
9408
|
+
] }) : /* @__PURE__ */ jsx5(
|
|
9251
9409
|
Table,
|
|
9252
9410
|
{
|
|
9253
9411
|
columns: [{ header: "WHEN", width: 15 }, { header: "RESULT", width: 9 }, { header: "CALLS", width: 7 }, { header: "AGENT", width: Math.max(8, bw - 31) }],
|
|
@@ -9263,13 +9421,13 @@ function RateLimitPanel({ focused }) {
|
|
|
9263
9421
|
}
|
|
9264
9422
|
)
|
|
9265
9423
|
] }),
|
|
9266
|
-
/* @__PURE__ */
|
|
9267
|
-
/* @__PURE__ */
|
|
9268
|
-
/* @__PURE__ */
|
|
9269
|
-
/* @__PURE__ */
|
|
9270
|
-
lastChange ? /* @__PURE__ */
|
|
9271
|
-
dirty ? /* @__PURE__ */
|
|
9272
|
-
status ? /* @__PURE__ */
|
|
9424
|
+
/* @__PURE__ */ jsx5(Text5, { children: " " }),
|
|
9425
|
+
/* @__PURE__ */ jsxs5(Text5, { wrap: "truncate", children: [
|
|
9426
|
+
/* @__PURE__ */ jsx5(Text5, { color: theme.dim, children: "limit now " }),
|
|
9427
|
+
/* @__PURE__ */ jsx5(Text5, { children: lim > 0 ? `${lim}/min` : "no per-minute limit" }),
|
|
9428
|
+
lastChange ? /* @__PURE__ */ jsx5(Text5, { color: theme.dim, children: ` \xB7 changed ${when(lastChange.ts)}` }) : null,
|
|
9429
|
+
dirty ? /* @__PURE__ */ jsx5(Text5, { color: theme.warn, children: " \u25CF unsaved (s)" }) : null,
|
|
9430
|
+
status ? /* @__PURE__ */ jsx5(Text5, { color: status.startsWith("\u2717") ? theme.bad : theme.ok, children: " " + status }) : null
|
|
9273
9431
|
] })
|
|
9274
9432
|
] });
|
|
9275
9433
|
})() : null });
|
|
@@ -9277,15 +9435,15 @@ function RateLimitPanel({ focused }) {
|
|
|
9277
9435
|
function BusiestRow({ label, peak, limit }) {
|
|
9278
9436
|
const ctx = limit > 0 ? peak > limit ? `over ${limit}` : peak === limit ? `at limit ${limit}` : `limit ${limit}` : "no limit set";
|
|
9279
9437
|
const hot = limit > 0 && peak > limit;
|
|
9280
|
-
return /* @__PURE__ */
|
|
9281
|
-
/* @__PURE__ */
|
|
9282
|
-
/* @__PURE__ */
|
|
9283
|
-
/* @__PURE__ */
|
|
9438
|
+
return /* @__PURE__ */ jsxs5(Text5, { wrap: "truncate", children: [
|
|
9439
|
+
/* @__PURE__ */ jsx5(Text5, { color: theme.dim, children: (" " + label).padEnd(11) }),
|
|
9440
|
+
/* @__PURE__ */ jsx5(Text5, { color: hot ? theme.bad : void 0, bold: hot, children: String(peak).padStart(4) + " calls" }),
|
|
9441
|
+
/* @__PURE__ */ jsx5(Text5, { color: hot ? theme.bad : theme.dim, children: " \xB7 " + ctx })
|
|
9284
9442
|
] });
|
|
9285
9443
|
}
|
|
9286
9444
|
function FieldRow({ label, active: active2, children }) {
|
|
9287
|
-
return /* @__PURE__ */
|
|
9288
|
-
/* @__PURE__ */
|
|
9445
|
+
return /* @__PURE__ */ jsxs5(Text5, { wrap: "truncate", children: [
|
|
9446
|
+
/* @__PURE__ */ jsx5(Text5, { color: active2 ? theme.accentBright : void 0, children: (active2 ? "\u25B8 " : " ") + label.padEnd(11) }),
|
|
9289
9447
|
children
|
|
9290
9448
|
] });
|
|
9291
9449
|
}
|
|
@@ -9307,24 +9465,24 @@ var init_RateLimit = __esm({
|
|
|
9307
9465
|
});
|
|
9308
9466
|
|
|
9309
9467
|
// src/tui/panels/Dlp.tsx
|
|
9310
|
-
import { Box as
|
|
9468
|
+
import { Box as Box6, Text as Text6, useInput as useInput5 } from "ink";
|
|
9311
9469
|
import TextInput3 from "ink-text-input";
|
|
9312
|
-
import { useEffect as
|
|
9313
|
-
import { jsx as
|
|
9470
|
+
import { useEffect as useEffect6, useState as useState6 } from "react";
|
|
9471
|
+
import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
9314
9472
|
function DlpPanel({ focused }) {
|
|
9315
9473
|
const { cols, rows } = usePanelSize();
|
|
9316
9474
|
const q = useLoader(() => api.settings.getSecurityLayers());
|
|
9317
|
-
const [dlp, setDlp] =
|
|
9318
|
-
const [available, setAvailable] =
|
|
9319
|
-
const [ghostOn, setGhostOn] =
|
|
9320
|
-
const [ghostPats, setGhostPats] =
|
|
9321
|
-
const [sel, setSel] =
|
|
9322
|
-
const [dirty, setDirty] =
|
|
9323
|
-
const [status, setStatus] =
|
|
9324
|
-
const [adding, setAdding] =
|
|
9325
|
-
const [newName, setNewName] =
|
|
9326
|
-
const [input, setInput] =
|
|
9327
|
-
|
|
9475
|
+
const [dlp, setDlp] = useState6(null);
|
|
9476
|
+
const [available, setAvailable] = useState6([]);
|
|
9477
|
+
const [ghostOn, setGhostOn] = useState6(false);
|
|
9478
|
+
const [ghostPats, setGhostPats] = useState6([]);
|
|
9479
|
+
const [sel, setSel] = useState6(0);
|
|
9480
|
+
const [dirty, setDirty] = useState6(false);
|
|
9481
|
+
const [status, setStatus] = useState6(null);
|
|
9482
|
+
const [adding, setAdding] = useState6(null);
|
|
9483
|
+
const [newName, setNewName] = useState6("");
|
|
9484
|
+
const [input, setInput] = useState6("");
|
|
9485
|
+
useEffect6(() => {
|
|
9328
9486
|
if (q.data && !dirty) {
|
|
9329
9487
|
setDlp({ ...q.data.layers.dlp, patterns: [...q.data.layers.dlp.patterns], custom: [...q.data.layers.dlp.custom] });
|
|
9330
9488
|
setAvailable(q.data.availablePatterns);
|
|
@@ -9371,7 +9529,7 @@ function DlpPanel({ focused }) {
|
|
|
9371
9529
|
];
|
|
9372
9530
|
const selC = Math.min(sel, Math.max(0, entries.length - 1));
|
|
9373
9531
|
const cur = entries[selC];
|
|
9374
|
-
|
|
9532
|
+
useInput5(
|
|
9375
9533
|
(input2, key) => {
|
|
9376
9534
|
if (!dlp) return;
|
|
9377
9535
|
if (key.ctrl && input2 === "r") {
|
|
@@ -9416,13 +9574,13 @@ function DlpPanel({ focused }) {
|
|
|
9416
9574
|
const enabled = new Set(dlp?.patterns ?? []);
|
|
9417
9575
|
const lines = [];
|
|
9418
9576
|
const header = (key, label, extra) => lines.push({
|
|
9419
|
-
node: /* @__PURE__ */
|
|
9420
|
-
/* @__PURE__ */
|
|
9421
|
-
extra ? /* @__PURE__ */
|
|
9577
|
+
node: /* @__PURE__ */ jsxs6(Text6, { wrap: "truncate", children: [
|
|
9578
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.accentBright, bold: true, children: label }),
|
|
9579
|
+
extra ? /* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: " " + extra }) : null
|
|
9422
9580
|
] }, key),
|
|
9423
9581
|
entry: -1
|
|
9424
9582
|
});
|
|
9425
|
-
const note = (key, text) => lines.push({ node: /* @__PURE__ */
|
|
9583
|
+
const note = (key, text) => lines.push({ node: /* @__PURE__ */ jsx6(Text6, { color: theme.dim, wrap: "truncate", children: text }, key), entry: -1 });
|
|
9426
9584
|
let ei = 0;
|
|
9427
9585
|
header("h:builtin", "built-in secret patterns", "space toggles on/off");
|
|
9428
9586
|
available.forEach((p) => {
|
|
@@ -9430,10 +9588,10 @@ function DlpPanel({ focused }) {
|
|
|
9430
9588
|
const isCur = focused && ei === selC;
|
|
9431
9589
|
const idx = ei++;
|
|
9432
9590
|
lines.push({
|
|
9433
|
-
node: /* @__PURE__ */
|
|
9434
|
-
/* @__PURE__ */
|
|
9435
|
-
/* @__PURE__ */
|
|
9436
|
-
/* @__PURE__ */
|
|
9591
|
+
node: /* @__PURE__ */ jsxs6(Text6, { wrap: "truncate", backgroundColor: isCur ? "#1c2f63" : void 0, bold: isCur, children: [
|
|
9592
|
+
/* @__PURE__ */ jsx6(Text6, { color: isCur ? theme.accentBright : theme.dim, children: isCur ? "\u25B8 " : " " }),
|
|
9593
|
+
/* @__PURE__ */ jsx6(Text6, { color: on ? theme.ok : theme.dim, children: on ? "\u25CF " : "\u25CB " }),
|
|
9594
|
+
/* @__PURE__ */ jsx6(Text6, { color: on ? void 0 : theme.dim, children: p })
|
|
9437
9595
|
] }, "b:" + p),
|
|
9438
9596
|
entry: idx
|
|
9439
9597
|
});
|
|
@@ -9445,10 +9603,10 @@ function DlpPanel({ focused }) {
|
|
|
9445
9603
|
const isCur = focused && ei === selC;
|
|
9446
9604
|
const idx = ei++;
|
|
9447
9605
|
lines.push({
|
|
9448
|
-
node: /* @__PURE__ */
|
|
9449
|
-
/* @__PURE__ */
|
|
9450
|
-
/* @__PURE__ */
|
|
9451
|
-
/* @__PURE__ */
|
|
9606
|
+
node: /* @__PURE__ */ jsxs6(Text6, { wrap: "truncate", backgroundColor: isCur ? "#1c2f63" : void 0, bold: isCur, children: [
|
|
9607
|
+
/* @__PURE__ */ jsx6(Text6, { color: isCur ? theme.accentBright : theme.dim, children: isCur ? "\u25B8 " : " " }),
|
|
9608
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.accent, children: c2.name }),
|
|
9609
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: " " + truncate2(c2.re, Math.max(10, cols - c2.name.length - 8)) })
|
|
9452
9610
|
] }, "c:" + c2.name + i),
|
|
9453
9611
|
entry: idx
|
|
9454
9612
|
});
|
|
@@ -9460,10 +9618,10 @@ function DlpPanel({ focused }) {
|
|
|
9460
9618
|
const isCur = focused && ei === selC;
|
|
9461
9619
|
const idx = ei++;
|
|
9462
9620
|
lines.push({
|
|
9463
|
-
node: /* @__PURE__ */
|
|
9464
|
-
/* @__PURE__ */
|
|
9465
|
-
/* @__PURE__ */
|
|
9466
|
-
!ghostOn ? /* @__PURE__ */
|
|
9621
|
+
node: /* @__PURE__ */ jsxs6(Text6, { wrap: "truncate", backgroundColor: isCur ? "#1c2f63" : void 0, bold: isCur, children: [
|
|
9622
|
+
/* @__PURE__ */ jsx6(Text6, { color: isCur ? theme.accentBright : theme.dim, children: isCur ? "\u25B8 " : " " }),
|
|
9623
|
+
/* @__PURE__ */ jsx6(Text6, { color: ghostOn ? theme.accent : theme.dim, children: truncate2(p, Math.max(10, cols - 6)) }),
|
|
9624
|
+
!ghostOn ? /* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: " (ghost off)" }) : null
|
|
9467
9625
|
] }, "g:" + p + i),
|
|
9468
9626
|
entry: idx
|
|
9469
9627
|
});
|
|
@@ -9477,17 +9635,17 @@ function DlpPanel({ focused }) {
|
|
|
9477
9635
|
const win = lines.slice(start, start + budget);
|
|
9478
9636
|
const moreAbove = start;
|
|
9479
9637
|
const moreBelow = Math.max(0, lines.length - (start + budget));
|
|
9480
|
-
return /* @__PURE__ */
|
|
9481
|
-
/* @__PURE__ */
|
|
9482
|
-
/* @__PURE__ */
|
|
9483
|
-
/* @__PURE__ */
|
|
9484
|
-
/* @__PURE__ */
|
|
9485
|
-
dirty ? /* @__PURE__ */
|
|
9638
|
+
return /* @__PURE__ */ jsx6(DataView, { loading: q.loading && !dlp, error: q.error, children: dlp ? /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
|
|
9639
|
+
/* @__PURE__ */ jsxs6(Text6, { wrap: "truncate", children: [
|
|
9640
|
+
/* @__PURE__ */ jsx6(Text6, { children: "mode: " }),
|
|
9641
|
+
/* @__PURE__ */ jsx6(Text6, { color: modeColor(dlp.mode), bold: true, children: dlp.mode }),
|
|
9642
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: dlp.mode === "off" ? " (scanning disabled)" : dlp.mode === "detect" ? " (flag dlp:yes, redact output)" : " (deny + redact secrets)" }),
|
|
9643
|
+
dirty ? /* @__PURE__ */ jsx6(Text6, { color: theme.warn, children: " \u25CF unsaved (s save \xB7 x discard)" }) : null
|
|
9486
9644
|
] }),
|
|
9487
|
-
/* @__PURE__ */
|
|
9488
|
-
adding ? /* @__PURE__ */
|
|
9489
|
-
/* @__PURE__ */
|
|
9490
|
-
/* @__PURE__ */
|
|
9645
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, wrap: "truncate", children: focused ? `\u2191\u2193 move \xB7 space on/off \xB7 m mode \xB7 a add pattern \xB7 r add route \xB7 d remove \xB7 g ghost \xB7 s save \xB7 ^R refresh${moreAbove ? ` \xB7 \u25B2${moreAbove}` : ""}${moreBelow ? ` \xB7 \u25BC${moreBelow}` : ""}` : "press \u2192 to edit" }),
|
|
9646
|
+
adding ? /* @__PURE__ */ jsx6(Box6, { flexDirection: "column", children: /* @__PURE__ */ jsxs6(Box6, { children: [
|
|
9647
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.warn, children: adding === "name" ? "new pattern name: " : adding === "re" ? `pattern for "${newName}" (glob, * = any chars, e.g. sk-* AKIA*): ` : "ghost path to hide (glob, * = any chars, e.g. */.env *.pem): " }),
|
|
9648
|
+
/* @__PURE__ */ jsx6(
|
|
9491
9649
|
TextInput3,
|
|
9492
9650
|
{
|
|
9493
9651
|
value: input,
|
|
@@ -9514,8 +9672,8 @@ function DlpPanel({ focused }) {
|
|
|
9514
9672
|
}
|
|
9515
9673
|
)
|
|
9516
9674
|
] }) }) : null,
|
|
9517
|
-
/* @__PURE__ */
|
|
9518
|
-
status ? /* @__PURE__ */
|
|
9675
|
+
/* @__PURE__ */ jsx6(Box6, { marginTop: 1, flexDirection: "column", height: budget, overflow: "hidden", children: win.map((l) => l.node) }),
|
|
9676
|
+
status ? /* @__PURE__ */ jsx6(Text6, { color: status.startsWith("\u2717") ? theme.bad : theme.ok, wrap: "truncate", children: status }) : null
|
|
9519
9677
|
] }) : null });
|
|
9520
9678
|
}
|
|
9521
9679
|
var MODES2;
|
|
@@ -9531,13 +9689,13 @@ var init_Dlp = __esm({
|
|
|
9531
9689
|
});
|
|
9532
9690
|
|
|
9533
9691
|
// src/tui/panels/Audit.tsx
|
|
9534
|
-
import { Box as
|
|
9692
|
+
import { Box as Box7, Text as Text7, useInput as useInput6 } from "ink";
|
|
9535
9693
|
import TextInput4 from "ink-text-input";
|
|
9536
9694
|
import { mkdirSync as mkdirSync7, writeFileSync as writeFileSync8 } from "fs";
|
|
9537
9695
|
import { homedir as homedir8 } from "os";
|
|
9538
9696
|
import { join as join10 } from "path";
|
|
9539
|
-
import { useState as
|
|
9540
|
-
import { jsx as
|
|
9697
|
+
import { useState as useState7 } from "react";
|
|
9698
|
+
import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
9541
9699
|
function loadLocalRows() {
|
|
9542
9700
|
return parseLocalLines(tailLines(LOCAL_LOG, LOCAL_MAX_BYTES)).map((j, i) => {
|
|
9543
9701
|
const rs = reasonSignals(j.reason);
|
|
@@ -9562,25 +9720,25 @@ function loadLocalRows() {
|
|
|
9562
9720
|
}
|
|
9563
9721
|
function AuditPanel({ active: active2, focused }) {
|
|
9564
9722
|
const { cols, rows } = usePanelSize();
|
|
9565
|
-
const [source, setSource] =
|
|
9566
|
-
const [view, setView] =
|
|
9567
|
-
const [di, setDi] =
|
|
9568
|
-
const [gi, setGi] =
|
|
9569
|
-
const [tool, setTool] =
|
|
9570
|
-
const [agent, setAgent] =
|
|
9571
|
-
const [search, setSearch] =
|
|
9572
|
-
const [sessFilter, setSessFilter] =
|
|
9573
|
-
const [page, setPage] =
|
|
9574
|
-
const [sel, setSel] =
|
|
9575
|
-
const [detailScroll, setDetailScroll] =
|
|
9576
|
-
const [editing, setEditing] =
|
|
9577
|
-
const [si, setSi] =
|
|
9578
|
-
const [sessSearch, setSessSearch] =
|
|
9579
|
-
const [sessSel, setSessSel] =
|
|
9580
|
-
const [confirm, setConfirm] =
|
|
9581
|
-
const [msg, setMsg] =
|
|
9582
|
-
const [showHelp, setShowHelp] =
|
|
9583
|
-
const [frozen, setFrozen] =
|
|
9723
|
+
const [source, setSource] = useState7("cloud");
|
|
9724
|
+
const [view, setView] = useState7("logs");
|
|
9725
|
+
const [di, setDi] = useState7(0);
|
|
9726
|
+
const [gi, setGi] = useState7(0);
|
|
9727
|
+
const [tool, setTool] = useState7("");
|
|
9728
|
+
const [agent, setAgent] = useState7("");
|
|
9729
|
+
const [search, setSearch] = useState7("");
|
|
9730
|
+
const [sessFilter, setSessFilter] = useState7("");
|
|
9731
|
+
const [page, setPage] = useState7(0);
|
|
9732
|
+
const [sel, setSel] = useState7(0);
|
|
9733
|
+
const [detailScroll, setDetailScroll] = useState7(0);
|
|
9734
|
+
const [editing, setEditing] = useState7(null);
|
|
9735
|
+
const [si, setSi] = useState7(0);
|
|
9736
|
+
const [sessSearch, setSessSearch] = useState7("");
|
|
9737
|
+
const [sessSel, setSessSel] = useState7(0);
|
|
9738
|
+
const [confirm, setConfirm] = useState7(null);
|
|
9739
|
+
const [msg, setMsg] = useState7(null);
|
|
9740
|
+
const [showHelp, setShowHelp] = useState7(false);
|
|
9741
|
+
const [frozen, setFrozen] = useState7(false);
|
|
9584
9742
|
const toTop = () => setSel(0);
|
|
9585
9743
|
const statsQ = useLoader(() => source === "cloud" ? api.stats.get() : Promise.resolve(null), [source]);
|
|
9586
9744
|
usePoll(statsQ.reloadQuiet, 15e3, active2 && source === "cloud" && !frozen);
|
|
@@ -9699,7 +9857,7 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
9699
9857
|
};
|
|
9700
9858
|
run10().then(({ n, file }) => setMsg({ text: `\u2713 exported ${n} rows \u2192 ${file}`, level: "ok" })).catch((e) => setMsg({ text: "\u2717 export failed: " + (e instanceof Error ? e.message : String(e)), level: "bad" }));
|
|
9701
9859
|
};
|
|
9702
|
-
|
|
9860
|
+
useInput6(
|
|
9703
9861
|
(input, key) => {
|
|
9704
9862
|
if (input === " ") {
|
|
9705
9863
|
setFrozen((f) => !f);
|
|
@@ -9833,58 +9991,58 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
9833
9991
|
{ isActive: focused && !editing }
|
|
9834
9992
|
);
|
|
9835
9993
|
const localAll = localQ.data ?? [];
|
|
9836
|
-
const strip = source === "cloud" ? /* @__PURE__ */
|
|
9837
|
-
/* @__PURE__ */
|
|
9838
|
-
/* @__PURE__ */
|
|
9839
|
-
/* @__PURE__ */
|
|
9994
|
+
const strip = source === "cloud" ? /* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
|
|
9995
|
+
/* @__PURE__ */ jsx7(Text7, { bold: true, children: statsQ.data ? statsQ.data.total_calls : "\xB7\xB7\xB7\xB7" }),
|
|
9996
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: " calls \xB7 " }),
|
|
9997
|
+
/* @__PURE__ */ jsxs7(Text7, { color: theme.ok, children: [
|
|
9840
9998
|
statsQ.data?.allowed ?? "\xB7\xB7\xB7",
|
|
9841
9999
|
" allow"
|
|
9842
10000
|
] }),
|
|
9843
|
-
/* @__PURE__ */
|
|
9844
|
-
/* @__PURE__ */
|
|
10001
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: " \xB7 " }),
|
|
10002
|
+
/* @__PURE__ */ jsxs7(Text7, { color: theme.bad, children: [
|
|
9845
10003
|
statsQ.data?.denied ?? "\xB7\xB7",
|
|
9846
10004
|
" deny"
|
|
9847
10005
|
] }),
|
|
9848
|
-
/* @__PURE__ */
|
|
9849
|
-
] }) : /* @__PURE__ */
|
|
9850
|
-
/* @__PURE__ */
|
|
9851
|
-
/* @__PURE__ */
|
|
9852
|
-
/* @__PURE__ */
|
|
10006
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: ` \xB7 ${statsQ.data?.active_policies ?? "\xB7"} policies` })
|
|
10007
|
+
] }) : /* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
|
|
10008
|
+
/* @__PURE__ */ jsx7(Text7, { bold: true, children: localAll.length }),
|
|
10009
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: " calls in local file \xB7 " }),
|
|
10010
|
+
/* @__PURE__ */ jsxs7(Text7, { color: theme.ok, children: [
|
|
9853
10011
|
localAll.filter((r) => r.decision === "ALLOW").length,
|
|
9854
10012
|
" allow"
|
|
9855
10013
|
] }),
|
|
9856
|
-
/* @__PURE__ */
|
|
9857
|
-
/* @__PURE__ */
|
|
10014
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: " \xB7 " }),
|
|
10015
|
+
/* @__PURE__ */ jsxs7(Text7, { color: theme.bad, children: [
|
|
9858
10016
|
localAll.filter((r) => r.decision !== "ALLOW").length,
|
|
9859
10017
|
" deny"
|
|
9860
10018
|
] }),
|
|
9861
|
-
/* @__PURE__ */
|
|
10019
|
+
/* @__PURE__ */ jsxs7(Text7, { color: theme.dim, children: [
|
|
9862
10020
|
" \xB7 ",
|
|
9863
10021
|
LOCAL_LOG
|
|
9864
10022
|
] })
|
|
9865
10023
|
] });
|
|
9866
|
-
const copyBanner = frozen ? /* @__PURE__ */
|
|
9867
|
-
const srcChip = /* @__PURE__ */
|
|
9868
|
-
/* @__PURE__ */
|
|
9869
|
-
/* @__PURE__ */
|
|
9870
|
-
/* @__PURE__ */
|
|
10024
|
+
const copyBanner = frozen ? /* @__PURE__ */ jsx7(Text7, { backgroundColor: "#123d1f", color: "#7bd88f", bold: true, wrap: "truncate", children: " \u23F5 COPY MODE \u2014 screen frozen, select & copy freely \xB7 space resume " }) : null;
|
|
10025
|
+
const srcChip = /* @__PURE__ */ jsxs7(Text7, { children: [
|
|
10026
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "src:" }),
|
|
10027
|
+
/* @__PURE__ */ jsx7(Text7, { color: source === "local" ? theme.ok : "#4f6db8", bold: true, children: source }),
|
|
10028
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: " (s) " })
|
|
9871
10029
|
] });
|
|
9872
10030
|
if (showHelp) {
|
|
9873
|
-
const colOf = (groups) => /* @__PURE__ */
|
|
9874
|
-
/* @__PURE__ */
|
|
9875
|
-
keys.map(([k, desc]) => /* @__PURE__ */
|
|
9876
|
-
/* @__PURE__ */
|
|
9877
|
-
/* @__PURE__ */
|
|
10031
|
+
const colOf = (groups) => /* @__PURE__ */ jsx7(Box7, { flexDirection: "column", width: "50%", paddingRight: 2, children: groups.map(([group, keys]) => /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", marginBottom: 1, children: [
|
|
10032
|
+
/* @__PURE__ */ jsx7(Text7, { bold: true, color: theme.accent, children: group }),
|
|
10033
|
+
keys.map(([k, desc]) => /* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
|
|
10034
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.accentBright, children: (" " + k).padEnd(19) }),
|
|
10035
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: desc })
|
|
9878
10036
|
] }, k))
|
|
9879
10037
|
] }, group)) });
|
|
9880
|
-
return /* @__PURE__ */
|
|
10038
|
+
return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
|
|
9881
10039
|
copyBanner,
|
|
9882
|
-
/* @__PURE__ */
|
|
10040
|
+
/* @__PURE__ */ jsxs7(Text7, { bold: true, color: theme.accentBright, children: [
|
|
9883
10041
|
"AUDIT \u2014 all keys",
|
|
9884
10042
|
" ",
|
|
9885
|
-
/* @__PURE__ */
|
|
10043
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: frozen ? "\xB7 screen frozen \u2014 space resumes, other keys are locked" : "\xB7 press any key to close \xB7 space = copy mode (works here too)" })
|
|
9886
10044
|
] }),
|
|
9887
|
-
/* @__PURE__ */
|
|
10045
|
+
/* @__PURE__ */ jsxs7(Box7, { marginTop: 1, children: [
|
|
9888
10046
|
colOf(AUDIT_HELP.slice(0, 1)),
|
|
9889
10047
|
colOf(AUDIT_HELP.slice(1))
|
|
9890
10048
|
] })
|
|
@@ -9903,53 +10061,53 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
9903
10061
|
const maxScroll = Math.max(0, contentLines.length - bodyRows);
|
|
9904
10062
|
const off = Math.min(detailScroll, maxScroll);
|
|
9905
10063
|
const win = contentLines.slice(off, off + bodyRows);
|
|
9906
|
-
return /* @__PURE__ */
|
|
10064
|
+
return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
|
|
9907
10065
|
copyBanner,
|
|
9908
|
-
/* @__PURE__ */
|
|
9909
|
-
/* @__PURE__ */
|
|
9910
|
-
/* @__PURE__ */
|
|
9911
|
-
/* @__PURE__ */
|
|
9912
|
-
/* @__PURE__ */
|
|
9913
|
-
e.dlp.length ? /* @__PURE__ */
|
|
9914
|
-
e.burst ? /* @__PURE__ */
|
|
9915
|
-
/* @__PURE__ */
|
|
10066
|
+
/* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
|
|
10067
|
+
/* @__PURE__ */ jsx7(Text7, { backgroundColor: BG2, color: "white", bold: true, children: " ENTRY " }),
|
|
10068
|
+
/* @__PURE__ */ jsx7(Text7, { color: decisionColor(e.decision), bold: true, children: " " + e.decision }),
|
|
10069
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.accent, bold: true, children: " " + e.tool }),
|
|
10070
|
+
/* @__PURE__ */ jsx7(Text7, { color: loc ? theme.ok : "white", children: " " + (loc ? "LOC" : "CLD") }),
|
|
10071
|
+
e.dlp.length ? /* @__PURE__ */ jsx7(Text7, { color: theme.bad, children: " DLP!" }) : null,
|
|
10072
|
+
e.burst ? /* @__PURE__ */ jsx7(Text7, { color: theme.warn, children: " BURST" }) : null,
|
|
10073
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: " \u2190 back" })
|
|
9916
10074
|
] }),
|
|
9917
|
-
/* @__PURE__ */
|
|
9918
|
-
/* @__PURE__ */
|
|
9919
|
-
/* @__PURE__ */
|
|
9920
|
-
/* @__PURE__ */
|
|
9921
|
-
/* @__PURE__ */
|
|
9922
|
-
/* @__PURE__ */
|
|
9923
|
-
/* @__PURE__ */
|
|
9924
|
-
/* @__PURE__ */
|
|
9925
|
-
/* @__PURE__ */
|
|
9926
|
-
/* @__PURE__ */
|
|
9927
|
-
/* @__PURE__ */
|
|
9928
|
-
/* @__PURE__ */
|
|
10075
|
+
/* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
|
|
10076
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "\u2502 when " }),
|
|
10077
|
+
/* @__PURE__ */ jsx7(Text7, { children: new Date(e.at).toLocaleString() }),
|
|
10078
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: " \u2502 perm " }),
|
|
10079
|
+
/* @__PURE__ */ jsx7(Text7, { children: e.permission || "\u2014" }),
|
|
10080
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: " \u2502 trust " }),
|
|
10081
|
+
/* @__PURE__ */ jsx7(Text7, { children: e.trust || "\u2014" }),
|
|
10082
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: " \u2502 eval " }),
|
|
10083
|
+
/* @__PURE__ */ jsx7(Text7, { color: e.evalMs != null && e.evalMs > 500 ? theme.warn : void 0, children: e.evalMs != null ? `${e.evalMs}ms` : "\u2014" }),
|
|
10084
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: " \u2502 agent " }),
|
|
10085
|
+
/* @__PURE__ */ jsx7(Text7, { children: e.agent ?? "\u2014" }),
|
|
10086
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: " \u2502" })
|
|
9929
10087
|
] }),
|
|
9930
|
-
/* @__PURE__ */
|
|
9931
|
-
/* @__PURE__ */
|
|
9932
|
-
/* @__PURE__ */
|
|
9933
|
-
/* @__PURE__ */
|
|
9934
|
-
/* @__PURE__ */
|
|
9935
|
-
/* @__PURE__ */
|
|
10088
|
+
/* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
|
|
10089
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "\u2502 session " }),
|
|
10090
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: e.session ?? "\u2014" }),
|
|
10091
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: " \u2502 rule " }),
|
|
10092
|
+
/* @__PURE__ */ jsx7(Text7, { color: e.rule && e.decision !== "ALLOW" ? theme.bad : theme.dim, children: e.rule ?? "\u2014" }),
|
|
10093
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: " \u2502" })
|
|
9936
10094
|
] }),
|
|
9937
|
-
/* @__PURE__ */
|
|
9938
|
-
/* @__PURE__ */
|
|
9939
|
-
/* @__PURE__ */
|
|
9940
|
-
/* @__PURE__ */
|
|
9941
|
-
/* @__PURE__ */
|
|
9942
|
-
/* @__PURE__ */
|
|
10095
|
+
/* @__PURE__ */ jsx7(PaneTitle, { label: "FULL CONTENT", extra: `${contentLines.length} lines${maxScroll ? ` \xB7 \u25BC${maxScroll - off} more \xB7 \u2191\u2193 scroll` : ""} \xB7 space copy \xB7 \u2190 back`, width: innerW }),
|
|
10096
|
+
/* @__PURE__ */ jsx7(Box7, { flexDirection: "column", height: bodyRows, overflow: "hidden", children: win.map((l, i) => /* @__PURE__ */ jsx7(Text7, { wrap: "truncate", children: l || " " }, off + i)) }),
|
|
10097
|
+
/* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
|
|
10098
|
+
/* @__PURE__ */ jsx7(Text7, { backgroundColor: BG2, color: "white", bold: true, children: " ENTRY " }),
|
|
10099
|
+
/* @__PURE__ */ jsx7(Text7, { backgroundColor: "#0b1530", color: "white", children: ` ${e.id} ` }),
|
|
10100
|
+
/* @__PURE__ */ jsx7(Text7, { backgroundColor: BG2, color: "white", children: " \u2191\u2193 scroll \xB7 space copy \xB7 ? all keys \xB7 \u2190 back \xB7 esc menu " })
|
|
9943
10101
|
] })
|
|
9944
10102
|
] });
|
|
9945
10103
|
}
|
|
9946
|
-
const chip = (label, val, on) => /* @__PURE__ */
|
|
9947
|
-
/* @__PURE__ */
|
|
10104
|
+
const chip = (label, val, on) => /* @__PURE__ */ jsxs7(Text7, { children: [
|
|
10105
|
+
/* @__PURE__ */ jsxs7(Text7, { color: theme.dim, children: [
|
|
9948
10106
|
label,
|
|
9949
10107
|
":"
|
|
9950
10108
|
] }),
|
|
9951
|
-
/* @__PURE__ */
|
|
9952
|
-
/* @__PURE__ */
|
|
10109
|
+
/* @__PURE__ */ jsx7(Text7, { color: on ? theme.accentBright : theme.dim, children: val }),
|
|
10110
|
+
/* @__PURE__ */ jsx7(Text7, { children: " " })
|
|
9953
10111
|
] });
|
|
9954
10112
|
if (view === "sessions") {
|
|
9955
10113
|
const headerRows2 = 5 + (editing ? 1 : 0);
|
|
@@ -9957,20 +10115,20 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
9957
10115
|
const selC = Math.min(sessSel, Math.max(0, sessionsFiltered.length - 1));
|
|
9958
10116
|
const start2 = Math.min(Math.max(0, selC - Math.floor((listRows2 - 1) / 2)), Math.max(0, sessionsFiltered.length - listRows2));
|
|
9959
10117
|
const win = sessionsFiltered.slice(start2, start2 + listRows2);
|
|
9960
|
-
return /* @__PURE__ */
|
|
10118
|
+
return /* @__PURE__ */ jsx7(DataView, { loading: sessLoading && !frozen, error: source === "cloud" ? agentsQ.error : localQ.error, children: /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
|
|
9961
10119
|
strip,
|
|
9962
10120
|
copyBanner,
|
|
9963
|
-
/* @__PURE__ */
|
|
10121
|
+
/* @__PURE__ */ jsxs7(Box7, { children: [
|
|
9964
10122
|
srcChip,
|
|
9965
|
-
/* @__PURE__ */
|
|
9966
|
-
/* @__PURE__ */
|
|
10123
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.accentBright, bold: true, children: "SESSIONS" }),
|
|
10124
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: " \xB7 logs (v) " }),
|
|
9967
10125
|
chip("status", SESS_STATUS[si] ?? "all", si !== 0),
|
|
9968
10126
|
chip("search", sessSearch || "\xB7", !!sessSearch)
|
|
9969
10127
|
] }),
|
|
9970
|
-
/* @__PURE__ */
|
|
9971
|
-
editing === "sess-search" ? /* @__PURE__ */
|
|
9972
|
-
/* @__PURE__ */
|
|
9973
|
-
/* @__PURE__ */
|
|
10128
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, wrap: "truncate", children: focused ? "\u2191\u2193 select \xB7 enter \u2192 session logs \xB7 v logs \xB7 ^R refresh \xB7 ? all keys" : "press \u2192 to browse" }),
|
|
10129
|
+
editing === "sess-search" ? /* @__PURE__ */ jsxs7(Box7, { children: [
|
|
10130
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.warn, children: "search: " }),
|
|
10131
|
+
/* @__PURE__ */ jsx7(
|
|
9974
10132
|
TextInput4,
|
|
9975
10133
|
{
|
|
9976
10134
|
value: sessSearch,
|
|
@@ -9982,8 +10140,8 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
9982
10140
|
}
|
|
9983
10141
|
)
|
|
9984
10142
|
] }) : null,
|
|
9985
|
-
/* @__PURE__ */
|
|
9986
|
-
/* @__PURE__ */
|
|
10143
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, wrap: "truncate", children: `${sessionsFiltered.length} sessions \xB7 ${selC + 1}/${sessionsFiltered.length}${start2 ? ` \xB7 \u25B2${start2}` : ""}${start2 + listRows2 < sessionsFiltered.length ? ` \xB7 \u25BC${sessionsFiltered.length - start2 - listRows2}` : ""}` }),
|
|
10144
|
+
/* @__PURE__ */ jsx7(
|
|
9987
10145
|
Table,
|
|
9988
10146
|
{
|
|
9989
10147
|
columns: [
|
|
@@ -10014,7 +10172,7 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
10014
10172
|
})
|
|
10015
10173
|
}
|
|
10016
10174
|
),
|
|
10017
|
-
sessionsFiltered.length === 0 ? /* @__PURE__ */
|
|
10175
|
+
sessionsFiltered.length === 0 ? /* @__PURE__ */ jsxs7(Text7, { color: theme.dim, children: [
|
|
10018
10176
|
"(no sessions",
|
|
10019
10177
|
source === "local" ? " in the local file" : "",
|
|
10020
10178
|
")"
|
|
@@ -10027,13 +10185,13 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
10027
10185
|
const maxStart = Math.max(0, pageRows.length - listRows);
|
|
10028
10186
|
const start = Math.min(Math.max(0, selClamped - Math.floor((listRows - 1) / 2)), maxStart);
|
|
10029
10187
|
const windowed = pageRows.slice(start, start + listRows);
|
|
10030
|
-
return /* @__PURE__ */
|
|
10188
|
+
return /* @__PURE__ */ jsx7(DataView, { loading: logsLoading && !frozen, error: source === "cloud" ? cloudQ.error : localQ.error, children: /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
|
|
10031
10189
|
strip,
|
|
10032
10190
|
copyBanner,
|
|
10033
|
-
/* @__PURE__ */
|
|
10191
|
+
/* @__PURE__ */ jsxs7(Box7, { children: [
|
|
10034
10192
|
srcChip,
|
|
10035
|
-
/* @__PURE__ */
|
|
10036
|
-
/* @__PURE__ */
|
|
10193
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.accentBright, bold: true, children: "LOGS" }),
|
|
10194
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: " \xB7 sessions (v) " }),
|
|
10037
10195
|
chip("dec", DECISIONS[di] ?? "all", di !== 0),
|
|
10038
10196
|
chip("sig", SIGNALS[gi] ?? "all", gi !== 0),
|
|
10039
10197
|
chip("tool", tool || "\xB7", !!tool),
|
|
@@ -10041,14 +10199,14 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
10041
10199
|
chip("search", search || "\xB7", !!search),
|
|
10042
10200
|
sessFilter ? chip("sess", sessFilter.slice(0, 8), true) : null
|
|
10043
10201
|
] }),
|
|
10044
|
-
/* @__PURE__ */
|
|
10045
|
-
msg ? /* @__PURE__ */
|
|
10046
|
-
editing && editing !== "sess-search" ? /* @__PURE__ */
|
|
10047
|
-
/* @__PURE__ */
|
|
10202
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, wrap: "truncate", children: focused ? "\u2191\u2193 select \xB7 enter full entry \xB7 \u2190\u2192 page \xB7 v sessions \xB7 ^R refresh \xB7 ? all keys" : "press \u2192 to browse" }),
|
|
10203
|
+
msg ? /* @__PURE__ */ jsx7(Text7, { color: msg.level === "bad" ? theme.bad : theme.ok, children: truncate2(msg.text, cols) }) : null,
|
|
10204
|
+
editing && editing !== "sess-search" ? /* @__PURE__ */ jsxs7(Box7, { children: [
|
|
10205
|
+
/* @__PURE__ */ jsxs7(Text7, { color: theme.warn, children: [
|
|
10048
10206
|
editing,
|
|
10049
10207
|
": "
|
|
10050
10208
|
] }),
|
|
10051
|
-
/* @__PURE__ */
|
|
10209
|
+
/* @__PURE__ */ jsx7(
|
|
10052
10210
|
TextInput4,
|
|
10053
10211
|
{
|
|
10054
10212
|
value: editing === "tool" ? tool : editing === "agent" ? agent : search,
|
|
@@ -10061,9 +10219,9 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
10061
10219
|
}
|
|
10062
10220
|
)
|
|
10063
10221
|
] }) : null,
|
|
10064
|
-
/* @__PURE__ */
|
|
10065
|
-
/* @__PURE__ */
|
|
10066
|
-
pageRows.length === 0 ? /* @__PURE__ */
|
|
10222
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, wrap: "truncate", children: `${total} matched \xB7 page ${Math.min(page + 1, pages)}/${pages} \xB7 ${PAGE}/page \xB7 ${pageRows.length ? selClamped + 1 : 0}/${pageRows.length}${start ? ` \xB7 \u25B2${start} newer` : ""}${start + listRows < pageRows.length ? ` \xB7 \u25BC${pageRows.length - start - listRows} older` : ""}` }),
|
|
10223
|
+
/* @__PURE__ */ jsx7(Box7, { flexDirection: "column", overflow: "hidden", children: windowed.map((e, i) => /* @__PURE__ */ jsx7(StreamLine, { e: toStream(e), loc: source === "local", selected: start + i === selClamped && focused, date: true }, e.id)) }),
|
|
10224
|
+
pageRows.length === 0 ? /* @__PURE__ */ jsxs7(Text7, { color: theme.dim, children: [
|
|
10067
10225
|
"(no entries",
|
|
10068
10226
|
source === "local" ? " in the local file" : "",
|
|
10069
10227
|
" \u2014 c clears filters)"
|
|
@@ -10472,10 +10630,10 @@ var init_global_install = __esm({
|
|
|
10472
10630
|
});
|
|
10473
10631
|
|
|
10474
10632
|
// src/tui/panels/Settings.tsx
|
|
10475
|
-
import { Box as
|
|
10633
|
+
import { Box as Box8, Text as Text8, useInput as useInput7 } from "ink";
|
|
10476
10634
|
import TextInput5 from "ink-text-input";
|
|
10477
|
-
import { useEffect as
|
|
10478
|
-
import { Fragment as Fragment5, jsx as
|
|
10635
|
+
import { useEffect as useEffect7, useRef as useRef3, useState as useState8 } from "react";
|
|
10636
|
+
import { Fragment as Fragment5, jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
10479
10637
|
function SettingsPanel({
|
|
10480
10638
|
active: active2,
|
|
10481
10639
|
focused,
|
|
@@ -10485,16 +10643,16 @@ function SettingsPanel({
|
|
|
10485
10643
|
}) {
|
|
10486
10644
|
void active2;
|
|
10487
10645
|
const { cols, rows } = usePanelSize();
|
|
10488
|
-
const [sel, setSel] =
|
|
10489
|
-
const [editing, setEditing] =
|
|
10490
|
-
const [input, setInput] =
|
|
10491
|
-
const [confirmDel, setConfirmDel] =
|
|
10492
|
-
const [msg, setMsg] =
|
|
10493
|
-
const [busy, setBusy] =
|
|
10494
|
-
const [editor, setEditor] =
|
|
10495
|
-
const [latest, setLatest] =
|
|
10646
|
+
const [sel, setSel] = useState8(0);
|
|
10647
|
+
const [editing, setEditing] = useState8(null);
|
|
10648
|
+
const [input, setInput] = useState8("");
|
|
10649
|
+
const [confirmDel, setConfirmDel] = useState8(null);
|
|
10650
|
+
const [msg, setMsg] = useState8(null);
|
|
10651
|
+
const [busy, setBusy] = useState8(false);
|
|
10652
|
+
const [editor, setEditor] = useState8(null);
|
|
10653
|
+
const [latest, setLatest] = useState8(null);
|
|
10496
10654
|
const ver = currentVersion();
|
|
10497
|
-
|
|
10655
|
+
useEffect7(() => {
|
|
10498
10656
|
let live2 = true;
|
|
10499
10657
|
latestVersion().then((v) => {
|
|
10500
10658
|
if (live2) setLatest(v);
|
|
@@ -10504,26 +10662,26 @@ function SettingsPanel({
|
|
|
10504
10662
|
live2 = false;
|
|
10505
10663
|
};
|
|
10506
10664
|
}, []);
|
|
10507
|
-
const [accounts, setAccounts] =
|
|
10508
|
-
const [login, setLogin] =
|
|
10509
|
-
const [tick, setTick] =
|
|
10665
|
+
const [accounts, setAccounts] = useState8(() => listAccounts());
|
|
10666
|
+
const [login, setLogin] = useState8(null);
|
|
10667
|
+
const [tick, setTick] = useState8(0);
|
|
10510
10668
|
const abort = useRef3(false);
|
|
10511
10669
|
const refreshAccounts = () => setAccounts(listAccounts());
|
|
10512
|
-
const [guardHere, setGuardHere] =
|
|
10513
|
-
const [guardVer, setGuardVer] =
|
|
10514
|
-
const [guardOld, setGuardOld] =
|
|
10670
|
+
const [guardHere, setGuardHere] = useState8(() => isGuardInstalled());
|
|
10671
|
+
const [guardVer, setGuardVer] = useState8(() => installedGuardVersion());
|
|
10672
|
+
const [guardOld, setGuardOld] = useState8(() => guardHookOutdated());
|
|
10515
10673
|
const refreshGuard = () => {
|
|
10516
10674
|
setGuardHere(isGuardInstalled());
|
|
10517
10675
|
setGuardVer(installedGuardVersion());
|
|
10518
10676
|
setGuardOld(guardHookOutdated());
|
|
10519
10677
|
};
|
|
10520
10678
|
const locked = accounts.length === 0;
|
|
10521
|
-
const [srv, setSrv] =
|
|
10522
|
-
|
|
10679
|
+
const [srv, setSrv] = useState8(() => logsServerStatus());
|
|
10680
|
+
useEffect7(() => {
|
|
10523
10681
|
const t = setInterval(() => setSrv(logsServerStatus()), 3e3);
|
|
10524
10682
|
return () => clearInterval(t);
|
|
10525
10683
|
}, []);
|
|
10526
|
-
|
|
10684
|
+
useEffect7(() => {
|
|
10527
10685
|
if (!login || login.phase === "done" || login.phase === "error") return;
|
|
10528
10686
|
const t = setInterval(() => setTick((n) => n + 1), 120);
|
|
10529
10687
|
return () => clearInterval(t);
|
|
@@ -10536,7 +10694,7 @@ function SettingsPanel({
|
|
|
10536
10694
|
const local = localQ.data;
|
|
10537
10695
|
const selfProt = selfQ.data;
|
|
10538
10696
|
const autoInstalledRef = useRef3(false);
|
|
10539
|
-
|
|
10697
|
+
useEffect7(() => {
|
|
10540
10698
|
if (autoInstalledRef.current) return;
|
|
10541
10699
|
if (guardHere && guardOld) {
|
|
10542
10700
|
autoInstalledRef.current = true;
|
|
@@ -10548,7 +10706,7 @@ function SettingsPanel({
|
|
|
10548
10706
|
}
|
|
10549
10707
|
}
|
|
10550
10708
|
}, [guardHere, guardOld]);
|
|
10551
|
-
const [hidden, setHidden] =
|
|
10709
|
+
const [hidden, setHidden] = useState8(/* @__PURE__ */ new Set());
|
|
10552
10710
|
const webhooks = (whQ.data?.webhooks ?? []).filter((w) => !hidden.has("wh:" + w.id));
|
|
10553
10711
|
const alerts = (alertQ.data?.rules ?? []).filter((r) => !hidden.has("alert:" + r.id));
|
|
10554
10712
|
const hasEmailAlert = alerts.some((r) => alertChannel(r) === "email");
|
|
@@ -10729,7 +10887,7 @@ function SettingsPanel({
|
|
|
10729
10887
|
setEditor({ ...editor, target: v, field: 1 });
|
|
10730
10888
|
}
|
|
10731
10889
|
};
|
|
10732
|
-
|
|
10890
|
+
useInput7(
|
|
10733
10891
|
(inp, key) => {
|
|
10734
10892
|
if (login && (login.phase === "starting" || login.phase === "waiting")) {
|
|
10735
10893
|
if (key.escape) {
|
|
@@ -10862,156 +11020,156 @@ function SettingsPanel({
|
|
|
10862
11020
|
);
|
|
10863
11021
|
const spin = SPIN2[tick % SPIN2.length];
|
|
10864
11022
|
if (login && (login.phase === "starting" || login.phase === "waiting")) {
|
|
10865
|
-
return /* @__PURE__ */
|
|
10866
|
-
/* @__PURE__ */
|
|
10867
|
-
login.phase === "starting" ? /* @__PURE__ */
|
|
11023
|
+
return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
|
|
11024
|
+
/* @__PURE__ */ jsx8(Text8, { bold: true, color: theme.accentBright, children: "Add an account" }),
|
|
11025
|
+
login.phase === "starting" ? /* @__PURE__ */ jsxs8(Text8, { color: theme.dim, children: [
|
|
10868
11026
|
spin,
|
|
10869
11027
|
" starting device pairing\u2026"
|
|
10870
|
-
] }) : /* @__PURE__ */
|
|
10871
|
-
/* @__PURE__ */
|
|
10872
|
-
/* @__PURE__ */
|
|
10873
|
-
/* @__PURE__ */
|
|
10874
|
-
/* @__PURE__ */
|
|
11028
|
+
] }) : /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", marginTop: 1, children: [
|
|
11029
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "Opening your browser to authorize. If it didn't open, visit:" }),
|
|
11030
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.accentBright, bold: true, wrap: "truncate", children: login.url }),
|
|
11031
|
+
/* @__PURE__ */ jsxs8(Box8, { marginTop: 1, children: [
|
|
11032
|
+
/* @__PURE__ */ jsxs8(Text8, { color: theme.warn, children: [
|
|
10875
11033
|
spin,
|
|
10876
11034
|
" waiting for authorization\u2026 "
|
|
10877
11035
|
] }),
|
|
10878
|
-
/* @__PURE__ */
|
|
11036
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "esc to cancel" })
|
|
10879
11037
|
] })
|
|
10880
11038
|
] })
|
|
10881
11039
|
] });
|
|
10882
11040
|
}
|
|
10883
11041
|
if (editor) {
|
|
10884
|
-
const fieldRow = (idx, label, value, hint) => /* @__PURE__ */
|
|
10885
|
-
/* @__PURE__ */
|
|
10886
|
-
/* @__PURE__ */
|
|
11042
|
+
const fieldRow = (idx, label, value, hint) => /* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", children: [
|
|
11043
|
+
/* @__PURE__ */ jsx8(Text8, { color: editor.field === idx ? theme.accentBright : theme.dim, children: editor.field === idx ? "\u25B8 " : " " }),
|
|
11044
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: label.padEnd(11) }),
|
|
10887
11045
|
value,
|
|
10888
|
-
editor.field === idx && hint ? /* @__PURE__ */
|
|
11046
|
+
editor.field === idx && hint ? /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: " " + hint }) : null
|
|
10889
11047
|
] });
|
|
10890
|
-
return /* @__PURE__ */
|
|
10891
|
-
/* @__PURE__ */
|
|
11048
|
+
return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
|
|
11049
|
+
/* @__PURE__ */ jsxs8(Text8, { bold: true, color: theme.accentBright, children: [
|
|
10892
11050
|
editor.id ? "Edit" : "New",
|
|
10893
11051
|
" ",
|
|
10894
11052
|
editor.channel,
|
|
10895
11053
|
" alert"
|
|
10896
11054
|
] }),
|
|
10897
|
-
/* @__PURE__ */
|
|
10898
|
-
editing === "alert-target" ? /* @__PURE__ */
|
|
10899
|
-
/* @__PURE__ */
|
|
10900
|
-
/* @__PURE__ */
|
|
10901
|
-
] }) : msg ? /* @__PURE__ */
|
|
10902
|
-
/* @__PURE__ */
|
|
10903
|
-
fieldRow(0, "target", editor.target ? /* @__PURE__ */
|
|
10904
|
-
fieldRow(1, "signal", /* @__PURE__ */
|
|
10905
|
-
fieldRow(2, "threshold", /* @__PURE__ */
|
|
10906
|
-
fieldRow(3, "window", /* @__PURE__ */
|
|
10907
|
-
editor.id ? fieldRow(4, "status", editor.enabled ? /* @__PURE__ */
|
|
11055
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "\u2191\u2193 field \xB7 \u2190\u2192 change \xB7 e edit target \xB7 enter save \xB7 esc cancel" }),
|
|
11056
|
+
editing === "alert-target" ? /* @__PURE__ */ jsxs8(Box8, { marginTop: 1, children: [
|
|
11057
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.warn, children: editor.channel === "email" ? "e-mail address: " : "telegram chat id (from @userinfobot): " }),
|
|
11058
|
+
/* @__PURE__ */ jsx8(TextInput5, { value: input, onChange: setInput, onSubmit: submitInput })
|
|
11059
|
+
] }) : msg ? /* @__PURE__ */ jsx8(Text8, { color: msg.level === "bad" ? theme.bad : theme.ok, children: truncate2(msg.text, cols) }) : /* @__PURE__ */ jsx8(Text8, { children: " " }),
|
|
11060
|
+
/* @__PURE__ */ jsxs8(Box8, { marginTop: 1, flexDirection: "column", children: [
|
|
11061
|
+
fieldRow(0, "target", editor.target ? /* @__PURE__ */ jsx8(Text8, { color: theme.accent, children: truncate2(editor.target, cols - 16) }) : /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "empty \u2014 press e" }), "press e to edit"),
|
|
11062
|
+
fieldRow(1, "signal", /* @__PURE__ */ jsx8(Text8, { color: theme.accent, children: SIGNAL_LABEL[editor.signal] }), "\u2190\u2192 change"),
|
|
11063
|
+
fieldRow(2, "threshold", /* @__PURE__ */ jsx8(Text8, { color: theme.accent, children: `\u2265 ${editor.threshold}` }), "\u2190\u2192 \xB15"),
|
|
11064
|
+
fieldRow(3, "window", /* @__PURE__ */ jsx8(Text8, { color: theme.accent, children: winLabel(editor.windowSeconds) }), "\u2190\u2192 change"),
|
|
11065
|
+
editor.id ? fieldRow(4, "status", editor.enabled ? /* @__PURE__ */ jsx8(Text8, { color: theme.ok, children: "on" }) : /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "off" }), "\u2190\u2192 turn on/off") : null
|
|
10908
11066
|
] }),
|
|
10909
|
-
/* @__PURE__ */
|
|
11067
|
+
/* @__PURE__ */ jsx8(Box8, { marginTop: 1, children: editor.id && !editor.enabled ? /* @__PURE__ */ jsx8(Text8, { color: theme.warn, children: "disabled \u2014 this alert will NOT fire until you set status back to on" }) : /* @__PURE__ */ jsxs8(Text8, { color: theme.dim, children: [
|
|
10910
11068
|
"fires when ",
|
|
10911
|
-
/* @__PURE__ */
|
|
11069
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.accent, children: SIGNAL_LABEL[editor.signal] }),
|
|
10912
11070
|
" reach ",
|
|
10913
|
-
/* @__PURE__ */
|
|
11071
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.accent, children: editor.threshold }),
|
|
10914
11072
|
" within",
|
|
10915
11073
|
" ",
|
|
10916
|
-
/* @__PURE__ */
|
|
11074
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.accent, children: winLabel(editor.windowSeconds) })
|
|
10917
11075
|
] }) })
|
|
10918
11076
|
] });
|
|
10919
11077
|
}
|
|
10920
11078
|
const loading = !locked && (localQ.loading && !localQ.data || whQ.loading && !whQ.data || alertQ.loading && !alertQ.data || guardQ.loading && !guardQ.data || selfQ.loading && !selfQ.data);
|
|
10921
11079
|
const error = locked ? null : localQ.error ?? whQ.error ?? alertQ.error ?? guardQ.error ?? selfQ.error;
|
|
10922
|
-
const onOff = (on) => on ? /* @__PURE__ */
|
|
11080
|
+
const onOff = (on) => on ? /* @__PURE__ */ jsx8(Text8, { color: theme.ok, children: "on " }) : /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "off" });
|
|
10923
11081
|
const chanOf = (rule) => [...rule.emails ?? [], ...(rule.telegram ?? []).map((t) => "tg " + t)].join(", ") || "\u2014";
|
|
10924
11082
|
const isCur = (r) => keyOf(r) === keyOf(cur) && focused;
|
|
10925
|
-
const cursor = (r) => /* @__PURE__ */
|
|
11083
|
+
const cursor = (r) => /* @__PURE__ */ jsx8(Text8, { color: isCur(r) ? theme.accentBright : theme.dim, children: isCur(r) ? "\u25B8 " : " " });
|
|
10926
11084
|
const rowLine = (r) => {
|
|
10927
11085
|
switch (r.kind) {
|
|
10928
11086
|
case "acct": {
|
|
10929
11087
|
const a = r.acc;
|
|
10930
11088
|
const isView = viewApiKey ? a.apiKey === viewApiKey : accounts[0]?.apiKey === a.apiKey;
|
|
10931
11089
|
const isActive = isActiveAccount(a.apiKey);
|
|
10932
|
-
return /* @__PURE__ */
|
|
11090
|
+
return /* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", children: [
|
|
10933
11091
|
cursor(r),
|
|
10934
|
-
/* @__PURE__ */
|
|
10935
|
-
isView ? /* @__PURE__ */
|
|
10936
|
-
isActive ? /* @__PURE__ */
|
|
10937
|
-
/* @__PURE__ */
|
|
11092
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.accent, children: truncate2(acctLabel(a), 30).padEnd(31) }),
|
|
11093
|
+
isView ? /* @__PURE__ */ jsx8(Text8, { color: theme.ok, children: "\u25CF viewing " }) : /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: " " }),
|
|
11094
|
+
isActive ? /* @__PURE__ */ jsx8(Text8, { color: theme.warn, children: "ACTIVE " }) : /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: " " }),
|
|
11095
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: a.project ? truncate2(a.project, 20) : "" })
|
|
10938
11096
|
] });
|
|
10939
11097
|
}
|
|
10940
11098
|
case "acct-add":
|
|
10941
|
-
return /* @__PURE__ */
|
|
11099
|
+
return /* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", children: [
|
|
10942
11100
|
cursor(r),
|
|
10943
|
-
/* @__PURE__ */
|
|
11101
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "+ add account (enter \u2014 device login in the browser)" })
|
|
10944
11102
|
] });
|
|
10945
11103
|
case "guard":
|
|
10946
|
-
return /* @__PURE__ */
|
|
11104
|
+
return /* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", children: [
|
|
10947
11105
|
cursor(r),
|
|
10948
|
-
/* @__PURE__ */
|
|
10949
|
-
!guardHere ? /* @__PURE__ */
|
|
10950
|
-
/* @__PURE__ */
|
|
10951
|
-
/* @__PURE__ */
|
|
10952
|
-
/* @__PURE__ */
|
|
10953
|
-
] }) : /* @__PURE__ */
|
|
10954
|
-
/* @__PURE__ */
|
|
10955
|
-
/* @__PURE__ */
|
|
10956
|
-
/* @__PURE__ */
|
|
11106
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "guard".padEnd(11) }),
|
|
11107
|
+
!guardHere ? /* @__PURE__ */ jsxs8(Fragment5, { children: [
|
|
11108
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.bad, bold: true, children: "removed" }),
|
|
11109
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: " \xB7 " }),
|
|
11110
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.accentBright, children: "enter to install" })
|
|
11111
|
+
] }) : /* @__PURE__ */ jsxs8(Fragment5, { children: [
|
|
11112
|
+
/* @__PURE__ */ jsx8(Text8, { color: guardOld ? theme.warn : theme.ok, children: `v${guardVer ?? "?"}` }),
|
|
11113
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: guardOld ? " \xB7 update available \xB7 enter update" : " (latest) \xB7 enter reinstall" }),
|
|
11114
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: " \xB7 d remove" })
|
|
10957
11115
|
] })
|
|
10958
11116
|
] });
|
|
10959
11117
|
case "self":
|
|
10960
|
-
return /* @__PURE__ */
|
|
11118
|
+
return /* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", children: [
|
|
10961
11119
|
cursor(r),
|
|
10962
|
-
/* @__PURE__ */
|
|
10963
|
-
selfProt ? onOff(selfProt.enabled) : /* @__PURE__ */
|
|
10964
|
-
/* @__PURE__ */
|
|
11120
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "self-prot".padEnd(11) }),
|
|
11121
|
+
selfProt ? onOff(selfProt.enabled) : /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "\u2026" }),
|
|
11122
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: " blocks agents editing SolonGate\u2019s own hooks/config \xB7 enter toggles" })
|
|
10965
11123
|
] });
|
|
10966
11124
|
case "ll-enabled":
|
|
10967
|
-
return /* @__PURE__ */
|
|
11125
|
+
return /* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", children: [
|
|
10968
11126
|
cursor(r),
|
|
10969
|
-
/* @__PURE__ */
|
|
11127
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "enabled ".padEnd(11) }),
|
|
10970
11128
|
onOff(!!local?.enabled),
|
|
10971
|
-
/* @__PURE__ */
|
|
11129
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: " enter toggles" })
|
|
10972
11130
|
] });
|
|
10973
11131
|
case "ll-path":
|
|
10974
|
-
return /* @__PURE__ */
|
|
11132
|
+
return /* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", children: [
|
|
10975
11133
|
cursor(r),
|
|
10976
|
-
/* @__PURE__ */
|
|
10977
|
-
local?.path ? /* @__PURE__ */
|
|
11134
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "path ".padEnd(11) }),
|
|
11135
|
+
local?.path ? /* @__PURE__ */ jsx8(Text8, { color: theme.accent, children: truncate2(local.path, cols - 14) }) : /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "not set \u2014 enter to edit" })
|
|
10978
11136
|
] });
|
|
10979
11137
|
case "ll-server":
|
|
10980
|
-
return /* @__PURE__ */
|
|
11138
|
+
return /* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", children: [
|
|
10981
11139
|
cursor(r),
|
|
10982
|
-
/* @__PURE__ */
|
|
10983
|
-
srv.running ? /* @__PURE__ */
|
|
10984
|
-
/* @__PURE__ */
|
|
11140
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "dashboard".padEnd(11) }),
|
|
11141
|
+
srv.running ? /* @__PURE__ */ jsx8(Text8, { color: theme.ok, children: `running 127.0.0.1:${srv.port}` }) : /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "stopped" }),
|
|
11142
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: srv.running ? " survives closing the dataroom \xB7 enter stops" : " enter starts the dashboard local-logs link" })
|
|
10985
11143
|
] });
|
|
10986
11144
|
case "wh":
|
|
10987
|
-
return /* @__PURE__ */
|
|
11145
|
+
return /* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", children: [
|
|
10988
11146
|
cursor(r),
|
|
10989
11147
|
onOff(r.wh.enabled),
|
|
10990
|
-
/* @__PURE__ */
|
|
10991
|
-
/* @__PURE__ */
|
|
11148
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.warn, children: (" " + r.wh.events).padEnd(9) }),
|
|
11149
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.accent, children: truncate2(r.wh.url, cols - 16) })
|
|
10992
11150
|
] });
|
|
10993
11151
|
case "wh-add":
|
|
10994
|
-
return /* @__PURE__ */
|
|
11152
|
+
return /* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", children: [
|
|
10995
11153
|
cursor(r),
|
|
10996
|
-
/* @__PURE__ */
|
|
11154
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "+ add webhook (enter)" })
|
|
10997
11155
|
] });
|
|
10998
11156
|
case "alert":
|
|
10999
|
-
return /* @__PURE__ */
|
|
11157
|
+
return /* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", children: [
|
|
11000
11158
|
cursor(r),
|
|
11001
11159
|
onOff(r.rule.enabled),
|
|
11002
|
-
/* @__PURE__ */
|
|
11003
|
-
/* @__PURE__ */
|
|
11004
|
-
/* @__PURE__ */
|
|
11160
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.warn, children: (" " + SIGNAL_LABEL[r.rule.signal]).padEnd(13) }),
|
|
11161
|
+
/* @__PURE__ */ jsx8(Text8, { children: `\u2265${r.rule.threshold}/${winLabel(r.rule.windowSeconds)} `.padEnd(11) }),
|
|
11162
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.accent, children: truncate2(chanOf(r.rule), cols - 34) })
|
|
11005
11163
|
] });
|
|
11006
11164
|
case "alert-add-email":
|
|
11007
|
-
return /* @__PURE__ */
|
|
11165
|
+
return /* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", children: [
|
|
11008
11166
|
cursor(r),
|
|
11009
|
-
/* @__PURE__ */
|
|
11167
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "+ add email alert (enter)" })
|
|
11010
11168
|
] });
|
|
11011
11169
|
case "alert-add-tg":
|
|
11012
|
-
return /* @__PURE__ */
|
|
11170
|
+
return /* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", children: [
|
|
11013
11171
|
cursor(r),
|
|
11014
|
-
/* @__PURE__ */
|
|
11172
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "+ add telegram alert (enter \u2014 numeric chat id from @userinfobot)" })
|
|
11015
11173
|
] });
|
|
11016
11174
|
}
|
|
11017
11175
|
};
|
|
@@ -11030,39 +11188,39 @@ function SettingsPanel({
|
|
|
11030
11188
|
const sec = sectionOf(r);
|
|
11031
11189
|
if (sec !== lastSec) {
|
|
11032
11190
|
if (lastSec) {
|
|
11033
|
-
lineEls.push(/* @__PURE__ */
|
|
11191
|
+
lineEls.push(/* @__PURE__ */ jsx8(Text8, { children: " " }, "sp:" + sec));
|
|
11034
11192
|
lineKey.push("");
|
|
11035
11193
|
}
|
|
11036
11194
|
lastSec = sec;
|
|
11037
11195
|
lineEls.push(
|
|
11038
|
-
/* @__PURE__ */
|
|
11039
|
-
/* @__PURE__ */
|
|
11040
|
-
/* @__PURE__ */
|
|
11196
|
+
/* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", children: [
|
|
11197
|
+
/* @__PURE__ */ jsx8(Text8, { bold: true, color: theme.accentBright, children: sec }),
|
|
11198
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: " \u2014 " + SECTION_DESC[sec] })
|
|
11041
11199
|
] }, "h:" + sec)
|
|
11042
11200
|
);
|
|
11043
11201
|
lineKey.push("");
|
|
11044
11202
|
if ((sec === "WEBHOOKS" || sec === "ALERTS") && local?.enabled) {
|
|
11045
11203
|
lineEls.push(
|
|
11046
|
-
/* @__PURE__ */
|
|
11204
|
+
/* @__PURE__ */ jsx8(Text8, { wrap: "truncate", color: theme.warn, children: ` \u26A0 local logs on \u2014 real denials stay on this machine, so ${sec.toLowerCase()} do NOT fire${sec === "WEBHOOKS" ? " (t test still works)" : ""}` }, "warn:" + sec)
|
|
11047
11205
|
);
|
|
11048
11206
|
lineKey.push("");
|
|
11049
11207
|
}
|
|
11050
11208
|
}
|
|
11051
|
-
lineEls.push(/* @__PURE__ */
|
|
11209
|
+
lineEls.push(/* @__PURE__ */ jsx8(Box8, { children: rowLine(r) }, keyOf(r)));
|
|
11052
11210
|
lineKey.push(keyOf(r));
|
|
11053
11211
|
});
|
|
11054
11212
|
if (hasEmailAlert && hasTgAlert) {
|
|
11055
11213
|
lineEls.push(
|
|
11056
|
-
/* @__PURE__ */
|
|
11214
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: " both channels in use \u2014 remove one (d) to change it" }, "both-note")
|
|
11057
11215
|
);
|
|
11058
11216
|
lineKey.push("");
|
|
11059
11217
|
}
|
|
11060
|
-
lineEls.push(/* @__PURE__ */
|
|
11218
|
+
lineEls.push(/* @__PURE__ */ jsx8(Text8, { children: " " }, "ver-sp"));
|
|
11061
11219
|
lineKey.push("");
|
|
11062
11220
|
lineEls.push(
|
|
11063
|
-
/* @__PURE__ */
|
|
11221
|
+
/* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", color: theme.dim, children: [
|
|
11064
11222
|
`solongate v${ver}`,
|
|
11065
|
-
latest ? newerThan(latest, ver) ? /* @__PURE__ */
|
|
11223
|
+
latest ? newerThan(latest, ver) ? /* @__PURE__ */ jsx8(Text8, { color: theme.warn, children: ` \xB7 v${latest} on npm \u2014 auto-updating` }) : /* @__PURE__ */ jsx8(Text8, { color: theme.ok, children: " \xB7 latest" }) : null
|
|
11066
11224
|
] }, "ver")
|
|
11067
11225
|
);
|
|
11068
11226
|
lineKey.push("");
|
|
@@ -11073,13 +11231,13 @@ function SettingsPanel({
|
|
|
11073
11231
|
const win = lineEls.slice(startL, startL + budget);
|
|
11074
11232
|
const moreAbove = startL;
|
|
11075
11233
|
const moreBelow = Math.max(0, lineEls.length - (startL + budget));
|
|
11076
|
-
return /* @__PURE__ */
|
|
11077
|
-
/* @__PURE__ */
|
|
11078
|
-
editing ? /* @__PURE__ */
|
|
11079
|
-
/* @__PURE__ */
|
|
11080
|
-
/* @__PURE__ */
|
|
11081
|
-
] }) : msg ? /* @__PURE__ */
|
|
11082
|
-
/* @__PURE__ */
|
|
11234
|
+
return /* @__PURE__ */ jsx8(DataView, { loading, error, children: /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
|
|
11235
|
+
/* @__PURE__ */ jsx8(Text8, { wrap: "truncate", color: theme.dim, children: focused ? `\u2191\u2193 move \xB7 enter act \xB7 m toggle \xB7 t test \xB7 e edit \xB7 x remove \xB7 d delete \xB7 n add${moreAbove ? ` \xB7 \u25B2${moreAbove}` : ""}${moreBelow ? ` \xB7 \u25BC${moreBelow}` : ""}` : "press \u2192 to configure" }),
|
|
11236
|
+
editing ? /* @__PURE__ */ jsxs8(Box8, { children: [
|
|
11237
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.warn, children: editing === "path" ? "local log path: " : "webhook url: " }),
|
|
11238
|
+
/* @__PURE__ */ jsx8(TextInput5, { value: input, onChange: setInput, onSubmit: submitInput })
|
|
11239
|
+
] }) : msg ? /* @__PURE__ */ jsx8(Text8, { wrap: "truncate", color: msg.level === "bad" ? theme.bad : theme.ok, children: truncate2(msg.text, cols) }) : login?.msg ? /* @__PURE__ */ jsx8(Text8, { wrap: "truncate", color: login.phase === "error" ? theme.bad : theme.ok, children: login.msg }) : /* @__PURE__ */ jsx8(Text8, { children: " " }),
|
|
11240
|
+
/* @__PURE__ */ jsx8(Box8, { flexDirection: "column", height: budget, overflow: "hidden", children: win })
|
|
11083
11241
|
] }) });
|
|
11084
11242
|
}
|
|
11085
11243
|
var EVENTS, SPIN2, SIGNALS2, SIGNAL_LABEL, WINDOWS, winLabel, THRESH_MIN, THRESH_MAX, nearestWindowIdx, editorFieldCount, acctLabel, alertChannel;
|
|
@@ -11115,17 +11273,17 @@ var init_Settings = __esm({
|
|
|
11115
11273
|
});
|
|
11116
11274
|
|
|
11117
11275
|
// src/tui/App.tsx
|
|
11118
|
-
import { Box as
|
|
11119
|
-
import { useEffect as
|
|
11120
|
-
import { jsx as
|
|
11276
|
+
import { Box as Box9, Text as Text9, useApp, useInput as useInput8 } from "ink";
|
|
11277
|
+
import { useEffect as useEffect8, useState as useState9 } from "react";
|
|
11278
|
+
import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
11121
11279
|
function LiveHint() {
|
|
11122
|
-
return /* @__PURE__ */
|
|
11123
|
-
/* @__PURE__ */
|
|
11124
|
-
/* @__PURE__ */
|
|
11125
|
-
/* @__PURE__ */
|
|
11126
|
-
/* @__PURE__ */
|
|
11280
|
+
return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", children: [
|
|
11281
|
+
/* @__PURE__ */ jsx9(Text9, { color: theme.accentBright, bold: true, children: "\u25B6 REALTIME CONSOLE" }),
|
|
11282
|
+
/* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: "Fullscreen live monitor \u2014 streaming tool calls, active charts," }),
|
|
11283
|
+
/* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: "counters, DLP hits and denial alerts. Updates every 2s." }),
|
|
11284
|
+
/* @__PURE__ */ jsx9(Box9, { marginTop: 1, children: /* @__PURE__ */ jsxs9(Text9, { children: [
|
|
11127
11285
|
"press ",
|
|
11128
|
-
/* @__PURE__ */
|
|
11286
|
+
/* @__PURE__ */ jsx9(Text9, { color: theme.accent, children: "enter" }),
|
|
11129
11287
|
" to go live"
|
|
11130
11288
|
] }) })
|
|
11131
11289
|
] });
|
|
@@ -11133,26 +11291,26 @@ function LiveHint() {
|
|
|
11133
11291
|
function Banner({ cols }) {
|
|
11134
11292
|
const wide = cols >= 82;
|
|
11135
11293
|
if (!wide) {
|
|
11136
|
-
return /* @__PURE__ */
|
|
11137
|
-
/* @__PURE__ */
|
|
11138
|
-
/* @__PURE__ */
|
|
11294
|
+
return /* @__PURE__ */ jsxs9(Box9, { children: [
|
|
11295
|
+
/* @__PURE__ */ jsx9(Text9, { bold: true, color: theme.accentBright, children: "SolonGate" }),
|
|
11296
|
+
/* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: " \u2014 security control center" })
|
|
11139
11297
|
] });
|
|
11140
11298
|
}
|
|
11141
|
-
return /* @__PURE__ */
|
|
11142
|
-
BANNER_FULL.map((line, i) => /* @__PURE__ */
|
|
11143
|
-
/* @__PURE__ */
|
|
11299
|
+
return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", children: [
|
|
11300
|
+
BANNER_FULL.map((line, i) => /* @__PURE__ */ jsx9(Text9, { bold: true, color: BANNER_HEX[i], children: line }, i)),
|
|
11301
|
+
/* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: " security control center \xB7 manage policies, rate limits, DLP & more" })
|
|
11144
11302
|
] });
|
|
11145
11303
|
}
|
|
11146
11304
|
function App() {
|
|
11147
11305
|
const { exit } = useApp();
|
|
11148
|
-
const [accounts, setAccounts] =
|
|
11149
|
-
const [viewKey, setViewKey] =
|
|
11150
|
-
const [viewNonce, setViewNonce] =
|
|
11151
|
-
const [section, setSection] =
|
|
11152
|
-
const [focus, setFocus] =
|
|
11153
|
-
const [help, setHelp] =
|
|
11154
|
-
const [update2, setUpdate] =
|
|
11155
|
-
|
|
11306
|
+
const [accounts, setAccounts] = useState9(() => listAccounts());
|
|
11307
|
+
const [viewKey, setViewKey] = useState9(() => accounts[0]?.apiKey);
|
|
11308
|
+
const [viewNonce, setViewNonce] = useState9(0);
|
|
11309
|
+
const [section, setSection] = useState9(accounts.length === 0 ? SETTINGS_SECTION : 0);
|
|
11310
|
+
const [focus, setFocus] = useState9("nav");
|
|
11311
|
+
const [help, setHelp] = useState9(false);
|
|
11312
|
+
const [update2, setUpdate] = useState9({ kind: "idle" });
|
|
11313
|
+
useEffect8(() => {
|
|
11156
11314
|
let alive = true;
|
|
11157
11315
|
const run10 = () => void tuiUpdateFlow((s) => alive && setUpdate(s));
|
|
11158
11316
|
run10();
|
|
@@ -11165,7 +11323,7 @@ function App() {
|
|
|
11165
11323
|
const acctIdx = Math.max(0, accounts.findIndex((a) => a.apiKey === viewKey));
|
|
11166
11324
|
const cur = accounts[acctIdx];
|
|
11167
11325
|
const acctLabel2 = cur ? cur.email || cur.user || cur.project || `account \u2026${cur.apiKey.slice(-4)}` : "not logged in";
|
|
11168
|
-
|
|
11326
|
+
useEffect8(() => {
|
|
11169
11327
|
if (!cur || cur.email) return;
|
|
11170
11328
|
let alive = true;
|
|
11171
11329
|
api.auth.me().then((r) => {
|
|
@@ -11201,7 +11359,7 @@ function App() {
|
|
|
11201
11359
|
};
|
|
11202
11360
|
const locked = accounts.length === 0;
|
|
11203
11361
|
const effectiveSection = locked ? SETTINGS_SECTION : section;
|
|
11204
|
-
|
|
11362
|
+
useInput8((input, key) => {
|
|
11205
11363
|
if (help) {
|
|
11206
11364
|
setHelp(false);
|
|
11207
11365
|
return;
|
|
@@ -11229,47 +11387,47 @@ function App() {
|
|
|
11229
11387
|
});
|
|
11230
11388
|
const { cols, rows } = useTermSize();
|
|
11231
11389
|
const current = SECTIONS[effectiveSection];
|
|
11232
|
-
if (help) return /* @__PURE__ */
|
|
11390
|
+
if (help) return /* @__PURE__ */ jsx9(HelpOverlay, { cols, rows });
|
|
11233
11391
|
if (current.label === "Live" && focus === "panel") {
|
|
11234
|
-
return /* @__PURE__ */
|
|
11392
|
+
return /* @__PURE__ */ jsx9(Box9, { flexDirection: "column", width: cols, height: rows - 1, overflow: "hidden", children: /* @__PURE__ */ jsx9(LivePanel, { active: true, focused: true }, viewNonce) });
|
|
11235
11393
|
}
|
|
11236
11394
|
const Panel = current.Panel;
|
|
11237
|
-
const panelBody = current.label === "Settings" ? /* @__PURE__ */
|
|
11395
|
+
const panelBody = current.label === "Settings" ? /* @__PURE__ */ jsx9(SettingsPanel, { active: true, focused: focus === "panel", viewApiKey: viewKey, onView: viewAccount, onAccountsChanged: syncAccounts }) : /* @__PURE__ */ jsx9(Panel, { active: focus === "panel" || current.label !== "Live", focused: focus === "panel" });
|
|
11238
11396
|
return (
|
|
11239
11397
|
// height rows-1 (not rows): once total output reaches stdout.rows ink stops
|
|
11240
11398
|
// diffing and clearTerminal-repaints every frame, which slides the banner.
|
|
11241
11399
|
// overflow hidden makes it a hard guarantee even if a panel over-renders.
|
|
11242
|
-
/* @__PURE__ */
|
|
11243
|
-
/* @__PURE__ */
|
|
11244
|
-
/* @__PURE__ */
|
|
11245
|
-
/* @__PURE__ */
|
|
11246
|
-
/* @__PURE__ */
|
|
11247
|
-
locked ? /* @__PURE__ */
|
|
11248
|
-
update2.kind === "updating" ? /* @__PURE__ */
|
|
11400
|
+
/* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", width: cols, height: rows - 1, paddingX: 1, paddingTop: 1, overflow: "hidden", children: [
|
|
11401
|
+
/* @__PURE__ */ jsx9(Banner, { cols }),
|
|
11402
|
+
/* @__PURE__ */ jsxs9(Text9, { wrap: "truncate", children: [
|
|
11403
|
+
/* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: "account: " }),
|
|
11404
|
+
/* @__PURE__ */ jsx9(Text9, { color: locked ? theme.warn : theme.accentBright, bold: true, children: acctLabel2 }),
|
|
11405
|
+
locked ? /* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: " \xB7 log in from Settings to unlock the dataroom" }) : accounts.length > 1 ? /* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: ` (${acctIdx + 1}/${accounts.length} \xB7 a switch \xB7 Settings to manage)` }) : /* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: " \xB7 Settings to add another" }),
|
|
11406
|
+
update2.kind === "updating" ? /* @__PURE__ */ jsx9(Text9, { color: theme.warn, children: ` \u2191 updating to v${update2.version}\u2026` }) : update2.kind === "updated" ? /* @__PURE__ */ jsx9(Text9, { color: theme.ok, bold: true, children: ` \u2191 v${update2.version} installed \u2014 restart (q, then solongate) to apply` }) : null
|
|
11249
11407
|
] }),
|
|
11250
|
-
/* @__PURE__ */
|
|
11251
|
-
/* @__PURE__ */
|
|
11408
|
+
/* @__PURE__ */ jsxs9(Box9, { marginTop: 1, flexGrow: 1, children: [
|
|
11409
|
+
/* @__PURE__ */ jsx9(Box9, { flexDirection: "column", flexShrink: 0, width: 16, borderStyle: "round", borderColor: focus === "nav" ? theme.accent : "gray", paddingX: 1, children: SECTIONS.map((s, i) => {
|
|
11252
11410
|
const isCur = i === effectiveSection;
|
|
11253
11411
|
const disabled = locked && s.label !== "Settings";
|
|
11254
|
-
return /* @__PURE__ */
|
|
11412
|
+
return /* @__PURE__ */ jsx9(Text9, { color: isCur ? theme.accentBright : disabled ? theme.dim : void 0, bold: isCur, dimColor: disabled, children: (isCur ? "\u25B8 " : disabled ? "\u2298 " : " ") + s.label }, s.label);
|
|
11255
11413
|
}) }),
|
|
11256
|
-
/* @__PURE__ */
|
|
11414
|
+
/* @__PURE__ */ jsx9(Box9, { flexGrow: 1, minWidth: 0, borderStyle: "round", borderColor: focus === "panel" ? theme.accent : "gray", paddingX: 1, paddingY: 0, overflow: "hidden", children: panelBody })
|
|
11257
11415
|
] }, viewNonce),
|
|
11258
|
-
/* @__PURE__ */
|
|
11416
|
+
/* @__PURE__ */ jsx9(Box9, { children: locked ? /* @__PURE__ */ jsx9(KeyHints, { hints: [["\u2192/enter", "open Settings"], ["n", "log in"], ["q", "quit"]] }) : focus === "nav" ? /* @__PURE__ */ jsx9(KeyHints, { hints: [["\u2191\u2193", "section"], ["\u2192/enter", "open"], ...accounts.length > 1 ? [["a", "account"]] : [], ["?", "help"], ["q", "quit"]] }) : /* @__PURE__ */ jsx9(KeyHints, { hints: [["\u2190/esc", "back"], ["\u2191\u2193", "in-panel"], ["space/s", "act"]] }) })
|
|
11259
11417
|
] })
|
|
11260
11418
|
);
|
|
11261
11419
|
}
|
|
11262
11420
|
function HelpOverlay({ cols, rows }) {
|
|
11263
|
-
return /* @__PURE__ */
|
|
11264
|
-
/* @__PURE__ */
|
|
11265
|
-
/* @__PURE__ */
|
|
11266
|
-
/* @__PURE__ */
|
|
11267
|
-
keys.map(([k, desc]) => /* @__PURE__ */
|
|
11268
|
-
/* @__PURE__ */
|
|
11269
|
-
/* @__PURE__ */
|
|
11421
|
+
return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", width: cols, height: rows, paddingX: 2, paddingTop: 1, children: [
|
|
11422
|
+
/* @__PURE__ */ jsx9(Text9, { bold: true, color: theme.accentBright, children: "SolonGate \u2014 keyboard shortcuts" }),
|
|
11423
|
+
/* @__PURE__ */ jsx9(Box9, { marginTop: 1, flexDirection: "column", children: HELP.map(([group, keys]) => /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", marginBottom: 1, children: [
|
|
11424
|
+
/* @__PURE__ */ jsx9(Text9, { bold: true, color: theme.accent, children: group }),
|
|
11425
|
+
keys.map(([k, desc]) => /* @__PURE__ */ jsxs9(Text9, { children: [
|
|
11426
|
+
/* @__PURE__ */ jsx9(Text9, { color: theme.accentBright, children: (" " + k).padEnd(16) }),
|
|
11427
|
+
/* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: desc })
|
|
11270
11428
|
] }, k))
|
|
11271
11429
|
] }, group)) }),
|
|
11272
|
-
/* @__PURE__ */
|
|
11430
|
+
/* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: "press any key to close" })
|
|
11273
11431
|
] });
|
|
11274
11432
|
}
|
|
11275
11433
|
var SECTIONS, BANNER_HEX, SETTINGS_SECTION, HELP;
|
|
@@ -11284,6 +11442,7 @@ var init_App = __esm({
|
|
|
11284
11442
|
init_RateLimit();
|
|
11285
11443
|
init_Dlp();
|
|
11286
11444
|
init_Audit();
|
|
11445
|
+
init_DryRun();
|
|
11287
11446
|
init_Settings();
|
|
11288
11447
|
init_hooks();
|
|
11289
11448
|
init_client();
|
|
@@ -11294,6 +11453,7 @@ var init_App = __esm({
|
|
|
11294
11453
|
{ label: "Policies", Panel: PoliciesPanel },
|
|
11295
11454
|
{ label: "Rate Limit", Panel: RateLimitPanel },
|
|
11296
11455
|
{ label: "DLP", Panel: DlpPanel },
|
|
11456
|
+
{ label: "Dry Run", Panel: DryRunPanel },
|
|
11297
11457
|
{ label: "Audit", Panel: AuditPanel },
|
|
11298
11458
|
{ label: "Settings", Panel: SettingsPanel }
|
|
11299
11459
|
];
|
|
@@ -11321,7 +11481,7 @@ import { appendFileSync as appendFileSync2, mkdirSync as mkdirSync9 } from "fs";
|
|
|
11321
11481
|
import { homedir as homedir10 } from "os";
|
|
11322
11482
|
import { join as join12 } from "path";
|
|
11323
11483
|
import { render } from "ink";
|
|
11324
|
-
import { jsx as
|
|
11484
|
+
import { jsx as jsx10 } from "react/jsx-runtime";
|
|
11325
11485
|
async function launchTui() {
|
|
11326
11486
|
if (!process.stdout.isTTY || !process.stdin.isTTY) {
|
|
11327
11487
|
process.stderr.write(
|
|
@@ -11346,7 +11506,7 @@ async function launchTui() {
|
|
|
11346
11506
|
console.info = toFile("info");
|
|
11347
11507
|
console.debug = toFile("debug");
|
|
11348
11508
|
try {
|
|
11349
|
-
const { waitUntilExit } = render(/* @__PURE__ */
|
|
11509
|
+
const { waitUntilExit } = render(/* @__PURE__ */ jsx10(App, {}), { patchConsole: false });
|
|
11350
11510
|
await waitUntilExit();
|
|
11351
11511
|
} finally {
|
|
11352
11512
|
Object.assign(console, saved);
|