@solongate/proxy 0.81.78 → 0.81.79

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.
@@ -11,6 +11,13 @@ export declare function globalPaths(): {
11
11
  };
12
12
  export declare function clearGuardUpdateCheck(): boolean;
13
13
  export declare function runGlobalRestore(): void;
14
+ /**
15
+ * Are the SolonGate guard hooks currently installed in the global Claude settings
16
+ * on THIS device? Reflects a local install/remove IMMEDIATELY — unlike the cloud
17
+ * guard-status (which shows the version this device last reported and lingers for
18
+ * ~14 days), so the dataroom can show "removed" the instant you remove it.
19
+ */
20
+ export declare function isGuardInstalled(): boolean;
14
21
  /**
15
22
  * TUI-safe uninstall (dataroom Settings → guard → remove). Same effect as
16
23
  * runGlobalRestore but returns a status string instead of writing to stdout —
@@ -137,20 +137,31 @@ function runGlobalRestore() {
137
137
  }
138
138
  console.log(" Global SolonGate enforcement uninstalled. Restart Claude Code.");
139
139
  }
140
+ function isGuardInstalled() {
141
+ try {
142
+ const p = globalPaths();
143
+ if (!existsSync(p.settingsPath)) return false;
144
+ const s = JSON.parse(readFileSync(p.settingsPath, "utf-8"));
145
+ return !!s.hooks && JSON.stringify(s.hooks).includes(".solongate");
146
+ } catch {
147
+ return false;
148
+ }
149
+ }
140
150
  function uninstallGlobalQuiet() {
141
151
  try {
142
152
  const p = globalPaths();
143
153
  unlockProtected();
144
154
  removeClaudeShim();
155
+ const applies = "applies to NEW Claude Code sessions \u2014 a session already running keeps its loaded hooks until it ends";
145
156
  if (existsSync(p.backupPath)) {
146
157
  writeFileSync(p.settingsPath, readFileSync(p.backupPath, "utf-8"));
147
- return { ok: true, message: "guard removed \u2014 restored the pre-install settings (restart Claude Code)" };
158
+ return { ok: true, message: `guard removed \u2014 restored the pre-install settings \xB7 ${applies}` };
148
159
  }
149
160
  if (existsSync(p.settingsPath)) {
150
161
  const s = JSON.parse(readFileSync(p.settingsPath, "utf-8"));
151
162
  delete s.hooks;
152
163
  writeFileSync(p.settingsPath, JSON.stringify(s, null, 2) + "\n");
153
- return { ok: true, message: "guard removed \u2014 SolonGate hooks cleared (restart Claude Code)" };
164
+ return { ok: true, message: `guard removed \u2014 hooks cleared \xB7 ${applies}` };
154
165
  }
155
166
  return { ok: true, message: "nothing to remove \u2014 no global Claude Code settings found" };
156
167
  } catch (e) {
@@ -299,6 +310,7 @@ export {
299
310
  globalPaths,
300
311
  installClaudeShim,
301
312
  installGlobalWithKey,
313
+ isGuardInstalled,
302
314
  lockProtected,
303
315
  removeClaudeShim,
304
316
  runGlobalInstall,
package/dist/index.js CHANGED
@@ -10182,20 +10182,31 @@ function clearGuardUpdateCheck() {
10182
10182
  return false;
10183
10183
  }
10184
10184
  }
10185
+ function isGuardInstalled() {
10186
+ try {
10187
+ const p = globalPaths();
10188
+ if (!existsSync4(p.settingsPath)) return false;
10189
+ const s = JSON.parse(readFileSync9(p.settingsPath, "utf-8"));
10190
+ return !!s.hooks && JSON.stringify(s.hooks).includes(".solongate");
10191
+ } catch {
10192
+ return false;
10193
+ }
10194
+ }
10185
10195
  function uninstallGlobalQuiet() {
10186
10196
  try {
10187
10197
  const p = globalPaths();
10188
10198
  unlockProtected();
10189
10199
  removeClaudeShim();
10200
+ const applies = "applies to NEW Claude Code sessions \u2014 a session already running keeps its loaded hooks until it ends";
10190
10201
  if (existsSync4(p.backupPath)) {
10191
10202
  writeFileSync9(p.settingsPath, readFileSync9(p.backupPath, "utf-8"));
10192
- return { ok: true, message: "guard removed \u2014 restored the pre-install settings (restart Claude Code)" };
10203
+ return { ok: true, message: `guard removed \u2014 restored the pre-install settings \xB7 ${applies}` };
10193
10204
  }
10194
10205
  if (existsSync4(p.settingsPath)) {
10195
10206
  const s = JSON.parse(readFileSync9(p.settingsPath, "utf-8"));
10196
10207
  delete s.hooks;
10197
10208
  writeFileSync9(p.settingsPath, JSON.stringify(s, null, 2) + "\n");
10198
- return { ok: true, message: "guard removed \u2014 SolonGate hooks cleared (restart Claude Code)" };
10209
+ return { ok: true, message: `guard removed \u2014 hooks cleared \xB7 ${applies}` };
10199
10210
  }
10200
10211
  return { ok: true, message: "nothing to remove \u2014 no global Claude Code settings found" };
10201
10212
  } catch (e) {
@@ -10272,6 +10283,7 @@ function SettingsPanel({
10272
10283
  const [tick, setTick] = useState7(0);
10273
10284
  const abort = useRef3(false);
10274
10285
  const refreshAccounts = () => setAccounts(listAccounts());
10286
+ const [guardHere, setGuardHere] = useState7(() => isGuardInstalled());
10275
10287
  const locked = accounts.length === 0;
10276
10288
  const [srv, setSrv] = useState7(() => logsServerStatus());
10277
10289
  useEffect6(() => {
@@ -10416,6 +10428,10 @@ function SettingsPanel({
10416
10428
  } else if (r.kind === "acct-add") {
10417
10429
  beginLogin();
10418
10430
  } else if (r.kind === "guard") {
10431
+ if (!guardHere) {
10432
+ setMsg({ text: "guard is removed on this device \u2014 log in again (Accounts \u2192 + add) to reinstall it", level: "bad" });
10433
+ return;
10434
+ }
10419
10435
  if (!guard) return;
10420
10436
  if (guard.up_to_date) {
10421
10437
  setMsg({ text: `guard already on the latest hook (v${guard.latest})`, level: "ok" });
@@ -10574,6 +10590,10 @@ function SettingsPanel({
10574
10590
  } else if (cur.kind === "alert-add-email") openAlertEditor("email");
10575
10591
  else if (cur.kind === "alert-add-tg") openAlertEditor("telegram");
10576
10592
  } else if (inp === "d" && cur.kind === "guard") {
10593
+ if (!guardHere) {
10594
+ setMsg({ text: "guard already removed on this device", level: "ok" });
10595
+ return;
10596
+ }
10577
10597
  const k = keyOf(cur);
10578
10598
  if (confirmDel !== k) {
10579
10599
  setConfirmDel(k);
@@ -10583,6 +10603,7 @@ function SettingsPanel({
10583
10603
  setConfirmDel(null);
10584
10604
  const res = uninstallGlobalQuiet();
10585
10605
  setMsg({ text: (res.ok ? "\u2713 " : "\u2717 ") + res.message, level: res.ok ? "ok" : "bad" });
10606
+ setGuardHere(isGuardInstalled());
10586
10607
  guardQ.reload();
10587
10608
  } else if (inp === "d" && (cur.kind === "wh" || cur.kind === "alert")) {
10588
10609
  const k = keyOf(cur);
@@ -10689,7 +10710,10 @@ function SettingsPanel({
10689
10710
  return /* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
10690
10711
  cursor(r),
10691
10712
  /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "guard".padEnd(11) }),
10692
- guard ? /* @__PURE__ */ jsxs7(Fragment4, { children: [
10713
+ !guardHere ? /* @__PURE__ */ jsxs7(Fragment4, { children: [
10714
+ /* @__PURE__ */ jsx7(Text7, { color: theme.bad, bold: true, children: "removed" }),
10715
+ /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: " \u2014 not installed on this device \xB7 new Claude Code sessions are unguarded" })
10716
+ ] }) : guard ? /* @__PURE__ */ jsxs7(Fragment4, { children: [
10693
10717
  /* @__PURE__ */ jsx7(Text7, { color: guard.up_to_date ? theme.ok : theme.warn, children: `v${guard.installed ?? "?"}` }),
10694
10718
  /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: guard.up_to_date ? " (latest)" : ` \u2192 v${guard.latest} available \xB7 enter update` }),
10695
10719
  /* @__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` })
package/dist/tui/index.js CHANGED
@@ -3215,20 +3215,31 @@ function clearGuardUpdateCheck() {
3215
3215
  return false;
3216
3216
  }
3217
3217
  }
3218
+ function isGuardInstalled() {
3219
+ try {
3220
+ const p = globalPaths();
3221
+ if (!existsSync2(p.settingsPath)) return false;
3222
+ const s = JSON.parse(readFileSync4(p.settingsPath, "utf-8"));
3223
+ return !!s.hooks && JSON.stringify(s.hooks).includes(".solongate");
3224
+ } catch {
3225
+ return false;
3226
+ }
3227
+ }
3218
3228
  function uninstallGlobalQuiet() {
3219
3229
  try {
3220
3230
  const p = globalPaths();
3221
3231
  unlockProtected();
3222
3232
  removeClaudeShim();
3233
+ const applies = "applies to NEW Claude Code sessions \u2014 a session already running keeps its loaded hooks until it ends";
3223
3234
  if (existsSync2(p.backupPath)) {
3224
3235
  writeFileSync5(p.settingsPath, readFileSync4(p.backupPath, "utf-8"));
3225
- return { ok: true, message: "guard removed \u2014 restored the pre-install settings (restart Claude Code)" };
3236
+ return { ok: true, message: `guard removed \u2014 restored the pre-install settings \xB7 ${applies}` };
3226
3237
  }
3227
3238
  if (existsSync2(p.settingsPath)) {
3228
3239
  const s = JSON.parse(readFileSync4(p.settingsPath, "utf-8"));
3229
3240
  delete s.hooks;
3230
3241
  writeFileSync5(p.settingsPath, JSON.stringify(s, null, 2) + "\n");
3231
- return { ok: true, message: "guard removed \u2014 SolonGate hooks cleared (restart Claude Code)" };
3242
+ return { ok: true, message: `guard removed \u2014 hooks cleared \xB7 ${applies}` };
3232
3243
  }
3233
3244
  return { ok: true, message: "nothing to remove \u2014 no global Claude Code settings found" };
3234
3245
  } catch (e) {
@@ -3385,6 +3396,7 @@ function SettingsPanel({
3385
3396
  const [tick, setTick] = useState7(0);
3386
3397
  const abort = useRef3(false);
3387
3398
  const refreshAccounts = () => setAccounts(listAccounts());
3399
+ const [guardHere, setGuardHere] = useState7(() => isGuardInstalled());
3388
3400
  const locked = accounts.length === 0;
3389
3401
  const [srv, setSrv] = useState7(() => logsServerStatus());
3390
3402
  useEffect6(() => {
@@ -3529,6 +3541,10 @@ function SettingsPanel({
3529
3541
  } else if (r.kind === "acct-add") {
3530
3542
  beginLogin();
3531
3543
  } else if (r.kind === "guard") {
3544
+ if (!guardHere) {
3545
+ setMsg({ text: "guard is removed on this device \u2014 log in again (Accounts \u2192 + add) to reinstall it", level: "bad" });
3546
+ return;
3547
+ }
3532
3548
  if (!guard) return;
3533
3549
  if (guard.up_to_date) {
3534
3550
  setMsg({ text: `guard already on the latest hook (v${guard.latest})`, level: "ok" });
@@ -3687,6 +3703,10 @@ function SettingsPanel({
3687
3703
  } else if (cur.kind === "alert-add-email") openAlertEditor("email");
3688
3704
  else if (cur.kind === "alert-add-tg") openAlertEditor("telegram");
3689
3705
  } else if (inp === "d" && cur.kind === "guard") {
3706
+ if (!guardHere) {
3707
+ setMsg({ text: "guard already removed on this device", level: "ok" });
3708
+ return;
3709
+ }
3690
3710
  const k = keyOf(cur);
3691
3711
  if (confirmDel !== k) {
3692
3712
  setConfirmDel(k);
@@ -3696,6 +3716,7 @@ function SettingsPanel({
3696
3716
  setConfirmDel(null);
3697
3717
  const res = uninstallGlobalQuiet();
3698
3718
  setMsg({ text: (res.ok ? "\u2713 " : "\u2717 ") + res.message, level: res.ok ? "ok" : "bad" });
3719
+ setGuardHere(isGuardInstalled());
3699
3720
  guardQ.reload();
3700
3721
  } else if (inp === "d" && (cur.kind === "wh" || cur.kind === "alert")) {
3701
3722
  const k = keyOf(cur);
@@ -3802,7 +3823,10 @@ function SettingsPanel({
3802
3823
  return /* @__PURE__ */ jsxs7(Text7, { wrap: "truncate", children: [
3803
3824
  cursor(r),
3804
3825
  /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: "guard".padEnd(11) }),
3805
- guard ? /* @__PURE__ */ jsxs7(Fragment4, { children: [
3826
+ !guardHere ? /* @__PURE__ */ jsxs7(Fragment4, { children: [
3827
+ /* @__PURE__ */ jsx7(Text7, { color: theme.bad, bold: true, children: "removed" }),
3828
+ /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: " \u2014 not installed on this device \xB7 new Claude Code sessions are unguarded" })
3829
+ ] }) : guard ? /* @__PURE__ */ jsxs7(Fragment4, { children: [
3806
3830
  /* @__PURE__ */ jsx7(Text7, { color: guard.up_to_date ? theme.ok : theme.warn, children: `v${guard.installed ?? "?"}` }),
3807
3831
  /* @__PURE__ */ jsx7(Text7, { color: theme.dim, children: guard.up_to_date ? " (latest)" : ` \u2192 v${guard.latest} available \xB7 enter update` }),
3808
3832
  /* @__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` })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solongate/proxy",
3
- "version": "0.81.78",
3
+ "version": "0.81.79",
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": {