@solongate/proxy 0.64.0 → 0.65.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/index.js +90 -61
- package/dist/tui/index.js +88 -59
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -7051,20 +7051,31 @@ function HBar({ label, value, max, width: width2, color }) {
|
|
|
7051
7051
|
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "\u2591".repeat(Math.max(0, width2 - filled)) + " " + value })
|
|
7052
7052
|
] });
|
|
7053
7053
|
}
|
|
7054
|
-
function
|
|
7055
|
-
const
|
|
7056
|
-
|
|
7054
|
+
function PaneTitle({ label, extra, width: width2 }) {
|
|
7055
|
+
const head = `\u2500 `;
|
|
7056
|
+
const tail = extra ? ` ${extra} ` : " ";
|
|
7057
|
+
const used = head.length + 1 + label.length + tail.length;
|
|
7058
|
+
return /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
7059
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: head }),
|
|
7060
|
+
/* @__PURE__ */ jsxs2(Text2, { color: theme.accentBright, bold: true, children: [
|
|
7061
|
+
"\u258E",
|
|
7062
|
+
label
|
|
7063
|
+
] }),
|
|
7064
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: tail + "\u2500".repeat(Math.max(0, width2 - used)) })
|
|
7065
|
+
] });
|
|
7057
7066
|
}
|
|
7058
7067
|
function LivePanel({ active: active2 }) {
|
|
7059
7068
|
const stats = useLoader(() => api.stats.get());
|
|
7060
7069
|
const ts = useLoader(() => api.stats.timeseries({ period: "24h" }));
|
|
7061
7070
|
const feed = useLoader(() => api.audit.list({ limit: 50 }));
|
|
7062
7071
|
const insights = useLoader(() => api.stats.securityInsights(7));
|
|
7072
|
+
const sessions = useLoader(() => api.agents.live({ limit: 30, includeDeactivated: true }));
|
|
7063
7073
|
usePoll(() => {
|
|
7064
7074
|
stats.reload();
|
|
7065
7075
|
ts.reload();
|
|
7066
7076
|
feed.reload();
|
|
7067
7077
|
}, 2e3, active2);
|
|
7078
|
+
usePoll(sessions.reload, 5e3, active2);
|
|
7068
7079
|
usePoll(insights.reload, 1e4, active2);
|
|
7069
7080
|
const [tick, setTick] = useState2(0);
|
|
7070
7081
|
useEffect2(() => {
|
|
@@ -7090,89 +7101,108 @@ function LivePanel({ active: active2 }) {
|
|
|
7090
7101
|
const minuteRaw = (ins.activity?.minute ?? []).map((b) => b.count);
|
|
7091
7102
|
const hourRaw = (ins.activity?.hour ?? []).map((b) => b.count);
|
|
7092
7103
|
const minuteLive = minuteRaw.some((c2) => c2 > 0);
|
|
7093
|
-
const
|
|
7094
|
-
const
|
|
7104
|
+
const rateSeries = minuteLive ? minuteRaw : hourRaw;
|
|
7105
|
+
const rateLabel = minuteLive ? "calls/min \xB7 60m" : "calls/hour \xB7 24h";
|
|
7095
7106
|
const limit = minuteLive ? ins.layers?.rateLimit?.perMinute ?? 0 : 0;
|
|
7107
|
+
const rlMode = ins.layers?.rateLimit?.mode ?? "?";
|
|
7108
|
+
const dlpMode = ins.layers?.dlp?.mode ?? "?";
|
|
7096
7109
|
const denySeries = (ts.data?.timeseries ?? []).map((p) => p.denied);
|
|
7097
7110
|
const spin = SPIN[tick % SPIN.length];
|
|
7098
|
-
const cursor = tick % 4 < 2 ? "\u258C" : " ";
|
|
7099
7111
|
const toolCounts = /* @__PURE__ */ new Map();
|
|
7100
|
-
|
|
7112
|
+
let dlpBufHits = 0;
|
|
7101
7113
|
for (const e of buffer) {
|
|
7102
7114
|
toolCounts.set(e.tool_name, (toolCounts.get(e.tool_name) ?? 0) + 1);
|
|
7103
|
-
|
|
7104
|
-
|
|
7105
|
-
|
|
7106
|
-
const
|
|
7107
|
-
const
|
|
7108
|
-
const
|
|
7109
|
-
const maxPerm = Math.max(1, ...perms.map(([, c2]) => c2));
|
|
7110
|
-
const dlpTop = (ins.dlpByPattern ?? []).slice(0, 2);
|
|
7115
|
+
if (e.dlp_matches?.length) dlpBufHits++;
|
|
7116
|
+
}
|
|
7117
|
+
const topTools = [...toolCounts.entries()].sort((a, b) => b[1] - a[1]).slice(0, 3);
|
|
7118
|
+
const dlpBars = (ins.dlpByPattern ?? []).slice(0, 3);
|
|
7119
|
+
const maxDlp = dlpBars[0]?.count ?? 1;
|
|
7120
|
+
const dlpRecent = (ins.dlpHits ?? []).slice(0, 2);
|
|
7111
7121
|
const denials = buffer.filter((e) => e.decision !== "ALLOW");
|
|
7112
7122
|
const lastDeny = denials[denials.length - 1];
|
|
7113
|
-
const bursts = limit > 0 ?
|
|
7114
|
-
const
|
|
7115
|
-
const
|
|
7116
|
-
const
|
|
7123
|
+
const bursts = limit > 0 ? rateSeries.filter((c2) => c2 > limit).length : 0;
|
|
7124
|
+
const sess = (sessions.data?.agents ?? []).slice().sort((a, b) => Date.parse(b.last_seen_at) - Date.parse(a.last_seen_at));
|
|
7125
|
+
const sessCounts = sessions.data?.counts;
|
|
7126
|
+
const chartH = rows >= 36 ? 6 : 4;
|
|
7127
|
+
const colH = rows >= 32 ? 6 : 5;
|
|
7128
|
+
const streamRows = Math.max(4, rows - 6 - chartH - colH);
|
|
7117
7129
|
const tail = buffer.slice(-streamRows);
|
|
7118
|
-
const colW = Math.max(
|
|
7130
|
+
const colW = Math.max(20, Math.floor((cols - 6) / 3));
|
|
7131
|
+
const innerW = cols - 2;
|
|
7119
7132
|
if (stats.error) return /* @__PURE__ */ jsxs2(Text2, { color: theme.bad, children: [
|
|
7120
7133
|
"\u2717 ",
|
|
7121
7134
|
stats.error
|
|
7122
7135
|
] });
|
|
7136
|
+
const sessionDot = (st) => st === "active" ? { ch: "\u25CF", color: theme.ok } : st === "idle" ? { ch: "\u25D0", color: theme.warn } : { ch: "\u25CB", color: theme.dim };
|
|
7123
7137
|
return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", paddingX: 1, children: [
|
|
7124
7138
|
/* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
7125
|
-
/* @__PURE__ */ jsx2(Text2, { backgroundColor: "#1432A0", color: "#AAC8FA", bold: true, children: " SOLONGATE
|
|
7126
|
-
/* @__PURE__ */
|
|
7127
|
-
|
|
7128
|
-
spin,
|
|
7129
|
-
" up ",
|
|
7130
|
-
fmtUp(Date.now() - startRef.current),
|
|
7131
|
-
" \xB7 ",
|
|
7132
|
-
hhmmss(Date.now()),
|
|
7133
|
-
" \xB7 poll 2s"
|
|
7134
|
-
] }),
|
|
7135
|
-
lastDeny ? /* @__PURE__ */ jsxs2(Text2, { color: theme.bad, children: [
|
|
7136
|
-
" \u26A0 ",
|
|
7137
|
-
hhmmss(lastDeny.created_at),
|
|
7138
|
-
" ",
|
|
7139
|
-
lastDeny.tool_name,
|
|
7140
|
-
" denied"
|
|
7141
|
-
] }) : null,
|
|
7142
|
-
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " esc menu \xB7 q quit" })
|
|
7139
|
+
/* @__PURE__ */ jsx2(Text2, { backgroundColor: "#1432A0", color: "#AAC8FA", bold: true, children: " \u26E8 SOLONGATE LIVE " }),
|
|
7140
|
+
/* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", children: ` ${spin} up ${fmtUp(Date.now() - startRef.current)} \xB7 ${hhmmss(Date.now())} ` }),
|
|
7141
|
+
lastDeny ? /* @__PURE__ */ jsx2(Text2, { backgroundColor: "#3d1220", color: "#ff6b6b", bold: true, children: ` \u26A0 ${hhmmss(lastDeny.created_at)} ${lastDeny.tool_name} DENIED ` }) : /* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#4f6db8", children: " \u2713 no recent denials " })
|
|
7143
7142
|
] }),
|
|
7144
7143
|
/* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
7145
|
-
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "calls " }),
|
|
7144
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "\u2502 calls " }),
|
|
7146
7145
|
/* @__PURE__ */ jsx2(Text2, { bold: true, children: s ? s.total_calls : "\xB7\xB7\xB7\xB7" }),
|
|
7147
|
-
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "
|
|
7146
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502 allow " }),
|
|
7148
7147
|
/* @__PURE__ */ jsx2(Text2, { color: theme.ok, children: s ? s.allowed : "\xB7\xB7\xB7" }),
|
|
7149
|
-
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "
|
|
7148
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502 deny " }),
|
|
7150
7149
|
/* @__PURE__ */ jsx2(Text2, { color: theme.bad, bold: true, children: s ? s.denied : "\xB7\xB7" }),
|
|
7151
|
-
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "
|
|
7150
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502 dlp(buf) " }),
|
|
7151
|
+
/* @__PURE__ */ jsx2(Text2, { color: dlpBufHits ? theme.bad : theme.dim, children: dlpBufHits }),
|
|
7152
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502 bursts " }),
|
|
7152
7153
|
/* @__PURE__ */ jsx2(Text2, { color: bursts ? theme.bad : theme.dim, children: bursts }),
|
|
7153
|
-
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "
|
|
7154
|
-
/* @__PURE__ */ jsx2(Text2, { color: theme.accent, children:
|
|
7155
|
-
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "
|
|
7156
|
-
/* @__PURE__ */ jsx2(Text2, { color: theme.accent, children: s ? s.active_policies : "\xB7" })
|
|
7154
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502 sessions " }),
|
|
7155
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.accent, children: sessCounts ? `${sessCounts.active}\u25B2 ${sessCounts.idle}\u25CC` : "\xB7" }),
|
|
7156
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502 policies " }),
|
|
7157
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.accent, children: s ? s.active_policies : "\xB7" }),
|
|
7158
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502" })
|
|
7157
7159
|
] }),
|
|
7158
|
-
/* @__PURE__ */ jsx2(
|
|
7159
|
-
|
|
7160
|
+
/* @__PURE__ */ jsx2(PaneTitle, { label: "RATE LIMIT", extra: `${rateLabel} \xB7 peak ${Math.max(0, ...rateSeries)} \xB7 limit ${limit || "off"} \xB7 mode ${rlMode}${limit ? " \xB7 red = over" : ""}`, width: innerW }),
|
|
7161
|
+
rateSeries.length ? /* @__PURE__ */ jsx2(ColumnChart, { series: rateSeries, height: chartH, width: innerW, color: theme.accent, limit }) : /* @__PURE__ */ jsx2(Box2, { height: chartH, children: /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: insights.loading ? `${spin} loading activity\u2026` : "no activity data" }) }),
|
|
7160
7162
|
/* @__PURE__ */ jsxs2(Box2, { children: [
|
|
7161
7163
|
/* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", width: colW, marginRight: 2, children: [
|
|
7162
|
-
/* @__PURE__ */ jsx2(
|
|
7164
|
+
/* @__PURE__ */ jsx2(PaneTitle, { label: "DENIALS", extra: "24h", width: colW }),
|
|
7163
7165
|
/* @__PURE__ */ jsx2(ColumnChart, { series: denySeries, height: colH - 1, width: colW, color: theme.bad })
|
|
7164
7166
|
] }),
|
|
7165
7167
|
/* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", width: colW, marginRight: 2, children: [
|
|
7166
|
-
/* @__PURE__ */ jsx2(
|
|
7167
|
-
|
|
7168
|
+
/* @__PURE__ */ jsx2(PaneTitle, { label: "DLP", extra: `7d \xB7 mode ${dlpMode}`, width: colW }),
|
|
7169
|
+
dlpBars.length ? dlpBars.map((d) => /* @__PURE__ */ jsx2(HBar, { label: truncate2(d.pattern, 9), value: d.count, max: maxDlp, width: Math.max(6, colW - 16), color: theme.bad }, d.pattern)) : /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "no dlp hits" }),
|
|
7170
|
+
dlpRecent.map((h, i) => /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
7171
|
+
/* @__PURE__ */ jsx2(Text2, { color: h.blocked ? theme.accent : theme.bad, children: h.blocked ? "\u2298" : "\u26A0" }),
|
|
7172
|
+
/* @__PURE__ */ jsxs2(Text2, { color: theme.dim, children: [
|
|
7173
|
+
" ",
|
|
7174
|
+
truncate2(h.pattern, colW - 14),
|
|
7175
|
+
" ",
|
|
7176
|
+
ago(h.at),
|
|
7177
|
+
" ago"
|
|
7178
|
+
] })
|
|
7179
|
+
] }, i))
|
|
7168
7180
|
] }),
|
|
7169
7181
|
/* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", width: colW, children: [
|
|
7170
|
-
/* @__PURE__ */ jsx2(
|
|
7171
|
-
|
|
7172
|
-
|
|
7182
|
+
/* @__PURE__ */ jsx2(PaneTitle, { label: "SESSIONS", extra: sessCounts ? `${sessCounts.active} active` : "", width: colW }),
|
|
7183
|
+
sess.length === 0 ? /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "no sessions" }) : null,
|
|
7184
|
+
sess.slice(0, colH - 1).map((a) => {
|
|
7185
|
+
const dot = sessionDot(a.status);
|
|
7186
|
+
return /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
7187
|
+
/* @__PURE__ */ jsxs2(Text2, { color: dot.color, children: [
|
|
7188
|
+
dot.ch,
|
|
7189
|
+
" "
|
|
7190
|
+
] }),
|
|
7191
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.accent, children: truncate2(a.agent_name ?? a.session_id, 12).padEnd(13) }),
|
|
7192
|
+
/* @__PURE__ */ jsxs2(Text2, { children: [
|
|
7193
|
+
String(a.total_calls).padStart(4),
|
|
7194
|
+
"c "
|
|
7195
|
+
] }),
|
|
7196
|
+
/* @__PURE__ */ jsxs2(Text2, { color: a.denied_calls ? theme.bad : theme.dim, children: [
|
|
7197
|
+
String(a.denied_calls).padStart(3),
|
|
7198
|
+
"d "
|
|
7199
|
+
] }),
|
|
7200
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: ago(a.last_seen_at) })
|
|
7201
|
+
] }, a.session_id);
|
|
7202
|
+
})
|
|
7173
7203
|
] })
|
|
7174
7204
|
] }),
|
|
7175
|
-
/* @__PURE__ */ jsx2(
|
|
7205
|
+
/* @__PURE__ */ jsx2(PaneTitle, { label: "TOOL STREAM", extra: `live tail \xB7 ${buffer.length} buffered`, width: innerW }),
|
|
7176
7206
|
tail.length === 0 ? /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "awaiting traffic\u2026" }) : null,
|
|
7177
7207
|
tail.map((e) => /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
7178
7208
|
/* @__PURE__ */ jsxs2(Text2, { color: theme.dim, children: [
|
|
@@ -7187,15 +7217,13 @@ function LivePanel({ active: active2 }) {
|
|
|
7187
7217
|
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: (e.arguments_summary ? JSON.stringify(e.arguments_summary) : e.reason ?? "").replace(/\s+/g, " ") })
|
|
7188
7218
|
] }, e.id)),
|
|
7189
7219
|
/* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
7190
|
-
/* @__PURE__ */ jsx2(Text2, { color:
|
|
7191
|
-
/* @__PURE__ */ jsx2(Text2, { color:
|
|
7192
|
-
/* @__PURE__ */ jsx2(Text2, { color:
|
|
7193
|
-
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "$ " }),
|
|
7194
|
-
/* @__PURE__ */ jsx2(Text2, { color: theme.accentBright, children: cursor })
|
|
7220
|
+
/* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", bold: true, children: " \u25B2 LIVE " }),
|
|
7221
|
+
/* @__PURE__ */ jsx2(Text2, { backgroundColor: "#0b1530", color: "#4f6db8", children: ` top ${topTools.map(([t, c2]) => `${t}\xD7${c2}`).join(" ") || "\u2014"} ` }),
|
|
7222
|
+
/* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", children: " esc menu \xB7 q quit " })
|
|
7195
7223
|
] })
|
|
7196
7224
|
] });
|
|
7197
7225
|
}
|
|
7198
|
-
var SPIN, hhmmss, fmtUp;
|
|
7226
|
+
var SPIN, BG, hhmmss, fmtUp;
|
|
7199
7227
|
var init_Live = __esm({
|
|
7200
7228
|
"src/tui/panels/Live.tsx"() {
|
|
7201
7229
|
"use strict";
|
|
@@ -7203,6 +7231,7 @@ var init_Live = __esm({
|
|
|
7203
7231
|
init_hooks();
|
|
7204
7232
|
init_theme();
|
|
7205
7233
|
SPIN = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
7234
|
+
BG = "#12234f";
|
|
7206
7235
|
hhmmss = (ts) => {
|
|
7207
7236
|
const d = new Date(ts);
|
|
7208
7237
|
return Number.isNaN(d.getTime()) ? "--:--:--" : d.toTimeString().slice(0, 8);
|
package/dist/tui/index.js
CHANGED
|
@@ -432,6 +432,7 @@ function usePoll(reload, intervalMs, enabled = true) {
|
|
|
432
432
|
// src/tui/panels/Live.tsx
|
|
433
433
|
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
434
434
|
var SPIN = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
435
|
+
var BG = "#12234f";
|
|
435
436
|
var hhmmss = (ts) => {
|
|
436
437
|
const d = new Date(ts);
|
|
437
438
|
return Number.isNaN(d.getTime()) ? "--:--:--" : d.toTimeString().slice(0, 8);
|
|
@@ -470,20 +471,31 @@ function HBar({ label, value, max, width, color }) {
|
|
|
470
471
|
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "\u2591".repeat(Math.max(0, width - filled)) + " " + value })
|
|
471
472
|
] });
|
|
472
473
|
}
|
|
473
|
-
function
|
|
474
|
-
const
|
|
475
|
-
|
|
474
|
+
function PaneTitle({ label, extra, width }) {
|
|
475
|
+
const head = `\u2500 `;
|
|
476
|
+
const tail = extra ? ` ${extra} ` : " ";
|
|
477
|
+
const used = head.length + 1 + label.length + tail.length;
|
|
478
|
+
return /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
479
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: head }),
|
|
480
|
+
/* @__PURE__ */ jsxs2(Text2, { color: theme.accentBright, bold: true, children: [
|
|
481
|
+
"\u258E",
|
|
482
|
+
label
|
|
483
|
+
] }),
|
|
484
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: tail + "\u2500".repeat(Math.max(0, width - used)) })
|
|
485
|
+
] });
|
|
476
486
|
}
|
|
477
487
|
function LivePanel({ active: active2 }) {
|
|
478
488
|
const stats = useLoader(() => api.stats.get());
|
|
479
489
|
const ts = useLoader(() => api.stats.timeseries({ period: "24h" }));
|
|
480
490
|
const feed = useLoader(() => api.audit.list({ limit: 50 }));
|
|
481
491
|
const insights = useLoader(() => api.stats.securityInsights(7));
|
|
492
|
+
const sessions = useLoader(() => api.agents.live({ limit: 30, includeDeactivated: true }));
|
|
482
493
|
usePoll(() => {
|
|
483
494
|
stats.reload();
|
|
484
495
|
ts.reload();
|
|
485
496
|
feed.reload();
|
|
486
497
|
}, 2e3, active2);
|
|
498
|
+
usePoll(sessions.reload, 5e3, active2);
|
|
487
499
|
usePoll(insights.reload, 1e4, active2);
|
|
488
500
|
const [tick, setTick] = useState2(0);
|
|
489
501
|
useEffect2(() => {
|
|
@@ -509,89 +521,108 @@ function LivePanel({ active: active2 }) {
|
|
|
509
521
|
const minuteRaw = (ins.activity?.minute ?? []).map((b) => b.count);
|
|
510
522
|
const hourRaw = (ins.activity?.hour ?? []).map((b) => b.count);
|
|
511
523
|
const minuteLive = minuteRaw.some((c2) => c2 > 0);
|
|
512
|
-
const
|
|
513
|
-
const
|
|
524
|
+
const rateSeries = minuteLive ? minuteRaw : hourRaw;
|
|
525
|
+
const rateLabel = minuteLive ? "calls/min \xB7 60m" : "calls/hour \xB7 24h";
|
|
514
526
|
const limit = minuteLive ? ins.layers?.rateLimit?.perMinute ?? 0 : 0;
|
|
527
|
+
const rlMode = ins.layers?.rateLimit?.mode ?? "?";
|
|
528
|
+
const dlpMode = ins.layers?.dlp?.mode ?? "?";
|
|
515
529
|
const denySeries = (ts.data?.timeseries ?? []).map((p) => p.denied);
|
|
516
530
|
const spin = SPIN[tick % SPIN.length];
|
|
517
|
-
const cursor = tick % 4 < 2 ? "\u258C" : " ";
|
|
518
531
|
const toolCounts = /* @__PURE__ */ new Map();
|
|
519
|
-
|
|
532
|
+
let dlpBufHits = 0;
|
|
520
533
|
for (const e of buffer) {
|
|
521
534
|
toolCounts.set(e.tool_name, (toolCounts.get(e.tool_name) ?? 0) + 1);
|
|
522
|
-
|
|
523
|
-
permCounts.set(perm, (permCounts.get(perm) ?? 0) + 1);
|
|
535
|
+
if (e.dlp_matches?.length) dlpBufHits++;
|
|
524
536
|
}
|
|
525
|
-
const topTools = [...toolCounts.entries()].sort((a, b) => b[1] - a[1]).slice(0,
|
|
526
|
-
const
|
|
527
|
-
const
|
|
528
|
-
const
|
|
529
|
-
const dlpTop = (ins.dlpByPattern ?? []).slice(0, 2);
|
|
537
|
+
const topTools = [...toolCounts.entries()].sort((a, b) => b[1] - a[1]).slice(0, 3);
|
|
538
|
+
const dlpBars = (ins.dlpByPattern ?? []).slice(0, 3);
|
|
539
|
+
const maxDlp = dlpBars[0]?.count ?? 1;
|
|
540
|
+
const dlpRecent = (ins.dlpHits ?? []).slice(0, 2);
|
|
530
541
|
const denials = buffer.filter((e) => e.decision !== "ALLOW");
|
|
531
542
|
const lastDeny = denials[denials.length - 1];
|
|
532
|
-
const bursts = limit > 0 ?
|
|
533
|
-
const
|
|
534
|
-
const
|
|
535
|
-
const
|
|
543
|
+
const bursts = limit > 0 ? rateSeries.filter((c2) => c2 > limit).length : 0;
|
|
544
|
+
const sess = (sessions.data?.agents ?? []).slice().sort((a, b) => Date.parse(b.last_seen_at) - Date.parse(a.last_seen_at));
|
|
545
|
+
const sessCounts = sessions.data?.counts;
|
|
546
|
+
const chartH = rows >= 36 ? 6 : 4;
|
|
547
|
+
const colH = rows >= 32 ? 6 : 5;
|
|
548
|
+
const streamRows = Math.max(4, rows - 6 - chartH - colH);
|
|
536
549
|
const tail = buffer.slice(-streamRows);
|
|
537
|
-
const colW = Math.max(
|
|
550
|
+
const colW = Math.max(20, Math.floor((cols - 6) / 3));
|
|
551
|
+
const innerW = cols - 2;
|
|
538
552
|
if (stats.error) return /* @__PURE__ */ jsxs2(Text2, { color: theme.bad, children: [
|
|
539
553
|
"\u2717 ",
|
|
540
554
|
stats.error
|
|
541
555
|
] });
|
|
556
|
+
const sessionDot = (st) => st === "active" ? { ch: "\u25CF", color: theme.ok } : st === "idle" ? { ch: "\u25D0", color: theme.warn } : { ch: "\u25CB", color: theme.dim };
|
|
542
557
|
return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", paddingX: 1, children: [
|
|
543
558
|
/* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
544
|
-
/* @__PURE__ */ jsx2(Text2, { backgroundColor: "#1432A0", color: "#AAC8FA", bold: true, children: " SOLONGATE
|
|
545
|
-
/* @__PURE__ */
|
|
546
|
-
|
|
547
|
-
spin,
|
|
548
|
-
" up ",
|
|
549
|
-
fmtUp(Date.now() - startRef.current),
|
|
550
|
-
" \xB7 ",
|
|
551
|
-
hhmmss(Date.now()),
|
|
552
|
-
" \xB7 poll 2s"
|
|
553
|
-
] }),
|
|
554
|
-
lastDeny ? /* @__PURE__ */ jsxs2(Text2, { color: theme.bad, children: [
|
|
555
|
-
" \u26A0 ",
|
|
556
|
-
hhmmss(lastDeny.created_at),
|
|
557
|
-
" ",
|
|
558
|
-
lastDeny.tool_name,
|
|
559
|
-
" denied"
|
|
560
|
-
] }) : null,
|
|
561
|
-
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " esc menu \xB7 q quit" })
|
|
559
|
+
/* @__PURE__ */ jsx2(Text2, { backgroundColor: "#1432A0", color: "#AAC8FA", bold: true, children: " \u26E8 SOLONGATE LIVE " }),
|
|
560
|
+
/* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", children: ` ${spin} up ${fmtUp(Date.now() - startRef.current)} \xB7 ${hhmmss(Date.now())} ` }),
|
|
561
|
+
lastDeny ? /* @__PURE__ */ jsx2(Text2, { backgroundColor: "#3d1220", color: "#ff6b6b", bold: true, children: ` \u26A0 ${hhmmss(lastDeny.created_at)} ${lastDeny.tool_name} DENIED ` }) : /* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#4f6db8", children: " \u2713 no recent denials " })
|
|
562
562
|
] }),
|
|
563
563
|
/* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
564
|
-
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "calls " }),
|
|
564
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "\u2502 calls " }),
|
|
565
565
|
/* @__PURE__ */ jsx2(Text2, { bold: true, children: s ? s.total_calls : "\xB7\xB7\xB7\xB7" }),
|
|
566
|
-
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "
|
|
566
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502 allow " }),
|
|
567
567
|
/* @__PURE__ */ jsx2(Text2, { color: theme.ok, children: s ? s.allowed : "\xB7\xB7\xB7" }),
|
|
568
|
-
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "
|
|
568
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502 deny " }),
|
|
569
569
|
/* @__PURE__ */ jsx2(Text2, { color: theme.bad, bold: true, children: s ? s.denied : "\xB7\xB7" }),
|
|
570
|
-
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "
|
|
570
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502 dlp(buf) " }),
|
|
571
|
+
/* @__PURE__ */ jsx2(Text2, { color: dlpBufHits ? theme.bad : theme.dim, children: dlpBufHits }),
|
|
572
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502 bursts " }),
|
|
571
573
|
/* @__PURE__ */ jsx2(Text2, { color: bursts ? theme.bad : theme.dim, children: bursts }),
|
|
572
|
-
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "
|
|
573
|
-
/* @__PURE__ */ jsx2(Text2, { color: theme.accent, children:
|
|
574
|
-
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "
|
|
575
|
-
/* @__PURE__ */ jsx2(Text2, { color: theme.accent, children: s ? s.active_policies : "\xB7" })
|
|
574
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502 sessions " }),
|
|
575
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.accent, children: sessCounts ? `${sessCounts.active}\u25B2 ${sessCounts.idle}\u25CC` : "\xB7" }),
|
|
576
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502 policies " }),
|
|
577
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.accent, children: s ? s.active_policies : "\xB7" }),
|
|
578
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502" })
|
|
576
579
|
] }),
|
|
577
|
-
/* @__PURE__ */ jsx2(
|
|
578
|
-
|
|
580
|
+
/* @__PURE__ */ jsx2(PaneTitle, { label: "RATE LIMIT", extra: `${rateLabel} \xB7 peak ${Math.max(0, ...rateSeries)} \xB7 limit ${limit || "off"} \xB7 mode ${rlMode}${limit ? " \xB7 red = over" : ""}`, width: innerW }),
|
|
581
|
+
rateSeries.length ? /* @__PURE__ */ jsx2(ColumnChart, { series: rateSeries, height: chartH, width: innerW, color: theme.accent, limit }) : /* @__PURE__ */ jsx2(Box2, { height: chartH, children: /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: insights.loading ? `${spin} loading activity\u2026` : "no activity data" }) }),
|
|
579
582
|
/* @__PURE__ */ jsxs2(Box2, { children: [
|
|
580
583
|
/* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", width: colW, marginRight: 2, children: [
|
|
581
|
-
/* @__PURE__ */ jsx2(
|
|
584
|
+
/* @__PURE__ */ jsx2(PaneTitle, { label: "DENIALS", extra: "24h", width: colW }),
|
|
582
585
|
/* @__PURE__ */ jsx2(ColumnChart, { series: denySeries, height: colH - 1, width: colW, color: theme.bad })
|
|
583
586
|
] }),
|
|
584
587
|
/* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", width: colW, marginRight: 2, children: [
|
|
585
|
-
/* @__PURE__ */ jsx2(
|
|
586
|
-
|
|
588
|
+
/* @__PURE__ */ jsx2(PaneTitle, { label: "DLP", extra: `7d \xB7 mode ${dlpMode}`, width: colW }),
|
|
589
|
+
dlpBars.length ? dlpBars.map((d) => /* @__PURE__ */ jsx2(HBar, { label: truncate(d.pattern, 9), value: d.count, max: maxDlp, width: Math.max(6, colW - 16), color: theme.bad }, d.pattern)) : /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "no dlp hits" }),
|
|
590
|
+
dlpRecent.map((h, i) => /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
591
|
+
/* @__PURE__ */ jsx2(Text2, { color: h.blocked ? theme.accent : theme.bad, children: h.blocked ? "\u2298" : "\u26A0" }),
|
|
592
|
+
/* @__PURE__ */ jsxs2(Text2, { color: theme.dim, children: [
|
|
593
|
+
" ",
|
|
594
|
+
truncate(h.pattern, colW - 14),
|
|
595
|
+
" ",
|
|
596
|
+
ago(h.at),
|
|
597
|
+
" ago"
|
|
598
|
+
] })
|
|
599
|
+
] }, i))
|
|
587
600
|
] }),
|
|
588
601
|
/* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", width: colW, children: [
|
|
589
|
-
/* @__PURE__ */ jsx2(
|
|
590
|
-
|
|
591
|
-
|
|
602
|
+
/* @__PURE__ */ jsx2(PaneTitle, { label: "SESSIONS", extra: sessCounts ? `${sessCounts.active} active` : "", width: colW }),
|
|
603
|
+
sess.length === 0 ? /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "no sessions" }) : null,
|
|
604
|
+
sess.slice(0, colH - 1).map((a) => {
|
|
605
|
+
const dot = sessionDot(a.status);
|
|
606
|
+
return /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
607
|
+
/* @__PURE__ */ jsxs2(Text2, { color: dot.color, children: [
|
|
608
|
+
dot.ch,
|
|
609
|
+
" "
|
|
610
|
+
] }),
|
|
611
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.accent, children: truncate(a.agent_name ?? a.session_id, 12).padEnd(13) }),
|
|
612
|
+
/* @__PURE__ */ jsxs2(Text2, { children: [
|
|
613
|
+
String(a.total_calls).padStart(4),
|
|
614
|
+
"c "
|
|
615
|
+
] }),
|
|
616
|
+
/* @__PURE__ */ jsxs2(Text2, { color: a.denied_calls ? theme.bad : theme.dim, children: [
|
|
617
|
+
String(a.denied_calls).padStart(3),
|
|
618
|
+
"d "
|
|
619
|
+
] }),
|
|
620
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: ago(a.last_seen_at) })
|
|
621
|
+
] }, a.session_id);
|
|
622
|
+
})
|
|
592
623
|
] })
|
|
593
624
|
] }),
|
|
594
|
-
/* @__PURE__ */ jsx2(
|
|
625
|
+
/* @__PURE__ */ jsx2(PaneTitle, { label: "TOOL STREAM", extra: `live tail \xB7 ${buffer.length} buffered`, width: innerW }),
|
|
595
626
|
tail.length === 0 ? /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "awaiting traffic\u2026" }) : null,
|
|
596
627
|
tail.map((e) => /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
597
628
|
/* @__PURE__ */ jsxs2(Text2, { color: theme.dim, children: [
|
|
@@ -606,11 +637,9 @@ function LivePanel({ active: active2 }) {
|
|
|
606
637
|
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: (e.arguments_summary ? JSON.stringify(e.arguments_summary) : e.reason ?? "").replace(/\s+/g, " ") })
|
|
607
638
|
] }, e.id)),
|
|
608
639
|
/* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
609
|
-
/* @__PURE__ */ jsx2(Text2, { color:
|
|
610
|
-
/* @__PURE__ */ jsx2(Text2, { color:
|
|
611
|
-
/* @__PURE__ */ jsx2(Text2, { color:
|
|
612
|
-
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "$ " }),
|
|
613
|
-
/* @__PURE__ */ jsx2(Text2, { color: theme.accentBright, children: cursor })
|
|
640
|
+
/* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", bold: true, children: " \u25B2 LIVE " }),
|
|
641
|
+
/* @__PURE__ */ jsx2(Text2, { backgroundColor: "#0b1530", color: "#4f6db8", children: ` top ${topTools.map(([t, c2]) => `${t}\xD7${c2}`).join(" ") || "\u2014"} ` }),
|
|
642
|
+
/* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", children: " esc menu \xB7 q quit " })
|
|
614
643
|
] })
|
|
615
644
|
] });
|
|
616
645
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@solongate/proxy",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.65.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": {
|