@solongate/proxy 0.81.22 → 0.81.24
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 +602 -452
- package/dist/tui/index.js +550 -396
- package/dist/tui/local-log.d.ts +22 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -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"() {
|
|
@@ -7222,26 +7261,11 @@ var init_hooks = __esm({
|
|
|
7222
7261
|
// src/tui/panels/Live.tsx
|
|
7223
7262
|
import { Box as Box2, Text as Text2, useInput } from "ink";
|
|
7224
7263
|
import TextInput from "ink-text-input";
|
|
7225
|
-
import {
|
|
7226
|
-
import { homedir as
|
|
7227
|
-
import { join as
|
|
7264
|
+
import { mkdirSync as mkdirSync3, writeFileSync as writeFileSync3 } from "fs";
|
|
7265
|
+
import { homedir as homedir5 } from "os";
|
|
7266
|
+
import { join as join7 } from "path";
|
|
7228
7267
|
import { useCallback as useCallback2, useEffect as useEffect2, useRef as useRef2, useState as useState2 } from "react";
|
|
7229
7268
|
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
7269
|
function extractTarget(detail) {
|
|
7246
7270
|
try {
|
|
7247
7271
|
const j = JSON.parse(detail);
|
|
@@ -7785,9 +7809,9 @@ function LivePanel({ active: active2 }) {
|
|
|
7785
7809
|
else if (input === "x") toggleSignal("dlp");
|
|
7786
7810
|
else if (input === "r") toggleSignal("ratelimit");
|
|
7787
7811
|
else if (input === "e") {
|
|
7788
|
-
const file =
|
|
7812
|
+
const file = join7(homedir5(), ".solongate", "live-export.jsonl");
|
|
7789
7813
|
try {
|
|
7790
|
-
mkdirSync3(
|
|
7814
|
+
mkdirSync3(join7(homedir5(), ".solongate"), { recursive: true });
|
|
7791
7815
|
writeFileSync3(file, visibleDesc.map((x) => JSON.stringify(x)).join("\n") + "\n");
|
|
7792
7816
|
setActionMsg({ text: `\u2713 exported ${visibleDesc.length} lines \u2192 ${file}`, level: "ok", until: Date.now() + 6e3 });
|
|
7793
7817
|
} catch (err2) {
|
|
@@ -8103,10 +8127,11 @@ function LivePanel({ active: active2 }) {
|
|
|
8103
8127
|
] })
|
|
8104
8128
|
] });
|
|
8105
8129
|
}
|
|
8106
|
-
var CONFIG, SPIN, BG, DIM_FLOOR,
|
|
8130
|
+
var CONFIG, SPIN, BG, DIM_FLOOR, RING, hhmmss, fmtUp, FILTERS, sessStatus, STATUS_STYLE, LIVE_HELP;
|
|
8107
8131
|
var init_Live = __esm({
|
|
8108
8132
|
"src/tui/panels/Live.tsx"() {
|
|
8109
8133
|
"use strict";
|
|
8134
|
+
init_local_log();
|
|
8110
8135
|
init_api_client();
|
|
8111
8136
|
init_config2();
|
|
8112
8137
|
init_notify();
|
|
@@ -8116,8 +8141,7 @@ var init_Live = __esm({
|
|
|
8116
8141
|
SPIN = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
8117
8142
|
BG = "#12234f";
|
|
8118
8143
|
DIM_FLOOR = "#233457";
|
|
8119
|
-
|
|
8120
|
-
RING = join6(process.cwd(), ".solongate", ".eval-ring.jsonl");
|
|
8144
|
+
RING = join7(process.cwd(), ".solongate", ".eval-ring.jsonl");
|
|
8121
8145
|
hhmmss = (ts) => {
|
|
8122
8146
|
const d = new Date(ts);
|
|
8123
8147
|
return Number.isNaN(d.getTime()) ? "--:--:--" : d.toTimeString().slice(0, 8);
|
|
@@ -8193,11 +8217,13 @@ function ruleSummary(r) {
|
|
|
8193
8217
|
function PoliciesPanel({ focused }) {
|
|
8194
8218
|
const list6 = useLoader(() => api.policies.list());
|
|
8195
8219
|
const policies = list6.data?.policies ?? [];
|
|
8220
|
+
const activeQ = useLoader(() => api.policies.active());
|
|
8221
|
+
const activeId = activeQ.data?.policy?.id ?? null;
|
|
8222
|
+
const activeBy = activeQ.data?.matched_by;
|
|
8196
8223
|
const [view, setView] = useState3("list");
|
|
8197
8224
|
const [pi, setPi] = useState3(0);
|
|
8198
8225
|
const [ri, setRi] = useState3(0);
|
|
8199
8226
|
const [fi, setFi] = useState3(0);
|
|
8200
|
-
const [vi, setVi] = useState3(0);
|
|
8201
8227
|
const [rules, setRules] = useState3([]);
|
|
8202
8228
|
const [mode, setMode] = useState3("denylist");
|
|
8203
8229
|
const [dirty, setDirty] = useState3(false);
|
|
@@ -8206,15 +8232,6 @@ function PoliciesPanel({ focused }) {
|
|
|
8206
8232
|
const [status, setStatus] = useState3(null);
|
|
8207
8233
|
const selected = policies[Math.min(pi, Math.max(0, policies.length - 1))];
|
|
8208
8234
|
const detail = useLoader(() => selected ? api.policies.get(selected.id) : Promise.resolve(null), [selected?.id]);
|
|
8209
|
-
const versionsQ = useLoader(
|
|
8210
|
-
() => view === "versions" && selected ? api.policies.versions(selected.id, { limit: 50 }) : Promise.resolve(null),
|
|
8211
|
-
[view, selected?.id]
|
|
8212
|
-
);
|
|
8213
|
-
const diffVer = versionsQ.data?.versions[vi]?.version;
|
|
8214
|
-
const diffQ = useLoader(
|
|
8215
|
-
() => view === "versions" && selected && diffVer !== void 0 ? api.policies.get(selected.id, diffVer) : Promise.resolve(null),
|
|
8216
|
-
[view, selected?.id, diffVer]
|
|
8217
|
-
);
|
|
8218
8235
|
useEffect3(() => {
|
|
8219
8236
|
if (detail.data) {
|
|
8220
8237
|
setRules(detail.data.rules);
|
|
@@ -8265,6 +8282,20 @@ function PoliciesPanel({ focused }) {
|
|
|
8265
8282
|
else if (key.return || key.rightArrow) {
|
|
8266
8283
|
setStatus(null);
|
|
8267
8284
|
setView("rules");
|
|
8285
|
+
} else if (input === "a") {
|
|
8286
|
+
if (selected) {
|
|
8287
|
+
setStatus("Activating\u2026");
|
|
8288
|
+
void api.policies.setActive(selected.id).then(() => {
|
|
8289
|
+
setStatus(`\u2713 "${selected.name}" is now the ACTIVE policy (pinned) \xB7 reaches agents in ~30s`);
|
|
8290
|
+
activeQ.reload();
|
|
8291
|
+
}).catch((e) => setStatus("\u2717 " + (e instanceof Error ? e.message : String(e))));
|
|
8292
|
+
}
|
|
8293
|
+
} else if (input === "x") {
|
|
8294
|
+
setStatus("Deactivating\u2026");
|
|
8295
|
+
void api.policies.setActive(null).then(() => {
|
|
8296
|
+
setStatus("\u2713 active policy: NONE \u2014 no rules enforced, w/b grants are refused");
|
|
8297
|
+
activeQ.reload();
|
|
8298
|
+
}).catch((e) => setStatus("\u2717 " + (e instanceof Error ? e.message : String(e))));
|
|
8268
8299
|
}
|
|
8269
8300
|
return;
|
|
8270
8301
|
}
|
|
@@ -8298,32 +8329,10 @@ function PoliciesPanel({ focused }) {
|
|
|
8298
8329
|
} else if (input === "D") {
|
|
8299
8330
|
setStatus("Dry-running\u2026");
|
|
8300
8331
|
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))));
|
|
8301
|
-
} else if (input === "v") {
|
|
8302
|
-
setVi(0);
|
|
8303
|
-
setView("versions");
|
|
8304
8332
|
} else if (input === "s") void save();
|
|
8305
8333
|
else if (input === "x") discard();
|
|
8306
8334
|
return;
|
|
8307
8335
|
}
|
|
8308
|
-
if (view === "versions") {
|
|
8309
|
-
const vers = versionsQ.data?.versions ?? [];
|
|
8310
|
-
if (key.leftArrow) return void setView("rules");
|
|
8311
|
-
if (key.upArrow) setVi((n) => Math.max(0, n - 1));
|
|
8312
|
-
else if (key.downArrow) setVi((n) => Math.min(vers.length - 1, n + 1));
|
|
8313
|
-
else if (key.return) {
|
|
8314
|
-
const v = vers[vi];
|
|
8315
|
-
if (v && selected) {
|
|
8316
|
-
setStatus("Rolling back\u2026");
|
|
8317
|
-
void api.policies.rollback(selected.id, v.version).then((r) => {
|
|
8318
|
-
setStatus(`\u2713 rolled back to v${v.version} \u2192 new v${r.version}`);
|
|
8319
|
-
detail.reload();
|
|
8320
|
-
list6.reload();
|
|
8321
|
-
setView("rules");
|
|
8322
|
-
}).catch((e) => setStatus("\u2717 " + (e instanceof Error ? e.message : String(e))));
|
|
8323
|
-
}
|
|
8324
|
-
}
|
|
8325
|
-
return;
|
|
8326
|
-
}
|
|
8327
8336
|
const rule2 = rules[ri];
|
|
8328
8337
|
if (!rule2) return setView("rules");
|
|
8329
8338
|
const field = FIELDS[fi];
|
|
@@ -8345,18 +8354,30 @@ function PoliciesPanel({ focused }) {
|
|
|
8345
8354
|
{ isActive: focused && !editing }
|
|
8346
8355
|
);
|
|
8347
8356
|
if (view === "list") {
|
|
8357
|
+
const activeName = activeId ? policies.find((p) => p.id === activeId)?.name ?? activeId : null;
|
|
8348
8358
|
return /* @__PURE__ */ jsx3(DataView, { loading: list6.loading && !list6.data, error: list6.error, empty: !!list6.data && policies.length === 0, emptyText: "No policies.", children: /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", children: [
|
|
8349
|
-
/* @__PURE__ */
|
|
8359
|
+
/* @__PURE__ */ jsxs3(Box3, { children: [
|
|
8360
|
+
/* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: "active: " }),
|
|
8361
|
+
activeQ.loading && !activeQ.data ? /* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: "\u2026" }) : activeName ? /* @__PURE__ */ jsxs3(Fragment3, { children: [
|
|
8362
|
+
/* @__PURE__ */ jsxs3(Text3, { color: theme.ok, bold: true, children: [
|
|
8363
|
+
"\u25CF ",
|
|
8364
|
+
truncate2(activeName, 28)
|
|
8365
|
+
] }),
|
|
8366
|
+
/* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: activeBy ? ` (${activeBy})` : "" })
|
|
8367
|
+
] }) : /* @__PURE__ */ jsx3(Text3, { color: theme.bad, bold: true, children: "\u25CB NONE \u2014 nothing enforced, grants refused" })
|
|
8368
|
+
] }),
|
|
8369
|
+
/* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: focused ? "\u2191\u2193 select \xB7 enter open \xB7 a activate \xB7 x deactivate (none)" : "press \u2192 to browse" }),
|
|
8350
8370
|
/* @__PURE__ */ jsx3(Box3, { marginTop: 1, flexDirection: "column", children: policies.map((p, i) => /* @__PURE__ */ jsxs3(Text3, { color: i === pi ? theme.accentBright : void 0, bold: i === pi, children: [
|
|
8351
8371
|
(i === pi ? "\u25B8 " : " ") + truncate2(p.name, 26).padEnd(27),
|
|
8352
8372
|
/* @__PURE__ */ jsxs3(Text3, { color: theme.dim, children: [
|
|
8353
8373
|
p.mode.padEnd(10),
|
|
8354
8374
|
" ",
|
|
8355
8375
|
p.rules.length,
|
|
8356
|
-
" rules
|
|
8357
|
-
|
|
8358
|
-
|
|
8359
|
-
] }, p.id)) })
|
|
8376
|
+
" rules"
|
|
8377
|
+
] }),
|
|
8378
|
+
p.id === activeId ? /* @__PURE__ */ jsx3(Text3, { color: theme.ok, bold: true, children: " \u25CF ACTIVE" }) : null
|
|
8379
|
+
] }, p.id)) }),
|
|
8380
|
+
status ? /* @__PURE__ */ jsx3(Text3, { color: status.startsWith("\u2717") ? theme.bad : theme.ok, children: status }) : null
|
|
8360
8381
|
] }) });
|
|
8361
8382
|
}
|
|
8362
8383
|
const dirtyTag = dirty ? /* @__PURE__ */ jsx3(Text3, { color: theme.warn, children: " \u25CF unsaved (s save \xB7 x discard)" }) : null;
|
|
@@ -8368,7 +8389,7 @@ function PoliciesPanel({ focused }) {
|
|
|
8368
8389
|
/* @__PURE__ */ jsx3(Text3, { color: mode === "whitelist" ? theme.warn : void 0, children: mode }),
|
|
8369
8390
|
dirtyTag
|
|
8370
8391
|
] }),
|
|
8371
|
-
/* @__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
|
|
8392
|
+
/* @__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" }),
|
|
8372
8393
|
/* @__PURE__ */ jsx3(Box3, { marginTop: 1, children: /* @__PURE__ */ jsx3(
|
|
8373
8394
|
Table,
|
|
8374
8395
|
{
|
|
@@ -8394,50 +8415,6 @@ function PoliciesPanel({ focused }) {
|
|
|
8394
8415
|
status ? /* @__PURE__ */ jsx3(Text3, { color: status.startsWith("\u2717") ? theme.bad : theme.ok, children: status }) : null
|
|
8395
8416
|
] }) });
|
|
8396
8417
|
}
|
|
8397
|
-
if (view === "versions") {
|
|
8398
|
-
const vers = versionsQ.data?.versions ?? [];
|
|
8399
|
-
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: [
|
|
8400
|
-
/* @__PURE__ */ jsx3(Text3, { bold: true, color: theme.accentBright, children: truncate2(selected?.name ?? "", 28) }),
|
|
8401
|
-
/* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: "\u2191\u2193 select \xB7 enter roll back to that version \xB7 \u2190 back" }),
|
|
8402
|
-
/* @__PURE__ */ jsx3(Box3, { marginTop: 1, children: /* @__PURE__ */ jsx3(
|
|
8403
|
-
Table,
|
|
8404
|
-
{
|
|
8405
|
-
columns: [
|
|
8406
|
-
{ header: "", width: 2 },
|
|
8407
|
-
{ header: "VER", width: 5 },
|
|
8408
|
-
{ header: "RULES", width: 5 },
|
|
8409
|
-
{ header: "REASON", width: 34 },
|
|
8410
|
-
{ header: "WHEN", width: 16 }
|
|
8411
|
-
],
|
|
8412
|
-
rows: vers.map((v, i) => [
|
|
8413
|
-
{ value: i === vi ? "\u25B8" : "", color: theme.accentBright },
|
|
8414
|
-
{ value: `v${v.version}`, bold: i === vi },
|
|
8415
|
-
{ value: String(v.rules_count), dim: true },
|
|
8416
|
-
{ value: truncate2(v.reason || "\u2014", 34) },
|
|
8417
|
-
{ value: truncate2(v.created_at, 16), dim: true }
|
|
8418
|
-
])
|
|
8419
|
-
}
|
|
8420
|
-
) }),
|
|
8421
|
-
/* @__PURE__ */ jsxs3(Box3, { marginTop: 1, flexDirection: "column", children: [
|
|
8422
|
-
/* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: `Diff v${diffVer ?? "?"} vs current draft` }),
|
|
8423
|
-
(() => {
|
|
8424
|
-
const old = diffQ.data?.rules ?? [];
|
|
8425
|
-
const cur = rules;
|
|
8426
|
-
const oldIds = new Set(old.map((r) => r.id));
|
|
8427
|
-
const curIds = new Set(cur.map((r) => r.id));
|
|
8428
|
-
const added = cur.filter((r) => !oldIds.has(r.id));
|
|
8429
|
-
const removed = old.filter((r) => !curIds.has(r.id));
|
|
8430
|
-
if (diffQ.loading && !diffQ.data) return /* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: " loading\u2026" });
|
|
8431
|
-
if (!added.length && !removed.length) return /* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: " identical rule set" });
|
|
8432
|
-
return /* @__PURE__ */ jsxs3(Fragment3, { children: [
|
|
8433
|
-
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)),
|
|
8434
|
-
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))
|
|
8435
|
-
] });
|
|
8436
|
-
})()
|
|
8437
|
-
] }),
|
|
8438
|
-
status ? /* @__PURE__ */ jsx3(Text3, { color: status.startsWith("\u2717") ? theme.bad : theme.ok, children: status }) : null
|
|
8439
|
-
] }) });
|
|
8440
|
-
}
|
|
8441
8418
|
const rule = rules[ri];
|
|
8442
8419
|
return /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", children: [
|
|
8443
8420
|
/* @__PURE__ */ jsxs3(Box3, { children: [
|
|
@@ -8850,177 +8827,202 @@ var init_Dlp = __esm({
|
|
|
8850
8827
|
}
|
|
8851
8828
|
});
|
|
8852
8829
|
|
|
8853
|
-
// src/tui/panels/Stats.tsx
|
|
8854
|
-
import { Box as Box6, Text as Text6 } from "ink";
|
|
8855
|
-
import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
8856
|
-
function StatsPanel({ active: active2 }) {
|
|
8857
|
-
const stats = useLoader(() => api.stats.get());
|
|
8858
|
-
const ts = useLoader(() => api.stats.timeseries({ period: "24h" }));
|
|
8859
|
-
const drift2 = useLoader(() => api.stats.drift(7));
|
|
8860
|
-
usePoll(() => {
|
|
8861
|
-
stats.reload();
|
|
8862
|
-
ts.reload();
|
|
8863
|
-
}, 5e3, active2);
|
|
8864
|
-
usePoll(drift2.reload, 3e4, active2);
|
|
8865
|
-
const s = stats.data;
|
|
8866
|
-
const points = ts.data?.timeseries ?? [];
|
|
8867
|
-
const driftRules = (drift2.data?.rules ?? []).slice(0, 5);
|
|
8868
|
-
return /* @__PURE__ */ jsx6(DataView, { loading: stats.loading && !s, error: stats.error, children: s ? /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
|
|
8869
|
-
/* @__PURE__ */ jsxs6(Box6, { children: [
|
|
8870
|
-
/* @__PURE__ */ jsxs6(Text6, { bold: true, children: [
|
|
8871
|
-
s.total_calls,
|
|
8872
|
-
" "
|
|
8873
|
-
] }),
|
|
8874
|
-
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: "calls " }),
|
|
8875
|
-
/* @__PURE__ */ jsxs6(Text6, { color: theme.ok, children: [
|
|
8876
|
-
s.allowed,
|
|
8877
|
-
" allowed"
|
|
8878
|
-
] }),
|
|
8879
|
-
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: " " }),
|
|
8880
|
-
/* @__PURE__ */ jsxs6(Text6, { color: theme.bad, children: [
|
|
8881
|
-
s.denied,
|
|
8882
|
-
" denied"
|
|
8883
|
-
] })
|
|
8884
|
-
] }),
|
|
8885
|
-
/* @__PURE__ */ jsxs6(Text6, { color: theme.dim, children: [
|
|
8886
|
-
s.active_policies,
|
|
8887
|
-
" policies \xB7 ",
|
|
8888
|
-
s.registered_tools,
|
|
8889
|
-
" tools"
|
|
8890
|
-
] }),
|
|
8891
|
-
/* @__PURE__ */ jsxs6(Box6, { marginTop: 1, flexDirection: "column", children: [
|
|
8892
|
-
/* @__PURE__ */ jsxs6(Text6, { color: theme.dim, children: [
|
|
8893
|
-
"Last 24h ",
|
|
8894
|
-
ts.data ? `(per ${ts.data.granularity})` : ""
|
|
8895
|
-
] }),
|
|
8896
|
-
/* @__PURE__ */ jsxs6(Box6, { children: [
|
|
8897
|
-
/* @__PURE__ */ jsx6(Text6, { children: "total " }),
|
|
8898
|
-
/* @__PURE__ */ jsx6(Text6, { color: theme.accent, children: sparkline(points.map((p) => p.total), 64) })
|
|
8899
|
-
] }),
|
|
8900
|
-
/* @__PURE__ */ jsxs6(Box6, { children: [
|
|
8901
|
-
/* @__PURE__ */ jsx6(Text6, { children: "allowed " }),
|
|
8902
|
-
/* @__PURE__ */ jsx6(Text6, { color: theme.ok, children: sparkline(points.map((p) => p.allowed), 64) })
|
|
8903
|
-
] }),
|
|
8904
|
-
/* @__PURE__ */ jsxs6(Box6, { children: [
|
|
8905
|
-
/* @__PURE__ */ jsx6(Text6, { children: "denied " }),
|
|
8906
|
-
/* @__PURE__ */ jsx6(Text6, { color: theme.bad, children: sparkline(points.map((p) => p.denied), 64) })
|
|
8907
|
-
] })
|
|
8908
|
-
] }),
|
|
8909
|
-
/* @__PURE__ */ jsxs6(Box6, { marginTop: 1, flexDirection: "column", children: [
|
|
8910
|
-
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: "Recent" }),
|
|
8911
|
-
/* @__PURE__ */ jsx6(
|
|
8912
|
-
Table,
|
|
8913
|
-
{
|
|
8914
|
-
columns: [
|
|
8915
|
-
{ header: "DECISION", width: 9 },
|
|
8916
|
-
{ header: "TOOL", width: 20 },
|
|
8917
|
-
{ header: "MS", width: 5 },
|
|
8918
|
-
{ header: "WHEN", width: 6 }
|
|
8919
|
-
],
|
|
8920
|
-
rows: (s.recent_activity ?? []).slice(0, 6).map((a) => [
|
|
8921
|
-
{ value: a.decision, color: decisionColor(a.decision) },
|
|
8922
|
-
{ value: truncate2(a.tool_name, 20), color: theme.accent },
|
|
8923
|
-
{ value: String(a.evaluation_time_ms ?? "\u2014"), dim: true },
|
|
8924
|
-
{ value: ago(a.created_at), dim: true }
|
|
8925
|
-
])
|
|
8926
|
-
}
|
|
8927
|
-
)
|
|
8928
|
-
] }),
|
|
8929
|
-
/* @__PURE__ */ jsxs6(Box6, { marginTop: 1, flexDirection: "column", children: [
|
|
8930
|
-
/* @__PURE__ */ jsxs6(Text6, { color: theme.dim, children: [
|
|
8931
|
-
"Denial drift ",
|
|
8932
|
-
drift2.data ? `(7d: ${drift2.data.total_current} now vs ${drift2.data.total_previous} prev)` : ""
|
|
8933
|
-
] }),
|
|
8934
|
-
driftRules.length ? /* @__PURE__ */ jsx6(
|
|
8935
|
-
Table,
|
|
8936
|
-
{
|
|
8937
|
-
columns: [
|
|
8938
|
-
{ header: "NOW", width: 5 },
|
|
8939
|
-
{ header: "PREV", width: 5 },
|
|
8940
|
-
{ header: "\u0394", width: 6 },
|
|
8941
|
-
{ header: "RULE", width: 22 },
|
|
8942
|
-
{ header: "REASON", width: 26 }
|
|
8943
|
-
],
|
|
8944
|
-
rows: driftRules.map((r) => [
|
|
8945
|
-
{ value: String(r.current), bold: true },
|
|
8946
|
-
{ value: String(r.previous), dim: true },
|
|
8947
|
-
{ value: r.is_new ? "NEW" : r.spike ? `+${r.delta}` : String(r.delta), color: r.is_new ? theme.ok : r.spike ? theme.bad : void 0 },
|
|
8948
|
-
{ value: truncate2(r.rule_id ?? "\u2014", 22), color: theme.accent },
|
|
8949
|
-
{ value: truncate2(r.reason ?? r.last_tool ?? "\u2014", 26), dim: true }
|
|
8950
|
-
])
|
|
8951
|
-
}
|
|
8952
|
-
) : /* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: " no denials in window" })
|
|
8953
|
-
] })
|
|
8954
|
-
] }) : null });
|
|
8955
|
-
}
|
|
8956
|
-
var init_Stats = __esm({
|
|
8957
|
-
"src/tui/panels/Stats.tsx"() {
|
|
8958
|
-
"use strict";
|
|
8959
|
-
init_api_client();
|
|
8960
|
-
init_components();
|
|
8961
|
-
init_hooks();
|
|
8962
|
-
init_theme();
|
|
8963
|
-
}
|
|
8964
|
-
});
|
|
8965
|
-
|
|
8966
8830
|
// src/tui/panels/Audit.tsx
|
|
8967
|
-
import { Box as
|
|
8831
|
+
import { Box as Box6, Text as Text6, useInput as useInput5 } from "ink";
|
|
8968
8832
|
import TextInput4 from "ink-text-input";
|
|
8969
8833
|
import { useState as useState6 } from "react";
|
|
8970
|
-
import { Fragment as Fragment4, jsx as
|
|
8834
|
+
import { Fragment as Fragment4, jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
8835
|
+
function loadLocalRows() {
|
|
8836
|
+
return parseLocalLines(tailLines(LOCAL_LOG, LOCAL_MAX_BYTES)).map((j, i) => ({
|
|
8837
|
+
id: "l:" + j.at + ":" + i,
|
|
8838
|
+
at: j.at,
|
|
8839
|
+
tool: j.tool ?? "?",
|
|
8840
|
+
decision: j.decision ?? "ALLOW",
|
|
8841
|
+
permission: j.permission ?? "\u2014",
|
|
8842
|
+
trust: j.trust_level ?? "\u2014",
|
|
8843
|
+
agent: j.agent_name ?? null,
|
|
8844
|
+
session: j.session_id ?? null,
|
|
8845
|
+
reason: j.reason ?? null,
|
|
8846
|
+
rule: j.matched_rule_id ?? null,
|
|
8847
|
+
evalMs: j.evaluation_time_ms ?? null,
|
|
8848
|
+
dlp: j.dlp ? Array.isArray(j.dlp) ? j.dlp.map(String) : ["dlp"] : [],
|
|
8849
|
+
burst: !!j.rate_limit_burst,
|
|
8850
|
+
args: j.arguments ? JSON.stringify(j.arguments) : null
|
|
8851
|
+
})).sort((a, b) => b.at - a.at);
|
|
8852
|
+
}
|
|
8971
8853
|
function AuditPanel({ active: active2, focused }) {
|
|
8972
8854
|
const { cols, rows } = usePanelSize();
|
|
8855
|
+
const [source, setSource] = useState6("cloud");
|
|
8856
|
+
const [view, setView] = useState6("logs");
|
|
8973
8857
|
const [di, setDi] = useState6(0);
|
|
8974
8858
|
const [gi, setGi] = useState6(0);
|
|
8975
8859
|
const [tool, setTool] = useState6("");
|
|
8976
8860
|
const [agent, setAgent] = useState6("");
|
|
8977
8861
|
const [search, setSearch] = useState6("");
|
|
8862
|
+
const [sessFilter, setSessFilter] = useState6("");
|
|
8863
|
+
const [page, setPage] = useState6(0);
|
|
8978
8864
|
const [sel, setSel] = useState6(0);
|
|
8979
|
-
const [view, setView] = useState6("list");
|
|
8980
8865
|
const [detailScroll, setDetailScroll] = useState6(0);
|
|
8981
8866
|
const [editing, setEditing] = useState6(null);
|
|
8867
|
+
const [si, setSi] = useState6(0);
|
|
8868
|
+
const [sessSearch, setSessSearch] = useState6("");
|
|
8869
|
+
const [sessSel, setSessSel] = useState6(0);
|
|
8870
|
+
const toTop = () => setSel(0);
|
|
8871
|
+
const statsQ = useLoader(() => source === "cloud" ? api.stats.get() : Promise.resolve(null), [source]);
|
|
8872
|
+
const tsQ = useLoader(() => source === "cloud" ? api.stats.timeseries({ period: "24h" }) : Promise.resolve(null), [source]);
|
|
8873
|
+
usePoll(() => {
|
|
8874
|
+
statsQ.reload();
|
|
8875
|
+
tsQ.reload();
|
|
8876
|
+
}, 15e3, active2 && source === "cloud");
|
|
8982
8877
|
const query = {
|
|
8983
8878
|
filter: DECISIONS[di],
|
|
8984
8879
|
signal: SIGNALS[gi],
|
|
8985
8880
|
tool: tool || void 0,
|
|
8986
8881
|
agent_name: agent || void 0,
|
|
8987
8882
|
search: search || void 0,
|
|
8988
|
-
|
|
8883
|
+
session_id: sessFilter || void 0,
|
|
8884
|
+
limit: PAGE,
|
|
8885
|
+
offset: page * PAGE
|
|
8989
8886
|
};
|
|
8990
|
-
const
|
|
8991
|
-
|
|
8992
|
-
|
|
8993
|
-
|
|
8887
|
+
const cloudQ = useLoader(
|
|
8888
|
+
() => source === "cloud" ? api.audit.list(query) : Promise.resolve(null),
|
|
8889
|
+
[source, di, gi, tool, agent, search, sessFilter, page]
|
|
8890
|
+
);
|
|
8891
|
+
usePoll(cloudQ.reload, 6e3, active2 && source === "cloud" && view === "logs" && !editing && page === 0);
|
|
8892
|
+
const localQ = useLoader(() => source === "local" ? Promise.resolve(loadLocalRows()) : Promise.resolve(null), [source]);
|
|
8893
|
+
usePoll(localQ.reload, 6e3, active2 && source === "local" && view === "logs" && !editing && page === 0);
|
|
8894
|
+
let pageRows = [];
|
|
8895
|
+
let total = 0;
|
|
8896
|
+
if (source === "cloud") {
|
|
8897
|
+
pageRows = (cloudQ.data?.entries ?? []).map(cloudRow).sort((a, b) => b.at - a.at);
|
|
8898
|
+
total = cloudQ.data?.total ?? 0;
|
|
8899
|
+
} else {
|
|
8900
|
+
const all = localQ.data ?? [];
|
|
8901
|
+
const q = search.trim().toLowerCase();
|
|
8902
|
+
const filtered = all.filter((r) => {
|
|
8903
|
+
if (DECISIONS[di] && r.decision !== DECISIONS[di]) return false;
|
|
8904
|
+
if (SIGNALS[gi] === "dlp" && r.dlp.length === 0) return false;
|
|
8905
|
+
if (SIGNALS[gi] === "ratelimit" && !r.burst) return false;
|
|
8906
|
+
if (tool && !r.tool.toLowerCase().includes(tool.toLowerCase())) return false;
|
|
8907
|
+
if (agent && (r.agent ?? "").toLowerCase() !== agent.toLowerCase()) return false;
|
|
8908
|
+
if (sessFilter && r.session !== sessFilter) return false;
|
|
8909
|
+
if (q && !`${r.tool} ${r.agent ?? ""} ${r.reason ?? ""} ${r.args ?? ""}`.toLowerCase().includes(q)) return false;
|
|
8910
|
+
return true;
|
|
8911
|
+
});
|
|
8912
|
+
total = filtered.length;
|
|
8913
|
+
pageRows = filtered.slice(page * PAGE, page * PAGE + PAGE);
|
|
8914
|
+
}
|
|
8915
|
+
const pages = Math.max(1, Math.ceil(total / PAGE));
|
|
8916
|
+
const current = pageRows[Math.min(sel, Math.max(0, pageRows.length - 1))];
|
|
8917
|
+
const agentsQ = useLoader(
|
|
8918
|
+
() => source === "cloud" ? api.agents.live({ limit: 100, includeDeactivated: true }) : Promise.resolve(null),
|
|
8919
|
+
[source]
|
|
8920
|
+
);
|
|
8921
|
+
usePoll(agentsQ.reload, 8e3, active2 && source === "cloud" && view === "sessions");
|
|
8922
|
+
let sessions = [];
|
|
8923
|
+
if (source === "cloud") {
|
|
8924
|
+
sessions = (agentsQ.data?.agents ?? []).map((a) => ({
|
|
8925
|
+
id: a.session_id,
|
|
8926
|
+
agent: a.agent_name ?? a.session_id,
|
|
8927
|
+
status: a.status === "deactivated" ? "ended" : a.status,
|
|
8928
|
+
calls: a.total_calls,
|
|
8929
|
+
denies: a.denied_calls,
|
|
8930
|
+
dlp: a.dlp_events,
|
|
8931
|
+
trust: a.trust_score,
|
|
8932
|
+
lastAt: Date.parse(a.last_seen_at)
|
|
8933
|
+
}));
|
|
8934
|
+
} else {
|
|
8935
|
+
const bySess = /* @__PURE__ */ new Map();
|
|
8936
|
+
for (const r of localQ.data ?? []) {
|
|
8937
|
+
if (!r.session) continue;
|
|
8938
|
+
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 };
|
|
8939
|
+
cur.calls++;
|
|
8940
|
+
if (r.decision !== "ALLOW") cur.denies++;
|
|
8941
|
+
if (r.dlp.length) cur.dlp++;
|
|
8942
|
+
cur.lastAt = Math.max(cur.lastAt, r.at);
|
|
8943
|
+
if (r.agent) cur.agent = r.agent;
|
|
8944
|
+
bySess.set(r.session, cur);
|
|
8945
|
+
}
|
|
8946
|
+
sessions = [...bySess.values()];
|
|
8947
|
+
}
|
|
8948
|
+
const sq = sessSearch.trim().toLowerCase();
|
|
8949
|
+
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);
|
|
8950
|
+
const currentSess = sessionsFiltered[Math.min(sessSel, Math.max(0, sessionsFiltered.length - 1))];
|
|
8994
8951
|
const sessionQ = useLoader(
|
|
8995
|
-
() => view === "detail" && current?.
|
|
8996
|
-
[view, current?.
|
|
8952
|
+
() => view === "detail" && current?.session && source === "cloud" ? api.audit.list({ session_id: current.session, limit: 40 }) : Promise.resolve(null),
|
|
8953
|
+
[view, current?.session, source]
|
|
8997
8954
|
);
|
|
8998
8955
|
useInput5(
|
|
8999
8956
|
(input, key) => {
|
|
9000
8957
|
if (view === "detail") {
|
|
9001
|
-
if (key.leftArrow || key.escape) setView("
|
|
8958
|
+
if (key.leftArrow || key.escape) setView("logs");
|
|
9002
8959
|
else if (key.upArrow) setDetailScroll((n) => Math.max(0, n - 1));
|
|
9003
8960
|
else if (key.downArrow) setDetailScroll((n) => n + 1);
|
|
9004
8961
|
else if (key.pageUp) setDetailScroll((n) => Math.max(0, n - 10));
|
|
9005
8962
|
else if (key.pageDown) setDetailScroll((n) => n + 10);
|
|
9006
8963
|
return;
|
|
9007
8964
|
}
|
|
9008
|
-
|
|
8965
|
+
if (input === "s") {
|
|
8966
|
+
setSource((s) => s === "cloud" ? "local" : "cloud");
|
|
8967
|
+
setPage(0);
|
|
8968
|
+
toTop();
|
|
8969
|
+
setSessSel(0);
|
|
8970
|
+
return;
|
|
8971
|
+
}
|
|
8972
|
+
if (input === "v") {
|
|
8973
|
+
setView((v) => v === "logs" ? "sessions" : "logs");
|
|
8974
|
+
return;
|
|
8975
|
+
}
|
|
8976
|
+
if (view === "sessions") {
|
|
8977
|
+
if (key.upArrow) setSessSel((n) => Math.max(0, n - 1));
|
|
8978
|
+
else if (key.downArrow) setSessSel((n) => Math.min(sessionsFiltered.length - 1, n + 1));
|
|
8979
|
+
else if (key.pageUp) setSessSel((n) => Math.max(0, n - 10));
|
|
8980
|
+
else if (key.pageDown) setSessSel((n) => Math.min(sessionsFiltered.length - 1, n + 10));
|
|
8981
|
+
else if (key.return || key.rightArrow) {
|
|
8982
|
+
if (currentSess) {
|
|
8983
|
+
setSessFilter(currentSess.id);
|
|
8984
|
+
setPage(0);
|
|
8985
|
+
toTop();
|
|
8986
|
+
setView("logs");
|
|
8987
|
+
}
|
|
8988
|
+
} else if (input === "f") {
|
|
8989
|
+
setSi((n) => (n + 1) % SESS_STATUS.length);
|
|
8990
|
+
setSessSel(0);
|
|
8991
|
+
} else if (input === "/") setEditing("sess-search");
|
|
8992
|
+
else if (input === "c") {
|
|
8993
|
+
setSi(0);
|
|
8994
|
+
setSessSearch("");
|
|
8995
|
+
setSessSel(0);
|
|
8996
|
+
}
|
|
8997
|
+
return;
|
|
8998
|
+
}
|
|
9009
8999
|
if (key.upArrow) setSel((n) => Math.max(0, n - 1));
|
|
9010
|
-
else if (key.downArrow) setSel((n) => Math.min(
|
|
9000
|
+
else if (key.downArrow) setSel((n) => Math.min(pageRows.length - 1, n + 1));
|
|
9011
9001
|
else if (key.pageUp) setSel((n) => Math.max(0, n - 10));
|
|
9012
|
-
else if (key.pageDown) setSel((n) => Math.min(
|
|
9002
|
+
else if (key.pageDown) setSel((n) => Math.min(pageRows.length - 1, n + 10));
|
|
9013
9003
|
else if (key.return || key.rightArrow) {
|
|
9014
9004
|
if (current) {
|
|
9015
9005
|
setDetailScroll(0);
|
|
9016
9006
|
setView("detail");
|
|
9017
9007
|
}
|
|
9008
|
+
} else if (input === "]") {
|
|
9009
|
+
if (page < pages - 1) {
|
|
9010
|
+
setPage(page + 1);
|
|
9011
|
+
toTop();
|
|
9012
|
+
}
|
|
9013
|
+
} else if (input === "[") {
|
|
9014
|
+
if (page > 0) {
|
|
9015
|
+
setPage(page - 1);
|
|
9016
|
+
toTop();
|
|
9017
|
+
}
|
|
9018
9018
|
} else if (input === "f") {
|
|
9019
9019
|
setDi((n) => (n + 1) % DECISIONS.length);
|
|
9020
|
-
|
|
9020
|
+
setPage(0);
|
|
9021
|
+
toTop();
|
|
9021
9022
|
} else if (input === "g") {
|
|
9022
9023
|
setGi((n) => (n + 1) % SIGNALS.length);
|
|
9023
|
-
|
|
9024
|
+
setPage(0);
|
|
9025
|
+
toTop();
|
|
9024
9026
|
} else if (input === "t") setEditing("tool");
|
|
9025
9027
|
else if (input === "n") setEditing("agent");
|
|
9026
9028
|
else if (input === "/") setEditing("search");
|
|
@@ -9030,46 +9032,89 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
9030
9032
|
setTool("");
|
|
9031
9033
|
setAgent("");
|
|
9032
9034
|
setSearch("");
|
|
9033
|
-
|
|
9035
|
+
setSessFilter("");
|
|
9036
|
+
setPage(0);
|
|
9037
|
+
toTop();
|
|
9034
9038
|
}
|
|
9035
9039
|
},
|
|
9036
9040
|
{ isActive: focused && !editing }
|
|
9037
9041
|
);
|
|
9042
|
+
const points = tsQ.data?.timeseries ?? [];
|
|
9043
|
+
const localAll = localQ.data ?? [];
|
|
9044
|
+
const strip = source === "cloud" ? /* @__PURE__ */ jsxs6(Text6, { wrap: "truncate", children: [
|
|
9045
|
+
/* @__PURE__ */ jsx6(Text6, { bold: true, children: statsQ.data ? statsQ.data.total_calls : "\xB7\xB7\xB7\xB7" }),
|
|
9046
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: " calls \xB7 " }),
|
|
9047
|
+
/* @__PURE__ */ jsxs6(Text6, { color: theme.ok, children: [
|
|
9048
|
+
statsQ.data?.allowed ?? "\xB7\xB7\xB7",
|
|
9049
|
+
" allow"
|
|
9050
|
+
] }),
|
|
9051
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: " \xB7 " }),
|
|
9052
|
+
/* @__PURE__ */ jsxs6(Text6, { color: theme.bad, children: [
|
|
9053
|
+
statsQ.data?.denied ?? "\xB7\xB7",
|
|
9054
|
+
" deny"
|
|
9055
|
+
] }),
|
|
9056
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: ` \xB7 ${statsQ.data?.active_policies ?? "\xB7"} policies \xB7 ${statsQ.data?.registered_tools ?? "\xB7"} tools \xB7 24h ` }),
|
|
9057
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.accent, children: sparkline(points.map((p) => p.total), 24) }),
|
|
9058
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: " deny " }),
|
|
9059
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.bad, children: sparkline(points.map((p) => p.denied), 24) })
|
|
9060
|
+
] }) : /* @__PURE__ */ jsxs6(Text6, { wrap: "truncate", children: [
|
|
9061
|
+
/* @__PURE__ */ jsx6(Text6, { bold: true, children: localAll.length }),
|
|
9062
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: " calls in local file \xB7 " }),
|
|
9063
|
+
/* @__PURE__ */ jsxs6(Text6, { color: theme.ok, children: [
|
|
9064
|
+
localAll.filter((r) => r.decision === "ALLOW").length,
|
|
9065
|
+
" allow"
|
|
9066
|
+
] }),
|
|
9067
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: " \xB7 " }),
|
|
9068
|
+
/* @__PURE__ */ jsxs6(Text6, { color: theme.bad, children: [
|
|
9069
|
+
localAll.filter((r) => r.decision !== "ALLOW").length,
|
|
9070
|
+
" deny"
|
|
9071
|
+
] }),
|
|
9072
|
+
/* @__PURE__ */ jsxs6(Text6, { color: theme.dim, children: [
|
|
9073
|
+
" \xB7 ",
|
|
9074
|
+
LOCAL_LOG
|
|
9075
|
+
] })
|
|
9076
|
+
] });
|
|
9077
|
+
const srcChip = /* @__PURE__ */ jsxs6(Text6, { children: [
|
|
9078
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: "src:" }),
|
|
9079
|
+
/* @__PURE__ */ jsx6(Text6, { color: source === "local" ? theme.ok : "#4f6db8", bold: true, children: source }),
|
|
9080
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: " (s) " })
|
|
9081
|
+
] });
|
|
9038
9082
|
if (view === "detail" && current) {
|
|
9039
|
-
const sessionCalls = sessionQ.data?.entries ?? [];
|
|
9083
|
+
const sessionCalls = source === "cloud" ? (sessionQ.data?.entries ?? []).map(cloudRow) : localAll.filter((r) => r.session && r.session === current.session).slice(0, 40);
|
|
9040
9084
|
const bodyW = Math.max(20, cols - 2);
|
|
9041
9085
|
const reasonLines = wrapLines("reason: " + (current.reason ?? "\u2014"), bodyW);
|
|
9042
|
-
const argLines = current.
|
|
9043
|
-
const sessionRows = current.
|
|
9086
|
+
const argLines = current.args ? wrapLines(prettyJson(current.args), bodyW) : ["(no arguments recorded)"];
|
|
9087
|
+
const sessionRows = current.session ? Math.min(4, sessionCalls.length) + 2 : 1;
|
|
9044
9088
|
const reasonShown = reasonLines.slice(0, 4);
|
|
9045
9089
|
const argBudget = Math.max(3, rows - 2 - 5 - reasonShown.length - 1 - sessionRows - 1);
|
|
9046
9090
|
const maxScroll = Math.max(0, argLines.length - argBudget);
|
|
9047
9091
|
const off = Math.min(detailScroll, maxScroll);
|
|
9048
9092
|
const argWin = argLines.slice(off, off + argBudget);
|
|
9049
|
-
return /* @__PURE__ */
|
|
9050
|
-
/* @__PURE__ */
|
|
9051
|
-
/* @__PURE__ */
|
|
9052
|
-
/* @__PURE__ */
|
|
9053
|
-
/* @__PURE__ */
|
|
9093
|
+
return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
|
|
9094
|
+
/* @__PURE__ */ jsxs6(Box6, { children: [
|
|
9095
|
+
/* @__PURE__ */ jsx6(Text6, { color: decisionColor(current.decision), bold: true, children: current.decision }),
|
|
9096
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.accent, children: " " + current.tool }),
|
|
9097
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: " " + current.permission + " \xB7 " + current.trust + " " }),
|
|
9098
|
+
srcChip
|
|
9054
9099
|
] }),
|
|
9055
|
-
reasonShown.map((l, i) => /* @__PURE__ */
|
|
9056
|
-
/* @__PURE__ */
|
|
9057
|
-
/* @__PURE__ */
|
|
9058
|
-
] }) : /* @__PURE__ */
|
|
9059
|
-
/* @__PURE__ */
|
|
9060
|
-
/* @__PURE__ */
|
|
9061
|
-
/* @__PURE__ */
|
|
9062
|
-
/* @__PURE__ */
|
|
9063
|
-
/* @__PURE__ */
|
|
9064
|
-
/* @__PURE__ */
|
|
9065
|
-
/* @__PURE__ */
|
|
9066
|
-
current.
|
|
9067
|
-
/* @__PURE__ */
|
|
9100
|
+
reasonShown.map((l, i) => /* @__PURE__ */ jsx6(Text6, { wrap: "truncate", children: i === 0 ? /* @__PURE__ */ jsxs6(Fragment4, { children: [
|
|
9101
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: "reason " }),
|
|
9102
|
+
/* @__PURE__ */ jsx6(Text6, { children: l.slice("reason: ".length) })
|
|
9103
|
+
] }) : /* @__PURE__ */ jsx6(Text6, { children: " " + l }) }, "r" + i)),
|
|
9104
|
+
/* @__PURE__ */ jsx6(Detail, { label: "rule", value: current.rule ?? "\u2014" }),
|
|
9105
|
+
/* @__PURE__ */ jsx6(Detail, { label: "agent", value: current.agent ?? "\u2014" }),
|
|
9106
|
+
/* @__PURE__ */ jsx6(Detail, { label: "session", value: current.session ?? "\u2014" }),
|
|
9107
|
+
/* @__PURE__ */ jsx6(Detail, { label: "dlp", value: current.dlp.length ? current.dlp.join(", ") : "none", color: current.dlp.length ? theme.bad : void 0 }),
|
|
9108
|
+
/* @__PURE__ */ jsx6(Detail, { label: "when", value: new Date(current.at).toLocaleString() + (current.evalMs != null ? ` \xB7 eval ${current.evalMs}ms` : "") }),
|
|
9109
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: `arguments \u2014 full \xB7 ${argLines.length} lines${maxScroll ? ` \xB7 \u25BC${maxScroll - off} more \xB7 \u2191\u2193 scroll` : ""}` }),
|
|
9110
|
+
/* @__PURE__ */ jsx6(Box6, { flexDirection: "column", height: argBudget, overflow: "hidden", children: argWin.map((l, i) => /* @__PURE__ */ jsx6(Text6, { wrap: "truncate", children: l || " " }, off + i)) }),
|
|
9111
|
+
current.session ? /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
|
|
9112
|
+
/* @__PURE__ */ jsxs6(Text6, { color: theme.dim, children: [
|
|
9068
9113
|
"Session \xB7 ",
|
|
9069
9114
|
sessionCalls.length,
|
|
9070
9115
|
" calls"
|
|
9071
9116
|
] }),
|
|
9072
|
-
/* @__PURE__ */
|
|
9117
|
+
/* @__PURE__ */ jsx6(
|
|
9073
9118
|
Table,
|
|
9074
9119
|
{
|
|
9075
9120
|
columns: [
|
|
@@ -9080,59 +9125,136 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
9080
9125
|
],
|
|
9081
9126
|
rows: sessionCalls.slice(0, Math.max(1, sessionRows - 2)).map((e) => [
|
|
9082
9127
|
{ value: e.decision, color: decisionColor(e.decision) },
|
|
9083
|
-
{ value: truncate2(e.
|
|
9128
|
+
{ value: truncate2(e.tool, 20), color: theme.accent },
|
|
9084
9129
|
{ value: truncate2(e.reason ?? "\u2014", Math.max(16, cols - 48)) },
|
|
9085
|
-
{ value: ago(e.
|
|
9130
|
+
{ value: ago(e.at), dim: true }
|
|
9086
9131
|
])
|
|
9087
9132
|
}
|
|
9088
9133
|
)
|
|
9089
|
-
] }) : /* @__PURE__ */
|
|
9090
|
-
/* @__PURE__ */
|
|
9134
|
+
] }) : /* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: "(no session id)" }),
|
|
9135
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: "\u2191\u2193 scroll arguments \xB7 \u2190/esc back to logs" })
|
|
9091
9136
|
] });
|
|
9092
9137
|
}
|
|
9093
|
-
const chip = (label, val, on) => /* @__PURE__ */
|
|
9094
|
-
/* @__PURE__ */
|
|
9138
|
+
const chip = (label, val, on) => /* @__PURE__ */ jsxs6(Text6, { children: [
|
|
9139
|
+
/* @__PURE__ */ jsxs6(Text6, { color: theme.dim, children: [
|
|
9095
9140
|
label,
|
|
9096
9141
|
":"
|
|
9097
9142
|
] }),
|
|
9098
|
-
/* @__PURE__ */
|
|
9099
|
-
/* @__PURE__ */
|
|
9143
|
+
/* @__PURE__ */ jsx6(Text6, { color: on ? theme.accentBright : theme.dim, children: val }),
|
|
9144
|
+
/* @__PURE__ */ jsx6(Text6, { children: " " })
|
|
9100
9145
|
] });
|
|
9101
|
-
|
|
9146
|
+
if (view === "sessions") {
|
|
9147
|
+
const headerRows2 = 5 + (editing ? 1 : 0);
|
|
9148
|
+
const listRows2 = Math.max(4, rows - headerRows2);
|
|
9149
|
+
const selC = Math.min(sessSel, Math.max(0, sessionsFiltered.length - 1));
|
|
9150
|
+
const start2 = Math.min(Math.max(0, selC - Math.floor((listRows2 - 1) / 2)), Math.max(0, sessionsFiltered.length - listRows2));
|
|
9151
|
+
const win = sessionsFiltered.slice(start2, start2 + listRows2);
|
|
9152
|
+
const loading2 = source === "cloud" ? agentsQ.loading && !agentsQ.data : localQ.loading && !localQ.data;
|
|
9153
|
+
return /* @__PURE__ */ jsx6(DataView, { loading: loading2, error: source === "cloud" ? agentsQ.error : localQ.error, children: /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
|
|
9154
|
+
strip,
|
|
9155
|
+
/* @__PURE__ */ jsxs6(Box6, { children: [
|
|
9156
|
+
srcChip,
|
|
9157
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.accentBright, bold: true, children: "SESSIONS" }),
|
|
9158
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: " \xB7 logs (v) " }),
|
|
9159
|
+
chip("status", SESS_STATUS[si] ?? "all", si !== 0),
|
|
9160
|
+
chip("search", sessSearch || "\xB7", !!sessSearch)
|
|
9161
|
+
] }),
|
|
9162
|
+
/* @__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" }),
|
|
9163
|
+
editing === "sess-search" ? /* @__PURE__ */ jsxs6(Box6, { children: [
|
|
9164
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.warn, children: "search: " }),
|
|
9165
|
+
/* @__PURE__ */ jsx6(
|
|
9166
|
+
TextInput4,
|
|
9167
|
+
{
|
|
9168
|
+
value: sessSearch,
|
|
9169
|
+
onChange: (v) => {
|
|
9170
|
+
setSessSearch(v);
|
|
9171
|
+
setSessSel(0);
|
|
9172
|
+
},
|
|
9173
|
+
onSubmit: () => setEditing(null)
|
|
9174
|
+
}
|
|
9175
|
+
)
|
|
9176
|
+
] }) : null,
|
|
9177
|
+
/* @__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}` : ""}` }),
|
|
9178
|
+
/* @__PURE__ */ jsx6(
|
|
9179
|
+
Table,
|
|
9180
|
+
{
|
|
9181
|
+
columns: [
|
|
9182
|
+
{ header: "", width: 2 },
|
|
9183
|
+
{ header: "STATUS", width: 8 },
|
|
9184
|
+
{ header: "AGENT", width: 18 },
|
|
9185
|
+
{ header: "SESSION", width: 10 },
|
|
9186
|
+
{ header: "CALLS", width: 6 },
|
|
9187
|
+
{ header: "DENY", width: 5 },
|
|
9188
|
+
{ header: "DLP", width: 4 },
|
|
9189
|
+
{ header: "TRUST", width: 5 },
|
|
9190
|
+
{ header: "LAST", width: 6 }
|
|
9191
|
+
],
|
|
9192
|
+
rows: win.map((r, i) => {
|
|
9193
|
+
const st = STATUS_DOT[r.status];
|
|
9194
|
+
const isSel = start2 + i === selC && focused;
|
|
9195
|
+
return [
|
|
9196
|
+
{ value: isSel ? "\u25B8" : "", color: theme.accentBright },
|
|
9197
|
+
{ value: `${st.ch} ${r.status}`, color: st.color },
|
|
9198
|
+
{ value: truncate2(r.agent, 18), color: theme.accent, bold: isSel },
|
|
9199
|
+
{ value: r.id.slice(0, 8), dim: true },
|
|
9200
|
+
{ value: String(r.calls) },
|
|
9201
|
+
{ value: String(r.denies), color: r.denies ? theme.bad : void 0, dim: !r.denies },
|
|
9202
|
+
{ value: String(r.dlp), color: r.dlp ? theme.bad : void 0, dim: !r.dlp },
|
|
9203
|
+
{ value: r.trust != null ? String(r.trust) : "\u2014", dim: true },
|
|
9204
|
+
{ value: ago(r.lastAt), dim: true }
|
|
9205
|
+
];
|
|
9206
|
+
})
|
|
9207
|
+
}
|
|
9208
|
+
),
|
|
9209
|
+
sessionsFiltered.length === 0 ? /* @__PURE__ */ jsxs6(Text6, { color: theme.dim, children: [
|
|
9210
|
+
"(no sessions",
|
|
9211
|
+
source === "local" ? " in the local file" : "",
|
|
9212
|
+
")"
|
|
9213
|
+
] }) : null
|
|
9214
|
+
] }) });
|
|
9215
|
+
}
|
|
9216
|
+
const headerRows = 6 + (editing && editing !== "sess-search" ? 1 : 0);
|
|
9102
9217
|
const listRows = Math.max(4, rows - headerRows);
|
|
9103
|
-
const selClamped = Math.min(sel, Math.max(0,
|
|
9104
|
-
const maxStart = Math.max(0,
|
|
9218
|
+
const selClamped = Math.min(sel, Math.max(0, pageRows.length - 1));
|
|
9219
|
+
const maxStart = Math.max(0, pageRows.length - listRows);
|
|
9105
9220
|
const start = Math.min(Math.max(0, selClamped - Math.floor((listRows - 1) / 2)), maxStart);
|
|
9106
|
-
const windowed =
|
|
9221
|
+
const windowed = pageRows.slice(start, start + listRows);
|
|
9107
9222
|
const reasonW = Math.min(60, Math.max(12, cols - 67));
|
|
9108
|
-
|
|
9109
|
-
|
|
9223
|
+
const loading = source === "cloud" ? cloudQ.loading && !cloudQ.data : localQ.loading && !localQ.data;
|
|
9224
|
+
return /* @__PURE__ */ jsx6(DataView, { loading, error: source === "cloud" ? cloudQ.error : localQ.error, children: /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
|
|
9225
|
+
strip,
|
|
9226
|
+
/* @__PURE__ */ jsxs6(Box6, { children: [
|
|
9227
|
+
srcChip,
|
|
9228
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.accentBright, bold: true, children: "LOGS" }),
|
|
9229
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: " \xB7 sessions (v) " }),
|
|
9110
9230
|
chip("dec", DECISIONS[di] ?? "all", di !== 0),
|
|
9111
9231
|
chip("sig", SIGNALS[gi] ?? "all", gi !== 0),
|
|
9112
9232
|
chip("tool", tool || "\xB7", !!tool),
|
|
9113
9233
|
chip("agent", agent || "\xB7", !!agent),
|
|
9114
|
-
chip("search", search || "\xB7", !!search)
|
|
9234
|
+
chip("search", search || "\xB7", !!search),
|
|
9235
|
+
sessFilter ? chip("sess", sessFilter.slice(0, 8), true) : null
|
|
9115
9236
|
] }),
|
|
9116
|
-
/* @__PURE__ */
|
|
9117
|
-
editing ? /* @__PURE__ */
|
|
9118
|
-
/* @__PURE__ */
|
|
9237
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, wrap: "truncate", children: focused ? "\u2191\u2193 select \xB7 enter full entry \xB7 [ ] 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" }),
|
|
9238
|
+
editing && editing !== "sess-search" ? /* @__PURE__ */ jsxs6(Box6, { children: [
|
|
9239
|
+
/* @__PURE__ */ jsxs6(Text6, { color: theme.warn, children: [
|
|
9119
9240
|
editing,
|
|
9120
9241
|
": "
|
|
9121
9242
|
] }),
|
|
9122
|
-
/* @__PURE__ */
|
|
9243
|
+
/* @__PURE__ */ jsx6(
|
|
9123
9244
|
TextInput4,
|
|
9124
9245
|
{
|
|
9125
9246
|
value: editing === "tool" ? tool : editing === "agent" ? agent : search,
|
|
9126
9247
|
onChange: (v) => {
|
|
9127
9248
|
(editing === "tool" ? setTool : editing === "agent" ? setAgent : setSearch)(v);
|
|
9128
|
-
|
|
9249
|
+
setPage(0);
|
|
9250
|
+
toTop();
|
|
9129
9251
|
},
|
|
9130
9252
|
onSubmit: () => setEditing(null)
|
|
9131
9253
|
}
|
|
9132
9254
|
)
|
|
9133
9255
|
] }) : null,
|
|
9134
|
-
/* @__PURE__ */
|
|
9135
|
-
/* @__PURE__ */
|
|
9256
|
+
/* @__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` : ""}` }),
|
|
9257
|
+
/* @__PURE__ */ jsx6(
|
|
9136
9258
|
Table,
|
|
9137
9259
|
{
|
|
9138
9260
|
columns: [
|
|
@@ -9146,51 +9268,81 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
9146
9268
|
],
|
|
9147
9269
|
rows: windowed.map((e, i) => rowFor(e, start + i === selClamped && focused, reasonW))
|
|
9148
9270
|
}
|
|
9149
|
-
)
|
|
9271
|
+
),
|
|
9272
|
+
pageRows.length === 0 ? /* @__PURE__ */ jsxs6(Text6, { color: theme.dim, children: [
|
|
9273
|
+
"(no entries",
|
|
9274
|
+
source === "local" ? " in the local file" : "",
|
|
9275
|
+
" \u2014 c clears filters)"
|
|
9276
|
+
] }) : null
|
|
9150
9277
|
] }) });
|
|
9151
9278
|
}
|
|
9152
9279
|
function rowFor(e, active2, reasonW) {
|
|
9153
9280
|
return [
|
|
9154
9281
|
{ value: active2 ? "\u25B8" : "", color: theme.accentBright },
|
|
9155
9282
|
{ value: e.decision, color: decisionColor(e.decision) },
|
|
9156
|
-
{ value: truncate2(e.
|
|
9157
|
-
{ value: truncate2(e.
|
|
9158
|
-
{ value: truncate2(e.reason ?? "\u2014", reasonW) },
|
|
9159
|
-
{ value: e.
|
|
9160
|
-
{ value: ago(e.
|
|
9283
|
+
{ value: truncate2(e.tool, 18), color: theme.accent },
|
|
9284
|
+
{ value: truncate2(e.agent ?? "\u2014", 14), dim: true },
|
|
9285
|
+
{ value: truncate2(e.reason ?? e.args ?? "\u2014", reasonW) },
|
|
9286
|
+
{ value: e.dlp.length ? String(e.dlp.length) : "0", color: e.dlp.length ? theme.bad : void 0, dim: !e.dlp.length },
|
|
9287
|
+
{ value: ago(e.at), dim: true }
|
|
9161
9288
|
];
|
|
9162
9289
|
}
|
|
9163
9290
|
function Detail({ label, value, color }) {
|
|
9164
|
-
return /* @__PURE__ */
|
|
9165
|
-
/* @__PURE__ */
|
|
9166
|
-
/* @__PURE__ */
|
|
9291
|
+
return /* @__PURE__ */ jsxs6(Box6, { children: [
|
|
9292
|
+
/* @__PURE__ */ jsx6(Text6, { color: theme.dim, children: label.padEnd(9) }),
|
|
9293
|
+
/* @__PURE__ */ jsx6(Text6, { color, wrap: "truncate", children: value })
|
|
9167
9294
|
] });
|
|
9168
9295
|
}
|
|
9169
|
-
var DECISIONS, SIGNALS,
|
|
9296
|
+
var DECISIONS, SIGNALS, SESS_STATUS, PAGE, LOCAL_MAX_BYTES, cloudRow, sessStatus2, STATUS_DOT;
|
|
9170
9297
|
var init_Audit = __esm({
|
|
9171
9298
|
"src/tui/panels/Audit.tsx"() {
|
|
9172
9299
|
"use strict";
|
|
9173
9300
|
init_api_client();
|
|
9174
9301
|
init_components();
|
|
9175
9302
|
init_hooks();
|
|
9303
|
+
init_local_log();
|
|
9176
9304
|
init_theme();
|
|
9177
9305
|
DECISIONS = [void 0, "DENY", "ALLOW"];
|
|
9178
9306
|
SIGNALS = [void 0, "dlp", "ratelimit"];
|
|
9179
|
-
|
|
9307
|
+
SESS_STATUS = [void 0, "active", "idle", "ended"];
|
|
9308
|
+
PAGE = 500;
|
|
9309
|
+
LOCAL_MAX_BYTES = 16 * 1024 * 1024;
|
|
9310
|
+
cloudRow = (e) => ({
|
|
9311
|
+
id: e.id,
|
|
9312
|
+
at: Date.parse(e.created_at),
|
|
9313
|
+
tool: e.tool_name,
|
|
9314
|
+
decision: e.decision,
|
|
9315
|
+
permission: e.permission,
|
|
9316
|
+
trust: e.trust_level,
|
|
9317
|
+
agent: e.agent_name,
|
|
9318
|
+
session: e.session_id,
|
|
9319
|
+
reason: e.reason,
|
|
9320
|
+
rule: e.matched_rule_id,
|
|
9321
|
+
evalMs: e.evaluation_time_ms,
|
|
9322
|
+
dlp: e.dlp_matches ?? [],
|
|
9323
|
+
burst: !!e.rate_limit_burst,
|
|
9324
|
+
args: e.arguments_summary ? JSON.stringify(e.arguments_summary) : null
|
|
9325
|
+
});
|
|
9326
|
+
sessStatus2 = (lastAt) => Date.now() - lastAt < 6e4 ? "active" : Date.now() - lastAt < 3e5 ? "idle" : "ended";
|
|
9327
|
+
STATUS_DOT = {
|
|
9328
|
+
active: { ch: "\u25CF", color: theme.ok },
|
|
9329
|
+
idle: { ch: "\u25D0", color: theme.warn },
|
|
9330
|
+
ended: { ch: "\u25CB", color: theme.dim }
|
|
9331
|
+
};
|
|
9180
9332
|
}
|
|
9181
9333
|
});
|
|
9182
9334
|
|
|
9183
9335
|
// src/tui/panels/Agents.tsx
|
|
9184
|
-
import { Box as
|
|
9336
|
+
import { Box as Box7, Text as Text7, useInput as useInput6 } from "ink";
|
|
9185
9337
|
import { useState as useState7 } from "react";
|
|
9186
|
-
import { Fragment as Fragment5, jsx as
|
|
9338
|
+
import { Fragment as Fragment5, jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
9187
9339
|
function Bar({ label, value, max = 100, width: width2 = 16, color = theme.accent }) {
|
|
9188
9340
|
const filled = max > 0 ? Math.round(Math.min(value, max) / max * width2) : 0;
|
|
9189
|
-
return /* @__PURE__ */
|
|
9190
|
-
/* @__PURE__ */
|
|
9191
|
-
/* @__PURE__ */
|
|
9192
|
-
/* @__PURE__ */
|
|
9193
|
-
/* @__PURE__ */
|
|
9341
|
+
return /* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
|
|
9342
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: label.padEnd(9) }),
|
|
9343
|
+
/* @__PURE__ */ jsx7(Text7, { color, children: "\u2588".repeat(filled) }),
|
|
9344
|
+
/* @__PURE__ */ jsx7(Text7, { color: "#233457", children: "\u2591".repeat(Math.max(0, width2 - filled)) }),
|
|
9345
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: " " + value })
|
|
9194
9346
|
] });
|
|
9195
9347
|
}
|
|
9196
9348
|
function AgentsPanel({ focused }) {
|
|
@@ -9215,50 +9367,50 @@ function AgentsPanel({ focused }) {
|
|
|
9215
9367
|
const tools = tmap?.tools ?? [];
|
|
9216
9368
|
const resources = tmap?.resources ?? [];
|
|
9217
9369
|
const listW = 30;
|
|
9218
|
-
return /* @__PURE__ */
|
|
9219
|
-
/* @__PURE__ */
|
|
9220
|
-
/* @__PURE__ */
|
|
9221
|
-
agents.slice(0, 16).map((a, i) => /* @__PURE__ */
|
|
9222
|
-
/* @__PURE__ */
|
|
9370
|
+
return /* @__PURE__ */ jsx7(DataView, { loading: live2.loading && !live2.data, error: live2.error, empty: !!live2.data && agents.length === 0, emptyText: "No identified agents yet.", children: /* @__PURE__ */ jsxs7(Box7, { children: [
|
|
9371
|
+
/* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", width: listW, marginRight: 2, overflow: "hidden", children: [
|
|
9372
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: focused ? "\u2191\u2193 select agent" : "press \u2192 to browse" }),
|
|
9373
|
+
agents.slice(0, 16).map((a, i) => /* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", backgroundColor: focused && i === sel ? "#1c2f63" : void 0, bold: i === sel, children: [
|
|
9374
|
+
/* @__PURE__ */ jsxs7(Text7, { color: statusColor(a.status), children: [
|
|
9223
9375
|
a.status === "active" ? "\u25CF" : a.status === "idle" ? "\u25D0" : "\u25CB",
|
|
9224
9376
|
" "
|
|
9225
9377
|
] }),
|
|
9226
|
-
/* @__PURE__ */
|
|
9227
|
-
/* @__PURE__ */
|
|
9378
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.accent, children: truncate2(a.agent_name ?? a.agent_id ?? "?", 16).padEnd(17) }),
|
|
9379
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: `t${a.trust_score}` })
|
|
9228
9380
|
] }, a.session_id))
|
|
9229
9381
|
] }),
|
|
9230
|
-
/* @__PURE__ */
|
|
9231
|
-
/* @__PURE__ */
|
|
9232
|
-
/* @__PURE__ */
|
|
9233
|
-
/* @__PURE__ */
|
|
9382
|
+
/* @__PURE__ */ jsx7(Box7, { flexDirection: "column", flexGrow: 1, overflow: "hidden", children: !selected ? /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "select an agent" }) : detail.loading && !d ? /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "loading profile\u2026" }) : !d ? /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "no profile (agent has no calls yet)" }) : /* @__PURE__ */ jsxs7(Fragment5, { children: [
|
|
9383
|
+
/* @__PURE__ */ jsxs7(Box7, { children: [
|
|
9384
|
+
/* @__PURE__ */ jsx7(Text7, { bold: true, color: theme.accentBright, children: truncate2(selected.agent_name ?? selected.agent_id ?? "?", 22) }),
|
|
9385
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: ` trust ${base?.trustScore ?? "\u2014"}/100 \xB7 ${base?.character ?? ""}` })
|
|
9234
9386
|
] }),
|
|
9235
|
-
base?.characterBlurb ? /* @__PURE__ */
|
|
9236
|
-
radar ? /* @__PURE__ */
|
|
9237
|
-
/* @__PURE__ */
|
|
9238
|
-
/* @__PURE__ */
|
|
9239
|
-
/* @__PURE__ */
|
|
9240
|
-
/* @__PURE__ */
|
|
9241
|
-
/* @__PURE__ */
|
|
9242
|
-
/* @__PURE__ */
|
|
9387
|
+
base?.characterBlurb ? /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: truncate2(String(base.characterBlurb), 70) }) : null,
|
|
9388
|
+
radar ? /* @__PURE__ */ jsxs7(Box7, { marginTop: 1, flexDirection: "column", children: [
|
|
9389
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "Behaviour radar (0\u2013100)" }),
|
|
9390
|
+
/* @__PURE__ */ jsx7(Bar, { label: "read", value: Math.round((radar.read ?? 0) * 100) }),
|
|
9391
|
+
/* @__PURE__ */ jsx7(Bar, { label: "write", value: Math.round((radar.write ?? 0) * 100), color: theme.warn }),
|
|
9392
|
+
/* @__PURE__ */ jsx7(Bar, { label: "execute", value: Math.round((radar.execute ?? 0) * 100), color: theme.warn }),
|
|
9393
|
+
/* @__PURE__ */ jsx7(Bar, { label: "network", value: Math.round((radar.network ?? 0) * 100) }),
|
|
9394
|
+
/* @__PURE__ */ jsx7(Bar, { label: "complian.", value: Math.round((radar.compliance ?? 0) * 100), color: theme.ok })
|
|
9243
9395
|
] }) : null,
|
|
9244
|
-
/* @__PURE__ */
|
|
9245
|
-
/* @__PURE__ */
|
|
9396
|
+
/* @__PURE__ */ jsxs7(Box7, { marginTop: 1, flexDirection: "column", children: [
|
|
9397
|
+
/* @__PURE__ */ jsxs7(Text7, { color: theme.dim, children: [
|
|
9246
9398
|
"Anomalies ",
|
|
9247
9399
|
anomalies2.length ? `(${anomalies2.length})` : ""
|
|
9248
9400
|
] }),
|
|
9249
|
-
anomalies2.length === 0 ? /* @__PURE__ */
|
|
9250
|
-
/* @__PURE__ */
|
|
9251
|
-
/* @__PURE__ */
|
|
9252
|
-
/* @__PURE__ */
|
|
9401
|
+
anomalies2.length === 0 ? /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: " none" }) : anomalies2.slice(0, 4).map((an, i) => /* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
|
|
9402
|
+
/* @__PURE__ */ jsx7(Text7, { color: sevColor(String(an.severity)), children: ` ${String(an.severity).toUpperCase().slice(0, 4).padEnd(5)}` }),
|
|
9403
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.accent, children: String(an.kind).padEnd(12) }),
|
|
9404
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: truncate2(String(an.description ?? ""), 44) })
|
|
9253
9405
|
] }, i))
|
|
9254
9406
|
] }),
|
|
9255
|
-
/* @__PURE__ */
|
|
9256
|
-
/* @__PURE__ */
|
|
9257
|
-
tools.slice(0, 4).map((t, i) => /* @__PURE__ */
|
|
9258
|
-
/* @__PURE__ */
|
|
9259
|
-
/* @__PURE__ */
|
|
9407
|
+
/* @__PURE__ */ jsxs7(Box7, { marginTop: 1, flexDirection: "column", children: [
|
|
9408
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "Trust map \xB7 top tools" }),
|
|
9409
|
+
tools.slice(0, 4).map((t, i) => /* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
|
|
9410
|
+
/* @__PURE__ */ jsx7(Text7, { color: t.anomalous ? theme.bad : theme.accent, children: ` ${truncate2(String(t.name), 16).padEnd(17)}` }),
|
|
9411
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: `${t.count}\xD7 ${t.permission ?? ""}` })
|
|
9260
9412
|
] }, i)),
|
|
9261
|
-
resources.slice(0, 3).map((r, i) => /* @__PURE__ */
|
|
9413
|
+
resources.slice(0, 3).map((r, i) => /* @__PURE__ */ jsx7(Text7, { 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))
|
|
9262
9414
|
] })
|
|
9263
9415
|
] }) })
|
|
9264
9416
|
] }) });
|
|
@@ -9277,10 +9429,10 @@ var init_Agents = __esm({
|
|
|
9277
9429
|
});
|
|
9278
9430
|
|
|
9279
9431
|
// src/tui/panels/Settings.tsx
|
|
9280
|
-
import { Box as
|
|
9432
|
+
import { Box as Box8, Text as Text8, useInput as useInput7 } from "ink";
|
|
9281
9433
|
import TextInput5 from "ink-text-input";
|
|
9282
9434
|
import { useState as useState8 } from "react";
|
|
9283
|
-
import { jsx as
|
|
9435
|
+
import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
9284
9436
|
function alertBodyFor(channel) {
|
|
9285
9437
|
const c2 = channel.trim();
|
|
9286
9438
|
const base = { name: "dataroom alert", threshold: 5, windowSeconds: 60, signal: "any" };
|
|
@@ -9405,7 +9557,7 @@ function SettingsPanel({ active: active2, focused }) {
|
|
|
9405
9557
|
const loading = localQ.loading && !localQ.data || whQ.loading && !whQ.data || alertQ.loading && !alertQ.data;
|
|
9406
9558
|
const error = localQ.error ?? whQ.error ?? alertQ.error;
|
|
9407
9559
|
const mark = (r) => keyOf(r) === keyOf(cur) && focused ? "\u25B8 " : " ";
|
|
9408
|
-
const onOff = (on) => on ? /* @__PURE__ */
|
|
9560
|
+
const onOff = (on) => on ? /* @__PURE__ */ jsx8(Text8, { color: theme.ok, children: "on " }) : /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "off" });
|
|
9409
9561
|
const chanOf = (rule) => [...(rule.slackUrls ?? []).map((u) => "slack " + u), ...rule.emails ?? [], ...(rule.telegram ?? []).map((t) => "tg " + t)].join(", ") || "\u2014";
|
|
9410
9562
|
const listBudget = Math.max(4, rows - 8);
|
|
9411
9563
|
const start = Math.min(Math.max(0, selClamped - Math.floor(listBudget / 2)), Math.max(0, rowsAll.length - listBudget));
|
|
@@ -9413,68 +9565,68 @@ function SettingsPanel({ active: active2, focused }) {
|
|
|
9413
9565
|
const i = rowsAll.findIndex((x) => keyOf(x) === keyOf(r));
|
|
9414
9566
|
return i >= start && i < start + listBudget;
|
|
9415
9567
|
};
|
|
9416
|
-
return /* @__PURE__ */
|
|
9417
|
-
/* @__PURE__ */
|
|
9418
|
-
editing ? /* @__PURE__ */
|
|
9419
|
-
/* @__PURE__ */
|
|
9420
|
-
/* @__PURE__ */
|
|
9421
|
-
] }) : msg ? /* @__PURE__ */
|
|
9422
|
-
inWindow(rowsAll[0]) || inWindow(rowsAll[1]) ? /* @__PURE__ */
|
|
9423
|
-
/* @__PURE__ */
|
|
9568
|
+
return /* @__PURE__ */ jsx8(DataView, { loading, error, children: /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
|
|
9569
|
+
/* @__PURE__ */ jsx8(Text8, { 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" }),
|
|
9570
|
+
editing ? /* @__PURE__ */ jsxs8(Box8, { children: [
|
|
9571
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.warn, children: editing === "path" ? "local log path: " : editing === "wh-url" ? "webhook url: " : "channel (slack url / email / telegram id): " }),
|
|
9572
|
+
/* @__PURE__ */ jsx8(TextInput5, { value: input, onChange: setInput, onSubmit: submitInput })
|
|
9573
|
+
] }) : msg ? /* @__PURE__ */ jsx8(Text8, { color: msg.level === "bad" ? theme.bad : theme.ok, children: truncate2(msg.text, cols) }) : /* @__PURE__ */ jsx8(Text8, { children: " " }),
|
|
9574
|
+
inWindow(rowsAll[0]) || inWindow(rowsAll[1]) ? /* @__PURE__ */ jsxs8(Box8, { marginTop: 1, flexDirection: "column", children: [
|
|
9575
|
+
/* @__PURE__ */ jsxs8(Text8, { bold: true, color: theme.accentBright, children: [
|
|
9424
9576
|
"LOCAL LOGS ",
|
|
9425
|
-
/* @__PURE__ */
|
|
9577
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "\u2014 hooks mirror every decision to a file on the agent machine" })
|
|
9426
9578
|
] }),
|
|
9427
|
-
/* @__PURE__ */
|
|
9428
|
-
/* @__PURE__ */
|
|
9429
|
-
/* @__PURE__ */
|
|
9579
|
+
/* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", children: [
|
|
9580
|
+
/* @__PURE__ */ jsx8(Text8, { color: keyOf(cur) === "ll-enabled" && focused ? theme.accentBright : theme.dim, children: mark(rowsAll[0]) }),
|
|
9581
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "enabled ".padEnd(10) }),
|
|
9430
9582
|
onOff(!!local?.enabled),
|
|
9431
|
-
/* @__PURE__ */
|
|
9583
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: " enter toggles" })
|
|
9432
9584
|
] }),
|
|
9433
|
-
/* @__PURE__ */
|
|
9434
|
-
/* @__PURE__ */
|
|
9435
|
-
/* @__PURE__ */
|
|
9436
|
-
local?.path ? /* @__PURE__ */
|
|
9585
|
+
/* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", children: [
|
|
9586
|
+
/* @__PURE__ */ jsx8(Text8, { color: keyOf(cur) === "ll-path" && focused ? theme.accentBright : theme.dim, children: mark(rowsAll[1]) }),
|
|
9587
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "path ".padEnd(10) }),
|
|
9588
|
+
local?.path ? /* @__PURE__ */ jsx8(Text8, { color: theme.accent, children: truncate2(local.path, cols - 14) }) : /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "not set \u2014 enter to edit" })
|
|
9437
9589
|
] })
|
|
9438
9590
|
] }) : null,
|
|
9439
|
-
/* @__PURE__ */
|
|
9440
|
-
/* @__PURE__ */
|
|
9591
|
+
/* @__PURE__ */ jsxs8(Box8, { marginTop: 1, flexDirection: "column", children: [
|
|
9592
|
+
/* @__PURE__ */ jsxs8(Text8, { bold: true, color: theme.accentBright, children: [
|
|
9441
9593
|
"WEBHOOKS ",
|
|
9442
|
-
/* @__PURE__ */
|
|
9594
|
+
/* @__PURE__ */ jsxs8(Text8, { color: theme.dim, children: [
|
|
9443
9595
|
"\u2014 POST every matching event to your endpoint (",
|
|
9444
9596
|
webhooks.length,
|
|
9445
9597
|
")"
|
|
9446
9598
|
] })
|
|
9447
9599
|
] }),
|
|
9448
|
-
webhooks.filter((wh) => inWindow({ kind: "wh", wh })).map((wh) => /* @__PURE__ */
|
|
9449
|
-
/* @__PURE__ */
|
|
9600
|
+
webhooks.filter((wh) => inWindow({ kind: "wh", wh })).map((wh) => /* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", children: [
|
|
9601
|
+
/* @__PURE__ */ jsx8(Text8, { color: keyOf(cur) === "wh:" + wh.id && focused ? theme.accentBright : theme.dim, children: mark({ kind: "wh", wh }) }),
|
|
9450
9602
|
onOff(wh.enabled),
|
|
9451
|
-
/* @__PURE__ */
|
|
9452
|
-
/* @__PURE__ */
|
|
9603
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.warn, children: (" " + wh.events).padEnd(9) }),
|
|
9604
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.accent, children: truncate2(wh.url, cols - 16) })
|
|
9453
9605
|
] }, wh.id)),
|
|
9454
|
-
inWindow(rowsAll.find((r) => r.kind === "wh-add")) ? /* @__PURE__ */
|
|
9455
|
-
/* @__PURE__ */
|
|
9456
|
-
/* @__PURE__ */
|
|
9606
|
+
inWindow(rowsAll.find((r) => r.kind === "wh-add")) ? /* @__PURE__ */ jsxs8(Text8, { children: [
|
|
9607
|
+
/* @__PURE__ */ jsx8(Text8, { color: cur.kind === "wh-add" && focused ? theme.accentBright : theme.dim, children: mark({ kind: "wh-add" }) }),
|
|
9608
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "+ add webhook (enter)" })
|
|
9457
9609
|
] }) : null
|
|
9458
9610
|
] }),
|
|
9459
|
-
/* @__PURE__ */
|
|
9460
|
-
/* @__PURE__ */
|
|
9611
|
+
/* @__PURE__ */ jsxs8(Box8, { marginTop: 1, flexDirection: "column", children: [
|
|
9612
|
+
/* @__PURE__ */ jsxs8(Text8, { bold: true, color: theme.accentBright, children: [
|
|
9461
9613
|
"ALERTS ",
|
|
9462
|
-
/* @__PURE__ */
|
|
9614
|
+
/* @__PURE__ */ jsxs8(Text8, { color: theme.dim, children: [
|
|
9463
9615
|
"\u2014 notify on a signal spike (",
|
|
9464
9616
|
alerts.length,
|
|
9465
9617
|
")"
|
|
9466
9618
|
] })
|
|
9467
9619
|
] }),
|
|
9468
|
-
alerts.filter((rule) => inWindow({ kind: "alert", rule })).map((rule) => /* @__PURE__ */
|
|
9469
|
-
/* @__PURE__ */
|
|
9620
|
+
alerts.filter((rule) => inWindow({ kind: "alert", rule })).map((rule) => /* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", children: [
|
|
9621
|
+
/* @__PURE__ */ jsx8(Text8, { color: keyOf(cur) === "alert:" + rule.id && focused ? theme.accentBright : theme.dim, children: mark({ kind: "alert", rule }) }),
|
|
9470
9622
|
onOff(rule.enabled),
|
|
9471
|
-
/* @__PURE__ */
|
|
9472
|
-
/* @__PURE__ */
|
|
9473
|
-
/* @__PURE__ */
|
|
9623
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.warn, children: (" " + rule.signal).padEnd(11) }),
|
|
9624
|
+
/* @__PURE__ */ jsx8(Text8, { children: `\u2265${rule.threshold}/${rule.windowSeconds}s ` }),
|
|
9625
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.accent, children: truncate2(chanOf(rule), cols - 26) })
|
|
9474
9626
|
] }, rule.id)),
|
|
9475
|
-
inWindow(rowsAll[rowsAll.length - 1]) ? /* @__PURE__ */
|
|
9476
|
-
/* @__PURE__ */
|
|
9477
|
-
/* @__PURE__ */
|
|
9627
|
+
inWindow(rowsAll[rowsAll.length - 1]) ? /* @__PURE__ */ jsxs8(Text8, { children: [
|
|
9628
|
+
/* @__PURE__ */ jsx8(Text8, { color: cur.kind === "alert-add" && focused ? theme.accentBright : theme.dim, children: mark({ kind: "alert-add" }) }),
|
|
9629
|
+
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "+ add alert (enter \u2014 one channel: slack url, email or telegram chat id)" })
|
|
9478
9630
|
] }) : null
|
|
9479
9631
|
] })
|
|
9480
9632
|
] }) });
|
|
@@ -9492,17 +9644,17 @@ var init_Settings = __esm({
|
|
|
9492
9644
|
});
|
|
9493
9645
|
|
|
9494
9646
|
// src/tui/App.tsx
|
|
9495
|
-
import { Box as
|
|
9647
|
+
import { Box as Box9, Text as Text9, useApp, useInput as useInput8 } from "ink";
|
|
9496
9648
|
import { useState as useState9 } from "react";
|
|
9497
|
-
import { jsx as
|
|
9649
|
+
import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
9498
9650
|
function LiveHint() {
|
|
9499
|
-
return /* @__PURE__ */
|
|
9500
|
-
/* @__PURE__ */
|
|
9501
|
-
/* @__PURE__ */
|
|
9502
|
-
/* @__PURE__ */
|
|
9503
|
-
/* @__PURE__ */
|
|
9651
|
+
return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", children: [
|
|
9652
|
+
/* @__PURE__ */ jsx9(Text9, { color: theme.accentBright, bold: true, children: "\u25B6 REALTIME CONSOLE" }),
|
|
9653
|
+
/* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: "Fullscreen live monitor \u2014 streaming tool calls, active charts," }),
|
|
9654
|
+
/* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: "counters, DLP hits and denial alerts. Updates every 2s." }),
|
|
9655
|
+
/* @__PURE__ */ jsx9(Box9, { marginTop: 1, children: /* @__PURE__ */ jsxs9(Text9, { children: [
|
|
9504
9656
|
"press ",
|
|
9505
|
-
/* @__PURE__ */
|
|
9657
|
+
/* @__PURE__ */ jsx9(Text9, { color: theme.accent, children: "enter" }),
|
|
9506
9658
|
" to go live"
|
|
9507
9659
|
] }) })
|
|
9508
9660
|
] });
|
|
@@ -9510,14 +9662,14 @@ function LiveHint() {
|
|
|
9510
9662
|
function Banner({ cols }) {
|
|
9511
9663
|
const wide = cols >= 82;
|
|
9512
9664
|
if (!wide) {
|
|
9513
|
-
return /* @__PURE__ */
|
|
9514
|
-
/* @__PURE__ */
|
|
9515
|
-
/* @__PURE__ */
|
|
9665
|
+
return /* @__PURE__ */ jsxs9(Box9, { children: [
|
|
9666
|
+
/* @__PURE__ */ jsx9(Text9, { bold: true, color: theme.accentBright, children: "SolonGate" }),
|
|
9667
|
+
/* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: " \u2014 security control center" })
|
|
9516
9668
|
] });
|
|
9517
9669
|
}
|
|
9518
|
-
return /* @__PURE__ */
|
|
9519
|
-
BANNER_FULL.map((line, i) => /* @__PURE__ */
|
|
9520
|
-
/* @__PURE__ */
|
|
9670
|
+
return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", children: [
|
|
9671
|
+
BANNER_FULL.map((line, i) => /* @__PURE__ */ jsx9(Text9, { bold: true, color: BANNER_HEX[i], children: line }, i)),
|
|
9672
|
+
/* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: " security control center \xB7 manage policies, rate limits, DLP & more" })
|
|
9521
9673
|
] });
|
|
9522
9674
|
}
|
|
9523
9675
|
function App() {
|
|
@@ -9546,31 +9698,31 @@ function App() {
|
|
|
9546
9698
|
});
|
|
9547
9699
|
const { cols, rows } = useTermSize();
|
|
9548
9700
|
const current = SECTIONS[section];
|
|
9549
|
-
if (help) return /* @__PURE__ */
|
|
9701
|
+
if (help) return /* @__PURE__ */ jsx9(HelpOverlay, { cols, rows });
|
|
9550
9702
|
if (current.label === "Live" && focus === "panel") {
|
|
9551
|
-
return /* @__PURE__ */
|
|
9703
|
+
return /* @__PURE__ */ jsx9(Box9, { flexDirection: "column", width: cols, height: rows, children: /* @__PURE__ */ jsx9(LivePanel, { active: true, focused: true }) });
|
|
9552
9704
|
}
|
|
9553
9705
|
const Panel = current.Panel;
|
|
9554
|
-
return /* @__PURE__ */
|
|
9555
|
-
/* @__PURE__ */
|
|
9556
|
-
/* @__PURE__ */
|
|
9557
|
-
/* @__PURE__ */
|
|
9558
|
-
/* @__PURE__ */
|
|
9706
|
+
return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", width: cols, height: rows, paddingX: 1, paddingTop: 1, children: [
|
|
9707
|
+
/* @__PURE__ */ jsx9(Banner, { cols }),
|
|
9708
|
+
/* @__PURE__ */ jsxs9(Box9, { marginTop: 1, flexGrow: 1, children: [
|
|
9709
|
+
/* @__PURE__ */ jsx9(Box9, { flexDirection: "column", width: 16, borderStyle: "round", borderColor: focus === "nav" ? theme.accent : "gray", paddingX: 1, children: SECTIONS.map((s, i) => /* @__PURE__ */ jsx9(Text9, { color: i === section ? theme.accentBright : void 0, bold: i === section, children: (i === section ? "\u25B8 " : " ") + s.label }, s.label)) }),
|
|
9710
|
+
/* @__PURE__ */ jsx9(Box9, { flexGrow: 1, borderStyle: "round", borderColor: focus === "panel" ? theme.accent : "gray", paddingX: 1, paddingY: 0, children: /* @__PURE__ */ jsx9(Panel, { active: focus === "panel" || current.label !== "Live", focused: focus === "panel" }) })
|
|
9559
9711
|
] }),
|
|
9560
|
-
/* @__PURE__ */
|
|
9712
|
+
/* @__PURE__ */ jsx9(Box9, { children: focus === "nav" ? /* @__PURE__ */ jsx9(KeyHints, { hints: [["\u2191\u2193", "section"], ["\u2192/enter", "open"], ["?", "help"], ["q", "quit"]] }) : /* @__PURE__ */ jsx9(KeyHints, { hints: [["\u2190/esc", "back"], ["\u2191\u2193", "in-panel"], ["space/s", "act"]] }) })
|
|
9561
9713
|
] });
|
|
9562
9714
|
}
|
|
9563
9715
|
function HelpOverlay({ cols, rows }) {
|
|
9564
|
-
return /* @__PURE__ */
|
|
9565
|
-
/* @__PURE__ */
|
|
9566
|
-
/* @__PURE__ */
|
|
9567
|
-
/* @__PURE__ */
|
|
9568
|
-
keys.map(([k, desc]) => /* @__PURE__ */
|
|
9569
|
-
/* @__PURE__ */
|
|
9570
|
-
/* @__PURE__ */
|
|
9716
|
+
return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", width: cols, height: rows, paddingX: 2, paddingTop: 1, children: [
|
|
9717
|
+
/* @__PURE__ */ jsx9(Text9, { bold: true, color: theme.accentBright, children: "SolonGate \u2014 keyboard shortcuts" }),
|
|
9718
|
+
/* @__PURE__ */ jsx9(Box9, { marginTop: 1, flexDirection: "column", children: HELP.map(([group, keys]) => /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", marginBottom: 1, children: [
|
|
9719
|
+
/* @__PURE__ */ jsx9(Text9, { bold: true, color: theme.accent, children: group }),
|
|
9720
|
+
keys.map(([k, desc]) => /* @__PURE__ */ jsxs9(Text9, { children: [
|
|
9721
|
+
/* @__PURE__ */ jsx9(Text9, { color: theme.accentBright, children: (" " + k).padEnd(16) }),
|
|
9722
|
+
/* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: desc })
|
|
9571
9723
|
] }, k))
|
|
9572
9724
|
] }, group)) }),
|
|
9573
|
-
/* @__PURE__ */
|
|
9725
|
+
/* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: "press any key to close" })
|
|
9574
9726
|
] });
|
|
9575
9727
|
}
|
|
9576
9728
|
var SECTIONS, BANNER_HEX, HELP;
|
|
@@ -9584,7 +9736,6 @@ var init_App = __esm({
|
|
|
9584
9736
|
init_Policies();
|
|
9585
9737
|
init_RateLimit();
|
|
9586
9738
|
init_Dlp();
|
|
9587
|
-
init_Stats();
|
|
9588
9739
|
init_Audit();
|
|
9589
9740
|
init_Agents();
|
|
9590
9741
|
init_Settings();
|
|
@@ -9595,7 +9746,6 @@ var init_App = __esm({
|
|
|
9595
9746
|
{ label: "Policies", Panel: PoliciesPanel },
|
|
9596
9747
|
{ label: "Rate Limit", Panel: RateLimitPanel },
|
|
9597
9748
|
{ label: "DLP", Panel: DlpPanel },
|
|
9598
|
-
{ label: "Stats", Panel: StatsPanel },
|
|
9599
9749
|
{ label: "Audit", Panel: AuditPanel },
|
|
9600
9750
|
{ label: "Settings", Panel: SettingsPanel }
|
|
9601
9751
|
];
|
|
@@ -9603,9 +9753,9 @@ var init_App = __esm({
|
|
|
9603
9753
|
HELP = [
|
|
9604
9754
|
["Global", [["\u2191\u2193", "move between sections"], ["\u2192 / enter", "open a section"], ["\u2190 / esc", "back to the menu"], ["?", "this help"], ["q", "quit"]]],
|
|
9605
9755
|
["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)"]]],
|
|
9606
|
-
["Policies", [["\u2191\u2193", "browse / select"], ["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"], ["
|
|
9756
|
+
["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"]]],
|
|
9607
9757
|
["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"]]],
|
|
9608
|
-
["Audit", [["\u2191\u2193", "select (list scrolls)"], ["enter", "full entry
|
|
9758
|
+
["Audit", [["v", "logs \u2194 sessions"], ["s", "source: cloud \u2194 local"], ["[ / ]", "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"]]],
|
|
9609
9759
|
["Settings", [["\u2191\u2193", "move"], ["enter / space", "toggle \xB7 edit \xB7 add"], ["e", "webhook events"], ["d d", "delete"], ["r", "refresh"]]]
|
|
9610
9760
|
];
|
|
9611
9761
|
}
|
|
@@ -9617,7 +9767,7 @@ __export(tui_exports, {
|
|
|
9617
9767
|
launchTui: () => launchTui
|
|
9618
9768
|
});
|
|
9619
9769
|
import { render } from "ink";
|
|
9620
|
-
import { jsx as
|
|
9770
|
+
import { jsx as jsx10 } from "react/jsx-runtime";
|
|
9621
9771
|
async function launchTui() {
|
|
9622
9772
|
if (!process.stdout.isTTY || !process.stdin.isTTY) {
|
|
9623
9773
|
process.stderr.write(
|
|
@@ -9631,7 +9781,7 @@ async function launchTui() {
|
|
|
9631
9781
|
}
|
|
9632
9782
|
process.stdout.write("\x1B[?1049h\x1B[H");
|
|
9633
9783
|
try {
|
|
9634
|
-
const { waitUntilExit } = render(/* @__PURE__ */
|
|
9784
|
+
const { waitUntilExit } = render(/* @__PURE__ */ jsx10(App, {}));
|
|
9635
9785
|
await waitUntilExit();
|
|
9636
9786
|
} finally {
|
|
9637
9787
|
process.stdout.write("\x1B[?1049l");
|
|
@@ -10334,8 +10484,8 @@ var init_agents2 = __esm({
|
|
|
10334
10484
|
|
|
10335
10485
|
// src/commands/doctor.ts
|
|
10336
10486
|
import { existsSync as existsSync4, statSync as statSync2 } from "fs";
|
|
10337
|
-
import { homedir as
|
|
10338
|
-
import { join as
|
|
10487
|
+
import { homedir as homedir6 } from "os";
|
|
10488
|
+
import { join as join8 } from "path";
|
|
10339
10489
|
async function run6(argv) {
|
|
10340
10490
|
const { flags } = parse(argv);
|
|
10341
10491
|
const json = flagBool(flags, "json");
|
|
@@ -10395,14 +10545,14 @@ var init_doctor = __esm({
|
|
|
10395
10545
|
init_api_client();
|
|
10396
10546
|
init_format();
|
|
10397
10547
|
init_args();
|
|
10398
|
-
LOCAL_LOG2 =
|
|
10548
|
+
LOCAL_LOG2 = join8(homedir6(), ".solongate", "local-logs", "solongate-audit.jsonl");
|
|
10399
10549
|
}
|
|
10400
10550
|
});
|
|
10401
10551
|
|
|
10402
10552
|
// src/commands/watch.ts
|
|
10403
10553
|
import { closeSync as closeSync2, existsSync as existsSync5, openSync as openSync2, readSync as readSync2, statSync as statSync3 } from "fs";
|
|
10404
|
-
import { homedir as
|
|
10405
|
-
import { join as
|
|
10554
|
+
import { homedir as homedir7 } from "os";
|
|
10555
|
+
import { join as join9 } from "path";
|
|
10406
10556
|
function tailLocal(file, maxBytes = 131072) {
|
|
10407
10557
|
try {
|
|
10408
10558
|
const size = statSync3(file).size;
|
|
@@ -10509,7 +10659,7 @@ var init_watch = __esm({
|
|
|
10509
10659
|
init_cli_utils();
|
|
10510
10660
|
init_args();
|
|
10511
10661
|
init_format();
|
|
10512
|
-
LOCAL_LOG3 =
|
|
10662
|
+
LOCAL_LOG3 = join9(homedir7(), ".solongate", "local-logs", "solongate-audit.jsonl");
|
|
10513
10663
|
trunc = (s, n) => s.length <= n ? s : s.slice(0, n - 1) + "\u2026";
|
|
10514
10664
|
time = (ms) => new Date(ms).toTimeString().slice(0, 8);
|
|
10515
10665
|
}
|
|
@@ -10812,8 +10962,8 @@ __export(global_install_exports, {
|
|
|
10812
10962
|
unlockProtected: () => unlockProtected
|
|
10813
10963
|
});
|
|
10814
10964
|
import { readFileSync as readFileSync7, writeFileSync as writeFileSync4, existsSync as existsSync6, mkdirSync as mkdirSync4 } from "fs";
|
|
10815
|
-
import { resolve as resolve4, join as
|
|
10816
|
-
import { homedir as
|
|
10965
|
+
import { resolve as resolve4, join as join10, dirname } from "path";
|
|
10966
|
+
import { homedir as homedir8 } from "os";
|
|
10817
10967
|
import { fileURLToPath } from "url";
|
|
10818
10968
|
import { createInterface } from "readline";
|
|
10819
10969
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
@@ -10876,10 +11026,10 @@ function unlockFile(file) {
|
|
|
10876
11026
|
function protectedTargets() {
|
|
10877
11027
|
const p = globalPaths();
|
|
10878
11028
|
return [
|
|
10879
|
-
|
|
10880
|
-
|
|
10881
|
-
|
|
10882
|
-
|
|
11029
|
+
join10(p.hooksDir, "guard.mjs"),
|
|
11030
|
+
join10(p.hooksDir, "audit.mjs"),
|
|
11031
|
+
join10(p.hooksDir, "stop.mjs"),
|
|
11032
|
+
join10(p.hooksDir, "shield.mjs"),
|
|
10883
11033
|
p.configPath,
|
|
10884
11034
|
p.settingsPath
|
|
10885
11035
|
];
|
|
@@ -10891,25 +11041,25 @@ function unlockProtected() {
|
|
|
10891
11041
|
for (const f of protectedTargets()) unlockFile(f);
|
|
10892
11042
|
}
|
|
10893
11043
|
function globalPaths() {
|
|
10894
|
-
const home =
|
|
10895
|
-
const sgDir =
|
|
10896
|
-
const hooksDir =
|
|
10897
|
-
const claudeDir =
|
|
11044
|
+
const home = homedir8();
|
|
11045
|
+
const sgDir = join10(home, ".solongate");
|
|
11046
|
+
const hooksDir = join10(sgDir, "hooks");
|
|
11047
|
+
const claudeDir = join10(home, ".claude");
|
|
10898
11048
|
return {
|
|
10899
11049
|
home,
|
|
10900
11050
|
sgDir,
|
|
10901
11051
|
hooksDir,
|
|
10902
11052
|
claudeDir,
|
|
10903
|
-
settingsPath:
|
|
10904
|
-
backupPath:
|
|
10905
|
-
configPath:
|
|
11053
|
+
settingsPath: join10(claudeDir, "settings.json"),
|
|
11054
|
+
backupPath: join10(claudeDir, "settings.solongate.bak"),
|
|
11055
|
+
configPath: join10(sgDir, "cloud-guard.json")
|
|
10906
11056
|
};
|
|
10907
11057
|
}
|
|
10908
11058
|
function readHook(filename) {
|
|
10909
|
-
return readFileSync7(
|
|
11059
|
+
return readFileSync7(join10(HOOKS_DIR, filename), "utf-8");
|
|
10910
11060
|
}
|
|
10911
11061
|
function readGuard() {
|
|
10912
|
-
const bundled =
|
|
11062
|
+
const bundled = join10(HOOKS_DIR, "guard.bundled.mjs");
|
|
10913
11063
|
return existsSync6(bundled) ? readFileSync7(bundled, "utf-8") : readHook("guard.mjs");
|
|
10914
11064
|
}
|
|
10915
11065
|
function ask(question) {
|
|
@@ -10964,7 +11114,7 @@ function shimTargets() {
|
|
|
10964
11114
|
return [];
|
|
10965
11115
|
}
|
|
10966
11116
|
}
|
|
10967
|
-
return [".bashrc", ".zshrc", ".profile"].map((f) =>
|
|
11117
|
+
return [".bashrc", ".zshrc", ".profile"].map((f) => join10(homedir8(), f)).filter((f) => existsSync6(f));
|
|
10968
11118
|
}
|
|
10969
11119
|
function writeShimBlock(file, block2) {
|
|
10970
11120
|
const re = new RegExp(escapeRe(SHIM_BEGIN) + "[\\s\\S]*?" + escapeRe(SHIM_END) + "\\r?\\n?", "g");
|
|
@@ -11029,12 +11179,12 @@ async function runGlobalInstall(opts = {}) {
|
|
|
11029
11179
|
mkdirSync4(p.hooksDir, { recursive: true });
|
|
11030
11180
|
mkdirSync4(p.claudeDir, { recursive: true });
|
|
11031
11181
|
unlockProtected();
|
|
11032
|
-
writeFileSync4(
|
|
11033
|
-
writeFileSync4(
|
|
11034
|
-
writeFileSync4(
|
|
11035
|
-
writeFileSync4(
|
|
11182
|
+
writeFileSync4(join10(p.hooksDir, "guard.mjs"), readGuard());
|
|
11183
|
+
writeFileSync4(join10(p.hooksDir, "audit.mjs"), readHook("audit.mjs"));
|
|
11184
|
+
writeFileSync4(join10(p.hooksDir, "stop.mjs"), readHook("stop.mjs"));
|
|
11185
|
+
writeFileSync4(join10(p.hooksDir, "shield.mjs"), readHook("shield.mjs"));
|
|
11036
11186
|
console.log(` Installed hooks \u2192 ${p.hooksDir}`);
|
|
11037
|
-
installClaudeShim(
|
|
11187
|
+
installClaudeShim(join10(p.hooksDir, "shield.mjs"));
|
|
11038
11188
|
writeFileSync4(p.configPath, JSON.stringify({ apiKey, apiUrl }, null, 2) + "\n");
|
|
11039
11189
|
console.log(` Wrote ${p.configPath}`);
|
|
11040
11190
|
let existing = {};
|
|
@@ -11050,9 +11200,9 @@ async function runGlobalInstall(opts = {}) {
|
|
|
11050
11200
|
existing = {};
|
|
11051
11201
|
}
|
|
11052
11202
|
}
|
|
11053
|
-
const guardAbs =
|
|
11054
|
-
const auditAbs =
|
|
11055
|
-
const stopAbs =
|
|
11203
|
+
const guardAbs = join10(p.hooksDir, "guard.mjs").replace(/\\/g, "/");
|
|
11204
|
+
const auditAbs = join10(p.hooksDir, "audit.mjs").replace(/\\/g, "/");
|
|
11205
|
+
const stopAbs = join10(p.hooksDir, "stop.mjs").replace(/\\/g, "/");
|
|
11056
11206
|
const nodeBin = process.execPath.replace(/\\/g, "/");
|
|
11057
11207
|
const call = process.platform === "win32" ? "& " : "";
|
|
11058
11208
|
const hookCmd = (script) => `${call}"${nodeBin}" "${script}" claude-code "Claude Code"`;
|
|
@@ -11246,9 +11396,9 @@ import { spawn as spawn3 } from "child_process";
|
|
|
11246
11396
|
import { URL as URL2 } from "url";
|
|
11247
11397
|
import { readFileSync as readFileSync8, existsSync as existsSync7, readdirSync, statSync as statSync4 } from "fs";
|
|
11248
11398
|
import { resolve as resolve5 } from "path";
|
|
11249
|
-
import { homedir as
|
|
11399
|
+
import { homedir as homedir9 } from "os";
|
|
11250
11400
|
function findCacheFile() {
|
|
11251
|
-
const dir = resolve5(
|
|
11401
|
+
const dir = resolve5(homedir9(), ".solongate");
|
|
11252
11402
|
const envSel = process.env.SOLONGATE_AGENT_ID;
|
|
11253
11403
|
if (envSel) {
|
|
11254
11404
|
const f = resolve5(dir, ".policy-cache-" + envSel.replace(/[^a-zA-Z0-9_-]/g, "_") + ".json");
|
|
@@ -11563,8 +11713,8 @@ __export(logs_server_exports, {
|
|
|
11563
11713
|
});
|
|
11564
11714
|
import { createServer as createServer2 } from "http";
|
|
11565
11715
|
import { readFileSync as readFileSync9, statSync as statSync5 } from "fs";
|
|
11566
|
-
import { resolve as resolve6, join as
|
|
11567
|
-
import { homedir as
|
|
11716
|
+
import { resolve as resolve6, join as join11, isAbsolute } from "path";
|
|
11717
|
+
import { homedir as homedir10 } from "os";
|
|
11568
11718
|
import { readdirSync as readdirSync2 } from "fs";
|
|
11569
11719
|
function allowedOrigins() {
|
|
11570
11720
|
const base = [
|
|
@@ -11581,15 +11731,15 @@ function resolveLocalLogDir(rawPath) {
|
|
|
11581
11731
|
const dir = String(rawPath || "").trim().replace(/[\\/]+$/, "");
|
|
11582
11732
|
if (!dir) return null;
|
|
11583
11733
|
if (isAbsolute(dir)) return dir;
|
|
11584
|
-
return resolve6(
|
|
11734
|
+
return resolve6(homedir10(), ".solongate", "local-logs");
|
|
11585
11735
|
}
|
|
11586
11736
|
async function findLogDir() {
|
|
11587
|
-
const base = resolve6(
|
|
11737
|
+
const base = resolve6(homedir10(), ".solongate");
|
|
11588
11738
|
try {
|
|
11589
11739
|
const files = readdirSync2(base).filter((f) => f.startsWith(".policy-cache-") && f.endsWith(".json"));
|
|
11590
11740
|
for (const f of files) {
|
|
11591
11741
|
try {
|
|
11592
|
-
const c2 = JSON.parse(readFileSync9(
|
|
11742
|
+
const c2 = JSON.parse(readFileSync9(join11(base, f), "utf-8"));
|
|
11593
11743
|
const p = c2?.security?.localLogs?.path;
|
|
11594
11744
|
if (typeof p === "string" && p.trim()) return { dir: resolveLocalLogDir(p), configured: p };
|
|
11595
11745
|
} catch {
|
|
@@ -11598,7 +11748,7 @@ async function findLogDir() {
|
|
|
11598
11748
|
} catch {
|
|
11599
11749
|
}
|
|
11600
11750
|
try {
|
|
11601
|
-
const cfgRaw = readFileSync9(
|
|
11751
|
+
const cfgRaw = readFileSync9(join11(base, "cloud-guard.json"), "utf-8");
|
|
11602
11752
|
const { apiKey, apiUrl } = JSON.parse(cfgRaw);
|
|
11603
11753
|
if (apiKey) {
|
|
11604
11754
|
const url = `${apiUrl || "https://api.solongate.com"}/api/v1/policies/active`;
|
|
@@ -11627,7 +11777,7 @@ function setCors(req, res) {
|
|
|
11627
11777
|
}
|
|
11628
11778
|
function fileInfo(dir) {
|
|
11629
11779
|
if (!dir) return { file: null, exists: false, size: 0, mtimeMs: 0 };
|
|
11630
|
-
const file =
|
|
11780
|
+
const file = join11(dir, LOG_FILENAME);
|
|
11631
11781
|
try {
|
|
11632
11782
|
const st = statSync5(file);
|
|
11633
11783
|
return { file, exists: true, size: st.size, mtimeMs: st.mtimeMs };
|
|
@@ -12078,7 +12228,7 @@ var init_inject = __esm({
|
|
|
12078
12228
|
// src/create.ts
|
|
12079
12229
|
var create_exports = {};
|
|
12080
12230
|
import { mkdirSync as mkdirSync5, writeFileSync as writeFileSync6, existsSync as existsSync9 } from "fs";
|
|
12081
|
-
import { resolve as resolve8, join as
|
|
12231
|
+
import { resolve as resolve8, join as join12 } from "path";
|
|
12082
12232
|
import { execSync as execSync2 } from "child_process";
|
|
12083
12233
|
function withSpinner(message, fn) {
|
|
12084
12234
|
const frames = ["\u28FE", "\u28FD", "\u28FB", "\u28BF", "\u287F", "\u28DF", "\u28EF", "\u28F7"];
|
|
@@ -12158,7 +12308,7 @@ EXAMPLES
|
|
|
12158
12308
|
}
|
|
12159
12309
|
function createProject(dir, name, _policy) {
|
|
12160
12310
|
writeFileSync6(
|
|
12161
|
-
|
|
12311
|
+
join12(dir, "package.json"),
|
|
12162
12312
|
JSON.stringify(
|
|
12163
12313
|
{
|
|
12164
12314
|
name,
|
|
@@ -12188,7 +12338,7 @@ function createProject(dir, name, _policy) {
|
|
|
12188
12338
|
) + "\n"
|
|
12189
12339
|
);
|
|
12190
12340
|
writeFileSync6(
|
|
12191
|
-
|
|
12341
|
+
join12(dir, "tsconfig.json"),
|
|
12192
12342
|
JSON.stringify(
|
|
12193
12343
|
{
|
|
12194
12344
|
compilerOptions: {
|
|
@@ -12208,9 +12358,9 @@ function createProject(dir, name, _policy) {
|
|
|
12208
12358
|
2
|
|
12209
12359
|
) + "\n"
|
|
12210
12360
|
);
|
|
12211
|
-
mkdirSync5(
|
|
12361
|
+
mkdirSync5(join12(dir, "src"), { recursive: true });
|
|
12212
12362
|
writeFileSync6(
|
|
12213
|
-
|
|
12363
|
+
join12(dir, "src", "index.ts"),
|
|
12214
12364
|
`#!/usr/bin/env node
|
|
12215
12365
|
|
|
12216
12366
|
console.log = (...args: unknown[]) => {
|
|
@@ -12252,7 +12402,7 @@ console.log('Press Ctrl+C to stop.');
|
|
|
12252
12402
|
`
|
|
12253
12403
|
);
|
|
12254
12404
|
writeFileSync6(
|
|
12255
|
-
|
|
12405
|
+
join12(dir, ".mcp.json"),
|
|
12256
12406
|
JSON.stringify(
|
|
12257
12407
|
{
|
|
12258
12408
|
mcpServers: {
|
|
@@ -12270,12 +12420,12 @@ console.log('Press Ctrl+C to stop.');
|
|
|
12270
12420
|
) + "\n"
|
|
12271
12421
|
);
|
|
12272
12422
|
writeFileSync6(
|
|
12273
|
-
|
|
12423
|
+
join12(dir, ".env"),
|
|
12274
12424
|
`SOLONGATE_API_KEY=sg_live_YOUR_KEY_HERE
|
|
12275
12425
|
`
|
|
12276
12426
|
);
|
|
12277
12427
|
writeFileSync6(
|
|
12278
|
-
|
|
12428
|
+
join12(dir, ".gitignore"),
|
|
12279
12429
|
`node_modules/
|
|
12280
12430
|
dist/
|
|
12281
12431
|
*.solongate-backup
|