@solongate/proxy 0.81.18 → 0.81.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api-client/settings.d.ts +16 -0
- package/dist/commands/index.js +17 -1
- package/dist/index.js +598 -326
- package/dist/tui/hooks.d.ts +14 -0
- package/dist/tui/index.js +489 -227
- package/dist/tui/notify.d.ts +1 -3
- package/dist/tui/panels/Settings.d.ts +4 -0
- package/dist/tui/theme.d.ts +4 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -6750,6 +6750,25 @@ function sparkline(values, width2) {
|
|
|
6750
6750
|
if (max === 0) return BLOCKS[0].repeat(v.length);
|
|
6751
6751
|
return v.map((n) => BLOCKS[Math.min(BLOCKS.length - 1, Math.round(n / max * (BLOCKS.length - 1)))]).join("");
|
|
6752
6752
|
}
|
|
6753
|
+
function prettyJson(s) {
|
|
6754
|
+
try {
|
|
6755
|
+
return JSON.stringify(JSON.parse(s), null, 2);
|
|
6756
|
+
} catch {
|
|
6757
|
+
return s;
|
|
6758
|
+
}
|
|
6759
|
+
}
|
|
6760
|
+
function wrapLines(s, width2) {
|
|
6761
|
+
const w = Math.max(8, width2);
|
|
6762
|
+
const out2 = [];
|
|
6763
|
+
for (const raw of (s ?? "").split("\n")) {
|
|
6764
|
+
if (raw.length <= w) {
|
|
6765
|
+
out2.push(raw);
|
|
6766
|
+
continue;
|
|
6767
|
+
}
|
|
6768
|
+
for (let i = 0; i < raw.length; i += w) out2.push(raw.slice(i, i + w));
|
|
6769
|
+
}
|
|
6770
|
+
return out2;
|
|
6771
|
+
}
|
|
6753
6772
|
function truncate2(s, n) {
|
|
6754
6773
|
if (!s) return "";
|
|
6755
6774
|
return s.length <= n ? s : s.slice(0, Math.max(0, n - 1)) + "\u2026";
|
|
@@ -6903,12 +6922,16 @@ __export(settings_exports, {
|
|
|
6903
6922
|
deleteWebhook: () => deleteWebhook,
|
|
6904
6923
|
getAlerts: () => getAlerts,
|
|
6905
6924
|
getGuardStatus: () => getGuardStatus,
|
|
6925
|
+
getLocalLogs: () => getLocalLogs,
|
|
6906
6926
|
getRateLimitHistory: () => getRateLimitHistory,
|
|
6907
6927
|
getSecurityLayers: () => getSecurityLayers,
|
|
6908
6928
|
getSelfProtection: () => getSelfProtection,
|
|
6909
6929
|
getWebhooks: () => getWebhooks,
|
|
6930
|
+
setAlertEnabled: () => setAlertEnabled,
|
|
6931
|
+
setLocalLogs: () => setLocalLogs,
|
|
6910
6932
|
setSecurityLayers: () => setSecurityLayers,
|
|
6911
|
-
setSelfProtection: () => setSelfProtection
|
|
6933
|
+
setSelfProtection: () => setSelfProtection,
|
|
6934
|
+
updateWebhook: () => updateWebhook
|
|
6912
6935
|
});
|
|
6913
6936
|
function getSecurityLayers() {
|
|
6914
6937
|
return request("GET", "/settings/security-layers");
|
|
@@ -6931,6 +6954,12 @@ function getSelfProtection() {
|
|
|
6931
6954
|
function setSelfProtection(enabled) {
|
|
6932
6955
|
return request("PUT", "/settings/self-protection", { body: { enabled } });
|
|
6933
6956
|
}
|
|
6957
|
+
function getLocalLogs() {
|
|
6958
|
+
return request("GET", "/settings/local-logs");
|
|
6959
|
+
}
|
|
6960
|
+
function setLocalLogs(cfg) {
|
|
6961
|
+
return request("PUT", "/settings/local-logs", { body: cfg });
|
|
6962
|
+
}
|
|
6934
6963
|
function getAlerts() {
|
|
6935
6964
|
return request("GET", "/settings/denial-alerts");
|
|
6936
6965
|
}
|
|
@@ -6940,6 +6969,9 @@ function createAlert(body) {
|
|
|
6940
6969
|
function deleteAlert(id) {
|
|
6941
6970
|
return request("DELETE", "/settings/denial-alerts", { query: { id } });
|
|
6942
6971
|
}
|
|
6972
|
+
function setAlertEnabled(id, enabled) {
|
|
6973
|
+
return request("PATCH", "/settings/denial-alerts", { query: { id }, body: { enabled } });
|
|
6974
|
+
}
|
|
6943
6975
|
function getWebhooks() {
|
|
6944
6976
|
return request("GET", "/settings/denial-webhook");
|
|
6945
6977
|
}
|
|
@@ -6949,6 +6981,9 @@ function createWebhook(body) {
|
|
|
6949
6981
|
function deleteWebhook(id) {
|
|
6950
6982
|
return request("DELETE", "/settings/denial-webhook", { query: { id } });
|
|
6951
6983
|
}
|
|
6984
|
+
function updateWebhook(id, patch) {
|
|
6985
|
+
return request("PATCH", "/settings/denial-webhook", { body: { id, ...patch } });
|
|
6986
|
+
}
|
|
6952
6987
|
var init_settings = __esm({
|
|
6953
6988
|
"src/api-client/settings.ts"() {
|
|
6954
6989
|
"use strict";
|
|
@@ -7090,145 +7125,34 @@ var init_api_client = __esm({
|
|
|
7090
7125
|
});
|
|
7091
7126
|
|
|
7092
7127
|
// src/tui/notify.ts
|
|
7093
|
-
import { spawn
|
|
7094
|
-
|
|
7095
|
-
import { join as join6 } from "path";
|
|
7096
|
-
import { tmpdir as tmpdir2 } from "os";
|
|
7097
|
-
function captureFocusTarget() {
|
|
7128
|
+
import { spawn } from "child_process";
|
|
7129
|
+
function desktopNotify(title, msg) {
|
|
7098
7130
|
try {
|
|
7099
7131
|
if (process.platform === "linux") {
|
|
7100
|
-
|
|
7101
|
-
|
|
7102
|
-
|
|
7103
|
-
|
|
7104
|
-
} catch {
|
|
7105
|
-
focusToken = null;
|
|
7106
|
-
}
|
|
7107
|
-
}
|
|
7132
|
+
const p = spawn("notify-send", ["-a", "SolonGate", title, msg], { stdio: "ignore", detached: true });
|
|
7133
|
+
p.on("error", () => {
|
|
7134
|
+
});
|
|
7135
|
+
p.unref();
|
|
7108
7136
|
} else if (process.platform === "win32") {
|
|
7109
|
-
const
|
|
7110
|
-
|
|
7111
|
-
|
|
7112
|
-
|
|
7113
|
-
|
|
7114
|
-
|
|
7137
|
+
const q = (s) => s.replace(/'/g, "''");
|
|
7138
|
+
const ps = `Add-Type -AssemblyName System.Windows.Forms;Add-Type -AssemblyName System.Drawing;$n=New-Object System.Windows.Forms.NotifyIcon;$n.Icon=[System.Drawing.SystemIcons]::Information;$n.Visible=$true;$n.ShowBalloonTip(6000,'${q(title)}','${q(msg)}',[System.Windows.Forms.ToolTipIcon]::Warning);Start-Sleep -Milliseconds 6500;$n.Dispose()`;
|
|
7139
|
+
const p = spawn("powershell", ["-NoProfile", "-NonInteractive", "-Command", ps], { stdio: "ignore", detached: true, windowsHide: true });
|
|
7140
|
+
p.on("error", () => {
|
|
7141
|
+
});
|
|
7142
|
+
p.unref();
|
|
7143
|
+
} else if (process.platform === "darwin") {
|
|
7144
|
+
const esc = (s) => s.replace(/"/g, '\\"');
|
|
7145
|
+
const p = spawn("osascript", ["-e", `display notification "${esc(msg)}" with title "${esc(title)}"`], { stdio: "ignore", detached: true });
|
|
7146
|
+
p.on("error", () => {
|
|
7147
|
+
});
|
|
7148
|
+
p.unref();
|
|
7115
7149
|
}
|
|
7116
|
-
} catch {
|
|
7117
|
-
focusToken = null;
|
|
7118
|
-
}
|
|
7119
|
-
}
|
|
7120
|
-
function desktopNotify(title, msg) {
|
|
7121
|
-
try {
|
|
7122
|
-
if (process.platform === "linux") linuxNotify(title, msg);
|
|
7123
|
-
else if (process.platform === "win32") winNotify(title, msg);
|
|
7124
|
-
else if (process.platform === "darwin") macNotify(title, msg);
|
|
7125
|
-
} catch {
|
|
7126
|
-
}
|
|
7127
|
-
}
|
|
7128
|
-
function linuxNotify(title, msg) {
|
|
7129
|
-
let p;
|
|
7130
|
-
try {
|
|
7131
|
-
p = spawn("notify-send", ["--wait", "--action=default=Open", "-a", "SolonGate", title, msg], { stdio: ["ignore", "pipe", "ignore"] });
|
|
7132
|
-
} catch {
|
|
7133
|
-
return;
|
|
7134
|
-
}
|
|
7135
|
-
p.on("error", () => {
|
|
7136
|
-
});
|
|
7137
|
-
p.stdout?.on("data", (d) => {
|
|
7138
|
-
if (String(d).trim() === "default") raiseLinuxWindow();
|
|
7139
|
-
});
|
|
7140
|
-
p.unref();
|
|
7141
|
-
}
|
|
7142
|
-
function raiseLinuxWindow() {
|
|
7143
|
-
try {
|
|
7144
|
-
process.stdout.write("\x1B[5t");
|
|
7145
|
-
} catch {
|
|
7146
|
-
}
|
|
7147
|
-
if (!focusToken) return;
|
|
7148
|
-
try {
|
|
7149
|
-
const x = spawn("xdotool", ["windowactivate", focusToken], { stdio: "ignore" });
|
|
7150
|
-
x.on("error", () => {
|
|
7151
|
-
try {
|
|
7152
|
-
const hex = "0x" + Number(focusToken).toString(16);
|
|
7153
|
-
const w = spawn("wmctrl", ["-ia", hex], { stdio: "ignore" });
|
|
7154
|
-
w.on("error", () => {
|
|
7155
|
-
});
|
|
7156
|
-
w.unref();
|
|
7157
|
-
} catch {
|
|
7158
|
-
}
|
|
7159
|
-
});
|
|
7160
|
-
x.unref();
|
|
7161
|
-
} catch {
|
|
7162
|
-
}
|
|
7163
|
-
}
|
|
7164
|
-
function ensureWinScript() {
|
|
7165
|
-
if (winScriptPath && existsSync4(winScriptPath)) return winScriptPath;
|
|
7166
|
-
const p = join6(tmpdir2(), "solongate-toast.ps1");
|
|
7167
|
-
const script = [
|
|
7168
|
-
"param([string]$Title,[string]$Msg,[string]$Hwnd)",
|
|
7169
|
-
"Add-Type -AssemblyName System.Windows.Forms",
|
|
7170
|
-
"Add-Type -AssemblyName System.Drawing",
|
|
7171
|
-
`Add-Type -Name Win -Namespace Sg -MemberDefinition '[DllImport("user32.dll")]public static extern bool SetForegroundWindow(System.IntPtr h);[DllImport("user32.dll")]public static extern bool ShowWindow(System.IntPtr h,int c);'`,
|
|
7172
|
-
"$ni=New-Object System.Windows.Forms.NotifyIcon",
|
|
7173
|
-
"$ni.Icon=[System.Drawing.SystemIcons]::Information",
|
|
7174
|
-
"$ni.Visible=$true",
|
|
7175
|
-
"$script:clicked=$false",
|
|
7176
|
-
"$ni.add_BalloonTipClicked({$script:clicked=$true})",
|
|
7177
|
-
"$ni.ShowBalloonTip(8000,$Title,$Msg,[System.Windows.Forms.ToolTipIcon]::Warning)",
|
|
7178
|
-
"$sw=[System.Diagnostics.Stopwatch]::StartNew()",
|
|
7179
|
-
"while($sw.Elapsed.TotalSeconds -lt 9 -and -not $script:clicked){[System.Windows.Forms.Application]::DoEvents();Start-Sleep -Milliseconds 100}",
|
|
7180
|
-
"if($script:clicked -and $Hwnd){try{$h=[System.IntPtr][int64]$Hwnd;[Sg.Win]::ShowWindow($h,9)|Out-Null;[Sg.Win]::SetForegroundWindow($h)|Out-Null}catch{}}",
|
|
7181
|
-
"$ni.Visible=$false;$ni.Dispose()"
|
|
7182
|
-
].join("\n");
|
|
7183
|
-
try {
|
|
7184
|
-
writeFileSync3(p, script);
|
|
7185
|
-
winScriptPath = p;
|
|
7186
|
-
return p;
|
|
7187
|
-
} catch {
|
|
7188
|
-
return null;
|
|
7189
|
-
}
|
|
7190
|
-
}
|
|
7191
|
-
function winNotify(title, msg) {
|
|
7192
|
-
const script = ensureWinScript();
|
|
7193
|
-
if (!script) return;
|
|
7194
|
-
try {
|
|
7195
|
-
const p = spawn("powershell", ["-NoProfile", "-NonInteractive", "-ExecutionPolicy", "Bypass", "-File", script, "-Title", title, "-Msg", msg, "-Hwnd", focusToken || ""], { stdio: "ignore", detached: true, windowsHide: true });
|
|
7196
|
-
p.on("error", () => {
|
|
7197
|
-
});
|
|
7198
|
-
p.unref();
|
|
7199
7150
|
} catch {
|
|
7200
7151
|
}
|
|
7201
7152
|
}
|
|
7202
|
-
function macBundleId() {
|
|
7203
|
-
const prog = (process.env.TERM_PROGRAM || "").toLowerCase();
|
|
7204
|
-
if (prog.includes("iterm")) return "com.googlecode.iterm2";
|
|
7205
|
-
if (prog.includes("apple_terminal")) return "com.apple.Terminal";
|
|
7206
|
-
if (prog.includes("vscode")) return "com.microsoft.VSCode";
|
|
7207
|
-
return "com.apple.Terminal";
|
|
7208
|
-
}
|
|
7209
|
-
function macNotify(title, msg) {
|
|
7210
|
-
try {
|
|
7211
|
-
const p = spawn("terminal-notifier", ["-title", title, "-message", msg, "-activate", macBundleId(), "-sender", macBundleId()], { stdio: "ignore", detached: true });
|
|
7212
|
-
p.on("error", () => {
|
|
7213
|
-
try {
|
|
7214
|
-
const esc = (s) => s.replace(/"/g, '\\"');
|
|
7215
|
-
const a = spawn("osascript", ["-e", `display notification "${esc(msg)}" with title "${esc(title)}"`], { stdio: "ignore", detached: true });
|
|
7216
|
-
a.on("error", () => {
|
|
7217
|
-
});
|
|
7218
|
-
a.unref();
|
|
7219
|
-
} catch {
|
|
7220
|
-
}
|
|
7221
|
-
});
|
|
7222
|
-
p.unref();
|
|
7223
|
-
} catch {
|
|
7224
|
-
}
|
|
7225
|
-
}
|
|
7226
|
-
var focusToken, winScriptPath;
|
|
7227
7153
|
var init_notify = __esm({
|
|
7228
7154
|
"src/tui/notify.ts"() {
|
|
7229
7155
|
"use strict";
|
|
7230
|
-
focusToken = null;
|
|
7231
|
-
winScriptPath = null;
|
|
7232
7156
|
}
|
|
7233
7157
|
});
|
|
7234
7158
|
|
|
@@ -7271,6 +7195,24 @@ function usePoll(reload, intervalMs, enabled = true) {
|
|
|
7271
7195
|
return () => clearInterval(t);
|
|
7272
7196
|
}, [reload, intervalMs, enabled]);
|
|
7273
7197
|
}
|
|
7198
|
+
function useTermSize() {
|
|
7199
|
+
const read = () => ({ cols: process.stdout.columns ?? 100, rows: process.stdout.rows ?? 30 });
|
|
7200
|
+
const [size, setSize] = useState(read);
|
|
7201
|
+
useEffect(() => {
|
|
7202
|
+
const onResize = () => setSize(read());
|
|
7203
|
+
process.stdout.on("resize", onResize);
|
|
7204
|
+
return () => {
|
|
7205
|
+
process.stdout.off("resize", onResize);
|
|
7206
|
+
};
|
|
7207
|
+
}, []);
|
|
7208
|
+
return size;
|
|
7209
|
+
}
|
|
7210
|
+
function usePanelSize() {
|
|
7211
|
+
const { cols, rows } = useTermSize();
|
|
7212
|
+
const wide = cols >= 82;
|
|
7213
|
+
const shellRows = wide ? 12 : 7;
|
|
7214
|
+
return { cols: Math.max(30, cols - 22), rows: Math.max(8, rows - shellRows) };
|
|
7215
|
+
}
|
|
7274
7216
|
var init_hooks = __esm({
|
|
7275
7217
|
"src/tui/hooks.ts"() {
|
|
7276
7218
|
"use strict";
|
|
@@ -7280,9 +7222,9 @@ var init_hooks = __esm({
|
|
|
7280
7222
|
// src/tui/panels/Live.tsx
|
|
7281
7223
|
import { Box as Box2, Text as Text2, useInput } from "ink";
|
|
7282
7224
|
import TextInput from "ink-text-input";
|
|
7283
|
-
import { closeSync, mkdirSync as mkdirSync3, openSync, readSync, statSync, writeFileSync as
|
|
7225
|
+
import { closeSync, mkdirSync as mkdirSync3, openSync, readSync, statSync, writeFileSync as writeFileSync3 } from "fs";
|
|
7284
7226
|
import { homedir as homedir4 } from "os";
|
|
7285
|
-
import { join as
|
|
7227
|
+
import { join as join6 } from "path";
|
|
7286
7228
|
import { useCallback as useCallback2, useEffect as useEffect2, useRef as useRef2, useState as useState2 } from "react";
|
|
7287
7229
|
import { Fragment as Fragment2, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
7288
7230
|
function tailLines(file, maxBytes = 131072) {
|
|
@@ -7420,6 +7362,9 @@ function LivePanel({ active: active2 }) {
|
|
|
7420
7362
|
const [detail, setDetail] = useState2(null);
|
|
7421
7363
|
const [detailCloud, setDetailCloud] = useState2([]);
|
|
7422
7364
|
const [detailScroll, setDetailScroll] = useState2(0);
|
|
7365
|
+
const [inspect, setInspect] = useState2(null);
|
|
7366
|
+
const [inspectScroll, setInspectScroll] = useState2(0);
|
|
7367
|
+
const inspectFromRef = useRef2("stream");
|
|
7423
7368
|
const seenRef = useRef2(/* @__PURE__ */ new Set());
|
|
7424
7369
|
const lastLocalTs = useRef2(0);
|
|
7425
7370
|
const pausedUntil = useRef2(0);
|
|
@@ -7625,8 +7570,7 @@ function LivePanel({ active: active2 }) {
|
|
|
7625
7570
|
else if (e.burst) fireAlert("sec:" + e.id, "Rate-limit burst", `BURST ${e.tool}${who}`, "warn");
|
|
7626
7571
|
}
|
|
7627
7572
|
}, [tick, active2, fireAlert]);
|
|
7628
|
-
const cols
|
|
7629
|
-
const rows = process.stdout.rows ?? 30;
|
|
7573
|
+
const { cols, rows } = useTermSize();
|
|
7630
7574
|
const ins = insights.data ?? {};
|
|
7631
7575
|
const spin = SPIN[tick % SPIN.length];
|
|
7632
7576
|
const nowMs = Date.now();
|
|
@@ -7772,8 +7716,18 @@ function LivePanel({ active: active2 }) {
|
|
|
7772
7716
|
setEditingSearch(true);
|
|
7773
7717
|
return;
|
|
7774
7718
|
}
|
|
7719
|
+
if (mode === "inspect") {
|
|
7720
|
+
if (key.leftArrow) {
|
|
7721
|
+
setMode(inspectFromRef.current);
|
|
7722
|
+
setInspect(null);
|
|
7723
|
+
} else if (key.upArrow) setInspectScroll((n) => Math.max(0, n - 1));
|
|
7724
|
+
else if (key.downArrow) setInspectScroll((n) => n + 1);
|
|
7725
|
+
else if (key.pageUp) setInspectScroll((n) => Math.max(0, n - 10));
|
|
7726
|
+
else if (key.pageDown) setInspectScroll((n) => n + 10);
|
|
7727
|
+
return;
|
|
7728
|
+
}
|
|
7775
7729
|
if (mode === "detail") {
|
|
7776
|
-
const maxD = Math.max(0, detailEntries.length -
|
|
7730
|
+
const maxD = Math.max(0, detailEntries.length - 1);
|
|
7777
7731
|
if (key.leftArrow) {
|
|
7778
7732
|
setMode("stream");
|
|
7779
7733
|
setDetail(null);
|
|
@@ -7781,6 +7735,15 @@ function LivePanel({ active: active2 }) {
|
|
|
7781
7735
|
else if (key.downArrow) setDetailScroll((n) => Math.min(maxD, n + 1));
|
|
7782
7736
|
else if (key.pageUp) setDetailScroll((n) => Math.max(0, n - 10));
|
|
7783
7737
|
else if (key.pageDown) setDetailScroll((n) => Math.min(maxD, n + 10));
|
|
7738
|
+
else if (key.return) {
|
|
7739
|
+
const e = detailEntries[Math.min(detailScroll, maxD)];
|
|
7740
|
+
if (e) {
|
|
7741
|
+
inspectFromRef.current = "detail";
|
|
7742
|
+
setInspect(e);
|
|
7743
|
+
setInspectScroll(0);
|
|
7744
|
+
setMode("inspect");
|
|
7745
|
+
}
|
|
7746
|
+
}
|
|
7784
7747
|
return;
|
|
7785
7748
|
}
|
|
7786
7749
|
if (mode === "pick") {
|
|
@@ -7802,6 +7765,13 @@ function LivePanel({ active: active2 }) {
|
|
|
7802
7765
|
if (input === "f") {
|
|
7803
7766
|
setFilter((f) => FILTERS[(FILTERS.indexOf(f) + 1) % FILTERS.length]);
|
|
7804
7767
|
setSel(0);
|
|
7768
|
+
} else if (key.return) {
|
|
7769
|
+
if (selEntry) {
|
|
7770
|
+
inspectFromRef.current = "stream";
|
|
7771
|
+
setInspect(selEntry);
|
|
7772
|
+
setInspectScroll(0);
|
|
7773
|
+
setMode("inspect");
|
|
7774
|
+
}
|
|
7805
7775
|
} else if (input === "s") {
|
|
7806
7776
|
setPickIdx(0);
|
|
7807
7777
|
setMode("pick");
|
|
@@ -7811,10 +7781,10 @@ function LivePanel({ active: active2 }) {
|
|
|
7811
7781
|
else if (input === "x") toggleSignal("dlp");
|
|
7812
7782
|
else if (input === "r") toggleSignal("ratelimit");
|
|
7813
7783
|
else if (input === "e") {
|
|
7814
|
-
const file =
|
|
7784
|
+
const file = join6(homedir4(), ".solongate", "live-export.jsonl");
|
|
7815
7785
|
try {
|
|
7816
|
-
mkdirSync3(
|
|
7817
|
-
|
|
7786
|
+
mkdirSync3(join6(homedir4(), ".solongate"), { recursive: true });
|
|
7787
|
+
writeFileSync3(file, visibleDesc.map((x) => JSON.stringify(x)).join("\n") + "\n");
|
|
7818
7788
|
setActionMsg({ text: `\u2713 exported ${visibleDesc.length} lines \u2192 ${file}`, level: "ok", until: Date.now() + 6e3 });
|
|
7819
7789
|
} catch (err2) {
|
|
7820
7790
|
setActionMsg({ text: "\u2717 export failed: " + (err2 instanceof Error ? err2.message : String(err2)), level: "bad", until: Date.now() + 6e3 });
|
|
@@ -7864,6 +7834,52 @@ function LivePanel({ active: active2 }) {
|
|
|
7864
7834
|
/* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", children: ` ${spin} up ${fmtUp(nowMs - startRef.current)} \xB7 ${hhmmss(nowMs)} \xB7 api ${latNow}ms ` }),
|
|
7865
7835
|
frozen ? /* @__PURE__ */ jsx2(Text2, { backgroundColor: "#123d1f", color: "#7bd88f", bold: true, children: " \u23F5 COPY MODE \u2014 screen frozen, select & copy freely \xB7 space resume " }) : backingOff ? /* @__PURE__ */ jsx2(Text2, { backgroundColor: "#3d2a12", color: "#ffb454", bold: true, children: " RATE LIMITED \xB7 backing off " }) : lastDeny ? /* @__PURE__ */ jsx2(Text2, { backgroundColor: "#3d1220", color: "#ff6b6b", bold: true, children: ` \u26A0 ${hhmmss(lastDeny.at)} ${lastDeny.tool} DENIED ` }) : /* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#4f6db8", children: " \u2713 clean " })
|
|
7866
7836
|
] });
|
|
7837
|
+
if (mode === "inspect" && inspect) {
|
|
7838
|
+
const e = inspect;
|
|
7839
|
+
const bodyW = Math.max(20, cols - 4);
|
|
7840
|
+
const lines = wrapLines(prettyJson(e.detail || "(no arguments / reason recorded)"), bodyW);
|
|
7841
|
+
const bodyRows = Math.max(4, rows - 7);
|
|
7842
|
+
const maxScroll2 = Math.max(0, lines.length - bodyRows);
|
|
7843
|
+
const off = Math.min(inspectScroll, maxScroll2);
|
|
7844
|
+
const win = lines.slice(off, off + bodyRows);
|
|
7845
|
+
return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", paddingX: 1, children: [
|
|
7846
|
+
titleBar,
|
|
7847
|
+
/* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
7848
|
+
/* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#AAC8FA", bold: true, children: " ENTRY " }),
|
|
7849
|
+
/* @__PURE__ */ jsx2(Text2, { color: decisionColor(e.decision), bold: true, children: " " + e.decision }),
|
|
7850
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.accent, bold: true, children: " " + e.tool }),
|
|
7851
|
+
/* @__PURE__ */ jsx2(Text2, { color: isLoc(e) ? theme.ok : "#4f6db8", children: " " + (isLoc(e) ? "LOC" : "CLD") }),
|
|
7852
|
+
e.dlp ? /* @__PURE__ */ jsx2(Text2, { color: theme.bad, children: " DLP!" }) : null,
|
|
7853
|
+
e.burst ? /* @__PURE__ */ jsx2(Text2, { color: theme.warn, children: " BURST" }) : null,
|
|
7854
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2190 back" })
|
|
7855
|
+
] }),
|
|
7856
|
+
/* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
7857
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "\u2502 when " }),
|
|
7858
|
+
/* @__PURE__ */ jsx2(Text2, { children: new Date(e.at).toLocaleString() }),
|
|
7859
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502 perm " }),
|
|
7860
|
+
/* @__PURE__ */ jsx2(Text2, { children: e.permission || "\u2014" }),
|
|
7861
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502 eval " }),
|
|
7862
|
+
/* @__PURE__ */ jsx2(Text2, { color: e.evalMs != null && e.evalMs > 500 ? theme.warn : void 0, children: e.evalMs != null ? `${e.evalMs}ms` : "\u2014" }),
|
|
7863
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502 agent " }),
|
|
7864
|
+
/* @__PURE__ */ jsx2(Text2, { children: e.agent ?? "\u2014" }),
|
|
7865
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502" })
|
|
7866
|
+
] }),
|
|
7867
|
+
/* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
7868
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "\u2502 session " }),
|
|
7869
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: e.session ?? "\u2014" }),
|
|
7870
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502 rule " }),
|
|
7871
|
+
/* @__PURE__ */ jsx2(Text2, { color: e.rule && e.decision !== "ALLOW" ? theme.bad : theme.dim, children: e.rule ?? "\u2014" }),
|
|
7872
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502" })
|
|
7873
|
+
] }),
|
|
7874
|
+
/* @__PURE__ */ jsx2(PaneTitle, { label: "FULL CONTENT", extra: `${lines.length} lines${maxScroll2 ? ` \xB7 \u25BC${maxScroll2 - off} more \xB7 \u2191\u2193 scroll` : ""} \xB7 space copy \xB7 \u2190 back`, width: innerW }),
|
|
7875
|
+
/* @__PURE__ */ jsx2(Box2, { flexDirection: "column", height: bodyRows, overflow: "hidden", children: win.map((l, i) => /* @__PURE__ */ jsx2(Text2, { wrap: "truncate", children: l || " " }, off + i)) }),
|
|
7876
|
+
/* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
7877
|
+
/* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", bold: true, children: " ENTRY " }),
|
|
7878
|
+
/* @__PURE__ */ jsx2(Text2, { backgroundColor: "#0b1530", color: "#4f6db8", children: ` ${e.id} ` }),
|
|
7879
|
+
/* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", children: " \u2191\u2193 scroll \xB7 space copy mode \xB7 \u2190 back \xB7 esc menu " })
|
|
7880
|
+
] })
|
|
7881
|
+
] });
|
|
7882
|
+
}
|
|
7867
7883
|
if (mode === "detail" && detail) {
|
|
7868
7884
|
const d = detailEntries;
|
|
7869
7885
|
const allow = d.filter((e) => e.decision === "ALLOW").length;
|
|
@@ -7883,9 +7899,10 @@ function LivePanel({ active: active2 }) {
|
|
|
7883
7899
|
const last = d[0]?.at;
|
|
7884
7900
|
const tlRows = Math.max(4, rows - 10);
|
|
7885
7901
|
const tlBody = Math.max(3, tlRows - 1);
|
|
7886
|
-
const
|
|
7887
|
-
const
|
|
7888
|
-
const
|
|
7902
|
+
const dSel = Math.min(detailScroll, Math.max(0, d.length - 1));
|
|
7903
|
+
const maxStart = Math.max(0, d.length - tlBody);
|
|
7904
|
+
const start = Math.min(Math.max(0, dSel - Math.floor((tlBody - 1) / 2)), maxStart);
|
|
7905
|
+
const tl = d.slice(start, start + tlBody);
|
|
7889
7906
|
return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", paddingX: 1, children: [
|
|
7890
7907
|
titleBar,
|
|
7891
7908
|
/* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
@@ -7923,16 +7940,16 @@ function LivePanel({ active: active2 }) {
|
|
|
7923
7940
|
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: perms.map(([p, c2]) => `${p}\xD7${c2}`).join(" ") || "\u2014" }),
|
|
7924
7941
|
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2502" })
|
|
7925
7942
|
] }),
|
|
7926
|
-
/* @__PURE__ */ jsx2(PaneTitle, { label: "TIMELINE", extra: `${d.length}
|
|
7943
|
+
/* @__PURE__ */ jsx2(PaneTitle, { label: "TIMELINE", extra: `${dSel + 1}/${d.length} \xB7 newest first \xB7 \u2191\u2193 select \xB7 enter full entry \xB7 / search \xB7 \u2190 back`, width: innerW }),
|
|
7927
7944
|
/* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", height: tlRows, overflow: "hidden", children: [
|
|
7928
7945
|
searchRow,
|
|
7929
7946
|
tl.length === 0 ? /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: detailCloud.length === 0 ? spin + " loading history\u2026" : "no entries" }) : null,
|
|
7930
|
-
tl.map((e) => /* @__PURE__ */ jsx2(StreamLine, { e, loc: isLoc(e) }, e.id))
|
|
7947
|
+
tl.map((e, i) => /* @__PURE__ */ jsx2(StreamLine, { e, loc: isLoc(e), selected: start + i === dSel }, e.id))
|
|
7931
7948
|
] }),
|
|
7932
7949
|
/* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
7933
7950
|
/* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", bold: true, children: " SESSION " }),
|
|
7934
7951
|
/* @__PURE__ */ jsx2(Text2, { backgroundColor: "#0b1530", color: "#4f6db8", children: ` ${detail.id} ` }),
|
|
7935
|
-
/* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", children: " \u2191\u2193
|
|
7952
|
+
/* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", children: " \u2191\u2193 select \xB7 enter full entry \xB7 \u2190 back \xB7 esc menu " })
|
|
7936
7953
|
] })
|
|
7937
7954
|
] });
|
|
7938
7955
|
}
|
|
@@ -8045,7 +8062,7 @@ function LivePanel({ active: active2 }) {
|
|
|
8045
8062
|
PaneTitle,
|
|
8046
8063
|
{
|
|
8047
8064
|
label: "TOOL STREAM",
|
|
8048
|
-
extra: `${selClamped + 1}/${visibleDesc.length}${signal !== "none" ? ` \xB7 ${signal}` : ""}${q ? " \xB7 search" : ""} \xB7 \u2191\u2193 select \xB7 w allow \xB7 b block \xB7 d/x/r ${filter} \xB7 s`,
|
|
8065
|
+
extra: `${selClamped + 1}/${visibleDesc.length}${signal !== "none" ? ` \xB7 ${signal}` : ""}${q ? " \xB7 search" : ""} \xB7 \u2191\u2193 select \xB7 enter full \xB7 w allow \xB7 b block \xB7 d/x/r ${filter} \xB7 s`,
|
|
8049
8066
|
width: innerW
|
|
8050
8067
|
}
|
|
8051
8068
|
),
|
|
@@ -8053,7 +8070,7 @@ function LivePanel({ active: active2 }) {
|
|
|
8053
8070
|
searchRow,
|
|
8054
8071
|
localOn === false ? /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
8055
8072
|
/* @__PURE__ */ jsx2(Text2, { color: theme.warn, children: "local logs off" }),
|
|
8056
|
-
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2014 enable:
|
|
8073
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2014 enable: dataroom \u2192 Settings (local logs) or dashboard \u2192 Settings \xB7 hooks write ~/.solongate/local-logs" })
|
|
8057
8074
|
] }) : null,
|
|
8058
8075
|
windowed.length === 0 ? /* @__PURE__ */ jsxs2(Text2, { color: theme.dim, children: [
|
|
8059
8076
|
spin,
|
|
@@ -8064,7 +8081,7 @@ function LivePanel({ active: active2 }) {
|
|
|
8064
8081
|
/* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
8065
8082
|
/* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", bold: true, children: " LIVE " }),
|
|
8066
8083
|
/* @__PURE__ */ jsx2(Text2, { backgroundColor: "#0b1530", color: "#4f6db8", children: ` local ${localOn ? "on" : "off"} \xB7 ${localBuf.length} loc/${cloudBuf.length} cld \xB7 top ${topTools.map(([t, c2]) => `${t}\xD7${c2}`).join(" ") || "\u2014"} ` }),
|
|
8067
|
-
/* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", children: " \u2191\u2193 select \xB7 w allow \xB7 b block \xB7 d/x/r \xB7 / search \xB7 f \xB7 s \xB7 space copy \xB7 esc \xB7 q " })
|
|
8084
|
+
/* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", children: " \u2191\u2193 select \xB7 enter full \xB7 w allow \xB7 b block \xB7 d/x/r \xB7 / search \xB7 f \xB7 s \xB7 space copy \xB7 esc \xB7 q " })
|
|
8068
8085
|
] })
|
|
8069
8086
|
] });
|
|
8070
8087
|
}
|
|
@@ -8081,8 +8098,8 @@ var init_Live = __esm({
|
|
|
8081
8098
|
SPIN = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
8082
8099
|
BG = "#12234f";
|
|
8083
8100
|
DIM_FLOOR = "#233457";
|
|
8084
|
-
LOCAL_LOG =
|
|
8085
|
-
RING =
|
|
8101
|
+
LOCAL_LOG = join6(homedir4(), ".solongate", "local-logs", "solongate-audit.jsonl");
|
|
8102
|
+
RING = join6(process.cwd(), ".solongate", ".eval-ring.jsonl");
|
|
8086
8103
|
hhmmss = (ts) => {
|
|
8087
8104
|
const d = new Date(ts);
|
|
8088
8105
|
return Number.isNaN(d.getTime()) ? "--:--:--" : d.toTimeString().slice(0, 8);
|
|
@@ -8893,8 +8910,9 @@ var init_Stats = __esm({
|
|
|
8893
8910
|
import { Box as Box7, Text as Text7, useInput as useInput5 } from "ink";
|
|
8894
8911
|
import TextInput4 from "ink-text-input";
|
|
8895
8912
|
import { useState as useState6 } from "react";
|
|
8896
|
-
import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
8913
|
+
import { Fragment as Fragment4, jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
8897
8914
|
function AuditPanel({ active: active2, focused }) {
|
|
8915
|
+
const { cols, rows } = usePanelSize();
|
|
8898
8916
|
const [di, setDi] = useState6(0);
|
|
8899
8917
|
const [gi, setGi] = useState6(0);
|
|
8900
8918
|
const [tool, setTool] = useState6("");
|
|
@@ -8902,6 +8920,7 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
8902
8920
|
const [search, setSearch] = useState6("");
|
|
8903
8921
|
const [sel, setSel] = useState6(0);
|
|
8904
8922
|
const [view, setView] = useState6("list");
|
|
8923
|
+
const [detailScroll, setDetailScroll] = useState6(0);
|
|
8905
8924
|
const [editing, setEditing] = useState6(null);
|
|
8906
8925
|
const query = {
|
|
8907
8926
|
filter: DECISIONS[di],
|
|
@@ -8909,7 +8928,7 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
8909
8928
|
tool: tool || void 0,
|
|
8910
8929
|
agent_name: agent || void 0,
|
|
8911
8930
|
search: search || void 0,
|
|
8912
|
-
limit:
|
|
8931
|
+
limit: FETCH_LIMIT
|
|
8913
8932
|
};
|
|
8914
8933
|
const auditQ = useLoader(() => api.audit.list(query), [di, gi, tool, agent, search]);
|
|
8915
8934
|
usePoll(auditQ.reload, 6e3, active2 && view === "list" && !editing);
|
|
@@ -8923,15 +8942,29 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
8923
8942
|
(input, key) => {
|
|
8924
8943
|
if (view === "detail") {
|
|
8925
8944
|
if (key.leftArrow || key.escape) setView("list");
|
|
8945
|
+
else if (key.upArrow) setDetailScroll((n) => Math.max(0, n - 1));
|
|
8946
|
+
else if (key.downArrow) setDetailScroll((n) => n + 1);
|
|
8947
|
+
else if (key.pageUp) setDetailScroll((n) => Math.max(0, n - 10));
|
|
8948
|
+
else if (key.pageDown) setDetailScroll((n) => n + 10);
|
|
8926
8949
|
return;
|
|
8927
8950
|
}
|
|
8951
|
+
const clearSel = () => setSel(0);
|
|
8928
8952
|
if (key.upArrow) setSel((n) => Math.max(0, n - 1));
|
|
8929
8953
|
else if (key.downArrow) setSel((n) => Math.min(entries.length - 1, n + 1));
|
|
8954
|
+
else if (key.pageUp) setSel((n) => Math.max(0, n - 10));
|
|
8955
|
+
else if (key.pageDown) setSel((n) => Math.min(entries.length - 1, n + 10));
|
|
8930
8956
|
else if (key.return || key.rightArrow) {
|
|
8931
|
-
if (current)
|
|
8932
|
-
|
|
8933
|
-
|
|
8934
|
-
|
|
8957
|
+
if (current) {
|
|
8958
|
+
setDetailScroll(0);
|
|
8959
|
+
setView("detail");
|
|
8960
|
+
}
|
|
8961
|
+
} else if (input === "f") {
|
|
8962
|
+
setDi((n) => (n + 1) % DECISIONS.length);
|
|
8963
|
+
clearSel();
|
|
8964
|
+
} else if (input === "g") {
|
|
8965
|
+
setGi((n) => (n + 1) % SIGNALS.length);
|
|
8966
|
+
clearSel();
|
|
8967
|
+
} else if (input === "t") setEditing("tool");
|
|
8935
8968
|
else if (input === "n") setEditing("agent");
|
|
8936
8969
|
else if (input === "/") setEditing("search");
|
|
8937
8970
|
else if (input === "c") {
|
|
@@ -8940,49 +8973,64 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
8940
8973
|
setTool("");
|
|
8941
8974
|
setAgent("");
|
|
8942
8975
|
setSearch("");
|
|
8976
|
+
clearSel();
|
|
8943
8977
|
}
|
|
8944
8978
|
},
|
|
8945
8979
|
{ isActive: focused && !editing }
|
|
8946
8980
|
);
|
|
8947
8981
|
if (view === "detail" && current) {
|
|
8948
8982
|
const sessionCalls = sessionQ.data?.entries ?? [];
|
|
8983
|
+
const bodyW = Math.max(20, cols - 2);
|
|
8984
|
+
const reasonLines = wrapLines("reason: " + (current.reason ?? "\u2014"), bodyW);
|
|
8985
|
+
const argLines = current.arguments_summary ? wrapLines(prettyJson(JSON.stringify(current.arguments_summary)), bodyW) : ["(no arguments recorded)"];
|
|
8986
|
+
const sessionRows = current.session_id ? Math.min(4, sessionCalls.length) + 2 : 1;
|
|
8987
|
+
const reasonShown = reasonLines.slice(0, 4);
|
|
8988
|
+
const argBudget = Math.max(3, rows - 2 - 5 - reasonShown.length - 1 - sessionRows - 1);
|
|
8989
|
+
const maxScroll = Math.max(0, argLines.length - argBudget);
|
|
8990
|
+
const off = Math.min(detailScroll, maxScroll);
|
|
8991
|
+
const argWin = argLines.slice(off, off + argBudget);
|
|
8949
8992
|
return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
|
|
8950
8993
|
/* @__PURE__ */ jsxs7(Box7, { children: [
|
|
8951
8994
|
/* @__PURE__ */ jsx7(Text7, { color: decisionColor(current.decision), bold: true, children: current.decision }),
|
|
8952
8995
|
/* @__PURE__ */ jsx7(Text7, { color: theme.accent, children: " " + current.tool_name }),
|
|
8953
8996
|
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: " " + current.permission + " \xB7 " + current.trust_level })
|
|
8954
8997
|
] }),
|
|
8955
|
-
/* @__PURE__ */ jsx7(
|
|
8998
|
+
reasonShown.map((l, i) => /* @__PURE__ */ jsx7(Text7, { wrap: "truncate", children: i === 0 ? /* @__PURE__ */ jsxs7(Fragment4, { children: [
|
|
8999
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "reason " }),
|
|
9000
|
+
/* @__PURE__ */ jsx7(Text7, { children: l.slice("reason: ".length) })
|
|
9001
|
+
] }) : /* @__PURE__ */ jsx7(Text7, { children: " " + l }) }, "r" + i)),
|
|
8956
9002
|
/* @__PURE__ */ jsx7(Detail, { label: "rule", value: current.matched_rule_id ?? "\u2014" }),
|
|
8957
9003
|
/* @__PURE__ */ jsx7(Detail, { label: "agent", value: current.agent_name ?? "\u2014" }),
|
|
8958
9004
|
/* @__PURE__ */ jsx7(Detail, { label: "session", value: current.session_id ?? "\u2014" }),
|
|
8959
9005
|
/* @__PURE__ */ jsx7(Detail, { label: "dlp", value: current.dlp_matches?.length ? current.dlp_matches.join(", ") : "none", color: current.dlp_matches?.length ? theme.bad : void 0 }),
|
|
8960
|
-
/* @__PURE__ */ jsx7(Detail, { label: "when", value: new Date(current.created_at).toLocaleString() }),
|
|
8961
|
-
|
|
8962
|
-
/* @__PURE__ */
|
|
9006
|
+
/* @__PURE__ */ jsx7(Detail, { label: "when", value: new Date(current.created_at).toLocaleString() + (current.evaluation_time_ms != null ? ` \xB7 eval ${current.evaluation_time_ms}ms` : "") }),
|
|
9007
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: `arguments \u2014 full \xB7 ${argLines.length} lines${maxScroll ? ` \xB7 \u25BC${maxScroll - off} more \xB7 \u2191\u2193 scroll` : ""}` }),
|
|
9008
|
+
/* @__PURE__ */ jsx7(Box7, { flexDirection: "column", height: argBudget, overflow: "hidden", children: argWin.map((l, i) => /* @__PURE__ */ jsx7(Text7, { wrap: "truncate", children: l || " " }, off + i)) }),
|
|
9009
|
+
current.session_id ? /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
|
|
8963
9010
|
/* @__PURE__ */ jsxs7(Text7, { color: theme.dim, children: [
|
|
8964
|
-
"Session ",
|
|
8965
|
-
|
|
9011
|
+
"Session \xB7 ",
|
|
9012
|
+
sessionCalls.length,
|
|
9013
|
+
" calls"
|
|
8966
9014
|
] }),
|
|
8967
|
-
|
|
9015
|
+
/* @__PURE__ */ jsx7(
|
|
8968
9016
|
Table,
|
|
8969
9017
|
{
|
|
8970
9018
|
columns: [
|
|
8971
9019
|
{ header: "DECISION", width: 9 },
|
|
8972
9020
|
{ header: "TOOL", width: 20 },
|
|
8973
|
-
{ header: "REASON", width:
|
|
9021
|
+
{ header: "REASON", width: Math.max(16, cols - 48) },
|
|
8974
9022
|
{ header: "WHEN", width: 6 }
|
|
8975
9023
|
],
|
|
8976
|
-
rows: sessionCalls.slice(0,
|
|
9024
|
+
rows: sessionCalls.slice(0, Math.max(1, sessionRows - 2)).map((e) => [
|
|
8977
9025
|
{ value: e.decision, color: decisionColor(e.decision) },
|
|
8978
9026
|
{ value: truncate2(e.tool_name, 20), color: theme.accent },
|
|
8979
|
-
{ value: truncate2(e.reason ?? "\u2014",
|
|
9027
|
+
{ value: truncate2(e.reason ?? "\u2014", Math.max(16, cols - 48)) },
|
|
8980
9028
|
{ value: ago(e.created_at), dim: true }
|
|
8981
9029
|
])
|
|
8982
9030
|
}
|
|
8983
|
-
)
|
|
8984
|
-
] }),
|
|
8985
|
-
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "\u2190 back to list" })
|
|
9031
|
+
)
|
|
9032
|
+
] }) : /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "(no session id)" }),
|
|
9033
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "\u2191\u2193 scroll arguments \xB7 \u2190/esc back to list" })
|
|
8986
9034
|
] });
|
|
8987
9035
|
}
|
|
8988
9036
|
const chip = (label, val, on) => /* @__PURE__ */ jsxs7(Text7, { children: [
|
|
@@ -8993,6 +9041,13 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
8993
9041
|
/* @__PURE__ */ jsx7(Text7, { color: on ? theme.accentBright : theme.dim, children: val }),
|
|
8994
9042
|
/* @__PURE__ */ jsx7(Text7, { children: " " })
|
|
8995
9043
|
] });
|
|
9044
|
+
const headerRows = 4 + (editing ? 1 : 0);
|
|
9045
|
+
const listRows = Math.max(4, rows - headerRows);
|
|
9046
|
+
const selClamped = Math.min(sel, Math.max(0, entries.length - 1));
|
|
9047
|
+
const maxStart = Math.max(0, entries.length - listRows);
|
|
9048
|
+
const start = Math.min(Math.max(0, selClamped - Math.floor((listRows - 1) / 2)), maxStart);
|
|
9049
|
+
const windowed = entries.slice(start, start + listRows);
|
|
9050
|
+
const reasonW = Math.min(60, Math.max(12, cols - 67));
|
|
8996
9051
|
return /* @__PURE__ */ jsx7(DataView, { loading: auditQ.loading && !auditQ.data, error: auditQ.error, children: /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
|
|
8997
9052
|
/* @__PURE__ */ jsxs7(Box7, { children: [
|
|
8998
9053
|
chip("dec", DECISIONS[di] ?? "all", di !== 0),
|
|
@@ -9001,8 +9056,8 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
9001
9056
|
chip("agent", agent || "\xB7", !!agent),
|
|
9002
9057
|
chip("search", search || "\xB7", !!search)
|
|
9003
9058
|
] }),
|
|
9004
|
-
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: focused ? "\u2191\u2193 \xB7 enter
|
|
9005
|
-
editing ? /* @__PURE__ */ jsxs7(Box7, {
|
|
9059
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, wrap: "truncate", children: focused ? "\u2191\u2193 select \xB7 enter full entry \xB7 f dec \xB7 g sig \xB7 t tool \xB7 n agent \xB7 / search \xB7 c clear" : "press \u2192 to browse" }),
|
|
9060
|
+
editing ? /* @__PURE__ */ jsxs7(Box7, { children: [
|
|
9006
9061
|
/* @__PURE__ */ jsxs7(Text7, { color: theme.warn, children: [
|
|
9007
9062
|
editing,
|
|
9008
9063
|
": "
|
|
@@ -9011,16 +9066,15 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
9011
9066
|
TextInput4,
|
|
9012
9067
|
{
|
|
9013
9068
|
value: editing === "tool" ? tool : editing === "agent" ? agent : search,
|
|
9014
|
-
onChange:
|
|
9069
|
+
onChange: (v) => {
|
|
9070
|
+
(editing === "tool" ? setTool : editing === "agent" ? setAgent : setSearch)(v);
|
|
9071
|
+
setSel(0);
|
|
9072
|
+
},
|
|
9015
9073
|
onSubmit: () => setEditing(null)
|
|
9016
9074
|
}
|
|
9017
9075
|
)
|
|
9018
9076
|
] }) : null,
|
|
9019
|
-
/* @__PURE__ */ jsx7(
|
|
9020
|
-
auditQ.data?.total ?? 0,
|
|
9021
|
-
" matched \xB7 showing ",
|
|
9022
|
-
Math.min(entries.length, 12)
|
|
9023
|
-
] }) }),
|
|
9077
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, wrap: "truncate", children: `${auditQ.data?.total ?? 0} matched \xB7 ${entries.length} loaded \xB7 ${selClamped + 1}/${entries.length}${start ? ` \xB7 \u25B2${start} newer` : ""}${start + listRows < entries.length ? ` \xB7 \u25BC${entries.length - start - listRows} older` : ""}` }),
|
|
9024
9078
|
/* @__PURE__ */ jsx7(
|
|
9025
9079
|
Table,
|
|
9026
9080
|
{
|
|
@@ -9029,22 +9083,22 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
9029
9083
|
{ header: "DECISION", width: 9 },
|
|
9030
9084
|
{ header: "TOOL", width: 18 },
|
|
9031
9085
|
{ header: "AGENT", width: 14 },
|
|
9032
|
-
{ header: "REASON", width:
|
|
9086
|
+
{ header: "REASON", width: reasonW },
|
|
9033
9087
|
{ header: "DLP", width: 4 },
|
|
9034
9088
|
{ header: "WHEN", width: 6 }
|
|
9035
9089
|
],
|
|
9036
|
-
rows:
|
|
9090
|
+
rows: windowed.map((e, i) => rowFor(e, start + i === selClamped && focused, reasonW))
|
|
9037
9091
|
}
|
|
9038
9092
|
)
|
|
9039
9093
|
] }) });
|
|
9040
9094
|
}
|
|
9041
|
-
function rowFor(e, active2) {
|
|
9095
|
+
function rowFor(e, active2, reasonW) {
|
|
9042
9096
|
return [
|
|
9043
9097
|
{ value: active2 ? "\u25B8" : "", color: theme.accentBright },
|
|
9044
9098
|
{ value: e.decision, color: decisionColor(e.decision) },
|
|
9045
9099
|
{ value: truncate2(e.tool_name, 18), color: theme.accent },
|
|
9046
9100
|
{ value: truncate2(e.agent_name ?? "\u2014", 14), dim: true },
|
|
9047
|
-
{ value: truncate2(e.reason ?? "\u2014",
|
|
9101
|
+
{ value: truncate2(e.reason ?? "\u2014", reasonW) },
|
|
9048
9102
|
{ value: e.dlp_matches?.length ? String(e.dlp_matches.length) : "0", color: e.dlp_matches?.length ? theme.bad : void 0, dim: !e.dlp_matches?.length },
|
|
9049
9103
|
{ value: ago(e.created_at), dim: true }
|
|
9050
9104
|
];
|
|
@@ -9052,10 +9106,10 @@ function rowFor(e, active2) {
|
|
|
9052
9106
|
function Detail({ label, value, color }) {
|
|
9053
9107
|
return /* @__PURE__ */ jsxs7(Box7, { children: [
|
|
9054
9108
|
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: label.padEnd(9) }),
|
|
9055
|
-
/* @__PURE__ */ jsx7(Text7, { color, children: value })
|
|
9109
|
+
/* @__PURE__ */ jsx7(Text7, { color, wrap: "truncate", children: value })
|
|
9056
9110
|
] });
|
|
9057
9111
|
}
|
|
9058
|
-
var DECISIONS, SIGNALS;
|
|
9112
|
+
var DECISIONS, SIGNALS, FETCH_LIMIT;
|
|
9059
9113
|
var init_Audit = __esm({
|
|
9060
9114
|
"src/tui/panels/Audit.tsx"() {
|
|
9061
9115
|
"use strict";
|
|
@@ -9065,13 +9119,14 @@ var init_Audit = __esm({
|
|
|
9065
9119
|
init_theme();
|
|
9066
9120
|
DECISIONS = [void 0, "DENY", "ALLOW"];
|
|
9067
9121
|
SIGNALS = [void 0, "dlp", "ratelimit"];
|
|
9122
|
+
FETCH_LIMIT = 500;
|
|
9068
9123
|
}
|
|
9069
9124
|
});
|
|
9070
9125
|
|
|
9071
9126
|
// src/tui/panels/Agents.tsx
|
|
9072
9127
|
import { Box as Box8, Text as Text8, useInput as useInput6 } from "ink";
|
|
9073
9128
|
import { useState as useState7 } from "react";
|
|
9074
|
-
import { Fragment as
|
|
9129
|
+
import { Fragment as Fragment5, jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
9075
9130
|
function Bar({ label, value, max = 100, width: width2 = 16, color = theme.accent }) {
|
|
9076
9131
|
const filled = max > 0 ? Math.round(Math.min(value, max) / max * width2) : 0;
|
|
9077
9132
|
return /* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", children: [
|
|
@@ -9115,7 +9170,7 @@ function AgentsPanel({ focused }) {
|
|
|
9115
9170
|
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: `t${a.trust_score}` })
|
|
9116
9171
|
] }, a.session_id))
|
|
9117
9172
|
] }),
|
|
9118
|
-
/* @__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(
|
|
9173
|
+
/* @__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: [
|
|
9119
9174
|
/* @__PURE__ */ jsxs8(Box8, { children: [
|
|
9120
9175
|
/* @__PURE__ */ jsx8(Text8, { bold: true, color: theme.accentBright, children: truncate2(selected.agent_name ?? selected.agent_id ?? "?", 22) }),
|
|
9121
9176
|
/* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: ` trust ${base?.trustScore ?? "\u2014"}/100 \xB7 ${base?.character ?? ""}` })
|
|
@@ -9164,41 +9219,256 @@ var init_Agents = __esm({
|
|
|
9164
9219
|
}
|
|
9165
9220
|
});
|
|
9166
9221
|
|
|
9167
|
-
// src/tui/
|
|
9168
|
-
import { Box as Box9, Text as Text9,
|
|
9222
|
+
// src/tui/panels/Settings.tsx
|
|
9223
|
+
import { Box as Box9, Text as Text9, useInput as useInput7 } from "ink";
|
|
9224
|
+
import TextInput5 from "ink-text-input";
|
|
9169
9225
|
import { useState as useState8 } from "react";
|
|
9170
9226
|
import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
9227
|
+
function alertBodyFor(channel) {
|
|
9228
|
+
const c2 = channel.trim();
|
|
9229
|
+
const base = { name: "dataroom alert", threshold: 5, windowSeconds: 60, signal: "any" };
|
|
9230
|
+
if (/^https?:\/\//i.test(c2)) return { ...base, slackUrl: c2 };
|
|
9231
|
+
if (c2.includes("@")) return { ...base, emails: [c2] };
|
|
9232
|
+
return { ...base, telegram: [c2] };
|
|
9233
|
+
}
|
|
9234
|
+
function SettingsPanel({ active: active2, focused }) {
|
|
9235
|
+
void active2;
|
|
9236
|
+
const { cols, rows } = usePanelSize();
|
|
9237
|
+
const [sel, setSel] = useState8(0);
|
|
9238
|
+
const [editing, setEditing] = useState8(null);
|
|
9239
|
+
const [input, setInput] = useState8("");
|
|
9240
|
+
const [confirmDel, setConfirmDel] = useState8(null);
|
|
9241
|
+
const [msg, setMsg] = useState8(null);
|
|
9242
|
+
const [busy, setBusy] = useState8(false);
|
|
9243
|
+
const localQ = useLoader(() => api.settings.getLocalLogs());
|
|
9244
|
+
const whQ = useLoader(() => api.settings.getWebhooks());
|
|
9245
|
+
const alertQ = useLoader(() => api.settings.getAlerts());
|
|
9246
|
+
const local = localQ.data;
|
|
9247
|
+
const webhooks = whQ.data?.webhooks ?? [];
|
|
9248
|
+
const alerts = alertQ.data?.rules ?? [];
|
|
9249
|
+
const rowsAll = [
|
|
9250
|
+
{ kind: "ll-enabled" },
|
|
9251
|
+
{ kind: "ll-path" },
|
|
9252
|
+
...webhooks.map((wh) => ({ kind: "wh", wh })),
|
|
9253
|
+
{ kind: "wh-add" },
|
|
9254
|
+
...alerts.map((rule) => ({ kind: "alert", rule })),
|
|
9255
|
+
{ kind: "alert-add" }
|
|
9256
|
+
];
|
|
9257
|
+
const selClamped = Math.min(sel, rowsAll.length - 1);
|
|
9258
|
+
const cur = rowsAll[selClamped];
|
|
9259
|
+
const keyOf = (r) => r.kind === "wh" ? "wh:" + r.wh.id : r.kind === "alert" ? "alert:" + r.rule.id : r.kind;
|
|
9260
|
+
const reloadAll = () => {
|
|
9261
|
+
localQ.reload();
|
|
9262
|
+
whQ.reload();
|
|
9263
|
+
alertQ.reload();
|
|
9264
|
+
};
|
|
9265
|
+
const run12 = (label, fn, reload) => {
|
|
9266
|
+
if (busy) return;
|
|
9267
|
+
setBusy(true);
|
|
9268
|
+
setMsg({ text: label + "\u2026", level: "ok" });
|
|
9269
|
+
fn().then(() => {
|
|
9270
|
+
setMsg({ text: "\u2713 " + label, level: "ok" });
|
|
9271
|
+
reload();
|
|
9272
|
+
}).catch((e) => setMsg({ text: "\u2717 " + (e instanceof Error ? e.message : String(e)), level: "bad" })).finally(() => setBusy(false));
|
|
9273
|
+
};
|
|
9274
|
+
const activate = (r) => {
|
|
9275
|
+
if (r.kind === "ll-enabled") {
|
|
9276
|
+
if (!local) return;
|
|
9277
|
+
if (!local.enabled && !local.path.trim()) {
|
|
9278
|
+
setMsg({ text: "set a path first (\u2193 then enter)", level: "bad" });
|
|
9279
|
+
return;
|
|
9280
|
+
}
|
|
9281
|
+
run12(local.enabled ? "local logs disabled" : "local logs enabled", () => api.settings.setLocalLogs({ enabled: !local.enabled, path: local.path }), localQ.reload);
|
|
9282
|
+
} else if (r.kind === "ll-path") {
|
|
9283
|
+
setInput(local?.path ?? "");
|
|
9284
|
+
setEditing("path");
|
|
9285
|
+
} else if (r.kind === "wh") {
|
|
9286
|
+
run12(r.wh.enabled ? "webhook disabled" : "webhook enabled", () => api.settings.updateWebhook(r.wh.id, { enabled: !r.wh.enabled }), whQ.reload);
|
|
9287
|
+
} else if (r.kind === "wh-add") {
|
|
9288
|
+
setInput("");
|
|
9289
|
+
setEditing("wh-url");
|
|
9290
|
+
} else if (r.kind === "alert") {
|
|
9291
|
+
run12(r.rule.enabled ? "alert disabled" : "alert enabled", () => api.settings.setAlertEnabled(r.rule.id, !r.rule.enabled), alertQ.reload);
|
|
9292
|
+
} else {
|
|
9293
|
+
setInput("");
|
|
9294
|
+
setEditing("alert-channel");
|
|
9295
|
+
}
|
|
9296
|
+
};
|
|
9297
|
+
const submitInput = () => {
|
|
9298
|
+
const v = input.trim();
|
|
9299
|
+
const which = editing;
|
|
9300
|
+
setEditing(null);
|
|
9301
|
+
if (which === "path") {
|
|
9302
|
+
const enabled = (local?.enabled ?? false) && v.length > 0;
|
|
9303
|
+
run12(v ? `path saved${enabled ? "" : " (press enter on enabled to turn on)"}` : "path cleared (local logs off)", () => api.settings.setLocalLogs({ enabled, path: v }), localQ.reload);
|
|
9304
|
+
} else if (which === "wh-url") {
|
|
9305
|
+
if (!v) return;
|
|
9306
|
+
run12("webhook added", () => api.settings.createWebhook({ url: v, events: "denials" }), whQ.reload);
|
|
9307
|
+
} else if (which === "alert-channel") {
|
|
9308
|
+
if (!v) return;
|
|
9309
|
+
run12("alert rule added", () => api.settings.createAlert(alertBodyFor(v)), alertQ.reload);
|
|
9310
|
+
}
|
|
9311
|
+
};
|
|
9312
|
+
useInput7(
|
|
9313
|
+
(inp, key) => {
|
|
9314
|
+
setMsg(null);
|
|
9315
|
+
if (key.upArrow) {
|
|
9316
|
+
setSel((n) => Math.max(0, n - 1));
|
|
9317
|
+
setConfirmDel(null);
|
|
9318
|
+
} else if (key.downArrow) {
|
|
9319
|
+
setSel((n) => Math.min(rowsAll.length - 1, n + 1));
|
|
9320
|
+
setConfirmDel(null);
|
|
9321
|
+
} else if (key.return || inp === " ") activate(cur);
|
|
9322
|
+
else if (inp === "e" && cur.kind === "wh") {
|
|
9323
|
+
const next = EVENTS[(EVENTS.indexOf(cur.wh.events) + 1) % EVENTS.length];
|
|
9324
|
+
run12(`webhook events \u2192 ${next}`, () => api.settings.updateWebhook(cur.wh.id, { events: next }), whQ.reload);
|
|
9325
|
+
} else if (inp === "e" && cur.kind === "ll-path") activate(cur);
|
|
9326
|
+
else if (inp === "a") {
|
|
9327
|
+
if (cur.kind === "wh" || cur.kind === "wh-add") {
|
|
9328
|
+
setInput("");
|
|
9329
|
+
setEditing("wh-url");
|
|
9330
|
+
} else if (cur.kind === "alert" || cur.kind === "alert-add") {
|
|
9331
|
+
setInput("");
|
|
9332
|
+
setEditing("alert-channel");
|
|
9333
|
+
}
|
|
9334
|
+
} else if (inp === "d" && (cur.kind === "wh" || cur.kind === "alert")) {
|
|
9335
|
+
const k = keyOf(cur);
|
|
9336
|
+
if (confirmDel !== k) {
|
|
9337
|
+
setConfirmDel(k);
|
|
9338
|
+
setMsg({ text: "press d again to delete", level: "bad" });
|
|
9339
|
+
return;
|
|
9340
|
+
}
|
|
9341
|
+
setConfirmDel(null);
|
|
9342
|
+
if (cur.kind === "wh") run12("webhook deleted", () => api.settings.deleteWebhook(cur.wh.id), whQ.reload);
|
|
9343
|
+
else run12("alert deleted", () => api.settings.deleteAlert(cur.rule.id), alertQ.reload);
|
|
9344
|
+
} else if (inp === "r") reloadAll();
|
|
9345
|
+
},
|
|
9346
|
+
{ isActive: focused && !editing }
|
|
9347
|
+
);
|
|
9348
|
+
const loading = localQ.loading && !localQ.data || whQ.loading && !whQ.data || alertQ.loading && !alertQ.data;
|
|
9349
|
+
const error = localQ.error ?? whQ.error ?? alertQ.error;
|
|
9350
|
+
const mark = (r) => keyOf(r) === keyOf(cur) && focused ? "\u25B8 " : " ";
|
|
9351
|
+
const onOff = (on) => on ? /* @__PURE__ */ jsx9(Text9, { color: theme.ok, children: "on " }) : /* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: "off" });
|
|
9352
|
+
const chanOf = (rule) => [...(rule.slackUrls ?? []).map((u) => "slack " + u), ...rule.emails ?? [], ...(rule.telegram ?? []).map((t) => "tg " + t)].join(", ") || "\u2014";
|
|
9353
|
+
const listBudget = Math.max(4, rows - 8);
|
|
9354
|
+
const start = Math.min(Math.max(0, selClamped - Math.floor(listBudget / 2)), Math.max(0, rowsAll.length - listBudget));
|
|
9355
|
+
const inWindow = (r) => {
|
|
9356
|
+
const i = rowsAll.findIndex((x) => keyOf(x) === keyOf(r));
|
|
9357
|
+
return i >= start && i < start + listBudget;
|
|
9358
|
+
};
|
|
9359
|
+
return /* @__PURE__ */ jsx9(DataView, { loading, error, children: /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", children: [
|
|
9360
|
+
/* @__PURE__ */ jsx9(Text9, { 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" }),
|
|
9361
|
+
editing ? /* @__PURE__ */ jsxs9(Box9, { children: [
|
|
9362
|
+
/* @__PURE__ */ jsx9(Text9, { color: theme.warn, children: editing === "path" ? "local log path: " : editing === "wh-url" ? "webhook url: " : "channel (slack url / email / telegram id): " }),
|
|
9363
|
+
/* @__PURE__ */ jsx9(TextInput5, { value: input, onChange: setInput, onSubmit: submitInput })
|
|
9364
|
+
] }) : msg ? /* @__PURE__ */ jsx9(Text9, { color: msg.level === "bad" ? theme.bad : theme.ok, children: truncate2(msg.text, cols) }) : /* @__PURE__ */ jsx9(Text9, { children: " " }),
|
|
9365
|
+
inWindow(rowsAll[0]) || inWindow(rowsAll[1]) ? /* @__PURE__ */ jsxs9(Box9, { marginTop: 1, flexDirection: "column", children: [
|
|
9366
|
+
/* @__PURE__ */ jsxs9(Text9, { bold: true, color: theme.accentBright, children: [
|
|
9367
|
+
"LOCAL LOGS ",
|
|
9368
|
+
/* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: "\u2014 hooks mirror every decision to a file on the agent machine" })
|
|
9369
|
+
] }),
|
|
9370
|
+
/* @__PURE__ */ jsxs9(Text9, { wrap: "truncate", children: [
|
|
9371
|
+
/* @__PURE__ */ jsx9(Text9, { color: keyOf(cur) === "ll-enabled" && focused ? theme.accentBright : theme.dim, children: mark(rowsAll[0]) }),
|
|
9372
|
+
/* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: "enabled ".padEnd(10) }),
|
|
9373
|
+
onOff(!!local?.enabled),
|
|
9374
|
+
/* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: " enter toggles" })
|
|
9375
|
+
] }),
|
|
9376
|
+
/* @__PURE__ */ jsxs9(Text9, { wrap: "truncate", children: [
|
|
9377
|
+
/* @__PURE__ */ jsx9(Text9, { color: keyOf(cur) === "ll-path" && focused ? theme.accentBright : theme.dim, children: mark(rowsAll[1]) }),
|
|
9378
|
+
/* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: "path ".padEnd(10) }),
|
|
9379
|
+
local?.path ? /* @__PURE__ */ jsx9(Text9, { color: theme.accent, children: truncate2(local.path, cols - 14) }) : /* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: "not set \u2014 enter to edit" })
|
|
9380
|
+
] })
|
|
9381
|
+
] }) : null,
|
|
9382
|
+
/* @__PURE__ */ jsxs9(Box9, { marginTop: 1, flexDirection: "column", children: [
|
|
9383
|
+
/* @__PURE__ */ jsxs9(Text9, { bold: true, color: theme.accentBright, children: [
|
|
9384
|
+
"WEBHOOKS ",
|
|
9385
|
+
/* @__PURE__ */ jsxs9(Text9, { color: theme.dim, children: [
|
|
9386
|
+
"\u2014 POST every matching event to your endpoint (",
|
|
9387
|
+
webhooks.length,
|
|
9388
|
+
")"
|
|
9389
|
+
] })
|
|
9390
|
+
] }),
|
|
9391
|
+
webhooks.filter((wh) => inWindow({ kind: "wh", wh })).map((wh) => /* @__PURE__ */ jsxs9(Text9, { wrap: "truncate", children: [
|
|
9392
|
+
/* @__PURE__ */ jsx9(Text9, { color: keyOf(cur) === "wh:" + wh.id && focused ? theme.accentBright : theme.dim, children: mark({ kind: "wh", wh }) }),
|
|
9393
|
+
onOff(wh.enabled),
|
|
9394
|
+
/* @__PURE__ */ jsx9(Text9, { color: theme.warn, children: (" " + wh.events).padEnd(9) }),
|
|
9395
|
+
/* @__PURE__ */ jsx9(Text9, { color: theme.accent, children: truncate2(wh.url, cols - 16) })
|
|
9396
|
+
] }, wh.id)),
|
|
9397
|
+
inWindow(rowsAll.find((r) => r.kind === "wh-add")) ? /* @__PURE__ */ jsxs9(Text9, { children: [
|
|
9398
|
+
/* @__PURE__ */ jsx9(Text9, { color: cur.kind === "wh-add" && focused ? theme.accentBright : theme.dim, children: mark({ kind: "wh-add" }) }),
|
|
9399
|
+
/* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: "+ add webhook (enter)" })
|
|
9400
|
+
] }) : null
|
|
9401
|
+
] }),
|
|
9402
|
+
/* @__PURE__ */ jsxs9(Box9, { marginTop: 1, flexDirection: "column", children: [
|
|
9403
|
+
/* @__PURE__ */ jsxs9(Text9, { bold: true, color: theme.accentBright, children: [
|
|
9404
|
+
"ALERTS ",
|
|
9405
|
+
/* @__PURE__ */ jsxs9(Text9, { color: theme.dim, children: [
|
|
9406
|
+
"\u2014 notify on a signal spike (",
|
|
9407
|
+
alerts.length,
|
|
9408
|
+
")"
|
|
9409
|
+
] })
|
|
9410
|
+
] }),
|
|
9411
|
+
alerts.filter((rule) => inWindow({ kind: "alert", rule })).map((rule) => /* @__PURE__ */ jsxs9(Text9, { wrap: "truncate", children: [
|
|
9412
|
+
/* @__PURE__ */ jsx9(Text9, { color: keyOf(cur) === "alert:" + rule.id && focused ? theme.accentBright : theme.dim, children: mark({ kind: "alert", rule }) }),
|
|
9413
|
+
onOff(rule.enabled),
|
|
9414
|
+
/* @__PURE__ */ jsx9(Text9, { color: theme.warn, children: (" " + rule.signal).padEnd(11) }),
|
|
9415
|
+
/* @__PURE__ */ jsx9(Text9, { children: `\u2265${rule.threshold}/${rule.windowSeconds}s ` }),
|
|
9416
|
+
/* @__PURE__ */ jsx9(Text9, { color: theme.accent, children: truncate2(chanOf(rule), cols - 26) })
|
|
9417
|
+
] }, rule.id)),
|
|
9418
|
+
inWindow(rowsAll[rowsAll.length - 1]) ? /* @__PURE__ */ jsxs9(Text9, { children: [
|
|
9419
|
+
/* @__PURE__ */ jsx9(Text9, { color: cur.kind === "alert-add" && focused ? theme.accentBright : theme.dim, children: mark({ kind: "alert-add" }) }),
|
|
9420
|
+
/* @__PURE__ */ jsx9(Text9, { color: theme.dim, children: "+ add alert (enter \u2014 one channel: slack url, email or telegram chat id)" })
|
|
9421
|
+
] }) : null
|
|
9422
|
+
] })
|
|
9423
|
+
] }) });
|
|
9424
|
+
}
|
|
9425
|
+
var EVENTS;
|
|
9426
|
+
var init_Settings = __esm({
|
|
9427
|
+
"src/tui/panels/Settings.tsx"() {
|
|
9428
|
+
"use strict";
|
|
9429
|
+
init_api_client();
|
|
9430
|
+
init_components();
|
|
9431
|
+
init_hooks();
|
|
9432
|
+
init_theme();
|
|
9433
|
+
EVENTS = ["denials", "allowed", "all"];
|
|
9434
|
+
}
|
|
9435
|
+
});
|
|
9436
|
+
|
|
9437
|
+
// src/tui/App.tsx
|
|
9438
|
+
import { Box as Box10, Text as Text10, useApp, useInput as useInput8 } from "ink";
|
|
9439
|
+
import { useState as useState9 } from "react";
|
|
9440
|
+
import { jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
9171
9441
|
function LiveHint() {
|
|
9172
|
-
return /* @__PURE__ */
|
|
9173
|
-
/* @__PURE__ */
|
|
9174
|
-
/* @__PURE__ */
|
|
9175
|
-
/* @__PURE__ */
|
|
9176
|
-
/* @__PURE__ */
|
|
9442
|
+
return /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", children: [
|
|
9443
|
+
/* @__PURE__ */ jsx10(Text10, { color: theme.accentBright, bold: true, children: "\u25B6 REALTIME CONSOLE" }),
|
|
9444
|
+
/* @__PURE__ */ jsx10(Text10, { color: theme.dim, children: "Fullscreen live monitor \u2014 streaming tool calls, active charts," }),
|
|
9445
|
+
/* @__PURE__ */ jsx10(Text10, { color: theme.dim, children: "counters, DLP hits and denial alerts. Updates every 2s." }),
|
|
9446
|
+
/* @__PURE__ */ jsx10(Box10, { marginTop: 1, children: /* @__PURE__ */ jsxs10(Text10, { children: [
|
|
9177
9447
|
"press ",
|
|
9178
|
-
/* @__PURE__ */
|
|
9448
|
+
/* @__PURE__ */ jsx10(Text10, { color: theme.accent, children: "enter" }),
|
|
9179
9449
|
" to go live"
|
|
9180
9450
|
] }) })
|
|
9181
9451
|
] });
|
|
9182
9452
|
}
|
|
9183
|
-
function Banner() {
|
|
9184
|
-
const wide =
|
|
9453
|
+
function Banner({ cols }) {
|
|
9454
|
+
const wide = cols >= 82;
|
|
9185
9455
|
if (!wide) {
|
|
9186
|
-
return /* @__PURE__ */
|
|
9187
|
-
/* @__PURE__ */
|
|
9188
|
-
/* @__PURE__ */
|
|
9456
|
+
return /* @__PURE__ */ jsxs10(Box10, { children: [
|
|
9457
|
+
/* @__PURE__ */ jsx10(Text10, { bold: true, color: theme.accentBright, children: "SolonGate" }),
|
|
9458
|
+
/* @__PURE__ */ jsx10(Text10, { color: theme.dim, children: " \u2014 security control center" })
|
|
9189
9459
|
] });
|
|
9190
9460
|
}
|
|
9191
|
-
return /* @__PURE__ */
|
|
9192
|
-
BANNER_FULL.map((line, i) => /* @__PURE__ */
|
|
9193
|
-
/* @__PURE__ */
|
|
9461
|
+
return /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", children: [
|
|
9462
|
+
BANNER_FULL.map((line, i) => /* @__PURE__ */ jsx10(Text10, { bold: true, color: BANNER_HEX[i], children: line }, i)),
|
|
9463
|
+
/* @__PURE__ */ jsx10(Text10, { color: theme.dim, children: " security control center \xB7 manage policies, rate limits, DLP & more" })
|
|
9194
9464
|
] });
|
|
9195
9465
|
}
|
|
9196
9466
|
function App() {
|
|
9197
9467
|
const { exit } = useApp();
|
|
9198
|
-
const [section, setSection] =
|
|
9199
|
-
const [focus, setFocus] =
|
|
9200
|
-
const [help, setHelp] =
|
|
9201
|
-
|
|
9468
|
+
const [section, setSection] = useState9(0);
|
|
9469
|
+
const [focus, setFocus] = useState9("nav");
|
|
9470
|
+
const [help, setHelp] = useState9(false);
|
|
9471
|
+
useInput8((input, key) => {
|
|
9202
9472
|
if (help) {
|
|
9203
9473
|
setHelp(false);
|
|
9204
9474
|
return;
|
|
@@ -9217,34 +9487,33 @@ function App() {
|
|
|
9217
9487
|
else if (input === "q" && SECTIONS[section].label === "Live") exit();
|
|
9218
9488
|
}
|
|
9219
9489
|
});
|
|
9220
|
-
const cols
|
|
9221
|
-
const rows = process.stdout.rows ?? 30;
|
|
9490
|
+
const { cols, rows } = useTermSize();
|
|
9222
9491
|
const current = SECTIONS[section];
|
|
9223
|
-
if (help) return /* @__PURE__ */
|
|
9492
|
+
if (help) return /* @__PURE__ */ jsx10(HelpOverlay, { cols, rows });
|
|
9224
9493
|
if (current.label === "Live" && focus === "panel") {
|
|
9225
|
-
return /* @__PURE__ */
|
|
9494
|
+
return /* @__PURE__ */ jsx10(Box10, { flexDirection: "column", width: cols, height: rows, children: /* @__PURE__ */ jsx10(LivePanel, { active: true, focused: true }) });
|
|
9226
9495
|
}
|
|
9227
9496
|
const Panel = current.Panel;
|
|
9228
|
-
return /* @__PURE__ */
|
|
9229
|
-
/* @__PURE__ */
|
|
9230
|
-
/* @__PURE__ */
|
|
9231
|
-
/* @__PURE__ */
|
|
9232
|
-
/* @__PURE__ */
|
|
9497
|
+
return /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", width: cols, height: rows, paddingX: 1, paddingTop: 1, children: [
|
|
9498
|
+
/* @__PURE__ */ jsx10(Banner, { cols }),
|
|
9499
|
+
/* @__PURE__ */ jsxs10(Box10, { marginTop: 1, flexGrow: 1, children: [
|
|
9500
|
+
/* @__PURE__ */ jsx10(Box10, { flexDirection: "column", width: 16, borderStyle: "round", borderColor: focus === "nav" ? theme.accent : "gray", paddingX: 1, children: SECTIONS.map((s, i) => /* @__PURE__ */ jsx10(Text10, { color: i === section ? theme.accentBright : void 0, bold: i === section, children: (i === section ? "\u25B8 " : " ") + s.label }, s.label)) }),
|
|
9501
|
+
/* @__PURE__ */ jsx10(Box10, { flexGrow: 1, borderStyle: "round", borderColor: focus === "panel" ? theme.accent : "gray", paddingX: 1, paddingY: 0, children: /* @__PURE__ */ jsx10(Panel, { active: focus === "panel" || current.label !== "Live", focused: focus === "panel" }) })
|
|
9233
9502
|
] }),
|
|
9234
|
-
/* @__PURE__ */
|
|
9503
|
+
/* @__PURE__ */ jsx10(Box10, { children: focus === "nav" ? /* @__PURE__ */ jsx10(KeyHints, { hints: [["\u2191\u2193", "section"], ["\u2192/enter", "open"], ["?", "help"], ["q", "quit"]] }) : /* @__PURE__ */ jsx10(KeyHints, { hints: [["\u2190/esc", "back"], ["\u2191\u2193", "in-panel"], ["space/s", "act"]] }) })
|
|
9235
9504
|
] });
|
|
9236
9505
|
}
|
|
9237
9506
|
function HelpOverlay({ cols, rows }) {
|
|
9238
|
-
return /* @__PURE__ */
|
|
9239
|
-
/* @__PURE__ */
|
|
9240
|
-
/* @__PURE__ */
|
|
9241
|
-
/* @__PURE__ */
|
|
9242
|
-
keys.map(([k, desc]) => /* @__PURE__ */
|
|
9243
|
-
/* @__PURE__ */
|
|
9244
|
-
/* @__PURE__ */
|
|
9507
|
+
return /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", width: cols, height: rows, paddingX: 2, paddingTop: 1, children: [
|
|
9508
|
+
/* @__PURE__ */ jsx10(Text10, { bold: true, color: theme.accentBright, children: "SolonGate \u2014 keyboard shortcuts" }),
|
|
9509
|
+
/* @__PURE__ */ jsx10(Box10, { marginTop: 1, flexDirection: "column", children: HELP.map(([group, keys]) => /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", marginBottom: 1, children: [
|
|
9510
|
+
/* @__PURE__ */ jsx10(Text10, { bold: true, color: theme.accent, children: group }),
|
|
9511
|
+
keys.map(([k, desc]) => /* @__PURE__ */ jsxs10(Text10, { children: [
|
|
9512
|
+
/* @__PURE__ */ jsx10(Text10, { color: theme.accentBright, children: (" " + k).padEnd(16) }),
|
|
9513
|
+
/* @__PURE__ */ jsx10(Text10, { color: theme.dim, children: desc })
|
|
9245
9514
|
] }, k))
|
|
9246
9515
|
] }, group)) }),
|
|
9247
|
-
/* @__PURE__ */
|
|
9516
|
+
/* @__PURE__ */ jsx10(Text10, { color: theme.dim, children: "press any key to close" })
|
|
9248
9517
|
] });
|
|
9249
9518
|
}
|
|
9250
9519
|
var SECTIONS, BANNER_HEX, HELP;
|
|
@@ -9261,6 +9530,8 @@ var init_App = __esm({
|
|
|
9261
9530
|
init_Stats();
|
|
9262
9531
|
init_Audit();
|
|
9263
9532
|
init_Agents();
|
|
9533
|
+
init_Settings();
|
|
9534
|
+
init_hooks();
|
|
9264
9535
|
SECTIONS = [
|
|
9265
9536
|
{ label: "Live", Panel: LiveHint },
|
|
9266
9537
|
{ label: "Agents", Panel: AgentsPanel },
|
|
@@ -9268,14 +9539,17 @@ var init_App = __esm({
|
|
|
9268
9539
|
{ label: "Rate Limit", Panel: RateLimitPanel },
|
|
9269
9540
|
{ label: "DLP", Panel: DlpPanel },
|
|
9270
9541
|
{ label: "Stats", Panel: StatsPanel },
|
|
9271
|
-
{ label: "Audit", Panel: AuditPanel }
|
|
9542
|
+
{ label: "Audit", Panel: AuditPanel },
|
|
9543
|
+
{ label: "Settings", Panel: SettingsPanel }
|
|
9272
9544
|
];
|
|
9273
9545
|
BANNER_HEX = ["#1432A0", "#2850BE", "#3C6ED7", "#5A8CE6", "#82AAF0", "#AAC8FA"];
|
|
9274
9546
|
HELP = [
|
|
9275
9547
|
["Global", [["\u2191\u2193", "move between sections"], ["\u2192 / enter", "open a section"], ["\u2190 / esc", "back to the menu"], ["?", "this help"], ["q", "quit"]]],
|
|
9276
|
-
["Live", [["\u2191\u2193", "select a stream row"], ["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)"]]],
|
|
9548
|
+
["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)"]]],
|
|
9277
9549
|
["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"], ["v", "versions / rollback"], ["s", "save"], ["x", "discard"]]],
|
|
9278
|
-
["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"]]]
|
|
9550
|
+
["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"]]],
|
|
9551
|
+
["Audit", [["\u2191\u2193", "select (list scrolls)"], ["enter", "full entry detail"], ["f / g", "decision / signal filter"], ["t / n / /", "tool / agent / search"], ["c", "clear filters"]]],
|
|
9552
|
+
["Settings", [["\u2191\u2193", "move"], ["enter / space", "toggle \xB7 edit \xB7 add"], ["e", "webhook events"], ["d d", "delete"], ["r", "refresh"]]]
|
|
9279
9553
|
];
|
|
9280
9554
|
}
|
|
9281
9555
|
});
|
|
@@ -9286,7 +9560,7 @@ __export(tui_exports, {
|
|
|
9286
9560
|
launchTui: () => launchTui
|
|
9287
9561
|
});
|
|
9288
9562
|
import { render } from "ink";
|
|
9289
|
-
import { jsx as
|
|
9563
|
+
import { jsx as jsx11 } from "react/jsx-runtime";
|
|
9290
9564
|
async function launchTui() {
|
|
9291
9565
|
if (!process.stdout.isTTY || !process.stdin.isTTY) {
|
|
9292
9566
|
process.stderr.write(
|
|
@@ -9298,10 +9572,9 @@ async function launchTui() {
|
|
|
9298
9572
|
process.stderr.write("Not logged in. Run `solongate login` first.\n");
|
|
9299
9573
|
return;
|
|
9300
9574
|
}
|
|
9301
|
-
captureFocusTarget();
|
|
9302
9575
|
process.stdout.write("\x1B[?1049h\x1B[H");
|
|
9303
9576
|
try {
|
|
9304
|
-
const { waitUntilExit } = render(/* @__PURE__ */
|
|
9577
|
+
const { waitUntilExit } = render(/* @__PURE__ */ jsx11(App, {}));
|
|
9305
9578
|
await waitUntilExit();
|
|
9306
9579
|
} finally {
|
|
9307
9580
|
process.stdout.write("\x1B[?1049l");
|
|
@@ -9312,7 +9585,6 @@ var init_tui = __esm({
|
|
|
9312
9585
|
"use strict";
|
|
9313
9586
|
init_App();
|
|
9314
9587
|
init_client();
|
|
9315
|
-
init_notify();
|
|
9316
9588
|
}
|
|
9317
9589
|
});
|
|
9318
9590
|
|
|
@@ -10004,9 +10276,9 @@ var init_agents2 = __esm({
|
|
|
10004
10276
|
});
|
|
10005
10277
|
|
|
10006
10278
|
// src/commands/doctor.ts
|
|
10007
|
-
import { existsSync as
|
|
10279
|
+
import { existsSync as existsSync4, statSync as statSync2 } from "fs";
|
|
10008
10280
|
import { homedir as homedir5 } from "os";
|
|
10009
|
-
import { join as
|
|
10281
|
+
import { join as join7 } from "path";
|
|
10010
10282
|
async function run6(argv) {
|
|
10011
10283
|
const { flags } = parse(argv);
|
|
10012
10284
|
const json = flagBool(flags, "json");
|
|
@@ -10036,7 +10308,7 @@ async function run6(argv) {
|
|
|
10036
10308
|
} catch {
|
|
10037
10309
|
}
|
|
10038
10310
|
}
|
|
10039
|
-
if (
|
|
10311
|
+
if (existsSync4(LOCAL_LOG2)) {
|
|
10040
10312
|
const st = statSync2(LOCAL_LOG2);
|
|
10041
10313
|
const ageMin = (Date.now() - st.mtimeMs) / 6e4;
|
|
10042
10314
|
checks.push({ name: "local logs", ok: true, detail: `on \xB7 ${(st.size / 1024).toFixed(0)}KB \xB7 last write ${ageMin < 1 ? "just now" : Math.round(ageMin) + "m ago"}` });
|
|
@@ -10066,14 +10338,14 @@ var init_doctor = __esm({
|
|
|
10066
10338
|
init_api_client();
|
|
10067
10339
|
init_format();
|
|
10068
10340
|
init_args();
|
|
10069
|
-
LOCAL_LOG2 =
|
|
10341
|
+
LOCAL_LOG2 = join7(homedir5(), ".solongate", "local-logs", "solongate-audit.jsonl");
|
|
10070
10342
|
}
|
|
10071
10343
|
});
|
|
10072
10344
|
|
|
10073
10345
|
// src/commands/watch.ts
|
|
10074
|
-
import { closeSync as closeSync2, existsSync as
|
|
10346
|
+
import { closeSync as closeSync2, existsSync as existsSync5, openSync as openSync2, readSync as readSync2, statSync as statSync3 } from "fs";
|
|
10075
10347
|
import { homedir as homedir6 } from "os";
|
|
10076
|
-
import { join as
|
|
10348
|
+
import { join as join8 } from "path";
|
|
10077
10349
|
function tailLocal(file, maxBytes = 131072) {
|
|
10078
10350
|
try {
|
|
10079
10351
|
const size = statSync3(file).size;
|
|
@@ -10117,7 +10389,7 @@ async function run7(argv) {
|
|
|
10117
10389
|
for (const r of rows) if (keep(r)) print(r, json);
|
|
10118
10390
|
};
|
|
10119
10391
|
const pollLocal = () => {
|
|
10120
|
-
if (cloudOnly || !
|
|
10392
|
+
if (cloudOnly || !existsSync5(LOCAL_LOG3)) return;
|
|
10121
10393
|
const rows = [];
|
|
10122
10394
|
for (const line of tailLocal(LOCAL_LOG3)) {
|
|
10123
10395
|
try {
|
|
@@ -10180,7 +10452,7 @@ var init_watch = __esm({
|
|
|
10180
10452
|
init_cli_utils();
|
|
10181
10453
|
init_args();
|
|
10182
10454
|
init_format();
|
|
10183
|
-
LOCAL_LOG3 =
|
|
10455
|
+
LOCAL_LOG3 = join8(homedir6(), ".solongate", "local-logs", "solongate-audit.jsonl");
|
|
10184
10456
|
trunc = (s, n) => s.length <= n ? s : s.slice(0, n - 1) + "\u2026";
|
|
10185
10457
|
time = (ms) => new Date(ms).toTimeString().slice(0, 8);
|
|
10186
10458
|
}
|
|
@@ -10482,32 +10754,32 @@ __export(global_install_exports, {
|
|
|
10482
10754
|
runGlobalRestore: () => runGlobalRestore,
|
|
10483
10755
|
unlockProtected: () => unlockProtected
|
|
10484
10756
|
});
|
|
10485
|
-
import { readFileSync as readFileSync7, writeFileSync as
|
|
10486
|
-
import { resolve as resolve4, join as
|
|
10757
|
+
import { readFileSync as readFileSync7, writeFileSync as writeFileSync4, existsSync as existsSync6, mkdirSync as mkdirSync4 } from "fs";
|
|
10758
|
+
import { resolve as resolve4, join as join9, dirname } from "path";
|
|
10487
10759
|
import { homedir as homedir7 } from "os";
|
|
10488
10760
|
import { fileURLToPath } from "url";
|
|
10489
10761
|
import { createInterface } from "readline";
|
|
10490
|
-
import { execFileSync as
|
|
10762
|
+
import { execFileSync as execFileSync2 } from "child_process";
|
|
10491
10763
|
function lockFile(file) {
|
|
10492
|
-
if (!
|
|
10764
|
+
if (!existsSync6(file)) return;
|
|
10493
10765
|
try {
|
|
10494
10766
|
if (process.platform === "win32") {
|
|
10495
10767
|
try {
|
|
10496
|
-
|
|
10768
|
+
execFileSync2("icacls", [file, "/deny", "*S-1-1-0:(WD,AD,DC,DE)"], { stdio: "ignore" });
|
|
10497
10769
|
} catch {
|
|
10498
10770
|
}
|
|
10499
10771
|
try {
|
|
10500
|
-
|
|
10772
|
+
execFileSync2("attrib", ["+R", file], { stdio: "ignore" });
|
|
10501
10773
|
} catch {
|
|
10502
10774
|
}
|
|
10503
10775
|
} else if (process.platform === "darwin") {
|
|
10504
10776
|
try {
|
|
10505
|
-
|
|
10777
|
+
execFileSync2("chflags", ["uchg", file], { stdio: "ignore" });
|
|
10506
10778
|
} catch {
|
|
10507
10779
|
}
|
|
10508
10780
|
} else {
|
|
10509
10781
|
try {
|
|
10510
|
-
|
|
10782
|
+
execFileSync2("chattr", ["+i", file], { stdio: "ignore" });
|
|
10511
10783
|
} catch {
|
|
10512
10784
|
}
|
|
10513
10785
|
}
|
|
@@ -10515,29 +10787,29 @@ function lockFile(file) {
|
|
|
10515
10787
|
}
|
|
10516
10788
|
}
|
|
10517
10789
|
function unlockFile(file) {
|
|
10518
|
-
if (!
|
|
10790
|
+
if (!existsSync6(file)) return;
|
|
10519
10791
|
try {
|
|
10520
10792
|
if (process.platform === "win32") {
|
|
10521
10793
|
try {
|
|
10522
|
-
|
|
10794
|
+
execFileSync2("icacls", [file, "/remove:d", "*S-1-1-0"], { stdio: "ignore" });
|
|
10523
10795
|
} catch {
|
|
10524
10796
|
}
|
|
10525
10797
|
try {
|
|
10526
|
-
|
|
10798
|
+
execFileSync2("icacls", [file, "/reset"], { stdio: "ignore" });
|
|
10527
10799
|
} catch {
|
|
10528
10800
|
}
|
|
10529
10801
|
try {
|
|
10530
|
-
|
|
10802
|
+
execFileSync2("attrib", ["-R", file], { stdio: "ignore" });
|
|
10531
10803
|
} catch {
|
|
10532
10804
|
}
|
|
10533
10805
|
} else if (process.platform === "darwin") {
|
|
10534
10806
|
try {
|
|
10535
|
-
|
|
10807
|
+
execFileSync2("chflags", ["nouchg", file], { stdio: "ignore" });
|
|
10536
10808
|
} catch {
|
|
10537
10809
|
}
|
|
10538
10810
|
} else {
|
|
10539
10811
|
try {
|
|
10540
|
-
|
|
10812
|
+
execFileSync2("chattr", ["-i", file], { stdio: "ignore" });
|
|
10541
10813
|
} catch {
|
|
10542
10814
|
}
|
|
10543
10815
|
}
|
|
@@ -10547,10 +10819,10 @@ function unlockFile(file) {
|
|
|
10547
10819
|
function protectedTargets() {
|
|
10548
10820
|
const p = globalPaths();
|
|
10549
10821
|
return [
|
|
10550
|
-
|
|
10551
|
-
|
|
10552
|
-
|
|
10553
|
-
|
|
10822
|
+
join9(p.hooksDir, "guard.mjs"),
|
|
10823
|
+
join9(p.hooksDir, "audit.mjs"),
|
|
10824
|
+
join9(p.hooksDir, "stop.mjs"),
|
|
10825
|
+
join9(p.hooksDir, "shield.mjs"),
|
|
10554
10826
|
p.configPath,
|
|
10555
10827
|
p.settingsPath
|
|
10556
10828
|
];
|
|
@@ -10563,25 +10835,25 @@ function unlockProtected() {
|
|
|
10563
10835
|
}
|
|
10564
10836
|
function globalPaths() {
|
|
10565
10837
|
const home = homedir7();
|
|
10566
|
-
const sgDir =
|
|
10567
|
-
const hooksDir =
|
|
10568
|
-
const claudeDir =
|
|
10838
|
+
const sgDir = join9(home, ".solongate");
|
|
10839
|
+
const hooksDir = join9(sgDir, "hooks");
|
|
10840
|
+
const claudeDir = join9(home, ".claude");
|
|
10569
10841
|
return {
|
|
10570
10842
|
home,
|
|
10571
10843
|
sgDir,
|
|
10572
10844
|
hooksDir,
|
|
10573
10845
|
claudeDir,
|
|
10574
|
-
settingsPath:
|
|
10575
|
-
backupPath:
|
|
10576
|
-
configPath:
|
|
10846
|
+
settingsPath: join9(claudeDir, "settings.json"),
|
|
10847
|
+
backupPath: join9(claudeDir, "settings.solongate.bak"),
|
|
10848
|
+
configPath: join9(sgDir, "cloud-guard.json")
|
|
10577
10849
|
};
|
|
10578
10850
|
}
|
|
10579
10851
|
function readHook(filename) {
|
|
10580
|
-
return readFileSync7(
|
|
10852
|
+
return readFileSync7(join9(HOOKS_DIR, filename), "utf-8");
|
|
10581
10853
|
}
|
|
10582
10854
|
function readGuard() {
|
|
10583
|
-
const bundled =
|
|
10584
|
-
return
|
|
10855
|
+
const bundled = join9(HOOKS_DIR, "guard.bundled.mjs");
|
|
10856
|
+
return existsSync6(bundled) ? readFileSync7(bundled, "utf-8") : readHook("guard.mjs");
|
|
10585
10857
|
}
|
|
10586
10858
|
function ask(question) {
|
|
10587
10859
|
const rl = createInterface({ input: process.stdin, output: process.stderr });
|
|
@@ -10594,14 +10866,14 @@ function runGlobalRestore() {
|
|
|
10594
10866
|
const p = globalPaths();
|
|
10595
10867
|
unlockProtected();
|
|
10596
10868
|
removeClaudeShim();
|
|
10597
|
-
if (
|
|
10598
|
-
|
|
10869
|
+
if (existsSync6(p.backupPath)) {
|
|
10870
|
+
writeFileSync4(p.settingsPath, readFileSync7(p.backupPath, "utf-8"));
|
|
10599
10871
|
console.log(` Restored ${p.settingsPath} from backup.`);
|
|
10600
|
-
} else if (
|
|
10872
|
+
} else if (existsSync6(p.settingsPath)) {
|
|
10601
10873
|
try {
|
|
10602
10874
|
const s = JSON.parse(readFileSync7(p.settingsPath, "utf-8"));
|
|
10603
10875
|
delete s.hooks;
|
|
10604
|
-
|
|
10876
|
+
writeFileSync4(p.settingsPath, JSON.stringify(s, null, 2) + "\n");
|
|
10605
10877
|
console.log(` Removed SolonGate hooks from ${p.settingsPath}.`);
|
|
10606
10878
|
} catch {
|
|
10607
10879
|
}
|
|
@@ -10616,7 +10888,7 @@ function escapeRe(s) {
|
|
|
10616
10888
|
function resolveRealClaude() {
|
|
10617
10889
|
try {
|
|
10618
10890
|
const finder = process.platform === "win32" ? "where" : "which";
|
|
10619
|
-
const out2 =
|
|
10891
|
+
const out2 = execFileSync2(finder, ["claude"], { encoding: "utf-8" }).split(/\r?\n/).map((s) => s.trim()).filter(Boolean);
|
|
10620
10892
|
if (process.platform === "win32") {
|
|
10621
10893
|
const low = (s) => s.toLowerCase();
|
|
10622
10894
|
return out2.find((l) => low(l).endsWith(".cmd")) || out2.find((l) => low(l).endsWith(".exe")) || out2.find((l) => low(l).endsWith(".bat")) || out2[0] || null;
|
|
@@ -10629,24 +10901,24 @@ function resolveRealClaude() {
|
|
|
10629
10901
|
function shimTargets() {
|
|
10630
10902
|
if (process.platform === "win32") {
|
|
10631
10903
|
try {
|
|
10632
|
-
const prof =
|
|
10904
|
+
const prof = execFileSync2("powershell", ["-NoProfile", "-Command", "$PROFILE.CurrentUserAllHosts"], { encoding: "utf-8" }).trim();
|
|
10633
10905
|
return prof ? [prof] : [];
|
|
10634
10906
|
} catch {
|
|
10635
10907
|
return [];
|
|
10636
10908
|
}
|
|
10637
10909
|
}
|
|
10638
|
-
return [".bashrc", ".zshrc", ".profile"].map((f) =>
|
|
10910
|
+
return [".bashrc", ".zshrc", ".profile"].map((f) => join9(homedir7(), f)).filter((f) => existsSync6(f));
|
|
10639
10911
|
}
|
|
10640
10912
|
function writeShimBlock(file, block2) {
|
|
10641
10913
|
const re = new RegExp(escapeRe(SHIM_BEGIN) + "[\\s\\S]*?" + escapeRe(SHIM_END) + "\\r?\\n?", "g");
|
|
10642
|
-
let content =
|
|
10914
|
+
let content = existsSync6(file) ? readFileSync7(file, "utf-8") : "";
|
|
10643
10915
|
content = content.replace(re, "");
|
|
10644
10916
|
if (block2) {
|
|
10645
10917
|
if (content.length && !content.endsWith("\n")) content += "\n";
|
|
10646
10918
|
content += block2 + "\n";
|
|
10647
10919
|
}
|
|
10648
10920
|
mkdirSync4(dirname(file), { recursive: true });
|
|
10649
|
-
|
|
10921
|
+
writeFileSync4(file, content);
|
|
10650
10922
|
}
|
|
10651
10923
|
function installClaudeShim(shieldPath) {
|
|
10652
10924
|
const real = resolveRealClaude();
|
|
@@ -10700,19 +10972,19 @@ async function runGlobalInstall(opts = {}) {
|
|
|
10700
10972
|
mkdirSync4(p.hooksDir, { recursive: true });
|
|
10701
10973
|
mkdirSync4(p.claudeDir, { recursive: true });
|
|
10702
10974
|
unlockProtected();
|
|
10703
|
-
|
|
10704
|
-
|
|
10705
|
-
|
|
10706
|
-
|
|
10975
|
+
writeFileSync4(join9(p.hooksDir, "guard.mjs"), readGuard());
|
|
10976
|
+
writeFileSync4(join9(p.hooksDir, "audit.mjs"), readHook("audit.mjs"));
|
|
10977
|
+
writeFileSync4(join9(p.hooksDir, "stop.mjs"), readHook("stop.mjs"));
|
|
10978
|
+
writeFileSync4(join9(p.hooksDir, "shield.mjs"), readHook("shield.mjs"));
|
|
10707
10979
|
console.log(` Installed hooks \u2192 ${p.hooksDir}`);
|
|
10708
|
-
installClaudeShim(
|
|
10709
|
-
|
|
10980
|
+
installClaudeShim(join9(p.hooksDir, "shield.mjs"));
|
|
10981
|
+
writeFileSync4(p.configPath, JSON.stringify({ apiKey, apiUrl }, null, 2) + "\n");
|
|
10710
10982
|
console.log(` Wrote ${p.configPath}`);
|
|
10711
10983
|
let existing = {};
|
|
10712
|
-
if (
|
|
10984
|
+
if (existsSync6(p.settingsPath)) {
|
|
10713
10985
|
const raw = readFileSync7(p.settingsPath, "utf-8");
|
|
10714
|
-
if (!
|
|
10715
|
-
|
|
10986
|
+
if (!existsSync6(p.backupPath)) {
|
|
10987
|
+
writeFileSync4(p.backupPath, raw);
|
|
10716
10988
|
console.log(` Backed up existing settings \u2192 ${p.backupPath}`);
|
|
10717
10989
|
}
|
|
10718
10990
|
try {
|
|
@@ -10721,9 +10993,9 @@ async function runGlobalInstall(opts = {}) {
|
|
|
10721
10993
|
existing = {};
|
|
10722
10994
|
}
|
|
10723
10995
|
}
|
|
10724
|
-
const guardAbs =
|
|
10725
|
-
const auditAbs =
|
|
10726
|
-
const stopAbs =
|
|
10996
|
+
const guardAbs = join9(p.hooksDir, "guard.mjs").replace(/\\/g, "/");
|
|
10997
|
+
const auditAbs = join9(p.hooksDir, "audit.mjs").replace(/\\/g, "/");
|
|
10998
|
+
const stopAbs = join9(p.hooksDir, "stop.mjs").replace(/\\/g, "/");
|
|
10727
10999
|
const nodeBin = process.execPath.replace(/\\/g, "/");
|
|
10728
11000
|
const call = process.platform === "win32" ? "& " : "";
|
|
10729
11001
|
const hookCmd = (script) => `${call}"${nodeBin}" "${script}" claude-code "Claude Code"`;
|
|
@@ -10735,7 +11007,7 @@ async function runGlobalInstall(opts = {}) {
|
|
|
10735
11007
|
Stop: [{ matcher: "", hooks: [{ type: "command", command: hookCmd(stopAbs) }] }]
|
|
10736
11008
|
}
|
|
10737
11009
|
};
|
|
10738
|
-
|
|
11010
|
+
writeFileSync4(p.settingsPath, JSON.stringify(merged, null, 2) + "\n");
|
|
10739
11011
|
console.log(` Registered global hooks \u2192 ${p.settingsPath}`);
|
|
10740
11012
|
if (process.env["SOLONGATE_OS_LOCK"] === "1") {
|
|
10741
11013
|
lockProtected();
|
|
@@ -10915,7 +11187,7 @@ import { createServer, request as httpRequest } from "http";
|
|
|
10915
11187
|
import { request as httpsRequest } from "https";
|
|
10916
11188
|
import { spawn as spawn3 } from "child_process";
|
|
10917
11189
|
import { URL as URL2 } from "url";
|
|
10918
|
-
import { readFileSync as readFileSync8, existsSync as
|
|
11190
|
+
import { readFileSync as readFileSync8, existsSync as existsSync7, readdirSync, statSync as statSync4 } from "fs";
|
|
10919
11191
|
import { resolve as resolve5 } from "path";
|
|
10920
11192
|
import { homedir as homedir8 } from "os";
|
|
10921
11193
|
function findCacheFile() {
|
|
@@ -10923,7 +11195,7 @@ function findCacheFile() {
|
|
|
10923
11195
|
const envSel = process.env.SOLONGATE_AGENT_ID;
|
|
10924
11196
|
if (envSel) {
|
|
10925
11197
|
const f = resolve5(dir, ".policy-cache-" + envSel.replace(/[^a-zA-Z0-9_-]/g, "_") + ".json");
|
|
10926
|
-
if (
|
|
11198
|
+
if (existsSync7(f)) return f;
|
|
10927
11199
|
}
|
|
10928
11200
|
let best = null, bestTs = -1;
|
|
10929
11201
|
try {
|
|
@@ -10944,7 +11216,7 @@ function findCacheFile() {
|
|
|
10944
11216
|
function loadCfg() {
|
|
10945
11217
|
try {
|
|
10946
11218
|
const f = findCacheFile();
|
|
10947
|
-
if (f &&
|
|
11219
|
+
if (f && existsSync7(f)) {
|
|
10948
11220
|
const c2 = JSON.parse(readFileSync8(f, "utf-8"));
|
|
10949
11221
|
const d = c2?.security?.dlpRedact;
|
|
10950
11222
|
const g = c2?.security?.ghost;
|
|
@@ -11234,7 +11506,7 @@ __export(logs_server_exports, {
|
|
|
11234
11506
|
});
|
|
11235
11507
|
import { createServer as createServer2 } from "http";
|
|
11236
11508
|
import { readFileSync as readFileSync9, statSync as statSync5 } from "fs";
|
|
11237
|
-
import { resolve as resolve6, join as
|
|
11509
|
+
import { resolve as resolve6, join as join10, isAbsolute } from "path";
|
|
11238
11510
|
import { homedir as homedir9 } from "os";
|
|
11239
11511
|
import { readdirSync as readdirSync2 } from "fs";
|
|
11240
11512
|
function allowedOrigins() {
|
|
@@ -11260,7 +11532,7 @@ async function findLogDir() {
|
|
|
11260
11532
|
const files = readdirSync2(base).filter((f) => f.startsWith(".policy-cache-") && f.endsWith(".json"));
|
|
11261
11533
|
for (const f of files) {
|
|
11262
11534
|
try {
|
|
11263
|
-
const c2 = JSON.parse(readFileSync9(
|
|
11535
|
+
const c2 = JSON.parse(readFileSync9(join10(base, f), "utf-8"));
|
|
11264
11536
|
const p = c2?.security?.localLogs?.path;
|
|
11265
11537
|
if (typeof p === "string" && p.trim()) return { dir: resolveLocalLogDir(p), configured: p };
|
|
11266
11538
|
} catch {
|
|
@@ -11269,7 +11541,7 @@ async function findLogDir() {
|
|
|
11269
11541
|
} catch {
|
|
11270
11542
|
}
|
|
11271
11543
|
try {
|
|
11272
|
-
const cfgRaw = readFileSync9(
|
|
11544
|
+
const cfgRaw = readFileSync9(join10(base, "cloud-guard.json"), "utf-8");
|
|
11273
11545
|
const { apiKey, apiUrl } = JSON.parse(cfgRaw);
|
|
11274
11546
|
if (apiKey) {
|
|
11275
11547
|
const url = `${apiUrl || "https://api.solongate.com"}/api/v1/policies/active`;
|
|
@@ -11298,7 +11570,7 @@ function setCors(req, res) {
|
|
|
11298
11570
|
}
|
|
11299
11571
|
function fileInfo(dir) {
|
|
11300
11572
|
if (!dir) return { file: null, exists: false, size: 0, mtimeMs: 0 };
|
|
11301
|
-
const file =
|
|
11573
|
+
const file = join10(dir, LOG_FILENAME);
|
|
11302
11574
|
try {
|
|
11303
11575
|
const st = statSync5(file);
|
|
11304
11576
|
return { file, exists: true, size: st.size, mtimeMs: st.mtimeMs };
|
|
@@ -11411,7 +11683,7 @@ var init_logs_server = __esm({
|
|
|
11411
11683
|
|
|
11412
11684
|
// src/inject.ts
|
|
11413
11685
|
var inject_exports = {};
|
|
11414
|
-
import { readFileSync as readFileSync10, writeFileSync as
|
|
11686
|
+
import { readFileSync as readFileSync10, writeFileSync as writeFileSync5, existsSync as existsSync8, copyFileSync } from "fs";
|
|
11415
11687
|
import { resolve as resolve7 } from "path";
|
|
11416
11688
|
import { execSync } from "child_process";
|
|
11417
11689
|
function parseInjectArgs(argv) {
|
|
@@ -11469,7 +11741,7 @@ WHAT IT DOES
|
|
|
11469
11741
|
`);
|
|
11470
11742
|
}
|
|
11471
11743
|
function detectProject() {
|
|
11472
|
-
if (!
|
|
11744
|
+
if (!existsSync8(resolve7("package.json"))) return false;
|
|
11473
11745
|
try {
|
|
11474
11746
|
const pkg = JSON.parse(readFileSync10(resolve7("package.json"), "utf-8"));
|
|
11475
11747
|
const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
@@ -11485,13 +11757,13 @@ function findTsEntryFile() {
|
|
|
11485
11757
|
const binPath = typeof pkg.bin === "string" ? pkg.bin : Object.values(pkg.bin)[0];
|
|
11486
11758
|
if (typeof binPath === "string") {
|
|
11487
11759
|
const srcPath = binPath.replace(/^\.\/dist\//, "./src/").replace(/\.js$/, ".ts");
|
|
11488
|
-
if (
|
|
11489
|
-
if (
|
|
11760
|
+
if (existsSync8(resolve7(srcPath))) return resolve7(srcPath);
|
|
11761
|
+
if (existsSync8(resolve7(binPath))) return resolve7(binPath);
|
|
11490
11762
|
}
|
|
11491
11763
|
}
|
|
11492
11764
|
if (pkg.main) {
|
|
11493
11765
|
const srcPath = pkg.main.replace(/^\.\/dist\//, "./src/").replace(/\.js$/, ".ts");
|
|
11494
|
-
if (
|
|
11766
|
+
if (existsSync8(resolve7(srcPath))) return resolve7(srcPath);
|
|
11495
11767
|
}
|
|
11496
11768
|
} catch {
|
|
11497
11769
|
}
|
|
@@ -11505,7 +11777,7 @@ function findTsEntryFile() {
|
|
|
11505
11777
|
];
|
|
11506
11778
|
for (const c2 of candidates) {
|
|
11507
11779
|
const full = resolve7(c2);
|
|
11508
|
-
if (
|
|
11780
|
+
if (existsSync8(full)) {
|
|
11509
11781
|
try {
|
|
11510
11782
|
const content = readFileSync10(full, "utf-8");
|
|
11511
11783
|
if (content.includes("McpServer") || content.includes("McpServer")) {
|
|
@@ -11516,13 +11788,13 @@ function findTsEntryFile() {
|
|
|
11516
11788
|
}
|
|
11517
11789
|
}
|
|
11518
11790
|
for (const c2 of candidates) {
|
|
11519
|
-
if (
|
|
11791
|
+
if (existsSync8(resolve7(c2))) return resolve7(c2);
|
|
11520
11792
|
}
|
|
11521
11793
|
return null;
|
|
11522
11794
|
}
|
|
11523
11795
|
function detectPackageManager() {
|
|
11524
|
-
if (
|
|
11525
|
-
if (
|
|
11796
|
+
if (existsSync8(resolve7("pnpm-lock.yaml"))) return "pnpm";
|
|
11797
|
+
if (existsSync8(resolve7("yarn.lock"))) return "yarn";
|
|
11526
11798
|
return "npm";
|
|
11527
11799
|
}
|
|
11528
11800
|
function installSdk() {
|
|
@@ -11665,7 +11937,7 @@ async function main2() {
|
|
|
11665
11937
|
}
|
|
11666
11938
|
log3(" Language: TypeScript");
|
|
11667
11939
|
const entryFile = opts.file ? resolve7(opts.file) : findTsEntryFile();
|
|
11668
|
-
if (!entryFile || !
|
|
11940
|
+
if (!entryFile || !existsSync8(entryFile)) {
|
|
11669
11941
|
log3(` Could not find entry file.${opts.file ? ` File not found: ${opts.file}` : ""}`);
|
|
11670
11942
|
log3("");
|
|
11671
11943
|
log3(" Specify it manually: --file <path>");
|
|
@@ -11678,7 +11950,7 @@ async function main2() {
|
|
|
11678
11950
|
log3("");
|
|
11679
11951
|
const backupPath = entryFile + ".solongate-backup";
|
|
11680
11952
|
if (opts.restore) {
|
|
11681
|
-
if (!
|
|
11953
|
+
if (!existsSync8(backupPath)) {
|
|
11682
11954
|
log3(" No backup found. Nothing to restore.");
|
|
11683
11955
|
process.exit(1);
|
|
11684
11956
|
}
|
|
@@ -11714,12 +11986,12 @@ async function main2() {
|
|
|
11714
11986
|
log3(" To apply: npx @solongate/proxy inject");
|
|
11715
11987
|
process.exit(0);
|
|
11716
11988
|
}
|
|
11717
|
-
if (!
|
|
11989
|
+
if (!existsSync8(backupPath)) {
|
|
11718
11990
|
copyFileSync(entryFile, backupPath);
|
|
11719
11991
|
log3("");
|
|
11720
11992
|
log3(` Backup: ${backupPath}`);
|
|
11721
11993
|
}
|
|
11722
|
-
|
|
11994
|
+
writeFileSync5(entryFile, result.modified);
|
|
11723
11995
|
log3("");
|
|
11724
11996
|
log3(" \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510");
|
|
11725
11997
|
log3(" \u2502 SolonGate SDK injected successfully! \u2502");
|
|
@@ -11748,8 +12020,8 @@ var init_inject = __esm({
|
|
|
11748
12020
|
|
|
11749
12021
|
// src/create.ts
|
|
11750
12022
|
var create_exports = {};
|
|
11751
|
-
import { mkdirSync as mkdirSync5, writeFileSync as
|
|
11752
|
-
import { resolve as resolve8, join as
|
|
12023
|
+
import { mkdirSync as mkdirSync5, writeFileSync as writeFileSync6, existsSync as existsSync9 } from "fs";
|
|
12024
|
+
import { resolve as resolve8, join as join11 } from "path";
|
|
11753
12025
|
import { execSync as execSync2 } from "child_process";
|
|
11754
12026
|
function withSpinner(message, fn) {
|
|
11755
12027
|
const frames = ["\u28FE", "\u28FD", "\u28FB", "\u28BF", "\u287F", "\u28DF", "\u28EF", "\u28F7"];
|
|
@@ -11828,8 +12100,8 @@ EXAMPLES
|
|
|
11828
12100
|
`);
|
|
11829
12101
|
}
|
|
11830
12102
|
function createProject(dir, name, _policy) {
|
|
11831
|
-
|
|
11832
|
-
|
|
12103
|
+
writeFileSync6(
|
|
12104
|
+
join11(dir, "package.json"),
|
|
11833
12105
|
JSON.stringify(
|
|
11834
12106
|
{
|
|
11835
12107
|
name,
|
|
@@ -11858,8 +12130,8 @@ function createProject(dir, name, _policy) {
|
|
|
11858
12130
|
2
|
|
11859
12131
|
) + "\n"
|
|
11860
12132
|
);
|
|
11861
|
-
|
|
11862
|
-
|
|
12133
|
+
writeFileSync6(
|
|
12134
|
+
join11(dir, "tsconfig.json"),
|
|
11863
12135
|
JSON.stringify(
|
|
11864
12136
|
{
|
|
11865
12137
|
compilerOptions: {
|
|
@@ -11879,9 +12151,9 @@ function createProject(dir, name, _policy) {
|
|
|
11879
12151
|
2
|
|
11880
12152
|
) + "\n"
|
|
11881
12153
|
);
|
|
11882
|
-
mkdirSync5(
|
|
11883
|
-
|
|
11884
|
-
|
|
12154
|
+
mkdirSync5(join11(dir, "src"), { recursive: true });
|
|
12155
|
+
writeFileSync6(
|
|
12156
|
+
join11(dir, "src", "index.ts"),
|
|
11885
12157
|
`#!/usr/bin/env node
|
|
11886
12158
|
|
|
11887
12159
|
console.log = (...args: unknown[]) => {
|
|
@@ -11922,8 +12194,8 @@ console.log('');
|
|
|
11922
12194
|
console.log('Press Ctrl+C to stop.');
|
|
11923
12195
|
`
|
|
11924
12196
|
);
|
|
11925
|
-
|
|
11926
|
-
|
|
12197
|
+
writeFileSync6(
|
|
12198
|
+
join11(dir, ".mcp.json"),
|
|
11927
12199
|
JSON.stringify(
|
|
11928
12200
|
{
|
|
11929
12201
|
mcpServers: {
|
|
@@ -11940,13 +12212,13 @@ console.log('Press Ctrl+C to stop.');
|
|
|
11940
12212
|
2
|
|
11941
12213
|
) + "\n"
|
|
11942
12214
|
);
|
|
11943
|
-
|
|
11944
|
-
|
|
12215
|
+
writeFileSync6(
|
|
12216
|
+
join11(dir, ".env"),
|
|
11945
12217
|
`SOLONGATE_API_KEY=sg_live_YOUR_KEY_HERE
|
|
11946
12218
|
`
|
|
11947
12219
|
);
|
|
11948
|
-
|
|
11949
|
-
|
|
12220
|
+
writeFileSync6(
|
|
12221
|
+
join11(dir, ".gitignore"),
|
|
11950
12222
|
`node_modules/
|
|
11951
12223
|
dist/
|
|
11952
12224
|
*.solongate-backup
|
|
@@ -11960,7 +12232,7 @@ async function main3() {
|
|
|
11960
12232
|
const opts = parseCreateArgs(process.argv);
|
|
11961
12233
|
const dir = resolve8(opts.name);
|
|
11962
12234
|
printBanner("Create MCP Server");
|
|
11963
|
-
if (
|
|
12235
|
+
if (existsSync9(dir)) {
|
|
11964
12236
|
log3(` ${c.red}Error:${c.reset} Directory "${opts.name}" already exists.`);
|
|
11965
12237
|
process.exit(1);
|
|
11966
12238
|
}
|
|
@@ -12039,12 +12311,12 @@ var init_create = __esm({
|
|
|
12039
12311
|
|
|
12040
12312
|
// src/pull-push.ts
|
|
12041
12313
|
var pull_push_exports = {};
|
|
12042
|
-
import { readFileSync as readFileSync11, writeFileSync as
|
|
12314
|
+
import { readFileSync as readFileSync11, writeFileSync as writeFileSync7, existsSync as existsSync10 } from "fs";
|
|
12043
12315
|
import { resolve as resolve9 } from "path";
|
|
12044
12316
|
function loadEnv() {
|
|
12045
12317
|
if (process.env.SOLONGATE_API_KEY) return;
|
|
12046
12318
|
const envPath = resolve9(".env");
|
|
12047
|
-
if (!
|
|
12319
|
+
if (!existsSync10(envPath)) return;
|
|
12048
12320
|
try {
|
|
12049
12321
|
const content = readFileSync11(envPath, "utf-8");
|
|
12050
12322
|
for (const line of content.split("\n")) {
|
|
@@ -12234,7 +12506,7 @@ async function pull(apiKey, file, policyId) {
|
|
|
12234
12506
|
const policy = await fetchCloudPolicy(apiKey, API_URL, policyId);
|
|
12235
12507
|
const { id: _id, ...policyWithoutId } = policy;
|
|
12236
12508
|
const json = JSON.stringify(policyWithoutId, null, 2) + "\n";
|
|
12237
|
-
|
|
12509
|
+
writeFileSync7(file, json, "utf-8");
|
|
12238
12510
|
log5("");
|
|
12239
12511
|
log5(green2(" Saved to: ") + file);
|
|
12240
12512
|
log5(` ${dim2("Name:")} ${policy.name}`);
|
|
@@ -12246,7 +12518,7 @@ async function pull(apiKey, file, policyId) {
|
|
|
12246
12518
|
log5("");
|
|
12247
12519
|
}
|
|
12248
12520
|
async function push(apiKey, file, policyId) {
|
|
12249
|
-
if (!
|
|
12521
|
+
if (!existsSync10(file)) {
|
|
12250
12522
|
log5(red2(`ERROR: File not found: ${file}`));
|
|
12251
12523
|
process.exit(1);
|
|
12252
12524
|
}
|