@solongate/proxy 0.82.34 → 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 +63 -29
- package/dist/tui/index.js +62 -28
- 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}`));
|
|
@@ -8932,10 +8942,15 @@ function DryRunPanel({ focused }) {
|
|
|
8932
8942
|
/* @__PURE__ */ jsx3(Text3, { color: theme.accent, children: "\u2039 " + truncate2(selected?.name ?? "none", 30) + " \u203A" }),
|
|
8933
8943
|
/* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: ` ${policies.length ? pi + 1 : 0}/${policies.length} press p \xB7 mode ${selected?.mode ?? "-"}` })
|
|
8934
8944
|
] }),
|
|
8935
|
-
/* @__PURE__ */ jsxs3(
|
|
8945
|
+
editLogs !== null ? /* @__PURE__ */ jsxs3(Box3, { children: [
|
|
8936
8946
|
/* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: " logs " }),
|
|
8937
|
-
/* @__PURE__ */ jsx3(Text3, { color: theme.
|
|
8938
|
-
/* @__PURE__ */ jsx3(
|
|
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}` : ""}` })
|
|
8939
8954
|
] }),
|
|
8940
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" }),
|
|
8941
8956
|
running ? /* @__PURE__ */ jsx3(Text3, { color: theme.warn, children: "replaying recent traffic\u2026" }) : null,
|
|
@@ -8944,7 +8959,7 @@ function DryRunPanel({ focused }) {
|
|
|
8944
8959
|
/* @__PURE__ */ jsx3(Box3, { marginTop: 1, flexDirection: "column", children: win })
|
|
8945
8960
|
] }) });
|
|
8946
8961
|
}
|
|
8947
|
-
var
|
|
8962
|
+
var DEFAULT_LIMIT, pendingPolicyId, pct;
|
|
8948
8963
|
var init_DryRun = __esm({
|
|
8949
8964
|
"src/tui/panels/DryRun.tsx"() {
|
|
8950
8965
|
"use strict";
|
|
@@ -8952,7 +8967,7 @@ var init_DryRun = __esm({
|
|
|
8952
8967
|
init_components();
|
|
8953
8968
|
init_hooks();
|
|
8954
8969
|
init_theme();
|
|
8955
|
-
|
|
8970
|
+
DEFAULT_LIMIT = 1e3;
|
|
8956
8971
|
pendingPolicyId = null;
|
|
8957
8972
|
pct = (n, d) => d ? (n / d * 100).toFixed(1) + "%" : "0%";
|
|
8958
8973
|
}
|
|
@@ -8985,7 +9000,7 @@ var init_nav = __esm({
|
|
|
8985
9000
|
|
|
8986
9001
|
// src/tui/panels/Policies.tsx
|
|
8987
9002
|
import { Box as Box4, Text as Text4, useInput as useInput3 } from "ink";
|
|
8988
|
-
import
|
|
9003
|
+
import TextInput3 from "ink-text-input";
|
|
8989
9004
|
import { useEffect as useEffect4, useState as useState4 } from "react";
|
|
8990
9005
|
import { Fragment as Fragment3, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
8991
9006
|
function ruleSummary(r) {
|
|
@@ -9062,8 +9077,20 @@ function PoliciesPanel({ focused }) {
|
|
|
9062
9077
|
setDirty(false);
|
|
9063
9078
|
setStatus("discarded");
|
|
9064
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
|
+
}
|
|
9065
9091
|
useInput3(
|
|
9066
9092
|
(input, key) => {
|
|
9093
|
+
if (creating !== null) return;
|
|
9067
9094
|
if (key.ctrl && input === "r" && !editing) {
|
|
9068
9095
|
list6.reload();
|
|
9069
9096
|
activeQ.reload();
|
|
@@ -9085,6 +9112,9 @@ function PoliciesPanel({ focused }) {
|
|
|
9085
9112
|
activeQ.reload();
|
|
9086
9113
|
}).catch((e) => setStatus("\u2717 " + (e instanceof Error ? e.message : String(e))));
|
|
9087
9114
|
}
|
|
9115
|
+
} else if (input === "n" || input === "N") {
|
|
9116
|
+
setStatus(null);
|
|
9117
|
+
setCreating("");
|
|
9088
9118
|
} else if (input === "x") {
|
|
9089
9119
|
setStatus("Deactivating\u2026");
|
|
9090
9120
|
void api.policies.setActive(null).then(() => {
|
|
@@ -9152,7 +9182,7 @@ function PoliciesPanel({ focused }) {
|
|
|
9152
9182
|
);
|
|
9153
9183
|
if (view === "list") {
|
|
9154
9184
|
const activeName = activeId ? policies.find((p) => p.id === activeId)?.name ?? activeId : null;
|
|
9155
|
-
const lHead = 3 + (status ? 1 : 0);
|
|
9185
|
+
const lHead = 3 + (status ? 1 : 0) + (creating !== null ? 1 : 0);
|
|
9156
9186
|
const lBudget = Math.max(3, panelRows - lHead);
|
|
9157
9187
|
const lStart = Math.min(Math.max(0, pi - Math.floor(lBudget / 2)), Math.max(0, policies.length - lBudget));
|
|
9158
9188
|
const lWin = policies.slice(lStart, lStart + lBudget);
|
|
@@ -9169,7 +9199,11 @@ function PoliciesPanel({ focused }) {
|
|
|
9169
9199
|
/* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: activeBy ? ` (${activeBy})` : "" })
|
|
9170
9200
|
] }) : /* @__PURE__ */ jsx4(Text4, { color: theme.bad, bold: true, children: "\u25CB NONE \u2014 nothing enforced, grants refused" })
|
|
9171
9201
|
] }),
|
|
9172
|
-
/* @__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,
|
|
9173
9207
|
/* @__PURE__ */ jsx4(Box4, { marginTop: 1, flexDirection: "column", children: lWin.map((p, wi) => {
|
|
9174
9208
|
const i = lStart + wi;
|
|
9175
9209
|
return /* @__PURE__ */ jsxs4(Text4, { color: i === pi ? theme.accentBright : void 0, bold: i === pi, children: [
|
|
@@ -9249,7 +9283,7 @@ function PoliciesPanel({ focused }) {
|
|
|
9249
9283
|
return /* @__PURE__ */ jsxs4(Box4, { children: [
|
|
9250
9284
|
/* @__PURE__ */ jsx4(Text4, { color: active2 ? theme.accentBright : void 0, children: (active2 ? "\u25B8 " : " ") + f.label.padEnd(13) }),
|
|
9251
9285
|
active2 && editing && f.kind === "text" ? /* @__PURE__ */ jsx4(
|
|
9252
|
-
|
|
9286
|
+
TextInput3,
|
|
9253
9287
|
{
|
|
9254
9288
|
value: editVal,
|
|
9255
9289
|
onChange: setEditVal,
|
|
@@ -9487,7 +9521,7 @@ var init_RateLimit = __esm({
|
|
|
9487
9521
|
|
|
9488
9522
|
// src/tui/panels/Dlp.tsx
|
|
9489
9523
|
import { Box as Box6, Text as Text6, useInput as useInput5 } from "ink";
|
|
9490
|
-
import
|
|
9524
|
+
import TextInput4 from "ink-text-input";
|
|
9491
9525
|
import { useEffect as useEffect6, useState as useState6 } from "react";
|
|
9492
9526
|
import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
9493
9527
|
function DlpPanel({ focused }) {
|
|
@@ -9667,7 +9701,7 @@ function DlpPanel({ focused }) {
|
|
|
9667
9701
|
adding ? /* @__PURE__ */ jsx6(Box6, { flexDirection: "column", children: /* @__PURE__ */ jsxs6(Box6, { children: [
|
|
9668
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): " }),
|
|
9669
9703
|
/* @__PURE__ */ jsx6(
|
|
9670
|
-
|
|
9704
|
+
TextInput4,
|
|
9671
9705
|
{
|
|
9672
9706
|
value: input,
|
|
9673
9707
|
onChange: setInput,
|
|
@@ -9711,7 +9745,7 @@ var init_Dlp = __esm({
|
|
|
9711
9745
|
|
|
9712
9746
|
// src/tui/panels/Audit.tsx
|
|
9713
9747
|
import { Box as Box7, Text as Text7, useInput as useInput6 } from "ink";
|
|
9714
|
-
import
|
|
9748
|
+
import TextInput5 from "ink-text-input";
|
|
9715
9749
|
import { mkdirSync as mkdirSync7, writeFileSync as writeFileSync8 } from "fs";
|
|
9716
9750
|
import { homedir as homedir8 } from "os";
|
|
9717
9751
|
import { join as join10 } from "path";
|
|
@@ -10150,7 +10184,7 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
10150
10184
|
editing === "sess-search" ? /* @__PURE__ */ jsxs7(Box7, { children: [
|
|
10151
10185
|
/* @__PURE__ */ jsx7(Text7, { color: theme.warn, children: "search: " }),
|
|
10152
10186
|
/* @__PURE__ */ jsx7(
|
|
10153
|
-
|
|
10187
|
+
TextInput5,
|
|
10154
10188
|
{
|
|
10155
10189
|
value: sessSearch,
|
|
10156
10190
|
onChange: (v) => {
|
|
@@ -10228,7 +10262,7 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
10228
10262
|
": "
|
|
10229
10263
|
] }),
|
|
10230
10264
|
/* @__PURE__ */ jsx7(
|
|
10231
|
-
|
|
10265
|
+
TextInput5,
|
|
10232
10266
|
{
|
|
10233
10267
|
value: editing === "tool" ? tool : editing === "agent" ? agent : search,
|
|
10234
10268
|
onChange: (v) => {
|
|
@@ -10652,7 +10686,7 @@ var init_global_install = __esm({
|
|
|
10652
10686
|
|
|
10653
10687
|
// src/tui/panels/Settings.tsx
|
|
10654
10688
|
import { Box as Box8, Text as Text8, useInput as useInput7 } from "ink";
|
|
10655
|
-
import
|
|
10689
|
+
import TextInput6 from "ink-text-input";
|
|
10656
10690
|
import { useEffect as useEffect7, useRef as useRef3, useState as useState8 } from "react";
|
|
10657
10691
|
import { Fragment as Fragment5, jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
10658
10692
|
function SettingsPanel({
|
|
@@ -11076,7 +11110,7 @@ function SettingsPanel({
|
|
|
11076
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" }),
|
|
11077
11111
|
editing === "alert-target" ? /* @__PURE__ */ jsxs8(Box8, { marginTop: 1, children: [
|
|
11078
11112
|
/* @__PURE__ */ jsx8(Text8, { color: theme.warn, children: editor.channel === "email" ? "e-mail address: " : "telegram chat id (from @userinfobot): " }),
|
|
11079
|
-
/* @__PURE__ */ jsx8(
|
|
11113
|
+
/* @__PURE__ */ jsx8(TextInput6, { value: input, onChange: setInput, onSubmit: submitInput })
|
|
11080
11114
|
] }) : msg ? /* @__PURE__ */ jsx8(Text8, { color: msg.level === "bad" ? theme.bad : theme.ok, children: truncate2(msg.text, cols) }) : /* @__PURE__ */ jsx8(Text8, { children: " " }),
|
|
11081
11115
|
/* @__PURE__ */ jsxs8(Box8, { marginTop: 1, flexDirection: "column", children: [
|
|
11082
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"),
|
|
@@ -11256,7 +11290,7 @@ function SettingsPanel({
|
|
|
11256
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" }),
|
|
11257
11291
|
editing ? /* @__PURE__ */ jsxs8(Box8, { children: [
|
|
11258
11292
|
/* @__PURE__ */ jsx8(Text8, { color: theme.warn, children: editing === "path" ? "local log path: " : "webhook url: " }),
|
|
11259
|
-
/* @__PURE__ */ jsx8(
|
|
11293
|
+
/* @__PURE__ */ jsx8(TextInput6, { value: input, onChange: setInput, onSubmit: submitInput })
|
|
11260
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: " " }),
|
|
11261
11295
|
/* @__PURE__ */ jsx8(Box8, { flexDirection: "column", height: budget, overflow: "hidden", children: win })
|
|
11262
11296
|
] }) });
|
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}`));
|
|
@@ -2044,10 +2054,15 @@ function DryRunPanel({ focused }) {
|
|
|
2044
2054
|
/* @__PURE__ */ jsx3(Text3, { color: theme.accent, children: "\u2039 " + truncate(selected?.name ?? "none", 30) + " \u203A" }),
|
|
2045
2055
|
/* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: ` ${policies.length ? pi + 1 : 0}/${policies.length} press p \xB7 mode ${selected?.mode ?? "-"}` })
|
|
2046
2056
|
] }),
|
|
2047
|
-
/* @__PURE__ */ jsxs3(
|
|
2057
|
+
editLogs !== null ? /* @__PURE__ */ jsxs3(Box3, { children: [
|
|
2048
2058
|
/* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: " logs " }),
|
|
2049
|
-
/* @__PURE__ */ jsx3(Text3, { color: theme.
|
|
2050
|
-
/* @__PURE__ */ jsx3(
|
|
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}` : ""}` })
|
|
2051
2066
|
] }),
|
|
2052
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" }),
|
|
2053
2068
|
running ? /* @__PURE__ */ jsx3(Text3, { color: theme.warn, children: "replaying recent traffic\u2026" }) : null,
|
|
@@ -2173,8 +2188,20 @@ function PoliciesPanel({ focused }) {
|
|
|
2173
2188
|
setDirty(false);
|
|
2174
2189
|
setStatus("discarded");
|
|
2175
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
|
+
}
|
|
2176
2202
|
useInput3(
|
|
2177
2203
|
(input, key) => {
|
|
2204
|
+
if (creating !== null) return;
|
|
2178
2205
|
if (key.ctrl && input === "r" && !editing) {
|
|
2179
2206
|
list5.reload();
|
|
2180
2207
|
activeQ.reload();
|
|
@@ -2196,6 +2223,9 @@ function PoliciesPanel({ focused }) {
|
|
|
2196
2223
|
activeQ.reload();
|
|
2197
2224
|
}).catch((e) => setStatus("\u2717 " + (e instanceof Error ? e.message : String(e))));
|
|
2198
2225
|
}
|
|
2226
|
+
} else if (input === "n" || input === "N") {
|
|
2227
|
+
setStatus(null);
|
|
2228
|
+
setCreating("");
|
|
2199
2229
|
} else if (input === "x") {
|
|
2200
2230
|
setStatus("Deactivating\u2026");
|
|
2201
2231
|
void api.policies.setActive(null).then(() => {
|
|
@@ -2263,7 +2293,7 @@ function PoliciesPanel({ focused }) {
|
|
|
2263
2293
|
);
|
|
2264
2294
|
if (view === "list") {
|
|
2265
2295
|
const activeName = activeId ? policies.find((p) => p.id === activeId)?.name ?? activeId : null;
|
|
2266
|
-
const lHead = 3 + (status ? 1 : 0);
|
|
2296
|
+
const lHead = 3 + (status ? 1 : 0) + (creating !== null ? 1 : 0);
|
|
2267
2297
|
const lBudget = Math.max(3, panelRows - lHead);
|
|
2268
2298
|
const lStart = Math.min(Math.max(0, pi - Math.floor(lBudget / 2)), Math.max(0, policies.length - lBudget));
|
|
2269
2299
|
const lWin = policies.slice(lStart, lStart + lBudget);
|
|
@@ -2280,7 +2310,11 @@ function PoliciesPanel({ focused }) {
|
|
|
2280
2310
|
/* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: activeBy ? ` (${activeBy})` : "" })
|
|
2281
2311
|
] }) : /* @__PURE__ */ jsx4(Text4, { color: theme.bad, bold: true, children: "\u25CB NONE \u2014 nothing enforced, grants refused" })
|
|
2282
2312
|
] }),
|
|
2283
|
-
/* @__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,
|
|
2284
2318
|
/* @__PURE__ */ jsx4(Box4, { marginTop: 1, flexDirection: "column", children: lWin.map((p, wi) => {
|
|
2285
2319
|
const i = lStart + wi;
|
|
2286
2320
|
return /* @__PURE__ */ jsxs4(Text4, { color: i === pi ? theme.accentBright : void 0, bold: i === pi, children: [
|
|
@@ -2360,7 +2394,7 @@ function PoliciesPanel({ focused }) {
|
|
|
2360
2394
|
return /* @__PURE__ */ jsxs4(Box4, { children: [
|
|
2361
2395
|
/* @__PURE__ */ jsx4(Text4, { color: active2 ? theme.accentBright : void 0, children: (active2 ? "\u25B8 " : " ") + f.label.padEnd(13) }),
|
|
2362
2396
|
active2 && editing && f.kind === "text" ? /* @__PURE__ */ jsx4(
|
|
2363
|
-
|
|
2397
|
+
TextInput3,
|
|
2364
2398
|
{
|
|
2365
2399
|
value: editVal,
|
|
2366
2400
|
onChange: setEditVal,
|
|
@@ -2555,7 +2589,7 @@ function FieldRow({ label, active: active2, children }) {
|
|
|
2555
2589
|
|
|
2556
2590
|
// src/tui/panels/Dlp.tsx
|
|
2557
2591
|
import { Box as Box6, Text as Text6, useInput as useInput5 } from "ink";
|
|
2558
|
-
import
|
|
2592
|
+
import TextInput4 from "ink-text-input";
|
|
2559
2593
|
import { useEffect as useEffect6, useState as useState6 } from "react";
|
|
2560
2594
|
import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
2561
2595
|
var MODES2 = ["off", "detect", "block"];
|
|
@@ -2736,7 +2770,7 @@ function DlpPanel({ focused }) {
|
|
|
2736
2770
|
adding ? /* @__PURE__ */ jsx6(Box6, { flexDirection: "column", children: /* @__PURE__ */ jsxs6(Box6, { children: [
|
|
2737
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): " }),
|
|
2738
2772
|
/* @__PURE__ */ jsx6(
|
|
2739
|
-
|
|
2773
|
+
TextInput4,
|
|
2740
2774
|
{
|
|
2741
2775
|
value: input,
|
|
2742
2776
|
onChange: setInput,
|
|
@@ -2769,7 +2803,7 @@ function DlpPanel({ focused }) {
|
|
|
2769
2803
|
|
|
2770
2804
|
// src/tui/panels/Audit.tsx
|
|
2771
2805
|
import { Box as Box7, Text as Text7, useInput as useInput6 } from "ink";
|
|
2772
|
-
import
|
|
2806
|
+
import TextInput5 from "ink-text-input";
|
|
2773
2807
|
import { mkdirSync as mkdirSync3, writeFileSync as writeFileSync4 } from "fs";
|
|
2774
2808
|
import { homedir as homedir5 } from "os";
|
|
2775
2809
|
import { join as join5 } from "path";
|
|
@@ -3291,7 +3325,7 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
3291
3325
|
editing === "sess-search" ? /* @__PURE__ */ jsxs7(Box7, { children: [
|
|
3292
3326
|
/* @__PURE__ */ jsx7(Text7, { color: theme.warn, children: "search: " }),
|
|
3293
3327
|
/* @__PURE__ */ jsx7(
|
|
3294
|
-
|
|
3328
|
+
TextInput5,
|
|
3295
3329
|
{
|
|
3296
3330
|
value: sessSearch,
|
|
3297
3331
|
onChange: (v) => {
|
|
@@ -3369,7 +3403,7 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
3369
3403
|
": "
|
|
3370
3404
|
] }),
|
|
3371
3405
|
/* @__PURE__ */ jsx7(
|
|
3372
|
-
|
|
3406
|
+
TextInput5,
|
|
3373
3407
|
{
|
|
3374
3408
|
value: editing === "tool" ? tool : editing === "agent" ? agent : search,
|
|
3375
3409
|
onChange: (v) => {
|
|
@@ -3393,7 +3427,7 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
3393
3427
|
|
|
3394
3428
|
// src/tui/panels/Settings.tsx
|
|
3395
3429
|
import { Box as Box8, Text as Text8, useInput as useInput7 } from "ink";
|
|
3396
|
-
import
|
|
3430
|
+
import TextInput6 from "ink-text-input";
|
|
3397
3431
|
import { useEffect as useEffect7, useRef as useRef3, useState as useState8 } from "react";
|
|
3398
3432
|
|
|
3399
3433
|
// src/global-install.ts
|
|
@@ -4316,7 +4350,7 @@ function SettingsPanel({
|
|
|
4316
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" }),
|
|
4317
4351
|
editing === "alert-target" ? /* @__PURE__ */ jsxs8(Box8, { marginTop: 1, children: [
|
|
4318
4352
|
/* @__PURE__ */ jsx8(Text8, { color: theme.warn, children: editor.channel === "email" ? "e-mail address: " : "telegram chat id (from @userinfobot): " }),
|
|
4319
|
-
/* @__PURE__ */ jsx8(
|
|
4353
|
+
/* @__PURE__ */ jsx8(TextInput6, { value: input, onChange: setInput, onSubmit: submitInput })
|
|
4320
4354
|
] }) : msg ? /* @__PURE__ */ jsx8(Text8, { color: msg.level === "bad" ? theme.bad : theme.ok, children: truncate(msg.text, cols) }) : /* @__PURE__ */ jsx8(Text8, { children: " " }),
|
|
4321
4355
|
/* @__PURE__ */ jsxs8(Box8, { marginTop: 1, flexDirection: "column", children: [
|
|
4322
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"),
|
|
@@ -4496,7 +4530,7 @@ function SettingsPanel({
|
|
|
4496
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" }),
|
|
4497
4531
|
editing ? /* @__PURE__ */ jsxs8(Box8, { children: [
|
|
4498
4532
|
/* @__PURE__ */ jsx8(Text8, { color: theme.warn, children: editing === "path" ? "local log path: " : "webhook url: " }),
|
|
4499
|
-
/* @__PURE__ */ jsx8(
|
|
4533
|
+
/* @__PURE__ */ jsx8(TextInput6, { value: input, onChange: setInput, onSubmit: submitInput })
|
|
4500
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: " " }),
|
|
4501
4535
|
/* @__PURE__ */ jsx8(Box8, { flexDirection: "column", height: budget, overflow: "hidden", children: win })
|
|
4502
4536
|
] }) });
|
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": {
|