@solongate/proxy 0.83.56 → 0.83.58
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/commands/index.js +154 -71
- package/dist/global-install.d.ts +28 -0
- package/dist/global-install.js +349 -130
- package/dist/hook-health.d.ts +26 -0
- package/dist/hook-launcher.d.ts +57 -0
- package/dist/index.js +511 -252
- package/dist/tui/index.js +422 -167
- package/hooks/conversation.mjs +85 -30
- package/hooks/opencode-plugin.mjs +94 -1
- package/package.json +7 -7
package/dist/index.js
CHANGED
|
@@ -6187,14 +6187,213 @@ var init_cli_utils = __esm({
|
|
|
6187
6187
|
}
|
|
6188
6188
|
});
|
|
6189
6189
|
|
|
6190
|
+
// src/hook-launcher.ts
|
|
6191
|
+
function launcherScript(pinnedNode) {
|
|
6192
|
+
const pinned = pinnedNode.replace(/'/g, `'\\''`);
|
|
6193
|
+
return `#!/bin/sh
|
|
6194
|
+
# SolonGate hook launcher \u2014 generated by \`solongate init --global\` / \`repair\`.
|
|
6195
|
+
#
|
|
6196
|
+
# Finds a working node and execs the hook with it. Do not edit: a reinstall
|
|
6197
|
+
# overwrites this file, and on macOS it is chflags-locked besides.
|
|
6198
|
+
#
|
|
6199
|
+
# The reason it exists rather than the hook naming a node directly: an absolute
|
|
6200
|
+
# node path recorded at install time is a Homebrew Cellar path or an nvm version
|
|
6201
|
+
# directory, and both are deleted by a routine upgrade. The hook then could not
|
|
6202
|
+
# start, nothing was enforced, nothing was logged, and every check still said
|
|
6203
|
+
# the guard was registered \u2014 because it was.
|
|
6204
|
+
|
|
6205
|
+
set -u
|
|
6206
|
+
|
|
6207
|
+
script="\${1:-}"
|
|
6208
|
+
[ -n "$script" ] || { echo "solongate: launcher called with no hook script" >&2; exit 1; }
|
|
6209
|
+
shift
|
|
6210
|
+
|
|
6211
|
+
hook=\${script##*/}
|
|
6212
|
+
home=\${HOME:-~}
|
|
6213
|
+
beatdir="$home/.solongate/${BEAT_DIR}"
|
|
6214
|
+
|
|
6215
|
+
# The beat. Written BEFORE node is resolved, because its whole job is to record
|
|
6216
|
+
# that the client invoked us \u2014 which is true even when everything after this
|
|
6217
|
+
# line fails. The file's modification time is the timestamp; nothing is forked
|
|
6218
|
+
# to produce one, and the directory test is a builtin.
|
|
6219
|
+
#
|
|
6220
|
+
# The braces matter. A redirect into a missing directory is reported by the
|
|
6221
|
+
# SHELL, before the command runs, so a \`2>/dev/null\` on the printf alone does
|
|
6222
|
+
# not suppress it \u2014 it lands on the hook's stderr, and Claude Code shows a
|
|
6223
|
+
# hook's stderr to the person using it. Redirecting the group catches both.
|
|
6224
|
+
beat() {
|
|
6225
|
+
[ -d "$beatdir" ] || mkdir -p "$beatdir" 2>/dev/null || return 0
|
|
6226
|
+
{ printf '%s\\n' "$1" > "$beatdir/$hook"; } 2>/dev/null || true
|
|
6227
|
+
}
|
|
6228
|
+
|
|
6229
|
+
try() {
|
|
6230
|
+
[ -n "\${1:-}" ] && [ -x "$1" ]
|
|
6231
|
+
}
|
|
6232
|
+
|
|
6233
|
+
resolve_node() {
|
|
6234
|
+
# Told explicitly.
|
|
6235
|
+
if try "\${SOLONGATE_NODE:-}"; then echo "$SOLONGATE_NODE"; return 0; fi
|
|
6236
|
+
# The node this was installed with.
|
|
6237
|
+
if try '${pinned}'; then echo '${pinned}'; return 0; fi
|
|
6238
|
+
# PATH, when the client gave us one worth having.
|
|
6239
|
+
p=$(command -v node 2>/dev/null) || p=
|
|
6240
|
+
if try "$p"; then echo "$p"; return 0; fi
|
|
6241
|
+
# The fixed locations.
|
|
6242
|
+
for c in ${NODE_CANDIDATES.map((c2) => `"${c2}"`).join(" ")}; do
|
|
6243
|
+
for g in $c; do
|
|
6244
|
+
if try "$g"; then echo "$g"; return 0; fi
|
|
6245
|
+
done
|
|
6246
|
+
done
|
|
6247
|
+
# The version managers.
|
|
6248
|
+
for c in ${NODE_GLOBS.join(" ")}; do
|
|
6249
|
+
for g in $c; do
|
|
6250
|
+
if try "$g"; then echo "$g"; return 0; fi
|
|
6251
|
+
done
|
|
6252
|
+
done
|
|
6253
|
+
return 1
|
|
6254
|
+
}
|
|
6255
|
+
|
|
6256
|
+
node_bin=$(resolve_node) || node_bin=
|
|
6257
|
+
|
|
6258
|
+
# --sg-doctor: report what would be used and leave. This is what \`solongate
|
|
6259
|
+
# doctor\` runs, so the health check exercises the REAL resolution rather than a
|
|
6260
|
+
# copy of it that can drift.
|
|
6261
|
+
if [ "$script" = "--sg-doctor" ] || [ "\${1:-}" = "--sg-doctor" ]; then
|
|
6262
|
+
[ -n "$node_bin" ] && { echo "$node_bin"; exit 0; }
|
|
6263
|
+
echo "no node found" >&2
|
|
6264
|
+
exit 1
|
|
6265
|
+
fi
|
|
6266
|
+
|
|
6267
|
+
if [ -z "$node_bin" ]; then
|
|
6268
|
+
beat "no-node"
|
|
6269
|
+
# Nothing can be enforced without node, and which way to fail is not a
|
|
6270
|
+
# judgement call: the guard is fail-closed, so it refuses the call and says
|
|
6271
|
+
# why. Everything else here only records what already happened, and refusing
|
|
6272
|
+
# a tool call because the log could not be written would be a worse product
|
|
6273
|
+
# than a gap in the log.
|
|
6274
|
+
echo "solongate: no node runtime found, so $hook did not run." >&2
|
|
6275
|
+
echo "solongate: run \\\`solongate repair\\\` in a terminal, or set SOLONGATE_NODE to your node binary." >&2
|
|
6276
|
+
case "$hook" in
|
|
6277
|
+
guard.mjs) echo "solongate: this tool call is REFUSED \u2014 the guard is fail-closed." >&2; exit 2 ;;
|
|
6278
|
+
*) exit 0 ;;
|
|
6279
|
+
esac
|
|
6280
|
+
fi
|
|
6281
|
+
|
|
6282
|
+
beat "$node_bin"
|
|
6283
|
+
exec "$node_bin" "$script" "$@"
|
|
6284
|
+
`;
|
|
6285
|
+
}
|
|
6286
|
+
var NODE_CANDIDATES, NODE_GLOBS, LAUNCHER_NAME, BEAT_DIR;
|
|
6287
|
+
var init_hook_launcher = __esm({
|
|
6288
|
+
"src/hook-launcher.ts"() {
|
|
6289
|
+
"use strict";
|
|
6290
|
+
NODE_CANDIDATES = [
|
|
6291
|
+
// Homebrew, by the STABLE symlink rather than the Cellar path behind it —
|
|
6292
|
+
// the exact distinction this file exists for. Apple Silicon then Intel.
|
|
6293
|
+
"/opt/homebrew/bin/node",
|
|
6294
|
+
"/usr/local/bin/node",
|
|
6295
|
+
// Homebrew's keg-only layout, both prefixes.
|
|
6296
|
+
"/opt/homebrew/opt/node/bin/node",
|
|
6297
|
+
"/usr/local/opt/node/bin/node",
|
|
6298
|
+
// Distro and hand-built.
|
|
6299
|
+
"/usr/bin/node",
|
|
6300
|
+
"/usr/local/n/versions/node/*/bin/node",
|
|
6301
|
+
"/snap/bin/node"
|
|
6302
|
+
];
|
|
6303
|
+
NODE_GLOBS = [
|
|
6304
|
+
// nvm. NVM_DIR is exported by its own shell hook, which a non-interactive
|
|
6305
|
+
// hook environment does not run, so the default location is tried too.
|
|
6306
|
+
'"${NVM_DIR:-}"/versions/node/*/bin/node',
|
|
6307
|
+
'"$home"/.nvm/versions/node/*/bin/node',
|
|
6308
|
+
// fnm, both the XDG location and the macOS Application Support one.
|
|
6309
|
+
'"$home"/.local/share/fnm/node-versions/*/installation/bin/node',
|
|
6310
|
+
'"$home"/Library/Application Support/fnm/node-versions/*/installation/bin/node',
|
|
6311
|
+
// Volta.
|
|
6312
|
+
'"$home"/.volta/tools/image/node/*/bin/node',
|
|
6313
|
+
// asdf, old layout and the current plugin one.
|
|
6314
|
+
'"$home"/.asdf/installs/nodejs/*/bin/node',
|
|
6315
|
+
'"$home"/.asdf/installs/node/*/bin/node'
|
|
6316
|
+
];
|
|
6317
|
+
LAUNCHER_NAME = "sg-run.sh";
|
|
6318
|
+
BEAT_DIR = ".beat";
|
|
6319
|
+
}
|
|
6320
|
+
});
|
|
6321
|
+
|
|
6322
|
+
// src/hook-health.ts
|
|
6323
|
+
import { execFileSync as execFileSync2 } from "child_process";
|
|
6324
|
+
import { existsSync as existsSync3, readFileSync as readFileSync4, statSync } from "fs";
|
|
6325
|
+
import { join as join4 } from "path";
|
|
6326
|
+
import { homedir as homedir2 } from "os";
|
|
6327
|
+
function hookCanStart() {
|
|
6328
|
+
const launcher = join4(hooksDir(), LAUNCHER_NAME);
|
|
6329
|
+
if (process.platform === "win32") {
|
|
6330
|
+
const ok = existsSync3(process.execPath);
|
|
6331
|
+
return { ok, node: process.execPath, detail: ok ? process.execPath : `${process.execPath} is gone` };
|
|
6332
|
+
}
|
|
6333
|
+
if (!existsSync3(launcher)) {
|
|
6334
|
+
return { ok: false, detail: "hook launcher missing - run `solongate repair`" };
|
|
6335
|
+
}
|
|
6336
|
+
try {
|
|
6337
|
+
const out2 = execFileSync2("/bin/sh", [launcher, "--sg-doctor"], {
|
|
6338
|
+
encoding: "utf-8",
|
|
6339
|
+
timeout: 5e3,
|
|
6340
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
6341
|
+
}).trim();
|
|
6342
|
+
if (!out2) return { ok: false, detail: "launcher found no node runtime - set SOLONGATE_NODE or install node" };
|
|
6343
|
+
return { ok: true, node: out2, detail: out2 };
|
|
6344
|
+
} catch (e) {
|
|
6345
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
6346
|
+
return { ok: false, detail: `launcher will not run: ${msg.split("\n")[0]}` };
|
|
6347
|
+
}
|
|
6348
|
+
}
|
|
6349
|
+
function hookBeats() {
|
|
6350
|
+
const dir = join4(sgDir(), BEAT_DIR);
|
|
6351
|
+
const out2 = [];
|
|
6352
|
+
for (const hook of ["guard.mjs", "audit.mjs", "conversation.mjs", "stop.mjs"]) {
|
|
6353
|
+
const f = join4(dir, hook);
|
|
6354
|
+
try {
|
|
6355
|
+
const st = statSync(f);
|
|
6356
|
+
out2.push({ hook, at: st.mtime, node: readFileSync4(f, "utf-8").trim() });
|
|
6357
|
+
} catch {
|
|
6358
|
+
}
|
|
6359
|
+
}
|
|
6360
|
+
return out2.sort((a, b) => b.at.getTime() - a.at.getTime());
|
|
6361
|
+
}
|
|
6362
|
+
function guardBeat() {
|
|
6363
|
+
return hookBeats().find((b) => b.hook === "guard.mjs") ?? null;
|
|
6364
|
+
}
|
|
6365
|
+
function agoLabel(d) {
|
|
6366
|
+
const s = Math.max(0, Math.round((Date.now() - d.getTime()) / 1e3));
|
|
6367
|
+
if (s < 60) return s <= 3 ? "just now" : `${s}s ago`;
|
|
6368
|
+
if (s < 3600) return `${Math.round(s / 60)}m ago`;
|
|
6369
|
+
if (s < 86400) return `${Math.round(s / 3600)}h ago`;
|
|
6370
|
+
return `${Math.round(s / 86400)}d ago`;
|
|
6371
|
+
}
|
|
6372
|
+
var sgDir, hooksDir;
|
|
6373
|
+
var init_hook_health = __esm({
|
|
6374
|
+
"src/hook-health.ts"() {
|
|
6375
|
+
"use strict";
|
|
6376
|
+
init_hook_launcher();
|
|
6377
|
+
sgDir = () => join4(homedir2(), ".solongate");
|
|
6378
|
+
hooksDir = () => join4(sgDir(), "hooks");
|
|
6379
|
+
}
|
|
6380
|
+
});
|
|
6381
|
+
|
|
6190
6382
|
// src/global-install.ts
|
|
6191
6383
|
var global_install_exports = {};
|
|
6192
6384
|
__export(global_install_exports, {
|
|
6385
|
+
BEAT_DIR: () => BEAT_DIR,
|
|
6386
|
+
LAUNCHER_NAME: () => LAUNCHER_NAME,
|
|
6387
|
+
agoLabel: () => agoLabel,
|
|
6193
6388
|
clearGuardUpdateCheck: () => clearGuardUpdateCheck,
|
|
6194
6389
|
codexDetected: () => codexDetected,
|
|
6195
6390
|
codexHooksStatus: () => codexHooksStatus,
|
|
6196
6391
|
globalPaths: () => globalPaths,
|
|
6392
|
+
guardBeat: () => guardBeat,
|
|
6197
6393
|
guardHookOutdated: () => guardHookOutdated,
|
|
6394
|
+
hookBeats: () => hookBeats,
|
|
6395
|
+
hookCanStart: () => hookCanStart,
|
|
6396
|
+
hookCommandFor: () => hookCommandFor,
|
|
6198
6397
|
installClaudeShim: () => installClaudeShim,
|
|
6199
6398
|
installGlobalQuiet: () => installGlobalQuiet,
|
|
6200
6399
|
installGlobalWithKey: () => installGlobalWithKey,
|
|
@@ -6202,6 +6401,7 @@ __export(global_install_exports, {
|
|
|
6202
6401
|
isCodexGuardInstalled: () => isCodexGuardInstalled,
|
|
6203
6402
|
isGuardInstalled: () => isGuardInstalled,
|
|
6204
6403
|
isOpencodeGuardInstalled: () => isOpencodeGuardInstalled,
|
|
6404
|
+
launcherScript: () => launcherScript,
|
|
6205
6405
|
lockProtected: () => lockProtected,
|
|
6206
6406
|
opencodeDetected: () => opencodeDetected,
|
|
6207
6407
|
removeClaudeShim: () => removeClaudeShim,
|
|
@@ -6212,39 +6412,40 @@ __export(global_install_exports, {
|
|
|
6212
6412
|
sweepStrayScratchDirs: () => sweepStrayScratchDirs,
|
|
6213
6413
|
uninstallGlobalQuiet: () => uninstallGlobalQuiet,
|
|
6214
6414
|
unlockProtected: () => unlockProtected,
|
|
6415
|
+
writeLauncher: () => writeLauncher,
|
|
6215
6416
|
writeProtectedFile: () => writeProtectedFile
|
|
6216
6417
|
});
|
|
6217
|
-
import { readFileSync as
|
|
6218
|
-
import { resolve as resolve3, join as
|
|
6219
|
-
import { homedir as
|
|
6418
|
+
import { readFileSync as readFileSync5, writeFileSync as writeFileSync3, existsSync as existsSync4, mkdirSync as mkdirSync3, rmSync as rmSync2, rmdirSync, readdirSync, statSync as statSync2, chmodSync, copyFileSync, renameSync } from "fs";
|
|
6419
|
+
import { resolve as resolve3, join as join5, dirname, basename } from "path";
|
|
6420
|
+
import { homedir as homedir3 } from "os";
|
|
6220
6421
|
import { createRequire } from "module";
|
|
6221
6422
|
import { fileURLToPath } from "url";
|
|
6222
6423
|
import { createInterface } from "readline";
|
|
6223
|
-
import { execFileSync as
|
|
6424
|
+
import { execFileSync as execFileSync3, spawn } from "child_process";
|
|
6224
6425
|
function lockFile(file) {
|
|
6225
|
-
if (!
|
|
6426
|
+
if (!existsSync4(file)) return;
|
|
6226
6427
|
try {
|
|
6227
6428
|
if (process.platform === "win32") {
|
|
6228
6429
|
try {
|
|
6229
|
-
|
|
6430
|
+
execFileSync3("icacls", [file, "/deny", "*S-1-1-0:(WD,AD,DC,DE,WDAC,WO)"], { stdio: "ignore" });
|
|
6230
6431
|
} catch {
|
|
6231
6432
|
}
|
|
6232
6433
|
try {
|
|
6233
|
-
|
|
6434
|
+
execFileSync3("icacls", [file, "/grant", "*S-1-3-4:(RX)"], { stdio: "ignore" });
|
|
6234
6435
|
} catch {
|
|
6235
6436
|
}
|
|
6236
6437
|
try {
|
|
6237
|
-
|
|
6438
|
+
execFileSync3("attrib", ["+R", file], { stdio: "ignore" });
|
|
6238
6439
|
} catch {
|
|
6239
6440
|
}
|
|
6240
6441
|
} else if (process.platform === "darwin") {
|
|
6241
6442
|
try {
|
|
6242
|
-
|
|
6443
|
+
execFileSync3("chflags", ["uchg", file], { stdio: "ignore" });
|
|
6243
6444
|
} catch {
|
|
6244
6445
|
}
|
|
6245
6446
|
} else {
|
|
6246
6447
|
try {
|
|
6247
|
-
|
|
6448
|
+
execFileSync3("chattr", ["+i", file], { stdio: "ignore" });
|
|
6248
6449
|
} catch {
|
|
6249
6450
|
}
|
|
6250
6451
|
try {
|
|
@@ -6256,33 +6457,33 @@ function lockFile(file) {
|
|
|
6256
6457
|
}
|
|
6257
6458
|
}
|
|
6258
6459
|
function unlockFile(file) {
|
|
6259
|
-
if (!
|
|
6460
|
+
if (!existsSync4(file)) return;
|
|
6260
6461
|
try {
|
|
6261
6462
|
if (process.platform === "win32") {
|
|
6262
6463
|
try {
|
|
6263
|
-
|
|
6464
|
+
execFileSync3("icacls", [file, "/remove:g", "*S-1-3-4"], { stdio: "ignore" });
|
|
6264
6465
|
} catch {
|
|
6265
6466
|
}
|
|
6266
6467
|
try {
|
|
6267
|
-
|
|
6468
|
+
execFileSync3("icacls", [file, "/remove:d", "*S-1-1-0"], { stdio: "ignore" });
|
|
6268
6469
|
} catch {
|
|
6269
6470
|
}
|
|
6270
6471
|
try {
|
|
6271
|
-
|
|
6472
|
+
execFileSync3("icacls", [file, "/reset"], { stdio: "ignore" });
|
|
6272
6473
|
} catch {
|
|
6273
6474
|
}
|
|
6274
6475
|
try {
|
|
6275
|
-
|
|
6476
|
+
execFileSync3("attrib", ["-R", file], { stdio: "ignore" });
|
|
6276
6477
|
} catch {
|
|
6277
6478
|
}
|
|
6278
6479
|
} else if (process.platform === "darwin") {
|
|
6279
6480
|
try {
|
|
6280
|
-
|
|
6481
|
+
execFileSync3("chflags", ["nouchg", file], { stdio: "ignore" });
|
|
6281
6482
|
} catch {
|
|
6282
6483
|
}
|
|
6283
6484
|
} else {
|
|
6284
6485
|
try {
|
|
6285
|
-
|
|
6486
|
+
execFileSync3("chattr", ["-i", file], { stdio: "ignore" });
|
|
6286
6487
|
} catch {
|
|
6287
6488
|
}
|
|
6288
6489
|
try {
|
|
@@ -6296,14 +6497,19 @@ function unlockFile(file) {
|
|
|
6296
6497
|
function protectedTargets() {
|
|
6297
6498
|
const p = globalPaths();
|
|
6298
6499
|
return [
|
|
6299
|
-
|
|
6300
|
-
|
|
6301
|
-
|
|
6302
|
-
|
|
6500
|
+
join5(p.hooksDir, "guard.mjs"),
|
|
6501
|
+
join5(p.hooksDir, "audit.mjs"),
|
|
6502
|
+
join5(p.hooksDir, "stop.mjs"),
|
|
6503
|
+
join5(p.hooksDir, "shield.mjs"),
|
|
6303
6504
|
// The conversation record is locked with the rest. A guest who could edit
|
|
6304
6505
|
// it could decide what their host sees them say, which is the same class of
|
|
6305
6506
|
// problem as editing the guard.
|
|
6306
|
-
|
|
6507
|
+
join5(p.hooksDir, "conversation.mjs"),
|
|
6508
|
+
// The launcher is the enforcement path now: every hook command in every
|
|
6509
|
+
// client config runs THROUGH it. A program that could rewrite it could
|
|
6510
|
+
// point every hook at /bin/true and disarm the guard without touching a
|
|
6511
|
+
// single file that used to be locked.
|
|
6512
|
+
join5(p.hooksDir, LAUNCHER_NAME),
|
|
6307
6513
|
p.configPath,
|
|
6308
6514
|
p.settingsPath,
|
|
6309
6515
|
p.antigravityHooksPath,
|
|
@@ -6337,60 +6543,60 @@ function writeProtectedFile(file, contents) {
|
|
|
6337
6543
|
}
|
|
6338
6544
|
}
|
|
6339
6545
|
function globalPaths() {
|
|
6340
|
-
const home =
|
|
6341
|
-
const
|
|
6342
|
-
const
|
|
6343
|
-
const claudeDir =
|
|
6344
|
-
const antigravityDir =
|
|
6345
|
-
const codexDir = process.env["CODEX_HOME"] ? resolve3(process.env["CODEX_HOME"]) :
|
|
6346
|
-
const opencodeDir =
|
|
6347
|
-
const binDir =
|
|
6546
|
+
const home = homedir3();
|
|
6547
|
+
const sgDir2 = join5(home, ".solongate");
|
|
6548
|
+
const hooksDir2 = join5(sgDir2, "hooks");
|
|
6549
|
+
const claudeDir = join5(home, ".claude");
|
|
6550
|
+
const antigravityDir = join5(home, ".gemini", "config");
|
|
6551
|
+
const codexDir = process.env["CODEX_HOME"] ? resolve3(process.env["CODEX_HOME"]) : join5(home, ".codex");
|
|
6552
|
+
const opencodeDir = join5(process.env["XDG_CONFIG_HOME"] ? resolve3(process.env["XDG_CONFIG_HOME"]) : join5(home, ".config"), "opencode");
|
|
6553
|
+
const binDir = join5(sgDir2, "bin");
|
|
6348
6554
|
return {
|
|
6349
6555
|
home,
|
|
6350
|
-
sgDir,
|
|
6351
|
-
hooksDir,
|
|
6556
|
+
sgDir: sgDir2,
|
|
6557
|
+
hooksDir: hooksDir2,
|
|
6352
6558
|
binDir,
|
|
6353
6559
|
claudeDir,
|
|
6354
6560
|
antigravityDir,
|
|
6355
6561
|
codexDir,
|
|
6356
6562
|
opencodeDir,
|
|
6357
|
-
settingsPath:
|
|
6358
|
-
backupPath:
|
|
6359
|
-
configPath:
|
|
6563
|
+
settingsPath: join5(claudeDir, "settings.json"),
|
|
6564
|
+
backupPath: join5(claudeDir, "settings.solongate.bak"),
|
|
6565
|
+
configPath: join5(sgDir2, "cloud-guard.json"),
|
|
6360
6566
|
// Antigravity reads global hooks from ~/.gemini/config/hooks.json. Only the
|
|
6361
6567
|
// guard is registered there (PreToolUse); Antigravity's ALLOW-path audit is
|
|
6362
6568
|
// covered by the passive session-log collector, not a hook.
|
|
6363
|
-
antigravityHooksPath:
|
|
6364
|
-
antigravityBackupPath:
|
|
6569
|
+
antigravityHooksPath: join5(antigravityDir, "hooks.json"),
|
|
6570
|
+
antigravityBackupPath: join5(antigravityDir, "hooks.solongate.bak"),
|
|
6365
6571
|
// Codex reads user-level hooks from ~/.codex/hooks.json (or a [hooks] table
|
|
6366
6572
|
// in ~/.codex/config.toml — we use the JSON file so we never have to rewrite
|
|
6367
6573
|
// the user's TOML, which also holds the hook TRUST state Codex manages).
|
|
6368
|
-
codexHooksPath:
|
|
6369
|
-
codexBackupPath:
|
|
6370
|
-
codexConfigPath:
|
|
6574
|
+
codexHooksPath: join5(codexDir, "hooks.json"),
|
|
6575
|
+
codexBackupPath: join5(codexDir, "hooks.solongate.bak"),
|
|
6576
|
+
codexConfigPath: join5(codexDir, "config.toml"),
|
|
6371
6577
|
// OpenCode scans its plugin folder at startup and loads every module in it.
|
|
6372
6578
|
// Measured on 1.18.10: BOTH `plugin/` and `plugins/` are scanned, so the
|
|
6373
6579
|
// docs and the field reports are each half right. We write the documented
|
|
6374
6580
|
// one. There is nothing to register anywhere — dropping the file IS the
|
|
6375
6581
|
// installation, which also means deleting the file IS the uninstall.
|
|
6376
|
-
opencodePluginDir:
|
|
6377
|
-
opencodePluginPath:
|
|
6582
|
+
opencodePluginDir: join5(opencodeDir, "plugins"),
|
|
6583
|
+
opencodePluginPath: join5(opencodeDir, "plugins", "solongate.js")
|
|
6378
6584
|
};
|
|
6379
6585
|
}
|
|
6380
6586
|
function clearGuardUpdateCheck() {
|
|
6381
6587
|
try {
|
|
6382
|
-
rmSync2(
|
|
6588
|
+
rmSync2(join5(globalPaths().sgDir, ".hook-update-check"), { force: true });
|
|
6383
6589
|
return true;
|
|
6384
6590
|
} catch {
|
|
6385
6591
|
return false;
|
|
6386
6592
|
}
|
|
6387
6593
|
}
|
|
6388
6594
|
function readHook(filename) {
|
|
6389
|
-
return
|
|
6595
|
+
return readFileSync5(join5(HOOKS_DIR, filename), "utf-8");
|
|
6390
6596
|
}
|
|
6391
6597
|
function firstAccountCredential() {
|
|
6392
6598
|
try {
|
|
6393
|
-
const raw = JSON.parse(
|
|
6599
|
+
const raw = JSON.parse(readFileSync5(join5(homedir3(), ".solongate", "accounts.json"), "utf-8"));
|
|
6394
6600
|
if (Array.isArray(raw)) {
|
|
6395
6601
|
const acc = raw.find((a) => a && typeof a.apiKey === "string" && a.apiKey);
|
|
6396
6602
|
if (acc) return { apiKey: acc.apiKey, apiUrl: typeof acc.apiUrl === "string" ? acc.apiUrl : void 0 };
|
|
@@ -6400,8 +6606,8 @@ function firstAccountCredential() {
|
|
|
6400
6606
|
return {};
|
|
6401
6607
|
}
|
|
6402
6608
|
function readGuard() {
|
|
6403
|
-
const bundled =
|
|
6404
|
-
return
|
|
6609
|
+
const bundled = join5(HOOKS_DIR, "guard.bundled.mjs");
|
|
6610
|
+
return existsSync4(bundled) ? readFileSync5(bundled, "utf-8") : readHook("guard.mjs");
|
|
6405
6611
|
}
|
|
6406
6612
|
function installGoBinaries(binDir) {
|
|
6407
6613
|
const os_ = process.platform === "win32" ? "win32" : process.platform;
|
|
@@ -6421,10 +6627,10 @@ function installGoBinaries(binDir) {
|
|
|
6421
6627
|
return placed;
|
|
6422
6628
|
}
|
|
6423
6629
|
for (const name of ["solongate-guard", "solongate"]) {
|
|
6424
|
-
const from =
|
|
6425
|
-
const to =
|
|
6630
|
+
const from = join5(pkgDir, name + suffix);
|
|
6631
|
+
const to = join5(binDir, name + suffix);
|
|
6426
6632
|
try {
|
|
6427
|
-
if (!
|
|
6633
|
+
if (!existsSync4(from)) continue;
|
|
6428
6634
|
const tmp = to + ".new";
|
|
6429
6635
|
copyFileSync(from, tmp);
|
|
6430
6636
|
chmodSync(tmp, 493);
|
|
@@ -6436,16 +6642,17 @@ function installGoBinaries(binDir) {
|
|
|
6436
6642
|
return placed;
|
|
6437
6643
|
}
|
|
6438
6644
|
function antigravityHookCommand(guardAbs) {
|
|
6439
|
-
|
|
6440
|
-
|
|
6441
|
-
|
|
6645
|
+
return hookCommandFor(dirname(guardAbs), basename(guardAbs), "antigravity", "Antigravity");
|
|
6646
|
+
}
|
|
6647
|
+
function antigravityConversationCommand(guardAbs) {
|
|
6648
|
+
return hookCommandFor(dirname(guardAbs), "conversation.mjs", "antigravity", "Antigravity");
|
|
6442
6649
|
}
|
|
6443
6650
|
function installAntigravityGuard(p, guardAbs) {
|
|
6444
6651
|
mkdirSync3(p.antigravityDir, { recursive: true });
|
|
6445
6652
|
let existing = {};
|
|
6446
|
-
if (
|
|
6447
|
-
const raw =
|
|
6448
|
-
if (!
|
|
6653
|
+
if (existsSync4(p.antigravityHooksPath)) {
|
|
6654
|
+
const raw = readFileSync5(p.antigravityHooksPath, "utf-8");
|
|
6655
|
+
if (!existsSync4(p.antigravityBackupPath)) writeFileSync3(p.antigravityBackupPath, raw);
|
|
6449
6656
|
try {
|
|
6450
6657
|
existing = JSON.parse(raw);
|
|
6451
6658
|
} catch {
|
|
@@ -6455,15 +6662,16 @@ function installAntigravityGuard(p, guardAbs) {
|
|
|
6455
6662
|
const merged = {
|
|
6456
6663
|
...existing,
|
|
6457
6664
|
[ANTIGRAVITY_GROUP]: {
|
|
6458
|
-
PreToolUse: [{ matcher: "", hooks: [{ type: "command", command: antigravityHookCommand(guardAbs) }] }]
|
|
6665
|
+
PreToolUse: [{ matcher: "", hooks: [{ type: "command", command: antigravityHookCommand(guardAbs) }] }],
|
|
6666
|
+
Stop: [{ matcher: "", hooks: [{ type: "command", command: antigravityConversationCommand(guardAbs) }] }]
|
|
6459
6667
|
}
|
|
6460
6668
|
};
|
|
6461
6669
|
writeFileSync3(p.antigravityHooksPath, JSON.stringify(merged, null, 2) + "\n");
|
|
6462
6670
|
}
|
|
6463
6671
|
function removeAntigravityGuard(p) {
|
|
6464
|
-
if (!
|
|
6672
|
+
if (!existsSync4(p.antigravityHooksPath)) return;
|
|
6465
6673
|
try {
|
|
6466
|
-
const s = JSON.parse(
|
|
6674
|
+
const s = JSON.parse(readFileSync5(p.antigravityHooksPath, "utf-8"));
|
|
6467
6675
|
if (!(ANTIGRAVITY_GROUP in s)) return;
|
|
6468
6676
|
delete s[ANTIGRAVITY_GROUP];
|
|
6469
6677
|
writeFileSync3(p.antigravityHooksPath, JSON.stringify(s, null, 2) + "\n");
|
|
@@ -6471,8 +6679,10 @@ function removeAntigravityGuard(p) {
|
|
|
6471
6679
|
}
|
|
6472
6680
|
}
|
|
6473
6681
|
function codexHookCommand(scriptAbs) {
|
|
6474
|
-
|
|
6475
|
-
|
|
6682
|
+
if (process.platform === "win32") {
|
|
6683
|
+
return `"${process.execPath.replace(/\\/g, "/")}" "${scriptAbs.replace(/\\/g, "/")}" codex "Codex"`;
|
|
6684
|
+
}
|
|
6685
|
+
return hookCommandFor(dirname(scriptAbs), basename(scriptAbs), "codex", "Codex");
|
|
6476
6686
|
}
|
|
6477
6687
|
function isOurCodexGroup(group) {
|
|
6478
6688
|
const hooks = Array.isArray(group?.hooks) ? group.hooks : [];
|
|
@@ -6480,10 +6690,10 @@ function isOurCodexGroup(group) {
|
|
|
6480
6690
|
}
|
|
6481
6691
|
function readCodexHooksFile(path) {
|
|
6482
6692
|
const out2 = { hooks: {}, rest: {} };
|
|
6483
|
-
if (!
|
|
6693
|
+
if (!existsSync4(path)) return out2;
|
|
6484
6694
|
let raw;
|
|
6485
6695
|
try {
|
|
6486
|
-
raw = JSON.parse(
|
|
6696
|
+
raw = JSON.parse(readFileSync5(path, "utf-8"));
|
|
6487
6697
|
} catch {
|
|
6488
6698
|
return out2;
|
|
6489
6699
|
}
|
|
@@ -6528,10 +6738,10 @@ function writeCodexHooksFile(path, file) {
|
|
|
6528
6738
|
body["hooks"] = hooks;
|
|
6529
6739
|
writeFileSync3(path, JSON.stringify(body, null, 2) + "\n");
|
|
6530
6740
|
}
|
|
6531
|
-
function installCodexGuard(p,
|
|
6741
|
+
function installCodexGuard(p, hooksDir2) {
|
|
6532
6742
|
mkdirSync3(p.codexDir, { recursive: true });
|
|
6533
|
-
if (
|
|
6534
|
-
writeFileSync3(p.codexBackupPath,
|
|
6743
|
+
if (existsSync4(p.codexHooksPath) && !existsSync4(p.codexBackupPath)) {
|
|
6744
|
+
writeFileSync3(p.codexBackupPath, readFileSync5(p.codexHooksPath, "utf-8"));
|
|
6535
6745
|
}
|
|
6536
6746
|
const file = readCodexHooksFile(p.codexHooksPath);
|
|
6537
6747
|
const script = {
|
|
@@ -6555,7 +6765,7 @@ function installCodexGuard(p, hooksDir) {
|
|
|
6555
6765
|
...ev === "Stop" ? {} : { matcher: "*" },
|
|
6556
6766
|
hooks: [{
|
|
6557
6767
|
type: "command",
|
|
6558
|
-
command: codexHookCommand(
|
|
6768
|
+
command: codexHookCommand(join5(hooksDir2, script[ev]).replace(/\\/g, "/")),
|
|
6559
6769
|
timeout: CODEX_TIMEOUT_SEC,
|
|
6560
6770
|
statusMessage: status[ev]
|
|
6561
6771
|
}]
|
|
@@ -6565,7 +6775,7 @@ function installCodexGuard(p, hooksDir) {
|
|
|
6565
6775
|
writeCodexHooksFile(p.codexHooksPath, file);
|
|
6566
6776
|
}
|
|
6567
6777
|
function removeCodexGuard(p) {
|
|
6568
|
-
if (!
|
|
6778
|
+
if (!existsSync4(p.codexHooksPath)) return;
|
|
6569
6779
|
try {
|
|
6570
6780
|
const file = readCodexHooksFile(p.codexHooksPath);
|
|
6571
6781
|
let changed = false;
|
|
@@ -6591,7 +6801,7 @@ function isCodexGuardInstalled() {
|
|
|
6591
6801
|
}
|
|
6592
6802
|
function codexDetected() {
|
|
6593
6803
|
try {
|
|
6594
|
-
return
|
|
6804
|
+
return existsSync4(globalPaths().codexDir);
|
|
6595
6805
|
} catch {
|
|
6596
6806
|
return false;
|
|
6597
6807
|
}
|
|
@@ -6601,7 +6811,7 @@ function codexHooksStatus() {
|
|
|
6601
6811
|
const registered = isCodexGuardInstalled();
|
|
6602
6812
|
let trusted = false, disabled = false;
|
|
6603
6813
|
try {
|
|
6604
|
-
const toml =
|
|
6814
|
+
const toml = readFileSync5(p.codexConfigPath, "utf-8");
|
|
6605
6815
|
trusted = /trusted_hash\s*=/.test(toml);
|
|
6606
6816
|
disabled = /^\s*hooks\s*=\s*false\s*$/m.test(toml);
|
|
6607
6817
|
} catch {
|
|
@@ -6620,10 +6830,10 @@ function removeOpencodeGuard(p) {
|
|
|
6620
6830
|
} catch {
|
|
6621
6831
|
}
|
|
6622
6832
|
}
|
|
6623
|
-
function warmPolicyCache(
|
|
6833
|
+
function warmPolicyCache(hooksDir2, agents) {
|
|
6624
6834
|
for (const agent of agents) {
|
|
6625
6835
|
try {
|
|
6626
|
-
const child = spawn(process.execPath, [
|
|
6836
|
+
const child = spawn(process.execPath, [join5(hooksDir2, "guard.mjs"), agent, "--sg-refresh-policy"], {
|
|
6627
6837
|
detached: true,
|
|
6628
6838
|
stdio: "ignore",
|
|
6629
6839
|
windowsHide: true
|
|
@@ -6637,23 +6847,23 @@ function warmPolicyCache(hooksDir, agents) {
|
|
|
6637
6847
|
}
|
|
6638
6848
|
function isOpencodeGuardInstalled() {
|
|
6639
6849
|
try {
|
|
6640
|
-
return
|
|
6850
|
+
return readFileSync5(globalPaths().opencodePluginPath, "utf-8").includes("tool.execute.before");
|
|
6641
6851
|
} catch {
|
|
6642
6852
|
return false;
|
|
6643
6853
|
}
|
|
6644
6854
|
}
|
|
6645
6855
|
function opencodeDetected() {
|
|
6646
6856
|
try {
|
|
6647
|
-
return
|
|
6857
|
+
return existsSync4(globalPaths().opencodeDir);
|
|
6648
6858
|
} catch {
|
|
6649
6859
|
return false;
|
|
6650
6860
|
}
|
|
6651
6861
|
}
|
|
6652
|
-
function sweepStrayScratchDirs(root =
|
|
6862
|
+
function sweepStrayScratchDirs(root = homedir3(), maxDepth = 6, budget = 4e4) {
|
|
6653
6863
|
let removed = 0;
|
|
6654
6864
|
let visited = 0;
|
|
6655
6865
|
const skip = /* @__PURE__ */ new Set(["node_modules", ".git", "dist", ".next", "build"]);
|
|
6656
|
-
const store =
|
|
6866
|
+
const store = join5(homedir3(), ".solongate");
|
|
6657
6867
|
const walk = (dir, depth) => {
|
|
6658
6868
|
if (depth > maxDepth || visited++ > budget) return;
|
|
6659
6869
|
let entries;
|
|
@@ -6664,11 +6874,11 @@ function sweepStrayScratchDirs(root = homedir2(), maxDepth = 6, budget = 4e4) {
|
|
|
6664
6874
|
}
|
|
6665
6875
|
for (const name of entries) {
|
|
6666
6876
|
if (skip.has(name)) continue;
|
|
6667
|
-
const full =
|
|
6877
|
+
const full = join5(dir, name);
|
|
6668
6878
|
if (full === store) continue;
|
|
6669
6879
|
let isDir = false;
|
|
6670
6880
|
try {
|
|
6671
|
-
isDir =
|
|
6881
|
+
isDir = statSync2(full).isDirectory();
|
|
6672
6882
|
} catch {
|
|
6673
6883
|
continue;
|
|
6674
6884
|
}
|
|
@@ -6679,7 +6889,7 @@ function sweepStrayScratchDirs(root = homedir2(), maxDepth = 6, budget = 4e4) {
|
|
|
6679
6889
|
for (const f of readdirSync(full)) {
|
|
6680
6890
|
if (SCRATCH_FILES.has(f)) {
|
|
6681
6891
|
try {
|
|
6682
|
-
rmSync2(
|
|
6892
|
+
rmSync2(join5(full, f), { force: true });
|
|
6683
6893
|
} catch {
|
|
6684
6894
|
left.push(f);
|
|
6685
6895
|
}
|
|
@@ -6719,12 +6929,12 @@ function runGlobalRestore() {
|
|
|
6719
6929
|
removeOpencodeGuard(p);
|
|
6720
6930
|
} catch {
|
|
6721
6931
|
}
|
|
6722
|
-
if (
|
|
6723
|
-
writeFileSync3(p.settingsPath,
|
|
6932
|
+
if (existsSync4(p.backupPath)) {
|
|
6933
|
+
writeFileSync3(p.settingsPath, readFileSync5(p.backupPath, "utf-8"));
|
|
6724
6934
|
console.log(` Restored ${p.settingsPath} from backup.`);
|
|
6725
|
-
} else if (
|
|
6935
|
+
} else if (existsSync4(p.settingsPath)) {
|
|
6726
6936
|
try {
|
|
6727
|
-
const s = JSON.parse(
|
|
6937
|
+
const s = JSON.parse(readFileSync5(p.settingsPath, "utf-8"));
|
|
6728
6938
|
delete s.hooks;
|
|
6729
6939
|
writeFileSync3(p.settingsPath, JSON.stringify(s, null, 2) + "\n");
|
|
6730
6940
|
console.log(` Removed SolonGate hooks from ${p.settingsPath}.`);
|
|
@@ -6737,12 +6947,17 @@ function runGlobalRestore() {
|
|
|
6737
6947
|
}
|
|
6738
6948
|
function repairQuiet() {
|
|
6739
6949
|
const p = globalPaths();
|
|
6740
|
-
const has = (f) =>
|
|
6741
|
-
const guardFile =
|
|
6950
|
+
const has = (f) => existsSync4(f);
|
|
6951
|
+
const guardFile = join5(p.hooksDir, "guard.mjs");
|
|
6742
6952
|
const line = (label, ok, yes, no) => ({ label, ok, detail: ok ? yes : no });
|
|
6953
|
+
const runtime = () => {
|
|
6954
|
+
const r2 = hookCanStart();
|
|
6955
|
+
return { label: "hook runtime", ok: r2.ok, detail: r2.ok ? `node ${r2.detail}` : r2.detail };
|
|
6956
|
+
};
|
|
6743
6957
|
const before = [
|
|
6744
6958
|
line("guard hook file", has(guardFile), "present", "MISSING"),
|
|
6745
6959
|
line("cloud credential", has(p.configPath), "present", "MISSING"),
|
|
6960
|
+
runtime(),
|
|
6746
6961
|
line("Claude hooks", isGuardInstalled(), "guard registered", "guard NOT registered"),
|
|
6747
6962
|
line("Antigravity hooks", has(p.antigravityHooksPath), "guard registered", "guard NOT registered"),
|
|
6748
6963
|
line("Codex hooks", isCodexGuardInstalled(), "guard registered", "guard NOT registered"),
|
|
@@ -6752,6 +6967,7 @@ function repairQuiet() {
|
|
|
6752
6967
|
if (!r.ok) return { ok: false, message: r.message, before, after: [], notes: [] };
|
|
6753
6968
|
const after = [
|
|
6754
6969
|
{ label: "guard hook file", ok: true, detail: `present (v${installedGuardVersion() ?? "?"})` },
|
|
6970
|
+
runtime(),
|
|
6755
6971
|
line("Claude hooks", isGuardInstalled(), "guard registered", "NOT registered"),
|
|
6756
6972
|
line("Antigravity hooks", has(p.antigravityHooksPath), "guard registered", "NOT registered"),
|
|
6757
6973
|
line("Codex hooks", isCodexGuardInstalled(), "guard registered", "NOT registered"),
|
|
@@ -6812,7 +7028,7 @@ function installGlobalQuiet() {
|
|
|
6812
7028
|
let apiKey = process.env["SOLONGATE_API_KEY"] || "";
|
|
6813
7029
|
let apiUrl = process.env["SOLONGATE_API_URL"] || "https://api.solongate.com";
|
|
6814
7030
|
try {
|
|
6815
|
-
const cfg = JSON.parse(
|
|
7031
|
+
const cfg = JSON.parse(readFileSync5(p.configPath, "utf-8"));
|
|
6816
7032
|
if (cfg && typeof cfg.apiKey === "string") apiKey = apiKey || cfg.apiKey;
|
|
6817
7033
|
if (cfg && typeof cfg.apiUrl === "string") apiUrl = cfg.apiUrl;
|
|
6818
7034
|
} catch {
|
|
@@ -6828,26 +7044,26 @@ function installGlobalQuiet() {
|
|
|
6828
7044
|
mkdirSync3(p.hooksDir, { recursive: true });
|
|
6829
7045
|
mkdirSync3(p.claudeDir, { recursive: true });
|
|
6830
7046
|
unlockProtected();
|
|
6831
|
-
writeFileSync3(
|
|
7047
|
+
writeFileSync3(join5(p.hooksDir, "guard.mjs"), readGuard());
|
|
6832
7048
|
installGoBinaries(p.binDir);
|
|
6833
|
-
writeFileSync3(
|
|
6834
|
-
writeFileSync3(
|
|
6835
|
-
writeFileSync3(
|
|
6836
|
-
writeFileSync3(
|
|
7049
|
+
writeFileSync3(join5(p.hooksDir, "audit.mjs"), readHook("audit.mjs"));
|
|
7050
|
+
writeFileSync3(join5(p.hooksDir, "stop.mjs"), readHook("stop.mjs"));
|
|
7051
|
+
writeFileSync3(join5(p.hooksDir, "shield.mjs"), readHook("shield.mjs"));
|
|
7052
|
+
writeFileSync3(join5(p.hooksDir, "conversation.mjs"), readHook("conversation.mjs"));
|
|
7053
|
+
writeLauncher(p.hooksDir);
|
|
7054
|
+
writeLauncher(p.hooksDir);
|
|
6837
7055
|
writeFileSync3(p.configPath, JSON.stringify({ apiKey, apiUrl }, null, 2) + "\n");
|
|
6838
7056
|
let existing = {};
|
|
6839
|
-
if (
|
|
6840
|
-
const raw =
|
|
6841
|
-
if (!
|
|
7057
|
+
if (existsSync4(p.settingsPath)) {
|
|
7058
|
+
const raw = readFileSync5(p.settingsPath, "utf-8");
|
|
7059
|
+
if (!existsSync4(p.backupPath)) writeFileSync3(p.backupPath, raw);
|
|
6842
7060
|
try {
|
|
6843
7061
|
existing = JSON.parse(raw);
|
|
6844
7062
|
} catch {
|
|
6845
7063
|
existing = {};
|
|
6846
7064
|
}
|
|
6847
7065
|
}
|
|
6848
|
-
const
|
|
6849
|
-
const call = process.platform === "win32" ? "& " : "";
|
|
6850
|
-
const hookCmd = (script) => `${call}"${nodeBin}" "${join4(p.hooksDir, script).replace(/\\/g, "/")}" claude-code "Claude Code"`;
|
|
7066
|
+
const hookCmd = (script) => hookCommandFor(p.hooksDir, script);
|
|
6851
7067
|
const merged = {
|
|
6852
7068
|
...existing,
|
|
6853
7069
|
hooks: {
|
|
@@ -6874,7 +7090,7 @@ function installGlobalQuiet() {
|
|
|
6874
7090
|
};
|
|
6875
7091
|
writeFileSync3(p.settingsPath, JSON.stringify(merged, null, 2) + "\n");
|
|
6876
7092
|
try {
|
|
6877
|
-
installAntigravityGuard(p,
|
|
7093
|
+
installAntigravityGuard(p, join5(p.hooksDir, "guard.mjs").replace(/\\/g, "/"));
|
|
6878
7094
|
} catch {
|
|
6879
7095
|
}
|
|
6880
7096
|
try {
|
|
@@ -6895,7 +7111,7 @@ function installGlobalQuiet() {
|
|
|
6895
7111
|
function installedGuardVersion() {
|
|
6896
7112
|
try {
|
|
6897
7113
|
const p = globalPaths();
|
|
6898
|
-
const s =
|
|
7114
|
+
const s = readFileSync5(join5(p.hooksDir, "guard.mjs"), "utf-8");
|
|
6899
7115
|
const m = s.match(/HOOK_VERSION\s*=\s*(\d+)/);
|
|
6900
7116
|
return m ? parseInt(m[1], 10) : null;
|
|
6901
7117
|
} catch {
|
|
@@ -6905,16 +7121,35 @@ function installedGuardVersion() {
|
|
|
6905
7121
|
function guardHookOutdated() {
|
|
6906
7122
|
try {
|
|
6907
7123
|
const p = globalPaths();
|
|
6908
|
-
return
|
|
7124
|
+
return readFileSync5(join5(p.hooksDir, "guard.mjs"), "utf-8") !== readGuard();
|
|
6909
7125
|
} catch {
|
|
6910
7126
|
return false;
|
|
6911
7127
|
}
|
|
6912
7128
|
}
|
|
7129
|
+
function hookCommandFor(hooksDir2, script, client = "claude-code", label = "Claude Code") {
|
|
7130
|
+
const target = join5(hooksDir2, script).replace(/\\/g, "/");
|
|
7131
|
+
if (process.platform === "win32") {
|
|
7132
|
+
return `& "${process.execPath.replace(/\\/g, "/")}" "${target}" ${client} "${label}"`;
|
|
7133
|
+
}
|
|
7134
|
+
const launcher = join5(hooksDir2, LAUNCHER_NAME).replace(/\\/g, "/");
|
|
7135
|
+
return `/bin/sh "${launcher}" "${target}" ${client} "${label}"`;
|
|
7136
|
+
}
|
|
7137
|
+
function writeLauncher(hooksDir2) {
|
|
7138
|
+
writeFileSync3(join5(hooksDir2, LAUNCHER_NAME), launcherScript(process.execPath));
|
|
7139
|
+
try {
|
|
7140
|
+
chmodSync(join5(hooksDir2, LAUNCHER_NAME), 493);
|
|
7141
|
+
} catch {
|
|
7142
|
+
}
|
|
7143
|
+
try {
|
|
7144
|
+
mkdirSync3(join5(hooksDir2, "..", BEAT_DIR), { recursive: true });
|
|
7145
|
+
} catch {
|
|
7146
|
+
}
|
|
7147
|
+
}
|
|
6913
7148
|
function isGuardInstalled() {
|
|
6914
7149
|
try {
|
|
6915
7150
|
const p = globalPaths();
|
|
6916
|
-
if (!
|
|
6917
|
-
const s = JSON.parse(
|
|
7151
|
+
if (!existsSync4(p.settingsPath)) return false;
|
|
7152
|
+
const s = JSON.parse(readFileSync5(p.settingsPath, "utf-8"));
|
|
6918
7153
|
return !!s.hooks && JSON.stringify(s.hooks).includes(".solongate");
|
|
6919
7154
|
} catch {
|
|
6920
7155
|
return false;
|
|
@@ -6937,8 +7172,8 @@ function uninstallGlobalQuiet() {
|
|
|
6937
7172
|
removeOpencodeGuard(p);
|
|
6938
7173
|
} catch {
|
|
6939
7174
|
}
|
|
6940
|
-
if (!
|
|
6941
|
-
const s = JSON.parse(
|
|
7175
|
+
if (!existsSync4(p.settingsPath)) return { ok: true, message: "guard removed (open a new session)" };
|
|
7176
|
+
const s = JSON.parse(readFileSync5(p.settingsPath, "utf-8"));
|
|
6942
7177
|
delete s.hooks;
|
|
6943
7178
|
writeFileSync3(p.settingsPath, JSON.stringify(s, null, 2) + "\n");
|
|
6944
7179
|
return { ok: true, message: "guard removed (open a new session)" };
|
|
@@ -6952,7 +7187,7 @@ function escapeRe(s) {
|
|
|
6952
7187
|
function resolveRealClaude() {
|
|
6953
7188
|
try {
|
|
6954
7189
|
const finder = process.platform === "win32" ? "where" : "which";
|
|
6955
|
-
const out2 =
|
|
7190
|
+
const out2 = execFileSync3(finder, ["claude"], { encoding: "utf-8" }).split(/\r?\n/).map((s) => s.trim()).filter(Boolean);
|
|
6956
7191
|
if (process.platform === "win32") {
|
|
6957
7192
|
const low = (s) => s.toLowerCase();
|
|
6958
7193
|
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;
|
|
@@ -6965,17 +7200,17 @@ function resolveRealClaude() {
|
|
|
6965
7200
|
function shimTargets() {
|
|
6966
7201
|
if (process.platform === "win32") {
|
|
6967
7202
|
try {
|
|
6968
|
-
const prof =
|
|
7203
|
+
const prof = execFileSync3("powershell", ["-NoProfile", "-Command", "$PROFILE.CurrentUserAllHosts"], { encoding: "utf-8" }).trim();
|
|
6969
7204
|
return prof ? [prof] : [];
|
|
6970
7205
|
} catch {
|
|
6971
7206
|
return [];
|
|
6972
7207
|
}
|
|
6973
7208
|
}
|
|
6974
|
-
return [".bashrc", ".zshrc", ".profile"].map((f) =>
|
|
7209
|
+
return [".bashrc", ".zshrc", ".profile"].map((f) => join5(homedir3(), f)).filter((f) => existsSync4(f));
|
|
6975
7210
|
}
|
|
6976
7211
|
function writeShimBlock(file, block2) {
|
|
6977
7212
|
const re = new RegExp(escapeRe(SHIM_BEGIN) + "[\\s\\S]*?" + escapeRe(SHIM_END) + "\\r?\\n?", "g");
|
|
6978
|
-
let content =
|
|
7213
|
+
let content = existsSync4(file) ? readFileSync5(file, "utf-8") : "";
|
|
6979
7214
|
content = content.replace(re, "");
|
|
6980
7215
|
if (block2) {
|
|
6981
7216
|
if (content.length && !content.endsWith("\n")) content += "\n";
|
|
@@ -7020,7 +7255,7 @@ async function runGlobalInstall(opts = {}) {
|
|
|
7020
7255
|
let apiKey = opts.apiKey || process.env["SOLONGATE_API_KEY"] || "";
|
|
7021
7256
|
if (!apiKey || apiKey === "sg_live_your_key_here") {
|
|
7022
7257
|
try {
|
|
7023
|
-
const cfg = JSON.parse(
|
|
7258
|
+
const cfg = JSON.parse(readFileSync5(p.configPath, "utf-8"));
|
|
7024
7259
|
if (cfg && typeof cfg.apiKey === "string") apiKey = cfg.apiKey;
|
|
7025
7260
|
} catch {
|
|
7026
7261
|
}
|
|
@@ -7040,19 +7275,19 @@ async function runGlobalInstall(opts = {}) {
|
|
|
7040
7275
|
mkdirSync3(p.hooksDir, { recursive: true });
|
|
7041
7276
|
mkdirSync3(p.claudeDir, { recursive: true });
|
|
7042
7277
|
unlockProtected();
|
|
7043
|
-
writeFileSync3(
|
|
7044
|
-
writeFileSync3(
|
|
7045
|
-
writeFileSync3(
|
|
7046
|
-
writeFileSync3(
|
|
7047
|
-
writeFileSync3(
|
|
7278
|
+
writeFileSync3(join5(p.hooksDir, "guard.mjs"), readGuard());
|
|
7279
|
+
writeFileSync3(join5(p.hooksDir, "audit.mjs"), readHook("audit.mjs"));
|
|
7280
|
+
writeFileSync3(join5(p.hooksDir, "stop.mjs"), readHook("stop.mjs"));
|
|
7281
|
+
writeFileSync3(join5(p.hooksDir, "shield.mjs"), readHook("shield.mjs"));
|
|
7282
|
+
writeFileSync3(join5(p.hooksDir, "conversation.mjs"), readHook("conversation.mjs"));
|
|
7048
7283
|
console.log(` Installed hooks \u2192 ${p.hooksDir}`);
|
|
7049
|
-
installClaudeShim(
|
|
7284
|
+
installClaudeShim(join5(p.hooksDir, "shield.mjs"));
|
|
7050
7285
|
writeFileSync3(p.configPath, JSON.stringify({ apiKey, apiUrl }, null, 2) + "\n");
|
|
7051
7286
|
console.log(` Wrote ${p.configPath}`);
|
|
7052
7287
|
let existing = {};
|
|
7053
|
-
if (
|
|
7054
|
-
const raw =
|
|
7055
|
-
if (!
|
|
7288
|
+
if (existsSync4(p.settingsPath)) {
|
|
7289
|
+
const raw = readFileSync5(p.settingsPath, "utf-8");
|
|
7290
|
+
if (!existsSync4(p.backupPath)) {
|
|
7056
7291
|
writeFileSync3(p.backupPath, raw);
|
|
7057
7292
|
console.log(` Backed up existing settings \u2192 ${p.backupPath}`);
|
|
7058
7293
|
}
|
|
@@ -7062,22 +7297,17 @@ async function runGlobalInstall(opts = {}) {
|
|
|
7062
7297
|
existing = {};
|
|
7063
7298
|
}
|
|
7064
7299
|
}
|
|
7065
|
-
const guardAbs =
|
|
7066
|
-
const
|
|
7067
|
-
const stopAbs = join4(p.hooksDir, "stop.mjs").replace(/\\/g, "/");
|
|
7068
|
-
const convAbs = join4(p.hooksDir, "conversation.mjs").replace(/\\/g, "/");
|
|
7069
|
-
const nodeBin = process.execPath.replace(/\\/g, "/");
|
|
7070
|
-
const call = process.platform === "win32" ? "& " : "";
|
|
7071
|
-
const hookCmd = (script) => `${call}"${nodeBin}" "${script}" claude-code "Claude Code"`;
|
|
7300
|
+
const guardAbs = join5(p.hooksDir, "guard.mjs").replace(/\\/g, "/");
|
|
7301
|
+
const hookCmd = (script) => hookCommandFor(p.hooksDir, script);
|
|
7072
7302
|
const merged = {
|
|
7073
7303
|
...existing,
|
|
7074
7304
|
hooks: {
|
|
7075
|
-
PreToolUse: [{ matcher: "", hooks: [{ type: "command", command: hookCmd(
|
|
7076
|
-
PostToolUse: [{ matcher: "", hooks: [{ type: "command", command: hookCmd(
|
|
7077
|
-
UserPromptSubmit: [{ matcher: "", hooks: [{ type: "command", command: hookCmd(
|
|
7305
|
+
PreToolUse: [{ matcher: "", hooks: [{ type: "command", command: hookCmd("guard.mjs") }] }],
|
|
7306
|
+
PostToolUse: [{ matcher: "", hooks: [{ type: "command", command: hookCmd("audit.mjs") }] }],
|
|
7307
|
+
UserPromptSubmit: [{ matcher: "", hooks: [{ type: "command", command: hookCmd("conversation.mjs") }] }],
|
|
7078
7308
|
Stop: [
|
|
7079
|
-
{ matcher: "", hooks: [{ type: "command", command: hookCmd(
|
|
7080
|
-
{ matcher: "", hooks: [{ type: "command", command: hookCmd(
|
|
7309
|
+
{ matcher: "", hooks: [{ type: "command", command: hookCmd("stop.mjs") }] },
|
|
7310
|
+
{ matcher: "", hooks: [{ type: "command", command: hookCmd("conversation.mjs") }] }
|
|
7081
7311
|
]
|
|
7082
7312
|
}
|
|
7083
7313
|
};
|
|
@@ -7122,6 +7352,10 @@ var __dirname, HOOKS_DIR, ANTIGRAVITY_GROUP, CODEX_EVENTS, CODEX_TIMEOUT_SEC, SC
|
|
|
7122
7352
|
var init_global_install = __esm({
|
|
7123
7353
|
"src/global-install.ts"() {
|
|
7124
7354
|
"use strict";
|
|
7355
|
+
init_hook_launcher();
|
|
7356
|
+
init_hook_launcher();
|
|
7357
|
+
init_hook_health();
|
|
7358
|
+
init_hook_health();
|
|
7125
7359
|
__dirname = dirname(fileURLToPath(import.meta.url));
|
|
7126
7360
|
HOOKS_DIR = resolve3(__dirname, "..", "hooks");
|
|
7127
7361
|
ANTIGRAVITY_GROUP = "solongate-guard";
|
|
@@ -7152,14 +7386,14 @@ __export(self_update_exports, {
|
|
|
7152
7386
|
tuiUpdateFlow: () => tuiUpdateFlow,
|
|
7153
7387
|
updateNow: () => updateNow
|
|
7154
7388
|
});
|
|
7155
|
-
import { execFile, execFileSync as
|
|
7156
|
-
import { access, mkdirSync as mkdirSync4, openSync, readFileSync as
|
|
7157
|
-
import { homedir as
|
|
7158
|
-
import { dirname as dirname2, join as
|
|
7389
|
+
import { execFile, execFileSync as execFileSync4, spawn as spawn2 } from "child_process";
|
|
7390
|
+
import { access, mkdirSync as mkdirSync4, openSync, readFileSync as readFileSync6, writeFileSync as writeFileSync4, constants as FS } from "fs";
|
|
7391
|
+
import { homedir as homedir4 } from "os";
|
|
7392
|
+
import { dirname as dirname2, join as join6, sep } from "path";
|
|
7159
7393
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
7160
7394
|
function lockHeldAt() {
|
|
7161
7395
|
try {
|
|
7162
|
-
const ts = Number(
|
|
7396
|
+
const ts = Number(readFileSync6(LOCK_FILE, "utf-8").trim().split(/\s+/)[1] ?? 0);
|
|
7163
7397
|
if (!Number.isFinite(ts) || Date.now() - ts >= LOCK_STALE_MS) return null;
|
|
7164
7398
|
return ts;
|
|
7165
7399
|
} catch {
|
|
@@ -7168,7 +7402,7 @@ function lockHeldAt() {
|
|
|
7168
7402
|
}
|
|
7169
7403
|
function takeInstallLock() {
|
|
7170
7404
|
try {
|
|
7171
|
-
mkdirSync4(
|
|
7405
|
+
mkdirSync4(join6(homedir4(), ".solongate"), { recursive: true });
|
|
7172
7406
|
writeFileSync4(LOCK_FILE, `${process.pid} ${Date.now()}
|
|
7173
7407
|
`);
|
|
7174
7408
|
} catch {
|
|
@@ -7183,7 +7417,7 @@ function releaseInstallLock() {
|
|
|
7183
7417
|
}
|
|
7184
7418
|
function readState() {
|
|
7185
7419
|
try {
|
|
7186
|
-
const s = JSON.parse(
|
|
7420
|
+
const s = JSON.parse(readFileSync6(STATE_FILE, "utf-8"));
|
|
7187
7421
|
return s && typeof s === "object" ? s : {};
|
|
7188
7422
|
} catch {
|
|
7189
7423
|
return {};
|
|
@@ -7191,7 +7425,7 @@ function readState() {
|
|
|
7191
7425
|
}
|
|
7192
7426
|
function writeState(s) {
|
|
7193
7427
|
try {
|
|
7194
|
-
mkdirSync4(
|
|
7428
|
+
mkdirSync4(join6(homedir4(), ".solongate"), { recursive: true });
|
|
7195
7429
|
writeFileSync4(STATE_FILE, JSON.stringify(s));
|
|
7196
7430
|
} catch {
|
|
7197
7431
|
}
|
|
@@ -7212,7 +7446,7 @@ function setAutoUpdate(on) {
|
|
|
7212
7446
|
}
|
|
7213
7447
|
function currentVersion() {
|
|
7214
7448
|
try {
|
|
7215
|
-
const pkg = JSON.parse(
|
|
7449
|
+
const pkg = JSON.parse(readFileSync6(join6(dirname2(fileURLToPath2(import.meta.url)), "..", "package.json"), "utf-8"));
|
|
7216
7450
|
return pkg.version ?? "0.0.0";
|
|
7217
7451
|
} catch {
|
|
7218
7452
|
return "0.0.0";
|
|
@@ -7249,7 +7483,7 @@ async function fetchLatest() {
|
|
|
7249
7483
|
function spawnGlobalInstall(version) {
|
|
7250
7484
|
if (lockHeldAt() !== null) return false;
|
|
7251
7485
|
try {
|
|
7252
|
-
mkdirSync4(
|
|
7486
|
+
mkdirSync4(join6(homedir4(), ".solongate"), { recursive: true });
|
|
7253
7487
|
takeInstallLock();
|
|
7254
7488
|
const log3 = openSync(LOG_FILE, "a");
|
|
7255
7489
|
const p = spawn2("npm", ["install", "-g", `${PKG}@${version}`], {
|
|
@@ -7320,7 +7554,7 @@ async function runUpdateCommand() {
|
|
|
7320
7554
|
}
|
|
7321
7555
|
try {
|
|
7322
7556
|
if (newerThan(latest, cur)) {
|
|
7323
|
-
|
|
7557
|
+
execFileSync4("solongate", ["repair"], {
|
|
7324
7558
|
env: { ...process.env, SOLONGATE_INTERNAL: "1" },
|
|
7325
7559
|
stdio: "inherit",
|
|
7326
7560
|
shell: process.platform === "win32"
|
|
@@ -7337,7 +7571,7 @@ async function runUpdateCommand() {
|
|
|
7337
7571
|
function runGlobalInstall2(version) {
|
|
7338
7572
|
return new Promise((resolve8) => {
|
|
7339
7573
|
try {
|
|
7340
|
-
mkdirSync4(
|
|
7574
|
+
mkdirSync4(join6(homedir4(), ".solongate"), { recursive: true });
|
|
7341
7575
|
execFile(
|
|
7342
7576
|
"npm",
|
|
7343
7577
|
["install", "-g", `${PKG}@${version}`],
|
|
@@ -7530,9 +7764,9 @@ var init_self_update = __esm({
|
|
|
7530
7764
|
PKG = "@solongate/proxy";
|
|
7531
7765
|
CHECK_EVERY_MS = 30 * 60 * 1e3;
|
|
7532
7766
|
ATTEMPT_EVERY_MS = 6 * 60 * 60 * 1e3;
|
|
7533
|
-
STATE_FILE =
|
|
7534
|
-
LOG_FILE =
|
|
7535
|
-
LOCK_FILE =
|
|
7767
|
+
STATE_FILE = join6(homedir4(), ".solongate", ".self-update.json");
|
|
7768
|
+
LOG_FILE = join6(homedir4(), ".solongate", "self-update.log");
|
|
7769
|
+
LOCK_FILE = join6(homedir4(), ".solongate", ".update-install.lock");
|
|
7536
7770
|
LOCK_STALE_MS = 3 * 6e4;
|
|
7537
7771
|
LOCK_WAIT_MS = 9e4;
|
|
7538
7772
|
sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
@@ -7552,13 +7786,13 @@ __export(logs_server_daemon_exports, {
|
|
|
7552
7786
|
stopLogsServerDaemon: () => stopLogsServerDaemon
|
|
7553
7787
|
});
|
|
7554
7788
|
import { spawn as spawn3 } from "child_process";
|
|
7555
|
-
import { mkdirSync as mkdirSync5, openSync as openSync2, readFileSync as
|
|
7556
|
-
import { homedir as
|
|
7557
|
-
import { dirname as dirname3, join as
|
|
7789
|
+
import { mkdirSync as mkdirSync5, openSync as openSync2, readFileSync as readFileSync7, writeFileSync as writeFileSync5 } from "fs";
|
|
7790
|
+
import { homedir as homedir5 } from "os";
|
|
7791
|
+
import { dirname as dirname3, join as join7 } from "path";
|
|
7558
7792
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
7559
7793
|
function readState2() {
|
|
7560
7794
|
try {
|
|
7561
|
-
const s = JSON.parse(
|
|
7795
|
+
const s = JSON.parse(readFileSync7(STATE_FILE2, "utf-8"));
|
|
7562
7796
|
return s && typeof s === "object" ? s : {};
|
|
7563
7797
|
} catch {
|
|
7564
7798
|
return {};
|
|
@@ -7597,7 +7831,7 @@ function startLogsServerDaemon() {
|
|
|
7597
7831
|
try {
|
|
7598
7832
|
mkdirSync5(DIR, { recursive: true });
|
|
7599
7833
|
const log3 = openSync2(LOG_FILE2, "a");
|
|
7600
|
-
const cli =
|
|
7834
|
+
const cli = join7(dirname3(fileURLToPath3(import.meta.url)), "index.js");
|
|
7601
7835
|
const p = spawn3(process.execPath, [cli, "logs-server"], {
|
|
7602
7836
|
detached: true,
|
|
7603
7837
|
stdio: ["ignore", log3, log3],
|
|
@@ -7637,22 +7871,22 @@ var DIR, STATE_FILE2, LOG_FILE2, LOGS_SERVER_PORT;
|
|
|
7637
7871
|
var init_logs_server_daemon = __esm({
|
|
7638
7872
|
"src/logs-server-daemon.ts"() {
|
|
7639
7873
|
"use strict";
|
|
7640
|
-
DIR =
|
|
7641
|
-
STATE_FILE2 =
|
|
7642
|
-
LOG_FILE2 =
|
|
7874
|
+
DIR = join7(homedir5(), ".solongate");
|
|
7875
|
+
STATE_FILE2 = join7(DIR, ".logs-server.json");
|
|
7876
|
+
LOG_FILE2 = join7(DIR, "logs-server.log");
|
|
7643
7877
|
LOGS_SERVER_PORT = 8788;
|
|
7644
7878
|
}
|
|
7645
7879
|
});
|
|
7646
7880
|
|
|
7647
7881
|
// src/tui/config.ts
|
|
7648
|
-
import { readFileSync as
|
|
7649
|
-
import { homedir as
|
|
7650
|
-
import { join as
|
|
7882
|
+
import { readFileSync as readFileSync8 } from "fs";
|
|
7883
|
+
import { homedir as homedir6 } from "os";
|
|
7884
|
+
import { join as join8 } from "path";
|
|
7651
7885
|
function loadConfig() {
|
|
7652
7886
|
if (cached) return cached;
|
|
7653
7887
|
const defaults = { notifications: true };
|
|
7654
7888
|
try {
|
|
7655
|
-
const raw =
|
|
7889
|
+
const raw = readFileSync8(join8(homedir6(), ".solongate", "tui-config.json"), "utf-8");
|
|
7656
7890
|
const j = JSON.parse(raw);
|
|
7657
7891
|
cached = {
|
|
7658
7892
|
notifications: j.notifications !== false,
|
|
@@ -7823,16 +8057,16 @@ var init_components = __esm({
|
|
|
7823
8057
|
});
|
|
7824
8058
|
|
|
7825
8059
|
// src/tui/local-log.ts
|
|
7826
|
-
import { closeSync, existsSync as
|
|
7827
|
-
import { homedir as
|
|
8060
|
+
import { closeSync, existsSync as existsSync5, openSync as openSync3, readdirSync as readdirSync2, readFileSync as readFileSync9, readSync, statSync as statSync3, writeFileSync as writeFileSync6 } from "fs";
|
|
8061
|
+
import { homedir as homedir7 } from "os";
|
|
7828
8062
|
import { createHash as createHash2 } from "crypto";
|
|
7829
|
-
import { isAbsolute, join as
|
|
8063
|
+
import { isAbsolute, join as join9 } from "path";
|
|
7830
8064
|
function localLogsSetting() {
|
|
7831
8065
|
const off = { enabled: false, configuredPath: null, usableHere: true, file: DEFAULT_LOCAL_LOG };
|
|
7832
8066
|
try {
|
|
7833
8067
|
for (const cache of policyCachesNewestFirst()) {
|
|
7834
8068
|
try {
|
|
7835
|
-
const c2 = JSON.parse(
|
|
8069
|
+
const c2 = JSON.parse(readFileSync9(cache, "utf-8"));
|
|
7836
8070
|
const l = c2?.security?.localLogs;
|
|
7837
8071
|
if (!l || typeof l.enabled !== "boolean") continue;
|
|
7838
8072
|
if (!l.enabled) return { ...off, configuredPath: typeof l.path === "string" ? l.path.trim() || null : null };
|
|
@@ -7840,8 +8074,8 @@ function localLogsSetting() {
|
|
|
7840
8074
|
const dir = raw.replace(/[\\/]+$/, "");
|
|
7841
8075
|
if (!dir) return { enabled: true, configuredPath: null, usableHere: true, file: DEFAULT_LOCAL_LOG };
|
|
7842
8076
|
if (!isAbsolute(dir)) return { enabled: true, configuredPath: raw, usableHere: false, file: DEFAULT_LOCAL_LOG };
|
|
7843
|
-
const file =
|
|
7844
|
-
const usable =
|
|
8077
|
+
const file = join9(dir, "solongate-audit.jsonl");
|
|
8078
|
+
const usable = existsSync5(file) || existsSync5(dir);
|
|
7845
8079
|
return { enabled: true, configuredPath: raw, usableHere: usable, file: usable ? file : DEFAULT_LOCAL_LOG };
|
|
7846
8080
|
} catch {
|
|
7847
8081
|
}
|
|
@@ -7851,12 +8085,12 @@ function localLogsSetting() {
|
|
|
7851
8085
|
return off;
|
|
7852
8086
|
}
|
|
7853
8087
|
function policyCachesNewestFirst() {
|
|
7854
|
-
const
|
|
7855
|
-
return readdirSync2(
|
|
7856
|
-
const p =
|
|
8088
|
+
const sgDir2 = join9(homedir7(), ".solongate");
|
|
8089
|
+
return readdirSync2(sgDir2).filter((f) => f.startsWith(".policy-cache-") && f.endsWith(".json")).map((f) => {
|
|
8090
|
+
const p = join9(sgDir2, f);
|
|
7857
8091
|
let mtime = 0;
|
|
7858
8092
|
try {
|
|
7859
|
-
mtime =
|
|
8093
|
+
mtime = statSync3(p).mtimeMs;
|
|
7860
8094
|
} catch {
|
|
7861
8095
|
}
|
|
7862
8096
|
return { p, mtime };
|
|
@@ -7864,27 +8098,27 @@ function policyCachesNewestFirst() {
|
|
|
7864
8098
|
}
|
|
7865
8099
|
function localLogFile() {
|
|
7866
8100
|
try {
|
|
7867
|
-
const
|
|
7868
|
-
const caches = readdirSync2(
|
|
7869
|
-
const p =
|
|
8101
|
+
const sgDir2 = join9(homedir7(), ".solongate");
|
|
8102
|
+
const caches = readdirSync2(sgDir2).filter((f) => f.startsWith(".policy-cache-") && f.endsWith(".json")).map((f) => {
|
|
8103
|
+
const p = join9(sgDir2, f);
|
|
7870
8104
|
let mtime = 0;
|
|
7871
8105
|
try {
|
|
7872
|
-
mtime =
|
|
8106
|
+
mtime = statSync3(p).mtimeMs;
|
|
7873
8107
|
} catch {
|
|
7874
8108
|
}
|
|
7875
8109
|
return { p, mtime };
|
|
7876
8110
|
}).sort((a, b) => b.mtime - a.mtime);
|
|
7877
8111
|
for (const { p } of caches) {
|
|
7878
8112
|
try {
|
|
7879
|
-
const c2 = JSON.parse(
|
|
8113
|
+
const c2 = JSON.parse(readFileSync9(p, "utf-8"));
|
|
7880
8114
|
const l = c2?.security?.localLogs;
|
|
7881
8115
|
if (!l || !l.enabled || typeof l.path !== "string" || !l.path.trim()) continue;
|
|
7882
8116
|
const dir = l.path.trim().replace(/[\\/]+$/, "");
|
|
7883
8117
|
if (!dir) continue;
|
|
7884
8118
|
if (!isAbsolute(dir)) return DEFAULT_LOCAL_LOG;
|
|
7885
|
-
const file =
|
|
7886
|
-
if (
|
|
7887
|
-
return
|
|
8119
|
+
const file = join9(dir, "solongate-audit.jsonl");
|
|
8120
|
+
if (existsSync5(file)) return file;
|
|
8121
|
+
return existsSync5(dir) ? file : DEFAULT_LOCAL_LOG;
|
|
7888
8122
|
} catch {
|
|
7889
8123
|
}
|
|
7890
8124
|
}
|
|
@@ -7894,11 +8128,11 @@ function localLogFile() {
|
|
|
7894
8128
|
}
|
|
7895
8129
|
function ensureLocalLogOwner(activeApiKey) {
|
|
7896
8130
|
try {
|
|
7897
|
-
const marker =
|
|
8131
|
+
const marker = join9(homedir7(), ".solongate", "local-logs", ".owner");
|
|
7898
8132
|
const want = activeApiKey ? createHash2("sha256").update(activeApiKey).digest("hex").slice(0, 16) : "";
|
|
7899
8133
|
let have = "";
|
|
7900
8134
|
try {
|
|
7901
|
-
have =
|
|
8135
|
+
have = readFileSync9(marker, "utf-8").trim();
|
|
7902
8136
|
} catch {
|
|
7903
8137
|
}
|
|
7904
8138
|
if (have === want) return false;
|
|
@@ -7913,7 +8147,7 @@ function ensureLocalLogOwner(activeApiKey) {
|
|
|
7913
8147
|
}
|
|
7914
8148
|
function tailLines(file, maxBytes = 131072) {
|
|
7915
8149
|
try {
|
|
7916
|
-
const size =
|
|
8150
|
+
const size = statSync3(file).size;
|
|
7917
8151
|
const start = Math.max(0, size - maxBytes);
|
|
7918
8152
|
const fd = openSync3(file, "r");
|
|
7919
8153
|
const buf = Buffer.alloc(size - start);
|
|
@@ -7929,7 +8163,7 @@ function tailLines(file, maxBytes = 131072) {
|
|
|
7929
8163
|
function clearLocalLog() {
|
|
7930
8164
|
try {
|
|
7931
8165
|
const file = localLogFile();
|
|
7932
|
-
const n =
|
|
8166
|
+
const n = readFileSync9(file, "utf-8").split("\n").filter(Boolean).length;
|
|
7933
8167
|
writeFileSync6(file, "");
|
|
7934
8168
|
return n;
|
|
7935
8169
|
} catch {
|
|
@@ -7947,8 +8181,8 @@ function reasonSignals(reason) {
|
|
|
7947
8181
|
}
|
|
7948
8182
|
function ownMark() {
|
|
7949
8183
|
try {
|
|
7950
|
-
const p =
|
|
7951
|
-
const c2 = JSON.parse(
|
|
8184
|
+
const p = join9(homedir7(), ".solongate", "cloud-guard.json");
|
|
8185
|
+
const c2 = JSON.parse(readFileSync9(p, "utf-8"));
|
|
7952
8186
|
return c2?.apiKey ? createHash2("sha256").update(c2.apiKey).digest("hex").slice(0, 16) : "";
|
|
7953
8187
|
} catch {
|
|
7954
8188
|
return "";
|
|
@@ -7972,7 +8206,7 @@ var DEFAULT_LOCAL_LOG, LOCAL_LOG, DLP_REASON, RL_REASON;
|
|
|
7972
8206
|
var init_local_log = __esm({
|
|
7973
8207
|
"src/tui/local-log.ts"() {
|
|
7974
8208
|
"use strict";
|
|
7975
|
-
DEFAULT_LOCAL_LOG =
|
|
8209
|
+
DEFAULT_LOCAL_LOG = join9(homedir7(), ".solongate", "local-logs", "solongate-audit.jsonl");
|
|
7976
8210
|
LOCAL_LOG = localLogFile();
|
|
7977
8211
|
DLP_REASON = /security layer \(dlp\)/i;
|
|
7978
8212
|
RL_REASON = /security layer \(rate limit\)|rate[- ]?limit(?:ed)?\b.*exceed|exceeded \d+ calls/i;
|
|
@@ -7980,13 +8214,13 @@ var init_local_log = __esm({
|
|
|
7980
8214
|
});
|
|
7981
8215
|
|
|
7982
8216
|
// src/api-client/client.ts
|
|
7983
|
-
import { readFileSync as
|
|
7984
|
-
import { resolve as resolve4, join as
|
|
7985
|
-
import { homedir as
|
|
8217
|
+
import { readFileSync as readFileSync10, writeFileSync as writeFileSync7, mkdirSync as mkdirSync6, existsSync as existsSync6 } from "fs";
|
|
8218
|
+
import { resolve as resolve4, join as join10 } from "path";
|
|
8219
|
+
import { homedir as homedir8 } from "os";
|
|
7986
8220
|
function listAccounts() {
|
|
7987
8221
|
let list5 = [];
|
|
7988
8222
|
try {
|
|
7989
|
-
const raw = JSON.parse(
|
|
8223
|
+
const raw = JSON.parse(readFileSync10(accountsFile(), "utf-8"));
|
|
7990
8224
|
if (Array.isArray(raw)) list5 = raw.filter((a) => a && typeof a.apiKey === "string");
|
|
7991
8225
|
} catch {
|
|
7992
8226
|
}
|
|
@@ -8000,7 +8234,7 @@ function saveAccount(acc) {
|
|
|
8000
8234
|
try {
|
|
8001
8235
|
const list5 = (() => {
|
|
8002
8236
|
try {
|
|
8003
|
-
const raw = JSON.parse(
|
|
8237
|
+
const raw = JSON.parse(readFileSync10(accountsFile(), "utf-8"));
|
|
8004
8238
|
return Array.isArray(raw) ? raw.filter((a) => a && a.apiKey) : [];
|
|
8005
8239
|
} catch {
|
|
8006
8240
|
return [];
|
|
@@ -8008,7 +8242,7 @@ function saveAccount(acc) {
|
|
|
8008
8242
|
})();
|
|
8009
8243
|
const next = list5.filter((a) => a.apiKey !== acc.apiKey);
|
|
8010
8244
|
next.unshift({ ...acc, addedAt: acc.addedAt ?? Date.now() });
|
|
8011
|
-
mkdirSync6(
|
|
8245
|
+
mkdirSync6(join10(homedir8(), ".solongate"), { recursive: true });
|
|
8012
8246
|
writeFileSync7(accountsFile(), JSON.stringify(next, null, 2));
|
|
8013
8247
|
} catch {
|
|
8014
8248
|
}
|
|
@@ -8017,7 +8251,7 @@ function removeAccount(apiKey) {
|
|
|
8017
8251
|
try {
|
|
8018
8252
|
const list5 = (() => {
|
|
8019
8253
|
try {
|
|
8020
|
-
const raw = JSON.parse(
|
|
8254
|
+
const raw = JSON.parse(readFileSync10(accountsFile(), "utf-8"));
|
|
8021
8255
|
return Array.isArray(raw) ? raw.filter((a) => a && a.apiKey) : [];
|
|
8022
8256
|
} catch {
|
|
8023
8257
|
return [];
|
|
@@ -8039,12 +8273,12 @@ function isActiveAccount(apiKey) {
|
|
|
8039
8273
|
}
|
|
8040
8274
|
function setActiveAccount(creds) {
|
|
8041
8275
|
try {
|
|
8042
|
-
const dir =
|
|
8276
|
+
const dir = join10(homedir8(), ".solongate");
|
|
8043
8277
|
mkdirSync6(dir, { recursive: true });
|
|
8044
|
-
const p =
|
|
8278
|
+
const p = join10(dir, ["cloud", "guard.json"].join("-"));
|
|
8045
8279
|
let existing = {};
|
|
8046
8280
|
try {
|
|
8047
|
-
existing = JSON.parse(
|
|
8281
|
+
existing = JSON.parse(readFileSync10(p, "utf-8"));
|
|
8048
8282
|
} catch {
|
|
8049
8283
|
}
|
|
8050
8284
|
if (!writeProtectedFile(p, JSON.stringify({ ...existing, apiKey: creds.apiKey, apiUrl: creds.apiUrl }, null, 2))) return false;
|
|
@@ -8056,14 +8290,14 @@ function setActiveAccount(creds) {
|
|
|
8056
8290
|
}
|
|
8057
8291
|
function clearActiveCredential() {
|
|
8058
8292
|
try {
|
|
8059
|
-
const p =
|
|
8060
|
-
if (!
|
|
8293
|
+
const p = join10(homedir8(), ".solongate", ["cloud", "guard.json"].join("-"));
|
|
8294
|
+
if (!existsSync6(p)) {
|
|
8061
8295
|
cached2 = null;
|
|
8062
8296
|
return true;
|
|
8063
8297
|
}
|
|
8064
8298
|
let existing = {};
|
|
8065
8299
|
try {
|
|
8066
|
-
existing = JSON.parse(
|
|
8300
|
+
existing = JSON.parse(readFileSync10(p, "utf-8"));
|
|
8067
8301
|
} catch {
|
|
8068
8302
|
}
|
|
8069
8303
|
delete existing.apiKey;
|
|
@@ -8078,9 +8312,9 @@ function clearActiveCredential() {
|
|
|
8078
8312
|
}
|
|
8079
8313
|
function loginCredentialFile() {
|
|
8080
8314
|
try {
|
|
8081
|
-
const p =
|
|
8082
|
-
if (!
|
|
8083
|
-
const c2 = JSON.parse(
|
|
8315
|
+
const p = join10(homedir8(), ".solongate", "cloud-guard.json");
|
|
8316
|
+
if (!existsSync6(p)) return {};
|
|
8317
|
+
const c2 = JSON.parse(readFileSync10(p, "utf-8"));
|
|
8084
8318
|
return c2 && typeof c2 === "object" ? c2 : {};
|
|
8085
8319
|
} catch {
|
|
8086
8320
|
return {};
|
|
@@ -8089,8 +8323,8 @@ function loginCredentialFile() {
|
|
|
8089
8323
|
function dotenvApiKey() {
|
|
8090
8324
|
try {
|
|
8091
8325
|
const envPath = resolve4(".env");
|
|
8092
|
-
if (!
|
|
8093
|
-
for (const line of
|
|
8326
|
+
if (!existsSync6(envPath)) return void 0;
|
|
8327
|
+
for (const line of readFileSync10(envPath, "utf-8").split("\n")) {
|
|
8094
8328
|
const trimmed = line.trim();
|
|
8095
8329
|
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
8096
8330
|
const eq = trimmed.indexOf("=");
|
|
@@ -8194,7 +8428,7 @@ var init_client = __esm({
|
|
|
8194
8428
|
"use strict";
|
|
8195
8429
|
init_global_install();
|
|
8196
8430
|
DEFAULT_API_URL2 = "https://api.solongate.com";
|
|
8197
|
-
accountsFile = () =>
|
|
8431
|
+
accountsFile = () => join10(homedir8(), ".solongate", "accounts.json");
|
|
8198
8432
|
viewOverride = null;
|
|
8199
8433
|
ApiError = class extends Error {
|
|
8200
8434
|
status;
|
|
@@ -8678,8 +8912,8 @@ var init_hooks = __esm({
|
|
|
8678
8912
|
import { Box as Box2, Text as Text2, useInput } from "ink";
|
|
8679
8913
|
import TextInput from "ink-text-input";
|
|
8680
8914
|
import { mkdirSync as mkdirSync7, writeFileSync as writeFileSync8 } from "fs";
|
|
8681
|
-
import { homedir as
|
|
8682
|
-
import { join as
|
|
8915
|
+
import { homedir as homedir9 } from "os";
|
|
8916
|
+
import { join as join11, resolve as resolve5 } from "path";
|
|
8683
8917
|
import { useCallback as useCallback2, useEffect as useEffect2, useRef as useRef2, useState as useState2 } from "react";
|
|
8684
8918
|
import { Fragment as Fragment2, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
8685
8919
|
function extractTarget(detail) {
|
|
@@ -9236,9 +9470,9 @@ function LivePanel({ active: active2 }) {
|
|
|
9236
9470
|
else if (input === "x") toggleSignal("dlp");
|
|
9237
9471
|
else if (input === "r") toggleSignal("ratelimit");
|
|
9238
9472
|
else if (input === "e") {
|
|
9239
|
-
const file =
|
|
9473
|
+
const file = join11(homedir9(), ".solongate", "live-export.jsonl");
|
|
9240
9474
|
try {
|
|
9241
|
-
mkdirSync7(
|
|
9475
|
+
mkdirSync7(join11(homedir9(), ".solongate"), { recursive: true });
|
|
9242
9476
|
writeFileSync8(file, visibleDesc.map((x) => JSON.stringify(x)).join("\n") + "\n");
|
|
9243
9477
|
setActionMsg({ text: `\u2713 exported ${visibleDesc.length} lines \u2192 ${file}`, level: "ok", until: Date.now() + 6e3 });
|
|
9244
9478
|
} catch (err2) {
|
|
@@ -9676,7 +9910,7 @@ var init_Live = __esm({
|
|
|
9676
9910
|
}
|
|
9677
9911
|
return h.toString(16);
|
|
9678
9912
|
};
|
|
9679
|
-
RING =
|
|
9913
|
+
RING = join11(homedir9(), ".solongate", "projects", projectKey(resolve5(process.cwd())), ".eval-ring.jsonl");
|
|
9680
9914
|
fmtUp = (ms) => {
|
|
9681
9915
|
const s = Math.floor(ms / 1e3);
|
|
9682
9916
|
const p = (n) => String(n).padStart(2, "0");
|
|
@@ -10962,8 +11196,8 @@ var init_Dlp = __esm({
|
|
|
10962
11196
|
import { Box as Box7, Text as Text7, useInput as useInput6 } from "ink";
|
|
10963
11197
|
import TextInput5 from "ink-text-input";
|
|
10964
11198
|
import { mkdirSync as mkdirSync8, writeFileSync as writeFileSync9 } from "fs";
|
|
10965
|
-
import { homedir as
|
|
10966
|
-
import { join as
|
|
11199
|
+
import { homedir as homedir10 } from "os";
|
|
11200
|
+
import { join as join12 } from "path";
|
|
10967
11201
|
import { useState as useState7 } from "react";
|
|
10968
11202
|
import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
10969
11203
|
function loadLocalRows() {
|
|
@@ -11089,8 +11323,8 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
11089
11323
|
const doExport = (kind) => {
|
|
11090
11324
|
setMsg({ text: "exporting\u2026", level: "ok" });
|
|
11091
11325
|
const run12 = async () => {
|
|
11092
|
-
const dir =
|
|
11093
|
-
const file =
|
|
11326
|
+
const dir = join12(homedir10(), ".solongate");
|
|
11327
|
+
const file = join12(dir, `audit-export-${source}.jsonl`);
|
|
11094
11328
|
let rows2;
|
|
11095
11329
|
if (kind === "page") rows2 = pageRows;
|
|
11096
11330
|
else if (source === "cloud") {
|
|
@@ -11674,9 +11908,9 @@ var init_args = __esm({
|
|
|
11674
11908
|
});
|
|
11675
11909
|
|
|
11676
11910
|
// src/commands/doctor.ts
|
|
11677
|
-
import { existsSync as
|
|
11678
|
-
import { homedir as
|
|
11679
|
-
import { join as
|
|
11911
|
+
import { existsSync as existsSync7, readFileSync as readFileSync11, statSync as statSync4 } from "fs";
|
|
11912
|
+
import { homedir as homedir11 } from "os";
|
|
11913
|
+
import { join as join13 } from "path";
|
|
11680
11914
|
async function collectChecks() {
|
|
11681
11915
|
const checks = [];
|
|
11682
11916
|
if (!isAuthenticated()) {
|
|
@@ -11724,8 +11958,32 @@ async function collectChecks() {
|
|
|
11724
11958
|
ok: claudeReg,
|
|
11725
11959
|
detail: claudeReg ? "guard registered" : "guard NOT registered - run `solongate repair`"
|
|
11726
11960
|
});
|
|
11727
|
-
if (
|
|
11728
|
-
const
|
|
11961
|
+
if (claudeReg) {
|
|
11962
|
+
const start = hookCanStart();
|
|
11963
|
+
checks.push({
|
|
11964
|
+
name: "hook runtime",
|
|
11965
|
+
ok: start.ok,
|
|
11966
|
+
detail: start.ok ? `node ${start.detail}` : `${start.detail} - nothing is being enforced or logged`
|
|
11967
|
+
});
|
|
11968
|
+
const beat = guardBeat();
|
|
11969
|
+
if (!beat) {
|
|
11970
|
+
checks.push({
|
|
11971
|
+
name: "guard fired",
|
|
11972
|
+
ok: "warn",
|
|
11973
|
+
detail: "never - open your agent and run one tool call, then check again"
|
|
11974
|
+
});
|
|
11975
|
+
} else if (beat.node === "no-node") {
|
|
11976
|
+
checks.push({
|
|
11977
|
+
name: "guard fired",
|
|
11978
|
+
ok: false,
|
|
11979
|
+
detail: `${agoLabel(beat.at)}, but found no node to run with - run \`solongate repair\``
|
|
11980
|
+
});
|
|
11981
|
+
} else {
|
|
11982
|
+
checks.push({ name: "guard fired", ok: true, detail: `${agoLabel(beat.at)} \xB7 ${beat.node}` });
|
|
11983
|
+
}
|
|
11984
|
+
}
|
|
11985
|
+
if (existsSync7(globalPaths().antigravityDir)) {
|
|
11986
|
+
const reg = existsSync7(globalPaths().antigravityHooksPath);
|
|
11729
11987
|
checks.push({
|
|
11730
11988
|
name: "Antigravity hooks",
|
|
11731
11989
|
ok: reg,
|
|
@@ -11753,7 +12011,7 @@ async function collectChecks() {
|
|
|
11753
12011
|
});
|
|
11754
12012
|
}
|
|
11755
12013
|
try {
|
|
11756
|
-
const raw =
|
|
12014
|
+
const raw = readFileSync11(join13(homedir11(), ".solongate", ".key-rejected.json"), "utf-8");
|
|
11757
12015
|
const m = JSON.parse(raw);
|
|
11758
12016
|
const ageMin = m.ts ? Math.round((Date.now() - m.ts) / 6e4) : null;
|
|
11759
12017
|
checks.push({
|
|
@@ -11764,8 +12022,8 @@ async function collectChecks() {
|
|
|
11764
12022
|
} catch {
|
|
11765
12023
|
}
|
|
11766
12024
|
const LOCAL_LOG2 = localLogFile();
|
|
11767
|
-
if (
|
|
11768
|
-
const st =
|
|
12025
|
+
if (existsSync7(LOCAL_LOG2)) {
|
|
12026
|
+
const st = statSync4(LOCAL_LOG2);
|
|
11769
12027
|
const ageMin = (Date.now() - st.mtimeMs) / 6e4;
|
|
11770
12028
|
checks.push({ name: "local logs", ok: true, detail: `on \xB7 ${(st.size / 1024).toFixed(0)}KB \xB7 last write ${ageMin < 1 ? "just now" : Math.round(ageMin) + "m ago"}` });
|
|
11771
12029
|
} else {
|
|
@@ -11798,6 +12056,7 @@ var init_doctor = __esm({
|
|
|
11798
12056
|
"use strict";
|
|
11799
12057
|
init_api_client();
|
|
11800
12058
|
init_global_install();
|
|
12059
|
+
init_hook_health();
|
|
11801
12060
|
init_local_log();
|
|
11802
12061
|
init_format();
|
|
11803
12062
|
init_args();
|
|
@@ -12905,8 +13164,8 @@ __export(tui_exports, {
|
|
|
12905
13164
|
launchTui: () => launchTui
|
|
12906
13165
|
});
|
|
12907
13166
|
import { appendFileSync as appendFileSync2, mkdirSync as mkdirSync9 } from "fs";
|
|
12908
|
-
import { homedir as
|
|
12909
|
-
import { join as
|
|
13167
|
+
import { homedir as homedir12 } from "os";
|
|
13168
|
+
import { join as join14 } from "path";
|
|
12910
13169
|
import { render } from "ink";
|
|
12911
13170
|
import { jsx as jsx10 } from "react/jsx-runtime";
|
|
12912
13171
|
async function launchTui() {
|
|
@@ -12917,11 +13176,11 @@ async function launchTui() {
|
|
|
12917
13176
|
return;
|
|
12918
13177
|
}
|
|
12919
13178
|
process.stdout.write("\x1B[?1049h\x1B[H");
|
|
12920
|
-
const debugLog =
|
|
13179
|
+
const debugLog = join14(homedir12(), ".solongate", "dataroom-debug.log");
|
|
12921
13180
|
const saved = { log: console.log, warn: console.warn, error: console.error, info: console.info, debug: console.debug };
|
|
12922
13181
|
const toFile = (level) => (...args) => {
|
|
12923
13182
|
try {
|
|
12924
|
-
mkdirSync9(
|
|
13183
|
+
mkdirSync9(join14(homedir12(), ".solongate"), { recursive: true });
|
|
12925
13184
|
appendFileSync2(debugLog, `${(/* @__PURE__ */ new Date()).toISOString()} [${level}] ${args.map((a) => typeof a === "string" ? a : JSON.stringify(a)).join(" ")}
|
|
12926
13185
|
`);
|
|
12927
13186
|
} catch {
|
|
@@ -12948,7 +13207,7 @@ var init_tui = __esm({
|
|
|
12948
13207
|
});
|
|
12949
13208
|
|
|
12950
13209
|
// src/commands/policy.ts
|
|
12951
|
-
import { readFileSync as
|
|
13210
|
+
import { readFileSync as readFileSync12 } from "fs";
|
|
12952
13211
|
async function run2(argv) {
|
|
12953
13212
|
const { positionals, flags } = parse(argv);
|
|
12954
13213
|
const sub = positionals[0];
|
|
@@ -13157,7 +13416,7 @@ function printRules(rules) {
|
|
|
13157
13416
|
}
|
|
13158
13417
|
async function resolveRules(target) {
|
|
13159
13418
|
if (target.endsWith(".json")) {
|
|
13160
|
-
const parsed = JSON.parse(
|
|
13419
|
+
const parsed = JSON.parse(readFileSync12(target, "utf-8"));
|
|
13161
13420
|
return parsed.rules ?? [];
|
|
13162
13421
|
}
|
|
13163
13422
|
const p = await api.policies.get(target);
|
|
@@ -13656,11 +13915,11 @@ var init_agents2 = __esm({
|
|
|
13656
13915
|
});
|
|
13657
13916
|
|
|
13658
13917
|
// src/commands/trace.ts
|
|
13659
|
-
import { readdirSync as readdirSync3, readFileSync as
|
|
13660
|
-
import { homedir as
|
|
13661
|
-
import { join as
|
|
13918
|
+
import { readdirSync as readdirSync3, readFileSync as readFileSync13 } from "fs";
|
|
13919
|
+
import { homedir as homedir13 } from "os";
|
|
13920
|
+
import { join as join15, resolve as resolve6 } from "path";
|
|
13662
13921
|
function readAllRings() {
|
|
13663
|
-
const root =
|
|
13922
|
+
const root = join15(homedir13(), ".solongate", "projects");
|
|
13664
13923
|
let dirs;
|
|
13665
13924
|
try {
|
|
13666
13925
|
dirs = readdirSync3(root);
|
|
@@ -13671,7 +13930,7 @@ function readAllRings() {
|
|
|
13671
13930
|
for (const d of dirs) {
|
|
13672
13931
|
let text;
|
|
13673
13932
|
try {
|
|
13674
|
-
text =
|
|
13933
|
+
text = readFileSync13(join15(root, d, ".eval-ring.jsonl"), "utf-8");
|
|
13675
13934
|
} catch {
|
|
13676
13935
|
continue;
|
|
13677
13936
|
}
|
|
@@ -13764,10 +14023,10 @@ var init_trace = __esm({
|
|
|
13764
14023
|
});
|
|
13765
14024
|
|
|
13766
14025
|
// src/commands/watch.ts
|
|
13767
|
-
import { closeSync as closeSync2, existsSync as
|
|
14026
|
+
import { closeSync as closeSync2, existsSync as existsSync8, openSync as openSync4, readSync as readSync2, statSync as statSync5 } from "fs";
|
|
13768
14027
|
function tailLocal(file, maxBytes = 131072) {
|
|
13769
14028
|
try {
|
|
13770
|
-
const size =
|
|
14029
|
+
const size = statSync5(file).size;
|
|
13771
14030
|
const start = Math.max(0, size - maxBytes);
|
|
13772
14031
|
const fd = openSync4(file, "r");
|
|
13773
14032
|
const buf = Buffer.alloc(size - start);
|
|
@@ -13809,7 +14068,7 @@ async function run9(argv) {
|
|
|
13809
14068
|
};
|
|
13810
14069
|
const pollLocal = () => {
|
|
13811
14070
|
const LOCAL_LOG2 = localLogFile();
|
|
13812
|
-
if (cloudOnly || !
|
|
14071
|
+
if (cloudOnly || !existsSync8(LOCAL_LOG2)) return;
|
|
13813
14072
|
const rows = [];
|
|
13814
14073
|
for (const line of tailLocal(LOCAL_LOG2)) {
|
|
13815
14074
|
try {
|
|
@@ -14081,9 +14340,9 @@ __export(logs_server_exports, {
|
|
|
14081
14340
|
runLogsServer: () => runLogsServer
|
|
14082
14341
|
});
|
|
14083
14342
|
import { createServer } from "http";
|
|
14084
|
-
import { readFileSync as
|
|
14085
|
-
import { resolve as resolve7, join as
|
|
14086
|
-
import { homedir as
|
|
14343
|
+
import { readFileSync as readFileSync14, statSync as statSync6 } from "fs";
|
|
14344
|
+
import { resolve as resolve7, join as join16, isAbsolute as isAbsolute2 } from "path";
|
|
14345
|
+
import { homedir as homedir14 } from "os";
|
|
14087
14346
|
import { readdirSync as readdirSync4 } from "fs";
|
|
14088
14347
|
function allowedOrigins() {
|
|
14089
14348
|
const base = [
|
|
@@ -14100,15 +14359,15 @@ function resolveLocalLogDir(rawPath) {
|
|
|
14100
14359
|
const dir = String(rawPath || "").trim().replace(/[\\/]+$/, "");
|
|
14101
14360
|
if (!dir) return null;
|
|
14102
14361
|
if (isAbsolute2(dir)) return dir;
|
|
14103
|
-
return resolve7(
|
|
14362
|
+
return resolve7(homedir14(), ".solongate", "local-logs");
|
|
14104
14363
|
}
|
|
14105
14364
|
async function findLogDir() {
|
|
14106
|
-
const base = resolve7(
|
|
14365
|
+
const base = resolve7(homedir14(), ".solongate");
|
|
14107
14366
|
try {
|
|
14108
14367
|
const files = readdirSync4(base).filter((f) => f.startsWith(".policy-cache-") && f.endsWith(".json"));
|
|
14109
14368
|
for (const f of files) {
|
|
14110
14369
|
try {
|
|
14111
|
-
const c2 = JSON.parse(
|
|
14370
|
+
const c2 = JSON.parse(readFileSync14(join16(base, f), "utf-8"));
|
|
14112
14371
|
const p = c2?.security?.localLogs?.path;
|
|
14113
14372
|
if (typeof p === "string" && p.trim()) return { dir: resolveLocalLogDir(p), configured: p };
|
|
14114
14373
|
} catch {
|
|
@@ -14117,7 +14376,7 @@ async function findLogDir() {
|
|
|
14117
14376
|
} catch {
|
|
14118
14377
|
}
|
|
14119
14378
|
try {
|
|
14120
|
-
const cfgRaw =
|
|
14379
|
+
const cfgRaw = readFileSync14(join16(base, "cloud-guard.json"), "utf-8");
|
|
14121
14380
|
const { apiKey, apiUrl } = JSON.parse(cfgRaw);
|
|
14122
14381
|
if (apiKey) {
|
|
14123
14382
|
const url = `${apiUrl || "https://api.solongate.com"}/api/v1/policies/active`;
|
|
@@ -14146,9 +14405,9 @@ function setCors(req, res) {
|
|
|
14146
14405
|
}
|
|
14147
14406
|
function fileInfo(dir) {
|
|
14148
14407
|
if (!dir) return { file: null, exists: false, size: 0, mtimeMs: 0 };
|
|
14149
|
-
const file =
|
|
14408
|
+
const file = join16(dir, LOG_FILENAME);
|
|
14150
14409
|
try {
|
|
14151
|
-
const st =
|
|
14410
|
+
const st = statSync6(file);
|
|
14152
14411
|
return { file, exists: true, size: st.size, mtimeMs: st.mtimeMs };
|
|
14153
14412
|
} catch {
|
|
14154
14413
|
return { file, exists: false, size: 0, mtimeMs: 0 };
|
|
@@ -14229,7 +14488,7 @@ async function runLogsServer() {
|
|
|
14229
14488
|
return;
|
|
14230
14489
|
}
|
|
14231
14490
|
try {
|
|
14232
|
-
const text =
|
|
14491
|
+
const text = readFileSync14(info.file, "utf-8");
|
|
14233
14492
|
res.writeHead(200, { "Content-Type": "text/plain; charset=utf-8", "Last-Modified": lastMod, "X-Solongate-Exists": "1" });
|
|
14234
14493
|
res.end(text);
|
|
14235
14494
|
} catch {
|
|
@@ -14282,9 +14541,9 @@ var init_logs_server = __esm({
|
|
|
14282
14541
|
});
|
|
14283
14542
|
|
|
14284
14543
|
// src/index.ts
|
|
14285
|
-
import { readFileSync as
|
|
14544
|
+
import { readFileSync as readFileSync15 } from "fs";
|
|
14286
14545
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
14287
|
-
import { dirname as dirname4, join as
|
|
14546
|
+
import { dirname as dirname4, join as join17 } from "path";
|
|
14288
14547
|
|
|
14289
14548
|
// src/config.ts
|
|
14290
14549
|
import { readFileSync, existsSync } from "fs";
|
|
@@ -15397,9 +15656,9 @@ function extractFilenames(args) {
|
|
|
15397
15656
|
if (isUrl) return;
|
|
15398
15657
|
if (trimmed.includes("/") || trimmed.includes("\\")) {
|
|
15399
15658
|
const parts = trimmed.split(/[/\\]/);
|
|
15400
|
-
const
|
|
15401
|
-
if (
|
|
15402
|
-
addFilename(
|
|
15659
|
+
const basename2 = parts[parts.length - 1];
|
|
15660
|
+
if (basename2 && looksLikeFilename(basename2)) {
|
|
15661
|
+
addFilename(basename2);
|
|
15403
15662
|
}
|
|
15404
15663
|
}
|
|
15405
15664
|
const lower = trimmed.toLowerCase();
|
|
@@ -15417,9 +15676,9 @@ function extractFilenames(args) {
|
|
|
15417
15676
|
}
|
|
15418
15677
|
if (word.includes("/") || word.includes("\\")) {
|
|
15419
15678
|
const parts = word.split(/[/\\]/);
|
|
15420
|
-
const
|
|
15421
|
-
if (
|
|
15422
|
-
addFilename(
|
|
15679
|
+
const basename2 = parts[parts.length - 1];
|
|
15680
|
+
if (basename2 && looksLikeFilename(basename2)) {
|
|
15681
|
+
addFilename(basename2);
|
|
15423
15682
|
}
|
|
15424
15683
|
}
|
|
15425
15684
|
if (word.includes("*") || word.includes("?")) {
|
|
@@ -17679,8 +17938,8 @@ if (!IS_HUMAN_CLI) {
|
|
|
17679
17938
|
}
|
|
17680
17939
|
var PKG_VERSION = (() => {
|
|
17681
17940
|
try {
|
|
17682
|
-
const p =
|
|
17683
|
-
return JSON.parse(
|
|
17941
|
+
const p = join17(dirname4(fileURLToPath4(import.meta.url)), "..", "package.json");
|
|
17942
|
+
return JSON.parse(readFileSync15(p, "utf-8")).version || "unknown";
|
|
17684
17943
|
} catch {
|
|
17685
17944
|
return "unknown";
|
|
17686
17945
|
}
|