@solongate/proxy 0.70.0 → 0.71.0
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/commands/index.js +19 -9
- package/dist/index.js +40 -20
- package/dist/tui/index.js +40 -20
- package/package.json +1 -1
package/dist/commands/index.js
CHANGED
|
@@ -84,17 +84,27 @@ async function request(method, path, opts = {}) {
|
|
|
84
84
|
headers["Content-Type"] = "application/json";
|
|
85
85
|
bodyInit = JSON.stringify(opts.body);
|
|
86
86
|
}
|
|
87
|
+
const attempt = () => fetch(url, {
|
|
88
|
+
method,
|
|
89
|
+
headers,
|
|
90
|
+
body: bodyInit,
|
|
91
|
+
signal: AbortSignal.timeout(opts.timeoutMs ?? 15e3)
|
|
92
|
+
});
|
|
87
93
|
let res;
|
|
88
94
|
try {
|
|
89
|
-
res = await
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
95
|
+
res = await attempt();
|
|
96
|
+
} catch (firstErr) {
|
|
97
|
+
if (method !== "GET") {
|
|
98
|
+
const msg = firstErr instanceof Error ? firstErr.message : String(firstErr);
|
|
99
|
+
throw new ApiError(0, "NETWORK_ERROR", `Cannot reach SolonGate API: ${msg}`);
|
|
100
|
+
}
|
|
101
|
+
await new Promise((r) => setTimeout(r, 800));
|
|
102
|
+
try {
|
|
103
|
+
res = await attempt();
|
|
104
|
+
} catch (err2) {
|
|
105
|
+
const msg = err2 instanceof Error ? err2.message : String(err2);
|
|
106
|
+
throw new ApiError(0, "NETWORK_ERROR", `Cannot reach SolonGate API: ${msg}`);
|
|
107
|
+
}
|
|
98
108
|
}
|
|
99
109
|
const text = await res.text().catch(() => "");
|
|
100
110
|
let json = void 0;
|
package/dist/index.js
CHANGED
|
@@ -6633,17 +6633,27 @@ async function request(method, path, opts = {}) {
|
|
|
6633
6633
|
headers["Content-Type"] = "application/json";
|
|
6634
6634
|
bodyInit = JSON.stringify(opts.body);
|
|
6635
6635
|
}
|
|
6636
|
+
const attempt = () => fetch(url, {
|
|
6637
|
+
method,
|
|
6638
|
+
headers,
|
|
6639
|
+
body: bodyInit,
|
|
6640
|
+
signal: AbortSignal.timeout(opts.timeoutMs ?? 15e3)
|
|
6641
|
+
});
|
|
6636
6642
|
let res;
|
|
6637
6643
|
try {
|
|
6638
|
-
res = await
|
|
6639
|
-
|
|
6640
|
-
|
|
6641
|
-
|
|
6642
|
-
|
|
6643
|
-
}
|
|
6644
|
-
|
|
6645
|
-
|
|
6646
|
-
|
|
6644
|
+
res = await attempt();
|
|
6645
|
+
} catch (firstErr) {
|
|
6646
|
+
if (method !== "GET") {
|
|
6647
|
+
const msg = firstErr instanceof Error ? firstErr.message : String(firstErr);
|
|
6648
|
+
throw new ApiError(0, "NETWORK_ERROR", `Cannot reach SolonGate API: ${msg}`);
|
|
6649
|
+
}
|
|
6650
|
+
await new Promise((r) => setTimeout(r, 800));
|
|
6651
|
+
try {
|
|
6652
|
+
res = await attempt();
|
|
6653
|
+
} catch (err2) {
|
|
6654
|
+
const msg = err2 instanceof Error ? err2.message : String(err2);
|
|
6655
|
+
throw new ApiError(0, "NETWORK_ERROR", `Cannot reach SolonGate API: ${msg}`);
|
|
6656
|
+
}
|
|
6647
6657
|
}
|
|
6648
6658
|
const text = await res.text().catch(() => "");
|
|
6649
6659
|
let json = void 0;
|
|
@@ -7055,7 +7065,7 @@ function copyToClipboard(text) {
|
|
|
7055
7065
|
}
|
|
7056
7066
|
}
|
|
7057
7067
|
process.stdout.write(`\x1B]52;c;${Buffer.from(text, "utf-8").toString("base64")}\x07`);
|
|
7058
|
-
return
|
|
7068
|
+
return null;
|
|
7059
7069
|
}
|
|
7060
7070
|
function cloudItem(e) {
|
|
7061
7071
|
return {
|
|
@@ -7121,14 +7131,14 @@ function PaneTitle({ label, extra, width: width2 }) {
|
|
|
7121
7131
|
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: tail + "\u2500".repeat(Math.max(0, width2 - used)) })
|
|
7122
7132
|
] });
|
|
7123
7133
|
}
|
|
7124
|
-
function StreamLine({ e }) {
|
|
7134
|
+
function StreamLine({ e, loc }) {
|
|
7125
7135
|
return /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
7126
7136
|
/* @__PURE__ */ jsxs2(Text2, { color: theme.dim, children: [
|
|
7127
7137
|
"[",
|
|
7128
7138
|
hhmmss(e.at),
|
|
7129
7139
|
" "
|
|
7130
7140
|
] }),
|
|
7131
|
-
/* @__PURE__ */ jsx2(Text2, { color:
|
|
7141
|
+
/* @__PURE__ */ jsx2(Text2, { color: loc ? theme.ok : "#4f6db8", children: loc ? "LOC" : "CLD" }),
|
|
7132
7142
|
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "] " }),
|
|
7133
7143
|
/* @__PURE__ */ jsx2(Text2, { color: decisionColor(e.decision), bold: e.decision !== "ALLOW", children: e.decision.padEnd(6) }),
|
|
7134
7144
|
/* @__PURE__ */ jsx2(Text2, { color: theme.accent, children: truncate2(e.tool, 12).padEnd(13) }),
|
|
@@ -7323,9 +7333,13 @@ function LivePanel({ active: active2 }) {
|
|
|
7323
7333
|
const ins = insights.data ?? {};
|
|
7324
7334
|
const spin = SPIN[tick % SPIN.length];
|
|
7325
7335
|
const nowMs = Date.now();
|
|
7326
|
-
const
|
|
7327
|
-
|
|
7328
|
-
|
|
7336
|
+
const localKeys = /* @__PURE__ */ new Set();
|
|
7337
|
+
for (const e of localBuf) {
|
|
7338
|
+
const m = Math.round(e.at / 6e4);
|
|
7339
|
+
for (const d of [-1, 0, 1]) localKeys.add(`${e.tool}|${e.decision}|${m + d}`);
|
|
7340
|
+
}
|
|
7341
|
+
const cloudDeduped = cloudBuf.filter((e) => !localKeys.has(`${e.tool}|${e.decision}|${Math.round(e.at / 6e4)}`));
|
|
7342
|
+
const mergedAll = [...cloudDeduped, ...localBuf].sort((a, b) => a.at - b.at);
|
|
7329
7343
|
const points = tsData?.timeseries ?? [];
|
|
7330
7344
|
const nowMin = Math.floor(nowMs / 6e4);
|
|
7331
7345
|
const minuteCounts = new Array(60).fill(0);
|
|
@@ -7382,6 +7396,11 @@ function LivePanel({ active: active2 }) {
|
|
|
7382
7396
|
isMe: false
|
|
7383
7397
|
}))
|
|
7384
7398
|
];
|
|
7399
|
+
const localSessIds = new Set(localSess.keys());
|
|
7400
|
+
if (ring?.session) localSessIds.add(ring.session);
|
|
7401
|
+
const isLoc = (e) => e.source === "local" || !!e.session && localSessIds.has(e.session);
|
|
7402
|
+
const filtered = filter === "all" ? mergedAll : mergedAll.filter((e) => filter === "local" ? isLoc(e) : !isLoc(e));
|
|
7403
|
+
const visibleDesc = filtered.slice(-STREAM_KEEP).reverse();
|
|
7385
7404
|
const chartH = rows >= 36 ? 6 : 4;
|
|
7386
7405
|
const colH = rows >= 32 ? 7 : 5;
|
|
7387
7406
|
const streamRows = Math.max(4, rows - 5 - (1 + chartH) - colH);
|
|
@@ -7443,14 +7462,15 @@ function LivePanel({ active: active2 }) {
|
|
|
7443
7462
|
const dump = visibleDesc.map(
|
|
7444
7463
|
(e) => `[${new Date(e.at).toISOString()}] ${e.source.toUpperCase().padEnd(5)} ${e.decision.padEnd(6)} ${e.tool.padEnd(16)} ${e.permission.padEnd(5)} ${e.evalMs != null ? String(e.evalMs).padStart(5) + "ms " : " "}${(e.agent ?? "-").padEnd(14)} ${e.session ? e.session.slice(0, 8) : "- "} ${e.detail}`
|
|
7445
7464
|
).join("\n");
|
|
7446
|
-
let via = "file";
|
|
7447
7465
|
try {
|
|
7448
7466
|
mkdirSync3(dirname(DUMP), { recursive: true });
|
|
7449
7467
|
writeFileSync3(DUMP, dump + "\n");
|
|
7450
7468
|
} catch {
|
|
7451
7469
|
}
|
|
7452
|
-
via = copyToClipboard(dump);
|
|
7453
|
-
setToast(
|
|
7470
|
+
const via = copyToClipboard(dump);
|
|
7471
|
+
setToast(
|
|
7472
|
+
via ? { msg: `\u2713 ${visibleDesc.length} lines in clipboard (${via})`, until: Date.now() + 4e3 } : { msg: "\u2717 no clipboard tool \u2014 install wl-clipboard or xclip", until: Date.now() + 6e3 }
|
|
7473
|
+
);
|
|
7454
7474
|
}
|
|
7455
7475
|
},
|
|
7456
7476
|
{ isActive: active2 }
|
|
@@ -7526,7 +7546,7 @@ function LivePanel({ active: active2 }) {
|
|
|
7526
7546
|
/* @__PURE__ */ jsx2(PaneTitle, { label: "TIMELINE", extra: `${d.length} calls \xB7 newest first${dScroll ? ` \xB7 \u25BC${dScroll} older` : ""} \xB7 \u2191\u2193 scroll \xB7 \u2190 back`, width: innerW }),
|
|
7527
7547
|
/* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", height: tlRows, overflow: "hidden", children: [
|
|
7528
7548
|
tl.length === 0 ? /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: detailCloud.length === 0 ? spin + " loading history\u2026" : "no entries" }) : null,
|
|
7529
|
-
tl.map((e) => /* @__PURE__ */ jsx2(StreamLine, { e }, e.id))
|
|
7549
|
+
tl.map((e) => /* @__PURE__ */ jsx2(StreamLine, { e, loc: isLoc(e) }, e.id))
|
|
7530
7550
|
] }),
|
|
7531
7551
|
/* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
7532
7552
|
/* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", bold: true, children: " SESSION " }),
|
|
@@ -7645,7 +7665,7 @@ function LivePanel({ active: active2 }) {
|
|
|
7645
7665
|
spin,
|
|
7646
7666
|
" awaiting traffic\u2026"
|
|
7647
7667
|
] }) : null,
|
|
7648
|
-
windowed.map((e) => /* @__PURE__ */ jsx2(StreamLine, { e }, e.id))
|
|
7668
|
+
windowed.map((e) => /* @__PURE__ */ jsx2(StreamLine, { e, loc: isLoc(e) }, e.id))
|
|
7649
7669
|
] }),
|
|
7650
7670
|
/* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
7651
7671
|
/* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", bold: true, children: " LIVE " }),
|
package/dist/tui/index.js
CHANGED
|
@@ -220,17 +220,27 @@ async function request(method, path, opts = {}) {
|
|
|
220
220
|
headers["Content-Type"] = "application/json";
|
|
221
221
|
bodyInit = JSON.stringify(opts.body);
|
|
222
222
|
}
|
|
223
|
+
const attempt = () => fetch(url, {
|
|
224
|
+
method,
|
|
225
|
+
headers,
|
|
226
|
+
body: bodyInit,
|
|
227
|
+
signal: AbortSignal.timeout(opts.timeoutMs ?? 15e3)
|
|
228
|
+
});
|
|
223
229
|
let res;
|
|
224
230
|
try {
|
|
225
|
-
res = await
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
231
|
+
res = await attempt();
|
|
232
|
+
} catch (firstErr) {
|
|
233
|
+
if (method !== "GET") {
|
|
234
|
+
const msg = firstErr instanceof Error ? firstErr.message : String(firstErr);
|
|
235
|
+
throw new ApiError(0, "NETWORK_ERROR", `Cannot reach SolonGate API: ${msg}`);
|
|
236
|
+
}
|
|
237
|
+
await new Promise((r) => setTimeout(r, 800));
|
|
238
|
+
try {
|
|
239
|
+
res = await attempt();
|
|
240
|
+
} catch (err) {
|
|
241
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
242
|
+
throw new ApiError(0, "NETWORK_ERROR", `Cannot reach SolonGate API: ${msg}`);
|
|
243
|
+
}
|
|
234
244
|
}
|
|
235
245
|
const text = await res.text().catch(() => "");
|
|
236
246
|
let json = void 0;
|
|
@@ -480,7 +490,7 @@ function copyToClipboard(text) {
|
|
|
480
490
|
}
|
|
481
491
|
}
|
|
482
492
|
process.stdout.write(`\x1B]52;c;${Buffer.from(text, "utf-8").toString("base64")}\x07`);
|
|
483
|
-
return
|
|
493
|
+
return null;
|
|
484
494
|
}
|
|
485
495
|
function cloudItem(e) {
|
|
486
496
|
return {
|
|
@@ -546,14 +556,14 @@ function PaneTitle({ label, extra, width }) {
|
|
|
546
556
|
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: tail + "\u2500".repeat(Math.max(0, width - used)) })
|
|
547
557
|
] });
|
|
548
558
|
}
|
|
549
|
-
function StreamLine({ e }) {
|
|
559
|
+
function StreamLine({ e, loc }) {
|
|
550
560
|
return /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
551
561
|
/* @__PURE__ */ jsxs2(Text2, { color: theme.dim, children: [
|
|
552
562
|
"[",
|
|
553
563
|
hhmmss(e.at),
|
|
554
564
|
" "
|
|
555
565
|
] }),
|
|
556
|
-
/* @__PURE__ */ jsx2(Text2, { color:
|
|
566
|
+
/* @__PURE__ */ jsx2(Text2, { color: loc ? theme.ok : "#4f6db8", children: loc ? "LOC" : "CLD" }),
|
|
557
567
|
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "] " }),
|
|
558
568
|
/* @__PURE__ */ jsx2(Text2, { color: decisionColor(e.decision), bold: e.decision !== "ALLOW", children: e.decision.padEnd(6) }),
|
|
559
569
|
/* @__PURE__ */ jsx2(Text2, { color: theme.accent, children: truncate(e.tool, 12).padEnd(13) }),
|
|
@@ -749,9 +759,13 @@ function LivePanel({ active: active2 }) {
|
|
|
749
759
|
const ins = insights.data ?? {};
|
|
750
760
|
const spin = SPIN[tick % SPIN.length];
|
|
751
761
|
const nowMs = Date.now();
|
|
752
|
-
const
|
|
753
|
-
|
|
754
|
-
|
|
762
|
+
const localKeys = /* @__PURE__ */ new Set();
|
|
763
|
+
for (const e of localBuf) {
|
|
764
|
+
const m = Math.round(e.at / 6e4);
|
|
765
|
+
for (const d of [-1, 0, 1]) localKeys.add(`${e.tool}|${e.decision}|${m + d}`);
|
|
766
|
+
}
|
|
767
|
+
const cloudDeduped = cloudBuf.filter((e) => !localKeys.has(`${e.tool}|${e.decision}|${Math.round(e.at / 6e4)}`));
|
|
768
|
+
const mergedAll = [...cloudDeduped, ...localBuf].sort((a, b) => a.at - b.at);
|
|
755
769
|
const points = tsData?.timeseries ?? [];
|
|
756
770
|
const nowMin = Math.floor(nowMs / 6e4);
|
|
757
771
|
const minuteCounts = new Array(60).fill(0);
|
|
@@ -808,6 +822,11 @@ function LivePanel({ active: active2 }) {
|
|
|
808
822
|
isMe: false
|
|
809
823
|
}))
|
|
810
824
|
];
|
|
825
|
+
const localSessIds = new Set(localSess.keys());
|
|
826
|
+
if (ring?.session) localSessIds.add(ring.session);
|
|
827
|
+
const isLoc = (e) => e.source === "local" || !!e.session && localSessIds.has(e.session);
|
|
828
|
+
const filtered = filter === "all" ? mergedAll : mergedAll.filter((e) => filter === "local" ? isLoc(e) : !isLoc(e));
|
|
829
|
+
const visibleDesc = filtered.slice(-STREAM_KEEP).reverse();
|
|
811
830
|
const chartH = rows >= 36 ? 6 : 4;
|
|
812
831
|
const colH = rows >= 32 ? 7 : 5;
|
|
813
832
|
const streamRows = Math.max(4, rows - 5 - (1 + chartH) - colH);
|
|
@@ -869,14 +888,15 @@ function LivePanel({ active: active2 }) {
|
|
|
869
888
|
const dump = visibleDesc.map(
|
|
870
889
|
(e) => `[${new Date(e.at).toISOString()}] ${e.source.toUpperCase().padEnd(5)} ${e.decision.padEnd(6)} ${e.tool.padEnd(16)} ${e.permission.padEnd(5)} ${e.evalMs != null ? String(e.evalMs).padStart(5) + "ms " : " "}${(e.agent ?? "-").padEnd(14)} ${e.session ? e.session.slice(0, 8) : "- "} ${e.detail}`
|
|
871
890
|
).join("\n");
|
|
872
|
-
let via = "file";
|
|
873
891
|
try {
|
|
874
892
|
mkdirSync(dirname(DUMP), { recursive: true });
|
|
875
893
|
writeFileSync(DUMP, dump + "\n");
|
|
876
894
|
} catch {
|
|
877
895
|
}
|
|
878
|
-
via = copyToClipboard(dump);
|
|
879
|
-
setToast(
|
|
896
|
+
const via = copyToClipboard(dump);
|
|
897
|
+
setToast(
|
|
898
|
+
via ? { msg: `\u2713 ${visibleDesc.length} lines in clipboard (${via})`, until: Date.now() + 4e3 } : { msg: "\u2717 no clipboard tool \u2014 install wl-clipboard or xclip", until: Date.now() + 6e3 }
|
|
899
|
+
);
|
|
880
900
|
}
|
|
881
901
|
},
|
|
882
902
|
{ isActive: active2 }
|
|
@@ -952,7 +972,7 @@ function LivePanel({ active: active2 }) {
|
|
|
952
972
|
/* @__PURE__ */ jsx2(PaneTitle, { label: "TIMELINE", extra: `${d.length} calls \xB7 newest first${dScroll ? ` \xB7 \u25BC${dScroll} older` : ""} \xB7 \u2191\u2193 scroll \xB7 \u2190 back`, width: innerW }),
|
|
953
973
|
/* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", height: tlRows, overflow: "hidden", children: [
|
|
954
974
|
tl.length === 0 ? /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: detailCloud.length === 0 ? spin + " loading history\u2026" : "no entries" }) : null,
|
|
955
|
-
tl.map((e) => /* @__PURE__ */ jsx2(StreamLine, { e }, e.id))
|
|
975
|
+
tl.map((e) => /* @__PURE__ */ jsx2(StreamLine, { e, loc: isLoc(e) }, e.id))
|
|
956
976
|
] }),
|
|
957
977
|
/* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
958
978
|
/* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", bold: true, children: " SESSION " }),
|
|
@@ -1071,7 +1091,7 @@ function LivePanel({ active: active2 }) {
|
|
|
1071
1091
|
spin,
|
|
1072
1092
|
" awaiting traffic\u2026"
|
|
1073
1093
|
] }) : null,
|
|
1074
|
-
windowed.map((e) => /* @__PURE__ */ jsx2(StreamLine, { e }, e.id))
|
|
1094
|
+
windowed.map((e) => /* @__PURE__ */ jsx2(StreamLine, { e, loc: isLoc(e) }, e.id))
|
|
1075
1095
|
] }),
|
|
1076
1096
|
/* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
1077
1097
|
/* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", bold: true, children: " LIVE " }),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@solongate/proxy",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.71.0",
|
|
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": {
|