@solongate/proxy 0.81.45 → 0.81.47

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.
@@ -0,0 +1,12 @@
1
+ export interface Me {
2
+ user?: {
3
+ email?: string;
4
+ name?: string;
5
+ } | null;
6
+ project?: {
7
+ id?: string;
8
+ name?: string;
9
+ slug?: string;
10
+ } | null;
11
+ }
12
+ export declare function me(): Promise<Me>;
@@ -5,6 +5,7 @@
5
5
  export * from './client.js';
6
6
  export * from './types.js';
7
7
  export * from './device-login.js';
8
+ import * as auth from './auth.js';
8
9
  import * as policies from './policies.js';
9
10
  import * as settings from './settings.js';
10
11
  import * as stats from './stats.js';
@@ -13,6 +14,7 @@ import * as agents from './agents.js';
13
14
  import * as keys from './keys.js';
14
15
  import * as mcp from './mcp.js';
15
16
  export declare const api: {
17
+ auth: typeof auth;
16
18
  policies: typeof policies;
17
19
  settings: typeof settings;
18
20
  stats: typeof stats;
@@ -142,6 +142,15 @@ async function request(method, path, opts = {}) {
142
142
  // src/api-client/device-login.ts
143
143
  import { spawn } from "child_process";
144
144
 
145
+ // src/api-client/auth.ts
146
+ var auth_exports = {};
147
+ __export(auth_exports, {
148
+ me: () => me
149
+ });
150
+ function me() {
151
+ return request("GET", "/auth/me");
152
+ }
153
+
145
154
  // src/api-client/policies.ts
146
155
  var policies_exports = {};
147
156
  __export(policies_exports, {
@@ -364,7 +373,7 @@ function list4() {
364
373
  }
365
374
 
366
375
  // src/api-client/index.ts
367
- var api = { policies: policies_exports, settings: settings_exports, stats: stats_exports, audit: audit_exports, agents: agents_exports, keys: keys_exports, mcp: mcp_exports };
376
+ var api = { auth: auth_exports, policies: policies_exports, settings: settings_exports, stats: stats_exports, audit: audit_exports, agents: agents_exports, keys: keys_exports, mcp: mcp_exports };
368
377
 
369
378
  // src/cli-utils.ts
370
379
  var c = {
package/dist/index.js CHANGED
@@ -6554,15 +6554,151 @@ var init_cli_utils = __esm({
6554
6554
  }
6555
6555
  });
6556
6556
 
6557
- // src/tui/config.ts
6558
- import { readFileSync as readFileSync4 } from "fs";
6557
+ // src/self-update.ts
6558
+ var self_update_exports = {};
6559
+ __export(self_update_exports, {
6560
+ currentVersion: () => currentVersion,
6561
+ maybeSelfUpdate: () => maybeSelfUpdate
6562
+ });
6563
+ import { execFile, spawn } from "child_process";
6564
+ import { mkdirSync as mkdirSync3, openSync, readFileSync as readFileSync4, realpathSync, writeFileSync as writeFileSync3 } from "fs";
6559
6565
  import { homedir as homedir2 } from "os";
6560
- import { join as join4 } from "path";
6566
+ import { dirname, join as join4 } from "path";
6567
+ import { fileURLToPath } from "url";
6568
+ function readState() {
6569
+ try {
6570
+ const s = JSON.parse(readFileSync4(STATE_FILE, "utf-8"));
6571
+ return s && typeof s === "object" ? s : {};
6572
+ } catch {
6573
+ return {};
6574
+ }
6575
+ }
6576
+ function writeState(s) {
6577
+ try {
6578
+ mkdirSync3(join4(homedir2(), ".solongate"), { recursive: true });
6579
+ writeFileSync3(STATE_FILE, JSON.stringify(s));
6580
+ } catch {
6581
+ }
6582
+ }
6583
+ function currentVersion() {
6584
+ try {
6585
+ const pkg = JSON.parse(readFileSync4(join4(dirname(fileURLToPath(import.meta.url)), "..", "package.json"), "utf-8"));
6586
+ return pkg.version ?? "0.0.0";
6587
+ } catch {
6588
+ return "0.0.0";
6589
+ }
6590
+ }
6591
+ function newerThan(b, a) {
6592
+ const pa = a.split(".").map((n) => parseInt(n, 10) || 0);
6593
+ const pb = b.split(".").map((n) => parseInt(n, 10) || 0);
6594
+ for (let i = 0; i < 3; i++) {
6595
+ if ((pb[i] ?? 0) > (pa[i] ?? 0)) return true;
6596
+ if ((pb[i] ?? 0) < (pa[i] ?? 0)) return false;
6597
+ }
6598
+ return false;
6599
+ }
6600
+ async function fetchLatest() {
6601
+ try {
6602
+ const res = await fetch(`https://registry.npmjs.org/${PKG}/latest`, { signal: AbortSignal.timeout(2e3) });
6603
+ if (!res.ok) return null;
6604
+ const j = await res.json();
6605
+ return typeof j.version === "string" ? j.version : null;
6606
+ } catch {
6607
+ return null;
6608
+ }
6609
+ }
6610
+ function npmGlobalRoot() {
6611
+ return new Promise((resolve10) => {
6612
+ try {
6613
+ execFile("npm", ["root", "-g"], { timeout: 5e3, windowsHide: true, shell: process.platform === "win32" }, (err2, stdout) => {
6614
+ resolve10(err2 ? null : stdout.trim() || null);
6615
+ });
6616
+ } catch {
6617
+ resolve10(null);
6618
+ }
6619
+ });
6620
+ }
6621
+ async function isGlobalInstall() {
6622
+ try {
6623
+ const script = realpathSync(process.argv[1] ?? "");
6624
+ if (!script) return false;
6625
+ const root = await npmGlobalRoot();
6626
+ if (!root) return false;
6627
+ return script.startsWith(realpathSync(root));
6628
+ } catch {
6629
+ return false;
6630
+ }
6631
+ }
6632
+ function spawnGlobalInstall(version) {
6633
+ try {
6634
+ mkdirSync3(join4(homedir2(), ".solongate"), { recursive: true });
6635
+ const log6 = openSync(LOG_FILE, "a");
6636
+ const p = spawn("npm", ["install", "-g", `${PKG}@${version}`], {
6637
+ stdio: ["ignore", log6, log6],
6638
+ detached: true,
6639
+ windowsHide: true,
6640
+ shell: process.platform === "win32"
6641
+ });
6642
+ p.on("error", () => {
6643
+ });
6644
+ p.unref();
6645
+ return true;
6646
+ } catch {
6647
+ return false;
6648
+ }
6649
+ }
6650
+ function maybeSelfUpdate(notify = (l) => process.stderr.write(l + "\n")) {
6651
+ void (async () => {
6652
+ try {
6653
+ const state = readState();
6654
+ const now = Date.now();
6655
+ const current = currentVersion();
6656
+ let latest = state.latestSeen ?? null;
6657
+ if (now - (state.lastCheckAt ?? 0) >= CHECK_EVERY_MS) {
6658
+ latest = await fetchLatest();
6659
+ if (latest) writeState({ ...state, lastCheckAt: now, latestSeen: latest });
6660
+ else writeState({ ...state, lastCheckAt: now });
6661
+ }
6662
+ if (!latest || !newerThan(latest, current)) return;
6663
+ const attempts = readState().attempts ?? {};
6664
+ if (await isGlobalInstall()) {
6665
+ if (now - (attempts[latest] ?? 0) >= ATTEMPT_EVERY_MS) {
6666
+ writeState({ ...readState(), attempts: { [latest]: now } });
6667
+ if (spawnGlobalInstall(latest)) {
6668
+ notify(`${c.dim}\u2191 solongate v${latest} available (running v${current}) \u2014 updating in the background, next run uses it${c.reset}`);
6669
+ return;
6670
+ }
6671
+ } else {
6672
+ return;
6673
+ }
6674
+ }
6675
+ notify(`${c.dim}\u2191 solongate v${latest} available (running v${current}) \u2014 update: ${c.reset}${c.cyan}npm i -g ${PKG}@latest${c.reset}`);
6676
+ } catch {
6677
+ }
6678
+ })();
6679
+ }
6680
+ var PKG, CHECK_EVERY_MS, ATTEMPT_EVERY_MS, STATE_FILE, LOG_FILE;
6681
+ var init_self_update = __esm({
6682
+ "src/self-update.ts"() {
6683
+ "use strict";
6684
+ init_cli_utils();
6685
+ PKG = "@solongate/proxy";
6686
+ CHECK_EVERY_MS = 30 * 60 * 1e3;
6687
+ ATTEMPT_EVERY_MS = 6 * 60 * 60 * 1e3;
6688
+ STATE_FILE = join4(homedir2(), ".solongate", ".self-update.json");
6689
+ LOG_FILE = join4(homedir2(), ".solongate", "self-update.log");
6690
+ }
6691
+ });
6692
+
6693
+ // src/tui/config.ts
6694
+ import { readFileSync as readFileSync5 } from "fs";
6695
+ import { homedir as homedir3 } from "os";
6696
+ import { join as join5 } from "path";
6561
6697
  function loadConfig() {
6562
6698
  if (cached) return cached;
6563
6699
  const defaults = { notifications: true };
6564
6700
  try {
6565
- const raw = readFileSync4(join4(homedir2(), ".solongate", "tui-config.json"), "utf-8");
6701
+ const raw = readFileSync5(join5(homedir3(), ".solongate", "tui-config.json"), "utf-8");
6566
6702
  const j = JSON.parse(raw);
6567
6703
  cached = {
6568
6704
  notifications: j.notifications !== false,
@@ -6688,14 +6824,14 @@ var init_components = __esm({
6688
6824
  });
6689
6825
 
6690
6826
  // src/tui/local-log.ts
6691
- import { closeSync, openSync, readFileSync as readFileSync5, readSync, statSync, writeFileSync as writeFileSync3 } from "fs";
6692
- import { homedir as homedir3 } from "os";
6693
- import { join as join5 } from "path";
6827
+ import { closeSync, openSync as openSync2, readFileSync as readFileSync6, readSync, statSync, writeFileSync as writeFileSync4 } from "fs";
6828
+ import { homedir as homedir4 } from "os";
6829
+ import { join as join6 } from "path";
6694
6830
  function tailLines(file, maxBytes = 131072) {
6695
6831
  try {
6696
6832
  const size = statSync(file).size;
6697
6833
  const start = Math.max(0, size - maxBytes);
6698
- const fd = openSync(file, "r");
6834
+ const fd = openSync2(file, "r");
6699
6835
  const buf = Buffer.alloc(size - start);
6700
6836
  readSync(fd, buf, 0, buf.length, start);
6701
6837
  closeSync(fd);
@@ -6708,7 +6844,7 @@ function tailLines(file, maxBytes = 131072) {
6708
6844
  }
6709
6845
  function deleteLocalEntry(at, tool, session) {
6710
6846
  try {
6711
- const lines = readFileSync5(LOCAL_LOG, "utf-8").split("\n");
6847
+ const lines = readFileSync6(LOCAL_LOG, "utf-8").split("\n");
6712
6848
  let removed = 0;
6713
6849
  const kept = lines.filter((line) => {
6714
6850
  if (!line.trim()) return false;
@@ -6724,7 +6860,7 @@ function deleteLocalEntry(at, tool, session) {
6724
6860
  }
6725
6861
  return true;
6726
6862
  });
6727
- if (removed) writeFileSync3(LOCAL_LOG, kept.length ? kept.join("\n") + "\n" : "");
6863
+ if (removed) writeFileSync4(LOCAL_LOG, kept.length ? kept.join("\n") + "\n" : "");
6728
6864
  return removed;
6729
6865
  } catch {
6730
6866
  return 0;
@@ -6732,8 +6868,8 @@ function deleteLocalEntry(at, tool, session) {
6732
6868
  }
6733
6869
  function clearLocalLog() {
6734
6870
  try {
6735
- const n = readFileSync5(LOCAL_LOG, "utf-8").split("\n").filter(Boolean).length;
6736
- writeFileSync3(LOCAL_LOG, "");
6871
+ const n = readFileSync6(LOCAL_LOG, "utf-8").split("\n").filter(Boolean).length;
6872
+ writeFileSync4(LOCAL_LOG, "");
6737
6873
  return n;
6738
6874
  } catch {
6739
6875
  return 0;
@@ -6764,20 +6900,20 @@ var LOCAL_LOG, DLP_REASON, RL_REASON;
6764
6900
  var init_local_log = __esm({
6765
6901
  "src/tui/local-log.ts"() {
6766
6902
  "use strict";
6767
- LOCAL_LOG = join5(homedir3(), ".solongate", "local-logs", "solongate-audit.jsonl");
6903
+ LOCAL_LOG = join6(homedir4(), ".solongate", "local-logs", "solongate-audit.jsonl");
6768
6904
  DLP_REASON = /security layer \(dlp\)/i;
6769
6905
  RL_REASON = /security layer \(rate limit\)|rate[- ]?limit(?:ed)?\b.*exceed|exceeded \d+ calls/i;
6770
6906
  }
6771
6907
  });
6772
6908
 
6773
6909
  // src/api-client/client.ts
6774
- import { readFileSync as readFileSync6, writeFileSync as writeFileSync4, mkdirSync as mkdirSync3, existsSync as existsSync3 } from "fs";
6775
- import { resolve as resolve3, join as join6 } from "path";
6776
- import { homedir as homedir4 } from "os";
6910
+ import { readFileSync as readFileSync7, writeFileSync as writeFileSync5, mkdirSync as mkdirSync4, existsSync as existsSync3 } from "fs";
6911
+ import { resolve as resolve3, join as join7 } from "path";
6912
+ import { homedir as homedir5 } from "os";
6777
6913
  function listAccounts() {
6778
6914
  let list6 = [];
6779
6915
  try {
6780
- const raw = JSON.parse(readFileSync6(accountsFile(), "utf-8"));
6916
+ const raw = JSON.parse(readFileSync7(accountsFile(), "utf-8"));
6781
6917
  if (Array.isArray(raw)) list6 = raw.filter((a) => a && typeof a.apiKey === "string");
6782
6918
  } catch {
6783
6919
  }
@@ -6791,7 +6927,7 @@ function saveAccount(acc) {
6791
6927
  try {
6792
6928
  const list6 = (() => {
6793
6929
  try {
6794
- const raw = JSON.parse(readFileSync6(accountsFile(), "utf-8"));
6930
+ const raw = JSON.parse(readFileSync7(accountsFile(), "utf-8"));
6795
6931
  return Array.isArray(raw) ? raw.filter((a) => a && a.apiKey) : [];
6796
6932
  } catch {
6797
6933
  return [];
@@ -6799,8 +6935,8 @@ function saveAccount(acc) {
6799
6935
  })();
6800
6936
  const next = list6.filter((a) => a.apiKey !== acc.apiKey);
6801
6937
  next.unshift({ ...acc, addedAt: acc.addedAt ?? Date.now() });
6802
- mkdirSync3(join6(homedir4(), ".solongate"), { recursive: true });
6803
- writeFileSync4(accountsFile(), JSON.stringify(next, null, 2));
6938
+ mkdirSync4(join7(homedir5(), ".solongate"), { recursive: true });
6939
+ writeFileSync5(accountsFile(), JSON.stringify(next, null, 2));
6804
6940
  } catch {
6805
6941
  }
6806
6942
  }
@@ -6813,15 +6949,15 @@ function isActiveAccount(apiKey) {
6813
6949
  }
6814
6950
  function setActiveAccount(creds) {
6815
6951
  try {
6816
- const dir = join6(homedir4(), ".solongate");
6817
- mkdirSync3(dir, { recursive: true });
6818
- const p = join6(dir, ["cloud", "guard.json"].join("-"));
6952
+ const dir = join7(homedir5(), ".solongate");
6953
+ mkdirSync4(dir, { recursive: true });
6954
+ const p = join7(dir, ["cloud", "guard.json"].join("-"));
6819
6955
  let existing = {};
6820
6956
  try {
6821
- existing = JSON.parse(readFileSync6(p, "utf-8"));
6957
+ existing = JSON.parse(readFileSync7(p, "utf-8"));
6822
6958
  } catch {
6823
6959
  }
6824
- writeFileSync4(p, JSON.stringify({ ...existing, apiKey: creds.apiKey, apiUrl: creds.apiUrl }, null, 2));
6960
+ writeFileSync5(p, JSON.stringify({ ...existing, apiKey: creds.apiKey, apiUrl: creds.apiUrl }, null, 2));
6825
6961
  cached2 = null;
6826
6962
  return true;
6827
6963
  } catch {
@@ -6830,9 +6966,9 @@ function setActiveAccount(creds) {
6830
6966
  }
6831
6967
  function loginCredentialFile() {
6832
6968
  try {
6833
- const p = join6(homedir4(), ".solongate", "cloud-guard.json");
6969
+ const p = join7(homedir5(), ".solongate", "cloud-guard.json");
6834
6970
  if (!existsSync3(p)) return {};
6835
- const c2 = JSON.parse(readFileSync6(p, "utf-8"));
6971
+ const c2 = JSON.parse(readFileSync7(p, "utf-8"));
6836
6972
  return c2 && typeof c2 === "object" ? c2 : {};
6837
6973
  } catch {
6838
6974
  return {};
@@ -6842,7 +6978,7 @@ function dotenvApiKey() {
6842
6978
  try {
6843
6979
  const envPath = resolve3(".env");
6844
6980
  if (!existsSync3(envPath)) return void 0;
6845
- for (const line of readFileSync6(envPath, "utf-8").split("\n")) {
6981
+ for (const line of readFileSync7(envPath, "utf-8").split("\n")) {
6846
6982
  const trimmed = line.trim();
6847
6983
  if (!trimmed || trimmed.startsWith("#")) continue;
6848
6984
  const eq = trimmed.indexOf("=");
@@ -6944,7 +7080,7 @@ var init_client = __esm({
6944
7080
  "src/api-client/client.ts"() {
6945
7081
  "use strict";
6946
7082
  DEFAULT_API_URL2 = "https://api.solongate.com";
6947
- accountsFile = () => join6(homedir4(), ".solongate", "accounts.json");
7083
+ accountsFile = () => join7(homedir5(), ".solongate", "accounts.json");
6948
7084
  viewOverride = null;
6949
7085
  ApiError = class extends Error {
6950
7086
  status;
@@ -6974,12 +7110,12 @@ var init_types = __esm({
6974
7110
  });
6975
7111
 
6976
7112
  // src/api-client/device-login.ts
6977
- import { spawn } from "child_process";
7113
+ import { spawn as spawn2 } from "child_process";
6978
7114
  function openBrowser(url) {
6979
7115
  try {
6980
7116
  const cmd = process.platform === "win32" ? "cmd" : process.platform === "darwin" ? "open" : "xdg-open";
6981
7117
  const args = process.platform === "win32" ? ["/c", "start", '""', url] : [url];
6982
- const child = spawn(cmd, args, { stdio: "ignore", detached: true });
7118
+ const child = spawn2(cmd, args, { stdio: "ignore", detached: true });
6983
7119
  child.on("error", () => {
6984
7120
  });
6985
7121
  child.unref();
@@ -7021,6 +7157,21 @@ var init_device_login = __esm({
7021
7157
  }
7022
7158
  });
7023
7159
 
7160
+ // src/api-client/auth.ts
7161
+ var auth_exports = {};
7162
+ __export(auth_exports, {
7163
+ me: () => me
7164
+ });
7165
+ function me() {
7166
+ return request("GET", "/auth/me");
7167
+ }
7168
+ var init_auth = __esm({
7169
+ "src/api-client/auth.ts"() {
7170
+ "use strict";
7171
+ init_client();
7172
+ }
7173
+ });
7174
+
7024
7175
  // src/api-client/policies.ts
7025
7176
  var policies_exports = {};
7026
7177
  __export(policies_exports, {
@@ -7292,6 +7443,7 @@ var init_api_client = __esm({
7292
7443
  init_client();
7293
7444
  init_types();
7294
7445
  init_device_login();
7446
+ init_auth();
7295
7447
  init_policies();
7296
7448
  init_settings();
7297
7449
  init_stats();
@@ -7299,29 +7451,29 @@ var init_api_client = __esm({
7299
7451
  init_agents();
7300
7452
  init_keys();
7301
7453
  init_mcp();
7302
- api = { policies: policies_exports, settings: settings_exports, stats: stats_exports, audit: audit_exports, agents: agents_exports, keys: keys_exports, mcp: mcp_exports };
7454
+ api = { auth: auth_exports, policies: policies_exports, settings: settings_exports, stats: stats_exports, audit: audit_exports, agents: agents_exports, keys: keys_exports, mcp: mcp_exports };
7303
7455
  }
7304
7456
  });
7305
7457
 
7306
7458
  // src/tui/notify.ts
7307
- import { spawn as spawn2 } from "child_process";
7459
+ import { spawn as spawn3 } from "child_process";
7308
7460
  function desktopNotify(title, msg) {
7309
7461
  try {
7310
7462
  if (process.platform === "linux") {
7311
- const p = spawn2("notify-send", ["-a", "SolonGate", title, msg], { stdio: "ignore", detached: true });
7463
+ const p = spawn3("notify-send", ["-a", "SolonGate", title, msg], { stdio: "ignore", detached: true });
7312
7464
  p.on("error", () => {
7313
7465
  });
7314
7466
  p.unref();
7315
7467
  } else if (process.platform === "win32") {
7316
7468
  const q = (s) => s.replace(/'/g, "''");
7317
7469
  const ps = `Add-Type -AssemblyName System.Windows.Forms;Add-Type -AssemblyName System.Drawing;$n=New-Object System.Windows.Forms.NotifyIcon;$n.Icon=[System.Drawing.SystemIcons]::Information;$n.Visible=$true;$n.ShowBalloonTip(6000,'${q(title)}','${q(msg)}',[System.Windows.Forms.ToolTipIcon]::Warning);Start-Sleep -Milliseconds 6500;$n.Dispose()`;
7318
- const p = spawn2("powershell", ["-NoProfile", "-NonInteractive", "-Command", ps], { stdio: "ignore", detached: true, windowsHide: true });
7470
+ const p = spawn3("powershell", ["-NoProfile", "-NonInteractive", "-Command", ps], { stdio: "ignore", detached: true, windowsHide: true });
7319
7471
  p.on("error", () => {
7320
7472
  });
7321
7473
  p.unref();
7322
7474
  } else if (process.platform === "darwin") {
7323
7475
  const esc = (s) => s.replace(/"/g, '\\"');
7324
- const p = spawn2("osascript", ["-e", `display notification "${esc(msg)}" with title "${esc(title)}"`], { stdio: "ignore", detached: true });
7476
+ const p = spawn3("osascript", ["-e", `display notification "${esc(msg)}" with title "${esc(title)}"`], { stdio: "ignore", detached: true });
7325
7477
  p.on("error", () => {
7326
7478
  });
7327
7479
  p.unref();
@@ -7407,9 +7559,9 @@ var init_hooks = __esm({
7407
7559
  // src/tui/panels/Live.tsx
7408
7560
  import { Box as Box2, Text as Text2, useInput } from "ink";
7409
7561
  import TextInput from "ink-text-input";
7410
- import { mkdirSync as mkdirSync4, writeFileSync as writeFileSync5 } from "fs";
7411
- import { homedir as homedir5 } from "os";
7412
- import { join as join7 } from "path";
7562
+ import { mkdirSync as mkdirSync5, writeFileSync as writeFileSync6 } from "fs";
7563
+ import { homedir as homedir6 } from "os";
7564
+ import { join as join8 } from "path";
7413
7565
  import { useCallback as useCallback2, useEffect as useEffect2, useRef as useRef2, useState as useState2 } from "react";
7414
7566
  import { Fragment as Fragment2, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
7415
7567
  function extractTarget(detail) {
@@ -8000,10 +8152,10 @@ function LivePanel({ active: active2 }) {
8000
8152
  else if (input === "x") toggleSignal("dlp");
8001
8153
  else if (input === "r") toggleSignal("ratelimit");
8002
8154
  else if (input === "e") {
8003
- const file = join7(homedir5(), ".solongate", "live-export.jsonl");
8155
+ const file = join8(homedir6(), ".solongate", "live-export.jsonl");
8004
8156
  try {
8005
- mkdirSync4(join7(homedir5(), ".solongate"), { recursive: true });
8006
- writeFileSync5(file, visibleDesc.map((x) => JSON.stringify(x)).join("\n") + "\n");
8157
+ mkdirSync5(join8(homedir6(), ".solongate"), { recursive: true });
8158
+ writeFileSync6(file, visibleDesc.map((x) => JSON.stringify(x)).join("\n") + "\n");
8007
8159
  setActionMsg({ text: `\u2713 exported ${visibleDesc.length} lines \u2192 ${file}`, level: "ok", until: Date.now() + 6e3 });
8008
8160
  } catch (err2) {
8009
8161
  setActionMsg({ text: "\u2717 export failed: " + (err2 instanceof Error ? err2.message : String(err2)), level: "bad", until: Date.now() + 6e3 });
@@ -8413,7 +8565,7 @@ var init_Live = __esm({
8413
8565
  SPIN = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
8414
8566
  BG = "#12234f";
8415
8567
  DIM_FLOOR = "#233457";
8416
- RING = join7(process.cwd(), ".solongate", ".eval-ring.jsonl");
8568
+ RING = join8(process.cwd(), ".solongate", ".eval-ring.jsonl");
8417
8569
  hhmmss = (ts) => {
8418
8570
  const d = new Date(ts);
8419
8571
  return Number.isNaN(d.getTime()) ? "--:--:--" : d.toTimeString().slice(0, 8);
@@ -9103,9 +9255,9 @@ var init_Dlp = __esm({
9103
9255
  // src/tui/panels/Audit.tsx
9104
9256
  import { Box as Box6, Text as Text6, useInput as useInput5 } from "ink";
9105
9257
  import TextInput4 from "ink-text-input";
9106
- import { mkdirSync as mkdirSync5, writeFileSync as writeFileSync6 } from "fs";
9107
- import { homedir as homedir6 } from "os";
9108
- import { join as join8 } from "path";
9258
+ import { mkdirSync as mkdirSync6, writeFileSync as writeFileSync7 } from "fs";
9259
+ import { homedir as homedir7 } from "os";
9260
+ import { join as join9 } from "path";
9109
9261
  import { useState as useState6 } from "react";
9110
9262
  import { Fragment as Fragment4, jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
9111
9263
  function loadLocalRows() {
@@ -9259,16 +9411,16 @@ function AuditPanel({ active: active2, focused }) {
9259
9411
  const doExport = (kind) => {
9260
9412
  setMsg({ text: "exporting\u2026", level: "ok" });
9261
9413
  const run12 = async () => {
9262
- const dir = join8(homedir6(), ".solongate");
9263
- const file = join8(dir, `audit-export-${source}.jsonl`);
9414
+ const dir = join9(homedir7(), ".solongate");
9415
+ const file = join9(dir, `audit-export-${source}.jsonl`);
9264
9416
  let rows2;
9265
9417
  if (kind === "page") rows2 = pageRows;
9266
9418
  else if (source === "cloud") {
9267
9419
  const r = await api.audit.list({ ...query, limit: 1e4, offset: 0 });
9268
9420
  rows2 = r.entries.map(cloudRow).sort((a, b) => b.at - a.at);
9269
9421
  } else rows2 = localFiltered;
9270
- mkdirSync5(dir, { recursive: true });
9271
- writeFileSync6(file, rows2.map((x) => JSON.stringify(x)).join("\n") + (rows2.length ? "\n" : ""));
9422
+ mkdirSync6(dir, { recursive: true });
9423
+ writeFileSync7(file, rows2.map((x) => JSON.stringify(x)).join("\n") + (rows2.length ? "\n" : ""));
9272
9424
  return { n: rows2.length, file };
9273
9425
  };
9274
9426
  run12().then(({ n, file }) => setMsg({ text: `\u2713 exported ${n} rows \u2192 ${file}`, level: "ok" })).catch((e) => setMsg({ text: "\u2717 export failed: " + (e instanceof Error ? e.message : String(e)), level: "bad" }));
@@ -10041,7 +10193,7 @@ function AccountsPanel({
10041
10193
  if (a) {
10042
10194
  setViewCredentials({ apiKey: a.apiKey, apiUrl: a.apiUrl });
10043
10195
  onView?.(a);
10044
- setMsg({ text: `viewing ${a.project || a.user || a.apiKey.slice(0, 8)}`, level: "ok" });
10196
+ setMsg({ text: `viewing ${a.project || a.user || "account \u2026" + a.apiKey.slice(-4)}`, level: "ok" });
10045
10197
  }
10046
10198
  } else if (input === "m") {
10047
10199
  const a = accounts[sel];
@@ -10090,7 +10242,7 @@ function AccountsPanel({
10090
10242
  const isActive = isActiveAccount(a.apiKey);
10091
10243
  return /* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", backgroundColor: isSel ? "#333333" : void 0, bold: isSel, children: [
10092
10244
  /* @__PURE__ */ jsx8(Text8, { color: isSel ? theme.accentBright : theme.dim, children: isSel ? "\u25B8 " : " " }),
10093
- /* @__PURE__ */ jsx8(Text8, { color: theme.accent, children: truncate2(a.project || a.user || a.apiKey.slice(0, 12), 30).padEnd(31) }),
10245
+ /* @__PURE__ */ jsx8(Text8, { color: theme.accent, children: truncate2(a.project || a.user || "account \u2026" + a.apiKey.slice(-4), 30).padEnd(31) }),
10094
10246
  isView ? /* @__PURE__ */ jsx8(Text8, { color: theme.ok, children: "\u25CF viewing " }) : /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: " " }),
10095
10247
  isActive ? /* @__PURE__ */ jsx8(Text8, { color: theme.warn, children: "ACTIVE " }) : /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: " " }),
10096
10248
  /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: a.user && a.project ? truncate2(a.user, 24) : "" })
@@ -10112,7 +10264,7 @@ var init_Accounts = __esm({
10112
10264
 
10113
10265
  // src/tui/App.tsx
10114
10266
  import { Box as Box9, Text as Text9, useApp, useInput as useInput8 } from "ink";
10115
- import { useState as useState9 } from "react";
10267
+ import { useEffect as useEffect7, useState as useState9 } from "react";
10116
10268
  import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
10117
10269
  function LiveHint() {
10118
10270
  return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", children: [
@@ -10149,7 +10301,22 @@ function App() {
10149
10301
  const [help, setHelp] = useState9(false);
10150
10302
  const acctIdx = Math.max(0, accounts.findIndex((a) => a.apiKey === viewKey));
10151
10303
  const cur = accounts[acctIdx];
10152
- const acctLabel = cur ? cur.project || cur.user || cur.apiKey.slice(0, 8) : "not logged in";
10304
+ const acctLabel = cur ? cur.project || cur.user || `account \u2026${cur.apiKey.slice(-4)}` : "not logged in";
10305
+ useEffect7(() => {
10306
+ if (!cur || cur.project || cur.user) return;
10307
+ let alive = true;
10308
+ api.auth.me().then((r) => {
10309
+ const project = r.project?.name || void 0;
10310
+ const user = r.user?.name || r.user?.email || void 0;
10311
+ if (!alive || !project && !user) return;
10312
+ saveAccount({ ...cur, project, user });
10313
+ setAccounts(listAccounts());
10314
+ }).catch(() => {
10315
+ });
10316
+ return () => {
10317
+ alive = false;
10318
+ };
10319
+ }, [cur]);
10153
10320
  const viewAccount = (a) => {
10154
10321
  setViewCredentials({ apiKey: a.apiKey, apiUrl: a.apiUrl });
10155
10322
  setAccounts(listAccounts());
@@ -10243,6 +10410,7 @@ var init_App = __esm({
10243
10410
  init_Accounts();
10244
10411
  init_hooks();
10245
10412
  init_client();
10413
+ init_api_client();
10246
10414
  SECTIONS = [
10247
10415
  { label: "Live", Panel: LiveHint },
10248
10416
  { label: "Policies", Panel: PoliciesPanel },
@@ -10271,9 +10439,9 @@ var tui_exports = {};
10271
10439
  __export(tui_exports, {
10272
10440
  launchTui: () => launchTui
10273
10441
  });
10274
- import { appendFileSync as appendFileSync2, mkdirSync as mkdirSync6 } from "fs";
10275
- import { homedir as homedir7 } from "os";
10276
- import { join as join9 } from "path";
10442
+ import { appendFileSync as appendFileSync2, mkdirSync as mkdirSync7 } from "fs";
10443
+ import { homedir as homedir8 } from "os";
10444
+ import { join as join10 } from "path";
10277
10445
  import { render } from "ink";
10278
10446
  import { jsx as jsx10 } from "react/jsx-runtime";
10279
10447
  async function launchTui() {
@@ -10284,11 +10452,11 @@ async function launchTui() {
10284
10452
  return;
10285
10453
  }
10286
10454
  process.stdout.write("\x1B[?1049h\x1B[H");
10287
- const debugLog = join9(homedir7(), ".solongate", "dataroom-debug.log");
10455
+ const debugLog = join10(homedir8(), ".solongate", "dataroom-debug.log");
10288
10456
  const saved = { log: console.log, warn: console.warn, error: console.error, info: console.info, debug: console.debug };
10289
10457
  const toFile = (level) => (...args) => {
10290
10458
  try {
10291
- mkdirSync6(join9(homedir7(), ".solongate"), { recursive: true });
10459
+ mkdirSync7(join10(homedir8(), ".solongate"), { recursive: true });
10292
10460
  appendFileSync2(debugLog, `${(/* @__PURE__ */ new Date()).toISOString()} [${level}] ${args.map((a) => typeof a === "string" ? a : JSON.stringify(a)).join(" ")}
10293
10461
  `);
10294
10462
  } catch {
@@ -10412,7 +10580,7 @@ var init_args = __esm({
10412
10580
  });
10413
10581
 
10414
10582
  // src/commands/policy.ts
10415
- import { readFileSync as readFileSync7 } from "fs";
10583
+ import { readFileSync as readFileSync8 } from "fs";
10416
10584
  async function run(argv) {
10417
10585
  const { positionals, flags } = parse(argv);
10418
10586
  const sub = positionals[0];
@@ -10587,7 +10755,7 @@ function printRules(rules) {
10587
10755
  }
10588
10756
  async function resolveRules(target) {
10589
10757
  if (target.endsWith(".json")) {
10590
- const parsed = JSON.parse(readFileSync7(target, "utf-8"));
10758
+ const parsed = JSON.parse(readFileSync8(target, "utf-8"));
10591
10759
  return parsed.rules ?? [];
10592
10760
  }
10593
10761
  const p = await api.policies.get(target);
@@ -11003,8 +11171,8 @@ var init_agents2 = __esm({
11003
11171
 
11004
11172
  // src/commands/doctor.ts
11005
11173
  import { existsSync as existsSync4, statSync as statSync2 } from "fs";
11006
- import { homedir as homedir8 } from "os";
11007
- import { join as join10 } from "path";
11174
+ import { homedir as homedir9 } from "os";
11175
+ import { join as join11 } from "path";
11008
11176
  async function run6(argv) {
11009
11177
  const { flags } = parse(argv);
11010
11178
  const json = flagBool(flags, "json");
@@ -11064,19 +11232,19 @@ var init_doctor = __esm({
11064
11232
  init_api_client();
11065
11233
  init_format();
11066
11234
  init_args();
11067
- LOCAL_LOG2 = join10(homedir8(), ".solongate", "local-logs", "solongate-audit.jsonl");
11235
+ LOCAL_LOG2 = join11(homedir9(), ".solongate", "local-logs", "solongate-audit.jsonl");
11068
11236
  }
11069
11237
  });
11070
11238
 
11071
11239
  // src/commands/watch.ts
11072
- import { closeSync as closeSync2, existsSync as existsSync5, openSync as openSync2, readSync as readSync2, statSync as statSync3 } from "fs";
11073
- import { homedir as homedir9 } from "os";
11074
- import { join as join11 } from "path";
11240
+ import { closeSync as closeSync2, existsSync as existsSync5, openSync as openSync3, readSync as readSync2, statSync as statSync3 } from "fs";
11241
+ import { homedir as homedir10 } from "os";
11242
+ import { join as join12 } from "path";
11075
11243
  function tailLocal(file, maxBytes = 131072) {
11076
11244
  try {
11077
11245
  const size = statSync3(file).size;
11078
11246
  const start = Math.max(0, size - maxBytes);
11079
- const fd = openSync2(file, "r");
11247
+ const fd = openSync3(file, "r");
11080
11248
  const buf = Buffer.alloc(size - start);
11081
11249
  readSync2(fd, buf, 0, buf.length, start);
11082
11250
  closeSync2(fd);
@@ -11178,7 +11346,7 @@ var init_watch = __esm({
11178
11346
  init_cli_utils();
11179
11347
  init_args();
11180
11348
  init_format();
11181
- LOCAL_LOG3 = join11(homedir9(), ".solongate", "local-logs", "solongate-audit.jsonl");
11349
+ LOCAL_LOG3 = join12(homedir10(), ".solongate", "local-logs", "solongate-audit.jsonl");
11182
11350
  trunc = (s, n) => s.length <= n ? s : s.slice(0, n - 1) + "\u2026";
11183
11351
  time = (ms) => new Date(ms).toTimeString().slice(0, 8);
11184
11352
  }
@@ -11469,10 +11637,10 @@ var init_commands = __esm({
11469
11637
  });
11470
11638
 
11471
11639
  // src/global-install.ts
11472
- import { readFileSync as readFileSync8, writeFileSync as writeFileSync7, existsSync as existsSync6, mkdirSync as mkdirSync7 } from "fs";
11473
- import { resolve as resolve4, join as join12, dirname } from "path";
11474
- import { homedir as homedir10 } from "os";
11475
- import { fileURLToPath } from "url";
11640
+ import { readFileSync as readFileSync9, writeFileSync as writeFileSync8, existsSync as existsSync6, mkdirSync as mkdirSync8 } from "fs";
11641
+ import { resolve as resolve4, join as join13, dirname as dirname2 } from "path";
11642
+ import { homedir as homedir11 } from "os";
11643
+ import { fileURLToPath as fileURLToPath2 } from "url";
11476
11644
  import { createInterface } from "readline";
11477
11645
  import { execFileSync as execFileSync2 } from "child_process";
11478
11646
  function lockFile(file) {
@@ -11534,10 +11702,10 @@ function unlockFile(file) {
11534
11702
  function protectedTargets() {
11535
11703
  const p = globalPaths();
11536
11704
  return [
11537
- join12(p.hooksDir, "guard.mjs"),
11538
- join12(p.hooksDir, "audit.mjs"),
11539
- join12(p.hooksDir, "stop.mjs"),
11540
- join12(p.hooksDir, "shield.mjs"),
11705
+ join13(p.hooksDir, "guard.mjs"),
11706
+ join13(p.hooksDir, "audit.mjs"),
11707
+ join13(p.hooksDir, "stop.mjs"),
11708
+ join13(p.hooksDir, "shield.mjs"),
11541
11709
  p.configPath,
11542
11710
  p.settingsPath
11543
11711
  ];
@@ -11549,26 +11717,26 @@ function unlockProtected() {
11549
11717
  for (const f of protectedTargets()) unlockFile(f);
11550
11718
  }
11551
11719
  function globalPaths() {
11552
- const home = homedir10();
11553
- const sgDir = join12(home, ".solongate");
11554
- const hooksDir = join12(sgDir, "hooks");
11555
- const claudeDir = join12(home, ".claude");
11720
+ const home = homedir11();
11721
+ const sgDir = join13(home, ".solongate");
11722
+ const hooksDir = join13(sgDir, "hooks");
11723
+ const claudeDir = join13(home, ".claude");
11556
11724
  return {
11557
11725
  home,
11558
11726
  sgDir,
11559
11727
  hooksDir,
11560
11728
  claudeDir,
11561
- settingsPath: join12(claudeDir, "settings.json"),
11562
- backupPath: join12(claudeDir, "settings.solongate.bak"),
11563
- configPath: join12(sgDir, "cloud-guard.json")
11729
+ settingsPath: join13(claudeDir, "settings.json"),
11730
+ backupPath: join13(claudeDir, "settings.solongate.bak"),
11731
+ configPath: join13(sgDir, "cloud-guard.json")
11564
11732
  };
11565
11733
  }
11566
11734
  function readHook(filename) {
11567
- return readFileSync8(join12(HOOKS_DIR, filename), "utf-8");
11735
+ return readFileSync9(join13(HOOKS_DIR, filename), "utf-8");
11568
11736
  }
11569
11737
  function readGuard() {
11570
- const bundled = join12(HOOKS_DIR, "guard.bundled.mjs");
11571
- return existsSync6(bundled) ? readFileSync8(bundled, "utf-8") : readHook("guard.mjs");
11738
+ const bundled = join13(HOOKS_DIR, "guard.bundled.mjs");
11739
+ return existsSync6(bundled) ? readFileSync9(bundled, "utf-8") : readHook("guard.mjs");
11572
11740
  }
11573
11741
  function ask(question) {
11574
11742
  const rl = createInterface({ input: process.stdin, output: process.stderr });
@@ -11602,18 +11770,18 @@ function shimTargets() {
11602
11770
  return [];
11603
11771
  }
11604
11772
  }
11605
- return [".bashrc", ".zshrc", ".profile"].map((f) => join12(homedir10(), f)).filter((f) => existsSync6(f));
11773
+ return [".bashrc", ".zshrc", ".profile"].map((f) => join13(homedir11(), f)).filter((f) => existsSync6(f));
11606
11774
  }
11607
11775
  function writeShimBlock(file, block2) {
11608
11776
  const re = new RegExp(escapeRe(SHIM_BEGIN) + "[\\s\\S]*?" + escapeRe(SHIM_END) + "\\r?\\n?", "g");
11609
- let content = existsSync6(file) ? readFileSync8(file, "utf-8") : "";
11777
+ let content = existsSync6(file) ? readFileSync9(file, "utf-8") : "";
11610
11778
  content = content.replace(re, "");
11611
11779
  if (block2) {
11612
11780
  if (content.length && !content.endsWith("\n")) content += "\n";
11613
11781
  content += block2 + "\n";
11614
11782
  }
11615
- mkdirSync7(dirname(file), { recursive: true });
11616
- writeFileSync7(file, content);
11783
+ mkdirSync8(dirname2(file), { recursive: true });
11784
+ writeFileSync8(file, content);
11617
11785
  }
11618
11786
  function installClaudeShim(shieldPath) {
11619
11787
  const real = resolveRealClaude();
@@ -11643,7 +11811,7 @@ async function runGlobalInstall(opts = {}) {
11643
11811
  let apiKey = opts.apiKey || process.env["SOLONGATE_API_KEY"] || "";
11644
11812
  if (!apiKey || apiKey === "sg_live_your_key_here") {
11645
11813
  try {
11646
- const cfg = JSON.parse(readFileSync8(p.configPath, "utf-8"));
11814
+ const cfg = JSON.parse(readFileSync9(p.configPath, "utf-8"));
11647
11815
  if (cfg && typeof cfg.apiKey === "string") apiKey = cfg.apiKey;
11648
11816
  } catch {
11649
11817
  }
@@ -11656,22 +11824,22 @@ async function runGlobalInstall(opts = {}) {
11656
11824
  process.exit(1);
11657
11825
  }
11658
11826
  const apiUrl = opts.apiUrl || process.env["SOLONGATE_API_URL"] || "https://api.solongate.com";
11659
- mkdirSync7(p.hooksDir, { recursive: true });
11660
- mkdirSync7(p.claudeDir, { recursive: true });
11827
+ mkdirSync8(p.hooksDir, { recursive: true });
11828
+ mkdirSync8(p.claudeDir, { recursive: true });
11661
11829
  unlockProtected();
11662
- writeFileSync7(join12(p.hooksDir, "guard.mjs"), readGuard());
11663
- writeFileSync7(join12(p.hooksDir, "audit.mjs"), readHook("audit.mjs"));
11664
- writeFileSync7(join12(p.hooksDir, "stop.mjs"), readHook("stop.mjs"));
11665
- writeFileSync7(join12(p.hooksDir, "shield.mjs"), readHook("shield.mjs"));
11830
+ writeFileSync8(join13(p.hooksDir, "guard.mjs"), readGuard());
11831
+ writeFileSync8(join13(p.hooksDir, "audit.mjs"), readHook("audit.mjs"));
11832
+ writeFileSync8(join13(p.hooksDir, "stop.mjs"), readHook("stop.mjs"));
11833
+ writeFileSync8(join13(p.hooksDir, "shield.mjs"), readHook("shield.mjs"));
11666
11834
  console.log(` Installed hooks \u2192 ${p.hooksDir}`);
11667
- installClaudeShim(join12(p.hooksDir, "shield.mjs"));
11668
- writeFileSync7(p.configPath, JSON.stringify({ apiKey, apiUrl }, null, 2) + "\n");
11835
+ installClaudeShim(join13(p.hooksDir, "shield.mjs"));
11836
+ writeFileSync8(p.configPath, JSON.stringify({ apiKey, apiUrl }, null, 2) + "\n");
11669
11837
  console.log(` Wrote ${p.configPath}`);
11670
11838
  let existing = {};
11671
11839
  if (existsSync6(p.settingsPath)) {
11672
- const raw = readFileSync8(p.settingsPath, "utf-8");
11840
+ const raw = readFileSync9(p.settingsPath, "utf-8");
11673
11841
  if (!existsSync6(p.backupPath)) {
11674
- writeFileSync7(p.backupPath, raw);
11842
+ writeFileSync8(p.backupPath, raw);
11675
11843
  console.log(` Backed up existing settings \u2192 ${p.backupPath}`);
11676
11844
  }
11677
11845
  try {
@@ -11680,9 +11848,9 @@ async function runGlobalInstall(opts = {}) {
11680
11848
  existing = {};
11681
11849
  }
11682
11850
  }
11683
- const guardAbs = join12(p.hooksDir, "guard.mjs").replace(/\\/g, "/");
11684
- const auditAbs = join12(p.hooksDir, "audit.mjs").replace(/\\/g, "/");
11685
- const stopAbs = join12(p.hooksDir, "stop.mjs").replace(/\\/g, "/");
11851
+ const guardAbs = join13(p.hooksDir, "guard.mjs").replace(/\\/g, "/");
11852
+ const auditAbs = join13(p.hooksDir, "audit.mjs").replace(/\\/g, "/");
11853
+ const stopAbs = join13(p.hooksDir, "stop.mjs").replace(/\\/g, "/");
11686
11854
  const nodeBin = process.execPath.replace(/\\/g, "/");
11687
11855
  const call = process.platform === "win32" ? "& " : "";
11688
11856
  const hookCmd = (script) => `${call}"${nodeBin}" "${script}" claude-code "Claude Code"`;
@@ -11694,7 +11862,7 @@ async function runGlobalInstall(opts = {}) {
11694
11862
  Stop: [{ matcher: "", hooks: [{ type: "command", command: hookCmd(stopAbs) }] }]
11695
11863
  }
11696
11864
  };
11697
- writeFileSync7(p.settingsPath, JSON.stringify(merged, null, 2) + "\n");
11865
+ writeFileSync8(p.settingsPath, JSON.stringify(merged, null, 2) + "\n");
11698
11866
  console.log(` Registered global hooks \u2192 ${p.settingsPath}`);
11699
11867
  if (process.env["SOLONGATE_OS_LOCK"] === "1") {
11700
11868
  lockProtected();
@@ -11705,7 +11873,7 @@ var __dirname, HOOKS_DIR, SHIM_BEGIN, SHIM_END;
11705
11873
  var init_global_install = __esm({
11706
11874
  "src/global-install.ts"() {
11707
11875
  "use strict";
11708
- __dirname = dirname(fileURLToPath(import.meta.url));
11876
+ __dirname = dirname2(fileURLToPath2(import.meta.url));
11709
11877
  HOOKS_DIR = resolve4(__dirname, "..", "hooks");
11710
11878
  SHIM_BEGIN = "# >>> SolonGate shield (auto secret redaction) >>>";
11711
11879
  SHIM_END = "# <<< SolonGate shield <<<";
@@ -11714,7 +11882,7 @@ var init_global_install = __esm({
11714
11882
 
11715
11883
  // src/login.ts
11716
11884
  var login_exports = {};
11717
- import { spawn as spawn3 } from "child_process";
11885
+ import { spawn as spawn4 } from "child_process";
11718
11886
  function startSpinner(text) {
11719
11887
  if (!process.stderr.isTTY) {
11720
11888
  process.stderr.write(` ${text}
@@ -11750,7 +11918,7 @@ function openBrowser2(url) {
11750
11918
  try {
11751
11919
  const cmd = process.platform === "win32" ? "cmd" : process.platform === "darwin" ? "open" : "xdg-open";
11752
11920
  const args = process.platform === "win32" ? ["/c", "start", '""', url] : [url];
11753
- const child = spawn3(cmd, args, { stdio: "ignore", detached: true });
11921
+ const child = spawn4(cmd, args, { stdio: "ignore", detached: true });
11754
11922
  child.on("error", () => {
11755
11923
  });
11756
11924
  child.unref();
@@ -11870,13 +12038,13 @@ __export(shield_exports, {
11870
12038
  });
11871
12039
  import { createServer, request as httpRequest } from "http";
11872
12040
  import { request as httpsRequest } from "https";
11873
- import { spawn as spawn4 } from "child_process";
12041
+ import { spawn as spawn5 } from "child_process";
11874
12042
  import { URL as URL2 } from "url";
11875
- import { readFileSync as readFileSync9, existsSync as existsSync7, readdirSync, statSync as statSync4 } from "fs";
12043
+ import { readFileSync as readFileSync10, existsSync as existsSync7, readdirSync, statSync as statSync4 } from "fs";
11876
12044
  import { resolve as resolve5 } from "path";
11877
- import { homedir as homedir11 } from "os";
12045
+ import { homedir as homedir12 } from "os";
11878
12046
  function findCacheFile() {
11879
- const dir = resolve5(homedir11(), ".solongate");
12047
+ const dir = resolve5(homedir12(), ".solongate");
11880
12048
  const envSel = process.env.SOLONGATE_AGENT_ID;
11881
12049
  if (envSel) {
11882
12050
  const f = resolve5(dir, ".policy-cache-" + envSel.replace(/[^a-zA-Z0-9_-]/g, "_") + ".json");
@@ -11902,7 +12070,7 @@ function loadCfg() {
11902
12070
  try {
11903
12071
  const f = findCacheFile();
11904
12072
  if (f && existsSync7(f)) {
11905
- const c2 = JSON.parse(readFileSync9(f, "utf-8"));
12073
+ const c2 = JSON.parse(readFileSync10(f, "utf-8"));
11906
12074
  const d = c2?.security?.dlpRedact;
11907
12075
  const g = c2?.security?.ghost;
11908
12076
  const ghost = g && Array.isArray(g.patterns) ? g.patterns : [];
@@ -12130,7 +12298,7 @@ async function runShield() {
12130
12298
  const upstream = pickUpstream();
12131
12299
  const { port, close } = await startProxy(upstream);
12132
12300
  log4(`redacting secrets on the LLM path \u2192 masking before ${upstream.host} (127.0.0.1:${port})`);
12133
- const child = spawn4(cmd[0], cmd.slice(1), {
12301
+ const child = spawn5(cmd[0], cmd.slice(1), {
12134
12302
  stdio: "inherit",
12135
12303
  env: { ...process.env, ANTHROPIC_BASE_URL: `http://127.0.0.1:${port}` },
12136
12304
  shell: process.platform === "win32"
@@ -12190,9 +12358,9 @@ __export(logs_server_exports, {
12190
12358
  runLogsServer: () => runLogsServer
12191
12359
  });
12192
12360
  import { createServer as createServer2 } from "http";
12193
- import { readFileSync as readFileSync10, statSync as statSync5 } from "fs";
12194
- import { resolve as resolve6, join as join13, isAbsolute } from "path";
12195
- import { homedir as homedir12 } from "os";
12361
+ import { readFileSync as readFileSync11, statSync as statSync5 } from "fs";
12362
+ import { resolve as resolve6, join as join14, isAbsolute } from "path";
12363
+ import { homedir as homedir13 } from "os";
12196
12364
  import { readdirSync as readdirSync2 } from "fs";
12197
12365
  function allowedOrigins() {
12198
12366
  const base = [
@@ -12209,15 +12377,15 @@ function resolveLocalLogDir(rawPath) {
12209
12377
  const dir = String(rawPath || "").trim().replace(/[\\/]+$/, "");
12210
12378
  if (!dir) return null;
12211
12379
  if (isAbsolute(dir)) return dir;
12212
- return resolve6(homedir12(), ".solongate", "local-logs");
12380
+ return resolve6(homedir13(), ".solongate", "local-logs");
12213
12381
  }
12214
12382
  async function findLogDir() {
12215
- const base = resolve6(homedir12(), ".solongate");
12383
+ const base = resolve6(homedir13(), ".solongate");
12216
12384
  try {
12217
12385
  const files = readdirSync2(base).filter((f) => f.startsWith(".policy-cache-") && f.endsWith(".json"));
12218
12386
  for (const f of files) {
12219
12387
  try {
12220
- const c2 = JSON.parse(readFileSync10(join13(base, f), "utf-8"));
12388
+ const c2 = JSON.parse(readFileSync11(join14(base, f), "utf-8"));
12221
12389
  const p = c2?.security?.localLogs?.path;
12222
12390
  if (typeof p === "string" && p.trim()) return { dir: resolveLocalLogDir(p), configured: p };
12223
12391
  } catch {
@@ -12226,7 +12394,7 @@ async function findLogDir() {
12226
12394
  } catch {
12227
12395
  }
12228
12396
  try {
12229
- const cfgRaw = readFileSync10(join13(base, "cloud-guard.json"), "utf-8");
12397
+ const cfgRaw = readFileSync11(join14(base, "cloud-guard.json"), "utf-8");
12230
12398
  const { apiKey, apiUrl } = JSON.parse(cfgRaw);
12231
12399
  if (apiKey) {
12232
12400
  const url = `${apiUrl || "https://api.solongate.com"}/api/v1/policies/active`;
@@ -12255,7 +12423,7 @@ function setCors(req, res) {
12255
12423
  }
12256
12424
  function fileInfo(dir) {
12257
12425
  if (!dir) return { file: null, exists: false, size: 0, mtimeMs: 0 };
12258
- const file = join13(dir, LOG_FILENAME);
12426
+ const file = join14(dir, LOG_FILENAME);
12259
12427
  try {
12260
12428
  const st = statSync5(file);
12261
12429
  return { file, exists: true, size: st.size, mtimeMs: st.mtimeMs };
@@ -12316,7 +12484,7 @@ async function runLogsServer() {
12316
12484
  return;
12317
12485
  }
12318
12486
  try {
12319
- const text = readFileSync10(info.file, "utf-8");
12487
+ const text = readFileSync11(info.file, "utf-8");
12320
12488
  res.writeHead(200, { "Content-Type": "text/plain; charset=utf-8", "Last-Modified": lastMod, "X-Solongate-Exists": "1" });
12321
12489
  res.end(text);
12322
12490
  } catch {
@@ -12368,7 +12536,7 @@ var init_logs_server = __esm({
12368
12536
 
12369
12537
  // src/inject.ts
12370
12538
  var inject_exports = {};
12371
- import { readFileSync as readFileSync11, writeFileSync as writeFileSync8, existsSync as existsSync8, copyFileSync } from "fs";
12539
+ import { readFileSync as readFileSync12, writeFileSync as writeFileSync9, existsSync as existsSync8, copyFileSync } from "fs";
12372
12540
  import { resolve as resolve7 } from "path";
12373
12541
  import { execSync } from "child_process";
12374
12542
  function parseInjectArgs(argv) {
@@ -12428,7 +12596,7 @@ WHAT IT DOES
12428
12596
  function detectProject() {
12429
12597
  if (!existsSync8(resolve7("package.json"))) return false;
12430
12598
  try {
12431
- const pkg = JSON.parse(readFileSync11(resolve7("package.json"), "utf-8"));
12599
+ const pkg = JSON.parse(readFileSync12(resolve7("package.json"), "utf-8"));
12432
12600
  const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
12433
12601
  return !!(allDeps["@modelcontextprotocol/sdk"] || allDeps["@modelcontextprotocol/server"]);
12434
12602
  } catch {
@@ -12437,7 +12605,7 @@ function detectProject() {
12437
12605
  }
12438
12606
  function findTsEntryFile() {
12439
12607
  try {
12440
- const pkg = JSON.parse(readFileSync11(resolve7("package.json"), "utf-8"));
12608
+ const pkg = JSON.parse(readFileSync12(resolve7("package.json"), "utf-8"));
12441
12609
  if (pkg.bin) {
12442
12610
  const binPath = typeof pkg.bin === "string" ? pkg.bin : Object.values(pkg.bin)[0];
12443
12611
  if (typeof binPath === "string") {
@@ -12464,7 +12632,7 @@ function findTsEntryFile() {
12464
12632
  const full = resolve7(c2);
12465
12633
  if (existsSync8(full)) {
12466
12634
  try {
12467
- const content = readFileSync11(full, "utf-8");
12635
+ const content = readFileSync12(full, "utf-8");
12468
12636
  if (content.includes("McpServer") || content.includes("McpServer")) {
12469
12637
  return full;
12470
12638
  }
@@ -12484,7 +12652,7 @@ function detectPackageManager() {
12484
12652
  }
12485
12653
  function installSdk() {
12486
12654
  try {
12487
- const pkg = JSON.parse(readFileSync11(resolve7("package.json"), "utf-8"));
12655
+ const pkg = JSON.parse(readFileSync12(resolve7("package.json"), "utf-8"));
12488
12656
  const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
12489
12657
  if (allDeps["@solongate/proxy"]) {
12490
12658
  log3(" @solongate/proxy already installed");
@@ -12505,7 +12673,7 @@ function installSdk() {
12505
12673
  }
12506
12674
  }
12507
12675
  function injectTypeScript(filePath) {
12508
- const original = readFileSync11(filePath, "utf-8");
12676
+ const original = readFileSync12(filePath, "utf-8");
12509
12677
  const changes = [];
12510
12678
  let modified = original;
12511
12679
  if (modified.includes("SecureMcpServer")) {
@@ -12676,7 +12844,7 @@ async function main2() {
12676
12844
  log3("");
12677
12845
  log3(` Backup: ${backupPath}`);
12678
12846
  }
12679
- writeFileSync8(entryFile, result.modified);
12847
+ writeFileSync9(entryFile, result.modified);
12680
12848
  log3("");
12681
12849
  log3(" \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510");
12682
12850
  log3(" \u2502 SolonGate SDK injected successfully! \u2502");
@@ -12705,8 +12873,8 @@ var init_inject = __esm({
12705
12873
 
12706
12874
  // src/create.ts
12707
12875
  var create_exports = {};
12708
- import { mkdirSync as mkdirSync8, writeFileSync as writeFileSync9, existsSync as existsSync9 } from "fs";
12709
- import { resolve as resolve8, join as join14 } from "path";
12876
+ import { mkdirSync as mkdirSync9, writeFileSync as writeFileSync10, existsSync as existsSync9 } from "fs";
12877
+ import { resolve as resolve8, join as join15 } from "path";
12710
12878
  import { execSync as execSync2 } from "child_process";
12711
12879
  function withSpinner(message, fn) {
12712
12880
  const frames = ["\u28FE", "\u28FD", "\u28FB", "\u28BF", "\u287F", "\u28DF", "\u28EF", "\u28F7"];
@@ -12785,8 +12953,8 @@ EXAMPLES
12785
12953
  `);
12786
12954
  }
12787
12955
  function createProject(dir, name, _policy) {
12788
- writeFileSync9(
12789
- join14(dir, "package.json"),
12956
+ writeFileSync10(
12957
+ join15(dir, "package.json"),
12790
12958
  JSON.stringify(
12791
12959
  {
12792
12960
  name,
@@ -12815,8 +12983,8 @@ function createProject(dir, name, _policy) {
12815
12983
  2
12816
12984
  ) + "\n"
12817
12985
  );
12818
- writeFileSync9(
12819
- join14(dir, "tsconfig.json"),
12986
+ writeFileSync10(
12987
+ join15(dir, "tsconfig.json"),
12820
12988
  JSON.stringify(
12821
12989
  {
12822
12990
  compilerOptions: {
@@ -12836,9 +13004,9 @@ function createProject(dir, name, _policy) {
12836
13004
  2
12837
13005
  ) + "\n"
12838
13006
  );
12839
- mkdirSync8(join14(dir, "src"), { recursive: true });
12840
- writeFileSync9(
12841
- join14(dir, "src", "index.ts"),
13007
+ mkdirSync9(join15(dir, "src"), { recursive: true });
13008
+ writeFileSync10(
13009
+ join15(dir, "src", "index.ts"),
12842
13010
  `#!/usr/bin/env node
12843
13011
 
12844
13012
  console.log = (...args: unknown[]) => {
@@ -12879,8 +13047,8 @@ console.log('');
12879
13047
  console.log('Press Ctrl+C to stop.');
12880
13048
  `
12881
13049
  );
12882
- writeFileSync9(
12883
- join14(dir, ".mcp.json"),
13050
+ writeFileSync10(
13051
+ join15(dir, ".mcp.json"),
12884
13052
  JSON.stringify(
12885
13053
  {
12886
13054
  mcpServers: {
@@ -12897,13 +13065,13 @@ console.log('Press Ctrl+C to stop.');
12897
13065
  2
12898
13066
  ) + "\n"
12899
13067
  );
12900
- writeFileSync9(
12901
- join14(dir, ".env"),
13068
+ writeFileSync10(
13069
+ join15(dir, ".env"),
12902
13070
  `SOLONGATE_API_KEY=sg_live_YOUR_KEY_HERE
12903
13071
  `
12904
13072
  );
12905
- writeFileSync9(
12906
- join14(dir, ".gitignore"),
13073
+ writeFileSync10(
13074
+ join15(dir, ".gitignore"),
12907
13075
  `node_modules/
12908
13076
  dist/
12909
13077
  *.solongate-backup
@@ -12922,7 +13090,7 @@ async function main3() {
12922
13090
  process.exit(1);
12923
13091
  }
12924
13092
  withSpinner(`Setting up ${opts.name}...`, () => {
12925
- mkdirSync8(dir, { recursive: true });
13093
+ mkdirSync9(dir, { recursive: true });
12926
13094
  createProject(dir, opts.name, opts.policy);
12927
13095
  });
12928
13096
  if (!opts.noInstall) {
@@ -12996,14 +13164,14 @@ var init_create = __esm({
12996
13164
 
12997
13165
  // src/pull-push.ts
12998
13166
  var pull_push_exports = {};
12999
- import { readFileSync as readFileSync12, writeFileSync as writeFileSync10, existsSync as existsSync10 } from "fs";
13167
+ import { readFileSync as readFileSync13, writeFileSync as writeFileSync11, existsSync as existsSync10 } from "fs";
13000
13168
  import { resolve as resolve9 } from "path";
13001
13169
  function loadEnv() {
13002
13170
  if (process.env.SOLONGATE_API_KEY) return;
13003
13171
  const envPath = resolve9(".env");
13004
13172
  if (!existsSync10(envPath)) return;
13005
13173
  try {
13006
- const content = readFileSync12(envPath, "utf-8");
13174
+ const content = readFileSync13(envPath, "utf-8");
13007
13175
  for (const line of content.split("\n")) {
13008
13176
  const trimmed = line.trim();
13009
13177
  if (!trimmed || trimmed.startsWith("#")) continue;
@@ -13191,7 +13359,7 @@ async function pull(apiKey, file, policyId) {
13191
13359
  const policy = await fetchCloudPolicy(apiKey, API_URL, policyId);
13192
13360
  const { id: _id, ...policyWithoutId } = policy;
13193
13361
  const json = JSON.stringify(policyWithoutId, null, 2) + "\n";
13194
- writeFileSync10(file, json, "utf-8");
13362
+ writeFileSync11(file, json, "utf-8");
13195
13363
  log5("");
13196
13364
  log5(green2(" Saved to: ") + file);
13197
13365
  log5(` ${dim2("Name:")} ${policy.name}`);
@@ -13220,7 +13388,7 @@ async function push(apiKey, file, policyId) {
13220
13388
  log5(" solongate-proxy list");
13221
13389
  process.exit(1);
13222
13390
  }
13223
- const content = readFileSync12(file, "utf-8");
13391
+ const content = readFileSync13(file, "utf-8");
13224
13392
  let policy;
13225
13393
  try {
13226
13394
  policy = JSON.parse(content);
@@ -15380,7 +15548,7 @@ var SolonGate = class {
15380
15548
  */
15381
15549
  startPolicyPolling() {
15382
15550
  const apiUrl = this.config.apiUrl ?? "https://api.solongate.com";
15383
- let currentVersion = 0;
15551
+ let currentVersion2 = 0;
15384
15552
  const timer = setInterval(async () => {
15385
15553
  try {
15386
15554
  const res = await fetch(`${apiUrl}/api/v1/policies/default`, {
@@ -15390,7 +15558,7 @@ var SolonGate = class {
15390
15558
  if (!res.ok) return;
15391
15559
  const data = await res.json();
15392
15560
  const version = Number(data._version ?? 0);
15393
- if (version !== currentVersion && version > 0) {
15561
+ if (version !== currentVersion2 && version > 0) {
15394
15562
  const policySet = {
15395
15563
  id: String(data.id ?? "cloud"),
15396
15564
  name: String(data.name ?? "Cloud Policy"),
@@ -15402,7 +15570,7 @@ var SolonGate = class {
15402
15570
  };
15403
15571
  this.policyEngine.loadPolicySet(policySet);
15404
15572
  await this.loadCloudWasm(apiUrl, policySet.id);
15405
- currentVersion = version;
15573
+ currentVersion2 = version;
15406
15574
  }
15407
15575
  } catch {
15408
15576
  }
@@ -16370,6 +16538,12 @@ function printWelcome() {
16370
16538
  }
16371
16539
  async function main5() {
16372
16540
  const subcommand = process.argv[2];
16541
+ if (IS_HUMAN_CLI) {
16542
+ const tuiBound = subcommand === "dataroom" || process.argv.length <= 2 && process.stdout.isTTY && process.stdin.isTTY;
16543
+ const { maybeSelfUpdate: maybeSelfUpdate2 } = await Promise.resolve().then(() => (init_self_update(), self_update_exports));
16544
+ maybeSelfUpdate2(tuiBound ? () => {
16545
+ } : void 0);
16546
+ }
16373
16547
  if (process.argv.length <= 2) {
16374
16548
  if (process.stdout.isTTY && process.stdin.isTTY) {
16375
16549
  const { launchTui: launchTui2 } = await Promise.resolve().then(() => (init_tui(), tui_exports));
@@ -0,0 +1,6 @@
1
+ export declare function currentVersion(): string;
2
+ /**
3
+ * Fire-and-forget startup hook. `notify` writes the human-facing one-liner —
4
+ * callers pass a stderr writer so the notice never lands in piped stdout.
5
+ */
6
+ export declare function maybeSelfUpdate(notify?: (line: string) => void): void;
package/dist/tui/index.js CHANGED
@@ -12,7 +12,7 @@ import { render } from "ink";
12
12
 
13
13
  // src/tui/App.tsx
14
14
  import { Box as Box9, Text as Text9, useApp, useInput as useInput8 } from "ink";
15
- import { useState as useState9 } from "react";
15
+ import { useEffect as useEffect7, useState as useState9 } from "react";
16
16
 
17
17
  // src/cli-utils.ts
18
18
  var c = {
@@ -471,6 +471,15 @@ async function pollDeviceLogin(apiUrl, deviceCode) {
471
471
  }
472
472
  }
473
473
 
474
+ // src/api-client/auth.ts
475
+ var auth_exports = {};
476
+ __export(auth_exports, {
477
+ me: () => me
478
+ });
479
+ function me() {
480
+ return request("GET", "/auth/me");
481
+ }
482
+
474
483
  // src/api-client/policies.ts
475
484
  var policies_exports = {};
476
485
  __export(policies_exports, {
@@ -693,7 +702,7 @@ function list4() {
693
702
  }
694
703
 
695
704
  // src/api-client/index.ts
696
- var api = { policies: policies_exports, settings: settings_exports, stats: stats_exports, audit: audit_exports, agents: agents_exports, keys: keys_exports, mcp: mcp_exports };
705
+ var api = { auth: auth_exports, policies: policies_exports, settings: settings_exports, stats: stats_exports, audit: audit_exports, agents: agents_exports, keys: keys_exports, mcp: mcp_exports };
697
706
 
698
707
  // src/tui/notify.ts
699
708
  import { spawn as spawn2 } from "child_process";
@@ -3355,7 +3364,7 @@ function AccountsPanel({
3355
3364
  if (a) {
3356
3365
  setViewCredentials({ apiKey: a.apiKey, apiUrl: a.apiUrl });
3357
3366
  onView?.(a);
3358
- setMsg({ text: `viewing ${a.project || a.user || a.apiKey.slice(0, 8)}`, level: "ok" });
3367
+ setMsg({ text: `viewing ${a.project || a.user || "account \u2026" + a.apiKey.slice(-4)}`, level: "ok" });
3359
3368
  }
3360
3369
  } else if (input === "m") {
3361
3370
  const a = accounts[sel];
@@ -3404,7 +3413,7 @@ function AccountsPanel({
3404
3413
  const isActive = isActiveAccount(a.apiKey);
3405
3414
  return /* @__PURE__ */ jsxs8(Text8, { wrap: "truncate", backgroundColor: isSel ? "#333333" : void 0, bold: isSel, children: [
3406
3415
  /* @__PURE__ */ jsx8(Text8, { color: isSel ? theme.accentBright : theme.dim, children: isSel ? "\u25B8 " : " " }),
3407
- /* @__PURE__ */ jsx8(Text8, { color: theme.accent, children: truncate(a.project || a.user || a.apiKey.slice(0, 12), 30).padEnd(31) }),
3416
+ /* @__PURE__ */ jsx8(Text8, { color: theme.accent, children: truncate(a.project || a.user || "account \u2026" + a.apiKey.slice(-4), 30).padEnd(31) }),
3408
3417
  isView ? /* @__PURE__ */ jsx8(Text8, { color: theme.ok, children: "\u25CF viewing " }) : /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: " " }),
3409
3418
  isActive ? /* @__PURE__ */ jsx8(Text8, { color: theme.warn, children: "ACTIVE " }) : /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: " " }),
3410
3419
  /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: a.user && a.project ? truncate(a.user, 24) : "" })
@@ -3462,7 +3471,22 @@ function App() {
3462
3471
  const [help, setHelp] = useState9(false);
3463
3472
  const acctIdx = Math.max(0, accounts.findIndex((a) => a.apiKey === viewKey));
3464
3473
  const cur = accounts[acctIdx];
3465
- const acctLabel = cur ? cur.project || cur.user || cur.apiKey.slice(0, 8) : "not logged in";
3474
+ const acctLabel = cur ? cur.project || cur.user || `account \u2026${cur.apiKey.slice(-4)}` : "not logged in";
3475
+ useEffect7(() => {
3476
+ if (!cur || cur.project || cur.user) return;
3477
+ let alive = true;
3478
+ api.auth.me().then((r) => {
3479
+ const project = r.project?.name || void 0;
3480
+ const user = r.user?.name || r.user?.email || void 0;
3481
+ if (!alive || !project && !user) return;
3482
+ saveAccount({ ...cur, project, user });
3483
+ setAccounts(listAccounts());
3484
+ }).catch(() => {
3485
+ });
3486
+ return () => {
3487
+ alive = false;
3488
+ };
3489
+ }, [cur]);
3466
3490
  const viewAccount = (a) => {
3467
3491
  setViewCredentials({ apiKey: a.apiKey, apiUrl: a.apiUrl });
3468
3492
  setAccounts(listAccounts());
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solongate/proxy",
3
- "version": "0.81.45",
3
+ "version": "0.81.47",
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": {