@solongate/proxy 0.81.15 → 0.81.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +249 -118
- package/dist/tui/index.js +144 -21
- package/dist/tui/notify.d.ts +4 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -7089,6 +7089,145 @@ var init_api_client = __esm({
|
|
|
7089
7089
|
}
|
|
7090
7090
|
});
|
|
7091
7091
|
|
|
7092
|
+
// src/tui/notify.ts
|
|
7093
|
+
import { spawn, execFileSync as execFileSync2 } from "child_process";
|
|
7094
|
+
import { writeFileSync as writeFileSync3, existsSync as existsSync4 } from "fs";
|
|
7095
|
+
import { join as join6 } from "path";
|
|
7096
|
+
import { tmpdir as tmpdir2 } from "os";
|
|
7097
|
+
function captureFocusTarget() {
|
|
7098
|
+
try {
|
|
7099
|
+
if (process.platform === "linux") {
|
|
7100
|
+
focusToken = (process.env.WINDOWID || "").trim() || null;
|
|
7101
|
+
if (!focusToken) {
|
|
7102
|
+
try {
|
|
7103
|
+
focusToken = execFileSync2("xdotool", ["getactivewindow"], { encoding: "utf-8", timeout: 1500, stdio: ["ignore", "pipe", "ignore"] }).trim() || null;
|
|
7104
|
+
} catch {
|
|
7105
|
+
focusToken = null;
|
|
7106
|
+
}
|
|
7107
|
+
}
|
|
7108
|
+
} else if (process.platform === "win32") {
|
|
7109
|
+
const ps = `Add-Type -Name W -Namespace N -MemberDefinition '[DllImport("user32.dll")]public static extern System.IntPtr GetForegroundWindow();' | Out-Null; [N.W]::GetForegroundWindow().ToInt64()`;
|
|
7110
|
+
try {
|
|
7111
|
+
focusToken = execFileSync2("powershell", ["-NoProfile", "-NonInteractive", "-Command", ps], { encoding: "utf-8", timeout: 4e3, stdio: ["ignore", "pipe", "ignore"] }).trim() || null;
|
|
7112
|
+
} catch {
|
|
7113
|
+
focusToken = null;
|
|
7114
|
+
}
|
|
7115
|
+
}
|
|
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
|
+
if (!focusToken) return;
|
|
7144
|
+
try {
|
|
7145
|
+
const x = spawn("xdotool", ["windowactivate", focusToken], { stdio: "ignore" });
|
|
7146
|
+
x.on("error", () => {
|
|
7147
|
+
try {
|
|
7148
|
+
const hex = "0x" + Number(focusToken).toString(16);
|
|
7149
|
+
const w = spawn("wmctrl", ["-ia", hex], { stdio: "ignore" });
|
|
7150
|
+
w.on("error", () => {
|
|
7151
|
+
});
|
|
7152
|
+
w.unref();
|
|
7153
|
+
} catch {
|
|
7154
|
+
}
|
|
7155
|
+
});
|
|
7156
|
+
x.unref();
|
|
7157
|
+
} catch {
|
|
7158
|
+
}
|
|
7159
|
+
}
|
|
7160
|
+
function ensureWinScript() {
|
|
7161
|
+
if (winScriptPath && existsSync4(winScriptPath)) return winScriptPath;
|
|
7162
|
+
const p = join6(tmpdir2(), "solongate-toast.ps1");
|
|
7163
|
+
const script = [
|
|
7164
|
+
"param([string]$Title,[string]$Msg,[string]$Hwnd)",
|
|
7165
|
+
"Add-Type -AssemblyName System.Windows.Forms",
|
|
7166
|
+
"Add-Type -AssemblyName System.Drawing",
|
|
7167
|
+
`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);'`,
|
|
7168
|
+
"$ni=New-Object System.Windows.Forms.NotifyIcon",
|
|
7169
|
+
"$ni.Icon=[System.Drawing.SystemIcons]::Information",
|
|
7170
|
+
"$ni.Visible=$true",
|
|
7171
|
+
"$script:clicked=$false",
|
|
7172
|
+
"$ni.add_BalloonTipClicked({$script:clicked=$true})",
|
|
7173
|
+
"$ni.ShowBalloonTip(8000,$Title,$Msg,[System.Windows.Forms.ToolTipIcon]::Warning)",
|
|
7174
|
+
"$sw=[System.Diagnostics.Stopwatch]::StartNew()",
|
|
7175
|
+
"while($sw.Elapsed.TotalSeconds -lt 9 -and -not $script:clicked){[System.Windows.Forms.Application]::DoEvents();Start-Sleep -Milliseconds 100}",
|
|
7176
|
+
"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{}}",
|
|
7177
|
+
"$ni.Visible=$false;$ni.Dispose()"
|
|
7178
|
+
].join("\n");
|
|
7179
|
+
try {
|
|
7180
|
+
writeFileSync3(p, script);
|
|
7181
|
+
winScriptPath = p;
|
|
7182
|
+
return p;
|
|
7183
|
+
} catch {
|
|
7184
|
+
return null;
|
|
7185
|
+
}
|
|
7186
|
+
}
|
|
7187
|
+
function winNotify(title, msg) {
|
|
7188
|
+
const script = ensureWinScript();
|
|
7189
|
+
if (!script) return;
|
|
7190
|
+
try {
|
|
7191
|
+
const p = spawn("powershell", ["-NoProfile", "-NonInteractive", "-ExecutionPolicy", "Bypass", "-File", script, "-Title", title, "-Msg", msg, "-Hwnd", focusToken || ""], { stdio: "ignore", detached: true, windowsHide: true });
|
|
7192
|
+
p.on("error", () => {
|
|
7193
|
+
});
|
|
7194
|
+
p.unref();
|
|
7195
|
+
} catch {
|
|
7196
|
+
}
|
|
7197
|
+
}
|
|
7198
|
+
function macBundleId() {
|
|
7199
|
+
const prog = (process.env.TERM_PROGRAM || "").toLowerCase();
|
|
7200
|
+
if (prog.includes("iterm")) return "com.googlecode.iterm2";
|
|
7201
|
+
if (prog.includes("apple_terminal")) return "com.apple.Terminal";
|
|
7202
|
+
if (prog.includes("vscode")) return "com.microsoft.VSCode";
|
|
7203
|
+
return "com.apple.Terminal";
|
|
7204
|
+
}
|
|
7205
|
+
function macNotify(title, msg) {
|
|
7206
|
+
try {
|
|
7207
|
+
const p = spawn("terminal-notifier", ["-title", title, "-message", msg, "-activate", macBundleId(), "-sender", macBundleId()], { stdio: "ignore", detached: true });
|
|
7208
|
+
p.on("error", () => {
|
|
7209
|
+
try {
|
|
7210
|
+
const esc = (s) => s.replace(/"/g, '\\"');
|
|
7211
|
+
const a = spawn("osascript", ["-e", `display notification "${esc(msg)}" with title "${esc(title)}"`], { stdio: "ignore", detached: true });
|
|
7212
|
+
a.on("error", () => {
|
|
7213
|
+
});
|
|
7214
|
+
a.unref();
|
|
7215
|
+
} catch {
|
|
7216
|
+
}
|
|
7217
|
+
});
|
|
7218
|
+
p.unref();
|
|
7219
|
+
} catch {
|
|
7220
|
+
}
|
|
7221
|
+
}
|
|
7222
|
+
var focusToken, winScriptPath;
|
|
7223
|
+
var init_notify = __esm({
|
|
7224
|
+
"src/tui/notify.ts"() {
|
|
7225
|
+
"use strict";
|
|
7226
|
+
focusToken = null;
|
|
7227
|
+
winScriptPath = null;
|
|
7228
|
+
}
|
|
7229
|
+
});
|
|
7230
|
+
|
|
7092
7231
|
// src/tui/hooks.ts
|
|
7093
7232
|
import { useCallback, useEffect, useRef, useState } from "react";
|
|
7094
7233
|
function useLoader(fn, deps = []) {
|
|
@@ -7137,10 +7276,9 @@ var init_hooks = __esm({
|
|
|
7137
7276
|
// src/tui/panels/Live.tsx
|
|
7138
7277
|
import { Box as Box2, Text as Text2, useInput } from "ink";
|
|
7139
7278
|
import TextInput from "ink-text-input";
|
|
7140
|
-
import {
|
|
7141
|
-
import { closeSync, mkdirSync as mkdirSync3, openSync, readSync, statSync, writeFileSync as writeFileSync3 } from "fs";
|
|
7279
|
+
import { closeSync, mkdirSync as mkdirSync3, openSync, readSync, statSync, writeFileSync as writeFileSync4 } from "fs";
|
|
7142
7280
|
import { homedir as homedir4 } from "os";
|
|
7143
|
-
import { join as
|
|
7281
|
+
import { join as join7 } from "path";
|
|
7144
7282
|
import { useCallback as useCallback2, useEffect as useEffect2, useRef as useRef2, useState as useState2 } from "react";
|
|
7145
7283
|
import { Fragment as Fragment2, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
7146
7284
|
function tailLines(file, maxBytes = 131072) {
|
|
@@ -7271,7 +7409,7 @@ function LivePanel({ active: active2 }) {
|
|
|
7271
7409
|
const [sel, setSel] = useState2(0);
|
|
7272
7410
|
const [actionMsg, setActionMsg] = useState2(null);
|
|
7273
7411
|
const notifiedRef = useRef2(/* @__PURE__ */ new Set());
|
|
7274
|
-
const
|
|
7412
|
+
const openedAtRef = useRef2(Date.now());
|
|
7275
7413
|
const activePolicyRef = useRef2(null);
|
|
7276
7414
|
const [mode, setMode] = useState2("stream");
|
|
7277
7415
|
const [pickIdx, setPickIdx] = useState2(0);
|
|
@@ -7455,13 +7593,7 @@ function LivePanel({ active: active2 }) {
|
|
|
7455
7593
|
process.stdout.write("\x07");
|
|
7456
7594
|
} catch {
|
|
7457
7595
|
}
|
|
7458
|
-
|
|
7459
|
-
const child = spawn("notify-send", ["-a", "SolonGate", title, msg], { stdio: "ignore", detached: true });
|
|
7460
|
-
child.on("error", () => {
|
|
7461
|
-
});
|
|
7462
|
-
child.unref();
|
|
7463
|
-
} catch {
|
|
7464
|
-
}
|
|
7596
|
+
desktopNotify(title, msg);
|
|
7465
7597
|
},
|
|
7466
7598
|
[pushLog]
|
|
7467
7599
|
);
|
|
@@ -7479,14 +7611,10 @@ function LivePanel({ active: active2 }) {
|
|
|
7479
7611
|
useEffect2(() => {
|
|
7480
7612
|
if (!active2) return;
|
|
7481
7613
|
const notable = mergedRef.current.filter((e) => e.decision !== "ALLOW" || e.dlp || e.burst);
|
|
7482
|
-
if (!notifyReady.current) {
|
|
7483
|
-
for (const e of notable) notifiedRef.current.add(e.id);
|
|
7484
|
-
notifyReady.current = true;
|
|
7485
|
-
return;
|
|
7486
|
-
}
|
|
7487
7614
|
for (const e of notable) {
|
|
7488
7615
|
if (notifiedRef.current.has(e.id)) continue;
|
|
7489
7616
|
notifiedRef.current.add(e.id);
|
|
7617
|
+
if (!(e.at > openedAtRef.current)) continue;
|
|
7490
7618
|
const who = e.agent ? ` \xB7 ${truncate2(e.agent, 20)}` : "";
|
|
7491
7619
|
if (e.dlp) fireAlert("sec:" + e.id, "DLP hit", `SECRET in ${e.tool}${who}: ${truncate2(e.detail, 60)}`, "bad");
|
|
7492
7620
|
else if (e.decision !== "ALLOW") fireAlert("sec:" + e.id, "Call denied", `DENY ${e.tool}${who}: ${truncate2(e.rule ?? e.detail, 60)}`, "bad");
|
|
@@ -7679,10 +7807,10 @@ function LivePanel({ active: active2 }) {
|
|
|
7679
7807
|
else if (input === "x") toggleSignal("dlp");
|
|
7680
7808
|
else if (input === "r") toggleSignal("ratelimit");
|
|
7681
7809
|
else if (input === "e") {
|
|
7682
|
-
const file =
|
|
7810
|
+
const file = join7(homedir4(), ".solongate", "live-export.jsonl");
|
|
7683
7811
|
try {
|
|
7684
|
-
mkdirSync3(
|
|
7685
|
-
|
|
7812
|
+
mkdirSync3(join7(homedir4(), ".solongate"), { recursive: true });
|
|
7813
|
+
writeFileSync4(file, visibleDesc.map((x) => JSON.stringify(x)).join("\n") + "\n");
|
|
7686
7814
|
setActionMsg({ text: `\u2713 exported ${visibleDesc.length} lines \u2192 ${file}`, level: "ok", until: Date.now() + 6e3 });
|
|
7687
7815
|
} catch (err2) {
|
|
7688
7816
|
setActionMsg({ text: "\u2717 export failed: " + (err2 instanceof Error ? err2.message : String(err2)), level: "bad", until: Date.now() + 6e3 });
|
|
@@ -7942,14 +8070,15 @@ var init_Live = __esm({
|
|
|
7942
8070
|
"use strict";
|
|
7943
8071
|
init_api_client();
|
|
7944
8072
|
init_config2();
|
|
8073
|
+
init_notify();
|
|
7945
8074
|
init_hooks();
|
|
7946
8075
|
init_theme();
|
|
7947
8076
|
CONFIG = loadConfig();
|
|
7948
8077
|
SPIN = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
7949
8078
|
BG = "#12234f";
|
|
7950
8079
|
DIM_FLOOR = "#233457";
|
|
7951
|
-
LOCAL_LOG =
|
|
7952
|
-
RING =
|
|
8080
|
+
LOCAL_LOG = join7(homedir4(), ".solongate", "local-logs", "solongate-audit.jsonl");
|
|
8081
|
+
RING = join7(process.cwd(), ".solongate", ".eval-ring.jsonl");
|
|
7953
8082
|
hhmmss = (ts) => {
|
|
7954
8083
|
const d = new Date(ts);
|
|
7955
8084
|
return Number.isNaN(d.getTime()) ? "--:--:--" : d.toTimeString().slice(0, 8);
|
|
@@ -9165,6 +9294,7 @@ async function launchTui() {
|
|
|
9165
9294
|
process.stderr.write("Not logged in. Run `solongate login` first.\n");
|
|
9166
9295
|
return;
|
|
9167
9296
|
}
|
|
9297
|
+
captureFocusTarget();
|
|
9168
9298
|
process.stdout.write("\x1B[?1049h\x1B[H");
|
|
9169
9299
|
try {
|
|
9170
9300
|
const { waitUntilExit } = render(/* @__PURE__ */ jsx10(App, {}));
|
|
@@ -9178,6 +9308,7 @@ var init_tui = __esm({
|
|
|
9178
9308
|
"use strict";
|
|
9179
9309
|
init_App();
|
|
9180
9310
|
init_client();
|
|
9311
|
+
init_notify();
|
|
9181
9312
|
}
|
|
9182
9313
|
});
|
|
9183
9314
|
|
|
@@ -9869,9 +10000,9 @@ var init_agents2 = __esm({
|
|
|
9869
10000
|
});
|
|
9870
10001
|
|
|
9871
10002
|
// src/commands/doctor.ts
|
|
9872
|
-
import { existsSync as
|
|
10003
|
+
import { existsSync as existsSync5, statSync as statSync2 } from "fs";
|
|
9873
10004
|
import { homedir as homedir5 } from "os";
|
|
9874
|
-
import { join as
|
|
10005
|
+
import { join as join8 } from "path";
|
|
9875
10006
|
async function run6(argv) {
|
|
9876
10007
|
const { flags } = parse(argv);
|
|
9877
10008
|
const json = flagBool(flags, "json");
|
|
@@ -9901,7 +10032,7 @@ async function run6(argv) {
|
|
|
9901
10032
|
} catch {
|
|
9902
10033
|
}
|
|
9903
10034
|
}
|
|
9904
|
-
if (
|
|
10035
|
+
if (existsSync5(LOCAL_LOG2)) {
|
|
9905
10036
|
const st = statSync2(LOCAL_LOG2);
|
|
9906
10037
|
const ageMin = (Date.now() - st.mtimeMs) / 6e4;
|
|
9907
10038
|
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"}` });
|
|
@@ -9931,14 +10062,14 @@ var init_doctor = __esm({
|
|
|
9931
10062
|
init_api_client();
|
|
9932
10063
|
init_format();
|
|
9933
10064
|
init_args();
|
|
9934
|
-
LOCAL_LOG2 =
|
|
10065
|
+
LOCAL_LOG2 = join8(homedir5(), ".solongate", "local-logs", "solongate-audit.jsonl");
|
|
9935
10066
|
}
|
|
9936
10067
|
});
|
|
9937
10068
|
|
|
9938
10069
|
// src/commands/watch.ts
|
|
9939
|
-
import { closeSync as closeSync2, existsSync as
|
|
10070
|
+
import { closeSync as closeSync2, existsSync as existsSync6, openSync as openSync2, readSync as readSync2, statSync as statSync3 } from "fs";
|
|
9940
10071
|
import { homedir as homedir6 } from "os";
|
|
9941
|
-
import { join as
|
|
10072
|
+
import { join as join9 } from "path";
|
|
9942
10073
|
function tailLocal(file, maxBytes = 131072) {
|
|
9943
10074
|
try {
|
|
9944
10075
|
const size = statSync3(file).size;
|
|
@@ -9982,7 +10113,7 @@ async function run7(argv) {
|
|
|
9982
10113
|
for (const r of rows) if (keep(r)) print(r, json);
|
|
9983
10114
|
};
|
|
9984
10115
|
const pollLocal = () => {
|
|
9985
|
-
if (cloudOnly || !
|
|
10116
|
+
if (cloudOnly || !existsSync6(LOCAL_LOG3)) return;
|
|
9986
10117
|
const rows = [];
|
|
9987
10118
|
for (const line of tailLocal(LOCAL_LOG3)) {
|
|
9988
10119
|
try {
|
|
@@ -10045,7 +10176,7 @@ var init_watch = __esm({
|
|
|
10045
10176
|
init_cli_utils();
|
|
10046
10177
|
init_args();
|
|
10047
10178
|
init_format();
|
|
10048
|
-
LOCAL_LOG3 =
|
|
10179
|
+
LOCAL_LOG3 = join9(homedir6(), ".solongate", "local-logs", "solongate-audit.jsonl");
|
|
10049
10180
|
trunc = (s, n) => s.length <= n ? s : s.slice(0, n - 1) + "\u2026";
|
|
10050
10181
|
time = (ms) => new Date(ms).toTimeString().slice(0, 8);
|
|
10051
10182
|
}
|
|
@@ -10347,32 +10478,32 @@ __export(global_install_exports, {
|
|
|
10347
10478
|
runGlobalRestore: () => runGlobalRestore,
|
|
10348
10479
|
unlockProtected: () => unlockProtected
|
|
10349
10480
|
});
|
|
10350
|
-
import { readFileSync as readFileSync7, writeFileSync as
|
|
10351
|
-
import { resolve as resolve4, join as
|
|
10481
|
+
import { readFileSync as readFileSync7, writeFileSync as writeFileSync5, existsSync as existsSync7, mkdirSync as mkdirSync4 } from "fs";
|
|
10482
|
+
import { resolve as resolve4, join as join10, dirname } from "path";
|
|
10352
10483
|
import { homedir as homedir7 } from "os";
|
|
10353
10484
|
import { fileURLToPath } from "url";
|
|
10354
10485
|
import { createInterface } from "readline";
|
|
10355
|
-
import { execFileSync as
|
|
10486
|
+
import { execFileSync as execFileSync3 } from "child_process";
|
|
10356
10487
|
function lockFile(file) {
|
|
10357
|
-
if (!
|
|
10488
|
+
if (!existsSync7(file)) return;
|
|
10358
10489
|
try {
|
|
10359
10490
|
if (process.platform === "win32") {
|
|
10360
10491
|
try {
|
|
10361
|
-
|
|
10492
|
+
execFileSync3("icacls", [file, "/deny", "*S-1-1-0:(WD,AD,DC,DE)"], { stdio: "ignore" });
|
|
10362
10493
|
} catch {
|
|
10363
10494
|
}
|
|
10364
10495
|
try {
|
|
10365
|
-
|
|
10496
|
+
execFileSync3("attrib", ["+R", file], { stdio: "ignore" });
|
|
10366
10497
|
} catch {
|
|
10367
10498
|
}
|
|
10368
10499
|
} else if (process.platform === "darwin") {
|
|
10369
10500
|
try {
|
|
10370
|
-
|
|
10501
|
+
execFileSync3("chflags", ["uchg", file], { stdio: "ignore" });
|
|
10371
10502
|
} catch {
|
|
10372
10503
|
}
|
|
10373
10504
|
} else {
|
|
10374
10505
|
try {
|
|
10375
|
-
|
|
10506
|
+
execFileSync3("chattr", ["+i", file], { stdio: "ignore" });
|
|
10376
10507
|
} catch {
|
|
10377
10508
|
}
|
|
10378
10509
|
}
|
|
@@ -10380,29 +10511,29 @@ function lockFile(file) {
|
|
|
10380
10511
|
}
|
|
10381
10512
|
}
|
|
10382
10513
|
function unlockFile(file) {
|
|
10383
|
-
if (!
|
|
10514
|
+
if (!existsSync7(file)) return;
|
|
10384
10515
|
try {
|
|
10385
10516
|
if (process.platform === "win32") {
|
|
10386
10517
|
try {
|
|
10387
|
-
|
|
10518
|
+
execFileSync3("icacls", [file, "/remove:d", "*S-1-1-0"], { stdio: "ignore" });
|
|
10388
10519
|
} catch {
|
|
10389
10520
|
}
|
|
10390
10521
|
try {
|
|
10391
|
-
|
|
10522
|
+
execFileSync3("icacls", [file, "/reset"], { stdio: "ignore" });
|
|
10392
10523
|
} catch {
|
|
10393
10524
|
}
|
|
10394
10525
|
try {
|
|
10395
|
-
|
|
10526
|
+
execFileSync3("attrib", ["-R", file], { stdio: "ignore" });
|
|
10396
10527
|
} catch {
|
|
10397
10528
|
}
|
|
10398
10529
|
} else if (process.platform === "darwin") {
|
|
10399
10530
|
try {
|
|
10400
|
-
|
|
10531
|
+
execFileSync3("chflags", ["nouchg", file], { stdio: "ignore" });
|
|
10401
10532
|
} catch {
|
|
10402
10533
|
}
|
|
10403
10534
|
} else {
|
|
10404
10535
|
try {
|
|
10405
|
-
|
|
10536
|
+
execFileSync3("chattr", ["-i", file], { stdio: "ignore" });
|
|
10406
10537
|
} catch {
|
|
10407
10538
|
}
|
|
10408
10539
|
}
|
|
@@ -10412,10 +10543,10 @@ function unlockFile(file) {
|
|
|
10412
10543
|
function protectedTargets() {
|
|
10413
10544
|
const p = globalPaths();
|
|
10414
10545
|
return [
|
|
10415
|
-
|
|
10416
|
-
|
|
10417
|
-
|
|
10418
|
-
|
|
10546
|
+
join10(p.hooksDir, "guard.mjs"),
|
|
10547
|
+
join10(p.hooksDir, "audit.mjs"),
|
|
10548
|
+
join10(p.hooksDir, "stop.mjs"),
|
|
10549
|
+
join10(p.hooksDir, "shield.mjs"),
|
|
10419
10550
|
p.configPath,
|
|
10420
10551
|
p.settingsPath
|
|
10421
10552
|
];
|
|
@@ -10428,25 +10559,25 @@ function unlockProtected() {
|
|
|
10428
10559
|
}
|
|
10429
10560
|
function globalPaths() {
|
|
10430
10561
|
const home = homedir7();
|
|
10431
|
-
const sgDir =
|
|
10432
|
-
const hooksDir =
|
|
10433
|
-
const claudeDir =
|
|
10562
|
+
const sgDir = join10(home, ".solongate");
|
|
10563
|
+
const hooksDir = join10(sgDir, "hooks");
|
|
10564
|
+
const claudeDir = join10(home, ".claude");
|
|
10434
10565
|
return {
|
|
10435
10566
|
home,
|
|
10436
10567
|
sgDir,
|
|
10437
10568
|
hooksDir,
|
|
10438
10569
|
claudeDir,
|
|
10439
|
-
settingsPath:
|
|
10440
|
-
backupPath:
|
|
10441
|
-
configPath:
|
|
10570
|
+
settingsPath: join10(claudeDir, "settings.json"),
|
|
10571
|
+
backupPath: join10(claudeDir, "settings.solongate.bak"),
|
|
10572
|
+
configPath: join10(sgDir, "cloud-guard.json")
|
|
10442
10573
|
};
|
|
10443
10574
|
}
|
|
10444
10575
|
function readHook(filename) {
|
|
10445
|
-
return readFileSync7(
|
|
10576
|
+
return readFileSync7(join10(HOOKS_DIR, filename), "utf-8");
|
|
10446
10577
|
}
|
|
10447
10578
|
function readGuard() {
|
|
10448
|
-
const bundled =
|
|
10449
|
-
return
|
|
10579
|
+
const bundled = join10(HOOKS_DIR, "guard.bundled.mjs");
|
|
10580
|
+
return existsSync7(bundled) ? readFileSync7(bundled, "utf-8") : readHook("guard.mjs");
|
|
10450
10581
|
}
|
|
10451
10582
|
function ask(question) {
|
|
10452
10583
|
const rl = createInterface({ input: process.stdin, output: process.stderr });
|
|
@@ -10459,14 +10590,14 @@ function runGlobalRestore() {
|
|
|
10459
10590
|
const p = globalPaths();
|
|
10460
10591
|
unlockProtected();
|
|
10461
10592
|
removeClaudeShim();
|
|
10462
|
-
if (
|
|
10463
|
-
|
|
10593
|
+
if (existsSync7(p.backupPath)) {
|
|
10594
|
+
writeFileSync5(p.settingsPath, readFileSync7(p.backupPath, "utf-8"));
|
|
10464
10595
|
console.log(` Restored ${p.settingsPath} from backup.`);
|
|
10465
|
-
} else if (
|
|
10596
|
+
} else if (existsSync7(p.settingsPath)) {
|
|
10466
10597
|
try {
|
|
10467
10598
|
const s = JSON.parse(readFileSync7(p.settingsPath, "utf-8"));
|
|
10468
10599
|
delete s.hooks;
|
|
10469
|
-
|
|
10600
|
+
writeFileSync5(p.settingsPath, JSON.stringify(s, null, 2) + "\n");
|
|
10470
10601
|
console.log(` Removed SolonGate hooks from ${p.settingsPath}.`);
|
|
10471
10602
|
} catch {
|
|
10472
10603
|
}
|
|
@@ -10481,7 +10612,7 @@ function escapeRe(s) {
|
|
|
10481
10612
|
function resolveRealClaude() {
|
|
10482
10613
|
try {
|
|
10483
10614
|
const finder = process.platform === "win32" ? "where" : "which";
|
|
10484
|
-
const out2 =
|
|
10615
|
+
const out2 = execFileSync3(finder, ["claude"], { encoding: "utf-8" }).split(/\r?\n/).map((s) => s.trim()).filter(Boolean);
|
|
10485
10616
|
if (process.platform === "win32") {
|
|
10486
10617
|
const low = (s) => s.toLowerCase();
|
|
10487
10618
|
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;
|
|
@@ -10494,24 +10625,24 @@ function resolveRealClaude() {
|
|
|
10494
10625
|
function shimTargets() {
|
|
10495
10626
|
if (process.platform === "win32") {
|
|
10496
10627
|
try {
|
|
10497
|
-
const prof =
|
|
10628
|
+
const prof = execFileSync3("powershell", ["-NoProfile", "-Command", "$PROFILE.CurrentUserAllHosts"], { encoding: "utf-8" }).trim();
|
|
10498
10629
|
return prof ? [prof] : [];
|
|
10499
10630
|
} catch {
|
|
10500
10631
|
return [];
|
|
10501
10632
|
}
|
|
10502
10633
|
}
|
|
10503
|
-
return [".bashrc", ".zshrc", ".profile"].map((f) =>
|
|
10634
|
+
return [".bashrc", ".zshrc", ".profile"].map((f) => join10(homedir7(), f)).filter((f) => existsSync7(f));
|
|
10504
10635
|
}
|
|
10505
10636
|
function writeShimBlock(file, block2) {
|
|
10506
10637
|
const re = new RegExp(escapeRe(SHIM_BEGIN) + "[\\s\\S]*?" + escapeRe(SHIM_END) + "\\r?\\n?", "g");
|
|
10507
|
-
let content =
|
|
10638
|
+
let content = existsSync7(file) ? readFileSync7(file, "utf-8") : "";
|
|
10508
10639
|
content = content.replace(re, "");
|
|
10509
10640
|
if (block2) {
|
|
10510
10641
|
if (content.length && !content.endsWith("\n")) content += "\n";
|
|
10511
10642
|
content += block2 + "\n";
|
|
10512
10643
|
}
|
|
10513
10644
|
mkdirSync4(dirname(file), { recursive: true });
|
|
10514
|
-
|
|
10645
|
+
writeFileSync5(file, content);
|
|
10515
10646
|
}
|
|
10516
10647
|
function installClaudeShim(shieldPath) {
|
|
10517
10648
|
const real = resolveRealClaude();
|
|
@@ -10565,19 +10696,19 @@ async function runGlobalInstall(opts = {}) {
|
|
|
10565
10696
|
mkdirSync4(p.hooksDir, { recursive: true });
|
|
10566
10697
|
mkdirSync4(p.claudeDir, { recursive: true });
|
|
10567
10698
|
unlockProtected();
|
|
10568
|
-
|
|
10569
|
-
|
|
10570
|
-
|
|
10571
|
-
|
|
10699
|
+
writeFileSync5(join10(p.hooksDir, "guard.mjs"), readGuard());
|
|
10700
|
+
writeFileSync5(join10(p.hooksDir, "audit.mjs"), readHook("audit.mjs"));
|
|
10701
|
+
writeFileSync5(join10(p.hooksDir, "stop.mjs"), readHook("stop.mjs"));
|
|
10702
|
+
writeFileSync5(join10(p.hooksDir, "shield.mjs"), readHook("shield.mjs"));
|
|
10572
10703
|
console.log(` Installed hooks \u2192 ${p.hooksDir}`);
|
|
10573
|
-
installClaudeShim(
|
|
10574
|
-
|
|
10704
|
+
installClaudeShim(join10(p.hooksDir, "shield.mjs"));
|
|
10705
|
+
writeFileSync5(p.configPath, JSON.stringify({ apiKey, apiUrl }, null, 2) + "\n");
|
|
10575
10706
|
console.log(` Wrote ${p.configPath}`);
|
|
10576
10707
|
let existing = {};
|
|
10577
|
-
if (
|
|
10708
|
+
if (existsSync7(p.settingsPath)) {
|
|
10578
10709
|
const raw = readFileSync7(p.settingsPath, "utf-8");
|
|
10579
|
-
if (!
|
|
10580
|
-
|
|
10710
|
+
if (!existsSync7(p.backupPath)) {
|
|
10711
|
+
writeFileSync5(p.backupPath, raw);
|
|
10581
10712
|
console.log(` Backed up existing settings \u2192 ${p.backupPath}`);
|
|
10582
10713
|
}
|
|
10583
10714
|
try {
|
|
@@ -10586,9 +10717,9 @@ async function runGlobalInstall(opts = {}) {
|
|
|
10586
10717
|
existing = {};
|
|
10587
10718
|
}
|
|
10588
10719
|
}
|
|
10589
|
-
const guardAbs =
|
|
10590
|
-
const auditAbs =
|
|
10591
|
-
const stopAbs =
|
|
10720
|
+
const guardAbs = join10(p.hooksDir, "guard.mjs").replace(/\\/g, "/");
|
|
10721
|
+
const auditAbs = join10(p.hooksDir, "audit.mjs").replace(/\\/g, "/");
|
|
10722
|
+
const stopAbs = join10(p.hooksDir, "stop.mjs").replace(/\\/g, "/");
|
|
10592
10723
|
const nodeBin = process.execPath.replace(/\\/g, "/");
|
|
10593
10724
|
const call = process.platform === "win32" ? "& " : "";
|
|
10594
10725
|
const hookCmd = (script) => `${call}"${nodeBin}" "${script}" claude-code "Claude Code"`;
|
|
@@ -10600,7 +10731,7 @@ async function runGlobalInstall(opts = {}) {
|
|
|
10600
10731
|
Stop: [{ matcher: "", hooks: [{ type: "command", command: hookCmd(stopAbs) }] }]
|
|
10601
10732
|
}
|
|
10602
10733
|
};
|
|
10603
|
-
|
|
10734
|
+
writeFileSync5(p.settingsPath, JSON.stringify(merged, null, 2) + "\n");
|
|
10604
10735
|
console.log(` Registered global hooks \u2192 ${p.settingsPath}`);
|
|
10605
10736
|
if (process.env["SOLONGATE_OS_LOCK"] === "1") {
|
|
10606
10737
|
lockProtected();
|
|
@@ -10780,7 +10911,7 @@ import { createServer, request as httpRequest } from "http";
|
|
|
10780
10911
|
import { request as httpsRequest } from "https";
|
|
10781
10912
|
import { spawn as spawn3 } from "child_process";
|
|
10782
10913
|
import { URL as URL2 } from "url";
|
|
10783
|
-
import { readFileSync as readFileSync8, existsSync as
|
|
10914
|
+
import { readFileSync as readFileSync8, existsSync as existsSync8, readdirSync, statSync as statSync4 } from "fs";
|
|
10784
10915
|
import { resolve as resolve5 } from "path";
|
|
10785
10916
|
import { homedir as homedir8 } from "os";
|
|
10786
10917
|
function findCacheFile() {
|
|
@@ -10788,7 +10919,7 @@ function findCacheFile() {
|
|
|
10788
10919
|
const envSel = process.env.SOLONGATE_AGENT_ID;
|
|
10789
10920
|
if (envSel) {
|
|
10790
10921
|
const f = resolve5(dir, ".policy-cache-" + envSel.replace(/[^a-zA-Z0-9_-]/g, "_") + ".json");
|
|
10791
|
-
if (
|
|
10922
|
+
if (existsSync8(f)) return f;
|
|
10792
10923
|
}
|
|
10793
10924
|
let best = null, bestTs = -1;
|
|
10794
10925
|
try {
|
|
@@ -10809,7 +10940,7 @@ function findCacheFile() {
|
|
|
10809
10940
|
function loadCfg() {
|
|
10810
10941
|
try {
|
|
10811
10942
|
const f = findCacheFile();
|
|
10812
|
-
if (f &&
|
|
10943
|
+
if (f && existsSync8(f)) {
|
|
10813
10944
|
const c2 = JSON.parse(readFileSync8(f, "utf-8"));
|
|
10814
10945
|
const d = c2?.security?.dlpRedact;
|
|
10815
10946
|
const g = c2?.security?.ghost;
|
|
@@ -11099,7 +11230,7 @@ __export(logs_server_exports, {
|
|
|
11099
11230
|
});
|
|
11100
11231
|
import { createServer as createServer2 } from "http";
|
|
11101
11232
|
import { readFileSync as readFileSync9, statSync as statSync5 } from "fs";
|
|
11102
|
-
import { resolve as resolve6, join as
|
|
11233
|
+
import { resolve as resolve6, join as join11, isAbsolute } from "path";
|
|
11103
11234
|
import { homedir as homedir9 } from "os";
|
|
11104
11235
|
import { readdirSync as readdirSync2 } from "fs";
|
|
11105
11236
|
function allowedOrigins() {
|
|
@@ -11125,7 +11256,7 @@ async function findLogDir() {
|
|
|
11125
11256
|
const files = readdirSync2(base).filter((f) => f.startsWith(".policy-cache-") && f.endsWith(".json"));
|
|
11126
11257
|
for (const f of files) {
|
|
11127
11258
|
try {
|
|
11128
|
-
const c2 = JSON.parse(readFileSync9(
|
|
11259
|
+
const c2 = JSON.parse(readFileSync9(join11(base, f), "utf-8"));
|
|
11129
11260
|
const p = c2?.security?.localLogs?.path;
|
|
11130
11261
|
if (typeof p === "string" && p.trim()) return { dir: resolveLocalLogDir(p), configured: p };
|
|
11131
11262
|
} catch {
|
|
@@ -11134,7 +11265,7 @@ async function findLogDir() {
|
|
|
11134
11265
|
} catch {
|
|
11135
11266
|
}
|
|
11136
11267
|
try {
|
|
11137
|
-
const cfgRaw = readFileSync9(
|
|
11268
|
+
const cfgRaw = readFileSync9(join11(base, "cloud-guard.json"), "utf-8");
|
|
11138
11269
|
const { apiKey, apiUrl } = JSON.parse(cfgRaw);
|
|
11139
11270
|
if (apiKey) {
|
|
11140
11271
|
const url = `${apiUrl || "https://api.solongate.com"}/api/v1/policies/active`;
|
|
@@ -11163,7 +11294,7 @@ function setCors(req, res) {
|
|
|
11163
11294
|
}
|
|
11164
11295
|
function fileInfo(dir) {
|
|
11165
11296
|
if (!dir) return { file: null, exists: false, size: 0, mtimeMs: 0 };
|
|
11166
|
-
const file =
|
|
11297
|
+
const file = join11(dir, LOG_FILENAME);
|
|
11167
11298
|
try {
|
|
11168
11299
|
const st = statSync5(file);
|
|
11169
11300
|
return { file, exists: true, size: st.size, mtimeMs: st.mtimeMs };
|
|
@@ -11276,7 +11407,7 @@ var init_logs_server = __esm({
|
|
|
11276
11407
|
|
|
11277
11408
|
// src/inject.ts
|
|
11278
11409
|
var inject_exports = {};
|
|
11279
|
-
import { readFileSync as readFileSync10, writeFileSync as
|
|
11410
|
+
import { readFileSync as readFileSync10, writeFileSync as writeFileSync6, existsSync as existsSync9, copyFileSync } from "fs";
|
|
11280
11411
|
import { resolve as resolve7 } from "path";
|
|
11281
11412
|
import { execSync } from "child_process";
|
|
11282
11413
|
function parseInjectArgs(argv) {
|
|
@@ -11334,7 +11465,7 @@ WHAT IT DOES
|
|
|
11334
11465
|
`);
|
|
11335
11466
|
}
|
|
11336
11467
|
function detectProject() {
|
|
11337
|
-
if (!
|
|
11468
|
+
if (!existsSync9(resolve7("package.json"))) return false;
|
|
11338
11469
|
try {
|
|
11339
11470
|
const pkg = JSON.parse(readFileSync10(resolve7("package.json"), "utf-8"));
|
|
11340
11471
|
const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
@@ -11350,13 +11481,13 @@ function findTsEntryFile() {
|
|
|
11350
11481
|
const binPath = typeof pkg.bin === "string" ? pkg.bin : Object.values(pkg.bin)[0];
|
|
11351
11482
|
if (typeof binPath === "string") {
|
|
11352
11483
|
const srcPath = binPath.replace(/^\.\/dist\//, "./src/").replace(/\.js$/, ".ts");
|
|
11353
|
-
if (
|
|
11354
|
-
if (
|
|
11484
|
+
if (existsSync9(resolve7(srcPath))) return resolve7(srcPath);
|
|
11485
|
+
if (existsSync9(resolve7(binPath))) return resolve7(binPath);
|
|
11355
11486
|
}
|
|
11356
11487
|
}
|
|
11357
11488
|
if (pkg.main) {
|
|
11358
11489
|
const srcPath = pkg.main.replace(/^\.\/dist\//, "./src/").replace(/\.js$/, ".ts");
|
|
11359
|
-
if (
|
|
11490
|
+
if (existsSync9(resolve7(srcPath))) return resolve7(srcPath);
|
|
11360
11491
|
}
|
|
11361
11492
|
} catch {
|
|
11362
11493
|
}
|
|
@@ -11370,7 +11501,7 @@ function findTsEntryFile() {
|
|
|
11370
11501
|
];
|
|
11371
11502
|
for (const c2 of candidates) {
|
|
11372
11503
|
const full = resolve7(c2);
|
|
11373
|
-
if (
|
|
11504
|
+
if (existsSync9(full)) {
|
|
11374
11505
|
try {
|
|
11375
11506
|
const content = readFileSync10(full, "utf-8");
|
|
11376
11507
|
if (content.includes("McpServer") || content.includes("McpServer")) {
|
|
@@ -11381,13 +11512,13 @@ function findTsEntryFile() {
|
|
|
11381
11512
|
}
|
|
11382
11513
|
}
|
|
11383
11514
|
for (const c2 of candidates) {
|
|
11384
|
-
if (
|
|
11515
|
+
if (existsSync9(resolve7(c2))) return resolve7(c2);
|
|
11385
11516
|
}
|
|
11386
11517
|
return null;
|
|
11387
11518
|
}
|
|
11388
11519
|
function detectPackageManager() {
|
|
11389
|
-
if (
|
|
11390
|
-
if (
|
|
11520
|
+
if (existsSync9(resolve7("pnpm-lock.yaml"))) return "pnpm";
|
|
11521
|
+
if (existsSync9(resolve7("yarn.lock"))) return "yarn";
|
|
11391
11522
|
return "npm";
|
|
11392
11523
|
}
|
|
11393
11524
|
function installSdk() {
|
|
@@ -11530,7 +11661,7 @@ async function main2() {
|
|
|
11530
11661
|
}
|
|
11531
11662
|
log3(" Language: TypeScript");
|
|
11532
11663
|
const entryFile = opts.file ? resolve7(opts.file) : findTsEntryFile();
|
|
11533
|
-
if (!entryFile || !
|
|
11664
|
+
if (!entryFile || !existsSync9(entryFile)) {
|
|
11534
11665
|
log3(` Could not find entry file.${opts.file ? ` File not found: ${opts.file}` : ""}`);
|
|
11535
11666
|
log3("");
|
|
11536
11667
|
log3(" Specify it manually: --file <path>");
|
|
@@ -11543,7 +11674,7 @@ async function main2() {
|
|
|
11543
11674
|
log3("");
|
|
11544
11675
|
const backupPath = entryFile + ".solongate-backup";
|
|
11545
11676
|
if (opts.restore) {
|
|
11546
|
-
if (!
|
|
11677
|
+
if (!existsSync9(backupPath)) {
|
|
11547
11678
|
log3(" No backup found. Nothing to restore.");
|
|
11548
11679
|
process.exit(1);
|
|
11549
11680
|
}
|
|
@@ -11579,12 +11710,12 @@ async function main2() {
|
|
|
11579
11710
|
log3(" To apply: npx @solongate/proxy inject");
|
|
11580
11711
|
process.exit(0);
|
|
11581
11712
|
}
|
|
11582
|
-
if (!
|
|
11713
|
+
if (!existsSync9(backupPath)) {
|
|
11583
11714
|
copyFileSync(entryFile, backupPath);
|
|
11584
11715
|
log3("");
|
|
11585
11716
|
log3(` Backup: ${backupPath}`);
|
|
11586
11717
|
}
|
|
11587
|
-
|
|
11718
|
+
writeFileSync6(entryFile, result.modified);
|
|
11588
11719
|
log3("");
|
|
11589
11720
|
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");
|
|
11590
11721
|
log3(" \u2502 SolonGate SDK injected successfully! \u2502");
|
|
@@ -11613,8 +11744,8 @@ var init_inject = __esm({
|
|
|
11613
11744
|
|
|
11614
11745
|
// src/create.ts
|
|
11615
11746
|
var create_exports = {};
|
|
11616
|
-
import { mkdirSync as mkdirSync5, writeFileSync as
|
|
11617
|
-
import { resolve as resolve8, join as
|
|
11747
|
+
import { mkdirSync as mkdirSync5, writeFileSync as writeFileSync7, existsSync as existsSync10 } from "fs";
|
|
11748
|
+
import { resolve as resolve8, join as join12 } from "path";
|
|
11618
11749
|
import { execSync as execSync2 } from "child_process";
|
|
11619
11750
|
function withSpinner(message, fn) {
|
|
11620
11751
|
const frames = ["\u28FE", "\u28FD", "\u28FB", "\u28BF", "\u287F", "\u28DF", "\u28EF", "\u28F7"];
|
|
@@ -11693,8 +11824,8 @@ EXAMPLES
|
|
|
11693
11824
|
`);
|
|
11694
11825
|
}
|
|
11695
11826
|
function createProject(dir, name, _policy) {
|
|
11696
|
-
|
|
11697
|
-
|
|
11827
|
+
writeFileSync7(
|
|
11828
|
+
join12(dir, "package.json"),
|
|
11698
11829
|
JSON.stringify(
|
|
11699
11830
|
{
|
|
11700
11831
|
name,
|
|
@@ -11723,8 +11854,8 @@ function createProject(dir, name, _policy) {
|
|
|
11723
11854
|
2
|
|
11724
11855
|
) + "\n"
|
|
11725
11856
|
);
|
|
11726
|
-
|
|
11727
|
-
|
|
11857
|
+
writeFileSync7(
|
|
11858
|
+
join12(dir, "tsconfig.json"),
|
|
11728
11859
|
JSON.stringify(
|
|
11729
11860
|
{
|
|
11730
11861
|
compilerOptions: {
|
|
@@ -11744,9 +11875,9 @@ function createProject(dir, name, _policy) {
|
|
|
11744
11875
|
2
|
|
11745
11876
|
) + "\n"
|
|
11746
11877
|
);
|
|
11747
|
-
mkdirSync5(
|
|
11748
|
-
|
|
11749
|
-
|
|
11878
|
+
mkdirSync5(join12(dir, "src"), { recursive: true });
|
|
11879
|
+
writeFileSync7(
|
|
11880
|
+
join12(dir, "src", "index.ts"),
|
|
11750
11881
|
`#!/usr/bin/env node
|
|
11751
11882
|
|
|
11752
11883
|
console.log = (...args: unknown[]) => {
|
|
@@ -11787,8 +11918,8 @@ console.log('');
|
|
|
11787
11918
|
console.log('Press Ctrl+C to stop.');
|
|
11788
11919
|
`
|
|
11789
11920
|
);
|
|
11790
|
-
|
|
11791
|
-
|
|
11921
|
+
writeFileSync7(
|
|
11922
|
+
join12(dir, ".mcp.json"),
|
|
11792
11923
|
JSON.stringify(
|
|
11793
11924
|
{
|
|
11794
11925
|
mcpServers: {
|
|
@@ -11805,13 +11936,13 @@ console.log('Press Ctrl+C to stop.');
|
|
|
11805
11936
|
2
|
|
11806
11937
|
) + "\n"
|
|
11807
11938
|
);
|
|
11808
|
-
|
|
11809
|
-
|
|
11939
|
+
writeFileSync7(
|
|
11940
|
+
join12(dir, ".env"),
|
|
11810
11941
|
`SOLONGATE_API_KEY=sg_live_YOUR_KEY_HERE
|
|
11811
11942
|
`
|
|
11812
11943
|
);
|
|
11813
|
-
|
|
11814
|
-
|
|
11944
|
+
writeFileSync7(
|
|
11945
|
+
join12(dir, ".gitignore"),
|
|
11815
11946
|
`node_modules/
|
|
11816
11947
|
dist/
|
|
11817
11948
|
*.solongate-backup
|
|
@@ -11825,7 +11956,7 @@ async function main3() {
|
|
|
11825
11956
|
const opts = parseCreateArgs(process.argv);
|
|
11826
11957
|
const dir = resolve8(opts.name);
|
|
11827
11958
|
printBanner("Create MCP Server");
|
|
11828
|
-
if (
|
|
11959
|
+
if (existsSync10(dir)) {
|
|
11829
11960
|
log3(` ${c.red}Error:${c.reset} Directory "${opts.name}" already exists.`);
|
|
11830
11961
|
process.exit(1);
|
|
11831
11962
|
}
|
|
@@ -11904,12 +12035,12 @@ var init_create = __esm({
|
|
|
11904
12035
|
|
|
11905
12036
|
// src/pull-push.ts
|
|
11906
12037
|
var pull_push_exports = {};
|
|
11907
|
-
import { readFileSync as readFileSync11, writeFileSync as
|
|
12038
|
+
import { readFileSync as readFileSync11, writeFileSync as writeFileSync8, existsSync as existsSync11 } from "fs";
|
|
11908
12039
|
import { resolve as resolve9 } from "path";
|
|
11909
12040
|
function loadEnv() {
|
|
11910
12041
|
if (process.env.SOLONGATE_API_KEY) return;
|
|
11911
12042
|
const envPath = resolve9(".env");
|
|
11912
|
-
if (!
|
|
12043
|
+
if (!existsSync11(envPath)) return;
|
|
11913
12044
|
try {
|
|
11914
12045
|
const content = readFileSync11(envPath, "utf-8");
|
|
11915
12046
|
for (const line of content.split("\n")) {
|
|
@@ -12099,7 +12230,7 @@ async function pull(apiKey, file, policyId) {
|
|
|
12099
12230
|
const policy = await fetchCloudPolicy(apiKey, API_URL, policyId);
|
|
12100
12231
|
const { id: _id, ...policyWithoutId } = policy;
|
|
12101
12232
|
const json = JSON.stringify(policyWithoutId, null, 2) + "\n";
|
|
12102
|
-
|
|
12233
|
+
writeFileSync8(file, json, "utf-8");
|
|
12103
12234
|
log5("");
|
|
12104
12235
|
log5(green2(" Saved to: ") + file);
|
|
12105
12236
|
log5(` ${dim2("Name:")} ${policy.name}`);
|
|
@@ -12111,7 +12242,7 @@ async function pull(apiKey, file, policyId) {
|
|
|
12111
12242
|
log5("");
|
|
12112
12243
|
}
|
|
12113
12244
|
async function push(apiKey, file, policyId) {
|
|
12114
|
-
if (!
|
|
12245
|
+
if (!existsSync11(file)) {
|
|
12115
12246
|
log5(red2(`ERROR: File not found: ${file}`));
|
|
12116
12247
|
process.exit(1);
|
|
12117
12248
|
}
|
package/dist/tui/index.js
CHANGED
|
@@ -150,10 +150,9 @@ function KeyHints({ hints }) {
|
|
|
150
150
|
// src/tui/panels/Live.tsx
|
|
151
151
|
import { Box as Box2, Text as Text2, useInput } from "ink";
|
|
152
152
|
import TextInput from "ink-text-input";
|
|
153
|
-
import {
|
|
154
|
-
import { closeSync, mkdirSync, openSync, readSync, statSync, writeFileSync } from "fs";
|
|
153
|
+
import { closeSync, mkdirSync, openSync, readSync, statSync, writeFileSync as writeFileSync2 } from "fs";
|
|
155
154
|
import { homedir as homedir3 } from "os";
|
|
156
|
-
import { join as
|
|
155
|
+
import { join as join4 } from "path";
|
|
157
156
|
import { useCallback as useCallback2, useEffect as useEffect2, useRef as useRef2, useState as useState2 } from "react";
|
|
158
157
|
|
|
159
158
|
// src/api-client/client.ts
|
|
@@ -489,6 +488,139 @@ function list4() {
|
|
|
489
488
|
// src/api-client/index.ts
|
|
490
489
|
var api = { policies: policies_exports, settings: settings_exports, stats: stats_exports, audit: audit_exports, agents: agents_exports, keys: keys_exports, mcp: mcp_exports };
|
|
491
490
|
|
|
491
|
+
// src/tui/notify.ts
|
|
492
|
+
import { spawn, execFileSync } from "child_process";
|
|
493
|
+
import { writeFileSync, existsSync as existsSync2 } from "fs";
|
|
494
|
+
import { join as join3 } from "path";
|
|
495
|
+
import { tmpdir } from "os";
|
|
496
|
+
var focusToken = null;
|
|
497
|
+
function captureFocusTarget() {
|
|
498
|
+
try {
|
|
499
|
+
if (process.platform === "linux") {
|
|
500
|
+
focusToken = (process.env.WINDOWID || "").trim() || null;
|
|
501
|
+
if (!focusToken) {
|
|
502
|
+
try {
|
|
503
|
+
focusToken = execFileSync("xdotool", ["getactivewindow"], { encoding: "utf-8", timeout: 1500, stdio: ["ignore", "pipe", "ignore"] }).trim() || null;
|
|
504
|
+
} catch {
|
|
505
|
+
focusToken = null;
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
} else if (process.platform === "win32") {
|
|
509
|
+
const ps = `Add-Type -Name W -Namespace N -MemberDefinition '[DllImport("user32.dll")]public static extern System.IntPtr GetForegroundWindow();' | Out-Null; [N.W]::GetForegroundWindow().ToInt64()`;
|
|
510
|
+
try {
|
|
511
|
+
focusToken = execFileSync("powershell", ["-NoProfile", "-NonInteractive", "-Command", ps], { encoding: "utf-8", timeout: 4e3, stdio: ["ignore", "pipe", "ignore"] }).trim() || null;
|
|
512
|
+
} catch {
|
|
513
|
+
focusToken = null;
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
} catch {
|
|
517
|
+
focusToken = null;
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
function desktopNotify(title, msg) {
|
|
521
|
+
try {
|
|
522
|
+
if (process.platform === "linux") linuxNotify(title, msg);
|
|
523
|
+
else if (process.platform === "win32") winNotify(title, msg);
|
|
524
|
+
else if (process.platform === "darwin") macNotify(title, msg);
|
|
525
|
+
} catch {
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
function linuxNotify(title, msg) {
|
|
529
|
+
let p;
|
|
530
|
+
try {
|
|
531
|
+
p = spawn("notify-send", ["--wait", "--action=default=Open", "-a", "SolonGate", title, msg], { stdio: ["ignore", "pipe", "ignore"] });
|
|
532
|
+
} catch {
|
|
533
|
+
return;
|
|
534
|
+
}
|
|
535
|
+
p.on("error", () => {
|
|
536
|
+
});
|
|
537
|
+
p.stdout?.on("data", (d) => {
|
|
538
|
+
if (String(d).trim() === "default") raiseLinuxWindow();
|
|
539
|
+
});
|
|
540
|
+
p.unref();
|
|
541
|
+
}
|
|
542
|
+
function raiseLinuxWindow() {
|
|
543
|
+
if (!focusToken) return;
|
|
544
|
+
try {
|
|
545
|
+
const x = spawn("xdotool", ["windowactivate", focusToken], { stdio: "ignore" });
|
|
546
|
+
x.on("error", () => {
|
|
547
|
+
try {
|
|
548
|
+
const hex = "0x" + Number(focusToken).toString(16);
|
|
549
|
+
const w = spawn("wmctrl", ["-ia", hex], { stdio: "ignore" });
|
|
550
|
+
w.on("error", () => {
|
|
551
|
+
});
|
|
552
|
+
w.unref();
|
|
553
|
+
} catch {
|
|
554
|
+
}
|
|
555
|
+
});
|
|
556
|
+
x.unref();
|
|
557
|
+
} catch {
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
var winScriptPath = null;
|
|
561
|
+
function ensureWinScript() {
|
|
562
|
+
if (winScriptPath && existsSync2(winScriptPath)) return winScriptPath;
|
|
563
|
+
const p = join3(tmpdir(), "solongate-toast.ps1");
|
|
564
|
+
const script = [
|
|
565
|
+
"param([string]$Title,[string]$Msg,[string]$Hwnd)",
|
|
566
|
+
"Add-Type -AssemblyName System.Windows.Forms",
|
|
567
|
+
"Add-Type -AssemblyName System.Drawing",
|
|
568
|
+
`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);'`,
|
|
569
|
+
"$ni=New-Object System.Windows.Forms.NotifyIcon",
|
|
570
|
+
"$ni.Icon=[System.Drawing.SystemIcons]::Information",
|
|
571
|
+
"$ni.Visible=$true",
|
|
572
|
+
"$script:clicked=$false",
|
|
573
|
+
"$ni.add_BalloonTipClicked({$script:clicked=$true})",
|
|
574
|
+
"$ni.ShowBalloonTip(8000,$Title,$Msg,[System.Windows.Forms.ToolTipIcon]::Warning)",
|
|
575
|
+
"$sw=[System.Diagnostics.Stopwatch]::StartNew()",
|
|
576
|
+
"while($sw.Elapsed.TotalSeconds -lt 9 -and -not $script:clicked){[System.Windows.Forms.Application]::DoEvents();Start-Sleep -Milliseconds 100}",
|
|
577
|
+
"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{}}",
|
|
578
|
+
"$ni.Visible=$false;$ni.Dispose()"
|
|
579
|
+
].join("\n");
|
|
580
|
+
try {
|
|
581
|
+
writeFileSync(p, script);
|
|
582
|
+
winScriptPath = p;
|
|
583
|
+
return p;
|
|
584
|
+
} catch {
|
|
585
|
+
return null;
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
function winNotify(title, msg) {
|
|
589
|
+
const script = ensureWinScript();
|
|
590
|
+
if (!script) return;
|
|
591
|
+
try {
|
|
592
|
+
const p = spawn("powershell", ["-NoProfile", "-NonInteractive", "-ExecutionPolicy", "Bypass", "-File", script, "-Title", title, "-Msg", msg, "-Hwnd", focusToken || ""], { stdio: "ignore", detached: true, windowsHide: true });
|
|
593
|
+
p.on("error", () => {
|
|
594
|
+
});
|
|
595
|
+
p.unref();
|
|
596
|
+
} catch {
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
function macBundleId() {
|
|
600
|
+
const prog = (process.env.TERM_PROGRAM || "").toLowerCase();
|
|
601
|
+
if (prog.includes("iterm")) return "com.googlecode.iterm2";
|
|
602
|
+
if (prog.includes("apple_terminal")) return "com.apple.Terminal";
|
|
603
|
+
if (prog.includes("vscode")) return "com.microsoft.VSCode";
|
|
604
|
+
return "com.apple.Terminal";
|
|
605
|
+
}
|
|
606
|
+
function macNotify(title, msg) {
|
|
607
|
+
try {
|
|
608
|
+
const p = spawn("terminal-notifier", ["-title", title, "-message", msg, "-activate", macBundleId(), "-sender", macBundleId()], { stdio: "ignore", detached: true });
|
|
609
|
+
p.on("error", () => {
|
|
610
|
+
try {
|
|
611
|
+
const esc = (s) => s.replace(/"/g, '\\"');
|
|
612
|
+
const a = spawn("osascript", ["-e", `display notification "${esc(msg)}" with title "${esc(title)}"`], { stdio: "ignore", detached: true });
|
|
613
|
+
a.on("error", () => {
|
|
614
|
+
});
|
|
615
|
+
a.unref();
|
|
616
|
+
} catch {
|
|
617
|
+
}
|
|
618
|
+
});
|
|
619
|
+
p.unref();
|
|
620
|
+
} catch {
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
|
|
492
624
|
// src/tui/hooks.ts
|
|
493
625
|
import { useCallback, useEffect, useRef, useState } from "react";
|
|
494
626
|
function useLoader(fn, deps = []) {
|
|
@@ -535,8 +667,8 @@ var CONFIG = loadConfig();
|
|
|
535
667
|
var SPIN = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
536
668
|
var BG = "#12234f";
|
|
537
669
|
var DIM_FLOOR = "#233457";
|
|
538
|
-
var LOCAL_LOG =
|
|
539
|
-
var RING =
|
|
670
|
+
var LOCAL_LOG = join4(homedir3(), ".solongate", "local-logs", "solongate-audit.jsonl");
|
|
671
|
+
var RING = join4(process.cwd(), ".solongate", ".eval-ring.jsonl");
|
|
540
672
|
var hhmmss = (ts) => {
|
|
541
673
|
const d = new Date(ts);
|
|
542
674
|
return Number.isNaN(d.getTime()) ? "--:--:--" : d.toTimeString().slice(0, 8);
|
|
@@ -681,7 +813,7 @@ function LivePanel({ active: active2 }) {
|
|
|
681
813
|
const [sel, setSel] = useState2(0);
|
|
682
814
|
const [actionMsg, setActionMsg] = useState2(null);
|
|
683
815
|
const notifiedRef = useRef2(/* @__PURE__ */ new Set());
|
|
684
|
-
const
|
|
816
|
+
const openedAtRef = useRef2(Date.now());
|
|
685
817
|
const activePolicyRef = useRef2(null);
|
|
686
818
|
const [mode, setMode] = useState2("stream");
|
|
687
819
|
const [pickIdx, setPickIdx] = useState2(0);
|
|
@@ -865,13 +997,7 @@ function LivePanel({ active: active2 }) {
|
|
|
865
997
|
process.stdout.write("\x07");
|
|
866
998
|
} catch {
|
|
867
999
|
}
|
|
868
|
-
|
|
869
|
-
const child = spawn("notify-send", ["-a", "SolonGate", title, msg], { stdio: "ignore", detached: true });
|
|
870
|
-
child.on("error", () => {
|
|
871
|
-
});
|
|
872
|
-
child.unref();
|
|
873
|
-
} catch {
|
|
874
|
-
}
|
|
1000
|
+
desktopNotify(title, msg);
|
|
875
1001
|
},
|
|
876
1002
|
[pushLog]
|
|
877
1003
|
);
|
|
@@ -889,14 +1015,10 @@ function LivePanel({ active: active2 }) {
|
|
|
889
1015
|
useEffect2(() => {
|
|
890
1016
|
if (!active2) return;
|
|
891
1017
|
const notable = mergedRef.current.filter((e) => e.decision !== "ALLOW" || e.dlp || e.burst);
|
|
892
|
-
if (!notifyReady.current) {
|
|
893
|
-
for (const e of notable) notifiedRef.current.add(e.id);
|
|
894
|
-
notifyReady.current = true;
|
|
895
|
-
return;
|
|
896
|
-
}
|
|
897
1018
|
for (const e of notable) {
|
|
898
1019
|
if (notifiedRef.current.has(e.id)) continue;
|
|
899
1020
|
notifiedRef.current.add(e.id);
|
|
1021
|
+
if (!(e.at > openedAtRef.current)) continue;
|
|
900
1022
|
const who = e.agent ? ` \xB7 ${truncate(e.agent, 20)}` : "";
|
|
901
1023
|
if (e.dlp) fireAlert("sec:" + e.id, "DLP hit", `SECRET in ${e.tool}${who}: ${truncate(e.detail, 60)}`, "bad");
|
|
902
1024
|
else if (e.decision !== "ALLOW") fireAlert("sec:" + e.id, "Call denied", `DENY ${e.tool}${who}: ${truncate(e.rule ?? e.detail, 60)}`, "bad");
|
|
@@ -1089,10 +1211,10 @@ function LivePanel({ active: active2 }) {
|
|
|
1089
1211
|
else if (input === "x") toggleSignal("dlp");
|
|
1090
1212
|
else if (input === "r") toggleSignal("ratelimit");
|
|
1091
1213
|
else if (input === "e") {
|
|
1092
|
-
const file =
|
|
1214
|
+
const file = join4(homedir3(), ".solongate", "live-export.jsonl");
|
|
1093
1215
|
try {
|
|
1094
|
-
mkdirSync(
|
|
1095
|
-
|
|
1216
|
+
mkdirSync(join4(homedir3(), ".solongate"), { recursive: true });
|
|
1217
|
+
writeFileSync2(file, visibleDesc.map((x) => JSON.stringify(x)).join("\n") + "\n");
|
|
1096
1218
|
setActionMsg({ text: `\u2713 exported ${visibleDesc.length} lines \u2192 ${file}`, level: "ok", until: Date.now() + 6e3 });
|
|
1097
1219
|
} catch (err) {
|
|
1098
1220
|
setActionMsg({ text: "\u2717 export failed: " + (err instanceof Error ? err.message : String(err)), level: "bad", until: Date.now() + 6e3 });
|
|
@@ -2461,6 +2583,7 @@ async function launchTui() {
|
|
|
2461
2583
|
process.stderr.write("Not logged in. Run `solongate login` first.\n");
|
|
2462
2584
|
return;
|
|
2463
2585
|
}
|
|
2586
|
+
captureFocusTarget();
|
|
2464
2587
|
process.stdout.write("\x1B[?1049h\x1B[H");
|
|
2465
2588
|
try {
|
|
2466
2589
|
const { waitUntilExit } = render(/* @__PURE__ */ jsx10(App, {}));
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
/** Capture the current terminal window once, at TUI startup. Cheap + best-effort. */
|
|
2
|
+
export declare function captureFocusTarget(): void;
|
|
3
|
+
/** Fire a desktop toast; clicking it raises the dataroom terminal. */
|
|
4
|
+
export declare function desktopNotify(title: string, msg: string): void;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@solongate/proxy",
|
|
3
|
-
"version": "0.81.
|
|
3
|
+
"version": "0.81.17",
|
|
4
4
|
"description": "AI tool security proxy: protect any AI tool server with customizable policies, path/command constraints, rate limiting, and audit logging. No code changes required.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|