@solongate/proxy 0.82.33 → 0.82.35
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 +113 -45
- package/dist/tui/index.js +104 -44
- package/dist/tui/nav.d.ts +6 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -8800,6 +8800,7 @@ var init_Live = __esm({
|
|
|
8800
8800
|
|
|
8801
8801
|
// src/tui/panels/DryRun.tsx
|
|
8802
8802
|
import { Box as Box3, Text as Text3, useInput as useInput2 } from "ink";
|
|
8803
|
+
import TextInput2 from "ink-text-input";
|
|
8803
8804
|
import { useEffect as useEffect3, useState as useState3 } from "react";
|
|
8804
8805
|
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
8805
8806
|
function requestDryRun(policyId) {
|
|
@@ -8809,21 +8810,24 @@ function DryRunPanel({ focused }) {
|
|
|
8809
8810
|
const list6 = useLoader(() => api.policies.list());
|
|
8810
8811
|
const policies = list6.data?.policies ?? [];
|
|
8811
8812
|
const [pi, setPi] = useState3(0);
|
|
8812
|
-
const [
|
|
8813
|
+
const [limit, setLimit] = useState3(DEFAULT_LIMIT);
|
|
8814
|
+
const [editLogs, setEditLogs] = useState3(null);
|
|
8815
|
+
const statsQ = useLoader(() => api.stats.get());
|
|
8816
|
+
const totalLogs = statsQ.data?.total_calls ?? null;
|
|
8813
8817
|
const [res, setRes] = useState3(null);
|
|
8814
8818
|
const [running, setRunning] = useState3(false);
|
|
8815
8819
|
const [err2, setErr] = useState3(null);
|
|
8816
8820
|
const [off, setOff] = useState3(0);
|
|
8817
8821
|
const { cols, rows } = usePanelSize();
|
|
8818
8822
|
const selected = policies[Math.min(pi, Math.max(0, policies.length - 1))];
|
|
8819
|
-
function run10(policyIdx = pi,
|
|
8823
|
+
function run10(policyIdx = pi, lim = limit) {
|
|
8820
8824
|
const p = policies[policyIdx];
|
|
8821
8825
|
if (!p) return;
|
|
8822
8826
|
setRunning(true);
|
|
8823
8827
|
setErr(null);
|
|
8824
8828
|
setRes(null);
|
|
8825
8829
|
setOff(0);
|
|
8826
|
-
api.policies.backtest({ rules: p.rules ?? [], mode: p.mode, limit:
|
|
8830
|
+
api.policies.backtest({ rules: p.rules ?? [], mode: p.mode, limit: lim }).then((r) => setRes(r)).catch((e) => setErr(e instanceof Error ? e.message : String(e))).finally(() => setRunning(false));
|
|
8827
8831
|
}
|
|
8828
8832
|
useEffect3(() => {
|
|
8829
8833
|
if (policies.length === 0 || res || running || err2) return;
|
|
@@ -8834,22 +8838,28 @@ function DryRunPanel({ focused }) {
|
|
|
8834
8838
|
pendingPolicyId = null;
|
|
8835
8839
|
}
|
|
8836
8840
|
setPi(idx);
|
|
8837
|
-
run10(idx,
|
|
8841
|
+
run10(idx, limit);
|
|
8838
8842
|
}, [policies.length]);
|
|
8839
8843
|
useInput2((input, key) => {
|
|
8840
|
-
if (!focused) return;
|
|
8844
|
+
if (!focused || editLogs !== null) return;
|
|
8841
8845
|
if (key.upArrow) setOff((n) => Math.max(0, n - 1));
|
|
8842
8846
|
else if (key.downArrow) setOff((n) => n + 1);
|
|
8843
|
-
else if (input === "p") {
|
|
8847
|
+
else if (input === "p" || input === "P") {
|
|
8844
8848
|
const n = policies.length ? (pi + 1) % policies.length : 0;
|
|
8845
8849
|
setPi(n);
|
|
8846
|
-
run10(n,
|
|
8847
|
-
} else if (input === "n") {
|
|
8848
|
-
|
|
8849
|
-
|
|
8850
|
-
run10(pi, n);
|
|
8851
|
-
} else if (input === "r") run10(pi, si);
|
|
8850
|
+
run10(n, limit);
|
|
8851
|
+
} else if (input === "n" || input === "N") {
|
|
8852
|
+
setEditLogs(String(limit));
|
|
8853
|
+
} else if (input === "r" || input === "R") run10(pi, limit);
|
|
8852
8854
|
});
|
|
8855
|
+
function commitLogs(raw) {
|
|
8856
|
+
const cap = totalLogs && totalLogs > 0 ? totalLogs : 5e3;
|
|
8857
|
+
const parsed = parseInt(raw.replace(/[^0-9]/g, ""), 10);
|
|
8858
|
+
const next = Number.isFinite(parsed) && parsed > 0 ? Math.min(parsed, cap) : limit;
|
|
8859
|
+
setEditLogs(null);
|
|
8860
|
+
setLimit(next);
|
|
8861
|
+
run10(pi, next);
|
|
8862
|
+
}
|
|
8853
8863
|
const w = Math.max(40, cols);
|
|
8854
8864
|
const lines = [];
|
|
8855
8865
|
const head = (t) => lines.push(/* @__PURE__ */ jsx3(Text3, { bold: true, color: theme.accentBright, children: t }, `h${lines.length}`));
|
|
@@ -8918,38 +8928,38 @@ function DryRunPanel({ focused }) {
|
|
|
8918
8928
|
}
|
|
8919
8929
|
}
|
|
8920
8930
|
}
|
|
8921
|
-
const headerRows =
|
|
8931
|
+
const headerRows = 5;
|
|
8922
8932
|
const budget = Math.max(3, rows - headerRows);
|
|
8923
8933
|
const maxOff = Math.max(0, lines.length - budget);
|
|
8924
8934
|
const start = Math.min(off, maxOff);
|
|
8925
8935
|
const win = lines.slice(start, start + budget);
|
|
8926
8936
|
const above = start;
|
|
8927
8937
|
const below = Math.max(0, lines.length - (start + budget));
|
|
8928
|
-
const sampleLabel = `${SAMPLES[si]}${res?.sampled != null ? ` (ran ${res.sampled})` : ""}`;
|
|
8929
8938
|
return /* @__PURE__ */ jsx3(DataView, { loading: list6.loading && !list6.data, error: list6.error, children: /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", children: [
|
|
8930
|
-
/* @__PURE__ */
|
|
8931
|
-
|
|
8932
|
-
/* @__PURE__ */
|
|
8933
|
-
|
|
8934
|
-
|
|
8935
|
-
|
|
8936
|
-
|
|
8937
|
-
|
|
8938
|
-
|
|
8939
|
-
|
|
8940
|
-
/* @__PURE__ */
|
|
8941
|
-
|
|
8942
|
-
|
|
8943
|
-
|
|
8939
|
+
/* @__PURE__ */ jsx3(Text3, { bold: true, color: theme.accentBright, children: "Policy Dry Run" }),
|
|
8940
|
+
/* @__PURE__ */ jsxs3(Text3, { wrap: "truncate", children: [
|
|
8941
|
+
/* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: " policy " }),
|
|
8942
|
+
/* @__PURE__ */ jsx3(Text3, { color: theme.accent, children: "\u2039 " + truncate2(selected?.name ?? "none", 30) + " \u203A" }),
|
|
8943
|
+
/* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: ` ${policies.length ? pi + 1 : 0}/${policies.length} press p \xB7 mode ${selected?.mode ?? "-"}` })
|
|
8944
|
+
] }),
|
|
8945
|
+
editLogs !== null ? /* @__PURE__ */ jsxs3(Box3, { children: [
|
|
8946
|
+
/* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: " logs " }),
|
|
8947
|
+
/* @__PURE__ */ jsx3(Text3, { color: theme.warn, children: "how many recent logs to replay: " }),
|
|
8948
|
+
/* @__PURE__ */ jsx3(TextInput2, { value: editLogs, onChange: setEditLogs, onSubmit: commitLogs }),
|
|
8949
|
+
/* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: totalLogs != null ? ` (you have ${totalLogs})` : "" })
|
|
8950
|
+
] }) : /* @__PURE__ */ jsxs3(Text3, { wrap: "truncate", children: [
|
|
8951
|
+
/* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: " logs " }),
|
|
8952
|
+
/* @__PURE__ */ jsx3(Text3, { color: theme.accent, children: "\u2039 " + String(limit) + " \u203A" }),
|
|
8953
|
+
/* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: ` press n to type a number${totalLogs != null ? ` you have ${totalLogs}` : ""}${res?.sampled != null ? ` replayed ${res.sampled}` : ""}` })
|
|
8944
8954
|
] }),
|
|
8945
|
-
/* @__PURE__ */ jsx3(Text3, { color: theme.dim, wrap: "truncate", children: focused ? `\u2191\u2193 scroll \xB7 p policy \xB7 n
|
|
8955
|
+
/* @__PURE__ */ jsx3(Text3, { color: theme.dim, wrap: "truncate", children: focused ? `\u2191\u2193 scroll \xB7 p policy \xB7 n logs \xB7 r re-run${above ? ` \xB7 \u25B2${above}` : ""}${below ? ` \xB7 \u25BC${below}` : ""}` : "press \u2192 to open" }),
|
|
8946
8956
|
running ? /* @__PURE__ */ jsx3(Text3, { color: theme.warn, children: "replaying recent traffic\u2026" }) : null,
|
|
8947
8957
|
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
|
|
8958
|
+
!running && !err2 && !res ? /* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: "no result yet, press r to run" }) : null,
|
|
8949
8959
|
/* @__PURE__ */ jsx3(Box3, { marginTop: 1, flexDirection: "column", children: win })
|
|
8950
8960
|
] }) });
|
|
8951
8961
|
}
|
|
8952
|
-
var
|
|
8962
|
+
var DEFAULT_LIMIT, pendingPolicyId, pct;
|
|
8953
8963
|
var init_DryRun = __esm({
|
|
8954
8964
|
"src/tui/panels/DryRun.tsx"() {
|
|
8955
8965
|
"use strict";
|
|
@@ -8957,15 +8967,40 @@ var init_DryRun = __esm({
|
|
|
8957
8967
|
init_components();
|
|
8958
8968
|
init_hooks();
|
|
8959
8969
|
init_theme();
|
|
8960
|
-
|
|
8970
|
+
DEFAULT_LIMIT = 1e3;
|
|
8961
8971
|
pendingPolicyId = null;
|
|
8962
8972
|
pct = (n, d) => d ? (n / d * 100).toFixed(1) + "%" : "0%";
|
|
8963
8973
|
}
|
|
8964
8974
|
});
|
|
8965
8975
|
|
|
8976
|
+
// src/tui/nav.ts
|
|
8977
|
+
function requestSection(label) {
|
|
8978
|
+
pending = label;
|
|
8979
|
+
for (const fn of subs) fn();
|
|
8980
|
+
}
|
|
8981
|
+
function takePendingSection() {
|
|
8982
|
+
const p = pending;
|
|
8983
|
+
pending = null;
|
|
8984
|
+
return p;
|
|
8985
|
+
}
|
|
8986
|
+
function onSectionRequest(fn) {
|
|
8987
|
+
subs.add(fn);
|
|
8988
|
+
return () => {
|
|
8989
|
+
subs.delete(fn);
|
|
8990
|
+
};
|
|
8991
|
+
}
|
|
8992
|
+
var pending, subs;
|
|
8993
|
+
var init_nav = __esm({
|
|
8994
|
+
"src/tui/nav.ts"() {
|
|
8995
|
+
"use strict";
|
|
8996
|
+
pending = null;
|
|
8997
|
+
subs = /* @__PURE__ */ new Set();
|
|
8998
|
+
}
|
|
8999
|
+
});
|
|
9000
|
+
|
|
8966
9001
|
// src/tui/panels/Policies.tsx
|
|
8967
9002
|
import { Box as Box4, Text as Text4, useInput as useInput3 } from "ink";
|
|
8968
|
-
import
|
|
9003
|
+
import TextInput3 from "ink-text-input";
|
|
8969
9004
|
import { useEffect as useEffect4, useState as useState4 } from "react";
|
|
8970
9005
|
import { Fragment as Fragment3, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
8971
9006
|
function ruleSummary(r) {
|
|
@@ -9042,8 +9077,20 @@ function PoliciesPanel({ focused }) {
|
|
|
9042
9077
|
setDirty(false);
|
|
9043
9078
|
setStatus("discarded");
|
|
9044
9079
|
};
|
|
9080
|
+
const [creating, setCreating] = useState4(null);
|
|
9081
|
+
function commitNewPolicy(name) {
|
|
9082
|
+
const n = name.trim();
|
|
9083
|
+
setCreating(null);
|
|
9084
|
+
if (!n) return;
|
|
9085
|
+
setStatus("Creating\u2026");
|
|
9086
|
+
void api.policies.create({ id: `policy-${Date.now()}`, name: n, rules: [], mode: "denylist" }).then(() => {
|
|
9087
|
+
setStatus(`\u2713 created "${n}" - open it and press n to add rules`);
|
|
9088
|
+
list6.reload();
|
|
9089
|
+
}).catch((e) => setStatus("\u2717 " + (e instanceof Error ? e.message : String(e))));
|
|
9090
|
+
}
|
|
9045
9091
|
useInput3(
|
|
9046
9092
|
(input, key) => {
|
|
9093
|
+
if (creating !== null) return;
|
|
9047
9094
|
if (key.ctrl && input === "r" && !editing) {
|
|
9048
9095
|
list6.reload();
|
|
9049
9096
|
activeQ.reload();
|
|
@@ -9065,6 +9112,9 @@ function PoliciesPanel({ focused }) {
|
|
|
9065
9112
|
activeQ.reload();
|
|
9066
9113
|
}).catch((e) => setStatus("\u2717 " + (e instanceof Error ? e.message : String(e))));
|
|
9067
9114
|
}
|
|
9115
|
+
} else if (input === "n" || input === "N") {
|
|
9116
|
+
setStatus(null);
|
|
9117
|
+
setCreating("");
|
|
9068
9118
|
} else if (input === "x") {
|
|
9069
9119
|
setStatus("Deactivating\u2026");
|
|
9070
9120
|
void api.policies.setActive(null).then(() => {
|
|
@@ -9104,7 +9154,7 @@ function PoliciesPanel({ focused }) {
|
|
|
9104
9154
|
} else if (input === "D") {
|
|
9105
9155
|
if (selected) {
|
|
9106
9156
|
requestDryRun(selected.id);
|
|
9107
|
-
|
|
9157
|
+
requestSection("Dry Run");
|
|
9108
9158
|
}
|
|
9109
9159
|
} else if (input === "s") void save();
|
|
9110
9160
|
else if (input === "x") discard();
|
|
@@ -9132,7 +9182,7 @@ function PoliciesPanel({ focused }) {
|
|
|
9132
9182
|
);
|
|
9133
9183
|
if (view === "list") {
|
|
9134
9184
|
const activeName = activeId ? policies.find((p) => p.id === activeId)?.name ?? activeId : null;
|
|
9135
|
-
const lHead = 3 + (status ? 1 : 0);
|
|
9185
|
+
const lHead = 3 + (status ? 1 : 0) + (creating !== null ? 1 : 0);
|
|
9136
9186
|
const lBudget = Math.max(3, panelRows - lHead);
|
|
9137
9187
|
const lStart = Math.min(Math.max(0, pi - Math.floor(lBudget / 2)), Math.max(0, policies.length - lBudget));
|
|
9138
9188
|
const lWin = policies.slice(lStart, lStart + lBudget);
|
|
@@ -9149,7 +9199,11 @@ function PoliciesPanel({ focused }) {
|
|
|
9149
9199
|
/* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: activeBy ? ` (${activeBy})` : "" })
|
|
9150
9200
|
] }) : /* @__PURE__ */ jsx4(Text4, { color: theme.bad, bold: true, children: "\u25CB NONE \u2014 nothing enforced, grants refused" })
|
|
9151
9201
|
] }),
|
|
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" }),
|
|
9202
|
+
/* @__PURE__ */ jsx4(Text4, { color: theme.dim, wrap: "truncate", children: focused ? `\u2191\u2193 select \xB7 enter open \xB7 n new policy \xB7 a activate \xB7 x deactivate \xB7 ^R refresh${lAbove ? ` \xB7 \u25B2${lAbove}` : ""}${lBelow ? ` \xB7 \u25BC${lBelow}` : ""}` : "press \u2192 to browse" }),
|
|
9203
|
+
creating !== null ? /* @__PURE__ */ jsxs4(Box4, { children: [
|
|
9204
|
+
/* @__PURE__ */ jsx4(Text4, { color: theme.warn, children: "new policy name: " }),
|
|
9205
|
+
/* @__PURE__ */ jsx4(TextInput3, { value: creating, onChange: setCreating, onSubmit: commitNewPolicy })
|
|
9206
|
+
] }) : null,
|
|
9153
9207
|
/* @__PURE__ */ jsx4(Box4, { marginTop: 1, flexDirection: "column", children: lWin.map((p, wi) => {
|
|
9154
9208
|
const i = lStart + wi;
|
|
9155
9209
|
return /* @__PURE__ */ jsxs4(Text4, { color: i === pi ? theme.accentBright : void 0, bold: i === pi, children: [
|
|
@@ -9229,7 +9283,7 @@ function PoliciesPanel({ focused }) {
|
|
|
9229
9283
|
return /* @__PURE__ */ jsxs4(Box4, { children: [
|
|
9230
9284
|
/* @__PURE__ */ jsx4(Text4, { color: active2 ? theme.accentBright : void 0, children: (active2 ? "\u25B8 " : " ") + f.label.padEnd(13) }),
|
|
9231
9285
|
active2 && editing && f.kind === "text" ? /* @__PURE__ */ jsx4(
|
|
9232
|
-
|
|
9286
|
+
TextInput3,
|
|
9233
9287
|
{
|
|
9234
9288
|
value: editVal,
|
|
9235
9289
|
onChange: setEditVal,
|
|
@@ -9257,6 +9311,7 @@ var init_Policies = __esm({
|
|
|
9257
9311
|
"use strict";
|
|
9258
9312
|
init_api_client();
|
|
9259
9313
|
init_DryRun();
|
|
9314
|
+
init_nav();
|
|
9260
9315
|
init_components();
|
|
9261
9316
|
init_hooks();
|
|
9262
9317
|
init_theme();
|
|
@@ -9466,7 +9521,7 @@ var init_RateLimit = __esm({
|
|
|
9466
9521
|
|
|
9467
9522
|
// src/tui/panels/Dlp.tsx
|
|
9468
9523
|
import { Box as Box6, Text as Text6, useInput as useInput5 } from "ink";
|
|
9469
|
-
import
|
|
9524
|
+
import TextInput4 from "ink-text-input";
|
|
9470
9525
|
import { useEffect as useEffect6, useState as useState6 } from "react";
|
|
9471
9526
|
import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
9472
9527
|
function DlpPanel({ focused }) {
|
|
@@ -9646,7 +9701,7 @@ function DlpPanel({ focused }) {
|
|
|
9646
9701
|
adding ? /* @__PURE__ */ jsx6(Box6, { flexDirection: "column", children: /* @__PURE__ */ jsxs6(Box6, { children: [
|
|
9647
9702
|
/* @__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
9703
|
/* @__PURE__ */ jsx6(
|
|
9649
|
-
|
|
9704
|
+
TextInput4,
|
|
9650
9705
|
{
|
|
9651
9706
|
value: input,
|
|
9652
9707
|
onChange: setInput,
|
|
@@ -9690,7 +9745,7 @@ var init_Dlp = __esm({
|
|
|
9690
9745
|
|
|
9691
9746
|
// src/tui/panels/Audit.tsx
|
|
9692
9747
|
import { Box as Box7, Text as Text7, useInput as useInput6 } from "ink";
|
|
9693
|
-
import
|
|
9748
|
+
import TextInput5 from "ink-text-input";
|
|
9694
9749
|
import { mkdirSync as mkdirSync7, writeFileSync as writeFileSync8 } from "fs";
|
|
9695
9750
|
import { homedir as homedir8 } from "os";
|
|
9696
9751
|
import { join as join10 } from "path";
|
|
@@ -10129,7 +10184,7 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
10129
10184
|
editing === "sess-search" ? /* @__PURE__ */ jsxs7(Box7, { children: [
|
|
10130
10185
|
/* @__PURE__ */ jsx7(Text7, { color: theme.warn, children: "search: " }),
|
|
10131
10186
|
/* @__PURE__ */ jsx7(
|
|
10132
|
-
|
|
10187
|
+
TextInput5,
|
|
10133
10188
|
{
|
|
10134
10189
|
value: sessSearch,
|
|
10135
10190
|
onChange: (v) => {
|
|
@@ -10207,7 +10262,7 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
10207
10262
|
": "
|
|
10208
10263
|
] }),
|
|
10209
10264
|
/* @__PURE__ */ jsx7(
|
|
10210
|
-
|
|
10265
|
+
TextInput5,
|
|
10211
10266
|
{
|
|
10212
10267
|
value: editing === "tool" ? tool : editing === "agent" ? agent : search,
|
|
10213
10268
|
onChange: (v) => {
|
|
@@ -10631,7 +10686,7 @@ var init_global_install = __esm({
|
|
|
10631
10686
|
|
|
10632
10687
|
// src/tui/panels/Settings.tsx
|
|
10633
10688
|
import { Box as Box8, Text as Text8, useInput as useInput7 } from "ink";
|
|
10634
|
-
import
|
|
10689
|
+
import TextInput6 from "ink-text-input";
|
|
10635
10690
|
import { useEffect as useEffect7, useRef as useRef3, useState as useState8 } from "react";
|
|
10636
10691
|
import { Fragment as Fragment5, jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
10637
10692
|
function SettingsPanel({
|
|
@@ -11055,7 +11110,7 @@ function SettingsPanel({
|
|
|
11055
11110
|
/* @__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
11111
|
editing === "alert-target" ? /* @__PURE__ */ jsxs8(Box8, { marginTop: 1, children: [
|
|
11057
11112
|
/* @__PURE__ */ jsx8(Text8, { color: theme.warn, children: editor.channel === "email" ? "e-mail address: " : "telegram chat id (from @userinfobot): " }),
|
|
11058
|
-
/* @__PURE__ */ jsx8(
|
|
11113
|
+
/* @__PURE__ */ jsx8(TextInput6, { value: input, onChange: setInput, onSubmit: submitInput })
|
|
11059
11114
|
] }) : msg ? /* @__PURE__ */ jsx8(Text8, { color: msg.level === "bad" ? theme.bad : theme.ok, children: truncate2(msg.text, cols) }) : /* @__PURE__ */ jsx8(Text8, { children: " " }),
|
|
11060
11115
|
/* @__PURE__ */ jsxs8(Box8, { marginTop: 1, flexDirection: "column", children: [
|
|
11061
11116
|
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"),
|
|
@@ -11235,7 +11290,7 @@ function SettingsPanel({
|
|
|
11235
11290
|
/* @__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
11291
|
editing ? /* @__PURE__ */ jsxs8(Box8, { children: [
|
|
11237
11292
|
/* @__PURE__ */ jsx8(Text8, { color: theme.warn, children: editing === "path" ? "local log path: " : "webhook url: " }),
|
|
11238
|
-
/* @__PURE__ */ jsx8(
|
|
11293
|
+
/* @__PURE__ */ jsx8(TextInput6, { value: input, onChange: setInput, onSubmit: submitInput })
|
|
11239
11294
|
] }) : 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
11295
|
/* @__PURE__ */ jsx8(Box8, { flexDirection: "column", height: budget, overflow: "hidden", children: win })
|
|
11241
11296
|
] }) });
|
|
@@ -11308,6 +11363,18 @@ function App() {
|
|
|
11308
11363
|
const [viewNonce, setViewNonce] = useState9(0);
|
|
11309
11364
|
const [section, setSection] = useState9(accounts.length === 0 ? SETTINGS_SECTION : 0);
|
|
11310
11365
|
const [focus, setFocus] = useState9("nav");
|
|
11366
|
+
useEffect8(
|
|
11367
|
+
() => onSectionRequest(() => {
|
|
11368
|
+
const label = takePendingSection();
|
|
11369
|
+
if (!label) return;
|
|
11370
|
+
const idx = SECTIONS.findIndex((s) => s.label === label);
|
|
11371
|
+
if (idx >= 0) {
|
|
11372
|
+
setSection(idx);
|
|
11373
|
+
setFocus("panel");
|
|
11374
|
+
}
|
|
11375
|
+
}),
|
|
11376
|
+
[]
|
|
11377
|
+
);
|
|
11311
11378
|
const [help, setHelp] = useState9(false);
|
|
11312
11379
|
const [update2, setUpdate] = useState9({ kind: "idle" });
|
|
11313
11380
|
useEffect8(() => {
|
|
@@ -11445,6 +11512,7 @@ var init_App = __esm({
|
|
|
11445
11512
|
init_DryRun();
|
|
11446
11513
|
init_Settings();
|
|
11447
11514
|
init_hooks();
|
|
11515
|
+
init_nav();
|
|
11448
11516
|
init_client();
|
|
11449
11517
|
init_api_client();
|
|
11450
11518
|
init_self_update();
|
package/dist/tui/index.js
CHANGED
|
@@ -1904,14 +1904,15 @@ function LivePanel({ active: active2 }) {
|
|
|
1904
1904
|
|
|
1905
1905
|
// src/tui/panels/Policies.tsx
|
|
1906
1906
|
import { Box as Box4, Text as Text4, useInput as useInput3 } from "ink";
|
|
1907
|
-
import
|
|
1907
|
+
import TextInput3 from "ink-text-input";
|
|
1908
1908
|
import { useEffect as useEffect4, useState as useState4 } from "react";
|
|
1909
1909
|
|
|
1910
1910
|
// src/tui/panels/DryRun.tsx
|
|
1911
1911
|
import { Box as Box3, Text as Text3, useInput as useInput2 } from "ink";
|
|
1912
|
+
import TextInput2 from "ink-text-input";
|
|
1912
1913
|
import { useEffect as useEffect3, useState as useState3 } from "react";
|
|
1913
1914
|
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
1914
|
-
var
|
|
1915
|
+
var DEFAULT_LIMIT = 1e3;
|
|
1915
1916
|
var pendingPolicyId = null;
|
|
1916
1917
|
function requestDryRun(policyId) {
|
|
1917
1918
|
pendingPolicyId = policyId;
|
|
@@ -1921,21 +1922,24 @@ function DryRunPanel({ focused }) {
|
|
|
1921
1922
|
const list5 = useLoader(() => api.policies.list());
|
|
1922
1923
|
const policies = list5.data?.policies ?? [];
|
|
1923
1924
|
const [pi, setPi] = useState3(0);
|
|
1924
|
-
const [
|
|
1925
|
+
const [limit, setLimit] = useState3(DEFAULT_LIMIT);
|
|
1926
|
+
const [editLogs, setEditLogs] = useState3(null);
|
|
1927
|
+
const statsQ = useLoader(() => api.stats.get());
|
|
1928
|
+
const totalLogs = statsQ.data?.total_calls ?? null;
|
|
1925
1929
|
const [res, setRes] = useState3(null);
|
|
1926
1930
|
const [running, setRunning] = useState3(false);
|
|
1927
1931
|
const [err, setErr] = useState3(null);
|
|
1928
1932
|
const [off, setOff] = useState3(0);
|
|
1929
1933
|
const { cols, rows } = usePanelSize();
|
|
1930
1934
|
const selected = policies[Math.min(pi, Math.max(0, policies.length - 1))];
|
|
1931
|
-
function run(policyIdx = pi,
|
|
1935
|
+
function run(policyIdx = pi, lim = limit) {
|
|
1932
1936
|
const p = policies[policyIdx];
|
|
1933
1937
|
if (!p) return;
|
|
1934
1938
|
setRunning(true);
|
|
1935
1939
|
setErr(null);
|
|
1936
1940
|
setRes(null);
|
|
1937
1941
|
setOff(0);
|
|
1938
|
-
api.policies.backtest({ rules: p.rules ?? [], mode: p.mode, limit:
|
|
1942
|
+
api.policies.backtest({ rules: p.rules ?? [], mode: p.mode, limit: lim }).then((r) => setRes(r)).catch((e) => setErr(e instanceof Error ? e.message : String(e))).finally(() => setRunning(false));
|
|
1939
1943
|
}
|
|
1940
1944
|
useEffect3(() => {
|
|
1941
1945
|
if (policies.length === 0 || res || running || err) return;
|
|
@@ -1946,22 +1950,28 @@ function DryRunPanel({ focused }) {
|
|
|
1946
1950
|
pendingPolicyId = null;
|
|
1947
1951
|
}
|
|
1948
1952
|
setPi(idx);
|
|
1949
|
-
run(idx,
|
|
1953
|
+
run(idx, limit);
|
|
1950
1954
|
}, [policies.length]);
|
|
1951
1955
|
useInput2((input, key) => {
|
|
1952
|
-
if (!focused) return;
|
|
1956
|
+
if (!focused || editLogs !== null) return;
|
|
1953
1957
|
if (key.upArrow) setOff((n) => Math.max(0, n - 1));
|
|
1954
1958
|
else if (key.downArrow) setOff((n) => n + 1);
|
|
1955
|
-
else if (input === "p") {
|
|
1959
|
+
else if (input === "p" || input === "P") {
|
|
1956
1960
|
const n = policies.length ? (pi + 1) % policies.length : 0;
|
|
1957
1961
|
setPi(n);
|
|
1958
|
-
run(n,
|
|
1959
|
-
} else if (input === "n") {
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
run(pi, n);
|
|
1963
|
-
} else if (input === "r") run(pi, si);
|
|
1962
|
+
run(n, limit);
|
|
1963
|
+
} else if (input === "n" || input === "N") {
|
|
1964
|
+
setEditLogs(String(limit));
|
|
1965
|
+
} else if (input === "r" || input === "R") run(pi, limit);
|
|
1964
1966
|
});
|
|
1967
|
+
function commitLogs(raw) {
|
|
1968
|
+
const cap = totalLogs && totalLogs > 0 ? totalLogs : 5e3;
|
|
1969
|
+
const parsed = parseInt(raw.replace(/[^0-9]/g, ""), 10);
|
|
1970
|
+
const next = Number.isFinite(parsed) && parsed > 0 ? Math.min(parsed, cap) : limit;
|
|
1971
|
+
setEditLogs(null);
|
|
1972
|
+
setLimit(next);
|
|
1973
|
+
run(pi, next);
|
|
1974
|
+
}
|
|
1965
1975
|
const w = Math.max(40, cols);
|
|
1966
1976
|
const lines = [];
|
|
1967
1977
|
const head = (t) => lines.push(/* @__PURE__ */ jsx3(Text3, { bold: true, color: theme.accentBright, children: t }, `h${lines.length}`));
|
|
@@ -2030,38 +2040,57 @@ function DryRunPanel({ focused }) {
|
|
|
2030
2040
|
}
|
|
2031
2041
|
}
|
|
2032
2042
|
}
|
|
2033
|
-
const headerRows =
|
|
2043
|
+
const headerRows = 5;
|
|
2034
2044
|
const budget = Math.max(3, rows - headerRows);
|
|
2035
2045
|
const maxOff = Math.max(0, lines.length - budget);
|
|
2036
2046
|
const start = Math.min(off, maxOff);
|
|
2037
2047
|
const win = lines.slice(start, start + budget);
|
|
2038
2048
|
const above = start;
|
|
2039
2049
|
const below = Math.max(0, lines.length - (start + budget));
|
|
2040
|
-
const sampleLabel = `${SAMPLES[si]}${res?.sampled != null ? ` (ran ${res.sampled})` : ""}`;
|
|
2041
2050
|
return /* @__PURE__ */ jsx3(DataView, { loading: list5.loading && !list5.data, error: list5.error, children: /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", children: [
|
|
2042
|
-
/* @__PURE__ */
|
|
2043
|
-
|
|
2044
|
-
/* @__PURE__ */
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
] }),
|
|
2048
|
-
/* @__PURE__ */ jsxs3(Text3, { color: theme.dim, children: [
|
|
2049
|
-
" mode: ",
|
|
2050
|
-
selected?.mode ?? "-"
|
|
2051
|
-
] }),
|
|
2052
|
-
/* @__PURE__ */ jsxs3(Text3, { color: theme.dim, children: [
|
|
2053
|
-
" sample: ",
|
|
2054
|
-
sampleLabel
|
|
2055
|
-
] })
|
|
2051
|
+
/* @__PURE__ */ jsx3(Text3, { bold: true, color: theme.accentBright, children: "Policy Dry Run" }),
|
|
2052
|
+
/* @__PURE__ */ jsxs3(Text3, { wrap: "truncate", children: [
|
|
2053
|
+
/* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: " policy " }),
|
|
2054
|
+
/* @__PURE__ */ jsx3(Text3, { color: theme.accent, children: "\u2039 " + truncate(selected?.name ?? "none", 30) + " \u203A" }),
|
|
2055
|
+
/* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: ` ${policies.length ? pi + 1 : 0}/${policies.length} press p \xB7 mode ${selected?.mode ?? "-"}` })
|
|
2056
2056
|
] }),
|
|
2057
|
-
/* @__PURE__ */
|
|
2057
|
+
editLogs !== null ? /* @__PURE__ */ jsxs3(Box3, { children: [
|
|
2058
|
+
/* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: " logs " }),
|
|
2059
|
+
/* @__PURE__ */ jsx3(Text3, { color: theme.warn, children: "how many recent logs to replay: " }),
|
|
2060
|
+
/* @__PURE__ */ jsx3(TextInput2, { value: editLogs, onChange: setEditLogs, onSubmit: commitLogs }),
|
|
2061
|
+
/* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: totalLogs != null ? ` (you have ${totalLogs})` : "" })
|
|
2062
|
+
] }) : /* @__PURE__ */ jsxs3(Text3, { wrap: "truncate", children: [
|
|
2063
|
+
/* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: " logs " }),
|
|
2064
|
+
/* @__PURE__ */ jsx3(Text3, { color: theme.accent, children: "\u2039 " + String(limit) + " \u203A" }),
|
|
2065
|
+
/* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: ` press n to type a number${totalLogs != null ? ` you have ${totalLogs}` : ""}${res?.sampled != null ? ` replayed ${res.sampled}` : ""}` })
|
|
2066
|
+
] }),
|
|
2067
|
+
/* @__PURE__ */ jsx3(Text3, { color: theme.dim, wrap: "truncate", children: focused ? `\u2191\u2193 scroll \xB7 p policy \xB7 n logs \xB7 r re-run${above ? ` \xB7 \u25B2${above}` : ""}${below ? ` \xB7 \u25BC${below}` : ""}` : "press \u2192 to open" }),
|
|
2058
2068
|
running ? /* @__PURE__ */ jsx3(Text3, { color: theme.warn, children: "replaying recent traffic\u2026" }) : null,
|
|
2059
2069
|
err ? /* @__PURE__ */ jsx3(Text3, { color: theme.bad, wrap: "truncate", children: "\u2717 " + err }) : null,
|
|
2060
|
-
!running && !err && !res ? /* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: "no result yet
|
|
2070
|
+
!running && !err && !res ? /* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: "no result yet, press r to run" }) : null,
|
|
2061
2071
|
/* @__PURE__ */ jsx3(Box3, { marginTop: 1, flexDirection: "column", children: win })
|
|
2062
2072
|
] }) });
|
|
2063
2073
|
}
|
|
2064
2074
|
|
|
2075
|
+
// src/tui/nav.ts
|
|
2076
|
+
var pending = null;
|
|
2077
|
+
var subs = /* @__PURE__ */ new Set();
|
|
2078
|
+
function requestSection(label) {
|
|
2079
|
+
pending = label;
|
|
2080
|
+
for (const fn of subs) fn();
|
|
2081
|
+
}
|
|
2082
|
+
function takePendingSection() {
|
|
2083
|
+
const p = pending;
|
|
2084
|
+
pending = null;
|
|
2085
|
+
return p;
|
|
2086
|
+
}
|
|
2087
|
+
function onSectionRequest(fn) {
|
|
2088
|
+
subs.add(fn);
|
|
2089
|
+
return () => {
|
|
2090
|
+
subs.delete(fn);
|
|
2091
|
+
};
|
|
2092
|
+
}
|
|
2093
|
+
|
|
2065
2094
|
// src/tui/panels/Policies.tsx
|
|
2066
2095
|
import { Fragment as Fragment3, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
2067
2096
|
var constr = (r, g, side) => (r[g]?.[side] ?? []).join(", ");
|
|
@@ -2159,8 +2188,20 @@ function PoliciesPanel({ focused }) {
|
|
|
2159
2188
|
setDirty(false);
|
|
2160
2189
|
setStatus("discarded");
|
|
2161
2190
|
};
|
|
2191
|
+
const [creating, setCreating] = useState4(null);
|
|
2192
|
+
function commitNewPolicy(name) {
|
|
2193
|
+
const n = name.trim();
|
|
2194
|
+
setCreating(null);
|
|
2195
|
+
if (!n) return;
|
|
2196
|
+
setStatus("Creating\u2026");
|
|
2197
|
+
void api.policies.create({ id: `policy-${Date.now()}`, name: n, rules: [], mode: "denylist" }).then(() => {
|
|
2198
|
+
setStatus(`\u2713 created "${n}" - open it and press n to add rules`);
|
|
2199
|
+
list5.reload();
|
|
2200
|
+
}).catch((e) => setStatus("\u2717 " + (e instanceof Error ? e.message : String(e))));
|
|
2201
|
+
}
|
|
2162
2202
|
useInput3(
|
|
2163
2203
|
(input, key) => {
|
|
2204
|
+
if (creating !== null) return;
|
|
2164
2205
|
if (key.ctrl && input === "r" && !editing) {
|
|
2165
2206
|
list5.reload();
|
|
2166
2207
|
activeQ.reload();
|
|
@@ -2182,6 +2223,9 @@ function PoliciesPanel({ focused }) {
|
|
|
2182
2223
|
activeQ.reload();
|
|
2183
2224
|
}).catch((e) => setStatus("\u2717 " + (e instanceof Error ? e.message : String(e))));
|
|
2184
2225
|
}
|
|
2226
|
+
} else if (input === "n" || input === "N") {
|
|
2227
|
+
setStatus(null);
|
|
2228
|
+
setCreating("");
|
|
2185
2229
|
} else if (input === "x") {
|
|
2186
2230
|
setStatus("Deactivating\u2026");
|
|
2187
2231
|
void api.policies.setActive(null).then(() => {
|
|
@@ -2221,7 +2265,7 @@ function PoliciesPanel({ focused }) {
|
|
|
2221
2265
|
} else if (input === "D") {
|
|
2222
2266
|
if (selected) {
|
|
2223
2267
|
requestDryRun(selected.id);
|
|
2224
|
-
|
|
2268
|
+
requestSection("Dry Run");
|
|
2225
2269
|
}
|
|
2226
2270
|
} else if (input === "s") void save();
|
|
2227
2271
|
else if (input === "x") discard();
|
|
@@ -2249,7 +2293,7 @@ function PoliciesPanel({ focused }) {
|
|
|
2249
2293
|
);
|
|
2250
2294
|
if (view === "list") {
|
|
2251
2295
|
const activeName = activeId ? policies.find((p) => p.id === activeId)?.name ?? activeId : null;
|
|
2252
|
-
const lHead = 3 + (status ? 1 : 0);
|
|
2296
|
+
const lHead = 3 + (status ? 1 : 0) + (creating !== null ? 1 : 0);
|
|
2253
2297
|
const lBudget = Math.max(3, panelRows - lHead);
|
|
2254
2298
|
const lStart = Math.min(Math.max(0, pi - Math.floor(lBudget / 2)), Math.max(0, policies.length - lBudget));
|
|
2255
2299
|
const lWin = policies.slice(lStart, lStart + lBudget);
|
|
@@ -2266,7 +2310,11 @@ function PoliciesPanel({ focused }) {
|
|
|
2266
2310
|
/* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: activeBy ? ` (${activeBy})` : "" })
|
|
2267
2311
|
] }) : /* @__PURE__ */ jsx4(Text4, { color: theme.bad, bold: true, children: "\u25CB NONE \u2014 nothing enforced, grants refused" })
|
|
2268
2312
|
] }),
|
|
2269
|
-
/* @__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" }),
|
|
2313
|
+
/* @__PURE__ */ jsx4(Text4, { color: theme.dim, wrap: "truncate", children: focused ? `\u2191\u2193 select \xB7 enter open \xB7 n new policy \xB7 a activate \xB7 x deactivate \xB7 ^R refresh${lAbove ? ` \xB7 \u25B2${lAbove}` : ""}${lBelow ? ` \xB7 \u25BC${lBelow}` : ""}` : "press \u2192 to browse" }),
|
|
2314
|
+
creating !== null ? /* @__PURE__ */ jsxs4(Box4, { children: [
|
|
2315
|
+
/* @__PURE__ */ jsx4(Text4, { color: theme.warn, children: "new policy name: " }),
|
|
2316
|
+
/* @__PURE__ */ jsx4(TextInput3, { value: creating, onChange: setCreating, onSubmit: commitNewPolicy })
|
|
2317
|
+
] }) : null,
|
|
2270
2318
|
/* @__PURE__ */ jsx4(Box4, { marginTop: 1, flexDirection: "column", children: lWin.map((p, wi) => {
|
|
2271
2319
|
const i = lStart + wi;
|
|
2272
2320
|
return /* @__PURE__ */ jsxs4(Text4, { color: i === pi ? theme.accentBright : void 0, bold: i === pi, children: [
|
|
@@ -2346,7 +2394,7 @@ function PoliciesPanel({ focused }) {
|
|
|
2346
2394
|
return /* @__PURE__ */ jsxs4(Box4, { children: [
|
|
2347
2395
|
/* @__PURE__ */ jsx4(Text4, { color: active2 ? theme.accentBright : void 0, children: (active2 ? "\u25B8 " : " ") + f.label.padEnd(13) }),
|
|
2348
2396
|
active2 && editing && f.kind === "text" ? /* @__PURE__ */ jsx4(
|
|
2349
|
-
|
|
2397
|
+
TextInput3,
|
|
2350
2398
|
{
|
|
2351
2399
|
value: editVal,
|
|
2352
2400
|
onChange: setEditVal,
|
|
@@ -2541,7 +2589,7 @@ function FieldRow({ label, active: active2, children }) {
|
|
|
2541
2589
|
|
|
2542
2590
|
// src/tui/panels/Dlp.tsx
|
|
2543
2591
|
import { Box as Box6, Text as Text6, useInput as useInput5 } from "ink";
|
|
2544
|
-
import
|
|
2592
|
+
import TextInput4 from "ink-text-input";
|
|
2545
2593
|
import { useEffect as useEffect6, useState as useState6 } from "react";
|
|
2546
2594
|
import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
2547
2595
|
var MODES2 = ["off", "detect", "block"];
|
|
@@ -2722,7 +2770,7 @@ function DlpPanel({ focused }) {
|
|
|
2722
2770
|
adding ? /* @__PURE__ */ jsx6(Box6, { flexDirection: "column", children: /* @__PURE__ */ jsxs6(Box6, { children: [
|
|
2723
2771
|
/* @__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): " }),
|
|
2724
2772
|
/* @__PURE__ */ jsx6(
|
|
2725
|
-
|
|
2773
|
+
TextInput4,
|
|
2726
2774
|
{
|
|
2727
2775
|
value: input,
|
|
2728
2776
|
onChange: setInput,
|
|
@@ -2755,7 +2803,7 @@ function DlpPanel({ focused }) {
|
|
|
2755
2803
|
|
|
2756
2804
|
// src/tui/panels/Audit.tsx
|
|
2757
2805
|
import { Box as Box7, Text as Text7, useInput as useInput6 } from "ink";
|
|
2758
|
-
import
|
|
2806
|
+
import TextInput5 from "ink-text-input";
|
|
2759
2807
|
import { mkdirSync as mkdirSync3, writeFileSync as writeFileSync4 } from "fs";
|
|
2760
2808
|
import { homedir as homedir5 } from "os";
|
|
2761
2809
|
import { join as join5 } from "path";
|
|
@@ -3277,7 +3325,7 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
3277
3325
|
editing === "sess-search" ? /* @__PURE__ */ jsxs7(Box7, { children: [
|
|
3278
3326
|
/* @__PURE__ */ jsx7(Text7, { color: theme.warn, children: "search: " }),
|
|
3279
3327
|
/* @__PURE__ */ jsx7(
|
|
3280
|
-
|
|
3328
|
+
TextInput5,
|
|
3281
3329
|
{
|
|
3282
3330
|
value: sessSearch,
|
|
3283
3331
|
onChange: (v) => {
|
|
@@ -3355,7 +3403,7 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
3355
3403
|
": "
|
|
3356
3404
|
] }),
|
|
3357
3405
|
/* @__PURE__ */ jsx7(
|
|
3358
|
-
|
|
3406
|
+
TextInput5,
|
|
3359
3407
|
{
|
|
3360
3408
|
value: editing === "tool" ? tool : editing === "agent" ? agent : search,
|
|
3361
3409
|
onChange: (v) => {
|
|
@@ -3379,7 +3427,7 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
3379
3427
|
|
|
3380
3428
|
// src/tui/panels/Settings.tsx
|
|
3381
3429
|
import { Box as Box8, Text as Text8, useInput as useInput7 } from "ink";
|
|
3382
|
-
import
|
|
3430
|
+
import TextInput6 from "ink-text-input";
|
|
3383
3431
|
import { useEffect as useEffect7, useRef as useRef3, useState as useState8 } from "react";
|
|
3384
3432
|
|
|
3385
3433
|
// src/global-install.ts
|
|
@@ -4302,7 +4350,7 @@ function SettingsPanel({
|
|
|
4302
4350
|
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "\u2191\u2193 field \xB7 \u2190\u2192 change \xB7 e edit target \xB7 enter save \xB7 esc cancel" }),
|
|
4303
4351
|
editing === "alert-target" ? /* @__PURE__ */ jsxs8(Box8, { marginTop: 1, children: [
|
|
4304
4352
|
/* @__PURE__ */ jsx8(Text8, { color: theme.warn, children: editor.channel === "email" ? "e-mail address: " : "telegram chat id (from @userinfobot): " }),
|
|
4305
|
-
/* @__PURE__ */ jsx8(
|
|
4353
|
+
/* @__PURE__ */ jsx8(TextInput6, { value: input, onChange: setInput, onSubmit: submitInput })
|
|
4306
4354
|
] }) : msg ? /* @__PURE__ */ jsx8(Text8, { color: msg.level === "bad" ? theme.bad : theme.ok, children: truncate(msg.text, cols) }) : /* @__PURE__ */ jsx8(Text8, { children: " " }),
|
|
4307
4355
|
/* @__PURE__ */ jsxs8(Box8, { marginTop: 1, flexDirection: "column", children: [
|
|
4308
4356
|
fieldRow(0, "target", editor.target ? /* @__PURE__ */ jsx8(Text8, { color: theme.accent, children: truncate(editor.target, cols - 16) }) : /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "empty \u2014 press e" }), "press e to edit"),
|
|
@@ -4482,7 +4530,7 @@ function SettingsPanel({
|
|
|
4482
4530
|
/* @__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" }),
|
|
4483
4531
|
editing ? /* @__PURE__ */ jsxs8(Box8, { children: [
|
|
4484
4532
|
/* @__PURE__ */ jsx8(Text8, { color: theme.warn, children: editing === "path" ? "local log path: " : "webhook url: " }),
|
|
4485
|
-
/* @__PURE__ */ jsx8(
|
|
4533
|
+
/* @__PURE__ */ jsx8(TextInput6, { value: input, onChange: setInput, onSubmit: submitInput })
|
|
4486
4534
|
] }) : msg ? /* @__PURE__ */ jsx8(Text8, { wrap: "truncate", color: msg.level === "bad" ? theme.bad : theme.ok, children: truncate(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: " " }),
|
|
4487
4535
|
/* @__PURE__ */ jsx8(Box8, { flexDirection: "column", height: budget, overflow: "hidden", children: win })
|
|
4488
4536
|
] }) });
|
|
@@ -4533,6 +4581,18 @@ function App() {
|
|
|
4533
4581
|
const [viewNonce, setViewNonce] = useState9(0);
|
|
4534
4582
|
const [section, setSection] = useState9(accounts.length === 0 ? SETTINGS_SECTION : 0);
|
|
4535
4583
|
const [focus, setFocus] = useState9("nav");
|
|
4584
|
+
useEffect8(
|
|
4585
|
+
() => onSectionRequest(() => {
|
|
4586
|
+
const label = takePendingSection();
|
|
4587
|
+
if (!label) return;
|
|
4588
|
+
const idx = SECTIONS.findIndex((s) => s.label === label);
|
|
4589
|
+
if (idx >= 0) {
|
|
4590
|
+
setSection(idx);
|
|
4591
|
+
setFocus("panel");
|
|
4592
|
+
}
|
|
4593
|
+
}),
|
|
4594
|
+
[]
|
|
4595
|
+
);
|
|
4536
4596
|
const [help, setHelp] = useState9(false);
|
|
4537
4597
|
const [update2, setUpdate] = useState9({ kind: "idle" });
|
|
4538
4598
|
useEffect8(() => {
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/** Ask the shell to switch to (and focus) the section with this label. */
|
|
2
|
+
export declare function requestSection(label: string): void;
|
|
3
|
+
/** Consume the pending request (returns null when there is none). */
|
|
4
|
+
export declare function takePendingSection(): string | null;
|
|
5
|
+
/** Subscribe to requests. Returns an unsubscribe function. */
|
|
6
|
+
export declare function onSectionRequest(fn: () => void): () => void;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@solongate/proxy",
|
|
3
|
-
"version": "0.82.
|
|
3
|
+
"version": "0.82.35",
|
|
4
4
|
"description": "AI tool security proxy: protect any AI tool server with customizable policies, path/command constraints, rate limiting, and audit logging. No code changes required.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|