@solongate/proxy 0.81.49 → 0.81.50

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
@@ -9956,8 +9956,8 @@ var init_Audit = __esm({
9956
9956
  // src/tui/panels/Settings.tsx
9957
9957
  import { Box as Box7, Text as Text7, useInput as useInput6 } from "ink";
9958
9958
  import TextInput5 from "ink-text-input";
9959
- import { useState as useState7 } from "react";
9960
- import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
9959
+ import { useEffect as useEffect6, useRef as useRef3, useState as useState7 } from "react";
9960
+ import { Fragment as Fragment5, jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
9961
9961
  function alertBodyFor(channel) {
9962
9962
  const c2 = channel.trim();
9963
9963
  const base = { name: "dataroom alert", threshold: 5, windowSeconds: 60, signal: "any" };
@@ -9965,7 +9965,12 @@ function alertBodyFor(channel) {
9965
9965
  if (c2.includes("@")) return { ...base, emails: [c2] };
9966
9966
  return { ...base, telegram: [c2] };
9967
9967
  }
9968
- function SettingsPanel({ active: active2, focused }) {
9968
+ function SettingsPanel({
9969
+ active: active2,
9970
+ focused,
9971
+ viewApiKey,
9972
+ onView
9973
+ }) {
9969
9974
  void active2;
9970
9975
  const { cols, rows } = usePanelSize();
9971
9976
  const [sel, setSel] = useState7(0);
@@ -9974,24 +9979,40 @@ function SettingsPanel({ active: active2, focused }) {
9974
9979
  const [confirmDel, setConfirmDel] = useState7(null);
9975
9980
  const [msg, setMsg] = useState7(null);
9976
9981
  const [busy, setBusy] = useState7(false);
9977
- const localQ = useLoader(() => api.settings.getLocalLogs());
9978
- const whQ = useLoader(() => api.settings.getWebhooks());
9979
- const alertQ = useLoader(() => api.settings.getAlerts());
9982
+ const [accounts, setAccounts] = useState7(() => listAccounts());
9983
+ const [login, setLogin] = useState7(null);
9984
+ const [tick, setTick] = useState7(0);
9985
+ const abort = useRef3(false);
9986
+ const refreshAccounts = () => setAccounts(listAccounts());
9987
+ const locked = accounts.length === 0;
9988
+ useEffect6(() => {
9989
+ if (!login || login.phase === "done" || login.phase === "error") return;
9990
+ const t = setInterval(() => setTick((n) => n + 1), 120);
9991
+ return () => clearInterval(t);
9992
+ }, [login]);
9993
+ const localQ = useLoader(() => listAccounts().length ? api.settings.getLocalLogs() : Promise.resolve(null));
9994
+ const whQ = useLoader(() => listAccounts().length ? api.settings.getWebhooks() : Promise.resolve(null));
9995
+ const alertQ = useLoader(() => listAccounts().length ? api.settings.getAlerts() : Promise.resolve(null));
9980
9996
  const local = localQ.data;
9981
9997
  const webhooks = whQ.data?.webhooks ?? [];
9982
9998
  const alerts = alertQ.data?.rules ?? [];
9983
9999
  const rowsAll = [
9984
- { kind: "ll-enabled" },
9985
- { kind: "ll-path" },
9986
- ...webhooks.map((wh) => ({ kind: "wh", wh })),
9987
- { kind: "wh-add" },
9988
- ...alerts.map((rule) => ({ kind: "alert", rule })),
9989
- { kind: "alert-add" }
10000
+ ...accounts.map((acc) => ({ kind: "acct", acc })),
10001
+ { kind: "acct-add" },
10002
+ ...locked ? [] : [
10003
+ { kind: "ll-enabled" },
10004
+ { kind: "ll-path" },
10005
+ ...webhooks.map((wh) => ({ kind: "wh", wh })),
10006
+ { kind: "wh-add" },
10007
+ ...alerts.map((rule) => ({ kind: "alert", rule })),
10008
+ { kind: "alert-add" }
10009
+ ]
9990
10010
  ];
9991
10011
  const selClamped = Math.min(sel, rowsAll.length - 1);
9992
10012
  const cur = rowsAll[selClamped];
9993
- const keyOf = (r) => r.kind === "wh" ? "wh:" + r.wh.id : r.kind === "alert" ? "alert:" + r.rule.id : r.kind;
10013
+ const keyOf = (r) => r.kind === "acct" ? "acct:" + r.acc.apiKey : r.kind === "wh" ? "wh:" + r.wh.id : r.kind === "alert" ? "alert:" + r.rule.id : r.kind;
9994
10014
  const reloadAll = () => {
10015
+ refreshAccounts();
9995
10016
  localQ.reload();
9996
10017
  whQ.reload();
9997
10018
  alertQ.reload();
@@ -10005,8 +10026,48 @@ function SettingsPanel({ active: active2, focused }) {
10005
10026
  reload();
10006
10027
  }).catch((e) => setMsg({ text: "\u2717 " + (e instanceof Error ? e.message : String(e)), level: "bad" })).finally(() => setBusy(false));
10007
10028
  };
10029
+ const beginLogin = () => {
10030
+ if (login && (login.phase === "starting" || login.phase === "waiting")) return;
10031
+ abort.current = false;
10032
+ setLogin({ phase: "starting" });
10033
+ void (async () => {
10034
+ let start2;
10035
+ try {
10036
+ start2 = await startDeviceLogin(DEFAULT_API_URL2);
10037
+ } catch (e) {
10038
+ setLogin({ phase: "error", msg: "could not reach SolonGate: " + (e instanceof Error ? e.message : String(e)) });
10039
+ return;
10040
+ }
10041
+ setLogin({ phase: "waiting", url: start2.verifyUrl });
10042
+ openBrowser(start2.verifyUrl);
10043
+ while (Date.now() < start2.expiresAt && !abort.current) {
10044
+ await new Promise((r) => setTimeout(r, start2.intervalMs));
10045
+ if (abort.current) return;
10046
+ const res = await pollDeviceLogin(DEFAULT_API_URL2, start2.deviceCode);
10047
+ if (res.status === "approved" && res.apiKey) {
10048
+ saveAccount({ apiKey: res.apiKey, apiUrl: DEFAULT_API_URL2, project: res.project, user: res.user, email: res.email });
10049
+ setLogin({ phase: "done", msg: `\u2713 added ${res.email || res.user || res.project || "account"}` });
10050
+ setViewCredentials({ apiKey: res.apiKey, apiUrl: DEFAULT_API_URL2 });
10051
+ onView?.({ apiKey: res.apiKey, apiUrl: DEFAULT_API_URL2, project: res.project, user: res.user, email: res.email });
10052
+ reloadAll();
10053
+ return;
10054
+ }
10055
+ if (res.status === "expired" || res.status === "not_found") {
10056
+ setLogin({ phase: "error", msg: "code expired \u2014 press n to retry" });
10057
+ return;
10058
+ }
10059
+ }
10060
+ if (!abort.current) setLogin({ phase: "error", msg: "timed out \u2014 press n to retry" });
10061
+ })();
10062
+ };
10008
10063
  const activate = (r) => {
10009
- if (r.kind === "ll-enabled") {
10064
+ if (r.kind === "acct") {
10065
+ setViewCredentials({ apiKey: r.acc.apiKey, apiUrl: r.acc.apiUrl });
10066
+ onView?.(r.acc);
10067
+ setMsg({ text: `viewing ${acctLabel(r.acc)}`, level: "ok" });
10068
+ } else if (r.kind === "acct-add") {
10069
+ beginLogin();
10070
+ } else if (r.kind === "ll-enabled") {
10010
10071
  if (!local) return;
10011
10072
  if (!local.enabled && !local.path.trim()) {
10012
10073
  setMsg({ text: "set a path first (\u2193 then enter)", level: "bad" });
@@ -10045,6 +10106,13 @@ function SettingsPanel({ active: active2, focused }) {
10045
10106
  };
10046
10107
  useInput6(
10047
10108
  (inp, key) => {
10109
+ if (login && (login.phase === "starting" || login.phase === "waiting")) {
10110
+ if (key.escape) {
10111
+ abort.current = true;
10112
+ setLogin(null);
10113
+ }
10114
+ return;
10115
+ }
10048
10116
  setMsg(null);
10049
10117
  if (key.upArrow) {
10050
10118
  setSel((n) => Math.max(0, n - 1));
@@ -10053,6 +10121,11 @@ function SettingsPanel({ active: active2, focused }) {
10053
10121
  setSel((n) => Math.min(rowsAll.length - 1, n + 1));
10054
10122
  setConfirmDel(null);
10055
10123
  } else if (key.return || inp === " ") activate(cur);
10124
+ else if (inp === "m" && cur.kind === "acct") {
10125
+ const ok = setActiveAccount({ apiKey: cur.acc.apiKey, apiUrl: cur.acc.apiUrl });
10126
+ setMsg(ok ? { text: `\u2713 ${acctLabel(cur.acc)} is now the ACTIVE key (guard + logging)`, level: "ok" } : { text: "\u2717 could not set active", level: "bad" });
10127
+ refreshAccounts();
10128
+ } else if (inp === "n") beginLogin();
10056
10129
  else if (inp === "e" && cur.kind === "wh") {
10057
10130
  const next = EVENTS[(EVENTS.indexOf(cur.wh.events) + 1) % EVENTS.length];
10058
10131
  run12(`webhook events \u2192 ${next}`, () => api.settings.updateWebhook(cur.wh.id, { events: next }), whQ.reload);
@@ -10079,247 +10152,163 @@ function SettingsPanel({ active: active2, focused }) {
10079
10152
  },
10080
10153
  { isActive: focused && !editing }
10081
10154
  );
10082
- const loading = localQ.loading && !localQ.data || whQ.loading && !whQ.data || alertQ.loading && !alertQ.data;
10083
- const error = localQ.error ?? whQ.error ?? alertQ.error;
10155
+ const spin = SPIN2[tick % SPIN2.length];
10156
+ if (login && (login.phase === "starting" || login.phase === "waiting")) {
10157
+ return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
10158
+ /* @__PURE__ */ jsx7(Text7, { bold: true, color: theme.accentBright, children: "Add an account" }),
10159
+ login.phase === "starting" ? /* @__PURE__ */ jsxs7(Text7, { color: theme.dim, children: [
10160
+ spin,
10161
+ " starting device pairing\u2026"
10162
+ ] }) : /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", marginTop: 1, children: [
10163
+ /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "Opening your browser to authorize. If it didn't open, visit:" }),
10164
+ /* @__PURE__ */ jsx7(Text7, { color: theme.accentBright, bold: true, wrap: "truncate", children: login.url }),
10165
+ /* @__PURE__ */ jsxs7(Box7, { marginTop: 1, children: [
10166
+ /* @__PURE__ */ jsxs7(Text7, { color: theme.warn, children: [
10167
+ spin,
10168
+ " waiting for authorization\u2026 "
10169
+ ] }),
10170
+ /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "esc to cancel" })
10171
+ ] })
10172
+ ] })
10173
+ ] });
10174
+ }
10175
+ const loading = !locked && (localQ.loading && !localQ.data || whQ.loading && !whQ.data || alertQ.loading && !alertQ.data);
10176
+ const error = locked ? null : localQ.error ?? whQ.error ?? alertQ.error;
10084
10177
  const mark = (r) => keyOf(r) === keyOf(cur) && focused ? "\u25B8 " : " ";
10085
10178
  const onOff = (on) => on ? /* @__PURE__ */ jsx7(Text7, { color: theme.ok, children: "on " }) : /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "off" });
10086
10179
  const chanOf = (rule) => [...(rule.slackUrls ?? []).map((u) => "slack " + u), ...rule.emails ?? [], ...(rule.telegram ?? []).map((t) => "tg " + t)].join(", ") || "\u2014";
10087
- const listBudget = Math.max(4, rows - 8);
10180
+ const listBudget = Math.max(4, rows - 10);
10088
10181
  const start = Math.min(Math.max(0, selClamped - Math.floor(listBudget / 2)), Math.max(0, rowsAll.length - listBudget));
10089
10182
  const inWindow = (r) => {
10090
10183
  const i = rowsAll.findIndex((x) => keyOf(x) === keyOf(r));
10091
10184
  return i >= start && i < start + listBudget;
10092
10185
  };
10093
10186
  return /* @__PURE__ */ jsx7(DataView, { loading, error, children: /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
10094
- /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: focused ? "\u2191\u2193 move \xB7 enter/space toggle-edit-add \xB7 e events \xB7 d delete \xB7 r refresh" : "press \u2192 to configure" }),
10187
+ /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: focused ? "\u2191\u2193 move \xB7 enter view-toggle-edit \xB7 m make active \xB7 n add account \xB7 e events \xB7 d delete \xB7 r refresh" : "press \u2192 to configure" }),
10095
10188
  editing ? /* @__PURE__ */ jsxs7(Box7, { children: [
10096
10189
  /* @__PURE__ */ jsx7(Text7, { color: theme.warn, children: editing === "path" ? "local log path: " : editing === "wh-url" ? "webhook url: " : "channel (slack url / email / telegram id): " }),
10097
10190
  /* @__PURE__ */ jsx7(TextInput5, { value: input, onChange: setInput, onSubmit: submitInput })
10098
- ] }) : msg ? /* @__PURE__ */ jsx7(Text7, { color: msg.level === "bad" ? theme.bad : theme.ok, children: truncate2(msg.text, cols) }) : /* @__PURE__ */ jsx7(Text7, { children: " " }),
10099
- inWindow(rowsAll[0]) || inWindow(rowsAll[1]) ? /* @__PURE__ */ jsxs7(Box7, { marginTop: 1, flexDirection: "column", children: [
10100
- /* @__PURE__ */ jsxs7(Text7, { bold: true, color: theme.accentBright, children: [
10101
- "LOCAL LOGS ",
10102
- /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "\u2014 hooks mirror every decision to a file on the agent machine" })
10103
- ] }),
10104
- /* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
10105
- /* @__PURE__ */ jsx7(Text7, { color: keyOf(cur) === "ll-enabled" && focused ? theme.accentBright : theme.dim, children: mark(rowsAll[0]) }),
10106
- /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "enabled ".padEnd(10) }),
10107
- onOff(!!local?.enabled),
10108
- /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: " enter toggles" })
10109
- ] }),
10110
- /* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
10111
- /* @__PURE__ */ jsx7(Text7, { color: keyOf(cur) === "ll-path" && focused ? theme.accentBright : theme.dim, children: mark(rowsAll[1]) }),
10112
- /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "path ".padEnd(10) }),
10113
- 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" })
10114
- ] })
10115
- ] }) : null,
10191
+ ] }) : msg ? /* @__PURE__ */ jsx7(Text7, { color: msg.level === "bad" ? theme.bad : theme.ok, children: truncate2(msg.text, cols) }) : login?.msg ? /* @__PURE__ */ jsx7(Text7, { color: login.phase === "error" ? theme.bad : theme.ok, children: login.msg }) : /* @__PURE__ */ jsx7(Text7, { children: " " }),
10116
10192
  /* @__PURE__ */ jsxs7(Box7, { marginTop: 1, flexDirection: "column", children: [
10117
10193
  /* @__PURE__ */ jsxs7(Text7, { bold: true, color: theme.accentBright, children: [
10118
- "WEBHOOKS ",
10194
+ "ACCOUNTS ",
10119
10195
  /* @__PURE__ */ jsxs7(Text7, { color: theme.dim, children: [
10120
- "\u2014 POST every matching event to your endpoint (",
10121
- webhooks.length,
10122
- ")"
10196
+ "\u2014 logged in on this device (",
10197
+ accounts.length,
10198
+ ") \xB7 \u25CF viewing = shown here \xB7 ACTIVE = key the guard uses"
10123
10199
  ] })
10124
10200
  ] }),
10125
- webhooks.filter((wh) => inWindow({ kind: "wh", wh })).map((wh) => /* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
10126
- /* @__PURE__ */ jsx7(Text7, { color: keyOf(cur) === "wh:" + wh.id && focused ? theme.accentBright : theme.dim, children: mark({ kind: "wh", wh }) }),
10127
- onOff(wh.enabled),
10128
- /* @__PURE__ */ jsx7(Text7, { color: theme.warn, children: (" " + wh.events).padEnd(9) }),
10129
- /* @__PURE__ */ jsx7(Text7, { color: theme.accent, children: truncate2(wh.url, cols - 16) })
10130
- ] }, wh.id)),
10131
- inWindow(rowsAll.find((r) => r.kind === "wh-add")) ? /* @__PURE__ */ jsxs7(Text7, { children: [
10132
- /* @__PURE__ */ jsx7(Text7, { color: cur.kind === "wh-add" && focused ? theme.accentBright : theme.dim, children: mark({ kind: "wh-add" }) }),
10133
- /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "+ add webhook (enter)" })
10201
+ accounts.length === 0 ? /* @__PURE__ */ jsxs7(Text7, { children: [
10202
+ /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: " no accounts yet \u2014 " }),
10203
+ /* @__PURE__ */ jsx7(Text7, { color: theme.accent, children: "n" }),
10204
+ /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: " (or enter) logs in, pairs this device and unlocks the dataroom" })
10205
+ ] }) : null,
10206
+ accounts.filter((acc) => inWindow({ kind: "acct", acc })).map((a) => {
10207
+ const isView = viewApiKey ? a.apiKey === viewApiKey : accounts[0]?.apiKey === a.apiKey;
10208
+ const isActive = isActiveAccount(a.apiKey);
10209
+ return /* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
10210
+ /* @__PURE__ */ jsx7(Text7, { color: keyOf(cur) === "acct:" + a.apiKey && focused ? theme.accentBright : theme.dim, children: mark({ kind: "acct", acc: a }) }),
10211
+ /* @__PURE__ */ jsx7(Text7, { color: theme.accent, children: truncate2(acctLabel(a), 30).padEnd(31) }),
10212
+ isView ? /* @__PURE__ */ jsx7(Text7, { color: theme.ok, children: "\u25CF viewing " }) : /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: " " }),
10213
+ isActive ? /* @__PURE__ */ jsx7(Text7, { color: theme.warn, children: "ACTIVE " }) : /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: " " }),
10214
+ /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: a.project ? truncate2(a.project, 24) : "" })
10215
+ ] }, a.apiKey);
10216
+ }),
10217
+ inWindow({ kind: "acct-add" }) ? /* @__PURE__ */ jsxs7(Text7, { children: [
10218
+ /* @__PURE__ */ jsx7(Text7, { color: cur.kind === "acct-add" && focused ? theme.accentBright : theme.dim, children: mark({ kind: "acct-add" }) }),
10219
+ /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "+ add account (enter \u2014 device login in the browser)" })
10134
10220
  ] }) : null
10135
10221
  ] }),
10136
- /* @__PURE__ */ jsxs7(Box7, { marginTop: 1, flexDirection: "column", children: [
10137
- /* @__PURE__ */ jsxs7(Text7, { bold: true, color: theme.accentBright, children: [
10138
- "ALERTS ",
10139
- /* @__PURE__ */ jsxs7(Text7, { color: theme.dim, children: [
10140
- "\u2014 notify on a signal spike (",
10141
- alerts.length,
10142
- ")"
10222
+ locked ? null : /* @__PURE__ */ jsxs7(Fragment5, { children: [
10223
+ inWindow({ kind: "ll-enabled" }) || inWindow({ kind: "ll-path" }) ? /* @__PURE__ */ jsxs7(Box7, { marginTop: 1, flexDirection: "column", children: [
10224
+ /* @__PURE__ */ jsxs7(Text7, { bold: true, color: theme.accentBright, children: [
10225
+ "LOCAL LOGS ",
10226
+ /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "\u2014 hooks mirror every decision to a file on the agent machine" })
10227
+ ] }),
10228
+ /* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
10229
+ /* @__PURE__ */ jsx7(Text7, { color: keyOf(cur) === "ll-enabled" && focused ? theme.accentBright : theme.dim, children: mark({ kind: "ll-enabled" }) }),
10230
+ /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "enabled ".padEnd(10) }),
10231
+ onOff(!!local?.enabled),
10232
+ /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: " enter toggles" })
10233
+ ] }),
10234
+ /* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
10235
+ /* @__PURE__ */ jsx7(Text7, { color: keyOf(cur) === "ll-path" && focused ? theme.accentBright : theme.dim, children: mark({ kind: "ll-path" }) }),
10236
+ /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "path ".padEnd(10) }),
10237
+ 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" })
10143
10238
  ] })
10239
+ ] }) : null,
10240
+ /* @__PURE__ */ jsxs7(Box7, { marginTop: 1, flexDirection: "column", children: [
10241
+ /* @__PURE__ */ jsxs7(Text7, { bold: true, color: theme.accentBright, children: [
10242
+ "WEBHOOKS ",
10243
+ /* @__PURE__ */ jsxs7(Text7, { color: theme.dim, children: [
10244
+ "\u2014 POST every matching event to your endpoint (",
10245
+ webhooks.length,
10246
+ ")"
10247
+ ] })
10248
+ ] }),
10249
+ webhooks.filter((wh) => inWindow({ kind: "wh", wh })).map((wh) => /* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
10250
+ /* @__PURE__ */ jsx7(Text7, { color: keyOf(cur) === "wh:" + wh.id && focused ? theme.accentBright : theme.dim, children: mark({ kind: "wh", wh }) }),
10251
+ onOff(wh.enabled),
10252
+ /* @__PURE__ */ jsx7(Text7, { color: theme.warn, children: (" " + wh.events).padEnd(9) }),
10253
+ /* @__PURE__ */ jsx7(Text7, { color: theme.accent, children: truncate2(wh.url, cols - 16) })
10254
+ ] }, wh.id)),
10255
+ inWindow({ kind: "wh-add" }) ? /* @__PURE__ */ jsxs7(Text7, { children: [
10256
+ /* @__PURE__ */ jsx7(Text7, { color: cur.kind === "wh-add" && focused ? theme.accentBright : theme.dim, children: mark({ kind: "wh-add" }) }),
10257
+ /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "+ add webhook (enter)" })
10258
+ ] }) : null
10144
10259
  ] }),
10145
- alerts.filter((rule) => inWindow({ kind: "alert", rule })).map((rule) => /* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
10146
- /* @__PURE__ */ jsx7(Text7, { color: keyOf(cur) === "alert:" + rule.id && focused ? theme.accentBright : theme.dim, children: mark({ kind: "alert", rule }) }),
10147
- onOff(rule.enabled),
10148
- /* @__PURE__ */ jsx7(Text7, { color: theme.warn, children: (" " + rule.signal).padEnd(11) }),
10149
- /* @__PURE__ */ jsx7(Text7, { children: `\u2265${rule.threshold}/${rule.windowSeconds}s ` }),
10150
- /* @__PURE__ */ jsx7(Text7, { color: theme.accent, children: truncate2(chanOf(rule), cols - 26) })
10151
- ] }, rule.id)),
10152
- inWindow(rowsAll[rowsAll.length - 1]) ? /* @__PURE__ */ jsxs7(Text7, { children: [
10153
- /* @__PURE__ */ jsx7(Text7, { color: cur.kind === "alert-add" && focused ? theme.accentBright : theme.dim, children: mark({ kind: "alert-add" }) }),
10154
- /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "+ add alert (enter \u2014 one channel: slack url, email or telegram chat id)" })
10155
- ] }) : null
10260
+ /* @__PURE__ */ jsxs7(Box7, { marginTop: 1, flexDirection: "column", children: [
10261
+ /* @__PURE__ */ jsxs7(Text7, { bold: true, color: theme.accentBright, children: [
10262
+ "ALERTS ",
10263
+ /* @__PURE__ */ jsxs7(Text7, { color: theme.dim, children: [
10264
+ "\u2014 notify on a signal spike (",
10265
+ alerts.length,
10266
+ ")"
10267
+ ] })
10268
+ ] }),
10269
+ alerts.filter((rule) => inWindow({ kind: "alert", rule })).map((rule) => /* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
10270
+ /* @__PURE__ */ jsx7(Text7, { color: keyOf(cur) === "alert:" + rule.id && focused ? theme.accentBright : theme.dim, children: mark({ kind: "alert", rule }) }),
10271
+ onOff(rule.enabled),
10272
+ /* @__PURE__ */ jsx7(Text7, { color: theme.warn, children: (" " + rule.signal).padEnd(11) }),
10273
+ /* @__PURE__ */ jsx7(Text7, { children: `\u2265${rule.threshold}/${rule.windowSeconds}s ` }),
10274
+ /* @__PURE__ */ jsx7(Text7, { color: theme.accent, children: truncate2(chanOf(rule), cols - 26) })
10275
+ ] }, rule.id)),
10276
+ inWindow({ kind: "alert-add" }) ? /* @__PURE__ */ jsxs7(Text7, { children: [
10277
+ /* @__PURE__ */ jsx7(Text7, { color: cur.kind === "alert-add" && focused ? theme.accentBright : theme.dim, children: mark({ kind: "alert-add" }) }),
10278
+ /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "+ add alert (enter \u2014 one channel: slack url, email or telegram chat id)" })
10279
+ ] }) : null
10280
+ ] })
10156
10281
  ] })
10157
10282
  ] }) });
10158
10283
  }
10159
- var EVENTS;
10284
+ var EVENTS, SPIN2, acctLabel;
10160
10285
  var init_Settings = __esm({
10161
10286
  "src/tui/panels/Settings.tsx"() {
10162
10287
  "use strict";
10163
10288
  init_api_client();
10289
+ init_client();
10290
+ init_device_login();
10164
10291
  init_components();
10165
10292
  init_hooks();
10166
10293
  init_theme();
10167
10294
  EVENTS = ["denials", "allowed", "all"];
10168
- }
10169
- });
10170
-
10171
- // src/tui/panels/Accounts.tsx
10172
- import { Box as Box8, Text as Text8, useInput as useInput7 } from "ink";
10173
- import { useEffect as useEffect6, useRef as useRef3, useState as useState8 } from "react";
10174
- import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
10175
- function AccountsPanel({
10176
- focused,
10177
- viewApiKey,
10178
- onView
10179
- }) {
10180
- const [accounts, setAccounts] = useState8(() => listAccounts());
10181
- const [sel, setSel] = useState8(0);
10182
- const [msg, setMsg] = useState8(null);
10183
- const [login, setLogin] = useState8(null);
10184
- const [tick, setTick] = useState8(0);
10185
- const abort = useRef3(false);
10186
- const refresh = () => setAccounts(listAccounts());
10187
- useEffect6(() => {
10188
- if (!login || login.phase === "done" || login.phase === "error") return;
10189
- const t = setInterval(() => setTick((n) => n + 1), 120);
10190
- return () => clearInterval(t);
10191
- }, [login]);
10192
- const beginLogin = () => {
10193
- if (login && (login.phase === "starting" || login.phase === "waiting")) return;
10194
- abort.current = false;
10195
- setLogin({ phase: "starting" });
10196
- void (async () => {
10197
- let start;
10198
- try {
10199
- start = await startDeviceLogin(DEFAULT_API_URL2);
10200
- } catch (e) {
10201
- setLogin({ phase: "error", msg: "could not reach SolonGate: " + (e instanceof Error ? e.message : String(e)) });
10202
- return;
10203
- }
10204
- setLogin({ phase: "waiting", url: start.verifyUrl });
10205
- openBrowser(start.verifyUrl);
10206
- while (Date.now() < start.expiresAt && !abort.current) {
10207
- await new Promise((r) => setTimeout(r, start.intervalMs));
10208
- if (abort.current) return;
10209
- const res = await pollDeviceLogin(DEFAULT_API_URL2, start.deviceCode);
10210
- if (res.status === "approved" && res.apiKey) {
10211
- saveAccount({ apiKey: res.apiKey, apiUrl: DEFAULT_API_URL2, project: res.project, user: res.user, email: res.email });
10212
- setLogin({ phase: "done", msg: `\u2713 added ${res.email || res.user || res.project || "account"}` });
10213
- refresh();
10214
- setViewCredentials({ apiKey: res.apiKey, apiUrl: DEFAULT_API_URL2 });
10215
- onView?.({ apiKey: res.apiKey, apiUrl: DEFAULT_API_URL2, project: res.project, user: res.user, email: res.email });
10216
- return;
10217
- }
10218
- if (res.status === "expired" || res.status === "not_found") {
10219
- setLogin({ phase: "error", msg: "code expired \u2014 press n to retry" });
10220
- return;
10221
- }
10222
- }
10223
- if (!abort.current) setLogin({ phase: "error", msg: "timed out \u2014 press n to retry" });
10224
- })();
10225
- };
10226
- useInput7(
10227
- (input, key) => {
10228
- if (login && (login.phase === "starting" || login.phase === "waiting")) {
10229
- if (key.escape) {
10230
- abort.current = true;
10231
- setLogin(null);
10232
- }
10233
- return;
10234
- }
10235
- if (key.upArrow) setSel((n) => Math.max(0, n - 1));
10236
- else if (key.downArrow) setSel((n) => Math.min(accounts.length - 1, n + 1));
10237
- else if (key.return) {
10238
- const a = accounts[sel];
10239
- if (a) {
10240
- setViewCredentials({ apiKey: a.apiKey, apiUrl: a.apiUrl });
10241
- onView?.(a);
10242
- setMsg({ text: `viewing ${a.email || a.user || a.project || "account \u2026" + a.apiKey.slice(-4)}`, level: "ok" });
10243
- }
10244
- } else if (input === "m") {
10245
- const a = accounts[sel];
10246
- if (a) {
10247
- const ok = setActiveAccount({ apiKey: a.apiKey, apiUrl: a.apiUrl });
10248
- setMsg(ok ? { text: `\u2713 ${a.email || a.user || a.project || "account"} is now the ACTIVE key (guard + logging)`, level: "ok" } : { text: "\u2717 could not set active", level: "bad" });
10249
- refresh();
10250
- }
10251
- } else if (input === "n") beginLogin();
10252
- else if (input === "r") refresh();
10253
- },
10254
- { isActive: focused }
10255
- );
10256
- const spin = SPIN2[tick % SPIN2.length];
10257
- if (login && (login.phase === "starting" || login.phase === "waiting")) {
10258
- return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
10259
- /* @__PURE__ */ jsx8(Text8, { bold: true, color: theme.accentBright, children: "Add an account" }),
10260
- login.phase === "starting" ? /* @__PURE__ */ jsxs8(Text8, { color: theme.dim, children: [
10261
- spin,
10262
- " starting device pairing\u2026"
10263
- ] }) : /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", marginTop: 1, children: [
10264
- /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "Opening your browser to authorize. If it didn't open, visit:" }),
10265
- /* @__PURE__ */ jsx8(Text8, { color: theme.accentBright, bold: true, wrap: "truncate", children: login.url }),
10266
- /* @__PURE__ */ jsxs8(Box8, { marginTop: 1, children: [
10267
- /* @__PURE__ */ jsxs8(Text8, { color: theme.warn, children: [
10268
- spin,
10269
- " waiting for authorization\u2026 "
10270
- ] }),
10271
- /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "esc to cancel" })
10272
- ] })
10273
- ] })
10274
- ] });
10275
- }
10276
- return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
10277
- /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: focused ? "\u2191\u2193 select \xB7 enter view \xB7 m make active \xB7 n add account \xB7 r refresh" : "press \u2192 to manage accounts" }),
10278
- msg ? /* @__PURE__ */ jsx8(Text8, { color: msg.level === "bad" ? theme.bad : theme.ok, children: truncate2(msg.text, 70) }) : login?.msg ? /* @__PURE__ */ jsx8(Text8, { color: login.phase === "error" ? theme.bad : theme.ok, children: login.msg }) : /* @__PURE__ */ jsx8(Text8, { children: " " }),
10279
- /* @__PURE__ */ jsx8(Box8, { marginTop: 1, flexDirection: "column", children: accounts.length === 0 ? /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
10280
- /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "No accounts on this device yet." }),
10281
- /* @__PURE__ */ jsxs8(Text8, { children: [
10282
- /* @__PURE__ */ jsx8(Text8, { color: theme.accent, children: "n" }),
10283
- /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: " to log in \u2014 pairs this device and starts protecting your Claude Code sessions." })
10284
- ] })
10285
- ] }) : accounts.map((a, i) => {
10286
- const isSel = i === sel && focused;
10287
- const isView = viewApiKey ? a.apiKey === viewApiKey : i === 0;
10288
- const isActive = isActiveAccount(a.apiKey);
10289
- return /* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", backgroundColor: isSel ? "#333333" : void 0, bold: isSel, children: [
10290
- /* @__PURE__ */ jsx8(Text8, { color: isSel ? theme.accentBright : theme.dim, children: isSel ? "\u25B8 " : " " }),
10291
- /* @__PURE__ */ jsx8(Text8, { color: theme.accent, children: truncate2(a.email || a.user || "account \u2026" + a.apiKey.slice(-4), 30).padEnd(31) }),
10292
- isView ? /* @__PURE__ */ jsx8(Text8, { color: theme.ok, children: "\u25CF viewing " }) : /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: " " }),
10293
- isActive ? /* @__PURE__ */ jsx8(Text8, { color: theme.warn, children: "ACTIVE " }) : /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: " " }),
10294
- /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: a.project ? truncate2(a.project, 24) : "" })
10295
- ] }, a.apiKey);
10296
- }) }),
10297
- /* @__PURE__ */ jsx8(Box8, { marginTop: 1, flexDirection: "column", children: /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "\u25CF viewing = the account the dataroom is showing \xB7 ACTIVE = the key the guard hooks + logging use" }) })
10298
- ] });
10299
- }
10300
- var SPIN2;
10301
- var init_Accounts = __esm({
10302
- "src/tui/panels/Accounts.tsx"() {
10303
- "use strict";
10304
- init_client();
10305
- init_device_login();
10306
- init_theme();
10307
10295
  SPIN2 = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
10296
+ acctLabel = (a) => a.email || a.user || "account \u2026" + a.apiKey.slice(-4);
10308
10297
  }
10309
10298
  });
10310
10299
 
10311
10300
  // src/tui/App.tsx
10312
- import { Box as Box9, Text as Text9, useApp, useInput as useInput8 } from "ink";
10313
- import { useEffect as useEffect7, useState as useState9 } from "react";
10314
- import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
10301
+ import { Box as Box8, Text as Text8, useApp, useInput as useInput7 } from "ink";
10302
+ import { useEffect as useEffect7, useState as useState8 } from "react";
10303
+ import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
10315
10304
  function LiveHint() {
10316
- return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", children: [
10317
- /* @__PURE__ */ jsx9(Text9, { color: theme.accentBright, bold: true, children: "\u25B6 REALTIME CONSOLE" }),
10318
- /* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: "Fullscreen live monitor \u2014 streaming tool calls, active charts," }),
10319
- /* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: "counters, DLP hits and denial alerts. Updates every 2s." }),
10320
- /* @__PURE__ */ jsx9(Box9, { marginTop: 1, children: /* @__PURE__ */ jsxs9(Text9, { children: [
10305
+ return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
10306
+ /* @__PURE__ */ jsx8(Text8, { color: theme.accentBright, bold: true, children: "\u25B6 REALTIME CONSOLE" }),
10307
+ /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "Fullscreen live monitor \u2014 streaming tool calls, active charts," }),
10308
+ /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "counters, DLP hits and denial alerts. Updates every 2s." }),
10309
+ /* @__PURE__ */ jsx8(Box8, { marginTop: 1, children: /* @__PURE__ */ jsxs8(Text8, { children: [
10321
10310
  "press ",
10322
- /* @__PURE__ */ jsx9(Text9, { color: theme.accent, children: "enter" }),
10311
+ /* @__PURE__ */ jsx8(Text8, { color: theme.accent, children: "enter" }),
10323
10312
  " to go live"
10324
10313
  ] }) })
10325
10314
  ] });
@@ -10327,25 +10316,25 @@ function LiveHint() {
10327
10316
  function Banner({ cols }) {
10328
10317
  const wide = cols >= 82;
10329
10318
  if (!wide) {
10330
- return /* @__PURE__ */ jsxs9(Box9, { children: [
10331
- /* @__PURE__ */ jsx9(Text9, { bold: true, color: theme.accentBright, children: "SolonGate" }),
10332
- /* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: " \u2014 security control center" })
10319
+ return /* @__PURE__ */ jsxs8(Box8, { children: [
10320
+ /* @__PURE__ */ jsx8(Text8, { bold: true, color: theme.accentBright, children: "SolonGate" }),
10321
+ /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: " \u2014 security control center" })
10333
10322
  ] });
10334
10323
  }
10335
- return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", children: [
10336
- BANNER_FULL.map((line, i) => /* @__PURE__ */ jsx9(Text9, { bold: true, color: BANNER_HEX[i], children: line }, i)),
10337
- /* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: " security control center \xB7 manage policies, rate limits, DLP & more" })
10324
+ return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
10325
+ BANNER_FULL.map((line, i) => /* @__PURE__ */ jsx8(Text8, { bold: true, color: BANNER_HEX[i], children: line }, i)),
10326
+ /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: " security control center \xB7 manage policies, rate limits, DLP & more" })
10338
10327
  ] });
10339
10328
  }
10340
10329
  function App() {
10341
10330
  const { exit } = useApp();
10342
- const [accounts, setAccounts] = useState9(() => listAccounts());
10343
- const [viewKey, setViewKey] = useState9(() => accounts[0]?.apiKey);
10344
- const [viewNonce, setViewNonce] = useState9(0);
10345
- const [section, setSection] = useState9(accounts.length === 0 ? ACCOUNTS_SECTION : 0);
10346
- const [focus, setFocus] = useState9("nav");
10347
- const [help, setHelp] = useState9(false);
10348
- const [update2, setUpdate] = useState9({ kind: "idle" });
10331
+ const [accounts, setAccounts] = useState8(() => listAccounts());
10332
+ const [viewKey, setViewKey] = useState8(() => accounts[0]?.apiKey);
10333
+ const [viewNonce, setViewNonce] = useState8(0);
10334
+ const [section, setSection] = useState8(accounts.length === 0 ? SETTINGS_SECTION : 0);
10335
+ const [focus, setFocus] = useState8("nav");
10336
+ const [help, setHelp] = useState8(false);
10337
+ const [update2, setUpdate] = useState8({ kind: "idle" });
10349
10338
  useEffect7(() => {
10350
10339
  let alive = true;
10351
10340
  const run12 = () => void tuiUpdateFlow((s) => alive && setUpdate(s));
@@ -10358,7 +10347,7 @@ function App() {
10358
10347
  }, []);
10359
10348
  const acctIdx = Math.max(0, accounts.findIndex((a) => a.apiKey === viewKey));
10360
10349
  const cur = accounts[acctIdx];
10361
- const acctLabel = cur ? cur.email || cur.user || cur.project || `account \u2026${cur.apiKey.slice(-4)}` : "not logged in";
10350
+ const acctLabel2 = cur ? cur.email || cur.user || cur.project || `account \u2026${cur.apiKey.slice(-4)}` : "not logged in";
10362
10351
  useEffect7(() => {
10363
10352
  if (!cur || cur.email) return;
10364
10353
  let alive = true;
@@ -10386,8 +10375,8 @@ function App() {
10386
10375
  viewAccount(accounts[(acctIdx + 1) % accounts.length]);
10387
10376
  };
10388
10377
  const locked = accounts.length === 0;
10389
- const effectiveSection = locked ? ACCOUNTS_SECTION : section;
10390
- useInput8((input, key) => {
10378
+ const effectiveSection = locked ? SETTINGS_SECTION : section;
10379
+ useInput7((input, key) => {
10391
10380
  if (help) {
10392
10381
  setHelp(false);
10393
10382
  return;
@@ -10415,45 +10404,45 @@ function App() {
10415
10404
  });
10416
10405
  const { cols, rows } = useTermSize();
10417
10406
  const current = SECTIONS[effectiveSection];
10418
- if (help) return /* @__PURE__ */ jsx9(HelpOverlay, { cols, rows });
10407
+ if (help) return /* @__PURE__ */ jsx8(HelpOverlay, { cols, rows });
10419
10408
  if (current.label === "Live" && focus === "panel") {
10420
- return /* @__PURE__ */ jsx9(Box9, { flexDirection: "column", width: cols, height: rows - 1, overflow: "hidden", children: /* @__PURE__ */ jsx9(LivePanel, { active: true, focused: true }, viewNonce) });
10409
+ return /* @__PURE__ */ jsx8(Box8, { flexDirection: "column", width: cols, height: rows - 1, overflow: "hidden", children: /* @__PURE__ */ jsx8(LivePanel, { active: true, focused: true }, viewNonce) });
10421
10410
  }
10422
10411
  const Panel = current.Panel;
10423
- const panelBody = current.label === "Accounts" ? /* @__PURE__ */ jsx9(AccountsPanel, { active: true, focused: focus === "panel", viewApiKey: viewKey, onView: viewAccount }) : /* @__PURE__ */ jsx9(Panel, { active: focus === "panel" || current.label !== "Live", focused: focus === "panel" });
10424
- return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", width: cols, height: rows, paddingX: 1, paddingTop: 1, children: [
10425
- /* @__PURE__ */ jsx9(Banner, { cols }),
10426
- /* @__PURE__ */ jsxs9(Text9, { wrap: "truncate", children: [
10427
- /* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: "account: " }),
10428
- /* @__PURE__ */ jsx9(Text9, { color: locked ? theme.warn : theme.accentBright, bold: true, children: acctLabel }),
10429
- locked ? /* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: " \xB7 log in from Accounts to unlock the dataroom" }) : accounts.length > 1 ? /* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: ` (${acctIdx + 1}/${accounts.length} \xB7 a switch \xB7 Accounts to manage)` }) : /* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: " \xB7 Accounts to add another" }),
10430
- 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` }) : update2.kind === "manual" ? /* @__PURE__ */ jsx9(Text9, { color: theme.warn, children: ` \u2191 v${update2.version} available \u2014 npm i -g @solongate/proxy@latest` }) : null
10412
+ const panelBody = current.label === "Settings" ? /* @__PURE__ */ jsx8(SettingsPanel, { active: true, focused: focus === "panel", viewApiKey: viewKey, onView: viewAccount }) : /* @__PURE__ */ jsx8(Panel, { active: focus === "panel" || current.label !== "Live", focused: focus === "panel" });
10413
+ return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", width: cols, height: rows, paddingX: 1, paddingTop: 1, children: [
10414
+ /* @__PURE__ */ jsx8(Banner, { cols }),
10415
+ /* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", children: [
10416
+ /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "account: " }),
10417
+ /* @__PURE__ */ jsx8(Text8, { color: locked ? theme.warn : theme.accentBright, bold: true, children: acctLabel2 }),
10418
+ 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" }),
10419
+ 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` }) : update2.kind === "manual" ? /* @__PURE__ */ jsx8(Text8, { color: theme.warn, children: ` \u2191 v${update2.version} available \u2014 npm i -g @solongate/proxy@latest` }) : null
10431
10420
  ] }),
10432
- /* @__PURE__ */ jsxs9(Box9, { marginTop: 1, flexGrow: 1, children: [
10433
- /* @__PURE__ */ jsx9(Box9, { flexDirection: "column", width: 16, borderStyle: "round", borderColor: focus === "nav" ? theme.accent : "gray", paddingX: 1, children: SECTIONS.map((s, i) => {
10421
+ /* @__PURE__ */ jsxs8(Box8, { marginTop: 1, flexGrow: 1, children: [
10422
+ /* @__PURE__ */ jsx8(Box8, { flexDirection: "column", width: 16, borderStyle: "round", borderColor: focus === "nav" ? theme.accent : "gray", paddingX: 1, children: SECTIONS.map((s, i) => {
10434
10423
  const isCur = i === effectiveSection;
10435
- const disabled = locked && s.label !== "Accounts";
10436
- 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);
10424
+ const disabled = locked && s.label !== "Settings";
10425
+ 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);
10437
10426
  }) }),
10438
- /* @__PURE__ */ jsx9(Box9, { flexGrow: 1, borderStyle: "round", borderColor: focus === "panel" ? theme.accent : "gray", paddingX: 1, paddingY: 0, children: panelBody })
10427
+ /* @__PURE__ */ jsx8(Box8, { flexGrow: 1, borderStyle: "round", borderColor: focus === "panel" ? theme.accent : "gray", paddingX: 1, paddingY: 0, children: panelBody })
10439
10428
  ] }, viewNonce),
10440
- /* @__PURE__ */ jsx9(Box9, { children: locked ? /* @__PURE__ */ jsx9(KeyHints, { hints: [["\u2192/enter", "open Accounts"], ["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"]] }) })
10429
+ /* @__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"]] }) })
10441
10430
  ] });
10442
10431
  }
10443
10432
  function HelpOverlay({ cols, rows }) {
10444
- return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", width: cols, height: rows, paddingX: 2, paddingTop: 1, children: [
10445
- /* @__PURE__ */ jsx9(Text9, { bold: true, color: theme.accentBright, children: "SolonGate \u2014 keyboard shortcuts" }),
10446
- /* @__PURE__ */ jsx9(Box9, { marginTop: 1, flexDirection: "column", children: HELP.map(([group, keys]) => /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", marginBottom: 1, children: [
10447
- /* @__PURE__ */ jsx9(Text9, { bold: true, color: theme.accent, children: group }),
10448
- keys.map(([k, desc]) => /* @__PURE__ */ jsxs9(Text9, { children: [
10449
- /* @__PURE__ */ jsx9(Text9, { color: theme.accentBright, children: (" " + k).padEnd(16) }),
10450
- /* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: desc })
10433
+ return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", width: cols, height: rows, paddingX: 2, paddingTop: 1, children: [
10434
+ /* @__PURE__ */ jsx8(Text8, { bold: true, color: theme.accentBright, children: "SolonGate \u2014 keyboard shortcuts" }),
10435
+ /* @__PURE__ */ jsx8(Box8, { marginTop: 1, flexDirection: "column", children: HELP.map(([group, keys]) => /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", marginBottom: 1, children: [
10436
+ /* @__PURE__ */ jsx8(Text8, { bold: true, color: theme.accent, children: group }),
10437
+ keys.map(([k, desc]) => /* @__PURE__ */ jsxs8(Text8, { children: [
10438
+ /* @__PURE__ */ jsx8(Text8, { color: theme.accentBright, children: (" " + k).padEnd(16) }),
10439
+ /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: desc })
10451
10440
  ] }, k))
10452
10441
  ] }, group)) }),
10453
- /* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: "press any key to close" })
10442
+ /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "press any key to close" })
10454
10443
  ] });
10455
10444
  }
10456
- var SECTIONS, BANNER_HEX, ACCOUNTS_SECTION, HELP;
10445
+ var SECTIONS, BANNER_HEX, SETTINGS_SECTION, HELP;
10457
10446
  var init_App = __esm({
10458
10447
  "src/tui/App.tsx"() {
10459
10448
  "use strict";
@@ -10466,7 +10455,6 @@ var init_App = __esm({
10466
10455
  init_Dlp();
10467
10456
  init_Audit();
10468
10457
  init_Settings();
10469
- init_Accounts();
10470
10458
  init_hooks();
10471
10459
  init_client();
10472
10460
  init_api_client();
@@ -10477,11 +10465,10 @@ var init_App = __esm({
10477
10465
  { label: "Rate Limit", Panel: RateLimitPanel },
10478
10466
  { label: "DLP", Panel: DlpPanel },
10479
10467
  { label: "Audit", Panel: AuditPanel },
10480
- { label: "Settings", Panel: SettingsPanel },
10481
- { label: "Accounts", Panel: AccountsPanel }
10468
+ { label: "Settings", Panel: SettingsPanel }
10482
10469
  ];
10483
10470
  BANNER_HEX = ["white", "white", "white", "white", "white", "white"];
10484
- ACCOUNTS_SECTION = SECTIONS.findIndex((s) => s.label === "Accounts");
10471
+ SETTINGS_SECTION = SECTIONS.findIndex((s) => s.label === "Settings");
10485
10472
  HELP = [
10486
10473
  ["Global", [["\u2191\u2193", "move between sections"], ["\u2192 / enter", "open a section"], ["\u2190 / esc", "back to the menu"], ["?", "this help"], ["q", "quit"]]],
10487
10474
  ["Live", [["\u2191\u2193", "select a stream row"], ["enter", "full entry content"], ["w", "whitelist the selected DENY"], ["b", "block the selected ALLOW"], ["d / x / r", "filter denies / dlp / rate-limit"], ["f", "local / cloud filter"], ["/", "search"], ["s", "sessions (\u2191\u2193 pick, enter open)"], ["space", "copy mode (freeze)"]]],
@@ -10503,7 +10490,7 @@ import { appendFileSync as appendFileSync2, mkdirSync as mkdirSync7 } from "fs";
10503
10490
  import { homedir as homedir8 } from "os";
10504
10491
  import { join as join10 } from "path";
10505
10492
  import { render } from "ink";
10506
- import { jsx as jsx10 } from "react/jsx-runtime";
10493
+ import { jsx as jsx9 } from "react/jsx-runtime";
10507
10494
  async function launchTui() {
10508
10495
  if (!process.stdout.isTTY || !process.stdin.isTTY) {
10509
10496
  process.stderr.write(
@@ -10528,7 +10515,7 @@ async function launchTui() {
10528
10515
  console.info = toFile("info");
10529
10516
  console.debug = toFile("debug");
10530
10517
  try {
10531
- const { waitUntilExit } = render(/* @__PURE__ */ jsx10(App, {}), { patchConsole: false });
10518
+ const { waitUntilExit } = render(/* @__PURE__ */ jsx9(App, {}), { patchConsole: false });
10532
10519
  await waitUntilExit();
10533
10520
  } finally {
10534
10521
  Object.assign(console, saved);