@solongate/proxy 0.81.44 → 0.81.46
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 +388 -151
- package/dist/self-update.d.ts +6 -0
- package/dist/tui/index.js +97 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -6554,15 +6554,151 @@ var init_cli_utils = __esm({
|
|
|
6554
6554
|
}
|
|
6555
6555
|
});
|
|
6556
6556
|
|
|
6557
|
-
// src/
|
|
6558
|
-
|
|
6557
|
+
// src/self-update.ts
|
|
6558
|
+
var self_update_exports = {};
|
|
6559
|
+
__export(self_update_exports, {
|
|
6560
|
+
currentVersion: () => currentVersion,
|
|
6561
|
+
maybeSelfUpdate: () => maybeSelfUpdate
|
|
6562
|
+
});
|
|
6563
|
+
import { execFile, spawn } from "child_process";
|
|
6564
|
+
import { mkdirSync as mkdirSync3, openSync, readFileSync as readFileSync4, realpathSync, writeFileSync as writeFileSync3 } from "fs";
|
|
6559
6565
|
import { homedir as homedir2 } from "os";
|
|
6560
|
-
import { join as join4 } from "path";
|
|
6566
|
+
import { dirname, join as join4 } from "path";
|
|
6567
|
+
import { fileURLToPath } from "url";
|
|
6568
|
+
function readState() {
|
|
6569
|
+
try {
|
|
6570
|
+
const s = JSON.parse(readFileSync4(STATE_FILE, "utf-8"));
|
|
6571
|
+
return s && typeof s === "object" ? s : {};
|
|
6572
|
+
} catch {
|
|
6573
|
+
return {};
|
|
6574
|
+
}
|
|
6575
|
+
}
|
|
6576
|
+
function writeState(s) {
|
|
6577
|
+
try {
|
|
6578
|
+
mkdirSync3(join4(homedir2(), ".solongate"), { recursive: true });
|
|
6579
|
+
writeFileSync3(STATE_FILE, JSON.stringify(s));
|
|
6580
|
+
} catch {
|
|
6581
|
+
}
|
|
6582
|
+
}
|
|
6583
|
+
function currentVersion() {
|
|
6584
|
+
try {
|
|
6585
|
+
const pkg = JSON.parse(readFileSync4(join4(dirname(fileURLToPath(import.meta.url)), "..", "package.json"), "utf-8"));
|
|
6586
|
+
return pkg.version ?? "0.0.0";
|
|
6587
|
+
} catch {
|
|
6588
|
+
return "0.0.0";
|
|
6589
|
+
}
|
|
6590
|
+
}
|
|
6591
|
+
function newerThan(b, a) {
|
|
6592
|
+
const pa = a.split(".").map((n) => parseInt(n, 10) || 0);
|
|
6593
|
+
const pb = b.split(".").map((n) => parseInt(n, 10) || 0);
|
|
6594
|
+
for (let i = 0; i < 3; i++) {
|
|
6595
|
+
if ((pb[i] ?? 0) > (pa[i] ?? 0)) return true;
|
|
6596
|
+
if ((pb[i] ?? 0) < (pa[i] ?? 0)) return false;
|
|
6597
|
+
}
|
|
6598
|
+
return false;
|
|
6599
|
+
}
|
|
6600
|
+
async function fetchLatest() {
|
|
6601
|
+
try {
|
|
6602
|
+
const res = await fetch(`https://registry.npmjs.org/${PKG}/latest`, { signal: AbortSignal.timeout(2e3) });
|
|
6603
|
+
if (!res.ok) return null;
|
|
6604
|
+
const j = await res.json();
|
|
6605
|
+
return typeof j.version === "string" ? j.version : null;
|
|
6606
|
+
} catch {
|
|
6607
|
+
return null;
|
|
6608
|
+
}
|
|
6609
|
+
}
|
|
6610
|
+
function npmGlobalRoot() {
|
|
6611
|
+
return new Promise((resolve10) => {
|
|
6612
|
+
try {
|
|
6613
|
+
execFile("npm", ["root", "-g"], { timeout: 5e3, windowsHide: true, shell: process.platform === "win32" }, (err2, stdout) => {
|
|
6614
|
+
resolve10(err2 ? null : stdout.trim() || null);
|
|
6615
|
+
});
|
|
6616
|
+
} catch {
|
|
6617
|
+
resolve10(null);
|
|
6618
|
+
}
|
|
6619
|
+
});
|
|
6620
|
+
}
|
|
6621
|
+
async function isGlobalInstall() {
|
|
6622
|
+
try {
|
|
6623
|
+
const script = realpathSync(process.argv[1] ?? "");
|
|
6624
|
+
if (!script) return false;
|
|
6625
|
+
const root = await npmGlobalRoot();
|
|
6626
|
+
if (!root) return false;
|
|
6627
|
+
return script.startsWith(realpathSync(root));
|
|
6628
|
+
} catch {
|
|
6629
|
+
return false;
|
|
6630
|
+
}
|
|
6631
|
+
}
|
|
6632
|
+
function spawnGlobalInstall(version) {
|
|
6633
|
+
try {
|
|
6634
|
+
mkdirSync3(join4(homedir2(), ".solongate"), { recursive: true });
|
|
6635
|
+
const log6 = openSync(LOG_FILE, "a");
|
|
6636
|
+
const p = spawn("npm", ["install", "-g", `${PKG}@${version}`], {
|
|
6637
|
+
stdio: ["ignore", log6, log6],
|
|
6638
|
+
detached: true,
|
|
6639
|
+
windowsHide: true,
|
|
6640
|
+
shell: process.platform === "win32"
|
|
6641
|
+
});
|
|
6642
|
+
p.on("error", () => {
|
|
6643
|
+
});
|
|
6644
|
+
p.unref();
|
|
6645
|
+
return true;
|
|
6646
|
+
} catch {
|
|
6647
|
+
return false;
|
|
6648
|
+
}
|
|
6649
|
+
}
|
|
6650
|
+
function maybeSelfUpdate(notify = (l) => process.stderr.write(l + "\n")) {
|
|
6651
|
+
void (async () => {
|
|
6652
|
+
try {
|
|
6653
|
+
const state = readState();
|
|
6654
|
+
const now = Date.now();
|
|
6655
|
+
const current = currentVersion();
|
|
6656
|
+
let latest = state.latestSeen ?? null;
|
|
6657
|
+
if (now - (state.lastCheckAt ?? 0) >= CHECK_EVERY_MS) {
|
|
6658
|
+
latest = await fetchLatest();
|
|
6659
|
+
if (latest) writeState({ ...state, lastCheckAt: now, latestSeen: latest });
|
|
6660
|
+
else writeState({ ...state, lastCheckAt: now });
|
|
6661
|
+
}
|
|
6662
|
+
if (!latest || !newerThan(latest, current)) return;
|
|
6663
|
+
const attempts = readState().attempts ?? {};
|
|
6664
|
+
if (await isGlobalInstall()) {
|
|
6665
|
+
if (now - (attempts[latest] ?? 0) >= ATTEMPT_EVERY_MS) {
|
|
6666
|
+
writeState({ ...readState(), attempts: { [latest]: now } });
|
|
6667
|
+
if (spawnGlobalInstall(latest)) {
|
|
6668
|
+
notify(`${c.dim}\u2191 solongate v${latest} available (running v${current}) \u2014 updating in the background, next run uses it${c.reset}`);
|
|
6669
|
+
return;
|
|
6670
|
+
}
|
|
6671
|
+
} else {
|
|
6672
|
+
return;
|
|
6673
|
+
}
|
|
6674
|
+
}
|
|
6675
|
+
notify(`${c.dim}\u2191 solongate v${latest} available (running v${current}) \u2014 update: ${c.reset}${c.cyan}npm i -g ${PKG}@latest${c.reset}`);
|
|
6676
|
+
} catch {
|
|
6677
|
+
}
|
|
6678
|
+
})();
|
|
6679
|
+
}
|
|
6680
|
+
var PKG, CHECK_EVERY_MS, ATTEMPT_EVERY_MS, STATE_FILE, LOG_FILE;
|
|
6681
|
+
var init_self_update = __esm({
|
|
6682
|
+
"src/self-update.ts"() {
|
|
6683
|
+
"use strict";
|
|
6684
|
+
init_cli_utils();
|
|
6685
|
+
PKG = "@solongate/proxy";
|
|
6686
|
+
CHECK_EVERY_MS = 30 * 60 * 1e3;
|
|
6687
|
+
ATTEMPT_EVERY_MS = 6 * 60 * 60 * 1e3;
|
|
6688
|
+
STATE_FILE = join4(homedir2(), ".solongate", ".self-update.json");
|
|
6689
|
+
LOG_FILE = join4(homedir2(), ".solongate", "self-update.log");
|
|
6690
|
+
}
|
|
6691
|
+
});
|
|
6692
|
+
|
|
6693
|
+
// src/tui/config.ts
|
|
6694
|
+
import { readFileSync as readFileSync5 } from "fs";
|
|
6695
|
+
import { homedir as homedir3 } from "os";
|
|
6696
|
+
import { join as join5 } from "path";
|
|
6561
6697
|
function loadConfig() {
|
|
6562
6698
|
if (cached) return cached;
|
|
6563
6699
|
const defaults = { notifications: true };
|
|
6564
6700
|
try {
|
|
6565
|
-
const raw =
|
|
6701
|
+
const raw = readFileSync5(join5(homedir3(), ".solongate", "tui-config.json"), "utf-8");
|
|
6566
6702
|
const j = JSON.parse(raw);
|
|
6567
6703
|
cached = {
|
|
6568
6704
|
notifications: j.notifications !== false,
|
|
@@ -6688,14 +6824,14 @@ var init_components = __esm({
|
|
|
6688
6824
|
});
|
|
6689
6825
|
|
|
6690
6826
|
// src/tui/local-log.ts
|
|
6691
|
-
import { closeSync, openSync, readFileSync as
|
|
6692
|
-
import { homedir as
|
|
6693
|
-
import { join as
|
|
6827
|
+
import { closeSync, openSync as openSync2, readFileSync as readFileSync6, readSync, statSync, writeFileSync as writeFileSync4 } from "fs";
|
|
6828
|
+
import { homedir as homedir4 } from "os";
|
|
6829
|
+
import { join as join6 } from "path";
|
|
6694
6830
|
function tailLines(file, maxBytes = 131072) {
|
|
6695
6831
|
try {
|
|
6696
6832
|
const size = statSync(file).size;
|
|
6697
6833
|
const start = Math.max(0, size - maxBytes);
|
|
6698
|
-
const fd =
|
|
6834
|
+
const fd = openSync2(file, "r");
|
|
6699
6835
|
const buf = Buffer.alloc(size - start);
|
|
6700
6836
|
readSync(fd, buf, 0, buf.length, start);
|
|
6701
6837
|
closeSync(fd);
|
|
@@ -6708,7 +6844,7 @@ function tailLines(file, maxBytes = 131072) {
|
|
|
6708
6844
|
}
|
|
6709
6845
|
function deleteLocalEntry(at, tool, session) {
|
|
6710
6846
|
try {
|
|
6711
|
-
const lines =
|
|
6847
|
+
const lines = readFileSync6(LOCAL_LOG, "utf-8").split("\n");
|
|
6712
6848
|
let removed = 0;
|
|
6713
6849
|
const kept = lines.filter((line) => {
|
|
6714
6850
|
if (!line.trim()) return false;
|
|
@@ -6724,7 +6860,7 @@ function deleteLocalEntry(at, tool, session) {
|
|
|
6724
6860
|
}
|
|
6725
6861
|
return true;
|
|
6726
6862
|
});
|
|
6727
|
-
if (removed)
|
|
6863
|
+
if (removed) writeFileSync4(LOCAL_LOG, kept.length ? kept.join("\n") + "\n" : "");
|
|
6728
6864
|
return removed;
|
|
6729
6865
|
} catch {
|
|
6730
6866
|
return 0;
|
|
@@ -6732,8 +6868,8 @@ function deleteLocalEntry(at, tool, session) {
|
|
|
6732
6868
|
}
|
|
6733
6869
|
function clearLocalLog() {
|
|
6734
6870
|
try {
|
|
6735
|
-
const n =
|
|
6736
|
-
|
|
6871
|
+
const n = readFileSync6(LOCAL_LOG, "utf-8").split("\n").filter(Boolean).length;
|
|
6872
|
+
writeFileSync4(LOCAL_LOG, "");
|
|
6737
6873
|
return n;
|
|
6738
6874
|
} catch {
|
|
6739
6875
|
return 0;
|
|
@@ -6764,20 +6900,20 @@ var LOCAL_LOG, DLP_REASON, RL_REASON;
|
|
|
6764
6900
|
var init_local_log = __esm({
|
|
6765
6901
|
"src/tui/local-log.ts"() {
|
|
6766
6902
|
"use strict";
|
|
6767
|
-
LOCAL_LOG =
|
|
6903
|
+
LOCAL_LOG = join6(homedir4(), ".solongate", "local-logs", "solongate-audit.jsonl");
|
|
6768
6904
|
DLP_REASON = /security layer \(dlp\)/i;
|
|
6769
6905
|
RL_REASON = /security layer \(rate limit\)|rate[- ]?limit(?:ed)?\b.*exceed|exceeded \d+ calls/i;
|
|
6770
6906
|
}
|
|
6771
6907
|
});
|
|
6772
6908
|
|
|
6773
6909
|
// src/api-client/client.ts
|
|
6774
|
-
import { readFileSync as
|
|
6775
|
-
import { resolve as resolve3, join as
|
|
6776
|
-
import { homedir as
|
|
6910
|
+
import { readFileSync as readFileSync7, writeFileSync as writeFileSync5, mkdirSync as mkdirSync4, existsSync as existsSync3 } from "fs";
|
|
6911
|
+
import { resolve as resolve3, join as join7 } from "path";
|
|
6912
|
+
import { homedir as homedir5 } from "os";
|
|
6777
6913
|
function listAccounts() {
|
|
6778
6914
|
let list6 = [];
|
|
6779
6915
|
try {
|
|
6780
|
-
const raw = JSON.parse(
|
|
6916
|
+
const raw = JSON.parse(readFileSync7(accountsFile(), "utf-8"));
|
|
6781
6917
|
if (Array.isArray(raw)) list6 = raw.filter((a) => a && typeof a.apiKey === "string");
|
|
6782
6918
|
} catch {
|
|
6783
6919
|
}
|
|
@@ -6791,7 +6927,7 @@ function saveAccount(acc) {
|
|
|
6791
6927
|
try {
|
|
6792
6928
|
const list6 = (() => {
|
|
6793
6929
|
try {
|
|
6794
|
-
const raw = JSON.parse(
|
|
6930
|
+
const raw = JSON.parse(readFileSync7(accountsFile(), "utf-8"));
|
|
6795
6931
|
return Array.isArray(raw) ? raw.filter((a) => a && a.apiKey) : [];
|
|
6796
6932
|
} catch {
|
|
6797
6933
|
return [];
|
|
@@ -6799,8 +6935,8 @@ function saveAccount(acc) {
|
|
|
6799
6935
|
})();
|
|
6800
6936
|
const next = list6.filter((a) => a.apiKey !== acc.apiKey);
|
|
6801
6937
|
next.unshift({ ...acc, addedAt: acc.addedAt ?? Date.now() });
|
|
6802
|
-
|
|
6803
|
-
|
|
6938
|
+
mkdirSync4(join7(homedir5(), ".solongate"), { recursive: true });
|
|
6939
|
+
writeFileSync5(accountsFile(), JSON.stringify(next, null, 2));
|
|
6804
6940
|
} catch {
|
|
6805
6941
|
}
|
|
6806
6942
|
}
|
|
@@ -6813,15 +6949,15 @@ function isActiveAccount(apiKey) {
|
|
|
6813
6949
|
}
|
|
6814
6950
|
function setActiveAccount(creds) {
|
|
6815
6951
|
try {
|
|
6816
|
-
const dir =
|
|
6817
|
-
|
|
6818
|
-
const p =
|
|
6952
|
+
const dir = join7(homedir5(), ".solongate");
|
|
6953
|
+
mkdirSync4(dir, { recursive: true });
|
|
6954
|
+
const p = join7(dir, ["cloud", "guard.json"].join("-"));
|
|
6819
6955
|
let existing = {};
|
|
6820
6956
|
try {
|
|
6821
|
-
existing = JSON.parse(
|
|
6957
|
+
existing = JSON.parse(readFileSync7(p, "utf-8"));
|
|
6822
6958
|
} catch {
|
|
6823
6959
|
}
|
|
6824
|
-
|
|
6960
|
+
writeFileSync5(p, JSON.stringify({ ...existing, apiKey: creds.apiKey, apiUrl: creds.apiUrl }, null, 2));
|
|
6825
6961
|
cached2 = null;
|
|
6826
6962
|
return true;
|
|
6827
6963
|
} catch {
|
|
@@ -6830,9 +6966,9 @@ function setActiveAccount(creds) {
|
|
|
6830
6966
|
}
|
|
6831
6967
|
function loginCredentialFile() {
|
|
6832
6968
|
try {
|
|
6833
|
-
const p =
|
|
6969
|
+
const p = join7(homedir5(), ".solongate", "cloud-guard.json");
|
|
6834
6970
|
if (!existsSync3(p)) return {};
|
|
6835
|
-
const c2 = JSON.parse(
|
|
6971
|
+
const c2 = JSON.parse(readFileSync7(p, "utf-8"));
|
|
6836
6972
|
return c2 && typeof c2 === "object" ? c2 : {};
|
|
6837
6973
|
} catch {
|
|
6838
6974
|
return {};
|
|
@@ -6842,7 +6978,7 @@ function dotenvApiKey() {
|
|
|
6842
6978
|
try {
|
|
6843
6979
|
const envPath = resolve3(".env");
|
|
6844
6980
|
if (!existsSync3(envPath)) return void 0;
|
|
6845
|
-
for (const line of
|
|
6981
|
+
for (const line of readFileSync7(envPath, "utf-8").split("\n")) {
|
|
6846
6982
|
const trimmed = line.trim();
|
|
6847
6983
|
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
6848
6984
|
const eq = trimmed.indexOf("=");
|
|
@@ -6944,7 +7080,7 @@ var init_client = __esm({
|
|
|
6944
7080
|
"src/api-client/client.ts"() {
|
|
6945
7081
|
"use strict";
|
|
6946
7082
|
DEFAULT_API_URL2 = "https://api.solongate.com";
|
|
6947
|
-
accountsFile = () =>
|
|
7083
|
+
accountsFile = () => join7(homedir5(), ".solongate", "accounts.json");
|
|
6948
7084
|
viewOverride = null;
|
|
6949
7085
|
ApiError = class extends Error {
|
|
6950
7086
|
status;
|
|
@@ -6974,12 +7110,12 @@ var init_types = __esm({
|
|
|
6974
7110
|
});
|
|
6975
7111
|
|
|
6976
7112
|
// src/api-client/device-login.ts
|
|
6977
|
-
import { spawn } from "child_process";
|
|
7113
|
+
import { spawn as spawn2 } from "child_process";
|
|
6978
7114
|
function openBrowser(url) {
|
|
6979
7115
|
try {
|
|
6980
7116
|
const cmd = process.platform === "win32" ? "cmd" : process.platform === "darwin" ? "open" : "xdg-open";
|
|
6981
7117
|
const args = process.platform === "win32" ? ["/c", "start", '""', url] : [url];
|
|
6982
|
-
const child =
|
|
7118
|
+
const child = spawn2(cmd, args, { stdio: "ignore", detached: true });
|
|
6983
7119
|
child.on("error", () => {
|
|
6984
7120
|
});
|
|
6985
7121
|
child.unref();
|
|
@@ -7304,24 +7440,24 @@ var init_api_client = __esm({
|
|
|
7304
7440
|
});
|
|
7305
7441
|
|
|
7306
7442
|
// src/tui/notify.ts
|
|
7307
|
-
import { spawn as
|
|
7443
|
+
import { spawn as spawn3 } from "child_process";
|
|
7308
7444
|
function desktopNotify(title, msg) {
|
|
7309
7445
|
try {
|
|
7310
7446
|
if (process.platform === "linux") {
|
|
7311
|
-
const p =
|
|
7447
|
+
const p = spawn3("notify-send", ["-a", "SolonGate", title, msg], { stdio: "ignore", detached: true });
|
|
7312
7448
|
p.on("error", () => {
|
|
7313
7449
|
});
|
|
7314
7450
|
p.unref();
|
|
7315
7451
|
} else if (process.platform === "win32") {
|
|
7316
7452
|
const q = (s) => s.replace(/'/g, "''");
|
|
7317
7453
|
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()`;
|
|
7318
|
-
const p =
|
|
7454
|
+
const p = spawn3("powershell", ["-NoProfile", "-NonInteractive", "-Command", ps], { stdio: "ignore", detached: true, windowsHide: true });
|
|
7319
7455
|
p.on("error", () => {
|
|
7320
7456
|
});
|
|
7321
7457
|
p.unref();
|
|
7322
7458
|
} else if (process.platform === "darwin") {
|
|
7323
7459
|
const esc = (s) => s.replace(/"/g, '\\"');
|
|
7324
|
-
const p =
|
|
7460
|
+
const p = spawn3("osascript", ["-e", `display notification "${esc(msg)}" with title "${esc(title)}"`], { stdio: "ignore", detached: true });
|
|
7325
7461
|
p.on("error", () => {
|
|
7326
7462
|
});
|
|
7327
7463
|
p.unref();
|
|
@@ -7407,9 +7543,9 @@ var init_hooks = __esm({
|
|
|
7407
7543
|
// src/tui/panels/Live.tsx
|
|
7408
7544
|
import { Box as Box2, Text as Text2, useInput } from "ink";
|
|
7409
7545
|
import TextInput from "ink-text-input";
|
|
7410
|
-
import { mkdirSync as
|
|
7411
|
-
import { homedir as
|
|
7412
|
-
import { join as
|
|
7546
|
+
import { mkdirSync as mkdirSync5, writeFileSync as writeFileSync6 } from "fs";
|
|
7547
|
+
import { homedir as homedir6 } from "os";
|
|
7548
|
+
import { join as join8 } from "path";
|
|
7413
7549
|
import { useCallback as useCallback2, useEffect as useEffect2, useRef as useRef2, useState as useState2 } from "react";
|
|
7414
7550
|
import { Fragment as Fragment2, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
7415
7551
|
function extractTarget(detail) {
|
|
@@ -7534,6 +7670,7 @@ function LivePanel({ active: active2 }) {
|
|
|
7534
7670
|
const [detailScroll, setDetailScroll] = useState2(0);
|
|
7535
7671
|
const [inspect, setInspect] = useState2(null);
|
|
7536
7672
|
const [inspectScroll, setInspectScroll] = useState2(0);
|
|
7673
|
+
const [layersScroll, setLayersScroll] = useState2(0);
|
|
7537
7674
|
const inspectFromRef = useRef2("stream");
|
|
7538
7675
|
const seenRef = useRef2(/* @__PURE__ */ new Set());
|
|
7539
7676
|
const lastLocalTs = useRef2(0);
|
|
@@ -7933,6 +8070,14 @@ function LivePanel({ active: active2 }) {
|
|
|
7933
8070
|
else if (key.pageDown) setInspectScroll((n) => n + 10);
|
|
7934
8071
|
return;
|
|
7935
8072
|
}
|
|
8073
|
+
if (mode === "layers") {
|
|
8074
|
+
if (key.leftArrow || input === "l") setMode("stream");
|
|
8075
|
+
else if (key.upArrow) setLayersScroll((n) => Math.max(0, n - 1));
|
|
8076
|
+
else if (key.downArrow) setLayersScroll((n) => n + 1);
|
|
8077
|
+
else if (key.pageUp) setLayersScroll((n) => Math.max(0, n - 10));
|
|
8078
|
+
else if (key.pageDown) setLayersScroll((n) => n + 10);
|
|
8079
|
+
return;
|
|
8080
|
+
}
|
|
7936
8081
|
if (mode === "detail") {
|
|
7937
8082
|
const maxD = Math.max(0, detailEntries.length - 1);
|
|
7938
8083
|
if (key.leftArrow) {
|
|
@@ -7982,16 +8127,19 @@ function LivePanel({ active: active2 }) {
|
|
|
7982
8127
|
} else if (input === "s") {
|
|
7983
8128
|
setPickIdx(0);
|
|
7984
8129
|
setMode("pick");
|
|
8130
|
+
} else if (input === "l") {
|
|
8131
|
+
setLayersScroll(0);
|
|
8132
|
+
setMode("layers");
|
|
7985
8133
|
} else if (input === "w") void doAction("whitelist");
|
|
7986
8134
|
else if (input === "b") void doAction("block");
|
|
7987
8135
|
else if (input === "d") toggleSignal("deny");
|
|
7988
8136
|
else if (input === "x") toggleSignal("dlp");
|
|
7989
8137
|
else if (input === "r") toggleSignal("ratelimit");
|
|
7990
8138
|
else if (input === "e") {
|
|
7991
|
-
const file =
|
|
8139
|
+
const file = join8(homedir6(), ".solongate", "live-export.jsonl");
|
|
7992
8140
|
try {
|
|
7993
|
-
|
|
7994
|
-
|
|
8141
|
+
mkdirSync5(join8(homedir6(), ".solongate"), { recursive: true });
|
|
8142
|
+
writeFileSync6(file, visibleDesc.map((x) => JSON.stringify(x)).join("\n") + "\n");
|
|
7995
8143
|
setActionMsg({ text: `\u2713 exported ${visibleDesc.length} lines \u2192 ${file}`, level: "ok", until: Date.now() + 6e3 });
|
|
7996
8144
|
} catch (err2) {
|
|
7997
8145
|
setActionMsg({ text: "\u2717 export failed: " + (err2 instanceof Error ? err2.message : String(err2)), level: "bad", until: Date.now() + 6e3 });
|
|
@@ -8101,6 +8249,87 @@ function LivePanel({ active: active2 }) {
|
|
|
8101
8249
|
] })
|
|
8102
8250
|
] });
|
|
8103
8251
|
}
|
|
8252
|
+
if (mode === "layers") {
|
|
8253
|
+
const modeColor4 = (m) => m === "block" || m === "on" ? theme.ok : m === "detect" ? theme.warn : theme.dim;
|
|
8254
|
+
const barW = Math.max(10, Math.min(40, innerW - 30));
|
|
8255
|
+
const burstsInBuf = mergedAll.filter((e) => e.burst).length;
|
|
8256
|
+
const dlpInBuf = mergedAll.filter((e) => e.dlp).length;
|
|
8257
|
+
const allHits = ins.dlpByPattern ?? [];
|
|
8258
|
+
const maxHit = allHits[0]?.count ?? 1;
|
|
8259
|
+
const L = [];
|
|
8260
|
+
const push2 = (el) => L.push(/* @__PURE__ */ jsx2(Box2, { children: el }, L.length));
|
|
8261
|
+
const blank = () => push2(/* @__PURE__ */ jsx2(Text2, { children: " " }));
|
|
8262
|
+
const section = (label, m, note) => push2(
|
|
8263
|
+
/* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
8264
|
+
/* @__PURE__ */ jsxs2(Text2, { bold: true, color: theme.accentBright, children: [
|
|
8265
|
+
"\u258E",
|
|
8266
|
+
label.padEnd(10)
|
|
8267
|
+
] }),
|
|
8268
|
+
/* @__PURE__ */ jsx2(Text2, { bold: true, color: modeColor4(m), children: (m ?? "?").padEnd(8) }),
|
|
8269
|
+
note ? /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: note }) : null
|
|
8270
|
+
] })
|
|
8271
|
+
);
|
|
8272
|
+
const kv = (k, v) => push2(
|
|
8273
|
+
/* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
8274
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: (" " + k).padEnd(16) }),
|
|
8275
|
+
v
|
|
8276
|
+
] })
|
|
8277
|
+
);
|
|
8278
|
+
section("RATELIMIT", rl?.mode, rl?.mode === "block" ? "over-limit calls are DENIED" : rl?.mode === "detect" ? "over-limit calls are observed & flagged rl:yes" : "no limit enforcement");
|
|
8279
|
+
kv("limits", /* @__PURE__ */ jsx2(Text2, { children: rl?.perMinute || rl?.perHour || rl?.perDay ? `${rl?.perMinute || "\u2014"}/min \xB7 ${rl?.perHour || "\u2014"}/hour \xB7 ${rl?.perDay || "\u2014"}/day` : "none configured" }));
|
|
8280
|
+
kv("load now", /* @__PURE__ */ jsx2(Text2, { children: `${minuteNow} calls in the last 60s` }));
|
|
8281
|
+
if (rl?.perMinute) push2(/* @__PURE__ */ jsx2(HBar, { label: " load/min", value: minuteNow, max: rl.perMinute, width: barW, color: minuteNow > rl.perMinute ? theme.bad : theme.accent }));
|
|
8282
|
+
kv("bursts", /* @__PURE__ */ jsx2(Text2, { color: burstsInBuf ? theme.warn : theme.dim, children: `${burstsInBuf} flagged in the live buffer` }));
|
|
8283
|
+
blank();
|
|
8284
|
+
section("DLP", dl?.mode, dl?.mode === "block" ? "secrets in arguments are DENIED + redacted" : dl?.mode === "detect" ? "secrets observed & flagged dlp:yes, output redacted" : "no secret scanning");
|
|
8285
|
+
kv("hits", /* @__PURE__ */ jsx2(Text2, { color: dlpInBuf ? theme.bad : theme.dim, children: `${dlpInBuf} flagged in the live buffer` }));
|
|
8286
|
+
const builtin = dl?.patterns ?? [];
|
|
8287
|
+
kv("builtin", /* @__PURE__ */ jsx2(Text2, { children: builtin.length ? `${builtin.length} patterns enabled` : "none enabled" }));
|
|
8288
|
+
for (const line of wrapLines(builtin.join(" \xB7 "), Math.max(20, innerW - 18))) push2(/* @__PURE__ */ jsx2(Text2, { wrap: "truncate", color: theme.dim, children: " " + line }));
|
|
8289
|
+
const custom = dl?.custom ?? [];
|
|
8290
|
+
kv("custom", /* @__PURE__ */ jsx2(Text2, { children: custom.length ? `${custom.length} patterns` : "none" }));
|
|
8291
|
+
for (const c2 of custom)
|
|
8292
|
+
push2(
|
|
8293
|
+
/* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
8294
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " " }),
|
|
8295
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.accent, children: truncate2(c2.name ?? "custom", 24).padEnd(25) }),
|
|
8296
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: truncate2(c2.re ?? "", Math.max(10, innerW - 44)) })
|
|
8297
|
+
] })
|
|
8298
|
+
);
|
|
8299
|
+
kv("pattern hits", /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: allHits.length ? "last 7 days" : "none in the last 7 days" }));
|
|
8300
|
+
for (const h of allHits) push2(/* @__PURE__ */ jsx2(HBar, { label: " " + truncate2(h.pattern, 10), value: h.count, max: maxHit, width: barW, color: theme.bad }));
|
|
8301
|
+
blank();
|
|
8302
|
+
section("GHOST", gh?.mode, gh?.mode === "on" ? "matching paths are hidden from agents" : "no hidden paths");
|
|
8303
|
+
const ghostPats = gh?.patterns ?? [];
|
|
8304
|
+
kv("patterns", /* @__PURE__ */ jsx2(Text2, { children: ghostPats.length ? `${ghostPats.length}` : "none" }));
|
|
8305
|
+
for (const line of wrapLines(ghostPats.join(" \xB7 "), Math.max(20, innerW - 18))) push2(/* @__PURE__ */ jsx2(Text2, { wrap: "truncate", color: theme.dim, children: " " + line }));
|
|
8306
|
+
blank();
|
|
8307
|
+
section("GUARD", guard.data ? guard.data.up_to_date ? "ok" : "stale" : "?", "the PreToolUse hook enforcing all of the above");
|
|
8308
|
+
kv(
|
|
8309
|
+
"hooks",
|
|
8310
|
+
guard.data ? /* @__PURE__ */ jsx2(Text2, { color: guard.data.up_to_date ? theme.ok : theme.warn, children: `v${guard.data.installed ?? "?"}${guard.data.up_to_date ? " (latest)" : ` \u2192 v${guard.data.latest} available`} \xB7 ${guard.data.device_count} device${guard.data.device_count === 1 ? "" : "s"}` }) : /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "loading\u2026" })
|
|
8311
|
+
);
|
|
8312
|
+
kv("local eval", ring ? /* @__PURE__ */ jsx2(Text2, { color: theme.ok, children: `avg ${ring.avgMs}ms over ${ring.count} recent calls` }) : /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "no local ring in cwd" }));
|
|
8313
|
+
const bodyRows = Math.max(4, rows - 5);
|
|
8314
|
+
const maxLScroll = Math.max(0, L.length - bodyRows);
|
|
8315
|
+
const lOff = Math.min(layersScroll, maxLScroll);
|
|
8316
|
+
const win = L.slice(lOff, lOff + bodyRows);
|
|
8317
|
+
return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", paddingX: 1, children: [
|
|
8318
|
+
titleBar,
|
|
8319
|
+
/* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
8320
|
+
/* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "white", bold: true, children: " LAYERS " }),
|
|
8321
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " security layers, limits and patterns \xB7 insights window: last 7 days" }),
|
|
8322
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2190 back" })
|
|
8323
|
+
] }),
|
|
8324
|
+
/* @__PURE__ */ jsx2(PaneTitle, { label: "LAYERS", extra: `${insights.data ? "" : spin + " loading \xB7 "}${maxLScroll ? `\u25BC${maxLScroll - lOff} more \xB7 \u2191\u2193 scroll \xB7 ` : ""}l or \u2190 back`, width: innerW }),
|
|
8325
|
+
/* @__PURE__ */ jsx2(Box2, { flexDirection: "column", height: bodyRows, overflow: "hidden", children: win }),
|
|
8326
|
+
/* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
8327
|
+
/* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "white", bold: true, children: " LAYERS " }),
|
|
8328
|
+
/* @__PURE__ */ jsx2(Text2, { backgroundColor: "#0b1530", color: "white", children: " rate limit \xB7 dlp \xB7 ghost \xB7 guard " }),
|
|
8329
|
+
/* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "white", children: " \u2191\u2193 scroll \xB7 ? all keys \xB7 \u2190 back \xB7 esc menu " })
|
|
8330
|
+
] })
|
|
8331
|
+
] });
|
|
8332
|
+
}
|
|
8104
8333
|
if (mode === "detail" && detail) {
|
|
8105
8334
|
const d = detailEntries;
|
|
8106
8335
|
const allow = d.filter((e) => e.decision === "ALLOW").length;
|
|
@@ -8220,7 +8449,7 @@ function LivePanel({ active: active2 }) {
|
|
|
8220
8449
|
] }),
|
|
8221
8450
|
/* @__PURE__ */ jsxs2(Box2, { height: colH, children: [
|
|
8222
8451
|
/* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", width: colW, marginRight: 2, overflow: "hidden", children: [
|
|
8223
|
-
/* @__PURE__ */ jsx2(PaneTitle, { label: "LAYERS", width: colW }),
|
|
8452
|
+
/* @__PURE__ */ jsx2(PaneTitle, { label: "LAYERS", extra: "l = inspect", width: colW }),
|
|
8224
8453
|
/* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
8225
8454
|
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "RATELIMIT ".padEnd(10) }),
|
|
8226
8455
|
/* @__PURE__ */ jsx2(Text2, { color: rl?.mode === "block" ? theme.ok : rl?.mode === "detect" ? theme.warn : theme.dim, children: (rl?.mode ?? "?").padEnd(7) }),
|
|
@@ -8253,7 +8482,8 @@ function LivePanel({ active: active2 }) {
|
|
|
8253
8482
|
" "
|
|
8254
8483
|
] }),
|
|
8255
8484
|
/* @__PURE__ */ jsx2(Text2, { color: st.color, children: st.label.padEnd(7) }),
|
|
8256
|
-
/* @__PURE__ */ jsx2(Text2, { color: theme.accentBright, children: truncate2(r.isMe ?
|
|
8485
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.accentBright, children: truncate2(r.agent, r.isMe ? 9 : 12).padEnd(r.isMe ? 10 : 13) }),
|
|
8486
|
+
r.isMe ? /* @__PURE__ */ jsx2(Text2, { color: theme.ok, children: "me " }) : null,
|
|
8257
8487
|
/* @__PURE__ */ jsxs2(Text2, { children: [
|
|
8258
8488
|
String(r.calls).padStart(4),
|
|
8259
8489
|
"c "
|
|
@@ -8319,7 +8549,7 @@ var init_Live = __esm({
|
|
|
8319
8549
|
SPIN = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
8320
8550
|
BG = "#12234f";
|
|
8321
8551
|
DIM_FLOOR = "#233457";
|
|
8322
|
-
RING =
|
|
8552
|
+
RING = join8(process.cwd(), ".solongate", ".eval-ring.jsonl");
|
|
8323
8553
|
hhmmss = (ts) => {
|
|
8324
8554
|
const d = new Date(ts);
|
|
8325
8555
|
return Number.isNaN(d.getTime()) ? "--:--:--" : d.toTimeString().slice(0, 8);
|
|
@@ -8348,6 +8578,7 @@ var init_Live = __esm({
|
|
|
8348
8578
|
["f", "source filter: all \u2192 local \u2192 cloud"],
|
|
8349
8579
|
["/", "live search (tool, agent, command\u2026) \xB7 enter done"],
|
|
8350
8580
|
["s", "session picker"],
|
|
8581
|
+
["l", "layers detail (rate limit \xB7 dlp \xB7 ghost \xB7 guard)"],
|
|
8351
8582
|
["e", "export visible rows \u2192 ~/.solongate/live-export.jsonl"],
|
|
8352
8583
|
["space", "copy mode: freeze screen for mouse selection"],
|
|
8353
8584
|
["esc", "back to menu"],
|
|
@@ -9008,9 +9239,9 @@ var init_Dlp = __esm({
|
|
|
9008
9239
|
// src/tui/panels/Audit.tsx
|
|
9009
9240
|
import { Box as Box6, Text as Text6, useInput as useInput5 } from "ink";
|
|
9010
9241
|
import TextInput4 from "ink-text-input";
|
|
9011
|
-
import { mkdirSync as
|
|
9012
|
-
import { homedir as
|
|
9013
|
-
import { join as
|
|
9242
|
+
import { mkdirSync as mkdirSync6, writeFileSync as writeFileSync7 } from "fs";
|
|
9243
|
+
import { homedir as homedir7 } from "os";
|
|
9244
|
+
import { join as join9 } from "path";
|
|
9014
9245
|
import { useState as useState6 } from "react";
|
|
9015
9246
|
import { Fragment as Fragment4, jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
9016
9247
|
function loadLocalRows() {
|
|
@@ -9164,16 +9395,16 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
9164
9395
|
const doExport = (kind) => {
|
|
9165
9396
|
setMsg({ text: "exporting\u2026", level: "ok" });
|
|
9166
9397
|
const run12 = async () => {
|
|
9167
|
-
const dir =
|
|
9168
|
-
const file =
|
|
9398
|
+
const dir = join9(homedir7(), ".solongate");
|
|
9399
|
+
const file = join9(dir, `audit-export-${source}.jsonl`);
|
|
9169
9400
|
let rows2;
|
|
9170
9401
|
if (kind === "page") rows2 = pageRows;
|
|
9171
9402
|
else if (source === "cloud") {
|
|
9172
9403
|
const r = await api.audit.list({ ...query, limit: 1e4, offset: 0 });
|
|
9173
9404
|
rows2 = r.entries.map(cloudRow).sort((a, b) => b.at - a.at);
|
|
9174
9405
|
} else rows2 = localFiltered;
|
|
9175
|
-
|
|
9176
|
-
|
|
9406
|
+
mkdirSync6(dir, { recursive: true });
|
|
9407
|
+
writeFileSync7(file, rows2.map((x) => JSON.stringify(x)).join("\n") + (rows2.length ? "\n" : ""));
|
|
9177
9408
|
return { n: rows2.length, file };
|
|
9178
9409
|
};
|
|
9179
9410
|
run12().then(({ n, file }) => setMsg({ text: `\u2713 exported ${n} rows \u2192 ${file}`, level: "ok" })).catch((e) => setMsg({ text: "\u2717 export failed: " + (e instanceof Error ? e.message : String(e)), level: "bad" }));
|
|
@@ -10176,9 +10407,9 @@ var tui_exports = {};
|
|
|
10176
10407
|
__export(tui_exports, {
|
|
10177
10408
|
launchTui: () => launchTui
|
|
10178
10409
|
});
|
|
10179
|
-
import { appendFileSync as appendFileSync2, mkdirSync as
|
|
10180
|
-
import { homedir as
|
|
10181
|
-
import { join as
|
|
10410
|
+
import { appendFileSync as appendFileSync2, mkdirSync as mkdirSync7 } from "fs";
|
|
10411
|
+
import { homedir as homedir8 } from "os";
|
|
10412
|
+
import { join as join10 } from "path";
|
|
10182
10413
|
import { render } from "ink";
|
|
10183
10414
|
import { jsx as jsx10 } from "react/jsx-runtime";
|
|
10184
10415
|
async function launchTui() {
|
|
@@ -10189,11 +10420,11 @@ async function launchTui() {
|
|
|
10189
10420
|
return;
|
|
10190
10421
|
}
|
|
10191
10422
|
process.stdout.write("\x1B[?1049h\x1B[H");
|
|
10192
|
-
const debugLog =
|
|
10423
|
+
const debugLog = join10(homedir8(), ".solongate", "dataroom-debug.log");
|
|
10193
10424
|
const saved = { log: console.log, warn: console.warn, error: console.error, info: console.info, debug: console.debug };
|
|
10194
10425
|
const toFile = (level) => (...args) => {
|
|
10195
10426
|
try {
|
|
10196
|
-
|
|
10427
|
+
mkdirSync7(join10(homedir8(), ".solongate"), { recursive: true });
|
|
10197
10428
|
appendFileSync2(debugLog, `${(/* @__PURE__ */ new Date()).toISOString()} [${level}] ${args.map((a) => typeof a === "string" ? a : JSON.stringify(a)).join(" ")}
|
|
10198
10429
|
`);
|
|
10199
10430
|
} catch {
|
|
@@ -10317,7 +10548,7 @@ var init_args = __esm({
|
|
|
10317
10548
|
});
|
|
10318
10549
|
|
|
10319
10550
|
// src/commands/policy.ts
|
|
10320
|
-
import { readFileSync as
|
|
10551
|
+
import { readFileSync as readFileSync8 } from "fs";
|
|
10321
10552
|
async function run(argv) {
|
|
10322
10553
|
const { positionals, flags } = parse(argv);
|
|
10323
10554
|
const sub = positionals[0];
|
|
@@ -10492,7 +10723,7 @@ function printRules(rules) {
|
|
|
10492
10723
|
}
|
|
10493
10724
|
async function resolveRules(target) {
|
|
10494
10725
|
if (target.endsWith(".json")) {
|
|
10495
|
-
const parsed = JSON.parse(
|
|
10726
|
+
const parsed = JSON.parse(readFileSync8(target, "utf-8"));
|
|
10496
10727
|
return parsed.rules ?? [];
|
|
10497
10728
|
}
|
|
10498
10729
|
const p = await api.policies.get(target);
|
|
@@ -10908,8 +11139,8 @@ var init_agents2 = __esm({
|
|
|
10908
11139
|
|
|
10909
11140
|
// src/commands/doctor.ts
|
|
10910
11141
|
import { existsSync as existsSync4, statSync as statSync2 } from "fs";
|
|
10911
|
-
import { homedir as
|
|
10912
|
-
import { join as
|
|
11142
|
+
import { homedir as homedir9 } from "os";
|
|
11143
|
+
import { join as join11 } from "path";
|
|
10913
11144
|
async function run6(argv) {
|
|
10914
11145
|
const { flags } = parse(argv);
|
|
10915
11146
|
const json = flagBool(flags, "json");
|
|
@@ -10969,19 +11200,19 @@ var init_doctor = __esm({
|
|
|
10969
11200
|
init_api_client();
|
|
10970
11201
|
init_format();
|
|
10971
11202
|
init_args();
|
|
10972
|
-
LOCAL_LOG2 =
|
|
11203
|
+
LOCAL_LOG2 = join11(homedir9(), ".solongate", "local-logs", "solongate-audit.jsonl");
|
|
10973
11204
|
}
|
|
10974
11205
|
});
|
|
10975
11206
|
|
|
10976
11207
|
// src/commands/watch.ts
|
|
10977
|
-
import { closeSync as closeSync2, existsSync as existsSync5, openSync as
|
|
10978
|
-
import { homedir as
|
|
10979
|
-
import { join as
|
|
11208
|
+
import { closeSync as closeSync2, existsSync as existsSync5, openSync as openSync3, readSync as readSync2, statSync as statSync3 } from "fs";
|
|
11209
|
+
import { homedir as homedir10 } from "os";
|
|
11210
|
+
import { join as join12 } from "path";
|
|
10980
11211
|
function tailLocal(file, maxBytes = 131072) {
|
|
10981
11212
|
try {
|
|
10982
11213
|
const size = statSync3(file).size;
|
|
10983
11214
|
const start = Math.max(0, size - maxBytes);
|
|
10984
|
-
const fd =
|
|
11215
|
+
const fd = openSync3(file, "r");
|
|
10985
11216
|
const buf = Buffer.alloc(size - start);
|
|
10986
11217
|
readSync2(fd, buf, 0, buf.length, start);
|
|
10987
11218
|
closeSync2(fd);
|
|
@@ -11083,7 +11314,7 @@ var init_watch = __esm({
|
|
|
11083
11314
|
init_cli_utils();
|
|
11084
11315
|
init_args();
|
|
11085
11316
|
init_format();
|
|
11086
|
-
LOCAL_LOG3 =
|
|
11317
|
+
LOCAL_LOG3 = join12(homedir10(), ".solongate", "local-logs", "solongate-audit.jsonl");
|
|
11087
11318
|
trunc = (s, n) => s.length <= n ? s : s.slice(0, n - 1) + "\u2026";
|
|
11088
11319
|
time = (ms) => new Date(ms).toTimeString().slice(0, 8);
|
|
11089
11320
|
}
|
|
@@ -11374,10 +11605,10 @@ var init_commands = __esm({
|
|
|
11374
11605
|
});
|
|
11375
11606
|
|
|
11376
11607
|
// src/global-install.ts
|
|
11377
|
-
import { readFileSync as
|
|
11378
|
-
import { resolve as resolve4, join as
|
|
11379
|
-
import { homedir as
|
|
11380
|
-
import { fileURLToPath } from "url";
|
|
11608
|
+
import { readFileSync as readFileSync9, writeFileSync as writeFileSync8, existsSync as existsSync6, mkdirSync as mkdirSync8 } from "fs";
|
|
11609
|
+
import { resolve as resolve4, join as join13, dirname as dirname2 } from "path";
|
|
11610
|
+
import { homedir as homedir11 } from "os";
|
|
11611
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
11381
11612
|
import { createInterface } from "readline";
|
|
11382
11613
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
11383
11614
|
function lockFile(file) {
|
|
@@ -11439,10 +11670,10 @@ function unlockFile(file) {
|
|
|
11439
11670
|
function protectedTargets() {
|
|
11440
11671
|
const p = globalPaths();
|
|
11441
11672
|
return [
|
|
11442
|
-
|
|
11443
|
-
|
|
11444
|
-
|
|
11445
|
-
|
|
11673
|
+
join13(p.hooksDir, "guard.mjs"),
|
|
11674
|
+
join13(p.hooksDir, "audit.mjs"),
|
|
11675
|
+
join13(p.hooksDir, "stop.mjs"),
|
|
11676
|
+
join13(p.hooksDir, "shield.mjs"),
|
|
11446
11677
|
p.configPath,
|
|
11447
11678
|
p.settingsPath
|
|
11448
11679
|
];
|
|
@@ -11454,26 +11685,26 @@ function unlockProtected() {
|
|
|
11454
11685
|
for (const f of protectedTargets()) unlockFile(f);
|
|
11455
11686
|
}
|
|
11456
11687
|
function globalPaths() {
|
|
11457
|
-
const home =
|
|
11458
|
-
const sgDir =
|
|
11459
|
-
const hooksDir =
|
|
11460
|
-
const claudeDir =
|
|
11688
|
+
const home = homedir11();
|
|
11689
|
+
const sgDir = join13(home, ".solongate");
|
|
11690
|
+
const hooksDir = join13(sgDir, "hooks");
|
|
11691
|
+
const claudeDir = join13(home, ".claude");
|
|
11461
11692
|
return {
|
|
11462
11693
|
home,
|
|
11463
11694
|
sgDir,
|
|
11464
11695
|
hooksDir,
|
|
11465
11696
|
claudeDir,
|
|
11466
|
-
settingsPath:
|
|
11467
|
-
backupPath:
|
|
11468
|
-
configPath:
|
|
11697
|
+
settingsPath: join13(claudeDir, "settings.json"),
|
|
11698
|
+
backupPath: join13(claudeDir, "settings.solongate.bak"),
|
|
11699
|
+
configPath: join13(sgDir, "cloud-guard.json")
|
|
11469
11700
|
};
|
|
11470
11701
|
}
|
|
11471
11702
|
function readHook(filename) {
|
|
11472
|
-
return
|
|
11703
|
+
return readFileSync9(join13(HOOKS_DIR, filename), "utf-8");
|
|
11473
11704
|
}
|
|
11474
11705
|
function readGuard() {
|
|
11475
|
-
const bundled =
|
|
11476
|
-
return existsSync6(bundled) ?
|
|
11706
|
+
const bundled = join13(HOOKS_DIR, "guard.bundled.mjs");
|
|
11707
|
+
return existsSync6(bundled) ? readFileSync9(bundled, "utf-8") : readHook("guard.mjs");
|
|
11477
11708
|
}
|
|
11478
11709
|
function ask(question) {
|
|
11479
11710
|
const rl = createInterface({ input: process.stdin, output: process.stderr });
|
|
@@ -11507,18 +11738,18 @@ function shimTargets() {
|
|
|
11507
11738
|
return [];
|
|
11508
11739
|
}
|
|
11509
11740
|
}
|
|
11510
|
-
return [".bashrc", ".zshrc", ".profile"].map((f) =>
|
|
11741
|
+
return [".bashrc", ".zshrc", ".profile"].map((f) => join13(homedir11(), f)).filter((f) => existsSync6(f));
|
|
11511
11742
|
}
|
|
11512
11743
|
function writeShimBlock(file, block2) {
|
|
11513
11744
|
const re = new RegExp(escapeRe(SHIM_BEGIN) + "[\\s\\S]*?" + escapeRe(SHIM_END) + "\\r?\\n?", "g");
|
|
11514
|
-
let content = existsSync6(file) ?
|
|
11745
|
+
let content = existsSync6(file) ? readFileSync9(file, "utf-8") : "";
|
|
11515
11746
|
content = content.replace(re, "");
|
|
11516
11747
|
if (block2) {
|
|
11517
11748
|
if (content.length && !content.endsWith("\n")) content += "\n";
|
|
11518
11749
|
content += block2 + "\n";
|
|
11519
11750
|
}
|
|
11520
|
-
|
|
11521
|
-
|
|
11751
|
+
mkdirSync8(dirname2(file), { recursive: true });
|
|
11752
|
+
writeFileSync8(file, content);
|
|
11522
11753
|
}
|
|
11523
11754
|
function installClaudeShim(shieldPath) {
|
|
11524
11755
|
const real = resolveRealClaude();
|
|
@@ -11548,7 +11779,7 @@ async function runGlobalInstall(opts = {}) {
|
|
|
11548
11779
|
let apiKey = opts.apiKey || process.env["SOLONGATE_API_KEY"] || "";
|
|
11549
11780
|
if (!apiKey || apiKey === "sg_live_your_key_here") {
|
|
11550
11781
|
try {
|
|
11551
|
-
const cfg = JSON.parse(
|
|
11782
|
+
const cfg = JSON.parse(readFileSync9(p.configPath, "utf-8"));
|
|
11552
11783
|
if (cfg && typeof cfg.apiKey === "string") apiKey = cfg.apiKey;
|
|
11553
11784
|
} catch {
|
|
11554
11785
|
}
|
|
@@ -11561,22 +11792,22 @@ async function runGlobalInstall(opts = {}) {
|
|
|
11561
11792
|
process.exit(1);
|
|
11562
11793
|
}
|
|
11563
11794
|
const apiUrl = opts.apiUrl || process.env["SOLONGATE_API_URL"] || "https://api.solongate.com";
|
|
11564
|
-
|
|
11565
|
-
|
|
11795
|
+
mkdirSync8(p.hooksDir, { recursive: true });
|
|
11796
|
+
mkdirSync8(p.claudeDir, { recursive: true });
|
|
11566
11797
|
unlockProtected();
|
|
11567
|
-
|
|
11568
|
-
|
|
11569
|
-
|
|
11570
|
-
|
|
11798
|
+
writeFileSync8(join13(p.hooksDir, "guard.mjs"), readGuard());
|
|
11799
|
+
writeFileSync8(join13(p.hooksDir, "audit.mjs"), readHook("audit.mjs"));
|
|
11800
|
+
writeFileSync8(join13(p.hooksDir, "stop.mjs"), readHook("stop.mjs"));
|
|
11801
|
+
writeFileSync8(join13(p.hooksDir, "shield.mjs"), readHook("shield.mjs"));
|
|
11571
11802
|
console.log(` Installed hooks \u2192 ${p.hooksDir}`);
|
|
11572
|
-
installClaudeShim(
|
|
11573
|
-
|
|
11803
|
+
installClaudeShim(join13(p.hooksDir, "shield.mjs"));
|
|
11804
|
+
writeFileSync8(p.configPath, JSON.stringify({ apiKey, apiUrl }, null, 2) + "\n");
|
|
11574
11805
|
console.log(` Wrote ${p.configPath}`);
|
|
11575
11806
|
let existing = {};
|
|
11576
11807
|
if (existsSync6(p.settingsPath)) {
|
|
11577
|
-
const raw =
|
|
11808
|
+
const raw = readFileSync9(p.settingsPath, "utf-8");
|
|
11578
11809
|
if (!existsSync6(p.backupPath)) {
|
|
11579
|
-
|
|
11810
|
+
writeFileSync8(p.backupPath, raw);
|
|
11580
11811
|
console.log(` Backed up existing settings \u2192 ${p.backupPath}`);
|
|
11581
11812
|
}
|
|
11582
11813
|
try {
|
|
@@ -11585,9 +11816,9 @@ async function runGlobalInstall(opts = {}) {
|
|
|
11585
11816
|
existing = {};
|
|
11586
11817
|
}
|
|
11587
11818
|
}
|
|
11588
|
-
const guardAbs =
|
|
11589
|
-
const auditAbs =
|
|
11590
|
-
const stopAbs =
|
|
11819
|
+
const guardAbs = join13(p.hooksDir, "guard.mjs").replace(/\\/g, "/");
|
|
11820
|
+
const auditAbs = join13(p.hooksDir, "audit.mjs").replace(/\\/g, "/");
|
|
11821
|
+
const stopAbs = join13(p.hooksDir, "stop.mjs").replace(/\\/g, "/");
|
|
11591
11822
|
const nodeBin = process.execPath.replace(/\\/g, "/");
|
|
11592
11823
|
const call = process.platform === "win32" ? "& " : "";
|
|
11593
11824
|
const hookCmd = (script) => `${call}"${nodeBin}" "${script}" claude-code "Claude Code"`;
|
|
@@ -11599,7 +11830,7 @@ async function runGlobalInstall(opts = {}) {
|
|
|
11599
11830
|
Stop: [{ matcher: "", hooks: [{ type: "command", command: hookCmd(stopAbs) }] }]
|
|
11600
11831
|
}
|
|
11601
11832
|
};
|
|
11602
|
-
|
|
11833
|
+
writeFileSync8(p.settingsPath, JSON.stringify(merged, null, 2) + "\n");
|
|
11603
11834
|
console.log(` Registered global hooks \u2192 ${p.settingsPath}`);
|
|
11604
11835
|
if (process.env["SOLONGATE_OS_LOCK"] === "1") {
|
|
11605
11836
|
lockProtected();
|
|
@@ -11610,7 +11841,7 @@ var __dirname, HOOKS_DIR, SHIM_BEGIN, SHIM_END;
|
|
|
11610
11841
|
var init_global_install = __esm({
|
|
11611
11842
|
"src/global-install.ts"() {
|
|
11612
11843
|
"use strict";
|
|
11613
|
-
__dirname =
|
|
11844
|
+
__dirname = dirname2(fileURLToPath2(import.meta.url));
|
|
11614
11845
|
HOOKS_DIR = resolve4(__dirname, "..", "hooks");
|
|
11615
11846
|
SHIM_BEGIN = "# >>> SolonGate shield (auto secret redaction) >>>";
|
|
11616
11847
|
SHIM_END = "# <<< SolonGate shield <<<";
|
|
@@ -11619,7 +11850,7 @@ var init_global_install = __esm({
|
|
|
11619
11850
|
|
|
11620
11851
|
// src/login.ts
|
|
11621
11852
|
var login_exports = {};
|
|
11622
|
-
import { spawn as
|
|
11853
|
+
import { spawn as spawn4 } from "child_process";
|
|
11623
11854
|
function startSpinner(text) {
|
|
11624
11855
|
if (!process.stderr.isTTY) {
|
|
11625
11856
|
process.stderr.write(` ${text}
|
|
@@ -11655,7 +11886,7 @@ function openBrowser2(url) {
|
|
|
11655
11886
|
try {
|
|
11656
11887
|
const cmd = process.platform === "win32" ? "cmd" : process.platform === "darwin" ? "open" : "xdg-open";
|
|
11657
11888
|
const args = process.platform === "win32" ? ["/c", "start", '""', url] : [url];
|
|
11658
|
-
const child =
|
|
11889
|
+
const child = spawn4(cmd, args, { stdio: "ignore", detached: true });
|
|
11659
11890
|
child.on("error", () => {
|
|
11660
11891
|
});
|
|
11661
11892
|
child.unref();
|
|
@@ -11775,13 +12006,13 @@ __export(shield_exports, {
|
|
|
11775
12006
|
});
|
|
11776
12007
|
import { createServer, request as httpRequest } from "http";
|
|
11777
12008
|
import { request as httpsRequest } from "https";
|
|
11778
|
-
import { spawn as
|
|
12009
|
+
import { spawn as spawn5 } from "child_process";
|
|
11779
12010
|
import { URL as URL2 } from "url";
|
|
11780
|
-
import { readFileSync as
|
|
12011
|
+
import { readFileSync as readFileSync10, existsSync as existsSync7, readdirSync, statSync as statSync4 } from "fs";
|
|
11781
12012
|
import { resolve as resolve5 } from "path";
|
|
11782
|
-
import { homedir as
|
|
12013
|
+
import { homedir as homedir12 } from "os";
|
|
11783
12014
|
function findCacheFile() {
|
|
11784
|
-
const dir = resolve5(
|
|
12015
|
+
const dir = resolve5(homedir12(), ".solongate");
|
|
11785
12016
|
const envSel = process.env.SOLONGATE_AGENT_ID;
|
|
11786
12017
|
if (envSel) {
|
|
11787
12018
|
const f = resolve5(dir, ".policy-cache-" + envSel.replace(/[^a-zA-Z0-9_-]/g, "_") + ".json");
|
|
@@ -11807,7 +12038,7 @@ function loadCfg() {
|
|
|
11807
12038
|
try {
|
|
11808
12039
|
const f = findCacheFile();
|
|
11809
12040
|
if (f && existsSync7(f)) {
|
|
11810
|
-
const c2 = JSON.parse(
|
|
12041
|
+
const c2 = JSON.parse(readFileSync10(f, "utf-8"));
|
|
11811
12042
|
const d = c2?.security?.dlpRedact;
|
|
11812
12043
|
const g = c2?.security?.ghost;
|
|
11813
12044
|
const ghost = g && Array.isArray(g.patterns) ? g.patterns : [];
|
|
@@ -12035,7 +12266,7 @@ async function runShield() {
|
|
|
12035
12266
|
const upstream = pickUpstream();
|
|
12036
12267
|
const { port, close } = await startProxy(upstream);
|
|
12037
12268
|
log4(`redacting secrets on the LLM path \u2192 masking before ${upstream.host} (127.0.0.1:${port})`);
|
|
12038
|
-
const child =
|
|
12269
|
+
const child = spawn5(cmd[0], cmd.slice(1), {
|
|
12039
12270
|
stdio: "inherit",
|
|
12040
12271
|
env: { ...process.env, ANTHROPIC_BASE_URL: `http://127.0.0.1:${port}` },
|
|
12041
12272
|
shell: process.platform === "win32"
|
|
@@ -12095,9 +12326,9 @@ __export(logs_server_exports, {
|
|
|
12095
12326
|
runLogsServer: () => runLogsServer
|
|
12096
12327
|
});
|
|
12097
12328
|
import { createServer as createServer2 } from "http";
|
|
12098
|
-
import { readFileSync as
|
|
12099
|
-
import { resolve as resolve6, join as
|
|
12100
|
-
import { homedir as
|
|
12329
|
+
import { readFileSync as readFileSync11, statSync as statSync5 } from "fs";
|
|
12330
|
+
import { resolve as resolve6, join as join14, isAbsolute } from "path";
|
|
12331
|
+
import { homedir as homedir13 } from "os";
|
|
12101
12332
|
import { readdirSync as readdirSync2 } from "fs";
|
|
12102
12333
|
function allowedOrigins() {
|
|
12103
12334
|
const base = [
|
|
@@ -12114,15 +12345,15 @@ function resolveLocalLogDir(rawPath) {
|
|
|
12114
12345
|
const dir = String(rawPath || "").trim().replace(/[\\/]+$/, "");
|
|
12115
12346
|
if (!dir) return null;
|
|
12116
12347
|
if (isAbsolute(dir)) return dir;
|
|
12117
|
-
return resolve6(
|
|
12348
|
+
return resolve6(homedir13(), ".solongate", "local-logs");
|
|
12118
12349
|
}
|
|
12119
12350
|
async function findLogDir() {
|
|
12120
|
-
const base = resolve6(
|
|
12351
|
+
const base = resolve6(homedir13(), ".solongate");
|
|
12121
12352
|
try {
|
|
12122
12353
|
const files = readdirSync2(base).filter((f) => f.startsWith(".policy-cache-") && f.endsWith(".json"));
|
|
12123
12354
|
for (const f of files) {
|
|
12124
12355
|
try {
|
|
12125
|
-
const c2 = JSON.parse(
|
|
12356
|
+
const c2 = JSON.parse(readFileSync11(join14(base, f), "utf-8"));
|
|
12126
12357
|
const p = c2?.security?.localLogs?.path;
|
|
12127
12358
|
if (typeof p === "string" && p.trim()) return { dir: resolveLocalLogDir(p), configured: p };
|
|
12128
12359
|
} catch {
|
|
@@ -12131,7 +12362,7 @@ async function findLogDir() {
|
|
|
12131
12362
|
} catch {
|
|
12132
12363
|
}
|
|
12133
12364
|
try {
|
|
12134
|
-
const cfgRaw =
|
|
12365
|
+
const cfgRaw = readFileSync11(join14(base, "cloud-guard.json"), "utf-8");
|
|
12135
12366
|
const { apiKey, apiUrl } = JSON.parse(cfgRaw);
|
|
12136
12367
|
if (apiKey) {
|
|
12137
12368
|
const url = `${apiUrl || "https://api.solongate.com"}/api/v1/policies/active`;
|
|
@@ -12160,7 +12391,7 @@ function setCors(req, res) {
|
|
|
12160
12391
|
}
|
|
12161
12392
|
function fileInfo(dir) {
|
|
12162
12393
|
if (!dir) return { file: null, exists: false, size: 0, mtimeMs: 0 };
|
|
12163
|
-
const file =
|
|
12394
|
+
const file = join14(dir, LOG_FILENAME);
|
|
12164
12395
|
try {
|
|
12165
12396
|
const st = statSync5(file);
|
|
12166
12397
|
return { file, exists: true, size: st.size, mtimeMs: st.mtimeMs };
|
|
@@ -12221,7 +12452,7 @@ async function runLogsServer() {
|
|
|
12221
12452
|
return;
|
|
12222
12453
|
}
|
|
12223
12454
|
try {
|
|
12224
|
-
const text =
|
|
12455
|
+
const text = readFileSync11(info.file, "utf-8");
|
|
12225
12456
|
res.writeHead(200, { "Content-Type": "text/plain; charset=utf-8", "Last-Modified": lastMod, "X-Solongate-Exists": "1" });
|
|
12226
12457
|
res.end(text);
|
|
12227
12458
|
} catch {
|
|
@@ -12273,7 +12504,7 @@ var init_logs_server = __esm({
|
|
|
12273
12504
|
|
|
12274
12505
|
// src/inject.ts
|
|
12275
12506
|
var inject_exports = {};
|
|
12276
|
-
import { readFileSync as
|
|
12507
|
+
import { readFileSync as readFileSync12, writeFileSync as writeFileSync9, existsSync as existsSync8, copyFileSync } from "fs";
|
|
12277
12508
|
import { resolve as resolve7 } from "path";
|
|
12278
12509
|
import { execSync } from "child_process";
|
|
12279
12510
|
function parseInjectArgs(argv) {
|
|
@@ -12333,7 +12564,7 @@ WHAT IT DOES
|
|
|
12333
12564
|
function detectProject() {
|
|
12334
12565
|
if (!existsSync8(resolve7("package.json"))) return false;
|
|
12335
12566
|
try {
|
|
12336
|
-
const pkg = JSON.parse(
|
|
12567
|
+
const pkg = JSON.parse(readFileSync12(resolve7("package.json"), "utf-8"));
|
|
12337
12568
|
const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
12338
12569
|
return !!(allDeps["@modelcontextprotocol/sdk"] || allDeps["@modelcontextprotocol/server"]);
|
|
12339
12570
|
} catch {
|
|
@@ -12342,7 +12573,7 @@ function detectProject() {
|
|
|
12342
12573
|
}
|
|
12343
12574
|
function findTsEntryFile() {
|
|
12344
12575
|
try {
|
|
12345
|
-
const pkg = JSON.parse(
|
|
12576
|
+
const pkg = JSON.parse(readFileSync12(resolve7("package.json"), "utf-8"));
|
|
12346
12577
|
if (pkg.bin) {
|
|
12347
12578
|
const binPath = typeof pkg.bin === "string" ? pkg.bin : Object.values(pkg.bin)[0];
|
|
12348
12579
|
if (typeof binPath === "string") {
|
|
@@ -12369,7 +12600,7 @@ function findTsEntryFile() {
|
|
|
12369
12600
|
const full = resolve7(c2);
|
|
12370
12601
|
if (existsSync8(full)) {
|
|
12371
12602
|
try {
|
|
12372
|
-
const content =
|
|
12603
|
+
const content = readFileSync12(full, "utf-8");
|
|
12373
12604
|
if (content.includes("McpServer") || content.includes("McpServer")) {
|
|
12374
12605
|
return full;
|
|
12375
12606
|
}
|
|
@@ -12389,7 +12620,7 @@ function detectPackageManager() {
|
|
|
12389
12620
|
}
|
|
12390
12621
|
function installSdk() {
|
|
12391
12622
|
try {
|
|
12392
|
-
const pkg = JSON.parse(
|
|
12623
|
+
const pkg = JSON.parse(readFileSync12(resolve7("package.json"), "utf-8"));
|
|
12393
12624
|
const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
12394
12625
|
if (allDeps["@solongate/proxy"]) {
|
|
12395
12626
|
log3(" @solongate/proxy already installed");
|
|
@@ -12410,7 +12641,7 @@ function installSdk() {
|
|
|
12410
12641
|
}
|
|
12411
12642
|
}
|
|
12412
12643
|
function injectTypeScript(filePath) {
|
|
12413
|
-
const original =
|
|
12644
|
+
const original = readFileSync12(filePath, "utf-8");
|
|
12414
12645
|
const changes = [];
|
|
12415
12646
|
let modified = original;
|
|
12416
12647
|
if (modified.includes("SecureMcpServer")) {
|
|
@@ -12581,7 +12812,7 @@ async function main2() {
|
|
|
12581
12812
|
log3("");
|
|
12582
12813
|
log3(` Backup: ${backupPath}`);
|
|
12583
12814
|
}
|
|
12584
|
-
|
|
12815
|
+
writeFileSync9(entryFile, result.modified);
|
|
12585
12816
|
log3("");
|
|
12586
12817
|
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");
|
|
12587
12818
|
log3(" \u2502 SolonGate SDK injected successfully! \u2502");
|
|
@@ -12610,8 +12841,8 @@ var init_inject = __esm({
|
|
|
12610
12841
|
|
|
12611
12842
|
// src/create.ts
|
|
12612
12843
|
var create_exports = {};
|
|
12613
|
-
import { mkdirSync as
|
|
12614
|
-
import { resolve as resolve8, join as
|
|
12844
|
+
import { mkdirSync as mkdirSync9, writeFileSync as writeFileSync10, existsSync as existsSync9 } from "fs";
|
|
12845
|
+
import { resolve as resolve8, join as join15 } from "path";
|
|
12615
12846
|
import { execSync as execSync2 } from "child_process";
|
|
12616
12847
|
function withSpinner(message, fn) {
|
|
12617
12848
|
const frames = ["\u28FE", "\u28FD", "\u28FB", "\u28BF", "\u287F", "\u28DF", "\u28EF", "\u28F7"];
|
|
@@ -12690,8 +12921,8 @@ EXAMPLES
|
|
|
12690
12921
|
`);
|
|
12691
12922
|
}
|
|
12692
12923
|
function createProject(dir, name, _policy) {
|
|
12693
|
-
|
|
12694
|
-
|
|
12924
|
+
writeFileSync10(
|
|
12925
|
+
join15(dir, "package.json"),
|
|
12695
12926
|
JSON.stringify(
|
|
12696
12927
|
{
|
|
12697
12928
|
name,
|
|
@@ -12720,8 +12951,8 @@ function createProject(dir, name, _policy) {
|
|
|
12720
12951
|
2
|
|
12721
12952
|
) + "\n"
|
|
12722
12953
|
);
|
|
12723
|
-
|
|
12724
|
-
|
|
12954
|
+
writeFileSync10(
|
|
12955
|
+
join15(dir, "tsconfig.json"),
|
|
12725
12956
|
JSON.stringify(
|
|
12726
12957
|
{
|
|
12727
12958
|
compilerOptions: {
|
|
@@ -12741,9 +12972,9 @@ function createProject(dir, name, _policy) {
|
|
|
12741
12972
|
2
|
|
12742
12973
|
) + "\n"
|
|
12743
12974
|
);
|
|
12744
|
-
|
|
12745
|
-
|
|
12746
|
-
|
|
12975
|
+
mkdirSync9(join15(dir, "src"), { recursive: true });
|
|
12976
|
+
writeFileSync10(
|
|
12977
|
+
join15(dir, "src", "index.ts"),
|
|
12747
12978
|
`#!/usr/bin/env node
|
|
12748
12979
|
|
|
12749
12980
|
console.log = (...args: unknown[]) => {
|
|
@@ -12784,8 +13015,8 @@ console.log('');
|
|
|
12784
13015
|
console.log('Press Ctrl+C to stop.');
|
|
12785
13016
|
`
|
|
12786
13017
|
);
|
|
12787
|
-
|
|
12788
|
-
|
|
13018
|
+
writeFileSync10(
|
|
13019
|
+
join15(dir, ".mcp.json"),
|
|
12789
13020
|
JSON.stringify(
|
|
12790
13021
|
{
|
|
12791
13022
|
mcpServers: {
|
|
@@ -12802,13 +13033,13 @@ console.log('Press Ctrl+C to stop.');
|
|
|
12802
13033
|
2
|
|
12803
13034
|
) + "\n"
|
|
12804
13035
|
);
|
|
12805
|
-
|
|
12806
|
-
|
|
13036
|
+
writeFileSync10(
|
|
13037
|
+
join15(dir, ".env"),
|
|
12807
13038
|
`SOLONGATE_API_KEY=sg_live_YOUR_KEY_HERE
|
|
12808
13039
|
`
|
|
12809
13040
|
);
|
|
12810
|
-
|
|
12811
|
-
|
|
13041
|
+
writeFileSync10(
|
|
13042
|
+
join15(dir, ".gitignore"),
|
|
12812
13043
|
`node_modules/
|
|
12813
13044
|
dist/
|
|
12814
13045
|
*.solongate-backup
|
|
@@ -12827,7 +13058,7 @@ async function main3() {
|
|
|
12827
13058
|
process.exit(1);
|
|
12828
13059
|
}
|
|
12829
13060
|
withSpinner(`Setting up ${opts.name}...`, () => {
|
|
12830
|
-
|
|
13061
|
+
mkdirSync9(dir, { recursive: true });
|
|
12831
13062
|
createProject(dir, opts.name, opts.policy);
|
|
12832
13063
|
});
|
|
12833
13064
|
if (!opts.noInstall) {
|
|
@@ -12901,14 +13132,14 @@ var init_create = __esm({
|
|
|
12901
13132
|
|
|
12902
13133
|
// src/pull-push.ts
|
|
12903
13134
|
var pull_push_exports = {};
|
|
12904
|
-
import { readFileSync as
|
|
13135
|
+
import { readFileSync as readFileSync13, writeFileSync as writeFileSync11, existsSync as existsSync10 } from "fs";
|
|
12905
13136
|
import { resolve as resolve9 } from "path";
|
|
12906
13137
|
function loadEnv() {
|
|
12907
13138
|
if (process.env.SOLONGATE_API_KEY) return;
|
|
12908
13139
|
const envPath = resolve9(".env");
|
|
12909
13140
|
if (!existsSync10(envPath)) return;
|
|
12910
13141
|
try {
|
|
12911
|
-
const content =
|
|
13142
|
+
const content = readFileSync13(envPath, "utf-8");
|
|
12912
13143
|
for (const line of content.split("\n")) {
|
|
12913
13144
|
const trimmed = line.trim();
|
|
12914
13145
|
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
@@ -13096,7 +13327,7 @@ async function pull(apiKey, file, policyId) {
|
|
|
13096
13327
|
const policy = await fetchCloudPolicy(apiKey, API_URL, policyId);
|
|
13097
13328
|
const { id: _id, ...policyWithoutId } = policy;
|
|
13098
13329
|
const json = JSON.stringify(policyWithoutId, null, 2) + "\n";
|
|
13099
|
-
|
|
13330
|
+
writeFileSync11(file, json, "utf-8");
|
|
13100
13331
|
log5("");
|
|
13101
13332
|
log5(green2(" Saved to: ") + file);
|
|
13102
13333
|
log5(` ${dim2("Name:")} ${policy.name}`);
|
|
@@ -13125,7 +13356,7 @@ async function push(apiKey, file, policyId) {
|
|
|
13125
13356
|
log5(" solongate-proxy list");
|
|
13126
13357
|
process.exit(1);
|
|
13127
13358
|
}
|
|
13128
|
-
const content =
|
|
13359
|
+
const content = readFileSync13(file, "utf-8");
|
|
13129
13360
|
let policy;
|
|
13130
13361
|
try {
|
|
13131
13362
|
policy = JSON.parse(content);
|
|
@@ -15285,7 +15516,7 @@ var SolonGate = class {
|
|
|
15285
15516
|
*/
|
|
15286
15517
|
startPolicyPolling() {
|
|
15287
15518
|
const apiUrl = this.config.apiUrl ?? "https://api.solongate.com";
|
|
15288
|
-
let
|
|
15519
|
+
let currentVersion2 = 0;
|
|
15289
15520
|
const timer = setInterval(async () => {
|
|
15290
15521
|
try {
|
|
15291
15522
|
const res = await fetch(`${apiUrl}/api/v1/policies/default`, {
|
|
@@ -15295,7 +15526,7 @@ var SolonGate = class {
|
|
|
15295
15526
|
if (!res.ok) return;
|
|
15296
15527
|
const data = await res.json();
|
|
15297
15528
|
const version = Number(data._version ?? 0);
|
|
15298
|
-
if (version !==
|
|
15529
|
+
if (version !== currentVersion2 && version > 0) {
|
|
15299
15530
|
const policySet = {
|
|
15300
15531
|
id: String(data.id ?? "cloud"),
|
|
15301
15532
|
name: String(data.name ?? "Cloud Policy"),
|
|
@@ -15307,7 +15538,7 @@ var SolonGate = class {
|
|
|
15307
15538
|
};
|
|
15308
15539
|
this.policyEngine.loadPolicySet(policySet);
|
|
15309
15540
|
await this.loadCloudWasm(apiUrl, policySet.id);
|
|
15310
|
-
|
|
15541
|
+
currentVersion2 = version;
|
|
15311
15542
|
}
|
|
15312
15543
|
} catch {
|
|
15313
15544
|
}
|
|
@@ -16275,6 +16506,12 @@ function printWelcome() {
|
|
|
16275
16506
|
}
|
|
16276
16507
|
async function main5() {
|
|
16277
16508
|
const subcommand = process.argv[2];
|
|
16509
|
+
if (IS_HUMAN_CLI) {
|
|
16510
|
+
const tuiBound = subcommand === "dataroom" || process.argv.length <= 2 && process.stdout.isTTY && process.stdin.isTTY;
|
|
16511
|
+
const { maybeSelfUpdate: maybeSelfUpdate2 } = await Promise.resolve().then(() => (init_self_update(), self_update_exports));
|
|
16512
|
+
maybeSelfUpdate2(tuiBound ? () => {
|
|
16513
|
+
} : void 0);
|
|
16514
|
+
}
|
|
16278
16515
|
if (process.argv.length <= 2) {
|
|
16279
16516
|
if (process.stdout.isTTY && process.stdin.isTTY) {
|
|
16280
16517
|
const { launchTui: launchTui2 } = await Promise.resolve().then(() => (init_tui(), tui_exports));
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export declare function currentVersion(): string;
|
|
2
|
+
/**
|
|
3
|
+
* Fire-and-forget startup hook. `notify` writes the human-facing one-liner —
|
|
4
|
+
* callers pass a stderr writer so the notice never lands in piped stdout.
|
|
5
|
+
*/
|
|
6
|
+
export declare function maybeSelfUpdate(notify?: (line: string) => void): void;
|
package/dist/tui/index.js
CHANGED
|
@@ -920,6 +920,7 @@ var LIVE_HELP = [
|
|
|
920
920
|
["f", "source filter: all \u2192 local \u2192 cloud"],
|
|
921
921
|
["/", "live search (tool, agent, command\u2026) \xB7 enter done"],
|
|
922
922
|
["s", "session picker"],
|
|
923
|
+
["l", "layers detail (rate limit \xB7 dlp \xB7 ghost \xB7 guard)"],
|
|
923
924
|
["e", "export visible rows \u2192 ~/.solongate/live-export.jsonl"],
|
|
924
925
|
["space", "copy mode: freeze screen for mouse selection"],
|
|
925
926
|
["esc", "back to menu"],
|
|
@@ -970,6 +971,7 @@ function LivePanel({ active: active2 }) {
|
|
|
970
971
|
const [detailScroll, setDetailScroll] = useState2(0);
|
|
971
972
|
const [inspect, setInspect] = useState2(null);
|
|
972
973
|
const [inspectScroll, setInspectScroll] = useState2(0);
|
|
974
|
+
const [layersScroll, setLayersScroll] = useState2(0);
|
|
973
975
|
const inspectFromRef = useRef2("stream");
|
|
974
976
|
const seenRef = useRef2(/* @__PURE__ */ new Set());
|
|
975
977
|
const lastLocalTs = useRef2(0);
|
|
@@ -1369,6 +1371,14 @@ function LivePanel({ active: active2 }) {
|
|
|
1369
1371
|
else if (key.pageDown) setInspectScroll((n) => n + 10);
|
|
1370
1372
|
return;
|
|
1371
1373
|
}
|
|
1374
|
+
if (mode === "layers") {
|
|
1375
|
+
if (key.leftArrow || input === "l") setMode("stream");
|
|
1376
|
+
else if (key.upArrow) setLayersScroll((n) => Math.max(0, n - 1));
|
|
1377
|
+
else if (key.downArrow) setLayersScroll((n) => n + 1);
|
|
1378
|
+
else if (key.pageUp) setLayersScroll((n) => Math.max(0, n - 10));
|
|
1379
|
+
else if (key.pageDown) setLayersScroll((n) => n + 10);
|
|
1380
|
+
return;
|
|
1381
|
+
}
|
|
1372
1382
|
if (mode === "detail") {
|
|
1373
1383
|
const maxD = Math.max(0, detailEntries.length - 1);
|
|
1374
1384
|
if (key.leftArrow) {
|
|
@@ -1418,6 +1428,9 @@ function LivePanel({ active: active2 }) {
|
|
|
1418
1428
|
} else if (input === "s") {
|
|
1419
1429
|
setPickIdx(0);
|
|
1420
1430
|
setMode("pick");
|
|
1431
|
+
} else if (input === "l") {
|
|
1432
|
+
setLayersScroll(0);
|
|
1433
|
+
setMode("layers");
|
|
1421
1434
|
} else if (input === "w") void doAction("whitelist");
|
|
1422
1435
|
else if (input === "b") void doAction("block");
|
|
1423
1436
|
else if (input === "d") toggleSignal("deny");
|
|
@@ -1537,6 +1550,87 @@ function LivePanel({ active: active2 }) {
|
|
|
1537
1550
|
] })
|
|
1538
1551
|
] });
|
|
1539
1552
|
}
|
|
1553
|
+
if (mode === "layers") {
|
|
1554
|
+
const modeColor2 = (m) => m === "block" || m === "on" ? theme.ok : m === "detect" ? theme.warn : theme.dim;
|
|
1555
|
+
const barW = Math.max(10, Math.min(40, innerW - 30));
|
|
1556
|
+
const burstsInBuf = mergedAll.filter((e) => e.burst).length;
|
|
1557
|
+
const dlpInBuf = mergedAll.filter((e) => e.dlp).length;
|
|
1558
|
+
const allHits = ins.dlpByPattern ?? [];
|
|
1559
|
+
const maxHit = allHits[0]?.count ?? 1;
|
|
1560
|
+
const L = [];
|
|
1561
|
+
const push = (el) => L.push(/* @__PURE__ */ jsx2(Box2, { children: el }, L.length));
|
|
1562
|
+
const blank = () => push(/* @__PURE__ */ jsx2(Text2, { children: " " }));
|
|
1563
|
+
const section = (label, m, note) => push(
|
|
1564
|
+
/* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
1565
|
+
/* @__PURE__ */ jsxs2(Text2, { bold: true, color: theme.accentBright, children: [
|
|
1566
|
+
"\u258E",
|
|
1567
|
+
label.padEnd(10)
|
|
1568
|
+
] }),
|
|
1569
|
+
/* @__PURE__ */ jsx2(Text2, { bold: true, color: modeColor2(m), children: (m ?? "?").padEnd(8) }),
|
|
1570
|
+
note ? /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: note }) : null
|
|
1571
|
+
] })
|
|
1572
|
+
);
|
|
1573
|
+
const kv = (k, v) => push(
|
|
1574
|
+
/* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
1575
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: (" " + k).padEnd(16) }),
|
|
1576
|
+
v
|
|
1577
|
+
] })
|
|
1578
|
+
);
|
|
1579
|
+
section("RATELIMIT", rl?.mode, rl?.mode === "block" ? "over-limit calls are DENIED" : rl?.mode === "detect" ? "over-limit calls are observed & flagged rl:yes" : "no limit enforcement");
|
|
1580
|
+
kv("limits", /* @__PURE__ */ jsx2(Text2, { children: rl?.perMinute || rl?.perHour || rl?.perDay ? `${rl?.perMinute || "\u2014"}/min \xB7 ${rl?.perHour || "\u2014"}/hour \xB7 ${rl?.perDay || "\u2014"}/day` : "none configured" }));
|
|
1581
|
+
kv("load now", /* @__PURE__ */ jsx2(Text2, { children: `${minuteNow} calls in the last 60s` }));
|
|
1582
|
+
if (rl?.perMinute) push(/* @__PURE__ */ jsx2(HBar, { label: " load/min", value: minuteNow, max: rl.perMinute, width: barW, color: minuteNow > rl.perMinute ? theme.bad : theme.accent }));
|
|
1583
|
+
kv("bursts", /* @__PURE__ */ jsx2(Text2, { color: burstsInBuf ? theme.warn : theme.dim, children: `${burstsInBuf} flagged in the live buffer` }));
|
|
1584
|
+
blank();
|
|
1585
|
+
section("DLP", dl?.mode, dl?.mode === "block" ? "secrets in arguments are DENIED + redacted" : dl?.mode === "detect" ? "secrets observed & flagged dlp:yes, output redacted" : "no secret scanning");
|
|
1586
|
+
kv("hits", /* @__PURE__ */ jsx2(Text2, { color: dlpInBuf ? theme.bad : theme.dim, children: `${dlpInBuf} flagged in the live buffer` }));
|
|
1587
|
+
const builtin = dl?.patterns ?? [];
|
|
1588
|
+
kv("builtin", /* @__PURE__ */ jsx2(Text2, { children: builtin.length ? `${builtin.length} patterns enabled` : "none enabled" }));
|
|
1589
|
+
for (const line of wrapLines(builtin.join(" \xB7 "), Math.max(20, innerW - 18))) push(/* @__PURE__ */ jsx2(Text2, { wrap: "truncate", color: theme.dim, children: " " + line }));
|
|
1590
|
+
const custom = dl?.custom ?? [];
|
|
1591
|
+
kv("custom", /* @__PURE__ */ jsx2(Text2, { children: custom.length ? `${custom.length} patterns` : "none" }));
|
|
1592
|
+
for (const c2 of custom)
|
|
1593
|
+
push(
|
|
1594
|
+
/* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
1595
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " " }),
|
|
1596
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.accent, children: truncate(c2.name ?? "custom", 24).padEnd(25) }),
|
|
1597
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: truncate(c2.re ?? "", Math.max(10, innerW - 44)) })
|
|
1598
|
+
] })
|
|
1599
|
+
);
|
|
1600
|
+
kv("pattern hits", /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: allHits.length ? "last 7 days" : "none in the last 7 days" }));
|
|
1601
|
+
for (const h of allHits) push(/* @__PURE__ */ jsx2(HBar, { label: " " + truncate(h.pattern, 10), value: h.count, max: maxHit, width: barW, color: theme.bad }));
|
|
1602
|
+
blank();
|
|
1603
|
+
section("GHOST", gh?.mode, gh?.mode === "on" ? "matching paths are hidden from agents" : "no hidden paths");
|
|
1604
|
+
const ghostPats = gh?.patterns ?? [];
|
|
1605
|
+
kv("patterns", /* @__PURE__ */ jsx2(Text2, { children: ghostPats.length ? `${ghostPats.length}` : "none" }));
|
|
1606
|
+
for (const line of wrapLines(ghostPats.join(" \xB7 "), Math.max(20, innerW - 18))) push(/* @__PURE__ */ jsx2(Text2, { wrap: "truncate", color: theme.dim, children: " " + line }));
|
|
1607
|
+
blank();
|
|
1608
|
+
section("GUARD", guard.data ? guard.data.up_to_date ? "ok" : "stale" : "?", "the PreToolUse hook enforcing all of the above");
|
|
1609
|
+
kv(
|
|
1610
|
+
"hooks",
|
|
1611
|
+
guard.data ? /* @__PURE__ */ jsx2(Text2, { color: guard.data.up_to_date ? theme.ok : theme.warn, children: `v${guard.data.installed ?? "?"}${guard.data.up_to_date ? " (latest)" : ` \u2192 v${guard.data.latest} available`} \xB7 ${guard.data.device_count} device${guard.data.device_count === 1 ? "" : "s"}` }) : /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "loading\u2026" })
|
|
1612
|
+
);
|
|
1613
|
+
kv("local eval", ring ? /* @__PURE__ */ jsx2(Text2, { color: theme.ok, children: `avg ${ring.avgMs}ms over ${ring.count} recent calls` }) : /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "no local ring in cwd" }));
|
|
1614
|
+
const bodyRows = Math.max(4, rows - 5);
|
|
1615
|
+
const maxLScroll = Math.max(0, L.length - bodyRows);
|
|
1616
|
+
const lOff = Math.min(layersScroll, maxLScroll);
|
|
1617
|
+
const win = L.slice(lOff, lOff + bodyRows);
|
|
1618
|
+
return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", paddingX: 1, children: [
|
|
1619
|
+
titleBar,
|
|
1620
|
+
/* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
1621
|
+
/* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "white", bold: true, children: " LAYERS " }),
|
|
1622
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " security layers, limits and patterns \xB7 insights window: last 7 days" }),
|
|
1623
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " \u2190 back" })
|
|
1624
|
+
] }),
|
|
1625
|
+
/* @__PURE__ */ jsx2(PaneTitle, { label: "LAYERS", extra: `${insights.data ? "" : spin + " loading \xB7 "}${maxLScroll ? `\u25BC${maxLScroll - lOff} more \xB7 \u2191\u2193 scroll \xB7 ` : ""}l or \u2190 back`, width: innerW }),
|
|
1626
|
+
/* @__PURE__ */ jsx2(Box2, { flexDirection: "column", height: bodyRows, overflow: "hidden", children: win }),
|
|
1627
|
+
/* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
1628
|
+
/* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "white", bold: true, children: " LAYERS " }),
|
|
1629
|
+
/* @__PURE__ */ jsx2(Text2, { backgroundColor: "#0b1530", color: "white", children: " rate limit \xB7 dlp \xB7 ghost \xB7 guard " }),
|
|
1630
|
+
/* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "white", children: " \u2191\u2193 scroll \xB7 ? all keys \xB7 \u2190 back \xB7 esc menu " })
|
|
1631
|
+
] })
|
|
1632
|
+
] });
|
|
1633
|
+
}
|
|
1540
1634
|
if (mode === "detail" && detail) {
|
|
1541
1635
|
const d = detailEntries;
|
|
1542
1636
|
const allow = d.filter((e) => e.decision === "ALLOW").length;
|
|
@@ -1656,7 +1750,7 @@ function LivePanel({ active: active2 }) {
|
|
|
1656
1750
|
] }),
|
|
1657
1751
|
/* @__PURE__ */ jsxs2(Box2, { height: colH, children: [
|
|
1658
1752
|
/* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", width: colW, marginRight: 2, overflow: "hidden", children: [
|
|
1659
|
-
/* @__PURE__ */ jsx2(PaneTitle, { label: "LAYERS", width: colW }),
|
|
1753
|
+
/* @__PURE__ */ jsx2(PaneTitle, { label: "LAYERS", extra: "l = inspect", width: colW }),
|
|
1660
1754
|
/* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
1661
1755
|
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: "RATELIMIT ".padEnd(10) }),
|
|
1662
1756
|
/* @__PURE__ */ jsx2(Text2, { color: rl?.mode === "block" ? theme.ok : rl?.mode === "detect" ? theme.warn : theme.dim, children: (rl?.mode ?? "?").padEnd(7) }),
|
|
@@ -1689,7 +1783,8 @@ function LivePanel({ active: active2 }) {
|
|
|
1689
1783
|
" "
|
|
1690
1784
|
] }),
|
|
1691
1785
|
/* @__PURE__ */ jsx2(Text2, { color: st.color, children: st.label.padEnd(7) }),
|
|
1692
|
-
/* @__PURE__ */ jsx2(Text2, { color: theme.accentBright, children: truncate(r.isMe ?
|
|
1786
|
+
/* @__PURE__ */ jsx2(Text2, { color: theme.accentBright, children: truncate(r.agent, r.isMe ? 9 : 12).padEnd(r.isMe ? 10 : 13) }),
|
|
1787
|
+
r.isMe ? /* @__PURE__ */ jsx2(Text2, { color: theme.ok, children: "me " }) : null,
|
|
1693
1788
|
/* @__PURE__ */ jsxs2(Text2, { children: [
|
|
1694
1789
|
String(r.calls).padStart(4),
|
|
1695
1790
|
"c "
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@solongate/proxy",
|
|
3
|
-
"version": "0.81.
|
|
3
|
+
"version": "0.81.46",
|
|
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": {
|