@solongate/proxy 0.77.2 → 0.79.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/api-client/audit.d.ts +8 -0
- package/dist/api-client/index.d.ts +4 -0
- package/dist/api-client/keys.d.ts +17 -0
- package/dist/api-client/mcp.d.ts +10 -0
- package/dist/api-client/policies.d.ts +1 -0
- package/dist/api-client/settings.d.ts +46 -0
- package/dist/commands/alerts.d.ts +1 -0
- package/dist/commands/doctor.d.ts +1 -0
- package/dist/commands/index.d.ts +1 -1
- package/dist/commands/index.js +421 -2
- package/dist/commands/keys.d.ts +1 -0
- package/dist/commands/mcp.d.ts +1 -0
- package/dist/commands/watch.d.ts +1 -0
- package/dist/commands/webhooks.d.ts +1 -0
- package/dist/index.js +710 -121
- package/dist/tui/index.js +197 -39
- package/package.json +1 -1
package/dist/tui/index.js
CHANGED
|
@@ -325,9 +325,15 @@ function dryRun(body) {
|
|
|
325
325
|
var settings_exports = {};
|
|
326
326
|
__export(settings_exports, {
|
|
327
327
|
clearRateLimitHistory: () => clearRateLimitHistory,
|
|
328
|
+
createAlert: () => createAlert,
|
|
329
|
+
createWebhook: () => createWebhook,
|
|
330
|
+
deleteAlert: () => deleteAlert,
|
|
331
|
+
deleteWebhook: () => deleteWebhook,
|
|
332
|
+
getAlerts: () => getAlerts,
|
|
328
333
|
getGuardStatus: () => getGuardStatus,
|
|
329
334
|
getRateLimitHistory: () => getRateLimitHistory,
|
|
330
335
|
getSecurityLayers: () => getSecurityLayers,
|
|
336
|
+
getWebhooks: () => getWebhooks,
|
|
331
337
|
setSecurityLayers: () => setSecurityLayers
|
|
332
338
|
});
|
|
333
339
|
function getSecurityLayers() {
|
|
@@ -345,6 +351,24 @@ function clearRateLimitHistory() {
|
|
|
345
351
|
function getGuardStatus() {
|
|
346
352
|
return request("GET", "/settings/guard-status");
|
|
347
353
|
}
|
|
354
|
+
function getAlerts() {
|
|
355
|
+
return request("GET", "/settings/denial-alerts");
|
|
356
|
+
}
|
|
357
|
+
function createAlert(body) {
|
|
358
|
+
return request("POST", "/settings/denial-alerts", { body });
|
|
359
|
+
}
|
|
360
|
+
function deleteAlert(id) {
|
|
361
|
+
return request("DELETE", "/settings/denial-alerts", { query: { id } });
|
|
362
|
+
}
|
|
363
|
+
function getWebhooks() {
|
|
364
|
+
return request("GET", "/settings/denial-webhook");
|
|
365
|
+
}
|
|
366
|
+
function createWebhook(body) {
|
|
367
|
+
return request("POST", "/settings/denial-webhook", { body });
|
|
368
|
+
}
|
|
369
|
+
function deleteWebhook(id) {
|
|
370
|
+
return request("DELETE", "/settings/denial-webhook", { query: { id } });
|
|
371
|
+
}
|
|
348
372
|
|
|
349
373
|
// src/api-client/stats.ts
|
|
350
374
|
var stats_exports = {};
|
|
@@ -370,6 +394,7 @@ function securityInsights(days) {
|
|
|
370
394
|
// src/api-client/audit.ts
|
|
371
395
|
var audit_exports = {};
|
|
372
396
|
__export(audit_exports, {
|
|
397
|
+
block: () => block,
|
|
373
398
|
list: () => list2,
|
|
374
399
|
whitelist: () => whitelist
|
|
375
400
|
});
|
|
@@ -379,6 +404,9 @@ function list2(query = {}) {
|
|
|
379
404
|
function whitelist(id, scope = "exact") {
|
|
380
405
|
return request("POST", `/audit-logs/${encodeURIComponent(id)}/whitelist`, { body: { scope } });
|
|
381
406
|
}
|
|
407
|
+
function block(id, scope = "exact") {
|
|
408
|
+
return request("POST", `/audit-logs/${encodeURIComponent(id)}/block`, { body: { scope } });
|
|
409
|
+
}
|
|
382
410
|
|
|
383
411
|
// src/api-client/agents.ts
|
|
384
412
|
var agents_exports = {};
|
|
@@ -401,8 +429,34 @@ function anomalies(id, limit) {
|
|
|
401
429
|
});
|
|
402
430
|
}
|
|
403
431
|
|
|
432
|
+
// src/api-client/keys.ts
|
|
433
|
+
var keys_exports = {};
|
|
434
|
+
__export(keys_exports, {
|
|
435
|
+
create: () => create2,
|
|
436
|
+
list: () => list3,
|
|
437
|
+
revoke: () => revoke
|
|
438
|
+
});
|
|
439
|
+
function list3() {
|
|
440
|
+
return request("GET", "/keys");
|
|
441
|
+
}
|
|
442
|
+
function create2(name, isLive = true) {
|
|
443
|
+
return request("POST", "/keys", { body: { name, is_live: isLive } });
|
|
444
|
+
}
|
|
445
|
+
function revoke(id) {
|
|
446
|
+
return request("DELETE", `/keys/${encodeURIComponent(id)}`);
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
// src/api-client/mcp.ts
|
|
450
|
+
var mcp_exports = {};
|
|
451
|
+
__export(mcp_exports, {
|
|
452
|
+
list: () => list4
|
|
453
|
+
});
|
|
454
|
+
function list4() {
|
|
455
|
+
return request("GET", "/mcp-servers");
|
|
456
|
+
}
|
|
457
|
+
|
|
404
458
|
// src/api-client/index.ts
|
|
405
|
-
var api = { policies: policies_exports, settings: settings_exports, stats: stats_exports, audit: audit_exports, agents: agents_exports };
|
|
459
|
+
var api = { policies: policies_exports, settings: settings_exports, stats: stats_exports, audit: audit_exports, agents: agents_exports, keys: keys_exports, mcp: mcp_exports };
|
|
406
460
|
|
|
407
461
|
// src/tui/hooks.ts
|
|
408
462
|
import { useCallback, useEffect, useRef, useState } from "react";
|
|
@@ -475,6 +529,19 @@ function tailLines(file, maxBytes = 131072) {
|
|
|
475
529
|
return [];
|
|
476
530
|
}
|
|
477
531
|
}
|
|
532
|
+
function extractTarget(detail) {
|
|
533
|
+
try {
|
|
534
|
+
const j = JSON.parse(detail);
|
|
535
|
+
const cmd = String(j.command ?? j.cmd ?? "").trim();
|
|
536
|
+
if (cmd) return { kind: "command", value: cmd };
|
|
537
|
+
const fp = String(j.file_path ?? j.path ?? "").trim();
|
|
538
|
+
if (fp) return { kind: "path", value: fp.split(/[\\/]/).pop() || fp };
|
|
539
|
+
const url = String(j.url ?? "").trim();
|
|
540
|
+
if (url) return { kind: "url", value: url };
|
|
541
|
+
} catch {
|
|
542
|
+
}
|
|
543
|
+
return null;
|
|
544
|
+
}
|
|
478
545
|
function cloudItem(e) {
|
|
479
546
|
return {
|
|
480
547
|
id: "c:" + e.id,
|
|
@@ -484,6 +551,7 @@ function cloudItem(e) {
|
|
|
484
551
|
permission: (e.permission ?? "").slice(0, 4),
|
|
485
552
|
detail: (e.arguments_summary ? JSON.stringify(e.arguments_summary) : e.reason ?? "").replace(/\s+/g, " "),
|
|
486
553
|
dlp: !!e.dlp_matches?.length,
|
|
554
|
+
burst: !!e.rate_limit_burst,
|
|
487
555
|
source: "cloud",
|
|
488
556
|
session: e.session_id ?? void 0,
|
|
489
557
|
agent: e.agent_name ?? void 0,
|
|
@@ -539,8 +607,9 @@ function PaneTitle({ label, extra, width }) {
|
|
|
539
607
|
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: tail + "\u2500".repeat(Math.max(0, width - used)) })
|
|
540
608
|
] });
|
|
541
609
|
}
|
|
542
|
-
function StreamLine({ e, loc }) {
|
|
543
|
-
return /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
610
|
+
function StreamLine({ e, loc, selected }) {
|
|
611
|
+
return /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", backgroundColor: selected ? "#1c2f63" : void 0, children: [
|
|
612
|
+
/* @__PURE__ */ jsx2(Text2, { color: selected ? theme.accentBright : theme.dim, children: selected ? "\u25B8" : " " }),
|
|
544
613
|
/* @__PURE__ */ jsxs2(Text2, { color: theme.dim, children: [
|
|
545
614
|
"[",
|
|
546
615
|
hhmmss(e.at),
|
|
@@ -574,9 +643,14 @@ function LivePanel({ active: active2 }) {
|
|
|
574
643
|
const [ring, setRing] = useState2(null);
|
|
575
644
|
const [log, setLog] = useState2([]);
|
|
576
645
|
const [filter, setFilter] = useState2("all");
|
|
646
|
+
const [signal, setSignal] = useState2("none");
|
|
577
647
|
const [search, setSearch] = useState2("");
|
|
578
648
|
const [editingSearch, setEditingSearch] = useState2(false);
|
|
579
|
-
const [
|
|
649
|
+
const [sel, setSel] = useState2(0);
|
|
650
|
+
const [actionMsg, setActionMsg] = useState2(null);
|
|
651
|
+
const notifiedRef = useRef2(/* @__PURE__ */ new Set());
|
|
652
|
+
const notifyReady = useRef2(false);
|
|
653
|
+
const activePolicyRef = useRef2(null);
|
|
580
654
|
const [mode, setMode] = useState2("stream");
|
|
581
655
|
const [pickIdx, setPickIdx] = useState2(0);
|
|
582
656
|
const [detail, setDetail] = useState2(null);
|
|
@@ -586,6 +660,7 @@ function LivePanel({ active: active2 }) {
|
|
|
586
660
|
const lastLocalTs = useRef2(0);
|
|
587
661
|
const pausedUntil = useRef2(0);
|
|
588
662
|
const sessRef = useRef2([]);
|
|
663
|
+
const mergedRef = useRef2([]);
|
|
589
664
|
const prevStatus = useRef2(/* @__PURE__ */ new Map());
|
|
590
665
|
const [alerts, setAlerts] = useState2([]);
|
|
591
666
|
const [frozen, setFrozen] = useState2(false);
|
|
@@ -634,6 +709,7 @@ function LivePanel({ active: active2 }) {
|
|
|
634
709
|
permission: (j.permission ?? "").slice(0, 4),
|
|
635
710
|
detail: (j.arguments ? JSON.stringify(j.arguments) : j.reason ?? "").replace(/\s+/g, " "),
|
|
636
711
|
dlp: !!j.dlp,
|
|
712
|
+
burst: !!j.rate_limit_burst,
|
|
637
713
|
source: "local",
|
|
638
714
|
session: j.session_id,
|
|
639
715
|
agent: j.agent_name,
|
|
@@ -748,30 +824,52 @@ function LivePanel({ active: active2 }) {
|
|
|
748
824
|
return () => clearInterval(t);
|
|
749
825
|
}, [active2, frozen]);
|
|
750
826
|
const startRef = useRef2(Date.now());
|
|
827
|
+
const fireAlert = useCallback2(
|
|
828
|
+
(id, title, msg, level = "warn") => {
|
|
829
|
+
pushLog(`${level === "bad" ? "\u26D4" : "\u23F8"} ${msg}`, level);
|
|
830
|
+
setAlerts((a) => [...a.filter((x) => x.id !== id), { id, msg, level, until: Date.now() + 15e3 }].slice(-4));
|
|
831
|
+
try {
|
|
832
|
+
process.stdout.write("\x07");
|
|
833
|
+
} catch {
|
|
834
|
+
}
|
|
835
|
+
try {
|
|
836
|
+
const child = spawn("notify-send", ["-a", "SolonGate", title, msg], { stdio: "ignore", detached: true });
|
|
837
|
+
child.on("error", () => {
|
|
838
|
+
});
|
|
839
|
+
child.unref();
|
|
840
|
+
} catch {
|
|
841
|
+
}
|
|
842
|
+
},
|
|
843
|
+
[pushLog]
|
|
844
|
+
);
|
|
751
845
|
useEffect2(() => {
|
|
752
846
|
if (!active2) return;
|
|
753
847
|
for (const r of sessRef.current) {
|
|
754
848
|
const prev = prevStatus.current.get(r.id);
|
|
755
849
|
if (prev && prev === "active" && r.status === "idle") {
|
|
756
850
|
const name = r.isMe ? `${r.agent} (this machine)` : r.agent;
|
|
757
|
-
|
|
758
|
-
pushLog(`\u23F8 ${msg}`, "warn");
|
|
759
|
-
setAlerts((a) => [...a.filter((x) => x.id !== r.id), { id: r.id, msg, until: Date.now() + 15e3 }].slice(-4));
|
|
760
|
-
try {
|
|
761
|
-
process.stdout.write("\x07");
|
|
762
|
-
} catch {
|
|
763
|
-
}
|
|
764
|
-
try {
|
|
765
|
-
const child = spawn("notify-send", ["-a", "SolonGate", "Agent idle", msg], { stdio: "ignore", detached: true });
|
|
766
|
-
child.on("error", () => {
|
|
767
|
-
});
|
|
768
|
-
child.unref();
|
|
769
|
-
} catch {
|
|
770
|
-
}
|
|
851
|
+
fireAlert("idle:" + r.id, "Agent idle", `${name} went IDLE, no tool call for 60s`, "warn");
|
|
771
852
|
}
|
|
772
853
|
prevStatus.current.set(r.id, r.status);
|
|
773
854
|
}
|
|
774
|
-
}, [tick, active2,
|
|
855
|
+
}, [tick, active2, fireAlert]);
|
|
856
|
+
useEffect2(() => {
|
|
857
|
+
if (!active2) return;
|
|
858
|
+
const notable = mergedRef.current.filter((e) => e.decision !== "ALLOW" || e.dlp || e.burst);
|
|
859
|
+
if (!notifyReady.current) {
|
|
860
|
+
for (const e of notable) notifiedRef.current.add(e.id);
|
|
861
|
+
notifyReady.current = true;
|
|
862
|
+
return;
|
|
863
|
+
}
|
|
864
|
+
for (const e of notable) {
|
|
865
|
+
if (notifiedRef.current.has(e.id)) continue;
|
|
866
|
+
notifiedRef.current.add(e.id);
|
|
867
|
+
const who = e.agent ? ` \xB7 ${truncate(e.agent, 20)}` : "";
|
|
868
|
+
if (e.dlp) fireAlert("sec:" + e.id, "DLP hit", `SECRET in ${e.tool}${who}: ${truncate(e.detail, 60)}`, "bad");
|
|
869
|
+
else if (e.decision !== "ALLOW") fireAlert("sec:" + e.id, "Call denied", `DENY ${e.tool}${who}: ${truncate(e.rule ?? e.detail, 60)}`, "bad");
|
|
870
|
+
else if (e.burst) fireAlert("sec:" + e.id, "Rate-limit burst", `BURST ${e.tool}${who}`, "warn");
|
|
871
|
+
}
|
|
872
|
+
}, [tick, active2, fireAlert]);
|
|
775
873
|
const cols = process.stdout.columns ?? 100;
|
|
776
874
|
const rows = process.stdout.rows ?? 30;
|
|
777
875
|
const ins = insights.data ?? {};
|
|
@@ -784,6 +882,7 @@ function LivePanel({ active: active2 }) {
|
|
|
784
882
|
}
|
|
785
883
|
const cloudDeduped = cloudBuf.filter((e) => !localKeys.has(`${e.tool}|${e.decision}|${Math.round(e.at / 6e4)}`));
|
|
786
884
|
const mergedAll = [...cloudDeduped, ...localBuf].sort((a, b) => a.at - b.at);
|
|
885
|
+
mergedRef.current = mergedAll;
|
|
787
886
|
const nowSlot = Math.floor(nowMs / 1e4);
|
|
788
887
|
const traffic = new Array(60).fill(0);
|
|
789
888
|
const trafficHot = new Array(60).fill(false);
|
|
@@ -843,7 +942,8 @@ function LivePanel({ active: active2 }) {
|
|
|
843
942
|
const isLoc = (e) => e.source === "local" || !!e.session && localSessIds.has(e.session);
|
|
844
943
|
const q = search.trim().toLowerCase();
|
|
845
944
|
const matches = (e) => !q || `${e.tool} ${e.agent ?? ""} ${e.decision} ${e.permission} ${e.rule ?? ""} ${e.detail}`.toLowerCase().includes(q);
|
|
846
|
-
const
|
|
945
|
+
const signalOk = (e) => signal === "none" ? true : signal === "deny" ? e.decision !== "ALLOW" : signal === "dlp" ? e.dlp : e.burst;
|
|
946
|
+
const filtered = (filter === "all" ? mergedAll : mergedAll.filter((e) => filter === "local" ? isLoc(e) : !isLoc(e))).filter(matches).filter(signalOk);
|
|
847
947
|
const visibleDesc = filtered.slice().reverse();
|
|
848
948
|
const chartH = rows >= 36 ? 6 : 4;
|
|
849
949
|
const colH = rows >= 32 ? 7 : 5;
|
|
@@ -854,9 +954,11 @@ function LivePanel({ active: active2 }) {
|
|
|
854
954
|
const colW = Math.max(20, Math.floor((innerW - 4) / 3));
|
|
855
955
|
const pickable = combinedSess.slice(0, colH - 1);
|
|
856
956
|
const streamBodyRows = Math.max(3, streamRows - 1);
|
|
957
|
+
const selClamped = Math.min(Math.max(0, sel), Math.max(0, visibleDesc.length - 1));
|
|
857
958
|
const maxScroll = Math.max(0, visibleDesc.length - streamBodyRows);
|
|
858
|
-
const clampedScroll = Math.min(
|
|
959
|
+
const clampedScroll = Math.min(Math.max(0, selClamped - Math.floor((streamBodyRows - 1) / 2)), maxScroll);
|
|
859
960
|
const windowed = visibleDesc.slice(clampedScroll, clampedScroll + streamBodyRows);
|
|
961
|
+
const selEntry = visibleDesc[selClamped];
|
|
860
962
|
const detailEntries = detail ? (() => {
|
|
861
963
|
const seen = /* @__PURE__ */ new Set();
|
|
862
964
|
const all = [];
|
|
@@ -868,6 +970,42 @@ function LivePanel({ active: active2 }) {
|
|
|
868
970
|
}
|
|
869
971
|
return all.sort((a, b) => b.at - a.at);
|
|
870
972
|
})() : [];
|
|
973
|
+
const doAction = async (act) => {
|
|
974
|
+
const e = selEntry;
|
|
975
|
+
if (!e) return;
|
|
976
|
+
const ok = act === "whitelist" ? e.decision !== "ALLOW" : e.decision === "ALLOW";
|
|
977
|
+
if (!ok) {
|
|
978
|
+
setActionMsg({ text: act === "whitelist" ? "select a DENY to whitelist (w)" : "select an ALLOW to block (b)", level: "bad", until: Date.now() + 4e3 });
|
|
979
|
+
return;
|
|
980
|
+
}
|
|
981
|
+
setActionMsg({ text: act === "whitelist" ? "whitelisting\u2026" : "blocking\u2026", level: "ok", until: Date.now() + 4e3 });
|
|
982
|
+
try {
|
|
983
|
+
let res;
|
|
984
|
+
if (e.source === "cloud") {
|
|
985
|
+
const realId = e.id.slice(2);
|
|
986
|
+
res = act === "whitelist" ? await api.audit.whitelist(realId) : await api.audit.block(realId);
|
|
987
|
+
} else {
|
|
988
|
+
let pid = activePolicyRef.current;
|
|
989
|
+
if (!pid) {
|
|
990
|
+
const a = await api.policies.active();
|
|
991
|
+
pid = a.policy?.id ?? null;
|
|
992
|
+
activePolicyRef.current = pid;
|
|
993
|
+
}
|
|
994
|
+
if (!pid) throw new Error("no active policy resolves for this machine");
|
|
995
|
+
const t = extractTarget(e.detail);
|
|
996
|
+
res = await api.policies.addRule(pid, { toolPattern: e.tool, kind: t?.kind ?? "tool", value: t?.value, effect: act === "whitelist" ? "ALLOW" : "DENY" });
|
|
997
|
+
}
|
|
998
|
+
const verb = act === "whitelist" ? "ALLOW" : "DENY";
|
|
999
|
+
setActionMsg({
|
|
1000
|
+
text: res.deduped ? `${verb} rule already present` : `${verb} rule added \u2192 ${res.policy_id ?? "?"}${res.policy_version ? " v" + res.policy_version : ""} \xB7 reaches agents in ~30s`,
|
|
1001
|
+
level: "ok",
|
|
1002
|
+
until: Date.now() + 7e3
|
|
1003
|
+
});
|
|
1004
|
+
pushLog(`${act === "whitelist" ? "\u2713 whitelisted" : "\u26D4 blocked"} ${e.tool}`, act === "whitelist" ? "ok" : "warn");
|
|
1005
|
+
} catch (err) {
|
|
1006
|
+
setActionMsg({ text: "\u2717 " + (err instanceof Error ? err.message : String(err)), level: "bad", until: Date.now() + 7e3 });
|
|
1007
|
+
}
|
|
1008
|
+
};
|
|
871
1009
|
useInput(
|
|
872
1010
|
(input, key) => {
|
|
873
1011
|
if (input === " ") {
|
|
@@ -902,16 +1040,25 @@ function LivePanel({ active: active2 }) {
|
|
|
902
1040
|
} else if (input === "s" || key.leftArrow) setMode("stream");
|
|
903
1041
|
return;
|
|
904
1042
|
}
|
|
1043
|
+
const toggleSignal = (s2) => {
|
|
1044
|
+
setSignal((cur) => cur === s2 ? "none" : s2);
|
|
1045
|
+
setSel(0);
|
|
1046
|
+
};
|
|
905
1047
|
if (input === "f") {
|
|
906
1048
|
setFilter((f) => FILTERS[(FILTERS.indexOf(f) + 1) % FILTERS.length]);
|
|
907
|
-
|
|
1049
|
+
setSel(0);
|
|
908
1050
|
} else if (input === "s") {
|
|
909
1051
|
setPickIdx(0);
|
|
910
1052
|
setMode("pick");
|
|
911
|
-
} else if (
|
|
912
|
-
else if (
|
|
913
|
-
else if (
|
|
914
|
-
else if (
|
|
1053
|
+
} else if (input === "w") void doAction("whitelist");
|
|
1054
|
+
else if (input === "b") void doAction("block");
|
|
1055
|
+
else if (input === "d") toggleSignal("deny");
|
|
1056
|
+
else if (input === "x") toggleSignal("dlp");
|
|
1057
|
+
else if (input === "r") toggleSignal("ratelimit");
|
|
1058
|
+
else if (key.downArrow) setSel((n) => Math.min(visibleDesc.length - 1, n + 1));
|
|
1059
|
+
else if (key.upArrow) setSel((n) => Math.max(0, n - 1));
|
|
1060
|
+
else if (key.pageDown) setSel((n) => Math.min(visibleDesc.length - 1, n + streamBodyRows));
|
|
1061
|
+
else if (key.pageUp) setSel((n) => Math.max(0, n - streamBodyRows));
|
|
915
1062
|
},
|
|
916
1063
|
{ isActive: active2 && !editingSearch }
|
|
917
1064
|
);
|
|
@@ -928,7 +1075,7 @@ function LivePanel({ active: active2 }) {
|
|
|
928
1075
|
return;
|
|
929
1076
|
}
|
|
930
1077
|
setSearch(v);
|
|
931
|
-
|
|
1078
|
+
setSel(0);
|
|
932
1079
|
setDetailScroll(0);
|
|
933
1080
|
},
|
|
934
1081
|
onSubmit: () => setEditingSearch(false)
|
|
@@ -1048,7 +1195,18 @@ function LivePanel({ active: active2 }) {
|
|
|
1048
1195
|
/* @__PURE__ */ jsx2(Text2, { color: guard.data?.up_to_date ? theme.ok : theme.warn, children: guard.data ? `v${guard.data.installed ?? "?"}${guard.data.up_to_date ? "" : "\u2192v" + guard.data.latest} ${guard.data.device_count}dev` : "\xB7" }),
|
|
1049
1196
|
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502" })
|
|
1050
1197
|
] }),
|
|
1051
|
-
alerts.filter((a) => nowMs < a.until).slice(-1).map((a) => /* @__PURE__ */ jsx2(
|
|
1198
|
+
alerts.filter((a) => nowMs < a.until).slice(-1).map((a) => /* @__PURE__ */ jsx2(
|
|
1199
|
+
Text2,
|
|
1200
|
+
{
|
|
1201
|
+
wrap: "truncate",
|
|
1202
|
+
backgroundColor: a.level === "bad" ? "#3d1220" : "#3d2a12",
|
|
1203
|
+
color: a.level === "bad" ? "#ff6b6b" : "#ffb454",
|
|
1204
|
+
bold: true,
|
|
1205
|
+
children: ` ${a.level === "bad" ? "\u26D4 ALERT" : "\u23F8 IDLE"} \xB7 ${truncate(a.msg, innerW - 14)} `
|
|
1206
|
+
},
|
|
1207
|
+
a.id
|
|
1208
|
+
)),
|
|
1209
|
+
actionMsg && nowMs < actionMsg.until ? /* @__PURE__ */ jsx2(Text2, { wrap: "truncate", backgroundColor: actionMsg.level === "bad" ? "#3d1220" : "#123d1f", color: actionMsg.level === "bad" ? "#ff6b6b" : "#7bd88f", bold: true, children: ` ${truncate(actionMsg.text, innerW - 4)} ` }) : null,
|
|
1052
1210
|
/* @__PURE__ */ jsxs2(Box2, { height: 1 + chartH, children: [
|
|
1053
1211
|
/* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", width: leftW, marginRight: 2, children: [
|
|
1054
1212
|
/* @__PURE__ */ jsx2(PaneTitle, { label: "TRAFFIC", extra: `${trafficLabel} \xB7 peak ${Math.max(0, ...traffic)} \xB7 red = denials`, width: leftW }),
|
|
@@ -1086,11 +1244,11 @@ function LivePanel({ active: active2 }) {
|
|
|
1086
1244
|
/* @__PURE__ */ jsx2(PaneTitle, { label: "SESSIONS", extra: mode === "pick" ? "\u2191\u2193 pick \xB7 enter open" : `${combinedSess.length} \xB7 s = inspect`, width: colW }),
|
|
1087
1245
|
pickable.length === 0 ? /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "scanning\u2026" }) : null,
|
|
1088
1246
|
pickable.map((r, i) => {
|
|
1089
|
-
const
|
|
1247
|
+
const sel2 = mode === "pick" && i === pickIdx;
|
|
1090
1248
|
const st = STATUS_STYLE[r.status];
|
|
1091
|
-
return /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", backgroundColor:
|
|
1092
|
-
/* @__PURE__ */ jsxs2(Text2, { color:
|
|
1093
|
-
|
|
1249
|
+
return /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", backgroundColor: sel2 ? "#1c2f63" : void 0, bold: sel2 || r.isMe, children: [
|
|
1250
|
+
/* @__PURE__ */ jsxs2(Text2, { color: sel2 ? theme.accentBright : st.color, children: [
|
|
1251
|
+
sel2 ? "\u25B8" : st.dot,
|
|
1094
1252
|
" "
|
|
1095
1253
|
] }),
|
|
1096
1254
|
/* @__PURE__ */ jsx2(Text2, { color: st.color, children: st.label.padEnd(7) }),
|
|
@@ -1123,7 +1281,7 @@ function LivePanel({ active: active2 }) {
|
|
|
1123
1281
|
PaneTitle,
|
|
1124
1282
|
{
|
|
1125
1283
|
label: "TOOL STREAM",
|
|
1126
|
-
extra: `${visibleDesc.length}
|
|
1284
|
+
extra: `${selClamped + 1}/${visibleDesc.length}${signal !== "none" ? ` \xB7 ${signal}` : ""}${q ? " \xB7 search" : ""} \xB7 \u2191\u2193 select \xB7 w allow \xB7 b block \xB7 d/x/r ${filter} \xB7 s`,
|
|
1127
1285
|
width: innerW
|
|
1128
1286
|
}
|
|
1129
1287
|
),
|
|
@@ -1137,12 +1295,12 @@ function LivePanel({ active: active2 }) {
|
|
|
1137
1295
|
spin,
|
|
1138
1296
|
" awaiting traffic\u2026"
|
|
1139
1297
|
] }) : null,
|
|
1140
|
-
windowed.map((e) => /* @__PURE__ */ jsx2(StreamLine, { e, loc: isLoc(e) }, e.id))
|
|
1298
|
+
windowed.map((e, i) => /* @__PURE__ */ jsx2(StreamLine, { e, loc: isLoc(e), selected: clampedScroll + i === selClamped }, e.id))
|
|
1141
1299
|
] }),
|
|
1142
1300
|
/* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
1143
1301
|
/* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", bold: true, children: " LIVE " }),
|
|
1144
1302
|
/* @__PURE__ */ jsx2(Text2, { backgroundColor: "#0b1530", color: "#4f6db8", children: ` local ${localOn ? "on" : "off"} \xB7 ${localBuf.length} loc/${cloudBuf.length} cld \xB7 top ${topTools.map(([t, c2]) => `${t}\xD7${c2}`).join(" ") || "\u2014"} ` }),
|
|
1145
|
-
/* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", children: "
|
|
1303
|
+
/* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", children: " \u2191\u2193 select \xB7 w allow \xB7 b block \xB7 d/x/r \xB7 / search \xB7 f \xB7 s \xB7 space copy \xB7 esc \xB7 q " })
|
|
1146
1304
|
] })
|
|
1147
1305
|
] });
|
|
1148
1306
|
}
|
|
@@ -1183,8 +1341,8 @@ function ruleSummary(r) {
|
|
|
1183
1341
|
return bits.join(" ");
|
|
1184
1342
|
}
|
|
1185
1343
|
function PoliciesPanel({ focused }) {
|
|
1186
|
-
const
|
|
1187
|
-
const policies =
|
|
1344
|
+
const list5 = useLoader(() => api.policies.list());
|
|
1345
|
+
const policies = list5.data?.policies ?? [];
|
|
1188
1346
|
const [view, setView] = useState3("list");
|
|
1189
1347
|
const [pi, setPi] = useState3(0);
|
|
1190
1348
|
const [ri, setRi] = useState3(0);
|
|
@@ -1226,7 +1384,7 @@ function PoliciesPanel({ focused }) {
|
|
|
1226
1384
|
setRules(res.rules);
|
|
1227
1385
|
setDirty(false);
|
|
1228
1386
|
setStatus("\u2713 Saved v" + res._version);
|
|
1229
|
-
|
|
1387
|
+
list5.reload();
|
|
1230
1388
|
} catch (e) {
|
|
1231
1389
|
setStatus("\u2717 " + (e instanceof Error ? e.message : String(e)));
|
|
1232
1390
|
}
|
|
@@ -1296,7 +1454,7 @@ function PoliciesPanel({ focused }) {
|
|
|
1296
1454
|
{ isActive: focused && !editing }
|
|
1297
1455
|
);
|
|
1298
1456
|
if (view === "list") {
|
|
1299
|
-
return /* @__PURE__ */ jsx3(DataView, { loading:
|
|
1457
|
+
return /* @__PURE__ */ jsx3(DataView, { loading: list5.loading && !list5.data, error: list5.error, empty: !!list5.data && policies.length === 0, emptyText: "No policies.", children: /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", children: [
|
|
1300
1458
|
/* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: focused ? "\u2191\u2193 select \xB7 enter open" : "press \u2192 to browse" }),
|
|
1301
1459
|
/* @__PURE__ */ jsx3(Box3, { marginTop: 1, flexDirection: "column", children: policies.map((p, i) => /* @__PURE__ */ jsxs3(Text3, { color: i === pi ? theme.accentBright : void 0, bold: i === pi, children: [
|
|
1302
1460
|
(i === pi ? "\u25B8 " : " ") + truncate(p.name, 26).padEnd(27),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@solongate/proxy",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.79.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": {
|