@solongate/proxy 0.82.42 → 0.82.44
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 +617 -386
- package/dist/logs-server.js +4 -1
- package/dist/self-update.d.ts +7 -0
- package/dist/tui/index.js +934 -920
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -6187,6 +6187,476 @@ var init_cli_utils = __esm({
|
|
|
6187
6187
|
}
|
|
6188
6188
|
});
|
|
6189
6189
|
|
|
6190
|
+
// src/global-install.ts
|
|
6191
|
+
var global_install_exports = {};
|
|
6192
|
+
__export(global_install_exports, {
|
|
6193
|
+
clearGuardUpdateCheck: () => clearGuardUpdateCheck,
|
|
6194
|
+
globalPaths: () => globalPaths,
|
|
6195
|
+
guardHookOutdated: () => guardHookOutdated,
|
|
6196
|
+
installClaudeShim: () => installClaudeShim,
|
|
6197
|
+
installGlobalQuiet: () => installGlobalQuiet,
|
|
6198
|
+
installGlobalWithKey: () => installGlobalWithKey,
|
|
6199
|
+
installedGuardVersion: () => installedGuardVersion,
|
|
6200
|
+
isGuardInstalled: () => isGuardInstalled,
|
|
6201
|
+
lockProtected: () => lockProtected,
|
|
6202
|
+
removeClaudeShim: () => removeClaudeShim,
|
|
6203
|
+
runGlobalInstall: () => runGlobalInstall,
|
|
6204
|
+
runGlobalRestore: () => runGlobalRestore,
|
|
6205
|
+
uninstallGlobalQuiet: () => uninstallGlobalQuiet,
|
|
6206
|
+
unlockProtected: () => unlockProtected
|
|
6207
|
+
});
|
|
6208
|
+
import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, existsSync as existsSync3, mkdirSync as mkdirSync3, rmSync as rmSync2 } from "fs";
|
|
6209
|
+
import { resolve as resolve3, join as join4, dirname } from "path";
|
|
6210
|
+
import { homedir as homedir2 } from "os";
|
|
6211
|
+
import { fileURLToPath } from "url";
|
|
6212
|
+
import { createInterface } from "readline";
|
|
6213
|
+
import { execFileSync as execFileSync2 } from "child_process";
|
|
6214
|
+
function lockFile(file) {
|
|
6215
|
+
if (!existsSync3(file)) return;
|
|
6216
|
+
try {
|
|
6217
|
+
if (process.platform === "win32") {
|
|
6218
|
+
try {
|
|
6219
|
+
execFileSync2("icacls", [file, "/deny", "*S-1-1-0:(WD,AD,DC,DE)"], { stdio: "ignore" });
|
|
6220
|
+
} catch {
|
|
6221
|
+
}
|
|
6222
|
+
try {
|
|
6223
|
+
execFileSync2("attrib", ["+R", file], { stdio: "ignore" });
|
|
6224
|
+
} catch {
|
|
6225
|
+
}
|
|
6226
|
+
} else if (process.platform === "darwin") {
|
|
6227
|
+
try {
|
|
6228
|
+
execFileSync2("chflags", ["uchg", file], { stdio: "ignore" });
|
|
6229
|
+
} catch {
|
|
6230
|
+
}
|
|
6231
|
+
} else {
|
|
6232
|
+
try {
|
|
6233
|
+
execFileSync2("chattr", ["+i", file], { stdio: "ignore" });
|
|
6234
|
+
} catch {
|
|
6235
|
+
}
|
|
6236
|
+
}
|
|
6237
|
+
} catch {
|
|
6238
|
+
}
|
|
6239
|
+
}
|
|
6240
|
+
function unlockFile(file) {
|
|
6241
|
+
if (!existsSync3(file)) return;
|
|
6242
|
+
try {
|
|
6243
|
+
if (process.platform === "win32") {
|
|
6244
|
+
try {
|
|
6245
|
+
execFileSync2("icacls", [file, "/remove:d", "*S-1-1-0"], { stdio: "ignore" });
|
|
6246
|
+
} catch {
|
|
6247
|
+
}
|
|
6248
|
+
try {
|
|
6249
|
+
execFileSync2("icacls", [file, "/reset"], { stdio: "ignore" });
|
|
6250
|
+
} catch {
|
|
6251
|
+
}
|
|
6252
|
+
try {
|
|
6253
|
+
execFileSync2("attrib", ["-R", file], { stdio: "ignore" });
|
|
6254
|
+
} catch {
|
|
6255
|
+
}
|
|
6256
|
+
} else if (process.platform === "darwin") {
|
|
6257
|
+
try {
|
|
6258
|
+
execFileSync2("chflags", ["nouchg", file], { stdio: "ignore" });
|
|
6259
|
+
} catch {
|
|
6260
|
+
}
|
|
6261
|
+
} else {
|
|
6262
|
+
try {
|
|
6263
|
+
execFileSync2("chattr", ["-i", file], { stdio: "ignore" });
|
|
6264
|
+
} catch {
|
|
6265
|
+
}
|
|
6266
|
+
}
|
|
6267
|
+
} catch {
|
|
6268
|
+
}
|
|
6269
|
+
}
|
|
6270
|
+
function protectedTargets() {
|
|
6271
|
+
const p = globalPaths();
|
|
6272
|
+
return [
|
|
6273
|
+
join4(p.hooksDir, "guard.mjs"),
|
|
6274
|
+
join4(p.hooksDir, "audit.mjs"),
|
|
6275
|
+
join4(p.hooksDir, "stop.mjs"),
|
|
6276
|
+
join4(p.hooksDir, "shield.mjs"),
|
|
6277
|
+
p.configPath,
|
|
6278
|
+
p.settingsPath,
|
|
6279
|
+
p.antigravityHooksPath
|
|
6280
|
+
];
|
|
6281
|
+
}
|
|
6282
|
+
function lockProtected() {
|
|
6283
|
+
for (const f of protectedTargets()) lockFile(f);
|
|
6284
|
+
}
|
|
6285
|
+
function unlockProtected() {
|
|
6286
|
+
for (const f of protectedTargets()) unlockFile(f);
|
|
6287
|
+
}
|
|
6288
|
+
function globalPaths() {
|
|
6289
|
+
const home = homedir2();
|
|
6290
|
+
const sgDir = join4(home, ".solongate");
|
|
6291
|
+
const hooksDir = join4(sgDir, "hooks");
|
|
6292
|
+
const claudeDir = join4(home, ".claude");
|
|
6293
|
+
const antigravityDir = join4(home, ".gemini", "config");
|
|
6294
|
+
return {
|
|
6295
|
+
home,
|
|
6296
|
+
sgDir,
|
|
6297
|
+
hooksDir,
|
|
6298
|
+
claudeDir,
|
|
6299
|
+
antigravityDir,
|
|
6300
|
+
settingsPath: join4(claudeDir, "settings.json"),
|
|
6301
|
+
backupPath: join4(claudeDir, "settings.solongate.bak"),
|
|
6302
|
+
configPath: join4(sgDir, "cloud-guard.json"),
|
|
6303
|
+
// Antigravity reads global hooks from ~/.gemini/config/hooks.json. Only the
|
|
6304
|
+
// guard is registered there (PreToolUse); Antigravity's ALLOW-path audit is
|
|
6305
|
+
// covered by the passive session-log collector, not a hook.
|
|
6306
|
+
antigravityHooksPath: join4(antigravityDir, "hooks.json"),
|
|
6307
|
+
antigravityBackupPath: join4(antigravityDir, "hooks.solongate.bak")
|
|
6308
|
+
};
|
|
6309
|
+
}
|
|
6310
|
+
function clearGuardUpdateCheck() {
|
|
6311
|
+
try {
|
|
6312
|
+
rmSync2(join4(globalPaths().sgDir, ".hook-update-check"), { force: true });
|
|
6313
|
+
return true;
|
|
6314
|
+
} catch {
|
|
6315
|
+
return false;
|
|
6316
|
+
}
|
|
6317
|
+
}
|
|
6318
|
+
function readHook(filename) {
|
|
6319
|
+
return readFileSync4(join4(HOOKS_DIR, filename), "utf-8");
|
|
6320
|
+
}
|
|
6321
|
+
function firstAccountCredential() {
|
|
6322
|
+
try {
|
|
6323
|
+
const raw = JSON.parse(readFileSync4(join4(homedir2(), ".solongate", "accounts.json"), "utf-8"));
|
|
6324
|
+
if (Array.isArray(raw)) {
|
|
6325
|
+
const acc = raw.find((a) => a && typeof a.apiKey === "string" && a.apiKey);
|
|
6326
|
+
if (acc) return { apiKey: acc.apiKey, apiUrl: typeof acc.apiUrl === "string" ? acc.apiUrl : void 0 };
|
|
6327
|
+
}
|
|
6328
|
+
} catch {
|
|
6329
|
+
}
|
|
6330
|
+
return {};
|
|
6331
|
+
}
|
|
6332
|
+
function readGuard() {
|
|
6333
|
+
const bundled = join4(HOOKS_DIR, "guard.bundled.mjs");
|
|
6334
|
+
return existsSync3(bundled) ? readFileSync4(bundled, "utf-8") : readHook("guard.mjs");
|
|
6335
|
+
}
|
|
6336
|
+
function antigravityHookCommand(guardAbs) {
|
|
6337
|
+
const nodeBin = process.execPath.replace(/\\/g, "/");
|
|
6338
|
+
const call = process.platform === "win32" ? "& " : "";
|
|
6339
|
+
return `${call}"${nodeBin}" "${guardAbs.replace(/\\/g, "/")}" antigravity "Antigravity"`;
|
|
6340
|
+
}
|
|
6341
|
+
function installAntigravityGuard(p, guardAbs) {
|
|
6342
|
+
mkdirSync3(p.antigravityDir, { recursive: true });
|
|
6343
|
+
let existing = {};
|
|
6344
|
+
if (existsSync3(p.antigravityHooksPath)) {
|
|
6345
|
+
const raw = readFileSync4(p.antigravityHooksPath, "utf-8");
|
|
6346
|
+
if (!existsSync3(p.antigravityBackupPath)) writeFileSync3(p.antigravityBackupPath, raw);
|
|
6347
|
+
try {
|
|
6348
|
+
existing = JSON.parse(raw);
|
|
6349
|
+
} catch {
|
|
6350
|
+
existing = {};
|
|
6351
|
+
}
|
|
6352
|
+
}
|
|
6353
|
+
const merged = {
|
|
6354
|
+
...existing,
|
|
6355
|
+
[ANTIGRAVITY_GROUP]: {
|
|
6356
|
+
PreToolUse: [{ matcher: "", hooks: [{ type: "command", command: antigravityHookCommand(guardAbs) }] }]
|
|
6357
|
+
}
|
|
6358
|
+
};
|
|
6359
|
+
writeFileSync3(p.antigravityHooksPath, JSON.stringify(merged, null, 2) + "\n");
|
|
6360
|
+
}
|
|
6361
|
+
function removeAntigravityGuard(p) {
|
|
6362
|
+
if (!existsSync3(p.antigravityHooksPath)) return;
|
|
6363
|
+
try {
|
|
6364
|
+
const s = JSON.parse(readFileSync4(p.antigravityHooksPath, "utf-8"));
|
|
6365
|
+
if (!(ANTIGRAVITY_GROUP in s)) return;
|
|
6366
|
+
delete s[ANTIGRAVITY_GROUP];
|
|
6367
|
+
writeFileSync3(p.antigravityHooksPath, JSON.stringify(s, null, 2) + "\n");
|
|
6368
|
+
} catch {
|
|
6369
|
+
}
|
|
6370
|
+
}
|
|
6371
|
+
function ask(question) {
|
|
6372
|
+
const rl = createInterface({ input: process.stdin, output: process.stderr });
|
|
6373
|
+
return new Promise((res) => rl.question(question, (a) => {
|
|
6374
|
+
rl.close();
|
|
6375
|
+
res(a.trim());
|
|
6376
|
+
}));
|
|
6377
|
+
}
|
|
6378
|
+
function runGlobalRestore() {
|
|
6379
|
+
const p = globalPaths();
|
|
6380
|
+
unlockProtected();
|
|
6381
|
+
removeClaudeShim();
|
|
6382
|
+
removeAntigravityGuard(p);
|
|
6383
|
+
if (existsSync3(p.backupPath)) {
|
|
6384
|
+
writeFileSync3(p.settingsPath, readFileSync4(p.backupPath, "utf-8"));
|
|
6385
|
+
console.log(` Restored ${p.settingsPath} from backup.`);
|
|
6386
|
+
} else if (existsSync3(p.settingsPath)) {
|
|
6387
|
+
try {
|
|
6388
|
+
const s = JSON.parse(readFileSync4(p.settingsPath, "utf-8"));
|
|
6389
|
+
delete s.hooks;
|
|
6390
|
+
writeFileSync3(p.settingsPath, JSON.stringify(s, null, 2) + "\n");
|
|
6391
|
+
console.log(` Removed SolonGate hooks from ${p.settingsPath}.`);
|
|
6392
|
+
} catch {
|
|
6393
|
+
}
|
|
6394
|
+
} else {
|
|
6395
|
+
console.log(" Nothing to restore \u2014 no global Claude Code settings found.");
|
|
6396
|
+
}
|
|
6397
|
+
console.log(" Global SolonGate enforcement uninstalled. Restart Claude Code.");
|
|
6398
|
+
}
|
|
6399
|
+
function installGlobalQuiet() {
|
|
6400
|
+
try {
|
|
6401
|
+
const p = globalPaths();
|
|
6402
|
+
let apiKey = process.env["SOLONGATE_API_KEY"] || "";
|
|
6403
|
+
let apiUrl = process.env["SOLONGATE_API_URL"] || "https://api.solongate.com";
|
|
6404
|
+
try {
|
|
6405
|
+
const cfg = JSON.parse(readFileSync4(p.configPath, "utf-8"));
|
|
6406
|
+
if (cfg && typeof cfg.apiKey === "string") apiKey = apiKey || cfg.apiKey;
|
|
6407
|
+
if (cfg && typeof cfg.apiUrl === "string") apiUrl = cfg.apiUrl;
|
|
6408
|
+
} catch {
|
|
6409
|
+
}
|
|
6410
|
+
if (!apiKey) {
|
|
6411
|
+
const acc = firstAccountCredential();
|
|
6412
|
+
if (acc.apiKey) {
|
|
6413
|
+
apiKey = acc.apiKey;
|
|
6414
|
+
if (acc.apiUrl) apiUrl = acc.apiUrl;
|
|
6415
|
+
}
|
|
6416
|
+
}
|
|
6417
|
+
if (!apiKey) return { ok: false, message: "no login on this device \u2014 add an account first (Accounts \u2192 + add)" };
|
|
6418
|
+
mkdirSync3(p.hooksDir, { recursive: true });
|
|
6419
|
+
mkdirSync3(p.claudeDir, { recursive: true });
|
|
6420
|
+
unlockProtected();
|
|
6421
|
+
writeFileSync3(join4(p.hooksDir, "guard.mjs"), readGuard());
|
|
6422
|
+
writeFileSync3(join4(p.hooksDir, "audit.mjs"), readHook("audit.mjs"));
|
|
6423
|
+
writeFileSync3(join4(p.hooksDir, "stop.mjs"), readHook("stop.mjs"));
|
|
6424
|
+
writeFileSync3(join4(p.hooksDir, "shield.mjs"), readHook("shield.mjs"));
|
|
6425
|
+
writeFileSync3(p.configPath, JSON.stringify({ apiKey, apiUrl }, null, 2) + "\n");
|
|
6426
|
+
let existing = {};
|
|
6427
|
+
if (existsSync3(p.settingsPath)) {
|
|
6428
|
+
const raw = readFileSync4(p.settingsPath, "utf-8");
|
|
6429
|
+
if (!existsSync3(p.backupPath)) writeFileSync3(p.backupPath, raw);
|
|
6430
|
+
try {
|
|
6431
|
+
existing = JSON.parse(raw);
|
|
6432
|
+
} catch {
|
|
6433
|
+
existing = {};
|
|
6434
|
+
}
|
|
6435
|
+
}
|
|
6436
|
+
const nodeBin = process.execPath.replace(/\\/g, "/");
|
|
6437
|
+
const call = process.platform === "win32" ? "& " : "";
|
|
6438
|
+
const hookCmd = (script) => `${call}"${nodeBin}" "${join4(p.hooksDir, script).replace(/\\/g, "/")}" claude-code "Claude Code"`;
|
|
6439
|
+
const merged = {
|
|
6440
|
+
...existing,
|
|
6441
|
+
hooks: {
|
|
6442
|
+
PreToolUse: [{ matcher: "", hooks: [{ type: "command", command: hookCmd("guard.mjs") }] }],
|
|
6443
|
+
PostToolUse: [{ matcher: "", hooks: [{ type: "command", command: hookCmd("audit.mjs") }] }],
|
|
6444
|
+
Stop: [{ matcher: "", hooks: [{ type: "command", command: hookCmd("stop.mjs") }] }]
|
|
6445
|
+
}
|
|
6446
|
+
};
|
|
6447
|
+
writeFileSync3(p.settingsPath, JSON.stringify(merged, null, 2) + "\n");
|
|
6448
|
+
try {
|
|
6449
|
+
installAntigravityGuard(p, join4(p.hooksDir, "guard.mjs").replace(/\\/g, "/"));
|
|
6450
|
+
} catch {
|
|
6451
|
+
}
|
|
6452
|
+
if (process.env["SOLONGATE_OS_LOCK"] === "1") lockProtected();
|
|
6453
|
+
return { ok: true, message: "guard installed (open a new session)" };
|
|
6454
|
+
} catch (e) {
|
|
6455
|
+
return { ok: false, message: e instanceof Error ? e.message : String(e) };
|
|
6456
|
+
}
|
|
6457
|
+
}
|
|
6458
|
+
function installedGuardVersion() {
|
|
6459
|
+
try {
|
|
6460
|
+
const p = globalPaths();
|
|
6461
|
+
const s = readFileSync4(join4(p.hooksDir, "guard.mjs"), "utf-8");
|
|
6462
|
+
const m = s.match(/HOOK_VERSION\s*=\s*(\d+)/);
|
|
6463
|
+
return m ? parseInt(m[1], 10) : null;
|
|
6464
|
+
} catch {
|
|
6465
|
+
return null;
|
|
6466
|
+
}
|
|
6467
|
+
}
|
|
6468
|
+
function guardHookOutdated() {
|
|
6469
|
+
try {
|
|
6470
|
+
const p = globalPaths();
|
|
6471
|
+
return readFileSync4(join4(p.hooksDir, "guard.mjs"), "utf-8") !== readGuard();
|
|
6472
|
+
} catch {
|
|
6473
|
+
return false;
|
|
6474
|
+
}
|
|
6475
|
+
}
|
|
6476
|
+
function isGuardInstalled() {
|
|
6477
|
+
try {
|
|
6478
|
+
const p = globalPaths();
|
|
6479
|
+
if (!existsSync3(p.settingsPath)) return false;
|
|
6480
|
+
const s = JSON.parse(readFileSync4(p.settingsPath, "utf-8"));
|
|
6481
|
+
return !!s.hooks && JSON.stringify(s.hooks).includes(".solongate");
|
|
6482
|
+
} catch {
|
|
6483
|
+
return false;
|
|
6484
|
+
}
|
|
6485
|
+
}
|
|
6486
|
+
function uninstallGlobalQuiet() {
|
|
6487
|
+
try {
|
|
6488
|
+
const p = globalPaths();
|
|
6489
|
+
unlockProtected();
|
|
6490
|
+
removeClaudeShim();
|
|
6491
|
+
try {
|
|
6492
|
+
removeAntigravityGuard(p);
|
|
6493
|
+
} catch {
|
|
6494
|
+
}
|
|
6495
|
+
if (!existsSync3(p.settingsPath)) return { ok: true, message: "guard removed (open a new session)" };
|
|
6496
|
+
const s = JSON.parse(readFileSync4(p.settingsPath, "utf-8"));
|
|
6497
|
+
delete s.hooks;
|
|
6498
|
+
writeFileSync3(p.settingsPath, JSON.stringify(s, null, 2) + "\n");
|
|
6499
|
+
return { ok: true, message: "guard removed (open a new session)" };
|
|
6500
|
+
} catch (e) {
|
|
6501
|
+
return { ok: false, message: e instanceof Error ? e.message : String(e) };
|
|
6502
|
+
}
|
|
6503
|
+
}
|
|
6504
|
+
function escapeRe(s) {
|
|
6505
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
6506
|
+
}
|
|
6507
|
+
function resolveRealClaude() {
|
|
6508
|
+
try {
|
|
6509
|
+
const finder = process.platform === "win32" ? "where" : "which";
|
|
6510
|
+
const out2 = execFileSync2(finder, ["claude"], { encoding: "utf-8" }).split(/\r?\n/).map((s) => s.trim()).filter(Boolean);
|
|
6511
|
+
if (process.platform === "win32") {
|
|
6512
|
+
const low = (s) => s.toLowerCase();
|
|
6513
|
+
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;
|
|
6514
|
+
}
|
|
6515
|
+
return out2[0] || null;
|
|
6516
|
+
} catch {
|
|
6517
|
+
return null;
|
|
6518
|
+
}
|
|
6519
|
+
}
|
|
6520
|
+
function shimTargets() {
|
|
6521
|
+
if (process.platform === "win32") {
|
|
6522
|
+
try {
|
|
6523
|
+
const prof = execFileSync2("powershell", ["-NoProfile", "-Command", "$PROFILE.CurrentUserAllHosts"], { encoding: "utf-8" }).trim();
|
|
6524
|
+
return prof ? [prof] : [];
|
|
6525
|
+
} catch {
|
|
6526
|
+
return [];
|
|
6527
|
+
}
|
|
6528
|
+
}
|
|
6529
|
+
return [".bashrc", ".zshrc", ".profile"].map((f) => join4(homedir2(), f)).filter((f) => existsSync3(f));
|
|
6530
|
+
}
|
|
6531
|
+
function writeShimBlock(file, block2) {
|
|
6532
|
+
const re = new RegExp(escapeRe(SHIM_BEGIN) + "[\\s\\S]*?" + escapeRe(SHIM_END) + "\\r?\\n?", "g");
|
|
6533
|
+
let content = existsSync3(file) ? readFileSync4(file, "utf-8") : "";
|
|
6534
|
+
content = content.replace(re, "");
|
|
6535
|
+
if (block2) {
|
|
6536
|
+
if (content.length && !content.endsWith("\n")) content += "\n";
|
|
6537
|
+
content += block2 + "\n";
|
|
6538
|
+
}
|
|
6539
|
+
mkdirSync3(dirname(file), { recursive: true });
|
|
6540
|
+
writeFileSync3(file, content);
|
|
6541
|
+
}
|
|
6542
|
+
function installClaudeShim(shieldPath) {
|
|
6543
|
+
const real = resolveRealClaude();
|
|
6544
|
+
if (!real) {
|
|
6545
|
+
console.log(" (Claude Code not found on PATH \u2014 skipped auto-shield. Install it, then re-open `solongate` \u2192 Settings \u2192 guard.)");
|
|
6546
|
+
return;
|
|
6547
|
+
}
|
|
6548
|
+
const node = process.execPath.replace(/\\/g, "/");
|
|
6549
|
+
const shield = shieldPath.replace(/\\/g, "/");
|
|
6550
|
+
const win = process.platform === "win32";
|
|
6551
|
+
const block2 = win ? `${SHIM_BEGIN}
|
|
6552
|
+
function claude { & "${node}" "${shield}" -- "${real}" @args }
|
|
6553
|
+
${SHIM_END}` : `${SHIM_BEGIN}
|
|
6554
|
+
claude() { "${node}" "${shield}" -- "${real}" "$@"; }
|
|
6555
|
+
${SHIM_END}`;
|
|
6556
|
+
const targets = shimTargets();
|
|
6557
|
+
if (targets.length === 0) return;
|
|
6558
|
+
for (const file of targets) {
|
|
6559
|
+
try {
|
|
6560
|
+
writeShimBlock(file, block2);
|
|
6561
|
+
} catch {
|
|
6562
|
+
}
|
|
6563
|
+
}
|
|
6564
|
+
}
|
|
6565
|
+
function removeClaudeShim() {
|
|
6566
|
+
for (const file of shimTargets()) {
|
|
6567
|
+
try {
|
|
6568
|
+
writeShimBlock(file, null);
|
|
6569
|
+
} catch {
|
|
6570
|
+
}
|
|
6571
|
+
}
|
|
6572
|
+
}
|
|
6573
|
+
async function runGlobalInstall(opts = {}) {
|
|
6574
|
+
const p = globalPaths();
|
|
6575
|
+
let apiKey = opts.apiKey || process.env["SOLONGATE_API_KEY"] || "";
|
|
6576
|
+
if (!apiKey || apiKey === "sg_live_your_key_here") {
|
|
6577
|
+
try {
|
|
6578
|
+
const cfg = JSON.parse(readFileSync4(p.configPath, "utf-8"));
|
|
6579
|
+
if (cfg && typeof cfg.apiKey === "string") apiKey = cfg.apiKey;
|
|
6580
|
+
} catch {
|
|
6581
|
+
}
|
|
6582
|
+
}
|
|
6583
|
+
if (!apiKey || apiKey === "sg_live_your_key_here") {
|
|
6584
|
+
const acc = firstAccountCredential();
|
|
6585
|
+
if (acc.apiKey) apiKey = acc.apiKey;
|
|
6586
|
+
}
|
|
6587
|
+
if (!apiKey || apiKey === "sg_live_your_key_here") {
|
|
6588
|
+
apiKey = await ask(" Enter your SolonGate API key (sg_live_\u2026 from https://dashboard.solongate.com): ");
|
|
6589
|
+
}
|
|
6590
|
+
if (!apiKey.startsWith("sg_live_") && !apiKey.startsWith("sg_test_")) {
|
|
6591
|
+
console.log(" Invalid API key. Must start with sg_live_ or sg_test_");
|
|
6592
|
+
process.exit(1);
|
|
6593
|
+
}
|
|
6594
|
+
const apiUrl = opts.apiUrl || process.env["SOLONGATE_API_URL"] || "https://api.solongate.com";
|
|
6595
|
+
mkdirSync3(p.hooksDir, { recursive: true });
|
|
6596
|
+
mkdirSync3(p.claudeDir, { recursive: true });
|
|
6597
|
+
unlockProtected();
|
|
6598
|
+
writeFileSync3(join4(p.hooksDir, "guard.mjs"), readGuard());
|
|
6599
|
+
writeFileSync3(join4(p.hooksDir, "audit.mjs"), readHook("audit.mjs"));
|
|
6600
|
+
writeFileSync3(join4(p.hooksDir, "stop.mjs"), readHook("stop.mjs"));
|
|
6601
|
+
writeFileSync3(join4(p.hooksDir, "shield.mjs"), readHook("shield.mjs"));
|
|
6602
|
+
console.log(` Installed hooks \u2192 ${p.hooksDir}`);
|
|
6603
|
+
installClaudeShim(join4(p.hooksDir, "shield.mjs"));
|
|
6604
|
+
writeFileSync3(p.configPath, JSON.stringify({ apiKey, apiUrl }, null, 2) + "\n");
|
|
6605
|
+
console.log(` Wrote ${p.configPath}`);
|
|
6606
|
+
let existing = {};
|
|
6607
|
+
if (existsSync3(p.settingsPath)) {
|
|
6608
|
+
const raw = readFileSync4(p.settingsPath, "utf-8");
|
|
6609
|
+
if (!existsSync3(p.backupPath)) {
|
|
6610
|
+
writeFileSync3(p.backupPath, raw);
|
|
6611
|
+
console.log(` Backed up existing settings \u2192 ${p.backupPath}`);
|
|
6612
|
+
}
|
|
6613
|
+
try {
|
|
6614
|
+
existing = JSON.parse(raw);
|
|
6615
|
+
} catch {
|
|
6616
|
+
existing = {};
|
|
6617
|
+
}
|
|
6618
|
+
}
|
|
6619
|
+
const guardAbs = join4(p.hooksDir, "guard.mjs").replace(/\\/g, "/");
|
|
6620
|
+
const auditAbs = join4(p.hooksDir, "audit.mjs").replace(/\\/g, "/");
|
|
6621
|
+
const stopAbs = join4(p.hooksDir, "stop.mjs").replace(/\\/g, "/");
|
|
6622
|
+
const nodeBin = process.execPath.replace(/\\/g, "/");
|
|
6623
|
+
const call = process.platform === "win32" ? "& " : "";
|
|
6624
|
+
const hookCmd = (script) => `${call}"${nodeBin}" "${script}" claude-code "Claude Code"`;
|
|
6625
|
+
const merged = {
|
|
6626
|
+
...existing,
|
|
6627
|
+
hooks: {
|
|
6628
|
+
PreToolUse: [{ matcher: "", hooks: [{ type: "command", command: hookCmd(guardAbs) }] }],
|
|
6629
|
+
PostToolUse: [{ matcher: "", hooks: [{ type: "command", command: hookCmd(auditAbs) }] }],
|
|
6630
|
+
Stop: [{ matcher: "", hooks: [{ type: "command", command: hookCmd(stopAbs) }] }]
|
|
6631
|
+
}
|
|
6632
|
+
};
|
|
6633
|
+
writeFileSync3(p.settingsPath, JSON.stringify(merged, null, 2) + "\n");
|
|
6634
|
+
console.log(` Registered global hooks \u2192 ${p.settingsPath}`);
|
|
6635
|
+
try {
|
|
6636
|
+
installAntigravityGuard(p, guardAbs);
|
|
6637
|
+
console.log(` Registered Antigravity CLI guard \u2192 ${p.antigravityHooksPath}`);
|
|
6638
|
+
} catch {
|
|
6639
|
+
}
|
|
6640
|
+
if (process.env["SOLONGATE_OS_LOCK"] === "1") {
|
|
6641
|
+
lockProtected();
|
|
6642
|
+
console.log(" Locked protection files (OS-level read-only/immutable).");
|
|
6643
|
+
}
|
|
6644
|
+
}
|
|
6645
|
+
async function installGlobalWithKey(apiKey, apiUrl) {
|
|
6646
|
+
await runGlobalInstall({ apiKey, apiUrl });
|
|
6647
|
+
}
|
|
6648
|
+
var __dirname, HOOKS_DIR, ANTIGRAVITY_GROUP, SHIM_BEGIN, SHIM_END;
|
|
6649
|
+
var init_global_install = __esm({
|
|
6650
|
+
"src/global-install.ts"() {
|
|
6651
|
+
"use strict";
|
|
6652
|
+
__dirname = dirname(fileURLToPath(import.meta.url));
|
|
6653
|
+
HOOKS_DIR = resolve3(__dirname, "..", "hooks");
|
|
6654
|
+
ANTIGRAVITY_GROUP = "solongate-guard";
|
|
6655
|
+
SHIM_BEGIN = "# >>> SolonGate shield (auto secret redaction) >>>";
|
|
6656
|
+
SHIM_END = "# <<< SolonGate shield <<<";
|
|
6657
|
+
}
|
|
6658
|
+
});
|
|
6659
|
+
|
|
6190
6660
|
// src/self-update.ts
|
|
6191
6661
|
var self_update_exports = {};
|
|
6192
6662
|
__export(self_update_exports, {
|
|
@@ -6194,16 +6664,17 @@ __export(self_update_exports, {
|
|
|
6194
6664
|
latestVersion: () => latestVersion,
|
|
6195
6665
|
maybeSelfUpdate: () => maybeSelfUpdate,
|
|
6196
6666
|
newerThan: () => newerThan,
|
|
6667
|
+
runUpdateCommand: () => runUpdateCommand,
|
|
6197
6668
|
tuiUpdateFlow: () => tuiUpdateFlow
|
|
6198
6669
|
});
|
|
6199
6670
|
import { execFile, spawn } from "child_process";
|
|
6200
|
-
import { mkdirSync as
|
|
6201
|
-
import { homedir as
|
|
6202
|
-
import { dirname, join as
|
|
6203
|
-
import { fileURLToPath } from "url";
|
|
6671
|
+
import { mkdirSync as mkdirSync4, openSync, readFileSync as readFileSync5, writeFileSync as writeFileSync4 } from "fs";
|
|
6672
|
+
import { homedir as homedir3 } from "os";
|
|
6673
|
+
import { dirname as dirname2, join as join5 } from "path";
|
|
6674
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
6204
6675
|
function readState() {
|
|
6205
6676
|
try {
|
|
6206
|
-
const s = JSON.parse(
|
|
6677
|
+
const s = JSON.parse(readFileSync5(STATE_FILE, "utf-8"));
|
|
6207
6678
|
return s && typeof s === "object" ? s : {};
|
|
6208
6679
|
} catch {
|
|
6209
6680
|
return {};
|
|
@@ -6211,14 +6682,14 @@ function readState() {
|
|
|
6211
6682
|
}
|
|
6212
6683
|
function writeState(s) {
|
|
6213
6684
|
try {
|
|
6214
|
-
|
|
6215
|
-
|
|
6685
|
+
mkdirSync4(join5(homedir3(), ".solongate"), { recursive: true });
|
|
6686
|
+
writeFileSync4(STATE_FILE, JSON.stringify(s));
|
|
6216
6687
|
} catch {
|
|
6217
6688
|
}
|
|
6218
6689
|
}
|
|
6219
6690
|
function currentVersion() {
|
|
6220
6691
|
try {
|
|
6221
|
-
const pkg = JSON.parse(
|
|
6692
|
+
const pkg = JSON.parse(readFileSync5(join5(dirname2(fileURLToPath2(import.meta.url)), "..", "package.json"), "utf-8"));
|
|
6222
6693
|
return pkg.version ?? "0.0.0";
|
|
6223
6694
|
} catch {
|
|
6224
6695
|
return "0.0.0";
|
|
@@ -6254,7 +6725,7 @@ async function fetchLatest() {
|
|
|
6254
6725
|
}
|
|
6255
6726
|
function spawnGlobalInstall(version) {
|
|
6256
6727
|
try {
|
|
6257
|
-
|
|
6728
|
+
mkdirSync4(join5(homedir3(), ".solongate"), { recursive: true });
|
|
6258
6729
|
const log3 = openSync(LOG_FILE, "a");
|
|
6259
6730
|
const p = spawn("npm", ["install", "-g", `${PKG}@${version}`], {
|
|
6260
6731
|
stdio: ["ignore", log3, log3],
|
|
@@ -6270,17 +6741,45 @@ function spawnGlobalInstall(version) {
|
|
|
6270
6741
|
return false;
|
|
6271
6742
|
}
|
|
6272
6743
|
}
|
|
6273
|
-
function
|
|
6744
|
+
async function runUpdateCommand() {
|
|
6745
|
+
const out2 = (s) => void process.stderr.write(s + "\n");
|
|
6746
|
+
const cur = currentVersion();
|
|
6747
|
+
out2(` current ${cur}`);
|
|
6748
|
+
const latest = await latestVersion();
|
|
6749
|
+
if (!latest) {
|
|
6750
|
+
out2(" could not reach the npm registry. Try again, or: npm i -g @solongate/proxy@latest");
|
|
6751
|
+
return 1;
|
|
6752
|
+
}
|
|
6753
|
+
if (newerThan(latest, cur)) {
|
|
6754
|
+
out2(` updating ${cur} -> ${latest} ...`);
|
|
6755
|
+
const ok = await runGlobalInstall2(latest);
|
|
6756
|
+
if (!ok) {
|
|
6757
|
+
out2(" update failed. Try: npm i -g @solongate/proxy@latest");
|
|
6758
|
+
return 1;
|
|
6759
|
+
}
|
|
6760
|
+
out2(` \u2713 updated to ${latest} (open a new session to use it)`);
|
|
6761
|
+
} else {
|
|
6762
|
+
out2(` \u2713 already up to date`);
|
|
6763
|
+
}
|
|
6764
|
+
try {
|
|
6765
|
+
const { installGlobalQuiet: installGlobalQuiet2, installedGuardVersion: installedGuardVersion2 } = await Promise.resolve().then(() => (init_global_install(), global_install_exports));
|
|
6766
|
+
const r = installGlobalQuiet2();
|
|
6767
|
+
out2(r.ok ? ` \u2713 guard hooks refreshed (v${installedGuardVersion2() ?? "?"})` : ` guard: ${r.message}`);
|
|
6768
|
+
} catch {
|
|
6769
|
+
}
|
|
6770
|
+
return 0;
|
|
6771
|
+
}
|
|
6772
|
+
function runGlobalInstall2(version) {
|
|
6274
6773
|
return new Promise((resolve6) => {
|
|
6275
6774
|
try {
|
|
6276
|
-
|
|
6775
|
+
mkdirSync4(join5(homedir3(), ".solongate"), { recursive: true });
|
|
6277
6776
|
execFile(
|
|
6278
6777
|
"npm",
|
|
6279
6778
|
["install", "-g", `${PKG}@${version}`],
|
|
6280
6779
|
{ timeout: 3e5, windowsHide: true, shell: process.platform === "win32" },
|
|
6281
6780
|
(err2, stdout, stderr) => {
|
|
6282
6781
|
try {
|
|
6283
|
-
|
|
6782
|
+
writeFileSync4(LOG_FILE, `${(/* @__PURE__ */ new Date()).toISOString()} install ${version}: ${err2 ? "FAILED" : "ok"}
|
|
6284
6783
|
${stdout}
|
|
6285
6784
|
${stderr}
|
|
6286
6785
|
`, { flag: "a" });
|
|
@@ -6306,7 +6805,7 @@ async function tuiUpdateFlow(onStatus) {
|
|
|
6306
6805
|
return;
|
|
6307
6806
|
}
|
|
6308
6807
|
onStatus({ kind: "updating", version: latest });
|
|
6309
|
-
if (await
|
|
6808
|
+
if (await runGlobalInstall2(latest)) {
|
|
6310
6809
|
writeState({ ...readState(), installed: latest });
|
|
6311
6810
|
onStatus({ kind: "updated", version: latest });
|
|
6312
6811
|
}
|
|
@@ -6345,8 +6844,8 @@ var init_self_update = __esm({
|
|
|
6345
6844
|
PKG = "@solongate/proxy";
|
|
6346
6845
|
CHECK_EVERY_MS = 30 * 60 * 1e3;
|
|
6347
6846
|
ATTEMPT_EVERY_MS = 6 * 60 * 60 * 1e3;
|
|
6348
|
-
STATE_FILE =
|
|
6349
|
-
LOG_FILE =
|
|
6847
|
+
STATE_FILE = join5(homedir3(), ".solongate", ".self-update.json");
|
|
6848
|
+
LOG_FILE = join5(homedir3(), ".solongate", "self-update.log");
|
|
6350
6849
|
}
|
|
6351
6850
|
});
|
|
6352
6851
|
|
|
@@ -6361,13 +6860,13 @@ __export(logs_server_daemon_exports, {
|
|
|
6361
6860
|
stopLogsServerDaemon: () => stopLogsServerDaemon
|
|
6362
6861
|
});
|
|
6363
6862
|
import { spawn as spawn2 } from "child_process";
|
|
6364
|
-
import { mkdirSync as
|
|
6365
|
-
import { homedir as
|
|
6366
|
-
import { dirname as
|
|
6367
|
-
import { fileURLToPath as
|
|
6863
|
+
import { mkdirSync as mkdirSync5, openSync as openSync2, readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "fs";
|
|
6864
|
+
import { homedir as homedir4 } from "os";
|
|
6865
|
+
import { dirname as dirname3, join as join6 } from "path";
|
|
6866
|
+
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
6368
6867
|
function readState2() {
|
|
6369
6868
|
try {
|
|
6370
|
-
const s = JSON.parse(
|
|
6869
|
+
const s = JSON.parse(readFileSync6(STATE_FILE2, "utf-8"));
|
|
6371
6870
|
return s && typeof s === "object" ? s : {};
|
|
6372
6871
|
} catch {
|
|
6373
6872
|
return {};
|
|
@@ -6375,8 +6874,8 @@ function readState2() {
|
|
|
6375
6874
|
}
|
|
6376
6875
|
function writeState2(s) {
|
|
6377
6876
|
try {
|
|
6378
|
-
|
|
6379
|
-
|
|
6877
|
+
mkdirSync5(DIR, { recursive: true });
|
|
6878
|
+
writeFileSync5(STATE_FILE2, JSON.stringify(s));
|
|
6380
6879
|
} catch {
|
|
6381
6880
|
}
|
|
6382
6881
|
}
|
|
@@ -6404,13 +6903,16 @@ function startLogsServerDaemon() {
|
|
|
6404
6903
|
return { ...cur, desired: "on" };
|
|
6405
6904
|
}
|
|
6406
6905
|
try {
|
|
6407
|
-
|
|
6906
|
+
mkdirSync5(DIR, { recursive: true });
|
|
6408
6907
|
const log3 = openSync2(LOG_FILE2, "a");
|
|
6409
|
-
const cli =
|
|
6908
|
+
const cli = join6(dirname3(fileURLToPath3(import.meta.url)), "index.js");
|
|
6410
6909
|
const p = spawn2(process.execPath, [cli, "logs-server"], {
|
|
6411
6910
|
detached: true,
|
|
6412
6911
|
stdio: ["ignore", log3, log3],
|
|
6413
|
-
windowsHide: true
|
|
6912
|
+
windowsHide: true,
|
|
6913
|
+
// Spawned by US, not by an agent: exempt from the human-only TTY gate
|
|
6914
|
+
// (a detached daemon has no terminal by definition).
|
|
6915
|
+
env: { ...process.env, SOLONGATE_INTERNAL: "1" }
|
|
6414
6916
|
});
|
|
6415
6917
|
p.on("error", () => {
|
|
6416
6918
|
});
|
|
@@ -6443,22 +6945,22 @@ var DIR, STATE_FILE2, LOG_FILE2, LOGS_SERVER_PORT;
|
|
|
6443
6945
|
var init_logs_server_daemon = __esm({
|
|
6444
6946
|
"src/logs-server-daemon.ts"() {
|
|
6445
6947
|
"use strict";
|
|
6446
|
-
DIR =
|
|
6447
|
-
STATE_FILE2 =
|
|
6448
|
-
LOG_FILE2 =
|
|
6948
|
+
DIR = join6(homedir4(), ".solongate");
|
|
6949
|
+
STATE_FILE2 = join6(DIR, ".logs-server.json");
|
|
6950
|
+
LOG_FILE2 = join6(DIR, "logs-server.log");
|
|
6449
6951
|
LOGS_SERVER_PORT = 8788;
|
|
6450
6952
|
}
|
|
6451
6953
|
});
|
|
6452
6954
|
|
|
6453
6955
|
// src/tui/config.ts
|
|
6454
|
-
import { readFileSync as
|
|
6455
|
-
import { homedir as
|
|
6456
|
-
import { join as
|
|
6956
|
+
import { readFileSync as readFileSync7 } from "fs";
|
|
6957
|
+
import { homedir as homedir5 } from "os";
|
|
6958
|
+
import { join as join7 } from "path";
|
|
6457
6959
|
function loadConfig() {
|
|
6458
6960
|
if (cached) return cached;
|
|
6459
6961
|
const defaults = { notifications: true };
|
|
6460
6962
|
try {
|
|
6461
|
-
const raw =
|
|
6963
|
+
const raw = readFileSync7(join7(homedir5(), ".solongate", "tui-config.json"), "utf-8");
|
|
6462
6964
|
const j = JSON.parse(raw);
|
|
6463
6965
|
cached = {
|
|
6464
6966
|
notifications: j.notifications !== false,
|
|
@@ -6629,9 +7131,9 @@ var init_components = __esm({
|
|
|
6629
7131
|
});
|
|
6630
7132
|
|
|
6631
7133
|
// src/tui/local-log.ts
|
|
6632
|
-
import { closeSync, openSync as openSync3, readFileSync as
|
|
6633
|
-
import { homedir as
|
|
6634
|
-
import { join as
|
|
7134
|
+
import { closeSync, openSync as openSync3, readFileSync as readFileSync8, readSync, statSync, writeFileSync as writeFileSync6 } from "fs";
|
|
7135
|
+
import { homedir as homedir6 } from "os";
|
|
7136
|
+
import { join as join8 } from "path";
|
|
6635
7137
|
function tailLines(file, maxBytes = 131072) {
|
|
6636
7138
|
try {
|
|
6637
7139
|
const size = statSync(file).size;
|
|
@@ -6649,7 +7151,7 @@ function tailLines(file, maxBytes = 131072) {
|
|
|
6649
7151
|
}
|
|
6650
7152
|
function deleteLocalEntry(at, tool, session) {
|
|
6651
7153
|
try {
|
|
6652
|
-
const lines =
|
|
7154
|
+
const lines = readFileSync8(LOCAL_LOG, "utf-8").split("\n");
|
|
6653
7155
|
let removed = 0;
|
|
6654
7156
|
const kept = lines.filter((line) => {
|
|
6655
7157
|
if (!line.trim()) return false;
|
|
@@ -6665,7 +7167,7 @@ function deleteLocalEntry(at, tool, session) {
|
|
|
6665
7167
|
}
|
|
6666
7168
|
return true;
|
|
6667
7169
|
});
|
|
6668
|
-
if (removed)
|
|
7170
|
+
if (removed) writeFileSync6(LOCAL_LOG, kept.length ? kept.join("\n") + "\n" : "");
|
|
6669
7171
|
return removed;
|
|
6670
7172
|
} catch {
|
|
6671
7173
|
return 0;
|
|
@@ -6673,8 +7175,8 @@ function deleteLocalEntry(at, tool, session) {
|
|
|
6673
7175
|
}
|
|
6674
7176
|
function clearLocalLog() {
|
|
6675
7177
|
try {
|
|
6676
|
-
const n =
|
|
6677
|
-
|
|
7178
|
+
const n = readFileSync8(LOCAL_LOG, "utf-8").split("\n").filter(Boolean).length;
|
|
7179
|
+
writeFileSync6(LOCAL_LOG, "");
|
|
6678
7180
|
return n;
|
|
6679
7181
|
} catch {
|
|
6680
7182
|
return 0;
|
|
@@ -6705,20 +7207,20 @@ var LOCAL_LOG, DLP_REASON, RL_REASON;
|
|
|
6705
7207
|
var init_local_log = __esm({
|
|
6706
7208
|
"src/tui/local-log.ts"() {
|
|
6707
7209
|
"use strict";
|
|
6708
|
-
LOCAL_LOG =
|
|
7210
|
+
LOCAL_LOG = join8(homedir6(), ".solongate", "local-logs", "solongate-audit.jsonl");
|
|
6709
7211
|
DLP_REASON = /security layer \(dlp\)/i;
|
|
6710
7212
|
RL_REASON = /security layer \(rate limit\)|rate[- ]?limit(?:ed)?\b.*exceed|exceeded \d+ calls/i;
|
|
6711
7213
|
}
|
|
6712
7214
|
});
|
|
6713
7215
|
|
|
6714
7216
|
// src/api-client/client.ts
|
|
6715
|
-
import { readFileSync as
|
|
6716
|
-
import { resolve as
|
|
6717
|
-
import { homedir as
|
|
7217
|
+
import { readFileSync as readFileSync9, writeFileSync as writeFileSync7, mkdirSync as mkdirSync6, existsSync as existsSync4 } from "fs";
|
|
7218
|
+
import { resolve as resolve4, join as join9 } from "path";
|
|
7219
|
+
import { homedir as homedir7 } from "os";
|
|
6718
7220
|
function listAccounts() {
|
|
6719
7221
|
let list5 = [];
|
|
6720
7222
|
try {
|
|
6721
|
-
const raw = JSON.parse(
|
|
7223
|
+
const raw = JSON.parse(readFileSync9(accountsFile(), "utf-8"));
|
|
6722
7224
|
if (Array.isArray(raw)) list5 = raw.filter((a) => a && typeof a.apiKey === "string");
|
|
6723
7225
|
} catch {
|
|
6724
7226
|
}
|
|
@@ -6732,7 +7234,7 @@ function saveAccount(acc) {
|
|
|
6732
7234
|
try {
|
|
6733
7235
|
const list5 = (() => {
|
|
6734
7236
|
try {
|
|
6735
|
-
const raw = JSON.parse(
|
|
7237
|
+
const raw = JSON.parse(readFileSync9(accountsFile(), "utf-8"));
|
|
6736
7238
|
return Array.isArray(raw) ? raw.filter((a) => a && a.apiKey) : [];
|
|
6737
7239
|
} catch {
|
|
6738
7240
|
return [];
|
|
@@ -6740,8 +7242,8 @@ function saveAccount(acc) {
|
|
|
6740
7242
|
})();
|
|
6741
7243
|
const next = list5.filter((a) => a.apiKey !== acc.apiKey);
|
|
6742
7244
|
next.unshift({ ...acc, addedAt: acc.addedAt ?? Date.now() });
|
|
6743
|
-
|
|
6744
|
-
|
|
7245
|
+
mkdirSync6(join9(homedir7(), ".solongate"), { recursive: true });
|
|
7246
|
+
writeFileSync7(accountsFile(), JSON.stringify(next, null, 2));
|
|
6745
7247
|
} catch {
|
|
6746
7248
|
}
|
|
6747
7249
|
}
|
|
@@ -6749,13 +7251,13 @@ function removeAccount(apiKey) {
|
|
|
6749
7251
|
try {
|
|
6750
7252
|
const list5 = (() => {
|
|
6751
7253
|
try {
|
|
6752
|
-
const raw = JSON.parse(
|
|
7254
|
+
const raw = JSON.parse(readFileSync9(accountsFile(), "utf-8"));
|
|
6753
7255
|
return Array.isArray(raw) ? raw.filter((a) => a && a.apiKey) : [];
|
|
6754
7256
|
} catch {
|
|
6755
7257
|
return [];
|
|
6756
7258
|
}
|
|
6757
7259
|
})();
|
|
6758
|
-
|
|
7260
|
+
writeFileSync7(accountsFile(), JSON.stringify(list5.filter((a) => a.apiKey !== apiKey), null, 2));
|
|
6759
7261
|
} catch {
|
|
6760
7262
|
}
|
|
6761
7263
|
}
|
|
@@ -6768,15 +7270,15 @@ function isActiveAccount(apiKey) {
|
|
|
6768
7270
|
}
|
|
6769
7271
|
function setActiveAccount(creds) {
|
|
6770
7272
|
try {
|
|
6771
|
-
const dir =
|
|
6772
|
-
|
|
6773
|
-
const p =
|
|
7273
|
+
const dir = join9(homedir7(), ".solongate");
|
|
7274
|
+
mkdirSync6(dir, { recursive: true });
|
|
7275
|
+
const p = join9(dir, ["cloud", "guard.json"].join("-"));
|
|
6774
7276
|
let existing = {};
|
|
6775
7277
|
try {
|
|
6776
|
-
existing = JSON.parse(
|
|
7278
|
+
existing = JSON.parse(readFileSync9(p, "utf-8"));
|
|
6777
7279
|
} catch {
|
|
6778
7280
|
}
|
|
6779
|
-
|
|
7281
|
+
writeFileSync7(p, JSON.stringify({ ...existing, apiKey: creds.apiKey, apiUrl: creds.apiUrl }, null, 2));
|
|
6780
7282
|
cached2 = null;
|
|
6781
7283
|
return true;
|
|
6782
7284
|
} catch {
|
|
@@ -6785,19 +7287,19 @@ function setActiveAccount(creds) {
|
|
|
6785
7287
|
}
|
|
6786
7288
|
function clearActiveCredential() {
|
|
6787
7289
|
try {
|
|
6788
|
-
const p =
|
|
6789
|
-
if (!
|
|
7290
|
+
const p = join9(homedir7(), ".solongate", ["cloud", "guard.json"].join("-"));
|
|
7291
|
+
if (!existsSync4(p)) {
|
|
6790
7292
|
cached2 = null;
|
|
6791
7293
|
return true;
|
|
6792
7294
|
}
|
|
6793
7295
|
let existing = {};
|
|
6794
7296
|
try {
|
|
6795
|
-
existing = JSON.parse(
|
|
7297
|
+
existing = JSON.parse(readFileSync9(p, "utf-8"));
|
|
6796
7298
|
} catch {
|
|
6797
7299
|
}
|
|
6798
7300
|
delete existing.apiKey;
|
|
6799
7301
|
delete existing.apiUrl;
|
|
6800
|
-
|
|
7302
|
+
writeFileSync7(p, JSON.stringify(existing, null, 2));
|
|
6801
7303
|
cached2 = null;
|
|
6802
7304
|
viewOverride = null;
|
|
6803
7305
|
return true;
|
|
@@ -6807,9 +7309,9 @@ function clearActiveCredential() {
|
|
|
6807
7309
|
}
|
|
6808
7310
|
function loginCredentialFile() {
|
|
6809
7311
|
try {
|
|
6810
|
-
const p =
|
|
6811
|
-
if (!
|
|
6812
|
-
const c2 = JSON.parse(
|
|
7312
|
+
const p = join9(homedir7(), ".solongate", "cloud-guard.json");
|
|
7313
|
+
if (!existsSync4(p)) return {};
|
|
7314
|
+
const c2 = JSON.parse(readFileSync9(p, "utf-8"));
|
|
6813
7315
|
return c2 && typeof c2 === "object" ? c2 : {};
|
|
6814
7316
|
} catch {
|
|
6815
7317
|
return {};
|
|
@@ -6817,9 +7319,9 @@ function loginCredentialFile() {
|
|
|
6817
7319
|
}
|
|
6818
7320
|
function dotenvApiKey() {
|
|
6819
7321
|
try {
|
|
6820
|
-
const envPath =
|
|
6821
|
-
if (!
|
|
6822
|
-
for (const line of
|
|
7322
|
+
const envPath = resolve4(".env");
|
|
7323
|
+
if (!existsSync4(envPath)) return void 0;
|
|
7324
|
+
for (const line of readFileSync9(envPath, "utf-8").split("\n")) {
|
|
6823
7325
|
const trimmed = line.trim();
|
|
6824
7326
|
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
6825
7327
|
const eq = trimmed.indexOf("=");
|
|
@@ -6922,7 +7424,7 @@ var init_client = __esm({
|
|
|
6922
7424
|
"src/api-client/client.ts"() {
|
|
6923
7425
|
"use strict";
|
|
6924
7426
|
DEFAULT_API_URL2 = "https://api.solongate.com";
|
|
6925
|
-
accountsFile = () =>
|
|
7427
|
+
accountsFile = () => join9(homedir7(), ".solongate", "accounts.json");
|
|
6926
7428
|
viewOverride = null;
|
|
6927
7429
|
ApiError = class extends Error {
|
|
6928
7430
|
status;
|
|
@@ -7413,9 +7915,9 @@ var init_hooks = __esm({
|
|
|
7413
7915
|
// src/tui/panels/Live.tsx
|
|
7414
7916
|
import { Box as Box2, Text as Text2, useInput } from "ink";
|
|
7415
7917
|
import TextInput from "ink-text-input";
|
|
7416
|
-
import { mkdirSync as
|
|
7417
|
-
import { homedir as
|
|
7418
|
-
import { join as
|
|
7918
|
+
import { mkdirSync as mkdirSync7, writeFileSync as writeFileSync8 } from "fs";
|
|
7919
|
+
import { homedir as homedir8 } from "os";
|
|
7920
|
+
import { join as join10 } from "path";
|
|
7419
7921
|
import { useCallback as useCallback2, useEffect as useEffect2, useRef as useRef2, useState as useState2 } from "react";
|
|
7420
7922
|
import { Fragment as Fragment2, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
7421
7923
|
function extractTarget(detail) {
|
|
@@ -7973,10 +8475,10 @@ function LivePanel({ active: active2 }) {
|
|
|
7973
8475
|
else if (input === "x") toggleSignal("dlp");
|
|
7974
8476
|
else if (input === "r") toggleSignal("ratelimit");
|
|
7975
8477
|
else if (input === "e") {
|
|
7976
|
-
const file =
|
|
8478
|
+
const file = join10(homedir8(), ".solongate", "live-export.jsonl");
|
|
7977
8479
|
try {
|
|
7978
|
-
|
|
7979
|
-
|
|
8480
|
+
mkdirSync7(join10(homedir8(), ".solongate"), { recursive: true });
|
|
8481
|
+
writeFileSync8(file, visibleDesc.map((x) => JSON.stringify(x)).join("\n") + "\n");
|
|
7980
8482
|
setActionMsg({ text: `\u2713 exported ${visibleDesc.length} lines \u2192 ${file}`, level: "ok", until: Date.now() + 6e3 });
|
|
7981
8483
|
} catch (err2) {
|
|
7982
8484
|
setActionMsg({ text: "\u2717 export failed: " + (err2 instanceof Error ? err2.message : String(err2)), level: "bad", until: Date.now() + 6e3 });
|
|
@@ -8387,7 +8889,7 @@ var init_Live = __esm({
|
|
|
8387
8889
|
SPIN = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
8388
8890
|
BG = "#12234f";
|
|
8389
8891
|
DIM_FLOOR = "#233457";
|
|
8390
|
-
RING =
|
|
8892
|
+
RING = join10(process.cwd(), ".solongate", ".eval-ring.jsonl");
|
|
8391
8893
|
fmtUp = (ms) => {
|
|
8392
8894
|
const s = Math.floor(ms / 1e3);
|
|
8393
8895
|
const p = (n) => String(n).padStart(2, "0");
|
|
@@ -9390,9 +9892,9 @@ var init_Dlp = __esm({
|
|
|
9390
9892
|
// src/tui/panels/Audit.tsx
|
|
9391
9893
|
import { Box as Box7, Text as Text7, useInput as useInput6 } from "ink";
|
|
9392
9894
|
import TextInput5 from "ink-text-input";
|
|
9393
|
-
import { mkdirSync as
|
|
9394
|
-
import { homedir as
|
|
9395
|
-
import { join as
|
|
9895
|
+
import { mkdirSync as mkdirSync8, writeFileSync as writeFileSync9 } from "fs";
|
|
9896
|
+
import { homedir as homedir9 } from "os";
|
|
9897
|
+
import { join as join11 } from "path";
|
|
9396
9898
|
import { useState as useState7 } from "react";
|
|
9397
9899
|
import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
9398
9900
|
function loadLocalRows() {
|
|
@@ -9542,16 +10044,16 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
9542
10044
|
const doExport = (kind) => {
|
|
9543
10045
|
setMsg({ text: "exporting\u2026", level: "ok" });
|
|
9544
10046
|
const run10 = async () => {
|
|
9545
|
-
const dir =
|
|
9546
|
-
const file =
|
|
10047
|
+
const dir = join11(homedir9(), ".solongate");
|
|
10048
|
+
const file = join11(dir, `audit-export-${source}.jsonl`);
|
|
9547
10049
|
let rows2;
|
|
9548
10050
|
if (kind === "page") rows2 = pageRows;
|
|
9549
10051
|
else if (source === "cloud") {
|
|
9550
10052
|
const r = await api.audit.list({ ...query, limit: 1e4, offset: 0 });
|
|
9551
10053
|
rows2 = r.entries.map(cloudRow).sort((a, b) => b.at - a.at);
|
|
9552
10054
|
} else rows2 = localFiltered;
|
|
9553
|
-
|
|
9554
|
-
|
|
10055
|
+
mkdirSync8(dir, { recursive: true });
|
|
10056
|
+
writeFileSync9(file, rows2.map((x) => JSON.stringify(x)).join("\n") + (rows2.length ? "\n" : ""));
|
|
9555
10057
|
return { n: rows2.length, file };
|
|
9556
10058
|
};
|
|
9557
10059
|
run10().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" }));
|
|
@@ -10022,312 +10524,6 @@ var init_Audit = __esm({
|
|
|
10022
10524
|
}
|
|
10023
10525
|
});
|
|
10024
10526
|
|
|
10025
|
-
// src/global-install.ts
|
|
10026
|
-
import { readFileSync as readFileSync9, writeFileSync as writeFileSync9, existsSync as existsSync4, mkdirSync as mkdirSync8, rmSync as rmSync2 } from "fs";
|
|
10027
|
-
import { resolve as resolve4, join as join11, dirname as dirname3 } from "path";
|
|
10028
|
-
import { homedir as homedir9 } from "os";
|
|
10029
|
-
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
10030
|
-
import { createInterface } from "readline";
|
|
10031
|
-
import { execFileSync as execFileSync2 } from "child_process";
|
|
10032
|
-
function lockFile(file) {
|
|
10033
|
-
if (!existsSync4(file)) return;
|
|
10034
|
-
try {
|
|
10035
|
-
if (process.platform === "win32") {
|
|
10036
|
-
try {
|
|
10037
|
-
execFileSync2("icacls", [file, "/deny", "*S-1-1-0:(WD,AD,DC,DE)"], { stdio: "ignore" });
|
|
10038
|
-
} catch {
|
|
10039
|
-
}
|
|
10040
|
-
try {
|
|
10041
|
-
execFileSync2("attrib", ["+R", file], { stdio: "ignore" });
|
|
10042
|
-
} catch {
|
|
10043
|
-
}
|
|
10044
|
-
} else if (process.platform === "darwin") {
|
|
10045
|
-
try {
|
|
10046
|
-
execFileSync2("chflags", ["uchg", file], { stdio: "ignore" });
|
|
10047
|
-
} catch {
|
|
10048
|
-
}
|
|
10049
|
-
} else {
|
|
10050
|
-
try {
|
|
10051
|
-
execFileSync2("chattr", ["+i", file], { stdio: "ignore" });
|
|
10052
|
-
} catch {
|
|
10053
|
-
}
|
|
10054
|
-
}
|
|
10055
|
-
} catch {
|
|
10056
|
-
}
|
|
10057
|
-
}
|
|
10058
|
-
function unlockFile(file) {
|
|
10059
|
-
if (!existsSync4(file)) return;
|
|
10060
|
-
try {
|
|
10061
|
-
if (process.platform === "win32") {
|
|
10062
|
-
try {
|
|
10063
|
-
execFileSync2("icacls", [file, "/remove:d", "*S-1-1-0"], { stdio: "ignore" });
|
|
10064
|
-
} catch {
|
|
10065
|
-
}
|
|
10066
|
-
try {
|
|
10067
|
-
execFileSync2("icacls", [file, "/reset"], { stdio: "ignore" });
|
|
10068
|
-
} catch {
|
|
10069
|
-
}
|
|
10070
|
-
try {
|
|
10071
|
-
execFileSync2("attrib", ["-R", file], { stdio: "ignore" });
|
|
10072
|
-
} catch {
|
|
10073
|
-
}
|
|
10074
|
-
} else if (process.platform === "darwin") {
|
|
10075
|
-
try {
|
|
10076
|
-
execFileSync2("chflags", ["nouchg", file], { stdio: "ignore" });
|
|
10077
|
-
} catch {
|
|
10078
|
-
}
|
|
10079
|
-
} else {
|
|
10080
|
-
try {
|
|
10081
|
-
execFileSync2("chattr", ["-i", file], { stdio: "ignore" });
|
|
10082
|
-
} catch {
|
|
10083
|
-
}
|
|
10084
|
-
}
|
|
10085
|
-
} catch {
|
|
10086
|
-
}
|
|
10087
|
-
}
|
|
10088
|
-
function protectedTargets() {
|
|
10089
|
-
const p = globalPaths();
|
|
10090
|
-
return [
|
|
10091
|
-
join11(p.hooksDir, "guard.mjs"),
|
|
10092
|
-
join11(p.hooksDir, "audit.mjs"),
|
|
10093
|
-
join11(p.hooksDir, "stop.mjs"),
|
|
10094
|
-
join11(p.hooksDir, "shield.mjs"),
|
|
10095
|
-
p.configPath,
|
|
10096
|
-
p.settingsPath,
|
|
10097
|
-
p.antigravityHooksPath
|
|
10098
|
-
];
|
|
10099
|
-
}
|
|
10100
|
-
function lockProtected() {
|
|
10101
|
-
for (const f of protectedTargets()) lockFile(f);
|
|
10102
|
-
}
|
|
10103
|
-
function unlockProtected() {
|
|
10104
|
-
for (const f of protectedTargets()) unlockFile(f);
|
|
10105
|
-
}
|
|
10106
|
-
function globalPaths() {
|
|
10107
|
-
const home = homedir9();
|
|
10108
|
-
const sgDir = join11(home, ".solongate");
|
|
10109
|
-
const hooksDir = join11(sgDir, "hooks");
|
|
10110
|
-
const claudeDir = join11(home, ".claude");
|
|
10111
|
-
const antigravityDir = join11(home, ".gemini", "config");
|
|
10112
|
-
return {
|
|
10113
|
-
home,
|
|
10114
|
-
sgDir,
|
|
10115
|
-
hooksDir,
|
|
10116
|
-
claudeDir,
|
|
10117
|
-
antigravityDir,
|
|
10118
|
-
settingsPath: join11(claudeDir, "settings.json"),
|
|
10119
|
-
backupPath: join11(claudeDir, "settings.solongate.bak"),
|
|
10120
|
-
configPath: join11(sgDir, "cloud-guard.json"),
|
|
10121
|
-
// Antigravity reads global hooks from ~/.gemini/config/hooks.json. Only the
|
|
10122
|
-
// guard is registered there (PreToolUse); Antigravity's ALLOW-path audit is
|
|
10123
|
-
// covered by the passive session-log collector, not a hook.
|
|
10124
|
-
antigravityHooksPath: join11(antigravityDir, "hooks.json"),
|
|
10125
|
-
antigravityBackupPath: join11(antigravityDir, "hooks.solongate.bak")
|
|
10126
|
-
};
|
|
10127
|
-
}
|
|
10128
|
-
function readHook(filename) {
|
|
10129
|
-
return readFileSync9(join11(HOOKS_DIR, filename), "utf-8");
|
|
10130
|
-
}
|
|
10131
|
-
function firstAccountCredential() {
|
|
10132
|
-
try {
|
|
10133
|
-
const raw = JSON.parse(readFileSync9(join11(homedir9(), ".solongate", "accounts.json"), "utf-8"));
|
|
10134
|
-
if (Array.isArray(raw)) {
|
|
10135
|
-
const acc = raw.find((a) => a && typeof a.apiKey === "string" && a.apiKey);
|
|
10136
|
-
if (acc) return { apiKey: acc.apiKey, apiUrl: typeof acc.apiUrl === "string" ? acc.apiUrl : void 0 };
|
|
10137
|
-
}
|
|
10138
|
-
} catch {
|
|
10139
|
-
}
|
|
10140
|
-
return {};
|
|
10141
|
-
}
|
|
10142
|
-
function readGuard() {
|
|
10143
|
-
const bundled = join11(HOOKS_DIR, "guard.bundled.mjs");
|
|
10144
|
-
return existsSync4(bundled) ? readFileSync9(bundled, "utf-8") : readHook("guard.mjs");
|
|
10145
|
-
}
|
|
10146
|
-
function antigravityHookCommand(guardAbs) {
|
|
10147
|
-
const nodeBin = process.execPath.replace(/\\/g, "/");
|
|
10148
|
-
const call = process.platform === "win32" ? "& " : "";
|
|
10149
|
-
return `${call}"${nodeBin}" "${guardAbs.replace(/\\/g, "/")}" antigravity "Antigravity"`;
|
|
10150
|
-
}
|
|
10151
|
-
function installAntigravityGuard(p, guardAbs) {
|
|
10152
|
-
mkdirSync8(p.antigravityDir, { recursive: true });
|
|
10153
|
-
let existing = {};
|
|
10154
|
-
if (existsSync4(p.antigravityHooksPath)) {
|
|
10155
|
-
const raw = readFileSync9(p.antigravityHooksPath, "utf-8");
|
|
10156
|
-
if (!existsSync4(p.antigravityBackupPath)) writeFileSync9(p.antigravityBackupPath, raw);
|
|
10157
|
-
try {
|
|
10158
|
-
existing = JSON.parse(raw);
|
|
10159
|
-
} catch {
|
|
10160
|
-
existing = {};
|
|
10161
|
-
}
|
|
10162
|
-
}
|
|
10163
|
-
const merged = {
|
|
10164
|
-
...existing,
|
|
10165
|
-
[ANTIGRAVITY_GROUP]: {
|
|
10166
|
-
PreToolUse: [{ matcher: "", hooks: [{ type: "command", command: antigravityHookCommand(guardAbs) }] }]
|
|
10167
|
-
}
|
|
10168
|
-
};
|
|
10169
|
-
writeFileSync9(p.antigravityHooksPath, JSON.stringify(merged, null, 2) + "\n");
|
|
10170
|
-
}
|
|
10171
|
-
function removeAntigravityGuard(p) {
|
|
10172
|
-
if (!existsSync4(p.antigravityHooksPath)) return;
|
|
10173
|
-
try {
|
|
10174
|
-
const s = JSON.parse(readFileSync9(p.antigravityHooksPath, "utf-8"));
|
|
10175
|
-
if (!(ANTIGRAVITY_GROUP in s)) return;
|
|
10176
|
-
delete s[ANTIGRAVITY_GROUP];
|
|
10177
|
-
writeFileSync9(p.antigravityHooksPath, JSON.stringify(s, null, 2) + "\n");
|
|
10178
|
-
} catch {
|
|
10179
|
-
}
|
|
10180
|
-
}
|
|
10181
|
-
function installGlobalQuiet() {
|
|
10182
|
-
try {
|
|
10183
|
-
const p = globalPaths();
|
|
10184
|
-
let apiKey = process.env["SOLONGATE_API_KEY"] || "";
|
|
10185
|
-
let apiUrl = process.env["SOLONGATE_API_URL"] || "https://api.solongate.com";
|
|
10186
|
-
try {
|
|
10187
|
-
const cfg = JSON.parse(readFileSync9(p.configPath, "utf-8"));
|
|
10188
|
-
if (cfg && typeof cfg.apiKey === "string") apiKey = apiKey || cfg.apiKey;
|
|
10189
|
-
if (cfg && typeof cfg.apiUrl === "string") apiUrl = cfg.apiUrl;
|
|
10190
|
-
} catch {
|
|
10191
|
-
}
|
|
10192
|
-
if (!apiKey) {
|
|
10193
|
-
const acc = firstAccountCredential();
|
|
10194
|
-
if (acc.apiKey) {
|
|
10195
|
-
apiKey = acc.apiKey;
|
|
10196
|
-
if (acc.apiUrl) apiUrl = acc.apiUrl;
|
|
10197
|
-
}
|
|
10198
|
-
}
|
|
10199
|
-
if (!apiKey) return { ok: false, message: "no login on this device \u2014 add an account first (Accounts \u2192 + add)" };
|
|
10200
|
-
mkdirSync8(p.hooksDir, { recursive: true });
|
|
10201
|
-
mkdirSync8(p.claudeDir, { recursive: true });
|
|
10202
|
-
unlockProtected();
|
|
10203
|
-
writeFileSync9(join11(p.hooksDir, "guard.mjs"), readGuard());
|
|
10204
|
-
writeFileSync9(join11(p.hooksDir, "audit.mjs"), readHook("audit.mjs"));
|
|
10205
|
-
writeFileSync9(join11(p.hooksDir, "stop.mjs"), readHook("stop.mjs"));
|
|
10206
|
-
writeFileSync9(join11(p.hooksDir, "shield.mjs"), readHook("shield.mjs"));
|
|
10207
|
-
writeFileSync9(p.configPath, JSON.stringify({ apiKey, apiUrl }, null, 2) + "\n");
|
|
10208
|
-
let existing = {};
|
|
10209
|
-
if (existsSync4(p.settingsPath)) {
|
|
10210
|
-
const raw = readFileSync9(p.settingsPath, "utf-8");
|
|
10211
|
-
if (!existsSync4(p.backupPath)) writeFileSync9(p.backupPath, raw);
|
|
10212
|
-
try {
|
|
10213
|
-
existing = JSON.parse(raw);
|
|
10214
|
-
} catch {
|
|
10215
|
-
existing = {};
|
|
10216
|
-
}
|
|
10217
|
-
}
|
|
10218
|
-
const nodeBin = process.execPath.replace(/\\/g, "/");
|
|
10219
|
-
const call = process.platform === "win32" ? "& " : "";
|
|
10220
|
-
const hookCmd = (script) => `${call}"${nodeBin}" "${join11(p.hooksDir, script).replace(/\\/g, "/")}" claude-code "Claude Code"`;
|
|
10221
|
-
const merged = {
|
|
10222
|
-
...existing,
|
|
10223
|
-
hooks: {
|
|
10224
|
-
PreToolUse: [{ matcher: "", hooks: [{ type: "command", command: hookCmd("guard.mjs") }] }],
|
|
10225
|
-
PostToolUse: [{ matcher: "", hooks: [{ type: "command", command: hookCmd("audit.mjs") }] }],
|
|
10226
|
-
Stop: [{ matcher: "", hooks: [{ type: "command", command: hookCmd("stop.mjs") }] }]
|
|
10227
|
-
}
|
|
10228
|
-
};
|
|
10229
|
-
writeFileSync9(p.settingsPath, JSON.stringify(merged, null, 2) + "\n");
|
|
10230
|
-
try {
|
|
10231
|
-
installAntigravityGuard(p, join11(p.hooksDir, "guard.mjs").replace(/\\/g, "/"));
|
|
10232
|
-
} catch {
|
|
10233
|
-
}
|
|
10234
|
-
if (process.env["SOLONGATE_OS_LOCK"] === "1") lockProtected();
|
|
10235
|
-
return { ok: true, message: "guard installed (open a new session)" };
|
|
10236
|
-
} catch (e) {
|
|
10237
|
-
return { ok: false, message: e instanceof Error ? e.message : String(e) };
|
|
10238
|
-
}
|
|
10239
|
-
}
|
|
10240
|
-
function installedGuardVersion() {
|
|
10241
|
-
try {
|
|
10242
|
-
const p = globalPaths();
|
|
10243
|
-
const s = readFileSync9(join11(p.hooksDir, "guard.mjs"), "utf-8");
|
|
10244
|
-
const m = s.match(/HOOK_VERSION\s*=\s*(\d+)/);
|
|
10245
|
-
return m ? parseInt(m[1], 10) : null;
|
|
10246
|
-
} catch {
|
|
10247
|
-
return null;
|
|
10248
|
-
}
|
|
10249
|
-
}
|
|
10250
|
-
function guardHookOutdated() {
|
|
10251
|
-
try {
|
|
10252
|
-
const p = globalPaths();
|
|
10253
|
-
return readFileSync9(join11(p.hooksDir, "guard.mjs"), "utf-8") !== readGuard();
|
|
10254
|
-
} catch {
|
|
10255
|
-
return false;
|
|
10256
|
-
}
|
|
10257
|
-
}
|
|
10258
|
-
function isGuardInstalled() {
|
|
10259
|
-
try {
|
|
10260
|
-
const p = globalPaths();
|
|
10261
|
-
if (!existsSync4(p.settingsPath)) return false;
|
|
10262
|
-
const s = JSON.parse(readFileSync9(p.settingsPath, "utf-8"));
|
|
10263
|
-
return !!s.hooks && JSON.stringify(s.hooks).includes(".solongate");
|
|
10264
|
-
} catch {
|
|
10265
|
-
return false;
|
|
10266
|
-
}
|
|
10267
|
-
}
|
|
10268
|
-
function uninstallGlobalQuiet() {
|
|
10269
|
-
try {
|
|
10270
|
-
const p = globalPaths();
|
|
10271
|
-
unlockProtected();
|
|
10272
|
-
removeClaudeShim();
|
|
10273
|
-
try {
|
|
10274
|
-
removeAntigravityGuard(p);
|
|
10275
|
-
} catch {
|
|
10276
|
-
}
|
|
10277
|
-
if (!existsSync4(p.settingsPath)) return { ok: true, message: "guard removed (open a new session)" };
|
|
10278
|
-
const s = JSON.parse(readFileSync9(p.settingsPath, "utf-8"));
|
|
10279
|
-
delete s.hooks;
|
|
10280
|
-
writeFileSync9(p.settingsPath, JSON.stringify(s, null, 2) + "\n");
|
|
10281
|
-
return { ok: true, message: "guard removed (open a new session)" };
|
|
10282
|
-
} catch (e) {
|
|
10283
|
-
return { ok: false, message: e instanceof Error ? e.message : String(e) };
|
|
10284
|
-
}
|
|
10285
|
-
}
|
|
10286
|
-
function escapeRe(s) {
|
|
10287
|
-
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
10288
|
-
}
|
|
10289
|
-
function shimTargets() {
|
|
10290
|
-
if (process.platform === "win32") {
|
|
10291
|
-
try {
|
|
10292
|
-
const prof = execFileSync2("powershell", ["-NoProfile", "-Command", "$PROFILE.CurrentUserAllHosts"], { encoding: "utf-8" }).trim();
|
|
10293
|
-
return prof ? [prof] : [];
|
|
10294
|
-
} catch {
|
|
10295
|
-
return [];
|
|
10296
|
-
}
|
|
10297
|
-
}
|
|
10298
|
-
return [".bashrc", ".zshrc", ".profile"].map((f) => join11(homedir9(), f)).filter((f) => existsSync4(f));
|
|
10299
|
-
}
|
|
10300
|
-
function writeShimBlock(file, block2) {
|
|
10301
|
-
const re = new RegExp(escapeRe(SHIM_BEGIN) + "[\\s\\S]*?" + escapeRe(SHIM_END) + "\\r?\\n?", "g");
|
|
10302
|
-
let content = existsSync4(file) ? readFileSync9(file, "utf-8") : "";
|
|
10303
|
-
content = content.replace(re, "");
|
|
10304
|
-
if (block2) {
|
|
10305
|
-
if (content.length && !content.endsWith("\n")) content += "\n";
|
|
10306
|
-
content += block2 + "\n";
|
|
10307
|
-
}
|
|
10308
|
-
mkdirSync8(dirname3(file), { recursive: true });
|
|
10309
|
-
writeFileSync9(file, content);
|
|
10310
|
-
}
|
|
10311
|
-
function removeClaudeShim() {
|
|
10312
|
-
for (const file of shimTargets()) {
|
|
10313
|
-
try {
|
|
10314
|
-
writeShimBlock(file, null);
|
|
10315
|
-
} catch {
|
|
10316
|
-
}
|
|
10317
|
-
}
|
|
10318
|
-
}
|
|
10319
|
-
var __dirname, HOOKS_DIR, ANTIGRAVITY_GROUP, SHIM_BEGIN, SHIM_END;
|
|
10320
|
-
var init_global_install = __esm({
|
|
10321
|
-
"src/global-install.ts"() {
|
|
10322
|
-
"use strict";
|
|
10323
|
-
__dirname = dirname3(fileURLToPath3(import.meta.url));
|
|
10324
|
-
HOOKS_DIR = resolve4(__dirname, "..", "hooks");
|
|
10325
|
-
ANTIGRAVITY_GROUP = "solongate-guard";
|
|
10326
|
-
SHIM_BEGIN = "# >>> SolonGate shield (auto secret redaction) >>>";
|
|
10327
|
-
SHIM_END = "# <<< SolonGate shield <<<";
|
|
10328
|
-
}
|
|
10329
|
-
});
|
|
10330
|
-
|
|
10331
10527
|
// src/tui/panels/Settings.tsx
|
|
10332
10528
|
import { Box as Box8, Text as Text8, useInput as useInput7 } from "ink";
|
|
10333
10529
|
import TextInput6 from "ink-text-input";
|
|
@@ -15862,7 +16058,7 @@ ${msg.content.text}`;
|
|
|
15862
16058
|
|
|
15863
16059
|
// src/index.ts
|
|
15864
16060
|
init_cli_utils();
|
|
15865
|
-
var CLI_SUBCOMMANDS = /* @__PURE__ */ new Set(["logs-server", "local-logs", "policy", "ratelimit", "dlp", "stats", "audit", "sessions", "session", "doctor", "watch", "alerts", "webhooks", "dataroom"]);
|
|
16061
|
+
var CLI_SUBCOMMANDS = /* @__PURE__ */ new Set(["update", "logs-server", "local-logs", "policy", "ratelimit", "dlp", "stats", "audit", "sessions", "session", "doctor", "watch", "alerts", "webhooks", "dataroom"]);
|
|
15866
16062
|
var CLI_INFO_ARGS = /* @__PURE__ */ new Set(["login", "help", "--help", "-h", "--version", "-v", "version"]);
|
|
15867
16063
|
var IS_HUMAN_CLI = process.argv.length <= 2 || CLI_SUBCOMMANDS.has(process.argv[2] ?? "") || CLI_INFO_ARGS.has(process.argv[2] ?? "");
|
|
15868
16064
|
if (!IS_HUMAN_CLI) {
|
|
@@ -15923,6 +16119,7 @@ function printHelp() {
|
|
|
15923
16119
|
console.log(` ${c.dim}Usage:${c.reset} ${c.cyan}solongate${c.reset} ${c.dim}[command]${c.reset} ${c.dim}(no command opens the dataroom: all of this in a terminal UI)${c.reset}`);
|
|
15924
16120
|
head("Setup & status");
|
|
15925
16121
|
cmd("solongate", "open the dataroom UI (login, policies, audit, settings)");
|
|
16122
|
+
cmd("update", "update SolonGate to the newest version and refresh the guard");
|
|
15926
16123
|
cmd("doctor", "health check: login, policy, guard, local logs");
|
|
15927
16124
|
cmd("doctor --json", "the same health check as machine-readable JSON");
|
|
15928
16125
|
cmd("logs-server start", "start the local audit-log service for the dashboard (background)");
|
|
@@ -15970,8 +16167,38 @@ function printHelp() {
|
|
|
15970
16167
|
console.log(` ${c.dim}Details for a command: ${c.reset}${c.cyan}solongate <command> help${c.reset}${c.dim} \xB7 Dashboard: ${c.reset}${c.cyan}https://dashboard.solongate.com${c.reset}`);
|
|
15971
16168
|
console.log("");
|
|
15972
16169
|
}
|
|
16170
|
+
var AGENT_ENV_MARKERS = [
|
|
16171
|
+
"CLAUDECODE",
|
|
16172
|
+
"CLAUDE_CODE",
|
|
16173
|
+
"CLAUDE_CODE_ENTRYPOINT",
|
|
16174
|
+
"ANTIGRAVITY",
|
|
16175
|
+
"ANTIGRAVITY_CLI",
|
|
16176
|
+
"GEMINI_CLI",
|
|
16177
|
+
"CURSOR_TRACE_ID",
|
|
16178
|
+
"AIDER_CHAT",
|
|
16179
|
+
"OPENAI_CODEX",
|
|
16180
|
+
"CODEX_SANDBOX",
|
|
16181
|
+
"OPENCLAW",
|
|
16182
|
+
"REPLIT_CLI",
|
|
16183
|
+
"DEVIN_session"
|
|
16184
|
+
];
|
|
16185
|
+
function assertHumanTerminal() {
|
|
16186
|
+
if (process.env["SOLONGATE_INTERNAL"] === "1") return;
|
|
16187
|
+
const marker = AGENT_ENV_MARKERS.find((k) => process.env[k]);
|
|
16188
|
+
const isTty = Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
16189
|
+
if (isTty && !marker) return;
|
|
16190
|
+
const w = (s) => void process.stderr.write(s + "\n");
|
|
16191
|
+
w("");
|
|
16192
|
+
w(" SolonGate is human-only.");
|
|
16193
|
+
w(" These commands control your security policy, so they cannot be run by an AI");
|
|
16194
|
+
w(" agent or any non-interactive process. Run them yourself, in a terminal.");
|
|
16195
|
+
w(marker ? ` (refused: agent environment detected via ${marker})` : " (refused: no interactive terminal)");
|
|
16196
|
+
w("");
|
|
16197
|
+
process.exit(1);
|
|
16198
|
+
}
|
|
15973
16199
|
async function main() {
|
|
15974
16200
|
const subcommand = process.argv[2];
|
|
16201
|
+
if (IS_HUMAN_CLI) assertHumanTerminal();
|
|
15975
16202
|
if (subcommand === "--help" || subcommand === "-h" || subcommand === "help") {
|
|
15976
16203
|
printHelp();
|
|
15977
16204
|
return;
|
|
@@ -16018,6 +16245,10 @@ async function main() {
|
|
|
16018
16245
|
console.log("");
|
|
16019
16246
|
return;
|
|
16020
16247
|
}
|
|
16248
|
+
if (subcommand === "update") {
|
|
16249
|
+
const { runUpdateCommand: runUpdateCommand2 } = await Promise.resolve().then(() => (init_self_update(), self_update_exports));
|
|
16250
|
+
process.exit(await runUpdateCommand2());
|
|
16251
|
+
}
|
|
16021
16252
|
if (subcommand === "logs-server" || subcommand === "local-logs") {
|
|
16022
16253
|
const { runLogsServer: runLogsServer2 } = await Promise.resolve().then(() => (init_logs_server(), logs_server_exports));
|
|
16023
16254
|
await runLogsServer2();
|