@solongate/proxy 0.81.76 → 0.81.78
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 +2 -2
- package/dist/global-install.d.ts +11 -0
- package/dist/global-install.js +21 -0
- package/dist/index.js +54 -307
- package/dist/tui/index.js +115 -5
- package/hooks/guard.bundled.mjs +1 -1
- package/hooks/guard.mjs +1 -1
- package/package.json +1 -1
package/dist/commands/index.js
CHANGED
|
@@ -22,7 +22,7 @@ var ApiError = class extends Error {
|
|
|
22
22
|
};
|
|
23
23
|
var NotAuthenticatedError = class extends Error {
|
|
24
24
|
constructor() {
|
|
25
|
-
super("Not logged in. Run `solongate
|
|
25
|
+
super("Not logged in. Run `solongate` and log in from the Accounts panel.");
|
|
26
26
|
this.name = "NotAuthenticatedError";
|
|
27
27
|
}
|
|
28
28
|
};
|
|
@@ -132,7 +132,7 @@ async function request(method, path, opts = {}) {
|
|
|
132
132
|
if (typeof envelope === "string") {
|
|
133
133
|
throw new ApiError(res.status, "ERROR", envelope);
|
|
134
134
|
}
|
|
135
|
-
if (res.status === 401) throw new ApiError(401, "AUTHENTICATION_ERROR", "Invalid API key. Run `solongate
|
|
135
|
+
if (res.status === 401) throw new ApiError(401, "AUTHENTICATION_ERROR", "Invalid API key. Run `solongate` and log in from the Accounts panel.");
|
|
136
136
|
if (res.status === 429) throw new ApiError(429, "RATE_LIMITED", "Rate limited by the API. Slow down and retry.");
|
|
137
137
|
throw new ApiError(res.status, "ERROR", text || res.statusText || `HTTP ${res.status}`);
|
|
138
138
|
}
|
package/dist/global-install.d.ts
CHANGED
|
@@ -11,6 +11,17 @@ export declare function globalPaths(): {
|
|
|
11
11
|
};
|
|
12
12
|
export declare function clearGuardUpdateCheck(): boolean;
|
|
13
13
|
export declare function runGlobalRestore(): void;
|
|
14
|
+
/**
|
|
15
|
+
* TUI-safe uninstall (dataroom Settings → guard → remove). Same effect as
|
|
16
|
+
* runGlobalRestore but returns a status string instead of writing to stdout —
|
|
17
|
+
* any console output would corrupt the Ink render. Unlocks the protected files,
|
|
18
|
+
* removes the auto-shield shell shim, then strips the SolonGate hooks from the
|
|
19
|
+
* global Claude settings (restoring the pre-install backup when present).
|
|
20
|
+
*/
|
|
21
|
+
export declare function uninstallGlobalQuiet(): {
|
|
22
|
+
ok: boolean;
|
|
23
|
+
message: string;
|
|
24
|
+
};
|
|
14
25
|
export declare function installClaudeShim(shieldPath: string): void;
|
|
15
26
|
export declare function removeClaudeShim(): void;
|
|
16
27
|
export declare function runGlobalInstall(opts?: {
|
package/dist/global-install.js
CHANGED
|
@@ -137,6 +137,26 @@ function runGlobalRestore() {
|
|
|
137
137
|
}
|
|
138
138
|
console.log(" Global SolonGate enforcement uninstalled. Restart Claude Code.");
|
|
139
139
|
}
|
|
140
|
+
function uninstallGlobalQuiet() {
|
|
141
|
+
try {
|
|
142
|
+
const p = globalPaths();
|
|
143
|
+
unlockProtected();
|
|
144
|
+
removeClaudeShim();
|
|
145
|
+
if (existsSync(p.backupPath)) {
|
|
146
|
+
writeFileSync(p.settingsPath, readFileSync(p.backupPath, "utf-8"));
|
|
147
|
+
return { ok: true, message: "guard removed \u2014 restored the pre-install settings (restart Claude Code)" };
|
|
148
|
+
}
|
|
149
|
+
if (existsSync(p.settingsPath)) {
|
|
150
|
+
const s = JSON.parse(readFileSync(p.settingsPath, "utf-8"));
|
|
151
|
+
delete s.hooks;
|
|
152
|
+
writeFileSync(p.settingsPath, JSON.stringify(s, null, 2) + "\n");
|
|
153
|
+
return { ok: true, message: "guard removed \u2014 SolonGate hooks cleared (restart Claude Code)" };
|
|
154
|
+
}
|
|
155
|
+
return { ok: true, message: "nothing to remove \u2014 no global Claude Code settings found" };
|
|
156
|
+
} catch (e) {
|
|
157
|
+
return { ok: false, message: e instanceof Error ? e.message : String(e) };
|
|
158
|
+
}
|
|
159
|
+
}
|
|
140
160
|
var SHIM_BEGIN = "# >>> SolonGate shield (auto secret redaction) >>>";
|
|
141
161
|
var SHIM_END = "# <<< SolonGate shield <<<";
|
|
142
162
|
function escapeRe(s) {
|
|
@@ -283,5 +303,6 @@ export {
|
|
|
283
303
|
removeClaudeShim,
|
|
284
304
|
runGlobalInstall,
|
|
285
305
|
runGlobalRestore,
|
|
306
|
+
uninstallGlobalQuiet,
|
|
286
307
|
unlockProtected
|
|
287
308
|
};
|
package/dist/index.js
CHANGED
|
@@ -7302,7 +7302,7 @@ async function request(method, path, opts = {}) {
|
|
|
7302
7302
|
if (typeof envelope === "string") {
|
|
7303
7303
|
throw new ApiError(res.status, "ERROR", envelope);
|
|
7304
7304
|
}
|
|
7305
|
-
if (res.status === 401) throw new ApiError(401, "AUTHENTICATION_ERROR", "Invalid API key. Run `solongate
|
|
7305
|
+
if (res.status === 401) throw new ApiError(401, "AUTHENTICATION_ERROR", "Invalid API key. Run `solongate` and log in from the Accounts panel.");
|
|
7306
7306
|
if (res.status === 429) throw new ApiError(429, "RATE_LIMITED", "Rate limited by the API. Slow down and retry.");
|
|
7307
7307
|
throw new ApiError(res.status, "ERROR", text || res.statusText || `HTTP ${res.status}`);
|
|
7308
7308
|
}
|
|
@@ -7327,7 +7327,7 @@ var init_client = __esm({
|
|
|
7327
7327
|
};
|
|
7328
7328
|
NotAuthenticatedError = class extends Error {
|
|
7329
7329
|
constructor() {
|
|
7330
|
-
super("Not logged in. Run `solongate
|
|
7330
|
+
super("Not logged in. Run `solongate` and log in from the Accounts panel.");
|
|
7331
7331
|
this.name = "NotAuthenticatedError";
|
|
7332
7332
|
}
|
|
7333
7333
|
};
|
|
@@ -10115,32 +10115,6 @@ import { homedir as homedir9 } from "os";
|
|
|
10115
10115
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
10116
10116
|
import { createInterface } from "readline";
|
|
10117
10117
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
10118
|
-
function lockFile(file) {
|
|
10119
|
-
if (!existsSync4(file)) return;
|
|
10120
|
-
try {
|
|
10121
|
-
if (process.platform === "win32") {
|
|
10122
|
-
try {
|
|
10123
|
-
execFileSync2("icacls", [file, "/deny", "*S-1-1-0:(WD,AD,DC,DE)"], { stdio: "ignore" });
|
|
10124
|
-
} catch {
|
|
10125
|
-
}
|
|
10126
|
-
try {
|
|
10127
|
-
execFileSync2("attrib", ["+R", file], { stdio: "ignore" });
|
|
10128
|
-
} catch {
|
|
10129
|
-
}
|
|
10130
|
-
} else if (process.platform === "darwin") {
|
|
10131
|
-
try {
|
|
10132
|
-
execFileSync2("chflags", ["uchg", file], { stdio: "ignore" });
|
|
10133
|
-
} catch {
|
|
10134
|
-
}
|
|
10135
|
-
} else {
|
|
10136
|
-
try {
|
|
10137
|
-
execFileSync2("chattr", ["+i", file], { stdio: "ignore" });
|
|
10138
|
-
} catch {
|
|
10139
|
-
}
|
|
10140
|
-
}
|
|
10141
|
-
} catch {
|
|
10142
|
-
}
|
|
10143
|
-
}
|
|
10144
10118
|
function unlockFile(file) {
|
|
10145
10119
|
if (!existsSync4(file)) return;
|
|
10146
10120
|
try {
|
|
@@ -10182,9 +10156,6 @@ function protectedTargets() {
|
|
|
10182
10156
|
p.settingsPath
|
|
10183
10157
|
];
|
|
10184
10158
|
}
|
|
10185
|
-
function lockProtected() {
|
|
10186
|
-
for (const f of protectedTargets()) lockFile(f);
|
|
10187
|
-
}
|
|
10188
10159
|
function unlockProtected() {
|
|
10189
10160
|
for (const f of protectedTargets()) unlockFile(f);
|
|
10190
10161
|
}
|
|
@@ -10211,36 +10182,29 @@ function clearGuardUpdateCheck() {
|
|
|
10211
10182
|
return false;
|
|
10212
10183
|
}
|
|
10213
10184
|
}
|
|
10214
|
-
function
|
|
10215
|
-
|
|
10216
|
-
|
|
10217
|
-
|
|
10218
|
-
|
|
10219
|
-
|
|
10220
|
-
|
|
10221
|
-
|
|
10222
|
-
|
|
10223
|
-
|
|
10224
|
-
|
|
10225
|
-
|
|
10226
|
-
|
|
10185
|
+
function uninstallGlobalQuiet() {
|
|
10186
|
+
try {
|
|
10187
|
+
const p = globalPaths();
|
|
10188
|
+
unlockProtected();
|
|
10189
|
+
removeClaudeShim();
|
|
10190
|
+
if (existsSync4(p.backupPath)) {
|
|
10191
|
+
writeFileSync9(p.settingsPath, readFileSync9(p.backupPath, "utf-8"));
|
|
10192
|
+
return { ok: true, message: "guard removed \u2014 restored the pre-install settings (restart Claude Code)" };
|
|
10193
|
+
}
|
|
10194
|
+
if (existsSync4(p.settingsPath)) {
|
|
10195
|
+
const s = JSON.parse(readFileSync9(p.settingsPath, "utf-8"));
|
|
10196
|
+
delete s.hooks;
|
|
10197
|
+
writeFileSync9(p.settingsPath, JSON.stringify(s, null, 2) + "\n");
|
|
10198
|
+
return { ok: true, message: "guard removed \u2014 SolonGate hooks cleared (restart Claude Code)" };
|
|
10199
|
+
}
|
|
10200
|
+
return { ok: true, message: "nothing to remove \u2014 no global Claude Code settings found" };
|
|
10201
|
+
} catch (e) {
|
|
10202
|
+
return { ok: false, message: e instanceof Error ? e.message : String(e) };
|
|
10203
|
+
}
|
|
10227
10204
|
}
|
|
10228
10205
|
function escapeRe(s) {
|
|
10229
10206
|
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
10230
10207
|
}
|
|
10231
|
-
function resolveRealClaude() {
|
|
10232
|
-
try {
|
|
10233
|
-
const finder = process.platform === "win32" ? "where" : "which";
|
|
10234
|
-
const out2 = execFileSync2(finder, ["claude"], { encoding: "utf-8" }).split(/\r?\n/).map((s) => s.trim()).filter(Boolean);
|
|
10235
|
-
if (process.platform === "win32") {
|
|
10236
|
-
const low = (s) => s.toLowerCase();
|
|
10237
|
-
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;
|
|
10238
|
-
}
|
|
10239
|
-
return out2[0] || null;
|
|
10240
|
-
} catch {
|
|
10241
|
-
return null;
|
|
10242
|
-
}
|
|
10243
|
-
}
|
|
10244
10208
|
function shimTargets() {
|
|
10245
10209
|
if (process.platform === "win32") {
|
|
10246
10210
|
try {
|
|
@@ -10263,92 +10227,14 @@ function writeShimBlock(file, block2) {
|
|
|
10263
10227
|
mkdirSync8(dirname3(file), { recursive: true });
|
|
10264
10228
|
writeFileSync9(file, content);
|
|
10265
10229
|
}
|
|
10266
|
-
function
|
|
10267
|
-
const
|
|
10268
|
-
if (!real) {
|
|
10269
|
-
console.log(" (Claude Code not found on PATH \u2014 skipped auto-shield. Install it, then re-run `login`.)");
|
|
10270
|
-
return;
|
|
10271
|
-
}
|
|
10272
|
-
const node = process.execPath.replace(/\\/g, "/");
|
|
10273
|
-
const shield = shieldPath.replace(/\\/g, "/");
|
|
10274
|
-
const win = process.platform === "win32";
|
|
10275
|
-
const block2 = win ? `${SHIM_BEGIN}
|
|
10276
|
-
function claude { & "${node}" "${shield}" -- "${real}" @args }
|
|
10277
|
-
${SHIM_END}` : `${SHIM_BEGIN}
|
|
10278
|
-
claude() { "${node}" "${shield}" -- "${real}" "$@"; }
|
|
10279
|
-
${SHIM_END}`;
|
|
10280
|
-
const targets = shimTargets();
|
|
10281
|
-
if (targets.length === 0) return;
|
|
10282
|
-
for (const file of targets) {
|
|
10230
|
+
function removeClaudeShim() {
|
|
10231
|
+
for (const file of shimTargets()) {
|
|
10283
10232
|
try {
|
|
10284
|
-
writeShimBlock(file,
|
|
10233
|
+
writeShimBlock(file, null);
|
|
10285
10234
|
} catch {
|
|
10286
10235
|
}
|
|
10287
10236
|
}
|
|
10288
10237
|
}
|
|
10289
|
-
async function runGlobalInstall2(opts = {}) {
|
|
10290
|
-
const p = globalPaths();
|
|
10291
|
-
let apiKey = opts.apiKey || process.env["SOLONGATE_API_KEY"] || "";
|
|
10292
|
-
if (!apiKey || apiKey === "sg_live_your_key_here") {
|
|
10293
|
-
try {
|
|
10294
|
-
const cfg = JSON.parse(readFileSync9(p.configPath, "utf-8"));
|
|
10295
|
-
if (cfg && typeof cfg.apiKey === "string") apiKey = cfg.apiKey;
|
|
10296
|
-
} catch {
|
|
10297
|
-
}
|
|
10298
|
-
}
|
|
10299
|
-
if (!apiKey || apiKey === "sg_live_your_key_here") {
|
|
10300
|
-
apiKey = await ask(" Enter your SolonGate API key (sg_live_\u2026 from https://dashboard.solongate.com): ");
|
|
10301
|
-
}
|
|
10302
|
-
if (!apiKey.startsWith("sg_live_") && !apiKey.startsWith("sg_test_")) {
|
|
10303
|
-
console.log(" Invalid API key. Must start with sg_live_ or sg_test_");
|
|
10304
|
-
process.exit(1);
|
|
10305
|
-
}
|
|
10306
|
-
const apiUrl = opts.apiUrl || process.env["SOLONGATE_API_URL"] || "https://api.solongate.com";
|
|
10307
|
-
mkdirSync8(p.hooksDir, { recursive: true });
|
|
10308
|
-
mkdirSync8(p.claudeDir, { recursive: true });
|
|
10309
|
-
unlockProtected();
|
|
10310
|
-
writeFileSync9(join11(p.hooksDir, "guard.mjs"), readGuard());
|
|
10311
|
-
writeFileSync9(join11(p.hooksDir, "audit.mjs"), readHook("audit.mjs"));
|
|
10312
|
-
writeFileSync9(join11(p.hooksDir, "stop.mjs"), readHook("stop.mjs"));
|
|
10313
|
-
writeFileSync9(join11(p.hooksDir, "shield.mjs"), readHook("shield.mjs"));
|
|
10314
|
-
console.log(` Installed hooks \u2192 ${p.hooksDir}`);
|
|
10315
|
-
installClaudeShim(join11(p.hooksDir, "shield.mjs"));
|
|
10316
|
-
writeFileSync9(p.configPath, JSON.stringify({ apiKey, apiUrl }, null, 2) + "\n");
|
|
10317
|
-
console.log(` Wrote ${p.configPath}`);
|
|
10318
|
-
let existing = {};
|
|
10319
|
-
if (existsSync4(p.settingsPath)) {
|
|
10320
|
-
const raw = readFileSync9(p.settingsPath, "utf-8");
|
|
10321
|
-
if (!existsSync4(p.backupPath)) {
|
|
10322
|
-
writeFileSync9(p.backupPath, raw);
|
|
10323
|
-
console.log(` Backed up existing settings \u2192 ${p.backupPath}`);
|
|
10324
|
-
}
|
|
10325
|
-
try {
|
|
10326
|
-
existing = JSON.parse(raw);
|
|
10327
|
-
} catch {
|
|
10328
|
-
existing = {};
|
|
10329
|
-
}
|
|
10330
|
-
}
|
|
10331
|
-
const guardAbs = join11(p.hooksDir, "guard.mjs").replace(/\\/g, "/");
|
|
10332
|
-
const auditAbs = join11(p.hooksDir, "audit.mjs").replace(/\\/g, "/");
|
|
10333
|
-
const stopAbs = join11(p.hooksDir, "stop.mjs").replace(/\\/g, "/");
|
|
10334
|
-
const nodeBin = process.execPath.replace(/\\/g, "/");
|
|
10335
|
-
const call = process.platform === "win32" ? "& " : "";
|
|
10336
|
-
const hookCmd = (script) => `${call}"${nodeBin}" "${script}" claude-code "Claude Code"`;
|
|
10337
|
-
const merged = {
|
|
10338
|
-
...existing,
|
|
10339
|
-
hooks: {
|
|
10340
|
-
PreToolUse: [{ matcher: "", hooks: [{ type: "command", command: hookCmd(guardAbs) }] }],
|
|
10341
|
-
PostToolUse: [{ matcher: "", hooks: [{ type: "command", command: hookCmd(auditAbs) }] }],
|
|
10342
|
-
Stop: [{ matcher: "", hooks: [{ type: "command", command: hookCmd(stopAbs) }] }]
|
|
10343
|
-
}
|
|
10344
|
-
};
|
|
10345
|
-
writeFileSync9(p.settingsPath, JSON.stringify(merged, null, 2) + "\n");
|
|
10346
|
-
console.log(` Registered global hooks \u2192 ${p.settingsPath}`);
|
|
10347
|
-
if (process.env["SOLONGATE_OS_LOCK"] === "1") {
|
|
10348
|
-
lockProtected();
|
|
10349
|
-
console.log(" Locked protection files (OS-level read-only/immutable).");
|
|
10350
|
-
}
|
|
10351
|
-
}
|
|
10352
10238
|
var __dirname, HOOKS_DIR, SHIM_BEGIN, SHIM_END;
|
|
10353
10239
|
var init_global_install = __esm({
|
|
10354
10240
|
"src/global-install.ts"() {
|
|
@@ -10687,6 +10573,17 @@ function SettingsPanel({
|
|
|
10687
10573
|
setEditing("wh-url");
|
|
10688
10574
|
} else if (cur.kind === "alert-add-email") openAlertEditor("email");
|
|
10689
10575
|
else if (cur.kind === "alert-add-tg") openAlertEditor("telegram");
|
|
10576
|
+
} else if (inp === "d" && cur.kind === "guard") {
|
|
10577
|
+
const k = keyOf(cur);
|
|
10578
|
+
if (confirmDel !== k) {
|
|
10579
|
+
setConfirmDel(k);
|
|
10580
|
+
setMsg({ text: "\u26A0 d again REMOVES the guard from this device \u2014 Claude Code sessions stop being protected until you reinstall", level: "bad" });
|
|
10581
|
+
return;
|
|
10582
|
+
}
|
|
10583
|
+
setConfirmDel(null);
|
|
10584
|
+
const res = uninstallGlobalQuiet();
|
|
10585
|
+
setMsg({ text: (res.ok ? "\u2713 " : "\u2717 ") + res.message, level: res.ok ? "ok" : "bad" });
|
|
10586
|
+
guardQ.reload();
|
|
10690
10587
|
} else if (inp === "d" && (cur.kind === "wh" || cur.kind === "alert")) {
|
|
10691
10588
|
const k = keyOf(cur);
|
|
10692
10589
|
if (confirmDel !== k) {
|
|
@@ -10794,8 +10691,8 @@ function SettingsPanel({
|
|
|
10794
10691
|
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "guard".padEnd(11) }),
|
|
10795
10692
|
guard ? /* @__PURE__ */ jsxs7(Fragment4, { children: [
|
|
10796
10693
|
/* @__PURE__ */ jsx7(Text7, { color: guard.up_to_date ? theme.ok : theme.warn, children: `v${guard.installed ?? "?"}` }),
|
|
10797
|
-
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: guard.up_to_date ? " (latest)" : ` \u2192 v${guard.latest} available \xB7 enter
|
|
10798
|
-
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: ` \xB7 ${guard.device_count} device${guard.device_count === 1 ? "" : "s"}${guard.outdated_count ? ` \xB7 ${guard.outdated_count} outdated` : ""}` })
|
|
10694
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: guard.up_to_date ? " (latest)" : ` \u2192 v${guard.latest} available \xB7 enter update` }),
|
|
10695
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: ` \xB7 ${guard.device_count} device${guard.device_count === 1 ? "" : "s"}${guard.outdated_count ? ` \xB7 ${guard.outdated_count} outdated` : ""} \xB7 d remove` })
|
|
10799
10696
|
] }) : /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "loading\u2026" })
|
|
10800
10697
|
] });
|
|
10801
10698
|
case "self":
|
|
@@ -10860,7 +10757,7 @@ function SettingsPanel({
|
|
|
10860
10757
|
const sectionOf = (r) => r.kind === "acct" || r.kind === "acct-add" ? "ACCOUNTS" : r.kind === "guard" || r.kind === "self" ? "PROTECTION" : r.kind === "ll-enabled" || r.kind === "ll-path" || r.kind === "ll-server" ? "LOCAL LOGS" : r.kind === "wh" || r.kind === "wh-add" ? "WEBHOOKS" : "ALERTS";
|
|
10861
10758
|
const SECTION_DESC = {
|
|
10862
10759
|
ACCOUNTS: `on this device (${accounts.length}) \xB7 \u25CF viewing \xB7 ACTIVE = guard key \xB7 x removes`,
|
|
10863
|
-
PROTECTION: "guard hook
|
|
10760
|
+
PROTECTION: "guard hook: enter update \xB7 d remove \xB7 + self-protection toggle",
|
|
10864
10761
|
"LOCAL LOGS": "mirror every decision to a file + dashboard link",
|
|
10865
10762
|
WEBHOOKS: `POST events to a URL (${webhooks.length}) \xB7 t tests`,
|
|
10866
10763
|
ALERTS: `one email + one telegram (${alerts.length}) \xB7 enter edits \xB7 m on/off`
|
|
@@ -12346,157 +12243,6 @@ var init_commands = __esm({
|
|
|
12346
12243
|
}
|
|
12347
12244
|
});
|
|
12348
12245
|
|
|
12349
|
-
// src/login.ts
|
|
12350
|
-
var login_exports = {};
|
|
12351
|
-
import { spawn as spawn5 } from "child_process";
|
|
12352
|
-
function startSpinner(text) {
|
|
12353
|
-
if (!process.stderr.isTTY) {
|
|
12354
|
-
process.stderr.write(` ${text}
|
|
12355
|
-
`);
|
|
12356
|
-
return (finalLine) => {
|
|
12357
|
-
if (finalLine) process.stderr.write(finalLine + "\n");
|
|
12358
|
-
};
|
|
12359
|
-
}
|
|
12360
|
-
let i = 0;
|
|
12361
|
-
const draw = () => {
|
|
12362
|
-
const frame = SPINNER_FRAMES[i = (i + 1) % SPINNER_FRAMES.length];
|
|
12363
|
-
process.stderr.write(`\r ${c.cyan}${frame}${c.reset} ${c.dim}${text}${c.reset}\x1B[K`);
|
|
12364
|
-
};
|
|
12365
|
-
draw();
|
|
12366
|
-
const timer = setInterval(draw, 80);
|
|
12367
|
-
return (finalLine) => {
|
|
12368
|
-
clearInterval(timer);
|
|
12369
|
-
process.stderr.write("\r\x1B[K");
|
|
12370
|
-
if (finalLine) process.stderr.write(finalLine + "\n");
|
|
12371
|
-
};
|
|
12372
|
-
}
|
|
12373
|
-
function parseArgs2(argv) {
|
|
12374
|
-
const args = argv.slice(3);
|
|
12375
|
-
let apiUrl = process.env["SOLONGATE_API_URL"] || "https://api.solongate.com";
|
|
12376
|
-
let install = true;
|
|
12377
|
-
for (let i = 0; i < args.length; i++) {
|
|
12378
|
-
if (args[i] === "--api-url") apiUrl = args[++i] || apiUrl;
|
|
12379
|
-
else if (args[i] === "--no-install") install = false;
|
|
12380
|
-
}
|
|
12381
|
-
return { apiUrl, install };
|
|
12382
|
-
}
|
|
12383
|
-
function openBrowser2(url) {
|
|
12384
|
-
try {
|
|
12385
|
-
const cmd = process.platform === "win32" ? "cmd" : process.platform === "darwin" ? "open" : "xdg-open";
|
|
12386
|
-
const args = process.platform === "win32" ? ["/c", "start", '""', url] : [url];
|
|
12387
|
-
const child = spawn5(cmd, args, { stdio: "ignore", detached: true });
|
|
12388
|
-
child.on("error", () => {
|
|
12389
|
-
});
|
|
12390
|
-
child.unref();
|
|
12391
|
-
} catch {
|
|
12392
|
-
}
|
|
12393
|
-
}
|
|
12394
|
-
async function main() {
|
|
12395
|
-
const { apiUrl, install } = parseArgs2(process.argv);
|
|
12396
|
-
console.log("");
|
|
12397
|
-
console.log(` ${c.bold}${c.blue4}SolonGate${c.reset} ${c.dim}\u2014 Login${c.reset}`);
|
|
12398
|
-
console.log("");
|
|
12399
|
-
let start;
|
|
12400
|
-
try {
|
|
12401
|
-
const res = await fetch(`${apiUrl}/api/v1/auth/device/start`, { method: "POST" });
|
|
12402
|
-
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
12403
|
-
start = await res.json();
|
|
12404
|
-
} catch (e) {
|
|
12405
|
-
console.log(` Could not reach SolonGate (${apiUrl}).`);
|
|
12406
|
-
console.log(` ${e instanceof Error ? e.message : String(e)}`);
|
|
12407
|
-
process.exit(1);
|
|
12408
|
-
}
|
|
12409
|
-
const { device_code, user_code, verification_uri_complete, verification_uri, interval, expires_in } = start;
|
|
12410
|
-
const verifyUrl = verification_uri_complete || verification_uri;
|
|
12411
|
-
console.log(` ${c.blue5}\u2192${c.reset} Opening your browser to authorize this device\u2026`);
|
|
12412
|
-
console.log("");
|
|
12413
|
-
console.log(` ${c.dim}If it doesn't open, visit this link:${c.reset}`);
|
|
12414
|
-
console.log(` ${c.cyan}${verifyUrl}${c.reset}`);
|
|
12415
|
-
console.log("");
|
|
12416
|
-
void user_code;
|
|
12417
|
-
openBrowser2(verifyUrl);
|
|
12418
|
-
const pollMs = Math.max(2, Number(interval) || 3) * 1e3;
|
|
12419
|
-
const deadline = Date.now() + (Number(expires_in) || 600) * 1e3;
|
|
12420
|
-
let apiKey = "";
|
|
12421
|
-
const stopSpinner = startSpinner("Waiting for authorization\u2026");
|
|
12422
|
-
while (Date.now() < deadline) {
|
|
12423
|
-
await sleep(pollMs);
|
|
12424
|
-
try {
|
|
12425
|
-
const res = await fetch(`${apiUrl}/api/v1/auth/device/poll`, {
|
|
12426
|
-
method: "POST",
|
|
12427
|
-
headers: { "Content-Type": "application/json" },
|
|
12428
|
-
body: JSON.stringify({ device_code })
|
|
12429
|
-
});
|
|
12430
|
-
const data = await res.json().catch(() => ({}));
|
|
12431
|
-
if (data?.status === "approved" && data?.api_key) {
|
|
12432
|
-
apiKey = data.api_key;
|
|
12433
|
-
stopSpinner();
|
|
12434
|
-
console.log("");
|
|
12435
|
-
const who = data?.user?.name || data?.user?.email;
|
|
12436
|
-
const mail = data?.user?.email;
|
|
12437
|
-
if (who) {
|
|
12438
|
-
const suffix = mail && mail !== who ? ` ${c.dim}(${mail})${c.reset}` : "";
|
|
12439
|
-
console.log(` ${c.green}\u2713${c.reset} ${c.bold}Logged in as ${c.white}${who}${c.reset}${suffix}`);
|
|
12440
|
-
} else {
|
|
12441
|
-
console.log(` ${c.green}\u2713${c.reset} ${c.bold}Logged in${c.reset}`);
|
|
12442
|
-
}
|
|
12443
|
-
if (data?.project?.name) {
|
|
12444
|
-
console.log(` ${c.dim}Project:${c.reset} ${c.cyan}${data.project.name}${c.reset}`);
|
|
12445
|
-
}
|
|
12446
|
-
saveAccount({ apiKey, apiUrl, project: data?.project?.name, user: data?.user?.name || data?.user?.email, email: data?.user?.email });
|
|
12447
|
-
break;
|
|
12448
|
-
}
|
|
12449
|
-
if (data?.status === "expired" || data?.status === "not_found") {
|
|
12450
|
-
stopSpinner(` ${c.red}\u2717${c.reset} Code expired. Run \`login\` again.`);
|
|
12451
|
-
process.exit(1);
|
|
12452
|
-
}
|
|
12453
|
-
} catch {
|
|
12454
|
-
}
|
|
12455
|
-
}
|
|
12456
|
-
if (!apiKey) {
|
|
12457
|
-
stopSpinner(` ${c.red}\u2717${c.reset} Timed out waiting for authorization. Run \`login\` again.`);
|
|
12458
|
-
process.exit(1);
|
|
12459
|
-
}
|
|
12460
|
-
if (!install) {
|
|
12461
|
-
console.log("");
|
|
12462
|
-
console.log(" Logged in. Re-run `login` to enable system-wide enforcement.");
|
|
12463
|
-
return;
|
|
12464
|
-
}
|
|
12465
|
-
console.log("");
|
|
12466
|
-
await runGlobalInstall2({ apiKey, apiUrl });
|
|
12467
|
-
console.log("");
|
|
12468
|
-
console.log(" \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510");
|
|
12469
|
-
console.log(" \u2502 You are logged in and protected. \u2502");
|
|
12470
|
-
console.log(" \u2502 Every Claude Code session on this machine is \u2502");
|
|
12471
|
-
console.log(" \u2502 now guarded by your cloud policy (OPA WASM). \u2502");
|
|
12472
|
-
console.log(" \u2502 \u2502");
|
|
12473
|
-
console.log(" \u2502 Manage policy: https://dashboard.solongate.com \u2502");
|
|
12474
|
-
console.log(" \u2502 Restart Claude Code to apply. \u2502");
|
|
12475
|
-
console.log(" \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518");
|
|
12476
|
-
console.log("");
|
|
12477
|
-
console.log(` ${c.bold}${c.yellow}! Already-open terminals are NOT protected yet.${c.reset}`);
|
|
12478
|
-
console.log(` ${c.dim} Hooks load only when a session starts, so any terminal`);
|
|
12479
|
-
console.log(` (and the Claude Code running in it) that was already open`);
|
|
12480
|
-
console.log(` won't be caught. Open a NEW terminal and start Claude Code`);
|
|
12481
|
-
console.log(` there for the guard + audit logging to take effect.${c.reset}`);
|
|
12482
|
-
console.log("");
|
|
12483
|
-
}
|
|
12484
|
-
var sleep, SPINNER_FRAMES;
|
|
12485
|
-
var init_login = __esm({
|
|
12486
|
-
"src/login.ts"() {
|
|
12487
|
-
"use strict";
|
|
12488
|
-
init_cli_utils();
|
|
12489
|
-
init_global_install();
|
|
12490
|
-
init_client();
|
|
12491
|
-
sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
12492
|
-
SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
12493
|
-
main().catch((err2) => {
|
|
12494
|
-
console.log(`Fatal: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
12495
|
-
process.exit(1);
|
|
12496
|
-
});
|
|
12497
|
-
}
|
|
12498
|
-
});
|
|
12499
|
-
|
|
12500
12246
|
// src/shield.ts
|
|
12501
12247
|
var shield_exports = {};
|
|
12502
12248
|
__export(shield_exports, {
|
|
@@ -12504,7 +12250,7 @@ __export(shield_exports, {
|
|
|
12504
12250
|
});
|
|
12505
12251
|
import { createServer, request as httpRequest } from "http";
|
|
12506
12252
|
import { request as httpsRequest } from "https";
|
|
12507
|
-
import { spawn as
|
|
12253
|
+
import { spawn as spawn5 } from "child_process";
|
|
12508
12254
|
import { URL as URL2 } from "url";
|
|
12509
12255
|
import { readFileSync as readFileSync11, existsSync as existsSync7, readdirSync, statSync as statSync4 } from "fs";
|
|
12510
12256
|
import { resolve as resolve5 } from "path";
|
|
@@ -12765,7 +12511,7 @@ async function runShield() {
|
|
|
12765
12511
|
const upstream = pickUpstream();
|
|
12766
12512
|
const { port, close } = await startProxy(upstream);
|
|
12767
12513
|
log4(`redacting secrets on the LLM path \u2192 masking before ${upstream.host} (127.0.0.1:${port})`);
|
|
12768
|
-
const child =
|
|
12514
|
+
const child = spawn5(cmd[0], cmd.slice(1), {
|
|
12769
12515
|
stdio: "inherit",
|
|
12770
12516
|
env: { ...process.env, ANTHROPIC_BASE_URL: `http://127.0.0.1:${port}` },
|
|
12771
12517
|
shell: process.platform === "win32"
|
|
@@ -13268,7 +13014,7 @@ function showDiff(result) {
|
|
|
13268
13014
|
}
|
|
13269
13015
|
log3("");
|
|
13270
13016
|
}
|
|
13271
|
-
async function
|
|
13017
|
+
async function main() {
|
|
13272
13018
|
const opts = parseInjectArgs(process.argv);
|
|
13273
13019
|
printBanner("Inject SDK");
|
|
13274
13020
|
if (!detectProject()) {
|
|
@@ -13355,7 +13101,7 @@ var init_inject = __esm({
|
|
|
13355
13101
|
"src/inject.ts"() {
|
|
13356
13102
|
"use strict";
|
|
13357
13103
|
init_cli_utils();
|
|
13358
|
-
|
|
13104
|
+
main().catch((err2) => {
|
|
13359
13105
|
log3(`Fatal: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
13360
13106
|
process.exit(1);
|
|
13361
13107
|
});
|
|
@@ -13572,7 +13318,7 @@ dist/
|
|
|
13572
13318
|
`
|
|
13573
13319
|
);
|
|
13574
13320
|
}
|
|
13575
|
-
async function
|
|
13321
|
+
async function main2() {
|
|
13576
13322
|
const opts = parseCreateArgs(process.argv);
|
|
13577
13323
|
const dir = resolve8(opts.name);
|
|
13578
13324
|
printBanner("Create MCP Server");
|
|
@@ -13646,7 +13392,7 @@ var init_create = __esm({
|
|
|
13646
13392
|
"src/create.ts"() {
|
|
13647
13393
|
"use strict";
|
|
13648
13394
|
init_cli_utils();
|
|
13649
|
-
|
|
13395
|
+
main2().catch((err2) => {
|
|
13650
13396
|
log3(`Fatal: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
13651
13397
|
process.exit(1);
|
|
13652
13398
|
});
|
|
@@ -13922,7 +13668,7 @@ async function push(apiKey, file, policyId) {
|
|
|
13922
13668
|
log5(` ${dim2("Method:")} ${method === "PUT" ? "Updated existing" : "Created new"}`);
|
|
13923
13669
|
log5("");
|
|
13924
13670
|
}
|
|
13925
|
-
async function
|
|
13671
|
+
async function main3() {
|
|
13926
13672
|
const { command, apiKey, file, policyId } = parseCliArgs();
|
|
13927
13673
|
try {
|
|
13928
13674
|
if (command === "pull") {
|
|
@@ -13967,7 +13713,7 @@ var init_pull_push = __esm({
|
|
|
13967
13713
|
cyan2 = (s) => `\x1B[36m${s}\x1B[0m`;
|
|
13968
13714
|
magenta = (s) => `\x1B[35m${s}\x1B[0m`;
|
|
13969
13715
|
API_URL = "https://api.solongate.com";
|
|
13970
|
-
|
|
13716
|
+
main3();
|
|
13971
13717
|
}
|
|
13972
13718
|
});
|
|
13973
13719
|
|
|
@@ -17017,17 +16763,17 @@ function printWelcome() {
|
|
|
17017
16763
|
console.log("");
|
|
17018
16764
|
console.log(" Get started with one command:");
|
|
17019
16765
|
console.log("");
|
|
17020
|
-
console.log(` ${c.cyan}solongate
|
|
16766
|
+
console.log(` ${c.cyan}solongate${c.reset}`);
|
|
17021
16767
|
console.log("");
|
|
17022
|
-
console.log(` ${c.dim}This
|
|
17023
|
-
console.log(` ${c.dim}
|
|
17024
|
-
console.log(` ${c.cyan}https://dashboard.solongate.com${c.reset}`);
|
|
16768
|
+
console.log(` ${c.dim}This opens the dataroom; log in from the Accounts panel to pair this${c.reset}`);
|
|
16769
|
+
console.log(` ${c.dim}device and protect every Claude Code session with your cloud policy.${c.reset}`);
|
|
16770
|
+
console.log(` ${c.dim}Manage it at ${c.reset}${c.cyan}https://dashboard.solongate.com${c.reset}`);
|
|
17025
16771
|
console.log("");
|
|
17026
16772
|
console.log(` ${c.dim}Using local log storage? Show it live in the dashboard with${c.reset}`);
|
|
17027
16773
|
console.log(` ${c.cyan}solongate logs-server${c.reset}`);
|
|
17028
16774
|
console.log("");
|
|
17029
16775
|
}
|
|
17030
|
-
async function
|
|
16776
|
+
async function main4() {
|
|
17031
16777
|
const subcommand = process.argv[2];
|
|
17032
16778
|
if (IS_HUMAN_CLI) {
|
|
17033
16779
|
const tuiBound = subcommand === "dataroom" || process.argv.length <= 2 && process.stdout.isTTY && process.stdin.isTTY;
|
|
@@ -17061,7 +16807,8 @@ async function main5() {
|
|
|
17061
16807
|
process.exit(code);
|
|
17062
16808
|
}
|
|
17063
16809
|
if (subcommand === "login") {
|
|
17064
|
-
await Promise.resolve().then(() => (
|
|
16810
|
+
const { launchTui: launchTui2 } = await Promise.resolve().then(() => (init_tui(), tui_exports));
|
|
16811
|
+
await launchTui2();
|
|
17065
16812
|
return;
|
|
17066
16813
|
}
|
|
17067
16814
|
if (subcommand === "shield") {
|
|
@@ -17099,4 +16846,4 @@ async function main5() {
|
|
|
17099
16846
|
process.exit(1);
|
|
17100
16847
|
}
|
|
17101
16848
|
}
|
|
17102
|
-
|
|
16849
|
+
main4();
|
package/dist/tui/index.js
CHANGED
|
@@ -400,7 +400,7 @@ var ApiError = class extends Error {
|
|
|
400
400
|
};
|
|
401
401
|
var NotAuthenticatedError = class extends Error {
|
|
402
402
|
constructor() {
|
|
403
|
-
super("Not logged in. Run `solongate
|
|
403
|
+
super("Not logged in. Run `solongate` and log in from the Accounts panel.");
|
|
404
404
|
this.name = "NotAuthenticatedError";
|
|
405
405
|
}
|
|
406
406
|
};
|
|
@@ -502,7 +502,7 @@ async function request(method, path, opts = {}) {
|
|
|
502
502
|
if (typeof envelope === "string") {
|
|
503
503
|
throw new ApiError(res.status, "ERROR", envelope);
|
|
504
504
|
}
|
|
505
|
-
if (res.status === 401) throw new ApiError(401, "AUTHENTICATION_ERROR", "Invalid API key. Run `solongate
|
|
505
|
+
if (res.status === 401) throw new ApiError(401, "AUTHENTICATION_ERROR", "Invalid API key. Run `solongate` and log in from the Accounts panel.");
|
|
506
506
|
if (res.status === 429) throw new ApiError(429, "RATE_LIMITED", "Rate limited by the API. Slow down and retry.");
|
|
507
507
|
throw new ApiError(res.status, "ERROR", text || res.statusText || `HTTP ${res.status}`);
|
|
508
508
|
}
|
|
@@ -3148,6 +3148,50 @@ import { createInterface } from "readline";
|
|
|
3148
3148
|
import { execFileSync } from "child_process";
|
|
3149
3149
|
var __dirname = dirname(fileURLToPath(import.meta.url));
|
|
3150
3150
|
var HOOKS_DIR = resolve2(__dirname, "..", "hooks");
|
|
3151
|
+
function unlockFile(file) {
|
|
3152
|
+
if (!existsSync2(file)) return;
|
|
3153
|
+
try {
|
|
3154
|
+
if (process.platform === "win32") {
|
|
3155
|
+
try {
|
|
3156
|
+
execFileSync("icacls", [file, "/remove:d", "*S-1-1-0"], { stdio: "ignore" });
|
|
3157
|
+
} catch {
|
|
3158
|
+
}
|
|
3159
|
+
try {
|
|
3160
|
+
execFileSync("icacls", [file, "/reset"], { stdio: "ignore" });
|
|
3161
|
+
} catch {
|
|
3162
|
+
}
|
|
3163
|
+
try {
|
|
3164
|
+
execFileSync("attrib", ["-R", file], { stdio: "ignore" });
|
|
3165
|
+
} catch {
|
|
3166
|
+
}
|
|
3167
|
+
} else if (process.platform === "darwin") {
|
|
3168
|
+
try {
|
|
3169
|
+
execFileSync("chflags", ["nouchg", file], { stdio: "ignore" });
|
|
3170
|
+
} catch {
|
|
3171
|
+
}
|
|
3172
|
+
} else {
|
|
3173
|
+
try {
|
|
3174
|
+
execFileSync("chattr", ["-i", file], { stdio: "ignore" });
|
|
3175
|
+
} catch {
|
|
3176
|
+
}
|
|
3177
|
+
}
|
|
3178
|
+
} catch {
|
|
3179
|
+
}
|
|
3180
|
+
}
|
|
3181
|
+
function protectedTargets() {
|
|
3182
|
+
const p = globalPaths();
|
|
3183
|
+
return [
|
|
3184
|
+
join6(p.hooksDir, "guard.mjs"),
|
|
3185
|
+
join6(p.hooksDir, "audit.mjs"),
|
|
3186
|
+
join6(p.hooksDir, "stop.mjs"),
|
|
3187
|
+
join6(p.hooksDir, "shield.mjs"),
|
|
3188
|
+
p.configPath,
|
|
3189
|
+
p.settingsPath
|
|
3190
|
+
];
|
|
3191
|
+
}
|
|
3192
|
+
function unlockProtected() {
|
|
3193
|
+
for (const f of protectedTargets()) unlockFile(f);
|
|
3194
|
+
}
|
|
3151
3195
|
function globalPaths() {
|
|
3152
3196
|
const home = homedir6();
|
|
3153
3197
|
const sgDir = join6(home, ".solongate");
|
|
@@ -3171,6 +3215,61 @@ function clearGuardUpdateCheck() {
|
|
|
3171
3215
|
return false;
|
|
3172
3216
|
}
|
|
3173
3217
|
}
|
|
3218
|
+
function uninstallGlobalQuiet() {
|
|
3219
|
+
try {
|
|
3220
|
+
const p = globalPaths();
|
|
3221
|
+
unlockProtected();
|
|
3222
|
+
removeClaudeShim();
|
|
3223
|
+
if (existsSync2(p.backupPath)) {
|
|
3224
|
+
writeFileSync5(p.settingsPath, readFileSync4(p.backupPath, "utf-8"));
|
|
3225
|
+
return { ok: true, message: "guard removed \u2014 restored the pre-install settings (restart Claude Code)" };
|
|
3226
|
+
}
|
|
3227
|
+
if (existsSync2(p.settingsPath)) {
|
|
3228
|
+
const s = JSON.parse(readFileSync4(p.settingsPath, "utf-8"));
|
|
3229
|
+
delete s.hooks;
|
|
3230
|
+
writeFileSync5(p.settingsPath, JSON.stringify(s, null, 2) + "\n");
|
|
3231
|
+
return { ok: true, message: "guard removed \u2014 SolonGate hooks cleared (restart Claude Code)" };
|
|
3232
|
+
}
|
|
3233
|
+
return { ok: true, message: "nothing to remove \u2014 no global Claude Code settings found" };
|
|
3234
|
+
} catch (e) {
|
|
3235
|
+
return { ok: false, message: e instanceof Error ? e.message : String(e) };
|
|
3236
|
+
}
|
|
3237
|
+
}
|
|
3238
|
+
var SHIM_BEGIN = "# >>> SolonGate shield (auto secret redaction) >>>";
|
|
3239
|
+
var SHIM_END = "# <<< SolonGate shield <<<";
|
|
3240
|
+
function escapeRe(s) {
|
|
3241
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
3242
|
+
}
|
|
3243
|
+
function shimTargets() {
|
|
3244
|
+
if (process.platform === "win32") {
|
|
3245
|
+
try {
|
|
3246
|
+
const prof = execFileSync("powershell", ["-NoProfile", "-Command", "$PROFILE.CurrentUserAllHosts"], { encoding: "utf-8" }).trim();
|
|
3247
|
+
return prof ? [prof] : [];
|
|
3248
|
+
} catch {
|
|
3249
|
+
return [];
|
|
3250
|
+
}
|
|
3251
|
+
}
|
|
3252
|
+
return [".bashrc", ".zshrc", ".profile"].map((f) => join6(homedir6(), f)).filter((f) => existsSync2(f));
|
|
3253
|
+
}
|
|
3254
|
+
function writeShimBlock(file, block2) {
|
|
3255
|
+
const re = new RegExp(escapeRe(SHIM_BEGIN) + "[\\s\\S]*?" + escapeRe(SHIM_END) + "\\r?\\n?", "g");
|
|
3256
|
+
let content = existsSync2(file) ? readFileSync4(file, "utf-8") : "";
|
|
3257
|
+
content = content.replace(re, "");
|
|
3258
|
+
if (block2) {
|
|
3259
|
+
if (content.length && !content.endsWith("\n")) content += "\n";
|
|
3260
|
+
content += block2 + "\n";
|
|
3261
|
+
}
|
|
3262
|
+
mkdirSync4(dirname(file), { recursive: true });
|
|
3263
|
+
writeFileSync5(file, content);
|
|
3264
|
+
}
|
|
3265
|
+
function removeClaudeShim() {
|
|
3266
|
+
for (const file of shimTargets()) {
|
|
3267
|
+
try {
|
|
3268
|
+
writeShimBlock(file, null);
|
|
3269
|
+
} catch {
|
|
3270
|
+
}
|
|
3271
|
+
}
|
|
3272
|
+
}
|
|
3174
3273
|
|
|
3175
3274
|
// src/logs-server-daemon.ts
|
|
3176
3275
|
import { spawn as spawn3 } from "child_process";
|
|
@@ -3587,6 +3686,17 @@ function SettingsPanel({
|
|
|
3587
3686
|
setEditing("wh-url");
|
|
3588
3687
|
} else if (cur.kind === "alert-add-email") openAlertEditor("email");
|
|
3589
3688
|
else if (cur.kind === "alert-add-tg") openAlertEditor("telegram");
|
|
3689
|
+
} else if (inp === "d" && cur.kind === "guard") {
|
|
3690
|
+
const k = keyOf(cur);
|
|
3691
|
+
if (confirmDel !== k) {
|
|
3692
|
+
setConfirmDel(k);
|
|
3693
|
+
setMsg({ text: "\u26A0 d again REMOVES the guard from this device \u2014 Claude Code sessions stop being protected until you reinstall", level: "bad" });
|
|
3694
|
+
return;
|
|
3695
|
+
}
|
|
3696
|
+
setConfirmDel(null);
|
|
3697
|
+
const res = uninstallGlobalQuiet();
|
|
3698
|
+
setMsg({ text: (res.ok ? "\u2713 " : "\u2717 ") + res.message, level: res.ok ? "ok" : "bad" });
|
|
3699
|
+
guardQ.reload();
|
|
3590
3700
|
} else if (inp === "d" && (cur.kind === "wh" || cur.kind === "alert")) {
|
|
3591
3701
|
const k = keyOf(cur);
|
|
3592
3702
|
if (confirmDel !== k) {
|
|
@@ -3694,8 +3804,8 @@ function SettingsPanel({
|
|
|
3694
3804
|
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "guard".padEnd(11) }),
|
|
3695
3805
|
guard ? /* @__PURE__ */ jsxs7(Fragment4, { children: [
|
|
3696
3806
|
/* @__PURE__ */ jsx7(Text7, { color: guard.up_to_date ? theme.ok : theme.warn, children: `v${guard.installed ?? "?"}` }),
|
|
3697
|
-
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: guard.up_to_date ? " (latest)" : ` \u2192 v${guard.latest} available \xB7 enter
|
|
3698
|
-
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: ` \xB7 ${guard.device_count} device${guard.device_count === 1 ? "" : "s"}${guard.outdated_count ? ` \xB7 ${guard.outdated_count} outdated` : ""}` })
|
|
3807
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: guard.up_to_date ? " (latest)" : ` \u2192 v${guard.latest} available \xB7 enter update` }),
|
|
3808
|
+
/* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: ` \xB7 ${guard.device_count} device${guard.device_count === 1 ? "" : "s"}${guard.outdated_count ? ` \xB7 ${guard.outdated_count} outdated` : ""} \xB7 d remove` })
|
|
3699
3809
|
] }) : /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "loading\u2026" })
|
|
3700
3810
|
] });
|
|
3701
3811
|
case "self":
|
|
@@ -3760,7 +3870,7 @@ function SettingsPanel({
|
|
|
3760
3870
|
const sectionOf = (r) => r.kind === "acct" || r.kind === "acct-add" ? "ACCOUNTS" : r.kind === "guard" || r.kind === "self" ? "PROTECTION" : r.kind === "ll-enabled" || r.kind === "ll-path" || r.kind === "ll-server" ? "LOCAL LOGS" : r.kind === "wh" || r.kind === "wh-add" ? "WEBHOOKS" : "ALERTS";
|
|
3761
3871
|
const SECTION_DESC = {
|
|
3762
3872
|
ACCOUNTS: `on this device (${accounts.length}) \xB7 \u25CF viewing \xB7 ACTIVE = guard key \xB7 x removes`,
|
|
3763
|
-
PROTECTION: "guard hook
|
|
3873
|
+
PROTECTION: "guard hook: enter update \xB7 d remove \xB7 + self-protection toggle",
|
|
3764
3874
|
"LOCAL LOGS": "mirror every decision to a file + dashboard link",
|
|
3765
3875
|
WEBHOOKS: `POST events to a URL (${webhooks.length}) \xB7 t tests`,
|
|
3766
3876
|
ALERTS: `one email + one telegram (${alerts.length}) \xB7 enter edits \xB7 m on/off`
|
package/hooks/guard.bundled.mjs
CHANGED
|
@@ -6536,7 +6536,7 @@ import { resolve, join, dirname, isAbsolute } from "node:path";
|
|
|
6536
6536
|
import { homedir } from "node:os";
|
|
6537
6537
|
import { gunzipSync } from "node:zlib";
|
|
6538
6538
|
import { createHash } from "node:crypto";
|
|
6539
|
-
var HOOK_VERSION =
|
|
6539
|
+
var HOOK_VERSION = 41;
|
|
6540
6540
|
function localLogsOnly(security) {
|
|
6541
6541
|
if (security && typeof security === "object") {
|
|
6542
6542
|
const l = security.localLogs;
|
package/hooks/guard.mjs
CHANGED
|
@@ -32,7 +32,7 @@ import { createHash } from 'node:crypto';
|
|
|
32
32
|
// the installed hook self-updates when the cloud version is higher (see
|
|
33
33
|
// maybeSelfUpdate). This is what makes guard fixes propagate without a manual
|
|
34
34
|
// reinstall — the same trust model as the OPA WASM this hook already runs.
|
|
35
|
-
const HOOK_VERSION =
|
|
35
|
+
const HOOK_VERSION = 41;
|
|
36
36
|
|
|
37
37
|
// True when local log storage is ON. In that mode logs are kept LOCAL ONLY and
|
|
38
38
|
// nothing is sent to the cloud audit log.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@solongate/proxy",
|
|
3
|
-
"version": "0.81.
|
|
3
|
+
"version": "0.81.78",
|
|
4
4
|
"description": "AI tool security proxy: protect any AI tool server with customizable policies, path/command constraints, rate limiting, and audit logging. No code changes required.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|