@solongate/proxy 0.81.23 → 0.81.25
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 +561 -533
- package/dist/tui/hooks.d.ts +3 -0
- package/dist/tui/index.js +505 -462
- package/dist/tui/local-log.d.ts +22 -0
- package/package.json +1 -1
- package/dist/tui/panels/Agents.d.ts +0 -4
- package/dist/tui/panels/Stats.d.ts +0 -3
package/dist/index.js
CHANGED
|
@@ -6814,7 +6814,7 @@ function DataView({
|
|
|
6814
6814
|
"\u2717 ",
|
|
6815
6815
|
error
|
|
6816
6816
|
] });
|
|
6817
|
-
if (loading) return /* @__PURE__ */ jsx(Text, { color: theme.
|
|
6817
|
+
if (loading) return /* @__PURE__ */ jsx(Text, { color: theme.warn, children: "\u27F3 loading\u2026" });
|
|
6818
6818
|
if (empty) return /* @__PURE__ */ jsx(Text, { color: theme.dim, children: emptyText ?? "No data." });
|
|
6819
6819
|
return /* @__PURE__ */ jsx(Fragment, { children });
|
|
6820
6820
|
}
|
|
@@ -6844,6 +6844,45 @@ var init_components = __esm({
|
|
|
6844
6844
|
}
|
|
6845
6845
|
});
|
|
6846
6846
|
|
|
6847
|
+
// src/tui/local-log.ts
|
|
6848
|
+
import { closeSync, openSync, readSync, statSync } from "fs";
|
|
6849
|
+
import { homedir as homedir4 } from "os";
|
|
6850
|
+
import { join as join6 } from "path";
|
|
6851
|
+
function tailLines(file, maxBytes = 131072) {
|
|
6852
|
+
try {
|
|
6853
|
+
const size = statSync(file).size;
|
|
6854
|
+
const start = Math.max(0, size - maxBytes);
|
|
6855
|
+
const fd = openSync(file, "r");
|
|
6856
|
+
const buf = Buffer.alloc(size - start);
|
|
6857
|
+
readSync(fd, buf, 0, buf.length, start);
|
|
6858
|
+
closeSync(fd);
|
|
6859
|
+
const lines = buf.toString("utf-8").split("\n").filter(Boolean);
|
|
6860
|
+
if (start > 0) lines.shift();
|
|
6861
|
+
return lines;
|
|
6862
|
+
} catch {
|
|
6863
|
+
return [];
|
|
6864
|
+
}
|
|
6865
|
+
}
|
|
6866
|
+
function parseLocalLines(lines) {
|
|
6867
|
+
const out2 = [];
|
|
6868
|
+
for (const line of lines) {
|
|
6869
|
+
try {
|
|
6870
|
+
const j = JSON.parse(line);
|
|
6871
|
+
const at = Date.parse(j.ts ?? "");
|
|
6872
|
+
if (Number.isFinite(at)) out2.push({ ...j, at });
|
|
6873
|
+
} catch {
|
|
6874
|
+
}
|
|
6875
|
+
}
|
|
6876
|
+
return out2;
|
|
6877
|
+
}
|
|
6878
|
+
var LOCAL_LOG;
|
|
6879
|
+
var init_local_log = __esm({
|
|
6880
|
+
"src/tui/local-log.ts"() {
|
|
6881
|
+
"use strict";
|
|
6882
|
+
LOCAL_LOG = join6(homedir4(), ".solongate", "local-logs", "solongate-audit.jsonl");
|
|
6883
|
+
}
|
|
6884
|
+
});
|
|
6885
|
+
|
|
6847
6886
|
// src/api-client/types.ts
|
|
6848
6887
|
var init_types = __esm({
|
|
6849
6888
|
"src/api-client/types.ts"() {
|
|
@@ -7164,6 +7203,7 @@ function useLoader(fn, deps = []) {
|
|
|
7164
7203
|
const [loading, setLoading] = useState(true);
|
|
7165
7204
|
const [nonce, setNonce] = useState(0);
|
|
7166
7205
|
const alive = useRef(true);
|
|
7206
|
+
const quiet = useRef(false);
|
|
7167
7207
|
const fnRef = useRef(fn);
|
|
7168
7208
|
fnRef.current = fn;
|
|
7169
7209
|
useEffect(() => {
|
|
@@ -7173,7 +7213,8 @@ function useLoader(fn, deps = []) {
|
|
|
7173
7213
|
};
|
|
7174
7214
|
}, []);
|
|
7175
7215
|
useEffect(() => {
|
|
7176
|
-
setLoading(true);
|
|
7216
|
+
if (!quiet.current) setLoading(true);
|
|
7217
|
+
quiet.current = false;
|
|
7177
7218
|
fnRef.current().then((d) => {
|
|
7178
7219
|
if (!alive.current) return;
|
|
7179
7220
|
setData(d);
|
|
@@ -7186,7 +7227,11 @@ function useLoader(fn, deps = []) {
|
|
|
7186
7227
|
});
|
|
7187
7228
|
}, [nonce, ...deps]);
|
|
7188
7229
|
const reload = useCallback(() => setNonce((n) => n + 1), []);
|
|
7189
|
-
|
|
7230
|
+
const reloadQuiet = useCallback(() => {
|
|
7231
|
+
quiet.current = true;
|
|
7232
|
+
setNonce((n) => n + 1);
|
|
7233
|
+
}, []);
|
|
7234
|
+
return { data, error, loading, reload, reloadQuiet };
|
|
7190
7235
|
}
|
|
7191
7236
|
function usePoll(reload, intervalMs, enabled = true) {
|
|
7192
7237
|
useEffect(() => {
|
|
@@ -7222,26 +7267,11 @@ var init_hooks = __esm({
|
|
|
7222
7267
|
// src/tui/panels/Live.tsx
|
|
7223
7268
|
import { Box as Box2, Text as Text2, useInput } from "ink";
|
|
7224
7269
|
import TextInput from "ink-text-input";
|
|
7225
|
-
import {
|
|
7226
|
-
import { homedir as
|
|
7227
|
-
import { join as
|
|
7270
|
+
import { mkdirSync as mkdirSync3, writeFileSync as writeFileSync3 } from "fs";
|
|
7271
|
+
import { homedir as homedir5 } from "os";
|
|
7272
|
+
import { join as join7 } from "path";
|
|
7228
7273
|
import { useCallback as useCallback2, useEffect as useEffect2, useRef as useRef2, useState as useState2 } from "react";
|
|
7229
7274
|
import { Fragment as Fragment2, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
7230
|
-
function tailLines(file, maxBytes = 131072) {
|
|
7231
|
-
try {
|
|
7232
|
-
const size = statSync(file).size;
|
|
7233
|
-
const start = Math.max(0, size - maxBytes);
|
|
7234
|
-
const fd = openSync(file, "r");
|
|
7235
|
-
const buf = Buffer.alloc(size - start);
|
|
7236
|
-
readSync(fd, buf, 0, buf.length, start);
|
|
7237
|
-
closeSync(fd);
|
|
7238
|
-
const lines = buf.toString("utf-8").split("\n").filter(Boolean);
|
|
7239
|
-
if (start > 0) lines.shift();
|
|
7240
|
-
return lines;
|
|
7241
|
-
} catch {
|
|
7242
|
-
return [];
|
|
7243
|
-
}
|
|
7244
|
-
}
|
|
7245
7275
|
function extractTarget(detail) {
|
|
7246
7276
|
try {
|
|
7247
7277
|
const j = JSON.parse(detail);
|
|
@@ -7505,13 +7535,13 @@ function LivePanel({ active: active2 }) {
|
|
|
7505
7535
|
const insights = useLoader(() => api.stats.securityInsights(7));
|
|
7506
7536
|
const guard = useLoader(() => api.settings.getGuardStatus());
|
|
7507
7537
|
usePoll(() => {
|
|
7508
|
-
if (!paused()) sessions.
|
|
7538
|
+
if (!paused()) sessions.reloadQuiet();
|
|
7509
7539
|
}, 8e3, active2);
|
|
7510
7540
|
usePoll(() => {
|
|
7511
|
-
if (!paused()) insights.
|
|
7541
|
+
if (!paused()) insights.reloadQuiet();
|
|
7512
7542
|
}, 2e4, active2);
|
|
7513
7543
|
usePoll(() => {
|
|
7514
|
-
if (!paused()) guard.
|
|
7544
|
+
if (!paused()) guard.reloadQuiet();
|
|
7515
7545
|
}, 6e4, active2);
|
|
7516
7546
|
useEffect2(() => {
|
|
7517
7547
|
if (!detail) return;
|
|
@@ -7785,9 +7815,9 @@ function LivePanel({ active: active2 }) {
|
|
|
7785
7815
|
else if (input === "x") toggleSignal("dlp");
|
|
7786
7816
|
else if (input === "r") toggleSignal("ratelimit");
|
|
7787
7817
|
else if (input === "e") {
|
|
7788
|
-
const file =
|
|
7818
|
+
const file = join7(homedir5(), ".solongate", "live-export.jsonl");
|
|
7789
7819
|
try {
|
|
7790
|
-
mkdirSync3(
|
|
7820
|
+
mkdirSync3(join7(homedir5(), ".solongate"), { recursive: true });
|
|
7791
7821
|
writeFileSync3(file, visibleDesc.map((x) => JSON.stringify(x)).join("\n") + "\n");
|
|
7792
7822
|
setActionMsg({ text: `\u2713 exported ${visibleDesc.length} lines \u2192 ${file}`, level: "ok", until: Date.now() + 6e3 });
|
|
7793
7823
|
} catch (err2) {
|
|
@@ -8103,10 +8133,11 @@ function LivePanel({ active: active2 }) {
|
|
|
8103
8133
|
] })
|
|
8104
8134
|
] });
|
|
8105
8135
|
}
|
|
8106
|
-
var CONFIG, SPIN, BG, DIM_FLOOR,
|
|
8136
|
+
var CONFIG, SPIN, BG, DIM_FLOOR, RING, hhmmss, fmtUp, FILTERS, sessStatus, STATUS_STYLE, LIVE_HELP;
|
|
8107
8137
|
var init_Live = __esm({
|
|
8108
8138
|
"src/tui/panels/Live.tsx"() {
|
|
8109
8139
|
"use strict";
|
|
8140
|
+
init_local_log();
|
|
8110
8141
|
init_api_client();
|
|
8111
8142
|
init_config2();
|
|
8112
8143
|
init_notify();
|
|
@@ -8116,8 +8147,7 @@ var init_Live = __esm({
|
|
|
8116
8147
|
SPIN = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
8117
8148
|
BG = "#12234f";
|
|
8118
8149
|
DIM_FLOOR = "#233457";
|
|
8119
|
-
|
|
8120
|
-
RING = join6(process.cwd(), ".solongate", ".eval-ring.jsonl");
|
|
8150
|
+
RING = join7(process.cwd(), ".solongate", ".eval-ring.jsonl");
|
|
8121
8151
|
hhmmss = (ts) => {
|
|
8122
8152
|
const d = new Date(ts);
|
|
8123
8153
|
return Number.isNaN(d.getTime()) ? "--:--:--" : d.toTimeString().slice(0, 8);
|
|
@@ -8200,7 +8230,6 @@ function PoliciesPanel({ focused }) {
|
|
|
8200
8230
|
const [pi, setPi] = useState3(0);
|
|
8201
8231
|
const [ri, setRi] = useState3(0);
|
|
8202
8232
|
const [fi, setFi] = useState3(0);
|
|
8203
|
-
const [vi, setVi] = useState3(0);
|
|
8204
8233
|
const [rules, setRules] = useState3([]);
|
|
8205
8234
|
const [mode, setMode] = useState3("denylist");
|
|
8206
8235
|
const [dirty, setDirty] = useState3(false);
|
|
@@ -8209,15 +8238,6 @@ function PoliciesPanel({ focused }) {
|
|
|
8209
8238
|
const [status, setStatus] = useState3(null);
|
|
8210
8239
|
const selected = policies[Math.min(pi, Math.max(0, policies.length - 1))];
|
|
8211
8240
|
const detail = useLoader(() => selected ? api.policies.get(selected.id) : Promise.resolve(null), [selected?.id]);
|
|
8212
|
-
const versionsQ = useLoader(
|
|
8213
|
-
() => view === "versions" && selected ? api.policies.versions(selected.id, { limit: 50 }) : Promise.resolve(null),
|
|
8214
|
-
[view, selected?.id]
|
|
8215
|
-
);
|
|
8216
|
-
const diffVer = versionsQ.data?.versions[vi]?.version;
|
|
8217
|
-
const diffQ = useLoader(
|
|
8218
|
-
() => view === "versions" && selected && diffVer !== void 0 ? api.policies.get(selected.id, diffVer) : Promise.resolve(null),
|
|
8219
|
-
[view, selected?.id, diffVer]
|
|
8220
|
-
);
|
|
8221
8241
|
useEffect3(() => {
|
|
8222
8242
|
if (detail.data) {
|
|
8223
8243
|
setRules(detail.data.rules);
|
|
@@ -8315,32 +8335,10 @@ function PoliciesPanel({ focused }) {
|
|
|
8315
8335
|
} else if (input === "D") {
|
|
8316
8336
|
setStatus("Dry-running\u2026");
|
|
8317
8337
|
void api.policies.dryRun({ rules, mode }).then((res) => setStatus(`dry-run ${res.evaluated} calls \xB7 allow ${res.would_allow} / deny ${res.would_deny} \xB7 newly blocked ${res.newly_blocked} \xB7 newly allowed ${res.newly_allowed}`)).catch((e) => setStatus("\u2717 " + (e instanceof Error ? e.message : String(e))));
|
|
8318
|
-
} else if (input === "v") {
|
|
8319
|
-
setVi(0);
|
|
8320
|
-
setView("versions");
|
|
8321
8338
|
} else if (input === "s") void save();
|
|
8322
8339
|
else if (input === "x") discard();
|
|
8323
8340
|
return;
|
|
8324
8341
|
}
|
|
8325
|
-
if (view === "versions") {
|
|
8326
|
-
const vers = versionsQ.data?.versions ?? [];
|
|
8327
|
-
if (key.leftArrow) return void setView("rules");
|
|
8328
|
-
if (key.upArrow) setVi((n) => Math.max(0, n - 1));
|
|
8329
|
-
else if (key.downArrow) setVi((n) => Math.min(vers.length - 1, n + 1));
|
|
8330
|
-
else if (key.return) {
|
|
8331
|
-
const v = vers[vi];
|
|
8332
|
-
if (v && selected) {
|
|
8333
|
-
setStatus("Rolling back\u2026");
|
|
8334
|
-
void api.policies.rollback(selected.id, v.version).then((r) => {
|
|
8335
|
-
setStatus(`\u2713 rolled back to v${v.version} \u2192 new v${r.version}`);
|
|
8336
|
-
detail.reload();
|
|
8337
|
-
list6.reload();
|
|
8338
|
-
setView("rules");
|
|
8339
|
-
}).catch((e) => setStatus("\u2717 " + (e instanceof Error ? e.message : String(e))));
|
|
8340
|
-
}
|
|
8341
|
-
}
|
|
8342
|
-
return;
|
|
8343
|
-
}
|
|
8344
8342
|
const rule2 = rules[ri];
|
|
8345
8343
|
if (!rule2) return setView("rules");
|
|
8346
8344
|
const field = FIELDS[fi];
|
|
@@ -8381,8 +8379,7 @@ function PoliciesPanel({ focused }) {
|
|
|
8381
8379
|
p.mode.padEnd(10),
|
|
8382
8380
|
" ",
|
|
8383
8381
|
p.rules.length,
|
|
8384
|
-
" rules
|
|
8385
|
-
p.version
|
|
8382
|
+
" rules"
|
|
8386
8383
|
] }),
|
|
8387
8384
|
p.id === activeId ? /* @__PURE__ */ jsx3(Text3, { color: theme.ok, bold: true, children: " \u25CF ACTIVE" }) : null
|
|
8388
8385
|
] }, p.id)) }),
|
|
@@ -8398,7 +8395,7 @@ function PoliciesPanel({ focused }) {
|
|
|
8398
8395
|
/* @__PURE__ */ jsx3(Text3, { color: mode === "whitelist" ? theme.warn : void 0, children: mode }),
|
|
8399
8396
|
dirtyTag
|
|
8400
8397
|
] }),
|
|
8401
|
-
/* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: "\u2191\u2193 \xB7 enter edit \xB7 space on/off \xB7 e effect \xB7 n new \xB7 d del \xB7 m mode \xB7 D dry-run \xB7
|
|
8398
|
+
/* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: "\u2191\u2193 \xB7 enter edit \xB7 space on/off \xB7 e effect \xB7 n new \xB7 d del \xB7 m mode \xB7 D dry-run \xB7 s save \xB7 \u2190 back" }),
|
|
8402
8399
|
/* @__PURE__ */ jsx3(Box3, { marginTop: 1, children: /* @__PURE__ */ jsx3(
|
|
8403
8400
|
Table,
|
|
8404
8401
|
{
|
|
@@ -8424,50 +8421,6 @@ function PoliciesPanel({ focused }) {
|
|
|
8424
8421
|
status ? /* @__PURE__ */ jsx3(Text3, { color: status.startsWith("\u2717") ? theme.bad : theme.ok, children: status }) : null
|
|
8425
8422
|
] }) });
|
|
8426
8423
|
}
|
|
8427
|
-
if (view === "versions") {
|
|
8428
|
-
const vers = versionsQ.data?.versions ?? [];
|
|
8429
|
-
return /* @__PURE__ */ jsx3(DataView, { loading: versionsQ.loading && !versionsQ.data, error: versionsQ.error, empty: !!versionsQ.data && vers.length === 0, emptyText: "No versions.", children: /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", children: [
|
|
8430
|
-
/* @__PURE__ */ jsx3(Text3, { bold: true, color: theme.accentBright, children: truncate2(selected?.name ?? "", 28) }),
|
|
8431
|
-
/* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: "\u2191\u2193 select \xB7 enter roll back to that version \xB7 \u2190 back" }),
|
|
8432
|
-
/* @__PURE__ */ jsx3(Box3, { marginTop: 1, children: /* @__PURE__ */ jsx3(
|
|
8433
|
-
Table,
|
|
8434
|
-
{
|
|
8435
|
-
columns: [
|
|
8436
|
-
{ header: "", width: 2 },
|
|
8437
|
-
{ header: "VER", width: 5 },
|
|
8438
|
-
{ header: "RULES", width: 5 },
|
|
8439
|
-
{ header: "REASON", width: 34 },
|
|
8440
|
-
{ header: "WHEN", width: 16 }
|
|
8441
|
-
],
|
|
8442
|
-
rows: vers.map((v, i) => [
|
|
8443
|
-
{ value: i === vi ? "\u25B8" : "", color: theme.accentBright },
|
|
8444
|
-
{ value: `v${v.version}`, bold: i === vi },
|
|
8445
|
-
{ value: String(v.rules_count), dim: true },
|
|
8446
|
-
{ value: truncate2(v.reason || "\u2014", 34) },
|
|
8447
|
-
{ value: truncate2(v.created_at, 16), dim: true }
|
|
8448
|
-
])
|
|
8449
|
-
}
|
|
8450
|
-
) }),
|
|
8451
|
-
/* @__PURE__ */ jsxs3(Box3, { marginTop: 1, flexDirection: "column", children: [
|
|
8452
|
-
/* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: `Diff v${diffVer ?? "?"} vs current draft` }),
|
|
8453
|
-
(() => {
|
|
8454
|
-
const old = diffQ.data?.rules ?? [];
|
|
8455
|
-
const cur = rules;
|
|
8456
|
-
const oldIds = new Set(old.map((r) => r.id));
|
|
8457
|
-
const curIds = new Set(cur.map((r) => r.id));
|
|
8458
|
-
const added = cur.filter((r) => !oldIds.has(r.id));
|
|
8459
|
-
const removed = old.filter((r) => !curIds.has(r.id));
|
|
8460
|
-
if (diffQ.loading && !diffQ.data) return /* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: " loading\u2026" });
|
|
8461
|
-
if (!added.length && !removed.length) return /* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: " identical rule set" });
|
|
8462
|
-
return /* @__PURE__ */ jsxs3(Fragment3, { children: [
|
|
8463
|
-
added.slice(0, 4).map((r) => /* @__PURE__ */ jsx3(Text3, { wrap: "truncate", color: theme.ok, children: ` + ${r.effect} ${truncate2(r.toolPattern, 18)} ${truncate2(r.description || r.id, 30)}` }, "a" + r.id)),
|
|
8464
|
-
removed.slice(0, 4).map((r) => /* @__PURE__ */ jsx3(Text3, { wrap: "truncate", color: theme.bad, children: ` - ${r.effect} ${truncate2(r.toolPattern, 18)} ${truncate2(r.description || r.id, 30)}` }, "r" + r.id))
|
|
8465
|
-
] });
|
|
8466
|
-
})()
|
|
8467
|
-
] }),
|
|
8468
|
-
status ? /* @__PURE__ */ jsx3(Text3, { color: status.startsWith("\u2717") ? theme.bad : theme.ok, children: status }) : null
|
|
8469
|
-
] }) });
|
|
8470
|
-
}
|
|
8471
8424
|
const rule = rules[ri];
|
|
8472
8425
|
return /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", children: [
|
|
8473
8426
|
/* @__PURE__ */ jsxs3(Box3, { children: [
|
|
@@ -8880,177 +8833,202 @@ var init_Dlp = __esm({
|
|
|
8880
8833
|
}
|
|
8881
8834
|
});
|
|
8882
8835
|
|
|
8883
|
-
// src/tui/panels/Stats.tsx
|
|
8884
|
-
import { Box as Box6, Text as Text6 } from "ink";
|
|
8885
|
-
import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
8886
|
-
function StatsPanel({ active: active2 }) {
|
|
8887
|
-
const stats = useLoader(() => api.stats.get());
|
|
8888
|
-
const ts = useLoader(() => api.stats.timeseries({ period: "24h" }));
|
|
8889
|
-
const drift2 = useLoader(() => api.stats.drift(7));
|
|
8890
|
-
usePoll(() => {
|
|
8891
|
-
stats.reload();
|
|
8892
|
-
ts.reload();
|
|
8893
|
-
}, 5e3, active2);
|
|
8894
|
-
usePoll(drift2.reload, 3e4, active2);
|
|
8895
|
-
const s = stats.data;
|
|
8896
|
-
const points = ts.data?.timeseries ?? [];
|
|
8897
|
-
const driftRules = (drift2.data?.rules ?? []).slice(0, 5);
|
|
8898
|
-
return /* @__PURE__ */ jsx6(DataView, { loading: stats.loading && !s, error: stats.error, children: s ? /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
|
|
8899
|
-
/* @__PURE__ */ jsxs6(Box6, { children: [
|
|
8900
|
-
/* @__PURE__ */ jsxs6(Text6, { bold: true, children: [
|
|
8901
|
-
s.total_calls,
|
|
8902
|
-
" "
|
|
8903
|
-
] }),
|
|
8904
|
-
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: "calls " }),
|
|
8905
|
-
/* @__PURE__ */ jsxs6(Text6, { color: theme.ok, children: [
|
|
8906
|
-
s.allowed,
|
|
8907
|
-
" allowed"
|
|
8908
|
-
] }),
|
|
8909
|
-
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: " " }),
|
|
8910
|
-
/* @__PURE__ */ jsxs6(Text6, { color: theme.bad, children: [
|
|
8911
|
-
s.denied,
|
|
8912
|
-
" denied"
|
|
8913
|
-
] })
|
|
8914
|
-
] }),
|
|
8915
|
-
/* @__PURE__ */ jsxs6(Text6, { color: theme.dim, children: [
|
|
8916
|
-
s.active_policies,
|
|
8917
|
-
" policies \xB7 ",
|
|
8918
|
-
s.registered_tools,
|
|
8919
|
-
" tools"
|
|
8920
|
-
] }),
|
|
8921
|
-
/* @__PURE__ */ jsxs6(Box6, { marginTop: 1, flexDirection: "column", children: [
|
|
8922
|
-
/* @__PURE__ */ jsxs6(Text6, { color: theme.dim, children: [
|
|
8923
|
-
"Last 24h ",
|
|
8924
|
-
ts.data ? `(per ${ts.data.granularity})` : ""
|
|
8925
|
-
] }),
|
|
8926
|
-
/* @__PURE__ */ jsxs6(Box6, { children: [
|
|
8927
|
-
/* @__PURE__ */ jsx6(Text6, { children: "total " }),
|
|
8928
|
-
/* @__PURE__ */ jsx6(Text6, { color: theme.accent, children: sparkline(points.map((p) => p.total), 64) })
|
|
8929
|
-
] }),
|
|
8930
|
-
/* @__PURE__ */ jsxs6(Box6, { children: [
|
|
8931
|
-
/* @__PURE__ */ jsx6(Text6, { children: "allowed " }),
|
|
8932
|
-
/* @__PURE__ */ jsx6(Text6, { color: theme.ok, children: sparkline(points.map((p) => p.allowed), 64) })
|
|
8933
|
-
] }),
|
|
8934
|
-
/* @__PURE__ */ jsxs6(Box6, { children: [
|
|
8935
|
-
/* @__PURE__ */ jsx6(Text6, { children: "denied " }),
|
|
8936
|
-
/* @__PURE__ */ jsx6(Text6, { color: theme.bad, children: sparkline(points.map((p) => p.denied), 64) })
|
|
8937
|
-
] })
|
|
8938
|
-
] }),
|
|
8939
|
-
/* @__PURE__ */ jsxs6(Box6, { marginTop: 1, flexDirection: "column", children: [
|
|
8940
|
-
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: "Recent" }),
|
|
8941
|
-
/* @__PURE__ */ jsx6(
|
|
8942
|
-
Table,
|
|
8943
|
-
{
|
|
8944
|
-
columns: [
|
|
8945
|
-
{ header: "DECISION", width: 9 },
|
|
8946
|
-
{ header: "TOOL", width: 20 },
|
|
8947
|
-
{ header: "MS", width: 5 },
|
|
8948
|
-
{ header: "WHEN", width: 6 }
|
|
8949
|
-
],
|
|
8950
|
-
rows: (s.recent_activity ?? []).slice(0, 6).map((a) => [
|
|
8951
|
-
{ value: a.decision, color: decisionColor(a.decision) },
|
|
8952
|
-
{ value: truncate2(a.tool_name, 20), color: theme.accent },
|
|
8953
|
-
{ value: String(a.evaluation_time_ms ?? "\u2014"), dim: true },
|
|
8954
|
-
{ value: ago(a.created_at), dim: true }
|
|
8955
|
-
])
|
|
8956
|
-
}
|
|
8957
|
-
)
|
|
8958
|
-
] }),
|
|
8959
|
-
/* @__PURE__ */ jsxs6(Box6, { marginTop: 1, flexDirection: "column", children: [
|
|
8960
|
-
/* @__PURE__ */ jsxs6(Text6, { color: theme.dim, children: [
|
|
8961
|
-
"Denial drift ",
|
|
8962
|
-
drift2.data ? `(7d: ${drift2.data.total_current} now vs ${drift2.data.total_previous} prev)` : ""
|
|
8963
|
-
] }),
|
|
8964
|
-
driftRules.length ? /* @__PURE__ */ jsx6(
|
|
8965
|
-
Table,
|
|
8966
|
-
{
|
|
8967
|
-
columns: [
|
|
8968
|
-
{ header: "NOW", width: 5 },
|
|
8969
|
-
{ header: "PREV", width: 5 },
|
|
8970
|
-
{ header: "\u0394", width: 6 },
|
|
8971
|
-
{ header: "RULE", width: 22 },
|
|
8972
|
-
{ header: "REASON", width: 26 }
|
|
8973
|
-
],
|
|
8974
|
-
rows: driftRules.map((r) => [
|
|
8975
|
-
{ value: String(r.current), bold: true },
|
|
8976
|
-
{ value: String(r.previous), dim: true },
|
|
8977
|
-
{ value: r.is_new ? "NEW" : r.spike ? `+${r.delta}` : String(r.delta), color: r.is_new ? theme.ok : r.spike ? theme.bad : void 0 },
|
|
8978
|
-
{ value: truncate2(r.rule_id ?? "\u2014", 22), color: theme.accent },
|
|
8979
|
-
{ value: truncate2(r.reason ?? r.last_tool ?? "\u2014", 26), dim: true }
|
|
8980
|
-
])
|
|
8981
|
-
}
|
|
8982
|
-
) : /* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: " no denials in window" })
|
|
8983
|
-
] })
|
|
8984
|
-
] }) : null });
|
|
8985
|
-
}
|
|
8986
|
-
var init_Stats = __esm({
|
|
8987
|
-
"src/tui/panels/Stats.tsx"() {
|
|
8988
|
-
"use strict";
|
|
8989
|
-
init_api_client();
|
|
8990
|
-
init_components();
|
|
8991
|
-
init_hooks();
|
|
8992
|
-
init_theme();
|
|
8993
|
-
}
|
|
8994
|
-
});
|
|
8995
|
-
|
|
8996
8836
|
// src/tui/panels/Audit.tsx
|
|
8997
|
-
import { Box as
|
|
8837
|
+
import { Box as Box6, Text as Text6, useInput as useInput5 } from "ink";
|
|
8998
8838
|
import TextInput4 from "ink-text-input";
|
|
8999
8839
|
import { useState as useState6 } from "react";
|
|
9000
|
-
import { Fragment as Fragment4, jsx as
|
|
8840
|
+
import { Fragment as Fragment4, jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
8841
|
+
function loadLocalRows() {
|
|
8842
|
+
return parseLocalLines(tailLines(LOCAL_LOG, LOCAL_MAX_BYTES)).map((j, i) => ({
|
|
8843
|
+
id: "l:" + j.at + ":" + i,
|
|
8844
|
+
at: j.at,
|
|
8845
|
+
tool: j.tool ?? "?",
|
|
8846
|
+
decision: j.decision ?? "ALLOW",
|
|
8847
|
+
permission: j.permission ?? "\u2014",
|
|
8848
|
+
trust: j.trust_level ?? "\u2014",
|
|
8849
|
+
agent: j.agent_name ?? null,
|
|
8850
|
+
session: j.session_id ?? null,
|
|
8851
|
+
reason: j.reason ?? null,
|
|
8852
|
+
rule: j.matched_rule_id ?? null,
|
|
8853
|
+
evalMs: j.evaluation_time_ms ?? null,
|
|
8854
|
+
dlp: j.dlp ? Array.isArray(j.dlp) ? j.dlp.map(String) : ["dlp"] : [],
|
|
8855
|
+
burst: !!j.rate_limit_burst,
|
|
8856
|
+
args: j.arguments ? JSON.stringify(j.arguments) : null
|
|
8857
|
+
})).sort((a, b) => b.at - a.at);
|
|
8858
|
+
}
|
|
9001
8859
|
function AuditPanel({ active: active2, focused }) {
|
|
9002
8860
|
const { cols, rows } = usePanelSize();
|
|
8861
|
+
const [source, setSource] = useState6("cloud");
|
|
8862
|
+
const [view, setView] = useState6("logs");
|
|
9003
8863
|
const [di, setDi] = useState6(0);
|
|
9004
8864
|
const [gi, setGi] = useState6(0);
|
|
9005
8865
|
const [tool, setTool] = useState6("");
|
|
9006
8866
|
const [agent, setAgent] = useState6("");
|
|
9007
8867
|
const [search, setSearch] = useState6("");
|
|
8868
|
+
const [sessFilter, setSessFilter] = useState6("");
|
|
8869
|
+
const [page, setPage] = useState6(0);
|
|
9008
8870
|
const [sel, setSel] = useState6(0);
|
|
9009
|
-
const [view, setView] = useState6("list");
|
|
9010
8871
|
const [detailScroll, setDetailScroll] = useState6(0);
|
|
9011
8872
|
const [editing, setEditing] = useState6(null);
|
|
8873
|
+
const [si, setSi] = useState6(0);
|
|
8874
|
+
const [sessSearch, setSessSearch] = useState6("");
|
|
8875
|
+
const [sessSel, setSessSel] = useState6(0);
|
|
8876
|
+
const toTop = () => setSel(0);
|
|
8877
|
+
const statsQ = useLoader(() => source === "cloud" ? api.stats.get() : Promise.resolve(null), [source]);
|
|
8878
|
+
const tsQ = useLoader(() => source === "cloud" ? api.stats.timeseries({ period: "24h" }) : Promise.resolve(null), [source]);
|
|
8879
|
+
usePoll(() => {
|
|
8880
|
+
statsQ.reloadQuiet();
|
|
8881
|
+
tsQ.reloadQuiet();
|
|
8882
|
+
}, 15e3, active2 && source === "cloud");
|
|
9012
8883
|
const query = {
|
|
9013
8884
|
filter: DECISIONS[di],
|
|
9014
8885
|
signal: SIGNALS[gi],
|
|
9015
8886
|
tool: tool || void 0,
|
|
9016
8887
|
agent_name: agent || void 0,
|
|
9017
8888
|
search: search || void 0,
|
|
9018
|
-
|
|
8889
|
+
session_id: sessFilter || void 0,
|
|
8890
|
+
limit: PAGE,
|
|
8891
|
+
offset: page * PAGE
|
|
9019
8892
|
};
|
|
9020
|
-
const
|
|
9021
|
-
|
|
9022
|
-
|
|
9023
|
-
|
|
8893
|
+
const cloudQ = useLoader(
|
|
8894
|
+
() => source === "cloud" ? api.audit.list(query) : Promise.resolve(null),
|
|
8895
|
+
[source, di, gi, tool, agent, search, sessFilter, page]
|
|
8896
|
+
);
|
|
8897
|
+
usePoll(cloudQ.reloadQuiet, 6e3, active2 && source === "cloud" && view === "logs" && !editing && page === 0);
|
|
8898
|
+
const localQ = useLoader(() => source === "local" ? Promise.resolve(loadLocalRows()) : Promise.resolve(null), [source]);
|
|
8899
|
+
usePoll(localQ.reloadQuiet, 6e3, active2 && source === "local" && view === "logs" && !editing && page === 0);
|
|
8900
|
+
let pageRows = [];
|
|
8901
|
+
let total = 0;
|
|
8902
|
+
if (source === "cloud") {
|
|
8903
|
+
pageRows = (cloudQ.data?.entries ?? []).map(cloudRow).sort((a, b) => b.at - a.at);
|
|
8904
|
+
total = cloudQ.data?.total ?? 0;
|
|
8905
|
+
} else {
|
|
8906
|
+
const all = localQ.data ?? [];
|
|
8907
|
+
const q = search.trim().toLowerCase();
|
|
8908
|
+
const filtered = all.filter((r) => {
|
|
8909
|
+
if (DECISIONS[di] && r.decision !== DECISIONS[di]) return false;
|
|
8910
|
+
if (SIGNALS[gi] === "dlp" && r.dlp.length === 0) return false;
|
|
8911
|
+
if (SIGNALS[gi] === "ratelimit" && !r.burst) return false;
|
|
8912
|
+
if (tool && !r.tool.toLowerCase().includes(tool.toLowerCase())) return false;
|
|
8913
|
+
if (agent && (r.agent ?? "").toLowerCase() !== agent.toLowerCase()) return false;
|
|
8914
|
+
if (sessFilter && r.session !== sessFilter) return false;
|
|
8915
|
+
if (q && !`${r.tool} ${r.agent ?? ""} ${r.reason ?? ""} ${r.args ?? ""}`.toLowerCase().includes(q)) return false;
|
|
8916
|
+
return true;
|
|
8917
|
+
});
|
|
8918
|
+
total = filtered.length;
|
|
8919
|
+
pageRows = filtered.slice(page * PAGE, page * PAGE + PAGE);
|
|
8920
|
+
}
|
|
8921
|
+
const pages = Math.max(1, Math.ceil(total / PAGE));
|
|
8922
|
+
const current = pageRows[Math.min(sel, Math.max(0, pageRows.length - 1))];
|
|
8923
|
+
const agentsQ = useLoader(
|
|
8924
|
+
() => source === "cloud" ? api.agents.live({ limit: 100, includeDeactivated: true }) : Promise.resolve(null),
|
|
8925
|
+
[source]
|
|
8926
|
+
);
|
|
8927
|
+
usePoll(agentsQ.reloadQuiet, 8e3, active2 && source === "cloud" && view === "sessions");
|
|
8928
|
+
let sessions = [];
|
|
8929
|
+
if (source === "cloud") {
|
|
8930
|
+
sessions = (agentsQ.data?.agents ?? []).map((a) => ({
|
|
8931
|
+
id: a.session_id,
|
|
8932
|
+
agent: a.agent_name ?? a.session_id,
|
|
8933
|
+
status: a.status === "deactivated" ? "ended" : a.status,
|
|
8934
|
+
calls: a.total_calls,
|
|
8935
|
+
denies: a.denied_calls,
|
|
8936
|
+
dlp: a.dlp_events,
|
|
8937
|
+
trust: a.trust_score,
|
|
8938
|
+
lastAt: Date.parse(a.last_seen_at)
|
|
8939
|
+
}));
|
|
8940
|
+
} else {
|
|
8941
|
+
const bySess = /* @__PURE__ */ new Map();
|
|
8942
|
+
for (const r of localQ.data ?? []) {
|
|
8943
|
+
if (!r.session) continue;
|
|
8944
|
+
const cur = bySess.get(r.session) ?? { id: r.session, agent: r.agent ?? "local agent", status: "ended", calls: 0, denies: 0, dlp: 0, trust: null, lastAt: 0 };
|
|
8945
|
+
cur.calls++;
|
|
8946
|
+
if (r.decision !== "ALLOW") cur.denies++;
|
|
8947
|
+
if (r.dlp.length) cur.dlp++;
|
|
8948
|
+
cur.lastAt = Math.max(cur.lastAt, r.at);
|
|
8949
|
+
if (r.agent) cur.agent = r.agent;
|
|
8950
|
+
bySess.set(r.session, cur);
|
|
8951
|
+
}
|
|
8952
|
+
sessions = [...bySess.values()];
|
|
8953
|
+
}
|
|
8954
|
+
const sq = sessSearch.trim().toLowerCase();
|
|
8955
|
+
const sessionsFiltered = sessions.map((s) => ({ ...s, status: source === "cloud" ? s.status : sessStatus2(s.lastAt) })).filter((s) => SESS_STATUS[si] ? s.status === SESS_STATUS[si] : true).filter((s) => !sq || `${s.agent} ${s.id}`.toLowerCase().includes(sq)).sort((a, b) => b.lastAt - a.lastAt);
|
|
8956
|
+
const currentSess = sessionsFiltered[Math.min(sessSel, Math.max(0, sessionsFiltered.length - 1))];
|
|
9024
8957
|
const sessionQ = useLoader(
|
|
9025
|
-
() => view === "detail" && current?.
|
|
9026
|
-
[view, current?.
|
|
8958
|
+
() => view === "detail" && current?.session && source === "cloud" ? api.audit.list({ session_id: current.session, limit: 40 }) : Promise.resolve(null),
|
|
8959
|
+
[view, current?.session, source]
|
|
9027
8960
|
);
|
|
9028
8961
|
useInput5(
|
|
9029
8962
|
(input, key) => {
|
|
9030
8963
|
if (view === "detail") {
|
|
9031
|
-
if (key.leftArrow || key.escape) setView("
|
|
8964
|
+
if (key.leftArrow || key.escape) setView("logs");
|
|
9032
8965
|
else if (key.upArrow) setDetailScroll((n) => Math.max(0, n - 1));
|
|
9033
8966
|
else if (key.downArrow) setDetailScroll((n) => n + 1);
|
|
9034
8967
|
else if (key.pageUp) setDetailScroll((n) => Math.max(0, n - 10));
|
|
9035
8968
|
else if (key.pageDown) setDetailScroll((n) => n + 10);
|
|
9036
8969
|
return;
|
|
9037
8970
|
}
|
|
9038
|
-
|
|
8971
|
+
if (input === "s") {
|
|
8972
|
+
setSource((s) => s === "cloud" ? "local" : "cloud");
|
|
8973
|
+
setPage(0);
|
|
8974
|
+
toTop();
|
|
8975
|
+
setSessSel(0);
|
|
8976
|
+
return;
|
|
8977
|
+
}
|
|
8978
|
+
if (input === "v") {
|
|
8979
|
+
setView((v) => v === "logs" ? "sessions" : "logs");
|
|
8980
|
+
return;
|
|
8981
|
+
}
|
|
8982
|
+
if (view === "sessions") {
|
|
8983
|
+
if (key.upArrow) setSessSel((n) => Math.max(0, n - 1));
|
|
8984
|
+
else if (key.downArrow) setSessSel((n) => Math.min(sessionsFiltered.length - 1, n + 1));
|
|
8985
|
+
else if (key.pageUp) setSessSel((n) => Math.max(0, n - 10));
|
|
8986
|
+
else if (key.pageDown) setSessSel((n) => Math.min(sessionsFiltered.length - 1, n + 10));
|
|
8987
|
+
else if (key.return) {
|
|
8988
|
+
if (currentSess) {
|
|
8989
|
+
setSessFilter(currentSess.id);
|
|
8990
|
+
setPage(0);
|
|
8991
|
+
toTop();
|
|
8992
|
+
setView("logs");
|
|
8993
|
+
}
|
|
8994
|
+
} else if (input === "f") {
|
|
8995
|
+
setSi((n) => (n + 1) % SESS_STATUS.length);
|
|
8996
|
+
setSessSel(0);
|
|
8997
|
+
} else if (input === "/") setEditing("sess-search");
|
|
8998
|
+
else if (input === "c") {
|
|
8999
|
+
setSi(0);
|
|
9000
|
+
setSessSearch("");
|
|
9001
|
+
setSessSel(0);
|
|
9002
|
+
}
|
|
9003
|
+
return;
|
|
9004
|
+
}
|
|
9039
9005
|
if (key.upArrow) setSel((n) => Math.max(0, n - 1));
|
|
9040
|
-
else if (key.downArrow) setSel((n) => Math.min(
|
|
9006
|
+
else if (key.downArrow) setSel((n) => Math.min(pageRows.length - 1, n + 1));
|
|
9041
9007
|
else if (key.pageUp) setSel((n) => Math.max(0, n - 10));
|
|
9042
|
-
else if (key.pageDown) setSel((n) => Math.min(
|
|
9043
|
-
else if (key.return
|
|
9008
|
+
else if (key.pageDown) setSel((n) => Math.min(pageRows.length - 1, n + 10));
|
|
9009
|
+
else if (key.return) {
|
|
9044
9010
|
if (current) {
|
|
9045
9011
|
setDetailScroll(0);
|
|
9046
9012
|
setView("detail");
|
|
9047
9013
|
}
|
|
9014
|
+
} else if (key.rightArrow) {
|
|
9015
|
+
if (page < pages - 1) {
|
|
9016
|
+
setPage(page + 1);
|
|
9017
|
+
toTop();
|
|
9018
|
+
}
|
|
9019
|
+
} else if (key.leftArrow) {
|
|
9020
|
+
if (page > 0) {
|
|
9021
|
+
setPage(page - 1);
|
|
9022
|
+
toTop();
|
|
9023
|
+
}
|
|
9048
9024
|
} else if (input === "f") {
|
|
9049
9025
|
setDi((n) => (n + 1) % DECISIONS.length);
|
|
9050
|
-
|
|
9026
|
+
setPage(0);
|
|
9027
|
+
toTop();
|
|
9051
9028
|
} else if (input === "g") {
|
|
9052
9029
|
setGi((n) => (n + 1) % SIGNALS.length);
|
|
9053
|
-
|
|
9030
|
+
setPage(0);
|
|
9031
|
+
toTop();
|
|
9054
9032
|
} else if (input === "t") setEditing("tool");
|
|
9055
9033
|
else if (input === "n") setEditing("agent");
|
|
9056
9034
|
else if (input === "/") setEditing("search");
|
|
@@ -9060,46 +9038,89 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
9060
9038
|
setTool("");
|
|
9061
9039
|
setAgent("");
|
|
9062
9040
|
setSearch("");
|
|
9063
|
-
|
|
9041
|
+
setSessFilter("");
|
|
9042
|
+
setPage(0);
|
|
9043
|
+
toTop();
|
|
9064
9044
|
}
|
|
9065
9045
|
},
|
|
9066
9046
|
{ isActive: focused && !editing }
|
|
9067
9047
|
);
|
|
9048
|
+
const points = tsQ.data?.timeseries ?? [];
|
|
9049
|
+
const localAll = localQ.data ?? [];
|
|
9050
|
+
const strip = source === "cloud" ? /* @__PURE__ */ jsxs6(Text6, { wrap: "truncate", children: [
|
|
9051
|
+
/* @__PURE__ */ jsx6(Text6, { bold: true, children: statsQ.data ? statsQ.data.total_calls : "\xB7\xB7\xB7\xB7" }),
|
|
9052
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: " calls \xB7 " }),
|
|
9053
|
+
/* @__PURE__ */ jsxs6(Text6, { color: theme.ok, children: [
|
|
9054
|
+
statsQ.data?.allowed ?? "\xB7\xB7\xB7",
|
|
9055
|
+
" allow"
|
|
9056
|
+
] }),
|
|
9057
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: " \xB7 " }),
|
|
9058
|
+
/* @__PURE__ */ jsxs6(Text6, { color: theme.bad, children: [
|
|
9059
|
+
statsQ.data?.denied ?? "\xB7\xB7",
|
|
9060
|
+
" deny"
|
|
9061
|
+
] }),
|
|
9062
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: ` \xB7 ${statsQ.data?.active_policies ?? "\xB7"} policies \xB7 ${statsQ.data?.registered_tools ?? "\xB7"} tools \xB7 24h ` }),
|
|
9063
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.accent, children: sparkline(points.map((p) => p.total), 24) }),
|
|
9064
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: " deny " }),
|
|
9065
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.bad, children: sparkline(points.map((p) => p.denied), 24) })
|
|
9066
|
+
] }) : /* @__PURE__ */ jsxs6(Text6, { wrap: "truncate", children: [
|
|
9067
|
+
/* @__PURE__ */ jsx6(Text6, { bold: true, children: localAll.length }),
|
|
9068
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: " calls in local file \xB7 " }),
|
|
9069
|
+
/* @__PURE__ */ jsxs6(Text6, { color: theme.ok, children: [
|
|
9070
|
+
localAll.filter((r) => r.decision === "ALLOW").length,
|
|
9071
|
+
" allow"
|
|
9072
|
+
] }),
|
|
9073
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: " \xB7 " }),
|
|
9074
|
+
/* @__PURE__ */ jsxs6(Text6, { color: theme.bad, children: [
|
|
9075
|
+
localAll.filter((r) => r.decision !== "ALLOW").length,
|
|
9076
|
+
" deny"
|
|
9077
|
+
] }),
|
|
9078
|
+
/* @__PURE__ */ jsxs6(Text6, { color: theme.dim, children: [
|
|
9079
|
+
" \xB7 ",
|
|
9080
|
+
LOCAL_LOG
|
|
9081
|
+
] })
|
|
9082
|
+
] });
|
|
9083
|
+
const srcChip = /* @__PURE__ */ jsxs6(Text6, { children: [
|
|
9084
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: "src:" }),
|
|
9085
|
+
/* @__PURE__ */ jsx6(Text6, { color: source === "local" ? theme.ok : "#4f6db8", bold: true, children: source }),
|
|
9086
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: " (s) " })
|
|
9087
|
+
] });
|
|
9068
9088
|
if (view === "detail" && current) {
|
|
9069
|
-
const sessionCalls = sessionQ.data?.entries ?? [];
|
|
9089
|
+
const sessionCalls = source === "cloud" ? (sessionQ.data?.entries ?? []).map(cloudRow) : localAll.filter((r) => r.session && r.session === current.session).slice(0, 40);
|
|
9070
9090
|
const bodyW = Math.max(20, cols - 2);
|
|
9071
9091
|
const reasonLines = wrapLines("reason: " + (current.reason ?? "\u2014"), bodyW);
|
|
9072
|
-
const argLines = current.
|
|
9073
|
-
const sessionRows = current.
|
|
9092
|
+
const argLines = current.args ? wrapLines(prettyJson(current.args), bodyW) : ["(no arguments recorded)"];
|
|
9093
|
+
const sessionRows = current.session ? Math.min(4, sessionCalls.length) + 2 : 1;
|
|
9074
9094
|
const reasonShown = reasonLines.slice(0, 4);
|
|
9075
9095
|
const argBudget = Math.max(3, rows - 2 - 5 - reasonShown.length - 1 - sessionRows - 1);
|
|
9076
9096
|
const maxScroll = Math.max(0, argLines.length - argBudget);
|
|
9077
9097
|
const off = Math.min(detailScroll, maxScroll);
|
|
9078
9098
|
const argWin = argLines.slice(off, off + argBudget);
|
|
9079
|
-
return /* @__PURE__ */
|
|
9080
|
-
/* @__PURE__ */
|
|
9081
|
-
/* @__PURE__ */
|
|
9082
|
-
/* @__PURE__ */
|
|
9083
|
-
/* @__PURE__ */
|
|
9099
|
+
return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
|
|
9100
|
+
/* @__PURE__ */ jsxs6(Box6, { children: [
|
|
9101
|
+
/* @__PURE__ */ jsx6(Text6, { color: decisionColor(current.decision), bold: true, children: current.decision }),
|
|
9102
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.accent, children: " " + current.tool }),
|
|
9103
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: " " + current.permission + " \xB7 " + current.trust + " " }),
|
|
9104
|
+
srcChip
|
|
9084
9105
|
] }),
|
|
9085
|
-
reasonShown.map((l, i) => /* @__PURE__ */
|
|
9086
|
-
/* @__PURE__ */
|
|
9087
|
-
/* @__PURE__ */
|
|
9088
|
-
] }) : /* @__PURE__ */
|
|
9089
|
-
/* @__PURE__ */
|
|
9090
|
-
/* @__PURE__ */
|
|
9091
|
-
/* @__PURE__ */
|
|
9092
|
-
/* @__PURE__ */
|
|
9093
|
-
/* @__PURE__ */
|
|
9094
|
-
/* @__PURE__ */
|
|
9095
|
-
/* @__PURE__ */
|
|
9096
|
-
current.
|
|
9097
|
-
/* @__PURE__ */
|
|
9106
|
+
reasonShown.map((l, i) => /* @__PURE__ */ jsx6(Text6, { wrap: "truncate", children: i === 0 ? /* @__PURE__ */ jsxs6(Fragment4, { children: [
|
|
9107
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: "reason " }),
|
|
9108
|
+
/* @__PURE__ */ jsx6(Text6, { children: l.slice("reason: ".length) })
|
|
9109
|
+
] }) : /* @__PURE__ */ jsx6(Text6, { children: " " + l }) }, "r" + i)),
|
|
9110
|
+
/* @__PURE__ */ jsx6(Detail, { label: "rule", value: current.rule ?? "\u2014" }),
|
|
9111
|
+
/* @__PURE__ */ jsx6(Detail, { label: "agent", value: current.agent ?? "\u2014" }),
|
|
9112
|
+
/* @__PURE__ */ jsx6(Detail, { label: "session", value: current.session ?? "\u2014" }),
|
|
9113
|
+
/* @__PURE__ */ jsx6(Detail, { label: "dlp", value: current.dlp.length ? current.dlp.join(", ") : "none", color: current.dlp.length ? theme.bad : void 0 }),
|
|
9114
|
+
/* @__PURE__ */ jsx6(Detail, { label: "when", value: new Date(current.at).toLocaleString() + (current.evalMs != null ? ` \xB7 eval ${current.evalMs}ms` : "") }),
|
|
9115
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: `arguments \u2014 full \xB7 ${argLines.length} lines${maxScroll ? ` \xB7 \u25BC${maxScroll - off} more \xB7 \u2191\u2193 scroll` : ""}` }),
|
|
9116
|
+
/* @__PURE__ */ jsx6(Box6, { flexDirection: "column", height: argBudget, overflow: "hidden", children: argWin.map((l, i) => /* @__PURE__ */ jsx6(Text6, { wrap: "truncate", children: l || " " }, off + i)) }),
|
|
9117
|
+
current.session ? /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
|
|
9118
|
+
/* @__PURE__ */ jsxs6(Text6, { color: theme.dim, children: [
|
|
9098
9119
|
"Session \xB7 ",
|
|
9099
9120
|
sessionCalls.length,
|
|
9100
9121
|
" calls"
|
|
9101
9122
|
] }),
|
|
9102
|
-
/* @__PURE__ */
|
|
9123
|
+
/* @__PURE__ */ jsx6(
|
|
9103
9124
|
Table,
|
|
9104
9125
|
{
|
|
9105
9126
|
columns: [
|
|
@@ -9110,59 +9131,136 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
9110
9131
|
],
|
|
9111
9132
|
rows: sessionCalls.slice(0, Math.max(1, sessionRows - 2)).map((e) => [
|
|
9112
9133
|
{ value: e.decision, color: decisionColor(e.decision) },
|
|
9113
|
-
{ value: truncate2(e.
|
|
9134
|
+
{ value: truncate2(e.tool, 20), color: theme.accent },
|
|
9114
9135
|
{ value: truncate2(e.reason ?? "\u2014", Math.max(16, cols - 48)) },
|
|
9115
|
-
{ value: ago(e.
|
|
9136
|
+
{ value: ago(e.at), dim: true }
|
|
9116
9137
|
])
|
|
9117
9138
|
}
|
|
9118
9139
|
)
|
|
9119
|
-
] }) : /* @__PURE__ */
|
|
9120
|
-
/* @__PURE__ */
|
|
9140
|
+
] }) : /* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: "(no session id)" }),
|
|
9141
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: "\u2191\u2193 scroll arguments \xB7 \u2190/esc back to logs" })
|
|
9121
9142
|
] });
|
|
9122
9143
|
}
|
|
9123
|
-
const chip = (label, val, on) => /* @__PURE__ */
|
|
9124
|
-
/* @__PURE__ */
|
|
9144
|
+
const chip = (label, val, on) => /* @__PURE__ */ jsxs6(Text6, { children: [
|
|
9145
|
+
/* @__PURE__ */ jsxs6(Text6, { color: theme.dim, children: [
|
|
9125
9146
|
label,
|
|
9126
9147
|
":"
|
|
9127
9148
|
] }),
|
|
9128
|
-
/* @__PURE__ */
|
|
9129
|
-
/* @__PURE__ */
|
|
9149
|
+
/* @__PURE__ */ jsx6(Text6, { color: on ? theme.accentBright : theme.dim, children: val }),
|
|
9150
|
+
/* @__PURE__ */ jsx6(Text6, { children: " " })
|
|
9130
9151
|
] });
|
|
9131
|
-
|
|
9152
|
+
if (view === "sessions") {
|
|
9153
|
+
const headerRows2 = 5 + (editing ? 1 : 0);
|
|
9154
|
+
const listRows2 = Math.max(4, rows - headerRows2);
|
|
9155
|
+
const selC = Math.min(sessSel, Math.max(0, sessionsFiltered.length - 1));
|
|
9156
|
+
const start2 = Math.min(Math.max(0, selC - Math.floor((listRows2 - 1) / 2)), Math.max(0, sessionsFiltered.length - listRows2));
|
|
9157
|
+
const win = sessionsFiltered.slice(start2, start2 + listRows2);
|
|
9158
|
+
const loading2 = source === "cloud" ? agentsQ.loading : localQ.loading;
|
|
9159
|
+
return /* @__PURE__ */ jsx6(DataView, { loading: loading2, error: source === "cloud" ? agentsQ.error : localQ.error, children: /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
|
|
9160
|
+
strip,
|
|
9161
|
+
/* @__PURE__ */ jsxs6(Box6, { children: [
|
|
9162
|
+
srcChip,
|
|
9163
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.accentBright, bold: true, children: "SESSIONS" }),
|
|
9164
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: " \xB7 logs (v) " }),
|
|
9165
|
+
chip("status", SESS_STATUS[si] ?? "all", si !== 0),
|
|
9166
|
+
chip("search", sessSearch || "\xB7", !!sessSearch)
|
|
9167
|
+
] }),
|
|
9168
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, wrap: "truncate", children: focused ? "\u2191\u2193 select \xB7 enter \u2192 session logs \xB7 f status \xB7 / search \xB7 s source \xB7 v logs \xB7 c clear" : "press \u2192 to browse" }),
|
|
9169
|
+
editing === "sess-search" ? /* @__PURE__ */ jsxs6(Box6, { children: [
|
|
9170
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.warn, children: "search: " }),
|
|
9171
|
+
/* @__PURE__ */ jsx6(
|
|
9172
|
+
TextInput4,
|
|
9173
|
+
{
|
|
9174
|
+
value: sessSearch,
|
|
9175
|
+
onChange: (v) => {
|
|
9176
|
+
setSessSearch(v);
|
|
9177
|
+
setSessSel(0);
|
|
9178
|
+
},
|
|
9179
|
+
onSubmit: () => setEditing(null)
|
|
9180
|
+
}
|
|
9181
|
+
)
|
|
9182
|
+
] }) : null,
|
|
9183
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, wrap: "truncate", children: `${sessionsFiltered.length} sessions \xB7 ${selC + 1}/${sessionsFiltered.length}${start2 ? ` \xB7 \u25B2${start2}` : ""}${start2 + listRows2 < sessionsFiltered.length ? ` \xB7 \u25BC${sessionsFiltered.length - start2 - listRows2}` : ""}` }),
|
|
9184
|
+
/* @__PURE__ */ jsx6(
|
|
9185
|
+
Table,
|
|
9186
|
+
{
|
|
9187
|
+
columns: [
|
|
9188
|
+
{ header: "", width: 2 },
|
|
9189
|
+
{ header: "STATUS", width: 8 },
|
|
9190
|
+
{ header: "AGENT", width: 18 },
|
|
9191
|
+
{ header: "SESSION", width: 10 },
|
|
9192
|
+
{ header: "CALLS", width: 6 },
|
|
9193
|
+
{ header: "DENY", width: 5 },
|
|
9194
|
+
{ header: "DLP", width: 4 },
|
|
9195
|
+
{ header: "TRUST", width: 5 },
|
|
9196
|
+
{ header: "LAST", width: 6 }
|
|
9197
|
+
],
|
|
9198
|
+
rows: win.map((r, i) => {
|
|
9199
|
+
const st = STATUS_DOT[r.status];
|
|
9200
|
+
const isSel = start2 + i === selC && focused;
|
|
9201
|
+
return [
|
|
9202
|
+
{ value: isSel ? "\u25B8" : "", color: theme.accentBright },
|
|
9203
|
+
{ value: `${st.ch} ${r.status}`, color: st.color },
|
|
9204
|
+
{ value: truncate2(r.agent, 18), color: theme.accent, bold: isSel },
|
|
9205
|
+
{ value: r.id.slice(0, 8), dim: true },
|
|
9206
|
+
{ value: String(r.calls) },
|
|
9207
|
+
{ value: String(r.denies), color: r.denies ? theme.bad : void 0, dim: !r.denies },
|
|
9208
|
+
{ value: String(r.dlp), color: r.dlp ? theme.bad : void 0, dim: !r.dlp },
|
|
9209
|
+
{ value: r.trust != null ? String(r.trust) : "\u2014", dim: true },
|
|
9210
|
+
{ value: ago(r.lastAt), dim: true }
|
|
9211
|
+
];
|
|
9212
|
+
})
|
|
9213
|
+
}
|
|
9214
|
+
),
|
|
9215
|
+
sessionsFiltered.length === 0 ? /* @__PURE__ */ jsxs6(Text6, { color: theme.dim, children: [
|
|
9216
|
+
"(no sessions",
|
|
9217
|
+
source === "local" ? " in the local file" : "",
|
|
9218
|
+
")"
|
|
9219
|
+
] }) : null
|
|
9220
|
+
] }) });
|
|
9221
|
+
}
|
|
9222
|
+
const headerRows = 6 + (editing && editing !== "sess-search" ? 1 : 0);
|
|
9132
9223
|
const listRows = Math.max(4, rows - headerRows);
|
|
9133
|
-
const selClamped = Math.min(sel, Math.max(0,
|
|
9134
|
-
const maxStart = Math.max(0,
|
|
9224
|
+
const selClamped = Math.min(sel, Math.max(0, pageRows.length - 1));
|
|
9225
|
+
const maxStart = Math.max(0, pageRows.length - listRows);
|
|
9135
9226
|
const start = Math.min(Math.max(0, selClamped - Math.floor((listRows - 1) / 2)), maxStart);
|
|
9136
|
-
const windowed =
|
|
9227
|
+
const windowed = pageRows.slice(start, start + listRows);
|
|
9137
9228
|
const reasonW = Math.min(60, Math.max(12, cols - 67));
|
|
9138
|
-
|
|
9139
|
-
|
|
9229
|
+
const loading = (source === "cloud" ? cloudQ.loading : localQ.loading) && !editing;
|
|
9230
|
+
return /* @__PURE__ */ jsx6(DataView, { loading, error: source === "cloud" ? cloudQ.error : localQ.error, children: /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
|
|
9231
|
+
strip,
|
|
9232
|
+
/* @__PURE__ */ jsxs6(Box6, { children: [
|
|
9233
|
+
srcChip,
|
|
9234
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.accentBright, bold: true, children: "LOGS" }),
|
|
9235
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: " \xB7 sessions (v) " }),
|
|
9140
9236
|
chip("dec", DECISIONS[di] ?? "all", di !== 0),
|
|
9141
9237
|
chip("sig", SIGNALS[gi] ?? "all", gi !== 0),
|
|
9142
9238
|
chip("tool", tool || "\xB7", !!tool),
|
|
9143
9239
|
chip("agent", agent || "\xB7", !!agent),
|
|
9144
|
-
chip("search", search || "\xB7", !!search)
|
|
9240
|
+
chip("search", search || "\xB7", !!search),
|
|
9241
|
+
sessFilter ? chip("sess", sessFilter.slice(0, 8), true) : null
|
|
9145
9242
|
] }),
|
|
9146
|
-
/* @__PURE__ */
|
|
9147
|
-
editing ? /* @__PURE__ */
|
|
9148
|
-
/* @__PURE__ */
|
|
9243
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, wrap: "truncate", children: focused ? "\u2191\u2193 select \xB7 enter full entry \xB7 \u2190\u2192 page \xB7 f dec \xB7 g sig \xB7 t tool \xB7 n agent \xB7 / search \xB7 s source \xB7 v sessions \xB7 c clear" : "press \u2192 to browse" }),
|
|
9244
|
+
editing && editing !== "sess-search" ? /* @__PURE__ */ jsxs6(Box6, { children: [
|
|
9245
|
+
/* @__PURE__ */ jsxs6(Text6, { color: theme.warn, children: [
|
|
9149
9246
|
editing,
|
|
9150
9247
|
": "
|
|
9151
9248
|
] }),
|
|
9152
|
-
/* @__PURE__ */
|
|
9249
|
+
/* @__PURE__ */ jsx6(
|
|
9153
9250
|
TextInput4,
|
|
9154
9251
|
{
|
|
9155
9252
|
value: editing === "tool" ? tool : editing === "agent" ? agent : search,
|
|
9156
9253
|
onChange: (v) => {
|
|
9157
9254
|
(editing === "tool" ? setTool : editing === "agent" ? setAgent : setSearch)(v);
|
|
9158
|
-
|
|
9255
|
+
setPage(0);
|
|
9256
|
+
toTop();
|
|
9159
9257
|
},
|
|
9160
9258
|
onSubmit: () => setEditing(null)
|
|
9161
9259
|
}
|
|
9162
9260
|
)
|
|
9163
9261
|
] }) : null,
|
|
9164
|
-
/* @__PURE__ */
|
|
9165
|
-
/* @__PURE__ */
|
|
9262
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, wrap: "truncate", children: `${total} matched \xB7 page ${Math.min(page + 1, pages)}/${pages} \xB7 ${PAGE}/page \xB7 ${pageRows.length ? selClamped + 1 : 0}/${pageRows.length}${start ? ` \xB7 \u25B2${start} newer` : ""}${start + listRows < pageRows.length ? ` \xB7 \u25BC${pageRows.length - start - listRows} older` : ""}` }),
|
|
9263
|
+
/* @__PURE__ */ jsx6(
|
|
9166
9264
|
Table,
|
|
9167
9265
|
{
|
|
9168
9266
|
columns: [
|
|
@@ -9176,141 +9274,75 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
9176
9274
|
],
|
|
9177
9275
|
rows: windowed.map((e, i) => rowFor(e, start + i === selClamped && focused, reasonW))
|
|
9178
9276
|
}
|
|
9179
|
-
)
|
|
9277
|
+
),
|
|
9278
|
+
pageRows.length === 0 ? /* @__PURE__ */ jsxs6(Text6, { color: theme.dim, children: [
|
|
9279
|
+
"(no entries",
|
|
9280
|
+
source === "local" ? " in the local file" : "",
|
|
9281
|
+
" \u2014 c clears filters)"
|
|
9282
|
+
] }) : null
|
|
9180
9283
|
] }) });
|
|
9181
9284
|
}
|
|
9182
9285
|
function rowFor(e, active2, reasonW) {
|
|
9183
9286
|
return [
|
|
9184
9287
|
{ value: active2 ? "\u25B8" : "", color: theme.accentBright },
|
|
9185
9288
|
{ value: e.decision, color: decisionColor(e.decision) },
|
|
9186
|
-
{ value: truncate2(e.
|
|
9187
|
-
{ value: truncate2(e.
|
|
9188
|
-
{ value: truncate2(e.reason ?? "\u2014", reasonW) },
|
|
9189
|
-
{ value: e.
|
|
9190
|
-
{ value: ago(e.
|
|
9289
|
+
{ value: truncate2(e.tool, 18), color: theme.accent },
|
|
9290
|
+
{ value: truncate2(e.agent ?? "\u2014", 14), dim: true },
|
|
9291
|
+
{ value: truncate2(e.reason ?? e.args ?? "\u2014", reasonW) },
|
|
9292
|
+
{ value: e.dlp.length ? String(e.dlp.length) : "0", color: e.dlp.length ? theme.bad : void 0, dim: !e.dlp.length },
|
|
9293
|
+
{ value: ago(e.at), dim: true }
|
|
9191
9294
|
];
|
|
9192
9295
|
}
|
|
9193
9296
|
function Detail({ label, value, color }) {
|
|
9194
|
-
return /* @__PURE__ */
|
|
9195
|
-
/* @__PURE__ */
|
|
9196
|
-
/* @__PURE__ */
|
|
9297
|
+
return /* @__PURE__ */ jsxs6(Box6, { children: [
|
|
9298
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: label.padEnd(9) }),
|
|
9299
|
+
/* @__PURE__ */ jsx6(Text6, { color, wrap: "truncate", children: value })
|
|
9197
9300
|
] });
|
|
9198
9301
|
}
|
|
9199
|
-
var DECISIONS, SIGNALS,
|
|
9302
|
+
var DECISIONS, SIGNALS, SESS_STATUS, PAGE, LOCAL_MAX_BYTES, cloudRow, sessStatus2, STATUS_DOT;
|
|
9200
9303
|
var init_Audit = __esm({
|
|
9201
9304
|
"src/tui/panels/Audit.tsx"() {
|
|
9202
9305
|
"use strict";
|
|
9203
9306
|
init_api_client();
|
|
9204
9307
|
init_components();
|
|
9205
9308
|
init_hooks();
|
|
9309
|
+
init_local_log();
|
|
9206
9310
|
init_theme();
|
|
9207
9311
|
DECISIONS = [void 0, "DENY", "ALLOW"];
|
|
9208
9312
|
SIGNALS = [void 0, "dlp", "ratelimit"];
|
|
9209
|
-
|
|
9210
|
-
|
|
9211
|
-
|
|
9212
|
-
|
|
9213
|
-
|
|
9214
|
-
|
|
9215
|
-
|
|
9216
|
-
|
|
9217
|
-
|
|
9218
|
-
|
|
9219
|
-
|
|
9220
|
-
|
|
9221
|
-
|
|
9222
|
-
|
|
9223
|
-
|
|
9224
|
-
|
|
9225
|
-
|
|
9226
|
-
|
|
9227
|
-
|
|
9228
|
-
|
|
9229
|
-
|
|
9230
|
-
|
|
9231
|
-
|
|
9232
|
-
|
|
9233
|
-
|
|
9234
|
-
(_input, key) => {
|
|
9235
|
-
if (key.upArrow) setSel((n) => Math.max(0, n - 1));
|
|
9236
|
-
else if (key.downArrow) setSel((n) => Math.min(agents.length - 1, n + 1));
|
|
9237
|
-
},
|
|
9238
|
-
{ isActive: focused }
|
|
9239
|
-
);
|
|
9240
|
-
const d = detail.data;
|
|
9241
|
-
const base = d?.baseline;
|
|
9242
|
-
const radar = base?.radar;
|
|
9243
|
-
const anomalies2 = d?.anomalies ?? [];
|
|
9244
|
-
const tmap = d?.trust_map;
|
|
9245
|
-
const tools = tmap?.tools ?? [];
|
|
9246
|
-
const resources = tmap?.resources ?? [];
|
|
9247
|
-
const listW = 30;
|
|
9248
|
-
return /* @__PURE__ */ jsx8(DataView, { loading: live2.loading && !live2.data, error: live2.error, empty: !!live2.data && agents.length === 0, emptyText: "No identified agents yet.", children: /* @__PURE__ */ jsxs8(Box8, { children: [
|
|
9249
|
-
/* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", width: listW, marginRight: 2, overflow: "hidden", children: [
|
|
9250
|
-
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: focused ? "\u2191\u2193 select agent" : "press \u2192 to browse" }),
|
|
9251
|
-
agents.slice(0, 16).map((a, i) => /* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", backgroundColor: focused && i === sel ? "#1c2f63" : void 0, bold: i === sel, children: [
|
|
9252
|
-
/* @__PURE__ */ jsxs8(Text8, { color: statusColor(a.status), children: [
|
|
9253
|
-
a.status === "active" ? "\u25CF" : a.status === "idle" ? "\u25D0" : "\u25CB",
|
|
9254
|
-
" "
|
|
9255
|
-
] }),
|
|
9256
|
-
/* @__PURE__ */ jsx8(Text8, { color: theme.accent, children: truncate2(a.agent_name ?? a.agent_id ?? "?", 16).padEnd(17) }),
|
|
9257
|
-
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: `t${a.trust_score}` })
|
|
9258
|
-
] }, a.session_id))
|
|
9259
|
-
] }),
|
|
9260
|
-
/* @__PURE__ */ jsx8(Box8, { flexDirection: "column", flexGrow: 1, overflow: "hidden", children: !selected ? /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "select an agent" }) : detail.loading && !d ? /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "loading profile\u2026" }) : !d ? /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "no profile (agent has no calls yet)" }) : /* @__PURE__ */ jsxs8(Fragment5, { children: [
|
|
9261
|
-
/* @__PURE__ */ jsxs8(Box8, { children: [
|
|
9262
|
-
/* @__PURE__ */ jsx8(Text8, { bold: true, color: theme.accentBright, children: truncate2(selected.agent_name ?? selected.agent_id ?? "?", 22) }),
|
|
9263
|
-
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: ` trust ${base?.trustScore ?? "\u2014"}/100 \xB7 ${base?.character ?? ""}` })
|
|
9264
|
-
] }),
|
|
9265
|
-
base?.characterBlurb ? /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: truncate2(String(base.characterBlurb), 70) }) : null,
|
|
9266
|
-
radar ? /* @__PURE__ */ jsxs8(Box8, { marginTop: 1, flexDirection: "column", children: [
|
|
9267
|
-
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "Behaviour radar (0\u2013100)" }),
|
|
9268
|
-
/* @__PURE__ */ jsx8(Bar, { label: "read", value: Math.round((radar.read ?? 0) * 100) }),
|
|
9269
|
-
/* @__PURE__ */ jsx8(Bar, { label: "write", value: Math.round((radar.write ?? 0) * 100), color: theme.warn }),
|
|
9270
|
-
/* @__PURE__ */ jsx8(Bar, { label: "execute", value: Math.round((radar.execute ?? 0) * 100), color: theme.warn }),
|
|
9271
|
-
/* @__PURE__ */ jsx8(Bar, { label: "network", value: Math.round((radar.network ?? 0) * 100) }),
|
|
9272
|
-
/* @__PURE__ */ jsx8(Bar, { label: "complian.", value: Math.round((radar.compliance ?? 0) * 100), color: theme.ok })
|
|
9273
|
-
] }) : null,
|
|
9274
|
-
/* @__PURE__ */ jsxs8(Box8, { marginTop: 1, flexDirection: "column", children: [
|
|
9275
|
-
/* @__PURE__ */ jsxs8(Text8, { color: theme.dim, children: [
|
|
9276
|
-
"Anomalies ",
|
|
9277
|
-
anomalies2.length ? `(${anomalies2.length})` : ""
|
|
9278
|
-
] }),
|
|
9279
|
-
anomalies2.length === 0 ? /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: " none" }) : anomalies2.slice(0, 4).map((an, i) => /* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", children: [
|
|
9280
|
-
/* @__PURE__ */ jsx8(Text8, { color: sevColor(String(an.severity)), children: ` ${String(an.severity).toUpperCase().slice(0, 4).padEnd(5)}` }),
|
|
9281
|
-
/* @__PURE__ */ jsx8(Text8, { color: theme.accent, children: String(an.kind).padEnd(12) }),
|
|
9282
|
-
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: truncate2(String(an.description ?? ""), 44) })
|
|
9283
|
-
] }, i))
|
|
9284
|
-
] }),
|
|
9285
|
-
/* @__PURE__ */ jsxs8(Box8, { marginTop: 1, flexDirection: "column", children: [
|
|
9286
|
-
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "Trust map \xB7 top tools" }),
|
|
9287
|
-
tools.slice(0, 4).map((t, i) => /* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", children: [
|
|
9288
|
-
/* @__PURE__ */ jsx8(Text8, { color: t.anomalous ? theme.bad : theme.accent, children: ` ${truncate2(String(t.name), 16).padEnd(17)}` }),
|
|
9289
|
-
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: `${t.count}\xD7 ${t.permission ?? ""}` })
|
|
9290
|
-
] }, i)),
|
|
9291
|
-
resources.slice(0, 3).map((r, i) => /* @__PURE__ */ jsx8(Text8, { wrap: "truncate", color: r.anomalous ? theme.bad : theme.dim, children: ` ${r.type === "domain" ? "\u{1F310}" : "\u{1F4C1}"} ${truncate2(String(r.value), 40)} ${r.count}\xD7` }, "r" + i))
|
|
9292
|
-
] })
|
|
9293
|
-
] }) })
|
|
9294
|
-
] }) });
|
|
9295
|
-
}
|
|
9296
|
-
var statusColor, sevColor;
|
|
9297
|
-
var init_Agents = __esm({
|
|
9298
|
-
"src/tui/panels/Agents.tsx"() {
|
|
9299
|
-
"use strict";
|
|
9300
|
-
init_api_client();
|
|
9301
|
-
init_components();
|
|
9302
|
-
init_hooks();
|
|
9303
|
-
init_theme();
|
|
9304
|
-
statusColor = (s) => s === "active" ? theme.ok : s === "idle" ? theme.warn : theme.dim;
|
|
9305
|
-
sevColor = (s) => s === "high" ? theme.bad : s === "medium" ? theme.warn : theme.dim;
|
|
9313
|
+
SESS_STATUS = [void 0, "active", "idle", "ended"];
|
|
9314
|
+
PAGE = 500;
|
|
9315
|
+
LOCAL_MAX_BYTES = 16 * 1024 * 1024;
|
|
9316
|
+
cloudRow = (e) => ({
|
|
9317
|
+
id: e.id,
|
|
9318
|
+
at: Date.parse(e.created_at),
|
|
9319
|
+
tool: e.tool_name,
|
|
9320
|
+
decision: e.decision,
|
|
9321
|
+
permission: e.permission,
|
|
9322
|
+
trust: e.trust_level,
|
|
9323
|
+
agent: e.agent_name,
|
|
9324
|
+
session: e.session_id,
|
|
9325
|
+
reason: e.reason,
|
|
9326
|
+
rule: e.matched_rule_id,
|
|
9327
|
+
evalMs: e.evaluation_time_ms,
|
|
9328
|
+
dlp: e.dlp_matches ?? [],
|
|
9329
|
+
burst: !!e.rate_limit_burst,
|
|
9330
|
+
args: e.arguments_summary ? JSON.stringify(e.arguments_summary) : null
|
|
9331
|
+
});
|
|
9332
|
+
sessStatus2 = (lastAt) => Date.now() - lastAt < 6e4 ? "active" : Date.now() - lastAt < 3e5 ? "idle" : "ended";
|
|
9333
|
+
STATUS_DOT = {
|
|
9334
|
+
active: { ch: "\u25CF", color: theme.ok },
|
|
9335
|
+
idle: { ch: "\u25D0", color: theme.warn },
|
|
9336
|
+
ended: { ch: "\u25CB", color: theme.dim }
|
|
9337
|
+
};
|
|
9306
9338
|
}
|
|
9307
9339
|
});
|
|
9308
9340
|
|
|
9309
9341
|
// src/tui/panels/Settings.tsx
|
|
9310
|
-
import { Box as
|
|
9342
|
+
import { Box as Box7, Text as Text7, useInput as useInput6 } from "ink";
|
|
9311
9343
|
import TextInput5 from "ink-text-input";
|
|
9312
|
-
import { useState as
|
|
9313
|
-
import { jsx as
|
|
9344
|
+
import { useState as useState7 } from "react";
|
|
9345
|
+
import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
9314
9346
|
function alertBodyFor(channel) {
|
|
9315
9347
|
const c2 = channel.trim();
|
|
9316
9348
|
const base = { name: "dataroom alert", threshold: 5, windowSeconds: 60, signal: "any" };
|
|
@@ -9321,12 +9353,12 @@ function alertBodyFor(channel) {
|
|
|
9321
9353
|
function SettingsPanel({ active: active2, focused }) {
|
|
9322
9354
|
void active2;
|
|
9323
9355
|
const { cols, rows } = usePanelSize();
|
|
9324
|
-
const [sel, setSel] =
|
|
9325
|
-
const [editing, setEditing] =
|
|
9326
|
-
const [input, setInput] =
|
|
9327
|
-
const [confirmDel, setConfirmDel] =
|
|
9328
|
-
const [msg, setMsg] =
|
|
9329
|
-
const [busy, setBusy] =
|
|
9356
|
+
const [sel, setSel] = useState7(0);
|
|
9357
|
+
const [editing, setEditing] = useState7(null);
|
|
9358
|
+
const [input, setInput] = useState7("");
|
|
9359
|
+
const [confirmDel, setConfirmDel] = useState7(null);
|
|
9360
|
+
const [msg, setMsg] = useState7(null);
|
|
9361
|
+
const [busy, setBusy] = useState7(false);
|
|
9330
9362
|
const localQ = useLoader(() => api.settings.getLocalLogs());
|
|
9331
9363
|
const whQ = useLoader(() => api.settings.getWebhooks());
|
|
9332
9364
|
const alertQ = useLoader(() => api.settings.getAlerts());
|
|
@@ -9396,7 +9428,7 @@ function SettingsPanel({ active: active2, focused }) {
|
|
|
9396
9428
|
run12("alert rule added", () => api.settings.createAlert(alertBodyFor(v)), alertQ.reload);
|
|
9397
9429
|
}
|
|
9398
9430
|
};
|
|
9399
|
-
|
|
9431
|
+
useInput6(
|
|
9400
9432
|
(inp, key) => {
|
|
9401
9433
|
setMsg(null);
|
|
9402
9434
|
if (key.upArrow) {
|
|
@@ -9435,7 +9467,7 @@ function SettingsPanel({ active: active2, focused }) {
|
|
|
9435
9467
|
const loading = localQ.loading && !localQ.data || whQ.loading && !whQ.data || alertQ.loading && !alertQ.data;
|
|
9436
9468
|
const error = localQ.error ?? whQ.error ?? alertQ.error;
|
|
9437
9469
|
const mark = (r) => keyOf(r) === keyOf(cur) && focused ? "\u25B8 " : " ";
|
|
9438
|
-
const onOff = (on) => on ? /* @__PURE__ */
|
|
9470
|
+
const onOff = (on) => on ? /* @__PURE__ */ jsx7(Text7, { color: theme.ok, children: "on " }) : /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "off" });
|
|
9439
9471
|
const chanOf = (rule) => [...(rule.slackUrls ?? []).map((u) => "slack " + u), ...rule.emails ?? [], ...(rule.telegram ?? []).map((t) => "tg " + t)].join(", ") || "\u2014";
|
|
9440
9472
|
const listBudget = Math.max(4, rows - 8);
|
|
9441
9473
|
const start = Math.min(Math.max(0, selClamped - Math.floor(listBudget / 2)), Math.max(0, rowsAll.length - listBudget));
|
|
@@ -9443,68 +9475,68 @@ function SettingsPanel({ active: active2, focused }) {
|
|
|
9443
9475
|
const i = rowsAll.findIndex((x) => keyOf(x) === keyOf(r));
|
|
9444
9476
|
return i >= start && i < start + listBudget;
|
|
9445
9477
|
};
|
|
9446
|
-
return /* @__PURE__ */
|
|
9447
|
-
/* @__PURE__ */
|
|
9448
|
-
editing ? /* @__PURE__ */
|
|
9449
|
-
/* @__PURE__ */
|
|
9450
|
-
/* @__PURE__ */
|
|
9451
|
-
] }) : msg ? /* @__PURE__ */
|
|
9452
|
-
inWindow(rowsAll[0]) || inWindow(rowsAll[1]) ? /* @__PURE__ */
|
|
9453
|
-
/* @__PURE__ */
|
|
9478
|
+
return /* @__PURE__ */ jsx7(DataView, { loading, error, children: /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
|
|
9479
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: focused ? "\u2191\u2193 move \xB7 enter/space toggle-edit-add \xB7 e events \xB7 d delete \xB7 r refresh" : "press \u2192 to configure" }),
|
|
9480
|
+
editing ? /* @__PURE__ */ jsxs7(Box7, { children: [
|
|
9481
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.warn, children: editing === "path" ? "local log path: " : editing === "wh-url" ? "webhook url: " : "channel (slack url / email / telegram id): " }),
|
|
9482
|
+
/* @__PURE__ */ jsx7(TextInput5, { value: input, onChange: setInput, onSubmit: submitInput })
|
|
9483
|
+
] }) : msg ? /* @__PURE__ */ jsx7(Text7, { color: msg.level === "bad" ? theme.bad : theme.ok, children: truncate2(msg.text, cols) }) : /* @__PURE__ */ jsx7(Text7, { children: " " }),
|
|
9484
|
+
inWindow(rowsAll[0]) || inWindow(rowsAll[1]) ? /* @__PURE__ */ jsxs7(Box7, { marginTop: 1, flexDirection: "column", children: [
|
|
9485
|
+
/* @__PURE__ */ jsxs7(Text7, { bold: true, color: theme.accentBright, children: [
|
|
9454
9486
|
"LOCAL LOGS ",
|
|
9455
|
-
/* @__PURE__ */
|
|
9487
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "\u2014 hooks mirror every decision to a file on the agent machine" })
|
|
9456
9488
|
] }),
|
|
9457
|
-
/* @__PURE__ */
|
|
9458
|
-
/* @__PURE__ */
|
|
9459
|
-
/* @__PURE__ */
|
|
9489
|
+
/* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
|
|
9490
|
+
/* @__PURE__ */ jsx7(Text7, { color: keyOf(cur) === "ll-enabled" && focused ? theme.accentBright : theme.dim, children: mark(rowsAll[0]) }),
|
|
9491
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "enabled ".padEnd(10) }),
|
|
9460
9492
|
onOff(!!local?.enabled),
|
|
9461
|
-
/* @__PURE__ */
|
|
9493
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: " enter toggles" })
|
|
9462
9494
|
] }),
|
|
9463
|
-
/* @__PURE__ */
|
|
9464
|
-
/* @__PURE__ */
|
|
9465
|
-
/* @__PURE__ */
|
|
9466
|
-
local?.path ? /* @__PURE__ */
|
|
9495
|
+
/* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
|
|
9496
|
+
/* @__PURE__ */ jsx7(Text7, { color: keyOf(cur) === "ll-path" && focused ? theme.accentBright : theme.dim, children: mark(rowsAll[1]) }),
|
|
9497
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "path ".padEnd(10) }),
|
|
9498
|
+
local?.path ? /* @__PURE__ */ jsx7(Text7, { color: theme.accent, children: truncate2(local.path, cols - 14) }) : /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "not set \u2014 enter to edit" })
|
|
9467
9499
|
] })
|
|
9468
9500
|
] }) : null,
|
|
9469
|
-
/* @__PURE__ */
|
|
9470
|
-
/* @__PURE__ */
|
|
9501
|
+
/* @__PURE__ */ jsxs7(Box7, { marginTop: 1, flexDirection: "column", children: [
|
|
9502
|
+
/* @__PURE__ */ jsxs7(Text7, { bold: true, color: theme.accentBright, children: [
|
|
9471
9503
|
"WEBHOOKS ",
|
|
9472
|
-
/* @__PURE__ */
|
|
9504
|
+
/* @__PURE__ */ jsxs7(Text7, { color: theme.dim, children: [
|
|
9473
9505
|
"\u2014 POST every matching event to your endpoint (",
|
|
9474
9506
|
webhooks.length,
|
|
9475
9507
|
")"
|
|
9476
9508
|
] })
|
|
9477
9509
|
] }),
|
|
9478
|
-
webhooks.filter((wh) => inWindow({ kind: "wh", wh })).map((wh) => /* @__PURE__ */
|
|
9479
|
-
/* @__PURE__ */
|
|
9510
|
+
webhooks.filter((wh) => inWindow({ kind: "wh", wh })).map((wh) => /* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
|
|
9511
|
+
/* @__PURE__ */ jsx7(Text7, { color: keyOf(cur) === "wh:" + wh.id && focused ? theme.accentBright : theme.dim, children: mark({ kind: "wh", wh }) }),
|
|
9480
9512
|
onOff(wh.enabled),
|
|
9481
|
-
/* @__PURE__ */
|
|
9482
|
-
/* @__PURE__ */
|
|
9513
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.warn, children: (" " + wh.events).padEnd(9) }),
|
|
9514
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.accent, children: truncate2(wh.url, cols - 16) })
|
|
9483
9515
|
] }, wh.id)),
|
|
9484
|
-
inWindow(rowsAll.find((r) => r.kind === "wh-add")) ? /* @__PURE__ */
|
|
9485
|
-
/* @__PURE__ */
|
|
9486
|
-
/* @__PURE__ */
|
|
9516
|
+
inWindow(rowsAll.find((r) => r.kind === "wh-add")) ? /* @__PURE__ */ jsxs7(Text7, { children: [
|
|
9517
|
+
/* @__PURE__ */ jsx7(Text7, { color: cur.kind === "wh-add" && focused ? theme.accentBright : theme.dim, children: mark({ kind: "wh-add" }) }),
|
|
9518
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "+ add webhook (enter)" })
|
|
9487
9519
|
] }) : null
|
|
9488
9520
|
] }),
|
|
9489
|
-
/* @__PURE__ */
|
|
9490
|
-
/* @__PURE__ */
|
|
9521
|
+
/* @__PURE__ */ jsxs7(Box7, { marginTop: 1, flexDirection: "column", children: [
|
|
9522
|
+
/* @__PURE__ */ jsxs7(Text7, { bold: true, color: theme.accentBright, children: [
|
|
9491
9523
|
"ALERTS ",
|
|
9492
|
-
/* @__PURE__ */
|
|
9524
|
+
/* @__PURE__ */ jsxs7(Text7, { color: theme.dim, children: [
|
|
9493
9525
|
"\u2014 notify on a signal spike (",
|
|
9494
9526
|
alerts.length,
|
|
9495
9527
|
")"
|
|
9496
9528
|
] })
|
|
9497
9529
|
] }),
|
|
9498
|
-
alerts.filter((rule) => inWindow({ kind: "alert", rule })).map((rule) => /* @__PURE__ */
|
|
9499
|
-
/* @__PURE__ */
|
|
9530
|
+
alerts.filter((rule) => inWindow({ kind: "alert", rule })).map((rule) => /* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
|
|
9531
|
+
/* @__PURE__ */ jsx7(Text7, { color: keyOf(cur) === "alert:" + rule.id && focused ? theme.accentBright : theme.dim, children: mark({ kind: "alert", rule }) }),
|
|
9500
9532
|
onOff(rule.enabled),
|
|
9501
|
-
/* @__PURE__ */
|
|
9502
|
-
/* @__PURE__ */
|
|
9503
|
-
/* @__PURE__ */
|
|
9533
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.warn, children: (" " + rule.signal).padEnd(11) }),
|
|
9534
|
+
/* @__PURE__ */ jsx7(Text7, { children: `\u2265${rule.threshold}/${rule.windowSeconds}s ` }),
|
|
9535
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.accent, children: truncate2(chanOf(rule), cols - 26) })
|
|
9504
9536
|
] }, rule.id)),
|
|
9505
|
-
inWindow(rowsAll[rowsAll.length - 1]) ? /* @__PURE__ */
|
|
9506
|
-
/* @__PURE__ */
|
|
9507
|
-
/* @__PURE__ */
|
|
9537
|
+
inWindow(rowsAll[rowsAll.length - 1]) ? /* @__PURE__ */ jsxs7(Text7, { children: [
|
|
9538
|
+
/* @__PURE__ */ jsx7(Text7, { color: cur.kind === "alert-add" && focused ? theme.accentBright : theme.dim, children: mark({ kind: "alert-add" }) }),
|
|
9539
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "+ add alert (enter \u2014 one channel: slack url, email or telegram chat id)" })
|
|
9508
9540
|
] }) : null
|
|
9509
9541
|
] })
|
|
9510
9542
|
] }) });
|
|
@@ -9522,17 +9554,17 @@ var init_Settings = __esm({
|
|
|
9522
9554
|
});
|
|
9523
9555
|
|
|
9524
9556
|
// src/tui/App.tsx
|
|
9525
|
-
import { Box as
|
|
9526
|
-
import { useState as
|
|
9527
|
-
import { jsx as
|
|
9557
|
+
import { Box as Box8, Text as Text8, useApp, useInput as useInput7 } from "ink";
|
|
9558
|
+
import { useState as useState8 } from "react";
|
|
9559
|
+
import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
9528
9560
|
function LiveHint() {
|
|
9529
|
-
return /* @__PURE__ */
|
|
9530
|
-
/* @__PURE__ */
|
|
9531
|
-
/* @__PURE__ */
|
|
9532
|
-
/* @__PURE__ */
|
|
9533
|
-
/* @__PURE__ */
|
|
9561
|
+
return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
|
|
9562
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.accentBright, bold: true, children: "\u25B6 REALTIME CONSOLE" }),
|
|
9563
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "Fullscreen live monitor \u2014 streaming tool calls, active charts," }),
|
|
9564
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "counters, DLP hits and denial alerts. Updates every 2s." }),
|
|
9565
|
+
/* @__PURE__ */ jsx8(Box8, { marginTop: 1, children: /* @__PURE__ */ jsxs8(Text8, { children: [
|
|
9534
9566
|
"press ",
|
|
9535
|
-
/* @__PURE__ */
|
|
9567
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.accent, children: "enter" }),
|
|
9536
9568
|
" to go live"
|
|
9537
9569
|
] }) })
|
|
9538
9570
|
] });
|
|
@@ -9540,22 +9572,22 @@ function LiveHint() {
|
|
|
9540
9572
|
function Banner({ cols }) {
|
|
9541
9573
|
const wide = cols >= 82;
|
|
9542
9574
|
if (!wide) {
|
|
9543
|
-
return /* @__PURE__ */
|
|
9544
|
-
/* @__PURE__ */
|
|
9545
|
-
/* @__PURE__ */
|
|
9575
|
+
return /* @__PURE__ */ jsxs8(Box8, { children: [
|
|
9576
|
+
/* @__PURE__ */ jsx8(Text8, { bold: true, color: theme.accentBright, children: "SolonGate" }),
|
|
9577
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: " \u2014 security control center" })
|
|
9546
9578
|
] });
|
|
9547
9579
|
}
|
|
9548
|
-
return /* @__PURE__ */
|
|
9549
|
-
BANNER_FULL.map((line, i) => /* @__PURE__ */
|
|
9550
|
-
/* @__PURE__ */
|
|
9580
|
+
return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
|
|
9581
|
+
BANNER_FULL.map((line, i) => /* @__PURE__ */ jsx8(Text8, { bold: true, color: BANNER_HEX[i], children: line }, i)),
|
|
9582
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: " security control center \xB7 manage policies, rate limits, DLP & more" })
|
|
9551
9583
|
] });
|
|
9552
9584
|
}
|
|
9553
9585
|
function App() {
|
|
9554
9586
|
const { exit } = useApp();
|
|
9555
|
-
const [section, setSection] =
|
|
9556
|
-
const [focus, setFocus] =
|
|
9557
|
-
const [help, setHelp] =
|
|
9558
|
-
|
|
9587
|
+
const [section, setSection] = useState8(0);
|
|
9588
|
+
const [focus, setFocus] = useState8("nav");
|
|
9589
|
+
const [help, setHelp] = useState8(false);
|
|
9590
|
+
useInput7((input, key) => {
|
|
9559
9591
|
if (help) {
|
|
9560
9592
|
setHelp(false);
|
|
9561
9593
|
return;
|
|
@@ -9576,31 +9608,31 @@ function App() {
|
|
|
9576
9608
|
});
|
|
9577
9609
|
const { cols, rows } = useTermSize();
|
|
9578
9610
|
const current = SECTIONS[section];
|
|
9579
|
-
if (help) return /* @__PURE__ */
|
|
9611
|
+
if (help) return /* @__PURE__ */ jsx8(HelpOverlay, { cols, rows });
|
|
9580
9612
|
if (current.label === "Live" && focus === "panel") {
|
|
9581
|
-
return /* @__PURE__ */
|
|
9613
|
+
return /* @__PURE__ */ jsx8(Box8, { flexDirection: "column", width: cols, height: rows, children: /* @__PURE__ */ jsx8(LivePanel, { active: true, focused: true }) });
|
|
9582
9614
|
}
|
|
9583
9615
|
const Panel = current.Panel;
|
|
9584
|
-
return /* @__PURE__ */
|
|
9585
|
-
/* @__PURE__ */
|
|
9586
|
-
/* @__PURE__ */
|
|
9587
|
-
/* @__PURE__ */
|
|
9588
|
-
/* @__PURE__ */
|
|
9616
|
+
return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", width: cols, height: rows, paddingX: 1, paddingTop: 1, children: [
|
|
9617
|
+
/* @__PURE__ */ jsx8(Banner, { cols }),
|
|
9618
|
+
/* @__PURE__ */ jsxs8(Box8, { marginTop: 1, flexGrow: 1, children: [
|
|
9619
|
+
/* @__PURE__ */ jsx8(Box8, { flexDirection: "column", width: 16, borderStyle: "round", borderColor: focus === "nav" ? theme.accent : "gray", paddingX: 1, children: SECTIONS.map((s, i) => /* @__PURE__ */ jsx8(Text8, { color: i === section ? theme.accentBright : void 0, bold: i === section, children: (i === section ? "\u25B8 " : " ") + s.label }, s.label)) }),
|
|
9620
|
+
/* @__PURE__ */ jsx8(Box8, { flexGrow: 1, borderStyle: "round", borderColor: focus === "panel" ? theme.accent : "gray", paddingX: 1, paddingY: 0, children: /* @__PURE__ */ jsx8(Panel, { active: focus === "panel" || current.label !== "Live", focused: focus === "panel" }) })
|
|
9589
9621
|
] }),
|
|
9590
|
-
/* @__PURE__ */
|
|
9622
|
+
/* @__PURE__ */ jsx8(Box8, { children: focus === "nav" ? /* @__PURE__ */ jsx8(KeyHints, { hints: [["\u2191\u2193", "section"], ["\u2192/enter", "open"], ["?", "help"], ["q", "quit"]] }) : /* @__PURE__ */ jsx8(KeyHints, { hints: [["\u2190/esc", "back"], ["\u2191\u2193", "in-panel"], ["space/s", "act"]] }) })
|
|
9591
9623
|
] });
|
|
9592
9624
|
}
|
|
9593
9625
|
function HelpOverlay({ cols, rows }) {
|
|
9594
|
-
return /* @__PURE__ */
|
|
9595
|
-
/* @__PURE__ */
|
|
9596
|
-
/* @__PURE__ */
|
|
9597
|
-
/* @__PURE__ */
|
|
9598
|
-
keys.map(([k, desc]) => /* @__PURE__ */
|
|
9599
|
-
/* @__PURE__ */
|
|
9600
|
-
/* @__PURE__ */
|
|
9626
|
+
return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", width: cols, height: rows, paddingX: 2, paddingTop: 1, children: [
|
|
9627
|
+
/* @__PURE__ */ jsx8(Text8, { bold: true, color: theme.accentBright, children: "SolonGate \u2014 keyboard shortcuts" }),
|
|
9628
|
+
/* @__PURE__ */ jsx8(Box8, { marginTop: 1, flexDirection: "column", children: HELP.map(([group, keys]) => /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", marginBottom: 1, children: [
|
|
9629
|
+
/* @__PURE__ */ jsx8(Text8, { bold: true, color: theme.accent, children: group }),
|
|
9630
|
+
keys.map(([k, desc]) => /* @__PURE__ */ jsxs8(Text8, { children: [
|
|
9631
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.accentBright, children: (" " + k).padEnd(16) }),
|
|
9632
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: desc })
|
|
9601
9633
|
] }, k))
|
|
9602
9634
|
] }, group)) }),
|
|
9603
|
-
/* @__PURE__ */
|
|
9635
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "press any key to close" })
|
|
9604
9636
|
] });
|
|
9605
9637
|
}
|
|
9606
9638
|
var SECTIONS, BANNER_HEX, HELP;
|
|
@@ -9614,18 +9646,14 @@ var init_App = __esm({
|
|
|
9614
9646
|
init_Policies();
|
|
9615
9647
|
init_RateLimit();
|
|
9616
9648
|
init_Dlp();
|
|
9617
|
-
init_Stats();
|
|
9618
9649
|
init_Audit();
|
|
9619
|
-
init_Agents();
|
|
9620
9650
|
init_Settings();
|
|
9621
9651
|
init_hooks();
|
|
9622
9652
|
SECTIONS = [
|
|
9623
9653
|
{ label: "Live", Panel: LiveHint },
|
|
9624
|
-
{ label: "Agents", Panel: AgentsPanel },
|
|
9625
9654
|
{ label: "Policies", Panel: PoliciesPanel },
|
|
9626
9655
|
{ label: "Rate Limit", Panel: RateLimitPanel },
|
|
9627
9656
|
{ label: "DLP", Panel: DlpPanel },
|
|
9628
|
-
{ label: "Stats", Panel: StatsPanel },
|
|
9629
9657
|
{ label: "Audit", Panel: AuditPanel },
|
|
9630
9658
|
{ label: "Settings", Panel: SettingsPanel }
|
|
9631
9659
|
];
|
|
@@ -9633,9 +9661,9 @@ var init_App = __esm({
|
|
|
9633
9661
|
HELP = [
|
|
9634
9662
|
["Global", [["\u2191\u2193", "move between sections"], ["\u2192 / enter", "open a section"], ["\u2190 / esc", "back to the menu"], ["?", "this help"], ["q", "quit"]]],
|
|
9635
9663
|
["Live", [["\u2191\u2193", "select a stream row"], ["enter", "full entry content"], ["w", "whitelist the selected DENY"], ["b", "block the selected ALLOW"], ["d / x / r", "filter denies / dlp / rate-limit"], ["f", "local / cloud filter"], ["/", "search"], ["s", "sessions (\u2191\u2193 pick, enter open)"], ["space", "copy mode (freeze)"]]],
|
|
9636
|
-
["Policies", [["\u2191\u2193", "browse / select"], ["a", "activate (pin) selected policy"], ["x", "deactivate \u2014 no active policy"], ["enter", "open rules \u2192 open a rule"], ["space", "toggle a rule on/off"], ["e", "flip effect"], ["n", "new rule"], ["d", "delete rule"], ["m", "flip mode"], ["D", "dry-run the draft"], ["
|
|
9664
|
+
["Policies", [["\u2191\u2193", "browse / select"], ["a", "activate (pin) selected policy"], ["x", "deactivate \u2014 no active policy"], ["enter", "open rules \u2192 open a rule"], ["space", "toggle a rule on/off"], ["e", "flip effect"], ["n", "new rule"], ["d", "delete rule"], ["m", "flip mode"], ["D", "dry-run the draft"], ["s", "save"], ["x", "discard"]]],
|
|
9637
9665
|
["Rate limit / DLP", [["\u2191\u2193", "field / pattern"], ["\u2190\u2192", "adjust (shift = \xB110)"], ["space", "toggle pattern"], ["m", "mode"], ["a / d", "add / remove custom"], ["g", "ghost mode"], ["P", "self-protection"], ["s", "save"]]],
|
|
9638
|
-
["Audit", [["\u2191\u2193", "select (list scrolls)"], ["enter", "full entry
|
|
9666
|
+
["Audit", [["v", "logs \u2194 sessions"], ["s", "source: cloud \u2194 local"], ["\u2190 \u2192", "prev / next page (500 each)"], ["\u2191\u2193", "select (list scrolls)"], ["enter", "full entry / session logs"], ["f / g", "decision / signal filter"], ["t / n / /", "tool / agent / search"], ["c", "clear filters"]]],
|
|
9639
9667
|
["Settings", [["\u2191\u2193", "move"], ["enter / space", "toggle \xB7 edit \xB7 add"], ["e", "webhook events"], ["d d", "delete"], ["r", "refresh"]]]
|
|
9640
9668
|
];
|
|
9641
9669
|
}
|
|
@@ -9647,7 +9675,7 @@ __export(tui_exports, {
|
|
|
9647
9675
|
launchTui: () => launchTui
|
|
9648
9676
|
});
|
|
9649
9677
|
import { render } from "ink";
|
|
9650
|
-
import { jsx as
|
|
9678
|
+
import { jsx as jsx9 } from "react/jsx-runtime";
|
|
9651
9679
|
async function launchTui() {
|
|
9652
9680
|
if (!process.stdout.isTTY || !process.stdin.isTTY) {
|
|
9653
9681
|
process.stderr.write(
|
|
@@ -9661,7 +9689,7 @@ async function launchTui() {
|
|
|
9661
9689
|
}
|
|
9662
9690
|
process.stdout.write("\x1B[?1049h\x1B[H");
|
|
9663
9691
|
try {
|
|
9664
|
-
const { waitUntilExit } = render(/* @__PURE__ */
|
|
9692
|
+
const { waitUntilExit } = render(/* @__PURE__ */ jsx9(App, {}));
|
|
9665
9693
|
await waitUntilExit();
|
|
9666
9694
|
} finally {
|
|
9667
9695
|
process.stdout.write("\x1B[?1049l");
|
|
@@ -10312,7 +10340,7 @@ async function runAgents(argv) {
|
|
|
10312
10340
|
table(
|
|
10313
10341
|
["STATUS", "AGENT", "CALLS", "DENY", "DLP", "TRUST", "CHARACTER"],
|
|
10314
10342
|
res.agents.map((a) => [
|
|
10315
|
-
|
|
10343
|
+
statusColor(a.status),
|
|
10316
10344
|
cyan(truncate3(a.agent_name ?? a.agent_id ?? a.session_id, 20)),
|
|
10317
10345
|
String(a.total_calls),
|
|
10318
10346
|
a.denied_calls ? red(String(a.denied_calls)) : dim("0"),
|
|
@@ -10331,7 +10359,7 @@ async function runAgent(argv) {
|
|
|
10331
10359
|
const a = await api.agents.get(id);
|
|
10332
10360
|
if (json) return printJson(a), 0;
|
|
10333
10361
|
err("");
|
|
10334
|
-
err(` ${bold(a.agent_id)} status: ${
|
|
10362
|
+
err(` ${bold(a.agent_id)} status: ${statusColor(String(a.status))}`);
|
|
10335
10363
|
const base = a.baseline;
|
|
10336
10364
|
if (base) {
|
|
10337
10365
|
err(` ${dim(base.character ?? "")} trust ${bold(String(base.trustScore ?? "\u2014"))}/100 deny-rate ${(Number(base.denyRate ?? 0) * 100).toFixed(0)}%`);
|
|
@@ -10351,21 +10379,21 @@ async function runAgent(argv) {
|
|
|
10351
10379
|
}
|
|
10352
10380
|
return 0;
|
|
10353
10381
|
}
|
|
10354
|
-
var
|
|
10382
|
+
var statusColor;
|
|
10355
10383
|
var init_agents2 = __esm({
|
|
10356
10384
|
"src/commands/agents.ts"() {
|
|
10357
10385
|
"use strict";
|
|
10358
10386
|
init_api_client();
|
|
10359
10387
|
init_args();
|
|
10360
10388
|
init_format();
|
|
10361
|
-
|
|
10389
|
+
statusColor = (s) => s === "active" ? green(s) : s === "idle" ? yellow(s) : dim(s);
|
|
10362
10390
|
}
|
|
10363
10391
|
});
|
|
10364
10392
|
|
|
10365
10393
|
// src/commands/doctor.ts
|
|
10366
10394
|
import { existsSync as existsSync4, statSync as statSync2 } from "fs";
|
|
10367
|
-
import { homedir as
|
|
10368
|
-
import { join as
|
|
10395
|
+
import { homedir as homedir6 } from "os";
|
|
10396
|
+
import { join as join8 } from "path";
|
|
10369
10397
|
async function run6(argv) {
|
|
10370
10398
|
const { flags } = parse(argv);
|
|
10371
10399
|
const json = flagBool(flags, "json");
|
|
@@ -10425,14 +10453,14 @@ var init_doctor = __esm({
|
|
|
10425
10453
|
init_api_client();
|
|
10426
10454
|
init_format();
|
|
10427
10455
|
init_args();
|
|
10428
|
-
LOCAL_LOG2 =
|
|
10456
|
+
LOCAL_LOG2 = join8(homedir6(), ".solongate", "local-logs", "solongate-audit.jsonl");
|
|
10429
10457
|
}
|
|
10430
10458
|
});
|
|
10431
10459
|
|
|
10432
10460
|
// src/commands/watch.ts
|
|
10433
10461
|
import { closeSync as closeSync2, existsSync as existsSync5, openSync as openSync2, readSync as readSync2, statSync as statSync3 } from "fs";
|
|
10434
|
-
import { homedir as
|
|
10435
|
-
import { join as
|
|
10462
|
+
import { homedir as homedir7 } from "os";
|
|
10463
|
+
import { join as join9 } from "path";
|
|
10436
10464
|
function tailLocal(file, maxBytes = 131072) {
|
|
10437
10465
|
try {
|
|
10438
10466
|
const size = statSync3(file).size;
|
|
@@ -10539,7 +10567,7 @@ var init_watch = __esm({
|
|
|
10539
10567
|
init_cli_utils();
|
|
10540
10568
|
init_args();
|
|
10541
10569
|
init_format();
|
|
10542
|
-
LOCAL_LOG3 =
|
|
10570
|
+
LOCAL_LOG3 = join9(homedir7(), ".solongate", "local-logs", "solongate-audit.jsonl");
|
|
10543
10571
|
trunc = (s, n) => s.length <= n ? s : s.slice(0, n - 1) + "\u2026";
|
|
10544
10572
|
time = (ms) => new Date(ms).toTimeString().slice(0, 8);
|
|
10545
10573
|
}
|
|
@@ -10842,8 +10870,8 @@ __export(global_install_exports, {
|
|
|
10842
10870
|
unlockProtected: () => unlockProtected
|
|
10843
10871
|
});
|
|
10844
10872
|
import { readFileSync as readFileSync7, writeFileSync as writeFileSync4, existsSync as existsSync6, mkdirSync as mkdirSync4 } from "fs";
|
|
10845
|
-
import { resolve as resolve4, join as
|
|
10846
|
-
import { homedir as
|
|
10873
|
+
import { resolve as resolve4, join as join10, dirname } from "path";
|
|
10874
|
+
import { homedir as homedir8 } from "os";
|
|
10847
10875
|
import { fileURLToPath } from "url";
|
|
10848
10876
|
import { createInterface } from "readline";
|
|
10849
10877
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
@@ -10906,10 +10934,10 @@ function unlockFile(file) {
|
|
|
10906
10934
|
function protectedTargets() {
|
|
10907
10935
|
const p = globalPaths();
|
|
10908
10936
|
return [
|
|
10909
|
-
|
|
10910
|
-
|
|
10911
|
-
|
|
10912
|
-
|
|
10937
|
+
join10(p.hooksDir, "guard.mjs"),
|
|
10938
|
+
join10(p.hooksDir, "audit.mjs"),
|
|
10939
|
+
join10(p.hooksDir, "stop.mjs"),
|
|
10940
|
+
join10(p.hooksDir, "shield.mjs"),
|
|
10913
10941
|
p.configPath,
|
|
10914
10942
|
p.settingsPath
|
|
10915
10943
|
];
|
|
@@ -10921,25 +10949,25 @@ function unlockProtected() {
|
|
|
10921
10949
|
for (const f of protectedTargets()) unlockFile(f);
|
|
10922
10950
|
}
|
|
10923
10951
|
function globalPaths() {
|
|
10924
|
-
const home =
|
|
10925
|
-
const sgDir =
|
|
10926
|
-
const hooksDir =
|
|
10927
|
-
const claudeDir =
|
|
10952
|
+
const home = homedir8();
|
|
10953
|
+
const sgDir = join10(home, ".solongate");
|
|
10954
|
+
const hooksDir = join10(sgDir, "hooks");
|
|
10955
|
+
const claudeDir = join10(home, ".claude");
|
|
10928
10956
|
return {
|
|
10929
10957
|
home,
|
|
10930
10958
|
sgDir,
|
|
10931
10959
|
hooksDir,
|
|
10932
10960
|
claudeDir,
|
|
10933
|
-
settingsPath:
|
|
10934
|
-
backupPath:
|
|
10935
|
-
configPath:
|
|
10961
|
+
settingsPath: join10(claudeDir, "settings.json"),
|
|
10962
|
+
backupPath: join10(claudeDir, "settings.solongate.bak"),
|
|
10963
|
+
configPath: join10(sgDir, "cloud-guard.json")
|
|
10936
10964
|
};
|
|
10937
10965
|
}
|
|
10938
10966
|
function readHook(filename) {
|
|
10939
|
-
return readFileSync7(
|
|
10967
|
+
return readFileSync7(join10(HOOKS_DIR, filename), "utf-8");
|
|
10940
10968
|
}
|
|
10941
10969
|
function readGuard() {
|
|
10942
|
-
const bundled =
|
|
10970
|
+
const bundled = join10(HOOKS_DIR, "guard.bundled.mjs");
|
|
10943
10971
|
return existsSync6(bundled) ? readFileSync7(bundled, "utf-8") : readHook("guard.mjs");
|
|
10944
10972
|
}
|
|
10945
10973
|
function ask(question) {
|
|
@@ -10994,7 +11022,7 @@ function shimTargets() {
|
|
|
10994
11022
|
return [];
|
|
10995
11023
|
}
|
|
10996
11024
|
}
|
|
10997
|
-
return [".bashrc", ".zshrc", ".profile"].map((f) =>
|
|
11025
|
+
return [".bashrc", ".zshrc", ".profile"].map((f) => join10(homedir8(), f)).filter((f) => existsSync6(f));
|
|
10998
11026
|
}
|
|
10999
11027
|
function writeShimBlock(file, block2) {
|
|
11000
11028
|
const re = new RegExp(escapeRe(SHIM_BEGIN) + "[\\s\\S]*?" + escapeRe(SHIM_END) + "\\r?\\n?", "g");
|
|
@@ -11059,12 +11087,12 @@ async function runGlobalInstall(opts = {}) {
|
|
|
11059
11087
|
mkdirSync4(p.hooksDir, { recursive: true });
|
|
11060
11088
|
mkdirSync4(p.claudeDir, { recursive: true });
|
|
11061
11089
|
unlockProtected();
|
|
11062
|
-
writeFileSync4(
|
|
11063
|
-
writeFileSync4(
|
|
11064
|
-
writeFileSync4(
|
|
11065
|
-
writeFileSync4(
|
|
11090
|
+
writeFileSync4(join10(p.hooksDir, "guard.mjs"), readGuard());
|
|
11091
|
+
writeFileSync4(join10(p.hooksDir, "audit.mjs"), readHook("audit.mjs"));
|
|
11092
|
+
writeFileSync4(join10(p.hooksDir, "stop.mjs"), readHook("stop.mjs"));
|
|
11093
|
+
writeFileSync4(join10(p.hooksDir, "shield.mjs"), readHook("shield.mjs"));
|
|
11066
11094
|
console.log(` Installed hooks \u2192 ${p.hooksDir}`);
|
|
11067
|
-
installClaudeShim(
|
|
11095
|
+
installClaudeShim(join10(p.hooksDir, "shield.mjs"));
|
|
11068
11096
|
writeFileSync4(p.configPath, JSON.stringify({ apiKey, apiUrl }, null, 2) + "\n");
|
|
11069
11097
|
console.log(` Wrote ${p.configPath}`);
|
|
11070
11098
|
let existing = {};
|
|
@@ -11080,9 +11108,9 @@ async function runGlobalInstall(opts = {}) {
|
|
|
11080
11108
|
existing = {};
|
|
11081
11109
|
}
|
|
11082
11110
|
}
|
|
11083
|
-
const guardAbs =
|
|
11084
|
-
const auditAbs =
|
|
11085
|
-
const stopAbs =
|
|
11111
|
+
const guardAbs = join10(p.hooksDir, "guard.mjs").replace(/\\/g, "/");
|
|
11112
|
+
const auditAbs = join10(p.hooksDir, "audit.mjs").replace(/\\/g, "/");
|
|
11113
|
+
const stopAbs = join10(p.hooksDir, "stop.mjs").replace(/\\/g, "/");
|
|
11086
11114
|
const nodeBin = process.execPath.replace(/\\/g, "/");
|
|
11087
11115
|
const call = process.platform === "win32" ? "& " : "";
|
|
11088
11116
|
const hookCmd = (script) => `${call}"${nodeBin}" "${script}" claude-code "Claude Code"`;
|
|
@@ -11276,9 +11304,9 @@ import { spawn as spawn3 } from "child_process";
|
|
|
11276
11304
|
import { URL as URL2 } from "url";
|
|
11277
11305
|
import { readFileSync as readFileSync8, existsSync as existsSync7, readdirSync, statSync as statSync4 } from "fs";
|
|
11278
11306
|
import { resolve as resolve5 } from "path";
|
|
11279
|
-
import { homedir as
|
|
11307
|
+
import { homedir as homedir9 } from "os";
|
|
11280
11308
|
function findCacheFile() {
|
|
11281
|
-
const dir = resolve5(
|
|
11309
|
+
const dir = resolve5(homedir9(), ".solongate");
|
|
11282
11310
|
const envSel = process.env.SOLONGATE_AGENT_ID;
|
|
11283
11311
|
if (envSel) {
|
|
11284
11312
|
const f = resolve5(dir, ".policy-cache-" + envSel.replace(/[^a-zA-Z0-9_-]/g, "_") + ".json");
|
|
@@ -11593,8 +11621,8 @@ __export(logs_server_exports, {
|
|
|
11593
11621
|
});
|
|
11594
11622
|
import { createServer as createServer2 } from "http";
|
|
11595
11623
|
import { readFileSync as readFileSync9, statSync as statSync5 } from "fs";
|
|
11596
|
-
import { resolve as resolve6, join as
|
|
11597
|
-
import { homedir as
|
|
11624
|
+
import { resolve as resolve6, join as join11, isAbsolute } from "path";
|
|
11625
|
+
import { homedir as homedir10 } from "os";
|
|
11598
11626
|
import { readdirSync as readdirSync2 } from "fs";
|
|
11599
11627
|
function allowedOrigins() {
|
|
11600
11628
|
const base = [
|
|
@@ -11611,15 +11639,15 @@ function resolveLocalLogDir(rawPath) {
|
|
|
11611
11639
|
const dir = String(rawPath || "").trim().replace(/[\\/]+$/, "");
|
|
11612
11640
|
if (!dir) return null;
|
|
11613
11641
|
if (isAbsolute(dir)) return dir;
|
|
11614
|
-
return resolve6(
|
|
11642
|
+
return resolve6(homedir10(), ".solongate", "local-logs");
|
|
11615
11643
|
}
|
|
11616
11644
|
async function findLogDir() {
|
|
11617
|
-
const base = resolve6(
|
|
11645
|
+
const base = resolve6(homedir10(), ".solongate");
|
|
11618
11646
|
try {
|
|
11619
11647
|
const files = readdirSync2(base).filter((f) => f.startsWith(".policy-cache-") && f.endsWith(".json"));
|
|
11620
11648
|
for (const f of files) {
|
|
11621
11649
|
try {
|
|
11622
|
-
const c2 = JSON.parse(readFileSync9(
|
|
11650
|
+
const c2 = JSON.parse(readFileSync9(join11(base, f), "utf-8"));
|
|
11623
11651
|
const p = c2?.security?.localLogs?.path;
|
|
11624
11652
|
if (typeof p === "string" && p.trim()) return { dir: resolveLocalLogDir(p), configured: p };
|
|
11625
11653
|
} catch {
|
|
@@ -11628,7 +11656,7 @@ async function findLogDir() {
|
|
|
11628
11656
|
} catch {
|
|
11629
11657
|
}
|
|
11630
11658
|
try {
|
|
11631
|
-
const cfgRaw = readFileSync9(
|
|
11659
|
+
const cfgRaw = readFileSync9(join11(base, "cloud-guard.json"), "utf-8");
|
|
11632
11660
|
const { apiKey, apiUrl } = JSON.parse(cfgRaw);
|
|
11633
11661
|
if (apiKey) {
|
|
11634
11662
|
const url = `${apiUrl || "https://api.solongate.com"}/api/v1/policies/active`;
|
|
@@ -11657,7 +11685,7 @@ function setCors(req, res) {
|
|
|
11657
11685
|
}
|
|
11658
11686
|
function fileInfo(dir) {
|
|
11659
11687
|
if (!dir) return { file: null, exists: false, size: 0, mtimeMs: 0 };
|
|
11660
|
-
const file =
|
|
11688
|
+
const file = join11(dir, LOG_FILENAME);
|
|
11661
11689
|
try {
|
|
11662
11690
|
const st = statSync5(file);
|
|
11663
11691
|
return { file, exists: true, size: st.size, mtimeMs: st.mtimeMs };
|
|
@@ -12108,7 +12136,7 @@ var init_inject = __esm({
|
|
|
12108
12136
|
// src/create.ts
|
|
12109
12137
|
var create_exports = {};
|
|
12110
12138
|
import { mkdirSync as mkdirSync5, writeFileSync as writeFileSync6, existsSync as existsSync9 } from "fs";
|
|
12111
|
-
import { resolve as resolve8, join as
|
|
12139
|
+
import { resolve as resolve8, join as join12 } from "path";
|
|
12112
12140
|
import { execSync as execSync2 } from "child_process";
|
|
12113
12141
|
function withSpinner(message, fn) {
|
|
12114
12142
|
const frames = ["\u28FE", "\u28FD", "\u28FB", "\u28BF", "\u287F", "\u28DF", "\u28EF", "\u28F7"];
|
|
@@ -12188,7 +12216,7 @@ EXAMPLES
|
|
|
12188
12216
|
}
|
|
12189
12217
|
function createProject(dir, name, _policy) {
|
|
12190
12218
|
writeFileSync6(
|
|
12191
|
-
|
|
12219
|
+
join12(dir, "package.json"),
|
|
12192
12220
|
JSON.stringify(
|
|
12193
12221
|
{
|
|
12194
12222
|
name,
|
|
@@ -12218,7 +12246,7 @@ function createProject(dir, name, _policy) {
|
|
|
12218
12246
|
) + "\n"
|
|
12219
12247
|
);
|
|
12220
12248
|
writeFileSync6(
|
|
12221
|
-
|
|
12249
|
+
join12(dir, "tsconfig.json"),
|
|
12222
12250
|
JSON.stringify(
|
|
12223
12251
|
{
|
|
12224
12252
|
compilerOptions: {
|
|
@@ -12238,9 +12266,9 @@ function createProject(dir, name, _policy) {
|
|
|
12238
12266
|
2
|
|
12239
12267
|
) + "\n"
|
|
12240
12268
|
);
|
|
12241
|
-
mkdirSync5(
|
|
12269
|
+
mkdirSync5(join12(dir, "src"), { recursive: true });
|
|
12242
12270
|
writeFileSync6(
|
|
12243
|
-
|
|
12271
|
+
join12(dir, "src", "index.ts"),
|
|
12244
12272
|
`#!/usr/bin/env node
|
|
12245
12273
|
|
|
12246
12274
|
console.log = (...args: unknown[]) => {
|
|
@@ -12282,7 +12310,7 @@ console.log('Press Ctrl+C to stop.');
|
|
|
12282
12310
|
`
|
|
12283
12311
|
);
|
|
12284
12312
|
writeFileSync6(
|
|
12285
|
-
|
|
12313
|
+
join12(dir, ".mcp.json"),
|
|
12286
12314
|
JSON.stringify(
|
|
12287
12315
|
{
|
|
12288
12316
|
mcpServers: {
|
|
@@ -12300,12 +12328,12 @@ console.log('Press Ctrl+C to stop.');
|
|
|
12300
12328
|
) + "\n"
|
|
12301
12329
|
);
|
|
12302
12330
|
writeFileSync6(
|
|
12303
|
-
|
|
12331
|
+
join12(dir, ".env"),
|
|
12304
12332
|
`SOLONGATE_API_KEY=sg_live_YOUR_KEY_HERE
|
|
12305
12333
|
`
|
|
12306
12334
|
);
|
|
12307
12335
|
writeFileSync6(
|
|
12308
|
-
|
|
12336
|
+
join12(dir, ".gitignore"),
|
|
12309
12337
|
`node_modules/
|
|
12310
12338
|
dist/
|
|
12311
12339
|
*.solongate-backup
|