@solongate/proxy 0.82.31 → 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 +595 -447
- package/dist/tui/index.js +583 -443
- 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();
|
|
@@ -8934,8 +9103,8 @@ function PoliciesPanel({ focused }) {
|
|
|
8934
9103
|
setView("rule");
|
|
8935
9104
|
} else if (input === "D") {
|
|
8936
9105
|
if (selected) {
|
|
8937
|
-
|
|
8938
|
-
setStatus(
|
|
9106
|
+
requestDryRun(selected.id);
|
|
9107
|
+
setStatus('Sent to Dry Run - open the "Dry Run" section in the left nav for the full report.');
|
|
8939
9108
|
}
|
|
8940
9109
|
} else if (input === "s") void save();
|
|
8941
9110
|
else if (input === "x") discard();
|
|
@@ -8969,35 +9138,35 @@ function PoliciesPanel({ focused }) {
|
|
|
8969
9138
|
const lWin = policies.slice(lStart, lStart + lBudget);
|
|
8970
9139
|
const lAbove = lStart;
|
|
8971
9140
|
const lBelow = Math.max(0, policies.length - (lStart + lBudget));
|
|
8972
|
-
return /* @__PURE__ */
|
|
8973
|
-
/* @__PURE__ */
|
|
8974
|
-
/* @__PURE__ */
|
|
8975
|
-
activeQ.loading && !activeQ.data ? /* @__PURE__ */
|
|
8976
|
-
/* @__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: [
|
|
8977
9146
|
"\u25CF ",
|
|
8978
9147
|
truncate2(activeName, 28)
|
|
8979
9148
|
] }),
|
|
8980
|
-
/* @__PURE__ */
|
|
8981
|
-
] }) : /* @__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" })
|
|
8982
9151
|
] }),
|
|
8983
|
-
/* @__PURE__ */
|
|
8984
|
-
/* @__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) => {
|
|
8985
9154
|
const i = lStart + wi;
|
|
8986
|
-
return /* @__PURE__ */
|
|
9155
|
+
return /* @__PURE__ */ jsxs4(Text4, { color: i === pi ? theme.accentBright : void 0, bold: i === pi, children: [
|
|
8987
9156
|
(i === pi ? "\u25B8 " : " ") + truncate2(p.name, 26).padEnd(27),
|
|
8988
|
-
/* @__PURE__ */
|
|
9157
|
+
/* @__PURE__ */ jsxs4(Text4, { color: theme.dim, children: [
|
|
8989
9158
|
p.mode.padEnd(10),
|
|
8990
9159
|
" ",
|
|
8991
9160
|
p.rules.length,
|
|
8992
9161
|
" rules"
|
|
8993
9162
|
] }),
|
|
8994
|
-
p.id === activeId ? /* @__PURE__ */
|
|
9163
|
+
p.id === activeId ? /* @__PURE__ */ jsx4(Text4, { color: theme.ok, bold: true, children: " \u25CF ACTIVE" }) : null
|
|
8995
9164
|
] }, p.id);
|
|
8996
9165
|
}) }),
|
|
8997
|
-
status ? /* @__PURE__ */
|
|
9166
|
+
status ? /* @__PURE__ */ jsx4(Text4, { color: status.startsWith("\u2717") ? theme.bad : theme.ok, children: status }) : null
|
|
8998
9167
|
] }) });
|
|
8999
9168
|
}
|
|
9000
|
-
const dirtyTag = dirty ? /* @__PURE__ */
|
|
9169
|
+
const dirtyTag = dirty ? /* @__PURE__ */ jsx4(Text4, { color: theme.warn, children: " \u25CF unsaved (s save \xB7 x discard)" }) : null;
|
|
9001
9170
|
if (view === "rules") {
|
|
9002
9171
|
const rStatusLines = status ? status.split("\n").length : 0;
|
|
9003
9172
|
const rHead = 4 + rStatusLines;
|
|
@@ -9007,16 +9176,16 @@ function PoliciesPanel({ focused }) {
|
|
|
9007
9176
|
const rWin = rules.slice(rStart, rStart + rBudget);
|
|
9008
9177
|
const rAbove = rStart;
|
|
9009
9178
|
const rBelow = Math.max(0, rules.length - (rStart + rBudget));
|
|
9010
|
-
return /* @__PURE__ */
|
|
9011
|
-
/* @__PURE__ */
|
|
9012
|
-
/* @__PURE__ */
|
|
9013
|
-
/* @__PURE__ */
|
|
9014
|
-
/* @__PURE__ */
|
|
9015
|
-
/* @__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` }),
|
|
9016
9185
|
dirtyTag
|
|
9017
9186
|
] }),
|
|
9018
|
-
/* @__PURE__ */
|
|
9019
|
-
/* @__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(
|
|
9020
9189
|
Table,
|
|
9021
9190
|
{
|
|
9022
9191
|
columns: [
|
|
@@ -9042,24 +9211,24 @@ function PoliciesPanel({ focused }) {
|
|
|
9042
9211
|
})
|
|
9043
9212
|
}
|
|
9044
9213
|
) }),
|
|
9045
|
-
rules.length === 0 ? /* @__PURE__ */
|
|
9046
|
-
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
|
|
9047
9216
|
] }) });
|
|
9048
9217
|
}
|
|
9049
9218
|
const rule = rules[ri];
|
|
9050
|
-
return /* @__PURE__ */
|
|
9051
|
-
/* @__PURE__ */
|
|
9052
|
-
/* @__PURE__ */
|
|
9053
|
-
/* @__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 ?? "" }),
|
|
9054
9223
|
dirtyTag
|
|
9055
9224
|
] }),
|
|
9056
|
-
/* @__PURE__ */
|
|
9057
|
-
/* @__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) => {
|
|
9058
9227
|
const val = rule ? f.get(rule) : "";
|
|
9059
9228
|
const active2 = i === fi;
|
|
9060
|
-
return /* @__PURE__ */
|
|
9061
|
-
/* @__PURE__ */
|
|
9062
|
-
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(
|
|
9063
9232
|
TextInput2,
|
|
9064
9233
|
{
|
|
9065
9234
|
value: editVal,
|
|
@@ -9069,8 +9238,8 @@ function PoliciesPanel({ focused }) {
|
|
|
9069
9238
|
setEditing(false);
|
|
9070
9239
|
}
|
|
9071
9240
|
}
|
|
9072
|
-
) : /* @__PURE__ */
|
|
9073
|
-
|
|
9241
|
+
) : /* @__PURE__ */ jsx4(
|
|
9242
|
+
Text4,
|
|
9074
9243
|
{
|
|
9075
9244
|
color: f.kind === "effect" ? val === "ALLOW" ? theme.ok : theme.bad : void 0,
|
|
9076
9245
|
dimColor: !val,
|
|
@@ -9079,19 +9248,18 @@ function PoliciesPanel({ focused }) {
|
|
|
9079
9248
|
)
|
|
9080
9249
|
] }, f.label);
|
|
9081
9250
|
}) }),
|
|
9082
|
-
status ? /* @__PURE__ */
|
|
9251
|
+
status ? /* @__PURE__ */ jsx4(Text4, { color: status.startsWith("\u2717") ? theme.bad : theme.ok, children: status }) : null
|
|
9083
9252
|
] });
|
|
9084
9253
|
}
|
|
9085
|
-
var
|
|
9254
|
+
var constr, setConstr, FIELDS;
|
|
9086
9255
|
var init_Policies = __esm({
|
|
9087
9256
|
"src/tui/panels/Policies.tsx"() {
|
|
9088
9257
|
"use strict";
|
|
9089
9258
|
init_api_client();
|
|
9090
|
-
|
|
9259
|
+
init_DryRun();
|
|
9091
9260
|
init_components();
|
|
9092
9261
|
init_hooks();
|
|
9093
9262
|
init_theme();
|
|
9094
|
-
DASHBOARD_URL = "https://dashboard.solongate.com";
|
|
9095
9263
|
constr = (r, g, side) => (r[g]?.[side] ?? []).join(", ");
|
|
9096
9264
|
setConstr = (r, g, side, val) => {
|
|
9097
9265
|
const arr = val.split(",").map((s) => s.trim()).filter(Boolean);
|
|
@@ -9117,19 +9285,19 @@ var init_Policies = __esm({
|
|
|
9117
9285
|
});
|
|
9118
9286
|
|
|
9119
9287
|
// src/tui/panels/RateLimit.tsx
|
|
9120
|
-
import { Box as
|
|
9121
|
-
import { useEffect as
|
|
9122
|
-
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";
|
|
9123
9291
|
function RateLimitPanel({ focused }) {
|
|
9124
9292
|
const { cols, rows } = usePanelSize();
|
|
9125
9293
|
const layersQ = useLoader(() => api.settings.getSecurityLayers());
|
|
9126
9294
|
const historyQ = useLoader(() => api.settings.getRateLimitHistory());
|
|
9127
9295
|
const insightsQ = useLoader(() => api.stats.securityInsights(7));
|
|
9128
|
-
const [draft, setDraft] =
|
|
9129
|
-
const [dirty, setDirty] =
|
|
9130
|
-
const [sel, setSel] =
|
|
9131
|
-
const [status, setStatus] =
|
|
9132
|
-
|
|
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(() => {
|
|
9133
9301
|
if (layersQ.data && !dirty) setDraft({ ...layersQ.data.layers.rateLimit });
|
|
9134
9302
|
}, [layersQ.data]);
|
|
9135
9303
|
usePoll(() => {
|
|
@@ -9177,7 +9345,7 @@ function RateLimitPanel({ focused }) {
|
|
|
9177
9345
|
const fi = onField ? selC : -1;
|
|
9178
9346
|
const bcur = onField ? -1 : selC - 4;
|
|
9179
9347
|
const off = bcur < 0 ? 0 : Math.min(Math.max(0, bcur - Math.floor(burstBudget / 2)), maxOff);
|
|
9180
|
-
|
|
9348
|
+
useInput4(
|
|
9181
9349
|
(input, key) => {
|
|
9182
9350
|
const step = key.shift ? 10 : 1;
|
|
9183
9351
|
if (key.upArrow) setSel((n) => Math.max(0, n - 1));
|
|
@@ -9196,48 +9364,48 @@ function RateLimitPanel({ focused }) {
|
|
|
9196
9364
|
},
|
|
9197
9365
|
{ isActive: focused }
|
|
9198
9366
|
);
|
|
9199
|
-
return /* @__PURE__ */
|
|
9367
|
+
return /* @__PURE__ */ jsx5(DataView, { loading: layersQ.loading && !draft, error: layersQ.error, children: draft ? (() => {
|
|
9200
9368
|
const lim = draft.perMinute;
|
|
9201
9369
|
const now = insightsQ.data ? insightsQ.data["activity"]?.minute?.slice(-1)[0]?.count ?? 0 : 0;
|
|
9202
9370
|
const loadPct = lim > 0 ? Math.min(100, Math.round(now / lim * 100)) : 0;
|
|
9203
9371
|
const last24h = (insightsQ.data?.["activity"]?.hour ?? []).reduce((s, b) => s + b.count, 0);
|
|
9204
9372
|
const shown = anomalies2.slice(off, off + burstBudget);
|
|
9205
9373
|
const bw = Math.max(10, cols - 30);
|
|
9206
|
-
return /* @__PURE__ */
|
|
9207
|
-
/* @__PURE__ */
|
|
9208
|
-
/* @__PURE__ */
|
|
9209
|
-
/* @__PURE__ */
|
|
9210
|
-
/* @__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" })
|
|
9211
9379
|
] }),
|
|
9212
|
-
/* @__PURE__ */
|
|
9213
|
-
/* @__PURE__ */
|
|
9214
|
-
/* @__PURE__ */
|
|
9215
|
-
showExtras && /* @__PURE__ */
|
|
9216
|
-
hasLoad ? /* @__PURE__ */
|
|
9217
|
-
/* @__PURE__ */
|
|
9218
|
-
/* @__PURE__ */
|
|
9219
|
-
/* @__PURE__ */
|
|
9220
|
-
/* @__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}%)` })
|
|
9221
9389
|
] }) : null,
|
|
9222
|
-
/* @__PURE__ */
|
|
9390
|
+
/* @__PURE__ */ jsxs5(Text5, { color: theme.accentBright, bold: true, wrap: "truncate", children: [
|
|
9223
9391
|
"Busiest 7d",
|
|
9224
|
-
/* @__PURE__ */
|
|
9392
|
+
/* @__PURE__ */ jsx5(Text5, { color: theme.dim, children: " most calls in one window vs your limit" })
|
|
9225
9393
|
] }),
|
|
9226
|
-
/* @__PURE__ */
|
|
9227
|
-
/* @__PURE__ */
|
|
9228
|
-
/* @__PURE__ */
|
|
9229
|
-
/* @__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` })
|
|
9230
9398
|
] }),
|
|
9231
|
-
/* @__PURE__ */
|
|
9232
|
-
/* @__PURE__ */
|
|
9399
|
+
/* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", children: [
|
|
9400
|
+
/* @__PURE__ */ jsxs5(Text5, { color: theme.accentBright, bold: true, wrap: "truncate", children: [
|
|
9233
9401
|
`Recent bursts 7d${anomalies2.length ? ` (${anomalies2.length})` : ""}`,
|
|
9234
|
-
maxOff > 0 ? /* @__PURE__ */
|
|
9235
|
-
/* @__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)" })
|
|
9236
9404
|
] }),
|
|
9237
|
-
anomalies2.length === 0 ? /* @__PURE__ */
|
|
9405
|
+
anomalies2.length === 0 ? /* @__PURE__ */ jsxs5(Text5, { color: theme.dim, children: [
|
|
9238
9406
|
" ",
|
|
9239
9407
|
insightsQ.loading ? "loading\u2026" : insightsQ.error ? `couldn't load bursts: ${String(insightsQ.error).slice(0, 60)}` : "no bursts in the last 7 days"
|
|
9240
|
-
] }) : /* @__PURE__ */
|
|
9408
|
+
] }) : /* @__PURE__ */ jsx5(
|
|
9241
9409
|
Table,
|
|
9242
9410
|
{
|
|
9243
9411
|
columns: [{ header: "WHEN", width: 15 }, { header: "RESULT", width: 9 }, { header: "CALLS", width: 7 }, { header: "AGENT", width: Math.max(8, bw - 31) }],
|
|
@@ -9253,13 +9421,13 @@ function RateLimitPanel({ focused }) {
|
|
|
9253
9421
|
}
|
|
9254
9422
|
)
|
|
9255
9423
|
] }),
|
|
9256
|
-
/* @__PURE__ */
|
|
9257
|
-
/* @__PURE__ */
|
|
9258
|
-
/* @__PURE__ */
|
|
9259
|
-
/* @__PURE__ */
|
|
9260
|
-
lastChange ? /* @__PURE__ */
|
|
9261
|
-
dirty ? /* @__PURE__ */
|
|
9262
|
-
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
|
|
9263
9431
|
] })
|
|
9264
9432
|
] });
|
|
9265
9433
|
})() : null });
|
|
@@ -9267,15 +9435,15 @@ function RateLimitPanel({ focused }) {
|
|
|
9267
9435
|
function BusiestRow({ label, peak, limit }) {
|
|
9268
9436
|
const ctx = limit > 0 ? peak > limit ? `over ${limit}` : peak === limit ? `at limit ${limit}` : `limit ${limit}` : "no limit set";
|
|
9269
9437
|
const hot = limit > 0 && peak > limit;
|
|
9270
|
-
return /* @__PURE__ */
|
|
9271
|
-
/* @__PURE__ */
|
|
9272
|
-
/* @__PURE__ */
|
|
9273
|
-
/* @__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 })
|
|
9274
9442
|
] });
|
|
9275
9443
|
}
|
|
9276
9444
|
function FieldRow({ label, active: active2, children }) {
|
|
9277
|
-
return /* @__PURE__ */
|
|
9278
|
-
/* @__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) }),
|
|
9279
9447
|
children
|
|
9280
9448
|
] });
|
|
9281
9449
|
}
|
|
@@ -9297,24 +9465,24 @@ var init_RateLimit = __esm({
|
|
|
9297
9465
|
});
|
|
9298
9466
|
|
|
9299
9467
|
// src/tui/panels/Dlp.tsx
|
|
9300
|
-
import { Box as
|
|
9468
|
+
import { Box as Box6, Text as Text6, useInput as useInput5 } from "ink";
|
|
9301
9469
|
import TextInput3 from "ink-text-input";
|
|
9302
|
-
import { useEffect as
|
|
9303
|
-
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";
|
|
9304
9472
|
function DlpPanel({ focused }) {
|
|
9305
9473
|
const { cols, rows } = usePanelSize();
|
|
9306
9474
|
const q = useLoader(() => api.settings.getSecurityLayers());
|
|
9307
|
-
const [dlp, setDlp] =
|
|
9308
|
-
const [available, setAvailable] =
|
|
9309
|
-
const [ghostOn, setGhostOn] =
|
|
9310
|
-
const [ghostPats, setGhostPats] =
|
|
9311
|
-
const [sel, setSel] =
|
|
9312
|
-
const [dirty, setDirty] =
|
|
9313
|
-
const [status, setStatus] =
|
|
9314
|
-
const [adding, setAdding] =
|
|
9315
|
-
const [newName, setNewName] =
|
|
9316
|
-
const [input, setInput] =
|
|
9317
|
-
|
|
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(() => {
|
|
9318
9486
|
if (q.data && !dirty) {
|
|
9319
9487
|
setDlp({ ...q.data.layers.dlp, patterns: [...q.data.layers.dlp.patterns], custom: [...q.data.layers.dlp.custom] });
|
|
9320
9488
|
setAvailable(q.data.availablePatterns);
|
|
@@ -9361,7 +9529,7 @@ function DlpPanel({ focused }) {
|
|
|
9361
9529
|
];
|
|
9362
9530
|
const selC = Math.min(sel, Math.max(0, entries.length - 1));
|
|
9363
9531
|
const cur = entries[selC];
|
|
9364
|
-
|
|
9532
|
+
useInput5(
|
|
9365
9533
|
(input2, key) => {
|
|
9366
9534
|
if (!dlp) return;
|
|
9367
9535
|
if (key.ctrl && input2 === "r") {
|
|
@@ -9406,13 +9574,13 @@ function DlpPanel({ focused }) {
|
|
|
9406
9574
|
const enabled = new Set(dlp?.patterns ?? []);
|
|
9407
9575
|
const lines = [];
|
|
9408
9576
|
const header = (key, label, extra) => lines.push({
|
|
9409
|
-
node: /* @__PURE__ */
|
|
9410
|
-
/* @__PURE__ */
|
|
9411
|
-
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
|
|
9412
9580
|
] }, key),
|
|
9413
9581
|
entry: -1
|
|
9414
9582
|
});
|
|
9415
|
-
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 });
|
|
9416
9584
|
let ei = 0;
|
|
9417
9585
|
header("h:builtin", "built-in secret patterns", "space toggles on/off");
|
|
9418
9586
|
available.forEach((p) => {
|
|
@@ -9420,10 +9588,10 @@ function DlpPanel({ focused }) {
|
|
|
9420
9588
|
const isCur = focused && ei === selC;
|
|
9421
9589
|
const idx = ei++;
|
|
9422
9590
|
lines.push({
|
|
9423
|
-
node: /* @__PURE__ */
|
|
9424
|
-
/* @__PURE__ */
|
|
9425
|
-
/* @__PURE__ */
|
|
9426
|
-
/* @__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 })
|
|
9427
9595
|
] }, "b:" + p),
|
|
9428
9596
|
entry: idx
|
|
9429
9597
|
});
|
|
@@ -9435,10 +9603,10 @@ function DlpPanel({ focused }) {
|
|
|
9435
9603
|
const isCur = focused && ei === selC;
|
|
9436
9604
|
const idx = ei++;
|
|
9437
9605
|
lines.push({
|
|
9438
|
-
node: /* @__PURE__ */
|
|
9439
|
-
/* @__PURE__ */
|
|
9440
|
-
/* @__PURE__ */
|
|
9441
|
-
/* @__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)) })
|
|
9442
9610
|
] }, "c:" + c2.name + i),
|
|
9443
9611
|
entry: idx
|
|
9444
9612
|
});
|
|
@@ -9450,10 +9618,10 @@ function DlpPanel({ focused }) {
|
|
|
9450
9618
|
const isCur = focused && ei === selC;
|
|
9451
9619
|
const idx = ei++;
|
|
9452
9620
|
lines.push({
|
|
9453
|
-
node: /* @__PURE__ */
|
|
9454
|
-
/* @__PURE__ */
|
|
9455
|
-
/* @__PURE__ */
|
|
9456
|
-
!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
|
|
9457
9625
|
] }, "g:" + p + i),
|
|
9458
9626
|
entry: idx
|
|
9459
9627
|
});
|
|
@@ -9467,17 +9635,17 @@ function DlpPanel({ focused }) {
|
|
|
9467
9635
|
const win = lines.slice(start, start + budget);
|
|
9468
9636
|
const moreAbove = start;
|
|
9469
9637
|
const moreBelow = Math.max(0, lines.length - (start + budget));
|
|
9470
|
-
return /* @__PURE__ */
|
|
9471
|
-
/* @__PURE__ */
|
|
9472
|
-
/* @__PURE__ */
|
|
9473
|
-
/* @__PURE__ */
|
|
9474
|
-
/* @__PURE__ */
|
|
9475
|
-
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
|
|
9476
9644
|
] }),
|
|
9477
|
-
/* @__PURE__ */
|
|
9478
|
-
adding ? /* @__PURE__ */
|
|
9479
|
-
/* @__PURE__ */
|
|
9480
|
-
/* @__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(
|
|
9481
9649
|
TextInput3,
|
|
9482
9650
|
{
|
|
9483
9651
|
value: input,
|
|
@@ -9504,8 +9672,8 @@ function DlpPanel({ focused }) {
|
|
|
9504
9672
|
}
|
|
9505
9673
|
)
|
|
9506
9674
|
] }) }) : null,
|
|
9507
|
-
/* @__PURE__ */
|
|
9508
|
-
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
|
|
9509
9677
|
] }) : null });
|
|
9510
9678
|
}
|
|
9511
9679
|
var MODES2;
|
|
@@ -9521,13 +9689,13 @@ var init_Dlp = __esm({
|
|
|
9521
9689
|
});
|
|
9522
9690
|
|
|
9523
9691
|
// src/tui/panels/Audit.tsx
|
|
9524
|
-
import { Box as
|
|
9692
|
+
import { Box as Box7, Text as Text7, useInput as useInput6 } from "ink";
|
|
9525
9693
|
import TextInput4 from "ink-text-input";
|
|
9526
9694
|
import { mkdirSync as mkdirSync7, writeFileSync as writeFileSync8 } from "fs";
|
|
9527
9695
|
import { homedir as homedir8 } from "os";
|
|
9528
9696
|
import { join as join10 } from "path";
|
|
9529
|
-
import { useState as
|
|
9530
|
-
import { jsx as
|
|
9697
|
+
import { useState as useState7 } from "react";
|
|
9698
|
+
import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
9531
9699
|
function loadLocalRows() {
|
|
9532
9700
|
return parseLocalLines(tailLines(LOCAL_LOG, LOCAL_MAX_BYTES)).map((j, i) => {
|
|
9533
9701
|
const rs = reasonSignals(j.reason);
|
|
@@ -9552,25 +9720,25 @@ function loadLocalRows() {
|
|
|
9552
9720
|
}
|
|
9553
9721
|
function AuditPanel({ active: active2, focused }) {
|
|
9554
9722
|
const { cols, rows } = usePanelSize();
|
|
9555
|
-
const [source, setSource] =
|
|
9556
|
-
const [view, setView] =
|
|
9557
|
-
const [di, setDi] =
|
|
9558
|
-
const [gi, setGi] =
|
|
9559
|
-
const [tool, setTool] =
|
|
9560
|
-
const [agent, setAgent] =
|
|
9561
|
-
const [search, setSearch] =
|
|
9562
|
-
const [sessFilter, setSessFilter] =
|
|
9563
|
-
const [page, setPage] =
|
|
9564
|
-
const [sel, setSel] =
|
|
9565
|
-
const [detailScroll, setDetailScroll] =
|
|
9566
|
-
const [editing, setEditing] =
|
|
9567
|
-
const [si, setSi] =
|
|
9568
|
-
const [sessSearch, setSessSearch] =
|
|
9569
|
-
const [sessSel, setSessSel] =
|
|
9570
|
-
const [confirm, setConfirm] =
|
|
9571
|
-
const [msg, setMsg] =
|
|
9572
|
-
const [showHelp, setShowHelp] =
|
|
9573
|
-
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);
|
|
9574
9742
|
const toTop = () => setSel(0);
|
|
9575
9743
|
const statsQ = useLoader(() => source === "cloud" ? api.stats.get() : Promise.resolve(null), [source]);
|
|
9576
9744
|
usePoll(statsQ.reloadQuiet, 15e3, active2 && source === "cloud" && !frozen);
|
|
@@ -9689,7 +9857,7 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
9689
9857
|
};
|
|
9690
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" }));
|
|
9691
9859
|
};
|
|
9692
|
-
|
|
9860
|
+
useInput6(
|
|
9693
9861
|
(input, key) => {
|
|
9694
9862
|
if (input === " ") {
|
|
9695
9863
|
setFrozen((f) => !f);
|
|
@@ -9823,58 +9991,58 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
9823
9991
|
{ isActive: focused && !editing }
|
|
9824
9992
|
);
|
|
9825
9993
|
const localAll = localQ.data ?? [];
|
|
9826
|
-
const strip = source === "cloud" ? /* @__PURE__ */
|
|
9827
|
-
/* @__PURE__ */
|
|
9828
|
-
/* @__PURE__ */
|
|
9829
|
-
/* @__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: [
|
|
9830
9998
|
statsQ.data?.allowed ?? "\xB7\xB7\xB7",
|
|
9831
9999
|
" allow"
|
|
9832
10000
|
] }),
|
|
9833
|
-
/* @__PURE__ */
|
|
9834
|
-
/* @__PURE__ */
|
|
10001
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: " \xB7 " }),
|
|
10002
|
+
/* @__PURE__ */ jsxs7(Text7, { color: theme.bad, children: [
|
|
9835
10003
|
statsQ.data?.denied ?? "\xB7\xB7",
|
|
9836
10004
|
" deny"
|
|
9837
10005
|
] }),
|
|
9838
|
-
/* @__PURE__ */
|
|
9839
|
-
] }) : /* @__PURE__ */
|
|
9840
|
-
/* @__PURE__ */
|
|
9841
|
-
/* @__PURE__ */
|
|
9842
|
-
/* @__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: [
|
|
9843
10011
|
localAll.filter((r) => r.decision === "ALLOW").length,
|
|
9844
10012
|
" allow"
|
|
9845
10013
|
] }),
|
|
9846
|
-
/* @__PURE__ */
|
|
9847
|
-
/* @__PURE__ */
|
|
10014
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: " \xB7 " }),
|
|
10015
|
+
/* @__PURE__ */ jsxs7(Text7, { color: theme.bad, children: [
|
|
9848
10016
|
localAll.filter((r) => r.decision !== "ALLOW").length,
|
|
9849
10017
|
" deny"
|
|
9850
10018
|
] }),
|
|
9851
|
-
/* @__PURE__ */
|
|
10019
|
+
/* @__PURE__ */ jsxs7(Text7, { color: theme.dim, children: [
|
|
9852
10020
|
" \xB7 ",
|
|
9853
10021
|
LOCAL_LOG
|
|
9854
10022
|
] })
|
|
9855
10023
|
] });
|
|
9856
|
-
const copyBanner = frozen ? /* @__PURE__ */
|
|
9857
|
-
const srcChip = /* @__PURE__ */
|
|
9858
|
-
/* @__PURE__ */
|
|
9859
|
-
/* @__PURE__ */
|
|
9860
|
-
/* @__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) " })
|
|
9861
10029
|
] });
|
|
9862
10030
|
if (showHelp) {
|
|
9863
|
-
const colOf = (groups) => /* @__PURE__ */
|
|
9864
|
-
/* @__PURE__ */
|
|
9865
|
-
keys.map(([k, desc]) => /* @__PURE__ */
|
|
9866
|
-
/* @__PURE__ */
|
|
9867
|
-
/* @__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 })
|
|
9868
10036
|
] }, k))
|
|
9869
10037
|
] }, group)) });
|
|
9870
|
-
return /* @__PURE__ */
|
|
10038
|
+
return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
|
|
9871
10039
|
copyBanner,
|
|
9872
|
-
/* @__PURE__ */
|
|
10040
|
+
/* @__PURE__ */ jsxs7(Text7, { bold: true, color: theme.accentBright, children: [
|
|
9873
10041
|
"AUDIT \u2014 all keys",
|
|
9874
10042
|
" ",
|
|
9875
|
-
/* @__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)" })
|
|
9876
10044
|
] }),
|
|
9877
|
-
/* @__PURE__ */
|
|
10045
|
+
/* @__PURE__ */ jsxs7(Box7, { marginTop: 1, children: [
|
|
9878
10046
|
colOf(AUDIT_HELP.slice(0, 1)),
|
|
9879
10047
|
colOf(AUDIT_HELP.slice(1))
|
|
9880
10048
|
] })
|
|
@@ -9893,53 +10061,53 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
9893
10061
|
const maxScroll = Math.max(0, contentLines.length - bodyRows);
|
|
9894
10062
|
const off = Math.min(detailScroll, maxScroll);
|
|
9895
10063
|
const win = contentLines.slice(off, off + bodyRows);
|
|
9896
|
-
return /* @__PURE__ */
|
|
10064
|
+
return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
|
|
9897
10065
|
copyBanner,
|
|
9898
|
-
/* @__PURE__ */
|
|
9899
|
-
/* @__PURE__ */
|
|
9900
|
-
/* @__PURE__ */
|
|
9901
|
-
/* @__PURE__ */
|
|
9902
|
-
/* @__PURE__ */
|
|
9903
|
-
e.dlp.length ? /* @__PURE__ */
|
|
9904
|
-
e.burst ? /* @__PURE__ */
|
|
9905
|
-
/* @__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" })
|
|
9906
10074
|
] }),
|
|
9907
|
-
/* @__PURE__ */
|
|
9908
|
-
/* @__PURE__ */
|
|
9909
|
-
/* @__PURE__ */
|
|
9910
|
-
/* @__PURE__ */
|
|
9911
|
-
/* @__PURE__ */
|
|
9912
|
-
/* @__PURE__ */
|
|
9913
|
-
/* @__PURE__ */
|
|
9914
|
-
/* @__PURE__ */
|
|
9915
|
-
/* @__PURE__ */
|
|
9916
|
-
/* @__PURE__ */
|
|
9917
|
-
/* @__PURE__ */
|
|
9918
|
-
/* @__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" })
|
|
9919
10087
|
] }),
|
|
9920
|
-
/* @__PURE__ */
|
|
9921
|
-
/* @__PURE__ */
|
|
9922
|
-
/* @__PURE__ */
|
|
9923
|
-
/* @__PURE__ */
|
|
9924
|
-
/* @__PURE__ */
|
|
9925
|
-
/* @__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" })
|
|
9926
10094
|
] }),
|
|
9927
|
-
/* @__PURE__ */
|
|
9928
|
-
/* @__PURE__ */
|
|
9929
|
-
/* @__PURE__ */
|
|
9930
|
-
/* @__PURE__ */
|
|
9931
|
-
/* @__PURE__ */
|
|
9932
|
-
/* @__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 " })
|
|
9933
10101
|
] })
|
|
9934
10102
|
] });
|
|
9935
10103
|
}
|
|
9936
|
-
const chip = (label, val, on) => /* @__PURE__ */
|
|
9937
|
-
/* @__PURE__ */
|
|
10104
|
+
const chip = (label, val, on) => /* @__PURE__ */ jsxs7(Text7, { children: [
|
|
10105
|
+
/* @__PURE__ */ jsxs7(Text7, { color: theme.dim, children: [
|
|
9938
10106
|
label,
|
|
9939
10107
|
":"
|
|
9940
10108
|
] }),
|
|
9941
|
-
/* @__PURE__ */
|
|
9942
|
-
/* @__PURE__ */
|
|
10109
|
+
/* @__PURE__ */ jsx7(Text7, { color: on ? theme.accentBright : theme.dim, children: val }),
|
|
10110
|
+
/* @__PURE__ */ jsx7(Text7, { children: " " })
|
|
9943
10111
|
] });
|
|
9944
10112
|
if (view === "sessions") {
|
|
9945
10113
|
const headerRows2 = 5 + (editing ? 1 : 0);
|
|
@@ -9947,20 +10115,20 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
9947
10115
|
const selC = Math.min(sessSel, Math.max(0, sessionsFiltered.length - 1));
|
|
9948
10116
|
const start2 = Math.min(Math.max(0, selC - Math.floor((listRows2 - 1) / 2)), Math.max(0, sessionsFiltered.length - listRows2));
|
|
9949
10117
|
const win = sessionsFiltered.slice(start2, start2 + listRows2);
|
|
9950
|
-
return /* @__PURE__ */
|
|
10118
|
+
return /* @__PURE__ */ jsx7(DataView, { loading: sessLoading && !frozen, error: source === "cloud" ? agentsQ.error : localQ.error, children: /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
|
|
9951
10119
|
strip,
|
|
9952
10120
|
copyBanner,
|
|
9953
|
-
/* @__PURE__ */
|
|
10121
|
+
/* @__PURE__ */ jsxs7(Box7, { children: [
|
|
9954
10122
|
srcChip,
|
|
9955
|
-
/* @__PURE__ */
|
|
9956
|
-
/* @__PURE__ */
|
|
10123
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.accentBright, bold: true, children: "SESSIONS" }),
|
|
10124
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: " \xB7 logs (v) " }),
|
|
9957
10125
|
chip("status", SESS_STATUS[si] ?? "all", si !== 0),
|
|
9958
10126
|
chip("search", sessSearch || "\xB7", !!sessSearch)
|
|
9959
10127
|
] }),
|
|
9960
|
-
/* @__PURE__ */
|
|
9961
|
-
editing === "sess-search" ? /* @__PURE__ */
|
|
9962
|
-
/* @__PURE__ */
|
|
9963
|
-
/* @__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(
|
|
9964
10132
|
TextInput4,
|
|
9965
10133
|
{
|
|
9966
10134
|
value: sessSearch,
|
|
@@ -9972,8 +10140,8 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
9972
10140
|
}
|
|
9973
10141
|
)
|
|
9974
10142
|
] }) : null,
|
|
9975
|
-
/* @__PURE__ */
|
|
9976
|
-
/* @__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(
|
|
9977
10145
|
Table,
|
|
9978
10146
|
{
|
|
9979
10147
|
columns: [
|
|
@@ -10004,7 +10172,7 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
10004
10172
|
})
|
|
10005
10173
|
}
|
|
10006
10174
|
),
|
|
10007
|
-
sessionsFiltered.length === 0 ? /* @__PURE__ */
|
|
10175
|
+
sessionsFiltered.length === 0 ? /* @__PURE__ */ jsxs7(Text7, { color: theme.dim, children: [
|
|
10008
10176
|
"(no sessions",
|
|
10009
10177
|
source === "local" ? " in the local file" : "",
|
|
10010
10178
|
")"
|
|
@@ -10017,13 +10185,13 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
10017
10185
|
const maxStart = Math.max(0, pageRows.length - listRows);
|
|
10018
10186
|
const start = Math.min(Math.max(0, selClamped - Math.floor((listRows - 1) / 2)), maxStart);
|
|
10019
10187
|
const windowed = pageRows.slice(start, start + listRows);
|
|
10020
|
-
return /* @__PURE__ */
|
|
10188
|
+
return /* @__PURE__ */ jsx7(DataView, { loading: logsLoading && !frozen, error: source === "cloud" ? cloudQ.error : localQ.error, children: /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
|
|
10021
10189
|
strip,
|
|
10022
10190
|
copyBanner,
|
|
10023
|
-
/* @__PURE__ */
|
|
10191
|
+
/* @__PURE__ */ jsxs7(Box7, { children: [
|
|
10024
10192
|
srcChip,
|
|
10025
|
-
/* @__PURE__ */
|
|
10026
|
-
/* @__PURE__ */
|
|
10193
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.accentBright, bold: true, children: "LOGS" }),
|
|
10194
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: " \xB7 sessions (v) " }),
|
|
10027
10195
|
chip("dec", DECISIONS[di] ?? "all", di !== 0),
|
|
10028
10196
|
chip("sig", SIGNALS[gi] ?? "all", gi !== 0),
|
|
10029
10197
|
chip("tool", tool || "\xB7", !!tool),
|
|
@@ -10031,14 +10199,14 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
10031
10199
|
chip("search", search || "\xB7", !!search),
|
|
10032
10200
|
sessFilter ? chip("sess", sessFilter.slice(0, 8), true) : null
|
|
10033
10201
|
] }),
|
|
10034
|
-
/* @__PURE__ */
|
|
10035
|
-
msg ? /* @__PURE__ */
|
|
10036
|
-
editing && editing !== "sess-search" ? /* @__PURE__ */
|
|
10037
|
-
/* @__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: [
|
|
10038
10206
|
editing,
|
|
10039
10207
|
": "
|
|
10040
10208
|
] }),
|
|
10041
|
-
/* @__PURE__ */
|
|
10209
|
+
/* @__PURE__ */ jsx7(
|
|
10042
10210
|
TextInput4,
|
|
10043
10211
|
{
|
|
10044
10212
|
value: editing === "tool" ? tool : editing === "agent" ? agent : search,
|
|
@@ -10051,9 +10219,9 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
10051
10219
|
}
|
|
10052
10220
|
)
|
|
10053
10221
|
] }) : null,
|
|
10054
|
-
/* @__PURE__ */
|
|
10055
|
-
/* @__PURE__ */
|
|
10056
|
-
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: [
|
|
10057
10225
|
"(no entries",
|
|
10058
10226
|
source === "local" ? " in the local file" : "",
|
|
10059
10227
|
" \u2014 c clears filters)"
|
|
@@ -10462,10 +10630,10 @@ var init_global_install = __esm({
|
|
|
10462
10630
|
});
|
|
10463
10631
|
|
|
10464
10632
|
// src/tui/panels/Settings.tsx
|
|
10465
|
-
import { Box as
|
|
10633
|
+
import { Box as Box8, Text as Text8, useInput as useInput7 } from "ink";
|
|
10466
10634
|
import TextInput5 from "ink-text-input";
|
|
10467
|
-
import { useEffect as
|
|
10468
|
-
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";
|
|
10469
10637
|
function SettingsPanel({
|
|
10470
10638
|
active: active2,
|
|
10471
10639
|
focused,
|
|
@@ -10475,16 +10643,16 @@ function SettingsPanel({
|
|
|
10475
10643
|
}) {
|
|
10476
10644
|
void active2;
|
|
10477
10645
|
const { cols, rows } = usePanelSize();
|
|
10478
|
-
const [sel, setSel] =
|
|
10479
|
-
const [editing, setEditing] =
|
|
10480
|
-
const [input, setInput] =
|
|
10481
|
-
const [confirmDel, setConfirmDel] =
|
|
10482
|
-
const [msg, setMsg] =
|
|
10483
|
-
const [busy, setBusy] =
|
|
10484
|
-
const [editor, setEditor] =
|
|
10485
|
-
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);
|
|
10486
10654
|
const ver = currentVersion();
|
|
10487
|
-
|
|
10655
|
+
useEffect7(() => {
|
|
10488
10656
|
let live2 = true;
|
|
10489
10657
|
latestVersion().then((v) => {
|
|
10490
10658
|
if (live2) setLatest(v);
|
|
@@ -10494,26 +10662,26 @@ function SettingsPanel({
|
|
|
10494
10662
|
live2 = false;
|
|
10495
10663
|
};
|
|
10496
10664
|
}, []);
|
|
10497
|
-
const [accounts, setAccounts] =
|
|
10498
|
-
const [login, setLogin] =
|
|
10499
|
-
const [tick, setTick] =
|
|
10665
|
+
const [accounts, setAccounts] = useState8(() => listAccounts());
|
|
10666
|
+
const [login, setLogin] = useState8(null);
|
|
10667
|
+
const [tick, setTick] = useState8(0);
|
|
10500
10668
|
const abort = useRef3(false);
|
|
10501
10669
|
const refreshAccounts = () => setAccounts(listAccounts());
|
|
10502
|
-
const [guardHere, setGuardHere] =
|
|
10503
|
-
const [guardVer, setGuardVer] =
|
|
10504
|
-
const [guardOld, setGuardOld] =
|
|
10670
|
+
const [guardHere, setGuardHere] = useState8(() => isGuardInstalled());
|
|
10671
|
+
const [guardVer, setGuardVer] = useState8(() => installedGuardVersion());
|
|
10672
|
+
const [guardOld, setGuardOld] = useState8(() => guardHookOutdated());
|
|
10505
10673
|
const refreshGuard = () => {
|
|
10506
10674
|
setGuardHere(isGuardInstalled());
|
|
10507
10675
|
setGuardVer(installedGuardVersion());
|
|
10508
10676
|
setGuardOld(guardHookOutdated());
|
|
10509
10677
|
};
|
|
10510
10678
|
const locked = accounts.length === 0;
|
|
10511
|
-
const [srv, setSrv] =
|
|
10512
|
-
|
|
10679
|
+
const [srv, setSrv] = useState8(() => logsServerStatus());
|
|
10680
|
+
useEffect7(() => {
|
|
10513
10681
|
const t = setInterval(() => setSrv(logsServerStatus()), 3e3);
|
|
10514
10682
|
return () => clearInterval(t);
|
|
10515
10683
|
}, []);
|
|
10516
|
-
|
|
10684
|
+
useEffect7(() => {
|
|
10517
10685
|
if (!login || login.phase === "done" || login.phase === "error") return;
|
|
10518
10686
|
const t = setInterval(() => setTick((n) => n + 1), 120);
|
|
10519
10687
|
return () => clearInterval(t);
|
|
@@ -10526,7 +10694,7 @@ function SettingsPanel({
|
|
|
10526
10694
|
const local = localQ.data;
|
|
10527
10695
|
const selfProt = selfQ.data;
|
|
10528
10696
|
const autoInstalledRef = useRef3(false);
|
|
10529
|
-
|
|
10697
|
+
useEffect7(() => {
|
|
10530
10698
|
if (autoInstalledRef.current) return;
|
|
10531
10699
|
if (guardHere && guardOld) {
|
|
10532
10700
|
autoInstalledRef.current = true;
|
|
@@ -10538,7 +10706,7 @@ function SettingsPanel({
|
|
|
10538
10706
|
}
|
|
10539
10707
|
}
|
|
10540
10708
|
}, [guardHere, guardOld]);
|
|
10541
|
-
const [hidden, setHidden] =
|
|
10709
|
+
const [hidden, setHidden] = useState8(/* @__PURE__ */ new Set());
|
|
10542
10710
|
const webhooks = (whQ.data?.webhooks ?? []).filter((w) => !hidden.has("wh:" + w.id));
|
|
10543
10711
|
const alerts = (alertQ.data?.rules ?? []).filter((r) => !hidden.has("alert:" + r.id));
|
|
10544
10712
|
const hasEmailAlert = alerts.some((r) => alertChannel(r) === "email");
|
|
@@ -10719,7 +10887,7 @@ function SettingsPanel({
|
|
|
10719
10887
|
setEditor({ ...editor, target: v, field: 1 });
|
|
10720
10888
|
}
|
|
10721
10889
|
};
|
|
10722
|
-
|
|
10890
|
+
useInput7(
|
|
10723
10891
|
(inp, key) => {
|
|
10724
10892
|
if (login && (login.phase === "starting" || login.phase === "waiting")) {
|
|
10725
10893
|
if (key.escape) {
|
|
@@ -10852,156 +11020,156 @@ function SettingsPanel({
|
|
|
10852
11020
|
);
|
|
10853
11021
|
const spin = SPIN2[tick % SPIN2.length];
|
|
10854
11022
|
if (login && (login.phase === "starting" || login.phase === "waiting")) {
|
|
10855
|
-
return /* @__PURE__ */
|
|
10856
|
-
/* @__PURE__ */
|
|
10857
|
-
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: [
|
|
10858
11026
|
spin,
|
|
10859
11027
|
" starting device pairing\u2026"
|
|
10860
|
-
] }) : /* @__PURE__ */
|
|
10861
|
-
/* @__PURE__ */
|
|
10862
|
-
/* @__PURE__ */
|
|
10863
|
-
/* @__PURE__ */
|
|
10864
|
-
/* @__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: [
|
|
10865
11033
|
spin,
|
|
10866
11034
|
" waiting for authorization\u2026 "
|
|
10867
11035
|
] }),
|
|
10868
|
-
/* @__PURE__ */
|
|
11036
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "esc to cancel" })
|
|
10869
11037
|
] })
|
|
10870
11038
|
] })
|
|
10871
11039
|
] });
|
|
10872
11040
|
}
|
|
10873
11041
|
if (editor) {
|
|
10874
|
-
const fieldRow = (idx, label, value, hint) => /* @__PURE__ */
|
|
10875
|
-
/* @__PURE__ */
|
|
10876
|
-
/* @__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) }),
|
|
10877
11045
|
value,
|
|
10878
|
-
editor.field === idx && hint ? /* @__PURE__ */
|
|
11046
|
+
editor.field === idx && hint ? /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: " " + hint }) : null
|
|
10879
11047
|
] });
|
|
10880
|
-
return /* @__PURE__ */
|
|
10881
|
-
/* @__PURE__ */
|
|
11048
|
+
return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
|
|
11049
|
+
/* @__PURE__ */ jsxs8(Text8, { bold: true, color: theme.accentBright, children: [
|
|
10882
11050
|
editor.id ? "Edit" : "New",
|
|
10883
11051
|
" ",
|
|
10884
11052
|
editor.channel,
|
|
10885
11053
|
" alert"
|
|
10886
11054
|
] }),
|
|
10887
|
-
/* @__PURE__ */
|
|
10888
|
-
editing === "alert-target" ? /* @__PURE__ */
|
|
10889
|
-
/* @__PURE__ */
|
|
10890
|
-
/* @__PURE__ */
|
|
10891
|
-
] }) : msg ? /* @__PURE__ */
|
|
10892
|
-
/* @__PURE__ */
|
|
10893
|
-
fieldRow(0, "target", editor.target ? /* @__PURE__ */
|
|
10894
|
-
fieldRow(1, "signal", /* @__PURE__ */
|
|
10895
|
-
fieldRow(2, "threshold", /* @__PURE__ */
|
|
10896
|
-
fieldRow(3, "window", /* @__PURE__ */
|
|
10897
|
-
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
|
|
10898
11066
|
] }),
|
|
10899
|
-
/* @__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: [
|
|
10900
11068
|
"fires when ",
|
|
10901
|
-
/* @__PURE__ */
|
|
11069
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.accent, children: SIGNAL_LABEL[editor.signal] }),
|
|
10902
11070
|
" reach ",
|
|
10903
|
-
/* @__PURE__ */
|
|
11071
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.accent, children: editor.threshold }),
|
|
10904
11072
|
" within",
|
|
10905
11073
|
" ",
|
|
10906
|
-
/* @__PURE__ */
|
|
11074
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.accent, children: winLabel(editor.windowSeconds) })
|
|
10907
11075
|
] }) })
|
|
10908
11076
|
] });
|
|
10909
11077
|
}
|
|
10910
11078
|
const loading = !locked && (localQ.loading && !localQ.data || whQ.loading && !whQ.data || alertQ.loading && !alertQ.data || guardQ.loading && !guardQ.data || selfQ.loading && !selfQ.data);
|
|
10911
11079
|
const error = locked ? null : localQ.error ?? whQ.error ?? alertQ.error ?? guardQ.error ?? selfQ.error;
|
|
10912
|
-
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" });
|
|
10913
11081
|
const chanOf = (rule) => [...rule.emails ?? [], ...(rule.telegram ?? []).map((t) => "tg " + t)].join(", ") || "\u2014";
|
|
10914
11082
|
const isCur = (r) => keyOf(r) === keyOf(cur) && focused;
|
|
10915
|
-
const cursor = (r) => /* @__PURE__ */
|
|
11083
|
+
const cursor = (r) => /* @__PURE__ */ jsx8(Text8, { color: isCur(r) ? theme.accentBright : theme.dim, children: isCur(r) ? "\u25B8 " : " " });
|
|
10916
11084
|
const rowLine = (r) => {
|
|
10917
11085
|
switch (r.kind) {
|
|
10918
11086
|
case "acct": {
|
|
10919
11087
|
const a = r.acc;
|
|
10920
11088
|
const isView = viewApiKey ? a.apiKey === viewApiKey : accounts[0]?.apiKey === a.apiKey;
|
|
10921
11089
|
const isActive = isActiveAccount(a.apiKey);
|
|
10922
|
-
return /* @__PURE__ */
|
|
11090
|
+
return /* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", children: [
|
|
10923
11091
|
cursor(r),
|
|
10924
|
-
/* @__PURE__ */
|
|
10925
|
-
isView ? /* @__PURE__ */
|
|
10926
|
-
isActive ? /* @__PURE__ */
|
|
10927
|
-
/* @__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) : "" })
|
|
10928
11096
|
] });
|
|
10929
11097
|
}
|
|
10930
11098
|
case "acct-add":
|
|
10931
|
-
return /* @__PURE__ */
|
|
11099
|
+
return /* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", children: [
|
|
10932
11100
|
cursor(r),
|
|
10933
|
-
/* @__PURE__ */
|
|
11101
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "+ add account (enter \u2014 device login in the browser)" })
|
|
10934
11102
|
] });
|
|
10935
11103
|
case "guard":
|
|
10936
|
-
return /* @__PURE__ */
|
|
11104
|
+
return /* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", children: [
|
|
10937
11105
|
cursor(r),
|
|
10938
|
-
/* @__PURE__ */
|
|
10939
|
-
!guardHere ? /* @__PURE__ */
|
|
10940
|
-
/* @__PURE__ */
|
|
10941
|
-
/* @__PURE__ */
|
|
10942
|
-
/* @__PURE__ */
|
|
10943
|
-
] }) : /* @__PURE__ */
|
|
10944
|
-
/* @__PURE__ */
|
|
10945
|
-
/* @__PURE__ */
|
|
10946
|
-
/* @__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" })
|
|
10947
11115
|
] })
|
|
10948
11116
|
] });
|
|
10949
11117
|
case "self":
|
|
10950
|
-
return /* @__PURE__ */
|
|
11118
|
+
return /* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", children: [
|
|
10951
11119
|
cursor(r),
|
|
10952
|
-
/* @__PURE__ */
|
|
10953
|
-
selfProt ? onOff(selfProt.enabled) : /* @__PURE__ */
|
|
10954
|
-
/* @__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" })
|
|
10955
11123
|
] });
|
|
10956
11124
|
case "ll-enabled":
|
|
10957
|
-
return /* @__PURE__ */
|
|
11125
|
+
return /* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", children: [
|
|
10958
11126
|
cursor(r),
|
|
10959
|
-
/* @__PURE__ */
|
|
11127
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "enabled ".padEnd(11) }),
|
|
10960
11128
|
onOff(!!local?.enabled),
|
|
10961
|
-
/* @__PURE__ */
|
|
11129
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: " enter toggles" })
|
|
10962
11130
|
] });
|
|
10963
11131
|
case "ll-path":
|
|
10964
|
-
return /* @__PURE__ */
|
|
11132
|
+
return /* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", children: [
|
|
10965
11133
|
cursor(r),
|
|
10966
|
-
/* @__PURE__ */
|
|
10967
|
-
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" })
|
|
10968
11136
|
] });
|
|
10969
11137
|
case "ll-server":
|
|
10970
|
-
return /* @__PURE__ */
|
|
11138
|
+
return /* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", children: [
|
|
10971
11139
|
cursor(r),
|
|
10972
|
-
/* @__PURE__ */
|
|
10973
|
-
srv.running ? /* @__PURE__ */
|
|
10974
|
-
/* @__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" })
|
|
10975
11143
|
] });
|
|
10976
11144
|
case "wh":
|
|
10977
|
-
return /* @__PURE__ */
|
|
11145
|
+
return /* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", children: [
|
|
10978
11146
|
cursor(r),
|
|
10979
11147
|
onOff(r.wh.enabled),
|
|
10980
|
-
/* @__PURE__ */
|
|
10981
|
-
/* @__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) })
|
|
10982
11150
|
] });
|
|
10983
11151
|
case "wh-add":
|
|
10984
|
-
return /* @__PURE__ */
|
|
11152
|
+
return /* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", children: [
|
|
10985
11153
|
cursor(r),
|
|
10986
|
-
/* @__PURE__ */
|
|
11154
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "+ add webhook (enter)" })
|
|
10987
11155
|
] });
|
|
10988
11156
|
case "alert":
|
|
10989
|
-
return /* @__PURE__ */
|
|
11157
|
+
return /* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", children: [
|
|
10990
11158
|
cursor(r),
|
|
10991
11159
|
onOff(r.rule.enabled),
|
|
10992
|
-
/* @__PURE__ */
|
|
10993
|
-
/* @__PURE__ */
|
|
10994
|
-
/* @__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) })
|
|
10995
11163
|
] });
|
|
10996
11164
|
case "alert-add-email":
|
|
10997
|
-
return /* @__PURE__ */
|
|
11165
|
+
return /* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", children: [
|
|
10998
11166
|
cursor(r),
|
|
10999
|
-
/* @__PURE__ */
|
|
11167
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "+ add email alert (enter)" })
|
|
11000
11168
|
] });
|
|
11001
11169
|
case "alert-add-tg":
|
|
11002
|
-
return /* @__PURE__ */
|
|
11170
|
+
return /* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", children: [
|
|
11003
11171
|
cursor(r),
|
|
11004
|
-
/* @__PURE__ */
|
|
11172
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "+ add telegram alert (enter \u2014 numeric chat id from @userinfobot)" })
|
|
11005
11173
|
] });
|
|
11006
11174
|
}
|
|
11007
11175
|
};
|
|
@@ -11020,39 +11188,39 @@ function SettingsPanel({
|
|
|
11020
11188
|
const sec = sectionOf(r);
|
|
11021
11189
|
if (sec !== lastSec) {
|
|
11022
11190
|
if (lastSec) {
|
|
11023
|
-
lineEls.push(/* @__PURE__ */
|
|
11191
|
+
lineEls.push(/* @__PURE__ */ jsx8(Text8, { children: " " }, "sp:" + sec));
|
|
11024
11192
|
lineKey.push("");
|
|
11025
11193
|
}
|
|
11026
11194
|
lastSec = sec;
|
|
11027
11195
|
lineEls.push(
|
|
11028
|
-
/* @__PURE__ */
|
|
11029
|
-
/* @__PURE__ */
|
|
11030
|
-
/* @__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] })
|
|
11031
11199
|
] }, "h:" + sec)
|
|
11032
11200
|
);
|
|
11033
11201
|
lineKey.push("");
|
|
11034
11202
|
if ((sec === "WEBHOOKS" || sec === "ALERTS") && local?.enabled) {
|
|
11035
11203
|
lineEls.push(
|
|
11036
|
-
/* @__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)
|
|
11037
11205
|
);
|
|
11038
11206
|
lineKey.push("");
|
|
11039
11207
|
}
|
|
11040
11208
|
}
|
|
11041
|
-
lineEls.push(/* @__PURE__ */
|
|
11209
|
+
lineEls.push(/* @__PURE__ */ jsx8(Box8, { children: rowLine(r) }, keyOf(r)));
|
|
11042
11210
|
lineKey.push(keyOf(r));
|
|
11043
11211
|
});
|
|
11044
11212
|
if (hasEmailAlert && hasTgAlert) {
|
|
11045
11213
|
lineEls.push(
|
|
11046
|
-
/* @__PURE__ */
|
|
11214
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: " both channels in use \u2014 remove one (d) to change it" }, "both-note")
|
|
11047
11215
|
);
|
|
11048
11216
|
lineKey.push("");
|
|
11049
11217
|
}
|
|
11050
|
-
lineEls.push(/* @__PURE__ */
|
|
11218
|
+
lineEls.push(/* @__PURE__ */ jsx8(Text8, { children: " " }, "ver-sp"));
|
|
11051
11219
|
lineKey.push("");
|
|
11052
11220
|
lineEls.push(
|
|
11053
|
-
/* @__PURE__ */
|
|
11221
|
+
/* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", color: theme.dim, children: [
|
|
11054
11222
|
`solongate v${ver}`,
|
|
11055
|
-
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
|
|
11056
11224
|
] }, "ver")
|
|
11057
11225
|
);
|
|
11058
11226
|
lineKey.push("");
|
|
@@ -11063,13 +11231,13 @@ function SettingsPanel({
|
|
|
11063
11231
|
const win = lineEls.slice(startL, startL + budget);
|
|
11064
11232
|
const moreAbove = startL;
|
|
11065
11233
|
const moreBelow = Math.max(0, lineEls.length - (startL + budget));
|
|
11066
|
-
return /* @__PURE__ */
|
|
11067
|
-
/* @__PURE__ */
|
|
11068
|
-
editing ? /* @__PURE__ */
|
|
11069
|
-
/* @__PURE__ */
|
|
11070
|
-
/* @__PURE__ */
|
|
11071
|
-
] }) : msg ? /* @__PURE__ */
|
|
11072
|
-
/* @__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 })
|
|
11073
11241
|
] }) });
|
|
11074
11242
|
}
|
|
11075
11243
|
var EVENTS, SPIN2, SIGNALS2, SIGNAL_LABEL, WINDOWS, winLabel, THRESH_MIN, THRESH_MAX, nearestWindowIdx, editorFieldCount, acctLabel, alertChannel;
|
|
@@ -11105,64 +11273,44 @@ var init_Settings = __esm({
|
|
|
11105
11273
|
});
|
|
11106
11274
|
|
|
11107
11275
|
// src/tui/App.tsx
|
|
11108
|
-
import { Box as
|
|
11109
|
-
import { useEffect as
|
|
11110
|
-
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";
|
|
11111
11279
|
function LiveHint() {
|
|
11112
|
-
return /* @__PURE__ */
|
|
11113
|
-
/* @__PURE__ */
|
|
11114
|
-
/* @__PURE__ */
|
|
11115
|
-
/* @__PURE__ */
|
|
11116
|
-
/* @__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: [
|
|
11117
11285
|
"press ",
|
|
11118
|
-
/* @__PURE__ */
|
|
11286
|
+
/* @__PURE__ */ jsx9(Text9, { color: theme.accent, children: "enter" }),
|
|
11119
11287
|
" to go live"
|
|
11120
11288
|
] }) })
|
|
11121
11289
|
] });
|
|
11122
11290
|
}
|
|
11123
|
-
function DryRunPanel({ focused }) {
|
|
11124
|
-
const [opened, setOpened] = useState8(false);
|
|
11125
|
-
useEffect7(() => {
|
|
11126
|
-
if (focused && !opened) {
|
|
11127
|
-
openBrowser("https://dashboard.solongate.com/playground");
|
|
11128
|
-
setOpened(true);
|
|
11129
|
-
}
|
|
11130
|
-
}, [focused, opened]);
|
|
11131
|
-
return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
|
|
11132
|
-
/* @__PURE__ */ jsx8(Text8, { color: theme.accentBright, bold: true, children: "Policy Dry Run" }),
|
|
11133
|
-
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "Replay a rule set against your real historical traffic and see exactly" }),
|
|
11134
|
-
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "what would change before you ship it." }),
|
|
11135
|
-
/* @__PURE__ */ jsx8(Box8, { marginTop: 1, children: opened ? /* @__PURE__ */ jsx8(Text8, { color: theme.ok, children: "Opened in your browser." }) : /* @__PURE__ */ jsxs8(Text8, { children: [
|
|
11136
|
-
"press ",
|
|
11137
|
-
/* @__PURE__ */ jsx8(Text8, { color: theme.accent, children: "enter" }),
|
|
11138
|
-
" to open the dry-run playground in your browser"
|
|
11139
|
-
] }) }),
|
|
11140
|
-
/* @__PURE__ */ jsx8(Box8, { marginTop: 1, children: /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "Pick any policy and tune the sample there. From Policies, open a policy and press D to dry-run that one." }) })
|
|
11141
|
-
] });
|
|
11142
|
-
}
|
|
11143
11291
|
function Banner({ cols }) {
|
|
11144
11292
|
const wide = cols >= 82;
|
|
11145
11293
|
if (!wide) {
|
|
11146
|
-
return /* @__PURE__ */
|
|
11147
|
-
/* @__PURE__ */
|
|
11148
|
-
/* @__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" })
|
|
11149
11297
|
] });
|
|
11150
11298
|
}
|
|
11151
|
-
return /* @__PURE__ */
|
|
11152
|
-
BANNER_FULL.map((line, i) => /* @__PURE__ */
|
|
11153
|
-
/* @__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" })
|
|
11154
11302
|
] });
|
|
11155
11303
|
}
|
|
11156
11304
|
function App() {
|
|
11157
11305
|
const { exit } = useApp();
|
|
11158
|
-
const [accounts, setAccounts] =
|
|
11159
|
-
const [viewKey, setViewKey] =
|
|
11160
|
-
const [viewNonce, setViewNonce] =
|
|
11161
|
-
const [section, setSection] =
|
|
11162
|
-
const [focus, setFocus] =
|
|
11163
|
-
const [help, setHelp] =
|
|
11164
|
-
const [update2, setUpdate] =
|
|
11165
|
-
|
|
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(() => {
|
|
11166
11314
|
let alive = true;
|
|
11167
11315
|
const run10 = () => void tuiUpdateFlow((s) => alive && setUpdate(s));
|
|
11168
11316
|
run10();
|
|
@@ -11175,7 +11323,7 @@ function App() {
|
|
|
11175
11323
|
const acctIdx = Math.max(0, accounts.findIndex((a) => a.apiKey === viewKey));
|
|
11176
11324
|
const cur = accounts[acctIdx];
|
|
11177
11325
|
const acctLabel2 = cur ? cur.email || cur.user || cur.project || `account \u2026${cur.apiKey.slice(-4)}` : "not logged in";
|
|
11178
|
-
|
|
11326
|
+
useEffect8(() => {
|
|
11179
11327
|
if (!cur || cur.email) return;
|
|
11180
11328
|
let alive = true;
|
|
11181
11329
|
api.auth.me().then((r) => {
|
|
@@ -11211,7 +11359,7 @@ function App() {
|
|
|
11211
11359
|
};
|
|
11212
11360
|
const locked = accounts.length === 0;
|
|
11213
11361
|
const effectiveSection = locked ? SETTINGS_SECTION : section;
|
|
11214
|
-
|
|
11362
|
+
useInput8((input, key) => {
|
|
11215
11363
|
if (help) {
|
|
11216
11364
|
setHelp(false);
|
|
11217
11365
|
return;
|
|
@@ -11239,47 +11387,47 @@ function App() {
|
|
|
11239
11387
|
});
|
|
11240
11388
|
const { cols, rows } = useTermSize();
|
|
11241
11389
|
const current = SECTIONS[effectiveSection];
|
|
11242
|
-
if (help) return /* @__PURE__ */
|
|
11390
|
+
if (help) return /* @__PURE__ */ jsx9(HelpOverlay, { cols, rows });
|
|
11243
11391
|
if (current.label === "Live" && focus === "panel") {
|
|
11244
|
-
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) });
|
|
11245
11393
|
}
|
|
11246
11394
|
const Panel = current.Panel;
|
|
11247
|
-
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" });
|
|
11248
11396
|
return (
|
|
11249
11397
|
// height rows-1 (not rows): once total output reaches stdout.rows ink stops
|
|
11250
11398
|
// diffing and clearTerminal-repaints every frame, which slides the banner.
|
|
11251
11399
|
// overflow hidden makes it a hard guarantee even if a panel over-renders.
|
|
11252
|
-
/* @__PURE__ */
|
|
11253
|
-
/* @__PURE__ */
|
|
11254
|
-
/* @__PURE__ */
|
|
11255
|
-
/* @__PURE__ */
|
|
11256
|
-
/* @__PURE__ */
|
|
11257
|
-
locked ? /* @__PURE__ */
|
|
11258
|
-
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
|
|
11259
11407
|
] }),
|
|
11260
|
-
/* @__PURE__ */
|
|
11261
|
-
/* @__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) => {
|
|
11262
11410
|
const isCur = i === effectiveSection;
|
|
11263
11411
|
const disabled = locked && s.label !== "Settings";
|
|
11264
|
-
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);
|
|
11265
11413
|
}) }),
|
|
11266
|
-
/* @__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 })
|
|
11267
11415
|
] }, viewNonce),
|
|
11268
|
-
/* @__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"]] }) })
|
|
11269
11417
|
] })
|
|
11270
11418
|
);
|
|
11271
11419
|
}
|
|
11272
11420
|
function HelpOverlay({ cols, rows }) {
|
|
11273
|
-
return /* @__PURE__ */
|
|
11274
|
-
/* @__PURE__ */
|
|
11275
|
-
/* @__PURE__ */
|
|
11276
|
-
/* @__PURE__ */
|
|
11277
|
-
keys.map(([k, desc]) => /* @__PURE__ */
|
|
11278
|
-
/* @__PURE__ */
|
|
11279
|
-
/* @__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 })
|
|
11280
11428
|
] }, k))
|
|
11281
11429
|
] }, group)) }),
|
|
11282
|
-
/* @__PURE__ */
|
|
11430
|
+
/* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: "press any key to close" })
|
|
11283
11431
|
] });
|
|
11284
11432
|
}
|
|
11285
11433
|
var SECTIONS, BANNER_HEX, SETTINGS_SECTION, HELP;
|
|
@@ -11294,10 +11442,10 @@ var init_App = __esm({
|
|
|
11294
11442
|
init_RateLimit();
|
|
11295
11443
|
init_Dlp();
|
|
11296
11444
|
init_Audit();
|
|
11445
|
+
init_DryRun();
|
|
11297
11446
|
init_Settings();
|
|
11298
11447
|
init_hooks();
|
|
11299
11448
|
init_client();
|
|
11300
|
-
init_device_login();
|
|
11301
11449
|
init_api_client();
|
|
11302
11450
|
init_self_update();
|
|
11303
11451
|
SECTIONS = [
|
|
@@ -11333,7 +11481,7 @@ import { appendFileSync as appendFileSync2, mkdirSync as mkdirSync9 } from "fs";
|
|
|
11333
11481
|
import { homedir as homedir10 } from "os";
|
|
11334
11482
|
import { join as join12 } from "path";
|
|
11335
11483
|
import { render } from "ink";
|
|
11336
|
-
import { jsx as
|
|
11484
|
+
import { jsx as jsx10 } from "react/jsx-runtime";
|
|
11337
11485
|
async function launchTui() {
|
|
11338
11486
|
if (!process.stdout.isTTY || !process.stdin.isTTY) {
|
|
11339
11487
|
process.stderr.write(
|
|
@@ -11358,7 +11506,7 @@ async function launchTui() {
|
|
|
11358
11506
|
console.info = toFile("info");
|
|
11359
11507
|
console.debug = toFile("debug");
|
|
11360
11508
|
try {
|
|
11361
|
-
const { waitUntilExit } = render(/* @__PURE__ */
|
|
11509
|
+
const { waitUntilExit } = render(/* @__PURE__ */ jsx10(App, {}), { patchConsole: false });
|
|
11362
11510
|
await waitUntilExit();
|
|
11363
11511
|
} finally {
|
|
11364
11512
|
Object.assign(console, saved);
|