@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/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/Policies.tsx
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 { Fragment as Fragment3, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
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] = useState3("list");
8819
- const [pi, setPi] = useState3(0);
8820
- const [ri, setRi] = useState3(0);
8821
- const [fi, setFi] = useState3(0);
8822
- const [rules, setRules] = useState3([]);
8823
- const [mode, setMode] = useState3("denylist");
8824
- const [dirty, setDirty] = useState3(false);
8825
- const [editing, setEditing] = useState3(false);
8826
- const [editVal, setEditVal] = useState3("");
8827
- const [status, setStatus] = useState3(null);
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
- useEffect3(() => {
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
- useInput2(
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
- openBrowser(`${DASHBOARD_URL}/playground?policy=${encodeURIComponent(selected.id)}`);
8938
- setStatus("Opened the dry-run playground in your browser.");
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__ */ jsx3(DataView, { loading: list6.loading && !list6.data, error: list6.error, empty: !!list6.data && policies.length === 0, emptyText: "No policies.", children: /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", children: [
8973
- /* @__PURE__ */ jsxs3(Box3, { children: [
8974
- /* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: "active: " }),
8975
- activeQ.loading && !activeQ.data ? /* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: "\u2026" }) : activeName ? /* @__PURE__ */ jsxs3(Fragment3, { children: [
8976
- /* @__PURE__ */ jsxs3(Text3, { color: theme.ok, bold: true, children: [
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__ */ jsx3(Text3, { color: theme.dim, children: activeBy ? ` (${activeBy})` : "" })
8981
- ] }) : /* @__PURE__ */ jsx3(Text3, { color: theme.bad, bold: true, children: "\u25CB NONE \u2014 nothing enforced, grants refused" })
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__ */ jsx3(Text3, { 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" }),
8984
- /* @__PURE__ */ jsx3(Box3, { marginTop: 1, flexDirection: "column", children: lWin.map((p, wi) => {
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__ */ jsxs3(Text3, { color: i === pi ? theme.accentBright : void 0, bold: i === pi, children: [
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__ */ jsxs3(Text3, { color: theme.dim, children: [
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__ */ jsx3(Text3, { color: theme.ok, bold: true, children: " \u25CF ACTIVE" }) : null
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__ */ jsx3(Text3, { color: status.startsWith("\u2717") ? theme.bad : theme.ok, children: status }) : null
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__ */ jsx3(Text3, { color: theme.warn, children: " \u25CF unsaved (s save \xB7 x discard)" }) : null;
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__ */ jsx3(DataView, { loading: detail.loading && !detail.data, error: detail.error, children: /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", children: [
9011
- /* @__PURE__ */ jsxs3(Box3, { children: [
9012
- /* @__PURE__ */ jsx3(Text3, { bold: true, color: theme.accentBright, children: truncate2(selected?.name ?? "", 28) }),
9013
- /* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: " mode: " }),
9014
- /* @__PURE__ */ jsx3(Text3, { color: mode === "whitelist" ? theme.warn : void 0, children: mode }),
9015
- /* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: ` ${rules.length} rules` }),
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__ */ jsx3(Text3, { 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}` : ""}` }),
9019
- /* @__PURE__ */ jsx3(Box3, { marginTop: 1, children: /* @__PURE__ */ jsx3(
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__ */ jsx3(Text3, { color: theme.dim, children: "(no rules)" }) : null,
9046
- status ? /* @__PURE__ */ jsx3(Text3, { color: status.startsWith("\u2717") ? theme.bad : theme.ok, children: status }) : null
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__ */ jsxs3(Box3, { flexDirection: "column", children: [
9051
- /* @__PURE__ */ jsxs3(Box3, { children: [
9052
- /* @__PURE__ */ jsx3(Text3, { bold: true, color: theme.accentBright, children: "Rule " }),
9053
- /* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: rule?.id ?? "" }),
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__ */ jsx3(Text3, { color: theme.dim, children: "\u2191\u2193 field \xB7 enter edit text \xB7 space/\u2192 toggle \xB7 s save \xB7 \u2190 back" }),
9057
- /* @__PURE__ */ jsx3(Box3, { marginTop: 1, flexDirection: "column", children: FIELDS.map((f, i) => {
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__ */ jsxs3(Box3, { children: [
9061
- /* @__PURE__ */ jsx3(Text3, { color: active2 ? theme.accentBright : void 0, children: (active2 ? "\u25B8 " : " ") + f.label.padEnd(13) }),
9062
- active2 && editing && f.kind === "text" ? /* @__PURE__ */ jsx3(
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__ */ jsx3(
9073
- Text3,
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__ */ jsx3(Text3, { color: status.startsWith("\u2717") ? theme.bad : theme.ok, children: status }) : null
9251
+ status ? /* @__PURE__ */ jsx4(Text4, { color: status.startsWith("\u2717") ? theme.bad : theme.ok, children: status }) : null
9083
9252
  ] });
9084
9253
  }
9085
- var DASHBOARD_URL, constr, setConstr, FIELDS;
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
- init_device_login();
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 Box4, Text as Text4, useInput as useInput3 } from "ink";
9121
- import { useEffect as useEffect4, useState as useState4 } from "react";
9122
- import { Fragment as Fragment4, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
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] = useState4(null);
9129
- const [dirty, setDirty] = useState4(false);
9130
- const [sel, setSel] = useState4(0);
9131
- const [status, setStatus] = useState4(null);
9132
- useEffect4(() => {
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
- useInput3(
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__ */ jsx4(DataView, { loading: layersQ.loading && !draft, error: layersQ.error, children: draft ? (() => {
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__ */ jsxs4(Box4, { flexDirection: "column", height: rows, overflow: "hidden", children: [
9207
- /* @__PURE__ */ jsx4(Text4, { 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" }),
9208
- /* @__PURE__ */ jsxs4(FieldRow, { label: "Mode", active: focused && fi === 0, children: [
9209
- /* @__PURE__ */ jsx4(Text4, { color: modeColor(draft.mode), bold: true, children: draft.mode }),
9210
- /* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: draft.mode === "off" ? " no limit" : draft.mode === "detect" ? " flag bursts, never block" : " DENY calls over the limit" })
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__ */ jsx4(FieldRow, { label: "Per minute", active: focused && fi === 1, children: /* @__PURE__ */ jsx4(Text4, { bold: true, children: draft.perMinute || "off" }) }),
9213
- /* @__PURE__ */ jsx4(FieldRow, { label: "Per hour", active: focused && fi === 2, children: /* @__PURE__ */ jsx4(Text4, { bold: true, children: draft.perHour || "off" }) }),
9214
- /* @__PURE__ */ jsx4(FieldRow, { label: "Per day", active: focused && fi === 3, children: /* @__PURE__ */ jsx4(Text4, { bold: true, children: draft.perDay || "off" }) }),
9215
- showExtras && /* @__PURE__ */ jsxs4(Fragment4, { children: [
9216
- hasLoad ? /* @__PURE__ */ jsxs4(Text4, { wrap: "truncate", children: [
9217
- /* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: "load now".padEnd(13) }),
9218
- /* @__PURE__ */ jsx4(Text4, { color: loadPct >= 100 ? theme.bad : loadPct >= 80 ? theme.warn : theme.ok, children: "\u2588".repeat(Math.min(18, Math.round(now / lim * 18))) }),
9219
- /* @__PURE__ */ jsx4(Text4, { color: "#233457", children: "\u2591".repeat(Math.max(0, 18 - Math.round(now / lim * 18))) }),
9220
- /* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: ` ${now}/${lim} this minute (${loadPct}%)` })
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__ */ jsxs4(Text4, { color: theme.accentBright, bold: true, wrap: "truncate", children: [
9390
+ /* @__PURE__ */ jsxs5(Text5, { color: theme.accentBright, bold: true, wrap: "truncate", children: [
9223
9391
  "Busiest 7d",
9224
- /* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: " most calls in one window vs your limit" })
9392
+ /* @__PURE__ */ jsx5(Text5, { color: theme.dim, children: " most calls in one window vs your limit" })
9225
9393
  ] }),
9226
- /* @__PURE__ */ jsx4(BusiestRow, { label: "minute", peak: peaks.minute, limit: draft.perMinute }),
9227
- /* @__PURE__ */ jsx4(BusiestRow, { label: "hour", peak: peaks.hour, limit: draft.perHour }),
9228
- /* @__PURE__ */ jsx4(BusiestRow, { label: "day", peak: peaks.day, limit: draft.perDay }),
9229
- /* @__PURE__ */ jsx4(Text4, { color: theme.dim, wrap: "truncate", children: `activity`.padEnd(11) + ` last 24h \xB7 ${last24h} calls \xB7 busiest hour ${peaks.hour}/hr` })
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__ */ jsxs4(Box4, { flexDirection: "column", children: [
9232
- /* @__PURE__ */ jsxs4(Text4, { color: theme.accentBright, bold: true, wrap: "truncate", children: [
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__ */ jsx4(Text4, { color: theme.warn, children: ` ${off + 1}-${Math.min(off + burstBudget, anomalies2.length)}/${anomalies2.length}` }) : null,
9235
- /* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: " over the per-minute limit \xB7 Bypassed = detect (not blocked)" })
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__ */ jsxs4(Text4, { color: theme.dim, children: [
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__ */ jsx4(
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__ */ jsx4(Text4, { children: " " }),
9257
- /* @__PURE__ */ jsxs4(Text4, { wrap: "truncate", children: [
9258
- /* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: "limit now " }),
9259
- /* @__PURE__ */ jsx4(Text4, { children: lim > 0 ? `${lim}/min` : "no per-minute limit" }),
9260
- lastChange ? /* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: ` \xB7 changed ${when(lastChange.ts)}` }) : null,
9261
- dirty ? /* @__PURE__ */ jsx4(Text4, { color: theme.warn, children: " \u25CF unsaved (s)" }) : null,
9262
- status ? /* @__PURE__ */ jsx4(Text4, { color: status.startsWith("\u2717") ? theme.bad : theme.ok, children: " " + status }) : null
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__ */ jsxs4(Text4, { wrap: "truncate", children: [
9271
- /* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: (" " + label).padEnd(11) }),
9272
- /* @__PURE__ */ jsx4(Text4, { color: hot ? theme.bad : void 0, bold: hot, children: String(peak).padStart(4) + " calls" }),
9273
- /* @__PURE__ */ jsx4(Text4, { color: hot ? theme.bad : theme.dim, children: " \xB7 " + ctx })
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__ */ jsxs4(Text4, { wrap: "truncate", children: [
9278
- /* @__PURE__ */ jsx4(Text4, { color: active2 ? theme.accentBright : void 0, children: (active2 ? "\u25B8 " : " ") + label.padEnd(11) }),
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 Box5, Text as Text5, useInput as useInput4 } from "ink";
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 useEffect5, useState as useState5 } from "react";
9303
- import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
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] = useState5(null);
9308
- const [available, setAvailable] = useState5([]);
9309
- const [ghostOn, setGhostOn] = useState5(false);
9310
- const [ghostPats, setGhostPats] = useState5([]);
9311
- const [sel, setSel] = useState5(0);
9312
- const [dirty, setDirty] = useState5(false);
9313
- const [status, setStatus] = useState5(null);
9314
- const [adding, setAdding] = useState5(null);
9315
- const [newName, setNewName] = useState5("");
9316
- const [input, setInput] = useState5("");
9317
- useEffect5(() => {
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
- useInput4(
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__ */ jsxs5(Text5, { wrap: "truncate", children: [
9410
- /* @__PURE__ */ jsx5(Text5, { color: theme.accentBright, bold: true, children: label }),
9411
- extra ? /* @__PURE__ */ jsx5(Text5, { color: theme.dim, children: " " + extra }) : null
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__ */ jsx5(Text5, { color: theme.dim, wrap: "truncate", children: text }, key), entry: -1 });
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__ */ jsxs5(Text5, { wrap: "truncate", backgroundColor: isCur ? "#1c2f63" : void 0, bold: isCur, children: [
9424
- /* @__PURE__ */ jsx5(Text5, { color: isCur ? theme.accentBright : theme.dim, children: isCur ? "\u25B8 " : " " }),
9425
- /* @__PURE__ */ jsx5(Text5, { color: on ? theme.ok : theme.dim, children: on ? "\u25CF " : "\u25CB " }),
9426
- /* @__PURE__ */ jsx5(Text5, { color: on ? void 0 : theme.dim, children: p })
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__ */ jsxs5(Text5, { wrap: "truncate", backgroundColor: isCur ? "#1c2f63" : void 0, bold: isCur, children: [
9439
- /* @__PURE__ */ jsx5(Text5, { color: isCur ? theme.accentBright : theme.dim, children: isCur ? "\u25B8 " : " " }),
9440
- /* @__PURE__ */ jsx5(Text5, { color: theme.accent, children: c2.name }),
9441
- /* @__PURE__ */ jsx5(Text5, { color: theme.dim, children: " " + truncate2(c2.re, Math.max(10, cols - c2.name.length - 8)) })
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__ */ jsxs5(Text5, { wrap: "truncate", backgroundColor: isCur ? "#1c2f63" : void 0, bold: isCur, children: [
9454
- /* @__PURE__ */ jsx5(Text5, { color: isCur ? theme.accentBright : theme.dim, children: isCur ? "\u25B8 " : " " }),
9455
- /* @__PURE__ */ jsx5(Text5, { color: ghostOn ? theme.accent : theme.dim, children: truncate2(p, Math.max(10, cols - 6)) }),
9456
- !ghostOn ? /* @__PURE__ */ jsx5(Text5, { color: theme.dim, children: " (ghost off)" }) : null
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__ */ jsx5(DataView, { loading: q.loading && !dlp, error: q.error, children: dlp ? /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", children: [
9471
- /* @__PURE__ */ jsxs5(Text5, { wrap: "truncate", children: [
9472
- /* @__PURE__ */ jsx5(Text5, { children: "mode: " }),
9473
- /* @__PURE__ */ jsx5(Text5, { color: modeColor(dlp.mode), bold: true, children: dlp.mode }),
9474
- /* @__PURE__ */ jsx5(Text5, { color: theme.dim, children: dlp.mode === "off" ? " (scanning disabled)" : dlp.mode === "detect" ? " (flag dlp:yes, redact output)" : " (deny + redact secrets)" }),
9475
- dirty ? /* @__PURE__ */ jsx5(Text5, { color: theme.warn, children: " \u25CF unsaved (s save \xB7 x discard)" }) : null
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__ */ jsx5(Text5, { 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" }),
9478
- adding ? /* @__PURE__ */ jsx5(Box5, { flexDirection: "column", children: /* @__PURE__ */ jsxs5(Box5, { children: [
9479
- /* @__PURE__ */ jsx5(Text5, { 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): " }),
9480
- /* @__PURE__ */ jsx5(
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__ */ jsx5(Box5, { marginTop: 1, flexDirection: "column", height: budget, overflow: "hidden", children: win.map((l) => l.node) }),
9508
- status ? /* @__PURE__ */ jsx5(Text5, { color: status.startsWith("\u2717") ? theme.bad : theme.ok, wrap: "truncate", children: status }) : null
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 Box6, Text as Text6, useInput as useInput5 } from "ink";
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 useState6 } from "react";
9530
- import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
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] = useState6("cloud");
9556
- const [view, setView] = useState6("logs");
9557
- const [di, setDi] = useState6(0);
9558
- const [gi, setGi] = useState6(0);
9559
- const [tool, setTool] = useState6("");
9560
- const [agent, setAgent] = useState6("");
9561
- const [search, setSearch] = useState6("");
9562
- const [sessFilter, setSessFilter] = useState6("");
9563
- const [page, setPage] = useState6(0);
9564
- const [sel, setSel] = useState6(0);
9565
- const [detailScroll, setDetailScroll] = useState6(0);
9566
- const [editing, setEditing] = useState6(null);
9567
- const [si, setSi] = useState6(0);
9568
- const [sessSearch, setSessSearch] = useState6("");
9569
- const [sessSel, setSessSel] = useState6(0);
9570
- const [confirm, setConfirm] = useState6(null);
9571
- const [msg, setMsg] = useState6(null);
9572
- const [showHelp, setShowHelp] = useState6(false);
9573
- const [frozen, setFrozen] = useState6(false);
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
- useInput5(
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__ */ jsxs6(Text6, { wrap: "truncate", children: [
9827
- /* @__PURE__ */ jsx6(Text6, { bold: true, children: statsQ.data ? statsQ.data.total_calls : "\xB7\xB7\xB7\xB7" }),
9828
- /* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: " calls \xB7 " }),
9829
- /* @__PURE__ */ jsxs6(Text6, { color: theme.ok, children: [
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__ */ jsx6(Text6, { color: theme.dim, children: " \xB7 " }),
9834
- /* @__PURE__ */ jsxs6(Text6, { color: theme.bad, children: [
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__ */ jsx6(Text6, { color: theme.dim, children: ` \xB7 ${statsQ.data?.active_policies ?? "\xB7"} policies` })
9839
- ] }) : /* @__PURE__ */ jsxs6(Text6, { wrap: "truncate", children: [
9840
- /* @__PURE__ */ jsx6(Text6, { bold: true, children: localAll.length }),
9841
- /* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: " calls in local file \xB7 " }),
9842
- /* @__PURE__ */ jsxs6(Text6, { color: theme.ok, children: [
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__ */ jsx6(Text6, { color: theme.dim, children: " \xB7 " }),
9847
- /* @__PURE__ */ jsxs6(Text6, { color: theme.bad, children: [
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__ */ jsxs6(Text6, { color: theme.dim, children: [
10019
+ /* @__PURE__ */ jsxs7(Text7, { color: theme.dim, children: [
9852
10020
  " \xB7 ",
9853
10021
  LOCAL_LOG
9854
10022
  ] })
9855
10023
  ] });
9856
- const copyBanner = frozen ? /* @__PURE__ */ jsx6(Text6, { backgroundColor: "#123d1f", color: "#7bd88f", bold: true, wrap: "truncate", children: " \u23F5 COPY MODE \u2014 screen frozen, select & copy freely \xB7 space resume " }) : null;
9857
- const srcChip = /* @__PURE__ */ jsxs6(Text6, { children: [
9858
- /* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: "src:" }),
9859
- /* @__PURE__ */ jsx6(Text6, { color: source === "local" ? theme.ok : "#4f6db8", bold: true, children: source }),
9860
- /* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: " (s) " })
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__ */ jsx6(Box6, { flexDirection: "column", width: "50%", paddingRight: 2, children: groups.map(([group, keys]) => /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", marginBottom: 1, children: [
9864
- /* @__PURE__ */ jsx6(Text6, { bold: true, color: theme.accent, children: group }),
9865
- keys.map(([k, desc]) => /* @__PURE__ */ jsxs6(Text6, { wrap: "truncate", children: [
9866
- /* @__PURE__ */ jsx6(Text6, { color: theme.accentBright, children: (" " + k).padEnd(19) }),
9867
- /* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: desc })
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__ */ jsxs6(Box6, { flexDirection: "column", children: [
10038
+ return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
9871
10039
  copyBanner,
9872
- /* @__PURE__ */ jsxs6(Text6, { bold: true, color: theme.accentBright, children: [
10040
+ /* @__PURE__ */ jsxs7(Text7, { bold: true, color: theme.accentBright, children: [
9873
10041
  "AUDIT \u2014 all keys",
9874
10042
  " ",
9875
- /* @__PURE__ */ jsx6(Text6, { 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)" })
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__ */ jsxs6(Box6, { marginTop: 1, children: [
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__ */ jsxs6(Box6, { flexDirection: "column", children: [
10064
+ return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
9897
10065
  copyBanner,
9898
- /* @__PURE__ */ jsxs6(Text6, { wrap: "truncate", children: [
9899
- /* @__PURE__ */ jsx6(Text6, { backgroundColor: BG2, color: "white", bold: true, children: " ENTRY " }),
9900
- /* @__PURE__ */ jsx6(Text6, { color: decisionColor(e.decision), bold: true, children: " " + e.decision }),
9901
- /* @__PURE__ */ jsx6(Text6, { color: theme.accent, bold: true, children: " " + e.tool }),
9902
- /* @__PURE__ */ jsx6(Text6, { color: loc ? theme.ok : "white", children: " " + (loc ? "LOC" : "CLD") }),
9903
- e.dlp.length ? /* @__PURE__ */ jsx6(Text6, { color: theme.bad, children: " DLP!" }) : null,
9904
- e.burst ? /* @__PURE__ */ jsx6(Text6, { color: theme.warn, children: " BURST" }) : null,
9905
- /* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: " \u2190 back" })
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__ */ jsxs6(Text6, { wrap: "truncate", children: [
9908
- /* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: "\u2502 when " }),
9909
- /* @__PURE__ */ jsx6(Text6, { children: new Date(e.at).toLocaleString() }),
9910
- /* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: " \u2502 perm " }),
9911
- /* @__PURE__ */ jsx6(Text6, { children: e.permission || "\u2014" }),
9912
- /* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: " \u2502 trust " }),
9913
- /* @__PURE__ */ jsx6(Text6, { children: e.trust || "\u2014" }),
9914
- /* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: " \u2502 eval " }),
9915
- /* @__PURE__ */ jsx6(Text6, { color: e.evalMs != null && e.evalMs > 500 ? theme.warn : void 0, children: e.evalMs != null ? `${e.evalMs}ms` : "\u2014" }),
9916
- /* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: " \u2502 agent " }),
9917
- /* @__PURE__ */ jsx6(Text6, { children: e.agent ?? "\u2014" }),
9918
- /* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: " \u2502" })
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__ */ jsxs6(Text6, { wrap: "truncate", children: [
9921
- /* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: "\u2502 session " }),
9922
- /* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: e.session ?? "\u2014" }),
9923
- /* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: " \u2502 rule " }),
9924
- /* @__PURE__ */ jsx6(Text6, { color: e.rule && e.decision !== "ALLOW" ? theme.bad : theme.dim, children: e.rule ?? "\u2014" }),
9925
- /* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: " \u2502" })
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__ */ jsx6(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 }),
9928
- /* @__PURE__ */ jsx6(Box6, { flexDirection: "column", height: bodyRows, overflow: "hidden", children: win.map((l, i) => /* @__PURE__ */ jsx6(Text6, { wrap: "truncate", children: l || " " }, off + i)) }),
9929
- /* @__PURE__ */ jsxs6(Text6, { wrap: "truncate", children: [
9930
- /* @__PURE__ */ jsx6(Text6, { backgroundColor: BG2, color: "white", bold: true, children: " ENTRY " }),
9931
- /* @__PURE__ */ jsx6(Text6, { backgroundColor: "#0b1530", color: "white", children: ` ${e.id} ` }),
9932
- /* @__PURE__ */ jsx6(Text6, { backgroundColor: BG2, color: "white", children: " \u2191\u2193 scroll \xB7 space copy \xB7 ? all keys \xB7 \u2190 back \xB7 esc menu " })
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__ */ jsxs6(Text6, { children: [
9937
- /* @__PURE__ */ jsxs6(Text6, { color: theme.dim, children: [
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__ */ jsx6(Text6, { color: on ? theme.accentBright : theme.dim, children: val }),
9942
- /* @__PURE__ */ jsx6(Text6, { children: " " })
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__ */ jsx6(DataView, { loading: sessLoading && !frozen, error: source === "cloud" ? agentsQ.error : localQ.error, children: /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
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__ */ jsxs6(Box6, { children: [
10121
+ /* @__PURE__ */ jsxs7(Box7, { children: [
9954
10122
  srcChip,
9955
- /* @__PURE__ */ jsx6(Text6, { color: theme.accentBright, bold: true, children: "SESSIONS" }),
9956
- /* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: " \xB7 logs (v) " }),
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__ */ jsx6(Text6, { 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" }),
9961
- editing === "sess-search" ? /* @__PURE__ */ jsxs6(Box6, { children: [
9962
- /* @__PURE__ */ jsx6(Text6, { color: theme.warn, children: "search: " }),
9963
- /* @__PURE__ */ jsx6(
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__ */ jsx6(Text6, { 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}` : ""}` }),
9976
- /* @__PURE__ */ jsx6(
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__ */ jsxs6(Text6, { color: theme.dim, children: [
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__ */ jsx6(DataView, { loading: logsLoading && !frozen, error: source === "cloud" ? cloudQ.error : localQ.error, children: /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
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__ */ jsxs6(Box6, { children: [
10191
+ /* @__PURE__ */ jsxs7(Box7, { children: [
10024
10192
  srcChip,
10025
- /* @__PURE__ */ jsx6(Text6, { color: theme.accentBright, bold: true, children: "LOGS" }),
10026
- /* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: " \xB7 sessions (v) " }),
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__ */ jsx6(Text6, { 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" }),
10035
- msg ? /* @__PURE__ */ jsx6(Text6, { color: msg.level === "bad" ? theme.bad : theme.ok, children: truncate2(msg.text, cols) }) : null,
10036
- editing && editing !== "sess-search" ? /* @__PURE__ */ jsxs6(Box6, { children: [
10037
- /* @__PURE__ */ jsxs6(Text6, { color: theme.warn, children: [
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__ */ jsx6(
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__ */ jsx6(Text6, { 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` : ""}` }),
10055
- /* @__PURE__ */ jsx6(Box6, { flexDirection: "column", overflow: "hidden", children: windowed.map((e, i) => /* @__PURE__ */ jsx6(StreamLine, { e: toStream(e), loc: source === "local", selected: start + i === selClamped && focused, date: true }, e.id)) }),
10056
- pageRows.length === 0 ? /* @__PURE__ */ jsxs6(Text6, { color: theme.dim, children: [
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 Box7, Text as Text7, useInput as useInput6 } from "ink";
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 useEffect6, useRef as useRef3, useState as useState7 } from "react";
10468
- import { Fragment as Fragment5, jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
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] = useState7(0);
10479
- const [editing, setEditing] = useState7(null);
10480
- const [input, setInput] = useState7("");
10481
- const [confirmDel, setConfirmDel] = useState7(null);
10482
- const [msg, setMsg] = useState7(null);
10483
- const [busy, setBusy] = useState7(false);
10484
- const [editor, setEditor] = useState7(null);
10485
- const [latest, setLatest] = useState7(null);
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
- useEffect6(() => {
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] = useState7(() => listAccounts());
10498
- const [login, setLogin] = useState7(null);
10499
- const [tick, setTick] = useState7(0);
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] = useState7(() => isGuardInstalled());
10503
- const [guardVer, setGuardVer] = useState7(() => installedGuardVersion());
10504
- const [guardOld, setGuardOld] = useState7(() => guardHookOutdated());
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] = useState7(() => logsServerStatus());
10512
- useEffect6(() => {
10679
+ const [srv, setSrv] = useState8(() => logsServerStatus());
10680
+ useEffect7(() => {
10513
10681
  const t = setInterval(() => setSrv(logsServerStatus()), 3e3);
10514
10682
  return () => clearInterval(t);
10515
10683
  }, []);
10516
- useEffect6(() => {
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
- useEffect6(() => {
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] = useState7(/* @__PURE__ */ new Set());
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
- useInput6(
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__ */ jsxs7(Box7, { flexDirection: "column", children: [
10856
- /* @__PURE__ */ jsx7(Text7, { bold: true, color: theme.accentBright, children: "Add an account" }),
10857
- login.phase === "starting" ? /* @__PURE__ */ jsxs7(Text7, { color: theme.dim, children: [
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__ */ jsxs7(Box7, { flexDirection: "column", marginTop: 1, children: [
10861
- /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "Opening your browser to authorize. If it didn't open, visit:" }),
10862
- /* @__PURE__ */ jsx7(Text7, { color: theme.accentBright, bold: true, wrap: "truncate", children: login.url }),
10863
- /* @__PURE__ */ jsxs7(Box7, { marginTop: 1, children: [
10864
- /* @__PURE__ */ jsxs7(Text7, { color: theme.warn, children: [
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__ */ jsx7(Text7, { color: theme.dim, children: "esc to cancel" })
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__ */ jsxs7(Text7, { wrap: "truncate", children: [
10875
- /* @__PURE__ */ jsx7(Text7, { color: editor.field === idx ? theme.accentBright : theme.dim, children: editor.field === idx ? "\u25B8 " : " " }),
10876
- /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: label.padEnd(11) }),
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__ */ jsx7(Text7, { color: theme.dim, children: " " + hint }) : null
11046
+ editor.field === idx && hint ? /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: " " + hint }) : null
10879
11047
  ] });
10880
- return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
10881
- /* @__PURE__ */ jsxs7(Text7, { bold: true, color: theme.accentBright, children: [
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__ */ jsx7(Text7, { color: theme.dim, children: "\u2191\u2193 field \xB7 \u2190\u2192 change \xB7 e edit target \xB7 enter save \xB7 esc cancel" }),
10888
- editing === "alert-target" ? /* @__PURE__ */ jsxs7(Box7, { marginTop: 1, children: [
10889
- /* @__PURE__ */ jsx7(Text7, { color: theme.warn, children: editor.channel === "email" ? "e-mail address: " : "telegram chat id (from @userinfobot): " }),
10890
- /* @__PURE__ */ jsx7(TextInput5, { value: input, onChange: setInput, onSubmit: submitInput })
10891
- ] }) : msg ? /* @__PURE__ */ jsx7(Text7, { color: msg.level === "bad" ? theme.bad : theme.ok, children: truncate2(msg.text, cols) }) : /* @__PURE__ */ jsx7(Text7, { children: " " }),
10892
- /* @__PURE__ */ jsxs7(Box7, { marginTop: 1, flexDirection: "column", children: [
10893
- fieldRow(0, "target", editor.target ? /* @__PURE__ */ jsx7(Text7, { color: theme.accent, children: truncate2(editor.target, cols - 16) }) : /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "empty \u2014 press e" }), "press e to edit"),
10894
- fieldRow(1, "signal", /* @__PURE__ */ jsx7(Text7, { color: theme.accent, children: SIGNAL_LABEL[editor.signal] }), "\u2190\u2192 change"),
10895
- fieldRow(2, "threshold", /* @__PURE__ */ jsx7(Text7, { color: theme.accent, children: `\u2265 ${editor.threshold}` }), "\u2190\u2192 \xB15"),
10896
- fieldRow(3, "window", /* @__PURE__ */ jsx7(Text7, { color: theme.accent, children: winLabel(editor.windowSeconds) }), "\u2190\u2192 change"),
10897
- editor.id ? fieldRow(4, "status", editor.enabled ? /* @__PURE__ */ jsx7(Text7, { color: theme.ok, children: "on" }) : /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "off" }), "\u2190\u2192 turn on/off") : null
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__ */ jsx7(Box7, { marginTop: 1, children: editor.id && !editor.enabled ? /* @__PURE__ */ jsx7(Text7, { color: theme.warn, children: "disabled \u2014 this alert will NOT fire until you set status back to on" }) : /* @__PURE__ */ jsxs7(Text7, { color: theme.dim, children: [
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__ */ jsx7(Text7, { color: theme.accent, children: SIGNAL_LABEL[editor.signal] }),
11069
+ /* @__PURE__ */ jsx8(Text8, { color: theme.accent, children: SIGNAL_LABEL[editor.signal] }),
10902
11070
  " reach ",
10903
- /* @__PURE__ */ jsx7(Text7, { color: theme.accent, children: editor.threshold }),
11071
+ /* @__PURE__ */ jsx8(Text8, { color: theme.accent, children: editor.threshold }),
10904
11072
  " within",
10905
11073
  " ",
10906
- /* @__PURE__ */ jsx7(Text7, { color: theme.accent, children: winLabel(editor.windowSeconds) })
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__ */ jsx7(Text7, { color: theme.ok, children: "on " }) : /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "off" });
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__ */ jsx7(Text7, { color: isCur(r) ? theme.accentBright : theme.dim, children: isCur(r) ? "\u25B8 " : " " });
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__ */ jsxs7(Text7, { wrap: "truncate", children: [
11090
+ return /* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", children: [
10923
11091
  cursor(r),
10924
- /* @__PURE__ */ jsx7(Text7, { color: theme.accent, children: truncate2(acctLabel(a), 30).padEnd(31) }),
10925
- isView ? /* @__PURE__ */ jsx7(Text7, { color: theme.ok, children: "\u25CF viewing " }) : /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: " " }),
10926
- isActive ? /* @__PURE__ */ jsx7(Text7, { color: theme.warn, children: "ACTIVE " }) : /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: " " }),
10927
- /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: a.project ? truncate2(a.project, 20) : "" })
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__ */ jsxs7(Text7, { wrap: "truncate", children: [
11099
+ return /* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", children: [
10932
11100
  cursor(r),
10933
- /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "+ add account (enter \u2014 device login in the browser)" })
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__ */ jsxs7(Text7, { wrap: "truncate", children: [
11104
+ return /* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", children: [
10937
11105
  cursor(r),
10938
- /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "guard".padEnd(11) }),
10939
- !guardHere ? /* @__PURE__ */ jsxs7(Fragment5, { children: [
10940
- /* @__PURE__ */ jsx7(Text7, { color: theme.bad, bold: true, children: "removed" }),
10941
- /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: " \xB7 " }),
10942
- /* @__PURE__ */ jsx7(Text7, { color: theme.accentBright, children: "enter to install" })
10943
- ] }) : /* @__PURE__ */ jsxs7(Fragment5, { children: [
10944
- /* @__PURE__ */ jsx7(Text7, { color: guardOld ? theme.warn : theme.ok, children: `v${guardVer ?? "?"}` }),
10945
- /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: guardOld ? " \xB7 update available \xB7 enter update" : " (latest) \xB7 enter reinstall" }),
10946
- /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: " \xB7 d remove" })
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__ */ jsxs7(Text7, { wrap: "truncate", children: [
11118
+ return /* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", children: [
10951
11119
  cursor(r),
10952
- /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "self-prot".padEnd(11) }),
10953
- selfProt ? onOff(selfProt.enabled) : /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "\u2026" }),
10954
- /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: " blocks agents editing SolonGate\u2019s own hooks/config \xB7 enter toggles" })
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__ */ jsxs7(Text7, { wrap: "truncate", children: [
11125
+ return /* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", children: [
10958
11126
  cursor(r),
10959
- /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "enabled ".padEnd(11) }),
11127
+ /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "enabled ".padEnd(11) }),
10960
11128
  onOff(!!local?.enabled),
10961
- /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: " enter toggles" })
11129
+ /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: " enter toggles" })
10962
11130
  ] });
10963
11131
  case "ll-path":
10964
- return /* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
11132
+ return /* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", children: [
10965
11133
  cursor(r),
10966
- /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "path ".padEnd(11) }),
10967
- local?.path ? /* @__PURE__ */ jsx7(Text7, { color: theme.accent, children: truncate2(local.path, cols - 14) }) : /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "not set \u2014 enter to edit" })
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__ */ jsxs7(Text7, { wrap: "truncate", children: [
11138
+ return /* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", children: [
10971
11139
  cursor(r),
10972
- /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "dashboard".padEnd(11) }),
10973
- srv.running ? /* @__PURE__ */ jsx7(Text7, { color: theme.ok, children: `running 127.0.0.1:${srv.port}` }) : /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "stopped" }),
10974
- /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: srv.running ? " survives closing the dataroom \xB7 enter stops" : " enter starts the dashboard local-logs link" })
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__ */ jsxs7(Text7, { wrap: "truncate", children: [
11145
+ return /* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", children: [
10978
11146
  cursor(r),
10979
11147
  onOff(r.wh.enabled),
10980
- /* @__PURE__ */ jsx7(Text7, { color: theme.warn, children: (" " + r.wh.events).padEnd(9) }),
10981
- /* @__PURE__ */ jsx7(Text7, { color: theme.accent, children: truncate2(r.wh.url, cols - 16) })
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__ */ jsxs7(Text7, { wrap: "truncate", children: [
11152
+ return /* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", children: [
10985
11153
  cursor(r),
10986
- /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "+ add webhook (enter)" })
11154
+ /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "+ add webhook (enter)" })
10987
11155
  ] });
10988
11156
  case "alert":
10989
- return /* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
11157
+ return /* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", children: [
10990
11158
  cursor(r),
10991
11159
  onOff(r.rule.enabled),
10992
- /* @__PURE__ */ jsx7(Text7, { color: theme.warn, children: (" " + SIGNAL_LABEL[r.rule.signal]).padEnd(13) }),
10993
- /* @__PURE__ */ jsx7(Text7, { children: `\u2265${r.rule.threshold}/${winLabel(r.rule.windowSeconds)} `.padEnd(11) }),
10994
- /* @__PURE__ */ jsx7(Text7, { color: theme.accent, children: truncate2(chanOf(r.rule), cols - 34) })
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__ */ jsxs7(Text7, { wrap: "truncate", children: [
11165
+ return /* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", children: [
10998
11166
  cursor(r),
10999
- /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "+ add email alert (enter)" })
11167
+ /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "+ add email alert (enter)" })
11000
11168
  ] });
11001
11169
  case "alert-add-tg":
11002
- return /* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
11170
+ return /* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", children: [
11003
11171
  cursor(r),
11004
- /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "+ add telegram alert (enter \u2014 numeric chat id from @userinfobot)" })
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__ */ jsx7(Text7, { children: " " }, "sp:" + sec));
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__ */ jsxs7(Text7, { wrap: "truncate", children: [
11029
- /* @__PURE__ */ jsx7(Text7, { bold: true, color: theme.accentBright, children: sec }),
11030
- /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: " \u2014 " + SECTION_DESC[sec] })
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__ */ jsx7(Text7, { 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)
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__ */ jsx7(Box7, { children: rowLine(r) }, keyOf(r)));
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__ */ jsx7(Text7, { color: theme.dim, children: " both channels in use \u2014 remove one (d) to change it" }, "both-note")
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__ */ jsx7(Text7, { children: " " }, "ver-sp"));
11218
+ lineEls.push(/* @__PURE__ */ jsx8(Text8, { children: " " }, "ver-sp"));
11051
11219
  lineKey.push("");
11052
11220
  lineEls.push(
11053
- /* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", color: theme.dim, children: [
11221
+ /* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", color: theme.dim, children: [
11054
11222
  `solongate v${ver}`,
11055
- latest ? newerThan(latest, ver) ? /* @__PURE__ */ jsx7(Text7, { color: theme.warn, children: ` \xB7 v${latest} on npm \u2014 auto-updating` }) : /* @__PURE__ */ jsx7(Text7, { color: theme.ok, children: " \xB7 latest" }) : null
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__ */ jsx7(DataView, { loading, error, children: /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
11067
- /* @__PURE__ */ jsx7(Text7, { 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" }),
11068
- editing ? /* @__PURE__ */ jsxs7(Box7, { children: [
11069
- /* @__PURE__ */ jsx7(Text7, { color: theme.warn, children: editing === "path" ? "local log path: " : "webhook url: " }),
11070
- /* @__PURE__ */ jsx7(TextInput5, { value: input, onChange: setInput, onSubmit: submitInput })
11071
- ] }) : msg ? /* @__PURE__ */ jsx7(Text7, { wrap: "truncate", color: msg.level === "bad" ? theme.bad : theme.ok, children: truncate2(msg.text, cols) }) : login?.msg ? /* @__PURE__ */ jsx7(Text7, { wrap: "truncate", color: login.phase === "error" ? theme.bad : theme.ok, children: login.msg }) : /* @__PURE__ */ jsx7(Text7, { children: " " }),
11072
- /* @__PURE__ */ jsx7(Box7, { flexDirection: "column", height: budget, overflow: "hidden", children: win })
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 Box8, Text as Text8, useApp, useInput as useInput7 } from "ink";
11109
- import { useEffect as useEffect7, useState as useState8 } from "react";
11110
- import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
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__ */ jsxs8(Box8, { flexDirection: "column", children: [
11113
- /* @__PURE__ */ jsx8(Text8, { color: theme.accentBright, bold: true, children: "\u25B6 REALTIME CONSOLE" }),
11114
- /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "Fullscreen live monitor \u2014 streaming tool calls, active charts," }),
11115
- /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "counters, DLP hits and denial alerts. Updates every 2s." }),
11116
- /* @__PURE__ */ jsx8(Box8, { marginTop: 1, children: /* @__PURE__ */ jsxs8(Text8, { children: [
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__ */ jsx8(Text8, { color: theme.accent, children: "enter" }),
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__ */ jsxs8(Box8, { children: [
11147
- /* @__PURE__ */ jsx8(Text8, { bold: true, color: theme.accentBright, children: "SolonGate" }),
11148
- /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: " \u2014 security control center" })
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__ */ jsxs8(Box8, { flexDirection: "column", children: [
11152
- BANNER_FULL.map((line, i) => /* @__PURE__ */ jsx8(Text8, { bold: true, color: BANNER_HEX[i], children: line }, i)),
11153
- /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: " security control center \xB7 manage policies, rate limits, DLP & more" })
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] = useState8(() => listAccounts());
11159
- const [viewKey, setViewKey] = useState8(() => accounts[0]?.apiKey);
11160
- const [viewNonce, setViewNonce] = useState8(0);
11161
- const [section, setSection] = useState8(accounts.length === 0 ? SETTINGS_SECTION : 0);
11162
- const [focus, setFocus] = useState8("nav");
11163
- const [help, setHelp] = useState8(false);
11164
- const [update2, setUpdate] = useState8({ kind: "idle" });
11165
- useEffect7(() => {
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
- useEffect7(() => {
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
- useInput7((input, key) => {
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__ */ jsx8(HelpOverlay, { cols, rows });
11390
+ if (help) return /* @__PURE__ */ jsx9(HelpOverlay, { cols, rows });
11243
11391
  if (current.label === "Live" && focus === "panel") {
11244
- return /* @__PURE__ */ jsx8(Box8, { flexDirection: "column", width: cols, height: rows - 1, overflow: "hidden", children: /* @__PURE__ */ jsx8(LivePanel, { active: true, focused: true }, viewNonce) });
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__ */ jsx8(SettingsPanel, { active: true, focused: focus === "panel", viewApiKey: viewKey, onView: viewAccount, onAccountsChanged: syncAccounts }) : /* @__PURE__ */ jsx8(Panel, { active: focus === "panel" || current.label !== "Live", focused: focus === "panel" });
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__ */ jsxs8(Box8, { flexDirection: "column", width: cols, height: rows - 1, paddingX: 1, paddingTop: 1, overflow: "hidden", children: [
11253
- /* @__PURE__ */ jsx8(Banner, { cols }),
11254
- /* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", children: [
11255
- /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "account: " }),
11256
- /* @__PURE__ */ jsx8(Text8, { color: locked ? theme.warn : theme.accentBright, bold: true, children: acctLabel2 }),
11257
- locked ? /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: " \xB7 log in from Settings to unlock the dataroom" }) : accounts.length > 1 ? /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: ` (${acctIdx + 1}/${accounts.length} \xB7 a switch \xB7 Settings to manage)` }) : /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: " \xB7 Settings to add another" }),
11258
- update2.kind === "updating" ? /* @__PURE__ */ jsx8(Text8, { color: theme.warn, children: ` \u2191 updating to v${update2.version}\u2026` }) : update2.kind === "updated" ? /* @__PURE__ */ jsx8(Text8, { color: theme.ok, bold: true, children: ` \u2191 v${update2.version} installed \u2014 restart (q, then solongate) to apply` }) : null
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__ */ jsxs8(Box8, { marginTop: 1, flexGrow: 1, children: [
11261
- /* @__PURE__ */ jsx8(Box8, { flexDirection: "column", flexShrink: 0, width: 16, borderStyle: "round", borderColor: focus === "nav" ? theme.accent : "gray", paddingX: 1, children: SECTIONS.map((s, i) => {
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__ */ jsx8(Text8, { color: isCur ? theme.accentBright : disabled ? theme.dim : void 0, bold: isCur, dimColor: disabled, children: (isCur ? "\u25B8 " : disabled ? "\u2298 " : " ") + s.label }, s.label);
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__ */ jsx8(Box8, { flexGrow: 1, minWidth: 0, borderStyle: "round", borderColor: focus === "panel" ? theme.accent : "gray", paddingX: 1, paddingY: 0, overflow: "hidden", children: panelBody })
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__ */ jsx8(Box8, { children: locked ? /* @__PURE__ */ jsx8(KeyHints, { hints: [["\u2192/enter", "open Settings"], ["n", "log in"], ["q", "quit"]] }) : focus === "nav" ? /* @__PURE__ */ jsx8(KeyHints, { hints: [["\u2191\u2193", "section"], ["\u2192/enter", "open"], ...accounts.length > 1 ? [["a", "account"]] : [], ["?", "help"], ["q", "quit"]] }) : /* @__PURE__ */ jsx8(KeyHints, { hints: [["\u2190/esc", "back"], ["\u2191\u2193", "in-panel"], ["space/s", "act"]] }) })
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__ */ jsxs8(Box8, { flexDirection: "column", width: cols, height: rows, paddingX: 2, paddingTop: 1, children: [
11274
- /* @__PURE__ */ jsx8(Text8, { bold: true, color: theme.accentBright, children: "SolonGate \u2014 keyboard shortcuts" }),
11275
- /* @__PURE__ */ jsx8(Box8, { marginTop: 1, flexDirection: "column", children: HELP.map(([group, keys]) => /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", marginBottom: 1, children: [
11276
- /* @__PURE__ */ jsx8(Text8, { bold: true, color: theme.accent, children: group }),
11277
- keys.map(([k, desc]) => /* @__PURE__ */ jsxs8(Text8, { children: [
11278
- /* @__PURE__ */ jsx8(Text8, { color: theme.accentBright, children: (" " + k).padEnd(16) }),
11279
- /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: desc })
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__ */ jsx8(Text8, { color: theme.dim, children: "press any key to close" })
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 jsx9 } from "react/jsx-runtime";
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__ */ jsx9(App, {}), { patchConsole: false });
11509
+ const { waitUntilExit } = render(/* @__PURE__ */ jsx10(App, {}), { patchConsole: false });
11362
11510
  await waitUntilExit();
11363
11511
  } finally {
11364
11512
  Object.assign(console, saved);