@solongate/proxy 0.81.27 → 0.81.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -8877,6 +8877,9 @@ var init_Dlp = __esm({
8877
8877
  // src/tui/panels/Audit.tsx
8878
8878
  import { Box as Box6, Text as Text6, useInput as useInput5 } from "ink";
8879
8879
  import TextInput4 from "ink-text-input";
8880
+ import { mkdirSync as mkdirSync4, writeFileSync as writeFileSync5 } from "fs";
8881
+ import { homedir as homedir6 } from "os";
8882
+ import { join as join8 } from "path";
8880
8883
  import { useState as useState6 } from "react";
8881
8884
  import { Fragment as Fragment4, jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
8882
8885
  function loadLocalRows() {
@@ -8941,26 +8944,25 @@ function AuditPanel({ active: active2, focused }) {
8941
8944
  usePoll(cloudQ.reloadQuiet, 6e3, active2 && source === "cloud" && view === "logs" && !editing && page === 0);
8942
8945
  const localQ = useLoader(() => source === "local" ? Promise.resolve(loadLocalRows()) : Promise.resolve(null), [source]);
8943
8946
  usePoll(localQ.reloadQuiet, 6e3, active2 && source === "local" && view === "logs" && !editing && page === 0);
8947
+ const q = search.trim().toLowerCase();
8948
+ const localFiltered = (localQ.data ?? []).filter((r) => {
8949
+ if (DECISIONS[di] && r.decision !== DECISIONS[di]) return false;
8950
+ if (SIGNALS[gi] === "dlp" && r.dlp.length === 0) return false;
8951
+ if (SIGNALS[gi] === "ratelimit" && !r.burst) return false;
8952
+ if (tool && !r.tool.toLowerCase().includes(tool.toLowerCase())) return false;
8953
+ if (agent && (r.agent ?? "").toLowerCase() !== agent.toLowerCase()) return false;
8954
+ if (sessFilter && r.session !== sessFilter) return false;
8955
+ if (q && !`${r.tool} ${r.agent ?? ""} ${r.reason ?? ""} ${r.args ?? ""}`.toLowerCase().includes(q)) return false;
8956
+ return true;
8957
+ });
8944
8958
  let pageRows = [];
8945
8959
  let total = 0;
8946
8960
  if (source === "cloud") {
8947
8961
  pageRows = (cloudQ.data?.entries ?? []).map(cloudRow).sort((a, b) => b.at - a.at);
8948
8962
  total = cloudQ.data?.total ?? 0;
8949
8963
  } else {
8950
- const all = localQ.data ?? [];
8951
- const q = search.trim().toLowerCase();
8952
- const filtered = all.filter((r) => {
8953
- if (DECISIONS[di] && r.decision !== DECISIONS[di]) return false;
8954
- if (SIGNALS[gi] === "dlp" && r.dlp.length === 0) return false;
8955
- if (SIGNALS[gi] === "ratelimit" && !r.burst) return false;
8956
- if (tool && !r.tool.toLowerCase().includes(tool.toLowerCase())) return false;
8957
- if (agent && (r.agent ?? "").toLowerCase() !== agent.toLowerCase()) return false;
8958
- if (sessFilter && r.session !== sessFilter) return false;
8959
- if (q && !`${r.tool} ${r.agent ?? ""} ${r.reason ?? ""} ${r.args ?? ""}`.toLowerCase().includes(q)) return false;
8960
- return true;
8961
- });
8962
- total = filtered.length;
8963
- pageRows = filtered.slice(page * PAGE, page * PAGE + PAGE);
8964
+ total = localFiltered.length;
8965
+ pageRows = localFiltered.slice(page * PAGE, page * PAGE + PAGE);
8964
8966
  }
8965
8967
  const pages = Math.max(1, Math.ceil(total / PAGE));
8966
8968
  const current = pageRows[Math.min(sel, Math.max(0, pageRows.length - 1))];
@@ -9027,6 +9029,23 @@ function AuditPanel({ active: active2, focused }) {
9027
9029
  toTop();
9028
9030
  }).catch((e) => setMsg({ text: "\u2717 " + (e instanceof Error ? e.message : String(e)), level: "bad" }));
9029
9031
  };
9032
+ const doExport = (kind) => {
9033
+ setMsg({ text: "exporting\u2026", level: "ok" });
9034
+ const run12 = async () => {
9035
+ const dir = join8(homedir6(), ".solongate");
9036
+ const file = join8(dir, `audit-export-${source}.jsonl`);
9037
+ let rows2;
9038
+ if (kind === "page") rows2 = pageRows;
9039
+ else if (source === "cloud") {
9040
+ const r = await api.audit.list({ ...query, limit: 1e4, offset: 0 });
9041
+ rows2 = r.entries.map(cloudRow).sort((a, b) => b.at - a.at);
9042
+ } else rows2 = localFiltered;
9043
+ mkdirSync4(dir, { recursive: true });
9044
+ writeFileSync5(file, rows2.map((x) => JSON.stringify(x)).join("\n") + (rows2.length ? "\n" : ""));
9045
+ return { n: rows2.length, file };
9046
+ };
9047
+ 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" }));
9048
+ };
9030
9049
  useInput5(
9031
9050
  (input, key) => {
9032
9051
  if (showHelp) {
@@ -9115,7 +9134,7 @@ function AuditPanel({ active: active2, focused }) {
9115
9134
  if (!current) return;
9116
9135
  if (confirm?.kind !== "one" || confirm.key !== current.id) {
9117
9136
  setConfirm({ kind: "one", key: current.id });
9118
- setMsg({ text: `delete ${current.decision} ${current.tool} (${ago(current.at)} ago)? press x again`, level: "bad" });
9137
+ setMsg({ text: `x = delete ONLY the selected entry: ${current.decision} ${current.tool} (${ago(current.at)} ago) \u2014 press x again`, level: "bad" });
9119
9138
  return;
9120
9139
  }
9121
9140
  setConfirm(null);
@@ -9123,12 +9142,14 @@ function AuditPanel({ active: active2, focused }) {
9123
9142
  } else if (input === "X") {
9124
9143
  if (confirm?.kind !== "all") {
9125
9144
  setConfirm({ kind: "all", key: "all" });
9126
- setMsg({ text: `DELETE ALL ${source} logs (${total} entries)? press X again`, level: "bad" });
9145
+ setMsg({ text: `\u26A0 X = delete ALL ${source} logs \u2014 every one of the ${total} matched entries! press X again`, level: "bad" });
9127
9146
  return;
9128
9147
  }
9129
9148
  setConfirm(null);
9130
9149
  doDelete("all");
9131
- } else if (input === "t") setEditing("tool");
9150
+ } else if (input === "e") doExport("page");
9151
+ else if (input === "E") doExport("all");
9152
+ else if (input === "t") setEditing("tool");
9132
9153
  else if (input === "n") setEditing("agent");
9133
9154
  else if (input === "/") setEditing("search");
9134
9155
  else if (input === "c") {
@@ -9451,8 +9472,10 @@ var init_Audit = __esm({
9451
9472
  ["g", "signal filter: all \u2192 dlp \u2192 ratelimit"],
9452
9473
  ["t / n", "tool / agent filter (type, enter done)"],
9453
9474
  ["/", "free-text search"],
9454
- ["x", "delete the selected entry (press x twice)"],
9455
- ["X", "delete ALL logs of the current source (press X twice)"],
9475
+ ["x", "delete ONLY the selected entry (press x twice)"],
9476
+ ["X", "delete ALL matched logs of the source (press X twice)"],
9477
+ ["e", "export this page \u2192 ~/.solongate/audit-export-<src>.jsonl"],
9478
+ ["E", "export ALL matched rows (cloud: up to 10k)"],
9456
9479
  ["c", "clear every filter (incl. session)"]
9457
9480
  ]
9458
9481
  ],
@@ -10540,8 +10563,8 @@ var init_agents2 = __esm({
10540
10563
 
10541
10564
  // src/commands/doctor.ts
10542
10565
  import { existsSync as existsSync4, statSync as statSync2 } from "fs";
10543
- import { homedir as homedir6 } from "os";
10544
- import { join as join8 } from "path";
10566
+ import { homedir as homedir7 } from "os";
10567
+ import { join as join9 } from "path";
10545
10568
  async function run6(argv) {
10546
10569
  const { flags } = parse(argv);
10547
10570
  const json = flagBool(flags, "json");
@@ -10601,14 +10624,14 @@ var init_doctor = __esm({
10601
10624
  init_api_client();
10602
10625
  init_format();
10603
10626
  init_args();
10604
- LOCAL_LOG2 = join8(homedir6(), ".solongate", "local-logs", "solongate-audit.jsonl");
10627
+ LOCAL_LOG2 = join9(homedir7(), ".solongate", "local-logs", "solongate-audit.jsonl");
10605
10628
  }
10606
10629
  });
10607
10630
 
10608
10631
  // src/commands/watch.ts
10609
10632
  import { closeSync as closeSync2, existsSync as existsSync5, openSync as openSync2, readSync as readSync2, statSync as statSync3 } from "fs";
10610
- import { homedir as homedir7 } from "os";
10611
- import { join as join9 } from "path";
10633
+ import { homedir as homedir8 } from "os";
10634
+ import { join as join10 } from "path";
10612
10635
  function tailLocal(file, maxBytes = 131072) {
10613
10636
  try {
10614
10637
  const size = statSync3(file).size;
@@ -10715,7 +10738,7 @@ var init_watch = __esm({
10715
10738
  init_cli_utils();
10716
10739
  init_args();
10717
10740
  init_format();
10718
- LOCAL_LOG3 = join9(homedir7(), ".solongate", "local-logs", "solongate-audit.jsonl");
10741
+ LOCAL_LOG3 = join10(homedir8(), ".solongate", "local-logs", "solongate-audit.jsonl");
10719
10742
  trunc = (s, n) => s.length <= n ? s : s.slice(0, n - 1) + "\u2026";
10720
10743
  time = (ms) => new Date(ms).toTimeString().slice(0, 8);
10721
10744
  }
@@ -11017,9 +11040,9 @@ __export(global_install_exports, {
11017
11040
  runGlobalRestore: () => runGlobalRestore,
11018
11041
  unlockProtected: () => unlockProtected
11019
11042
  });
11020
- import { readFileSync as readFileSync8, writeFileSync as writeFileSync5, existsSync as existsSync6, mkdirSync as mkdirSync4 } from "fs";
11021
- import { resolve as resolve4, join as join10, dirname } from "path";
11022
- import { homedir as homedir8 } from "os";
11043
+ import { readFileSync as readFileSync8, writeFileSync as writeFileSync6, existsSync as existsSync6, mkdirSync as mkdirSync5 } from "fs";
11044
+ import { resolve as resolve4, join as join11, dirname } from "path";
11045
+ import { homedir as homedir9 } from "os";
11023
11046
  import { fileURLToPath } from "url";
11024
11047
  import { createInterface } from "readline";
11025
11048
  import { execFileSync as execFileSync2 } from "child_process";
@@ -11082,10 +11105,10 @@ function unlockFile(file) {
11082
11105
  function protectedTargets() {
11083
11106
  const p = globalPaths();
11084
11107
  return [
11085
- join10(p.hooksDir, "guard.mjs"),
11086
- join10(p.hooksDir, "audit.mjs"),
11087
- join10(p.hooksDir, "stop.mjs"),
11088
- join10(p.hooksDir, "shield.mjs"),
11108
+ join11(p.hooksDir, "guard.mjs"),
11109
+ join11(p.hooksDir, "audit.mjs"),
11110
+ join11(p.hooksDir, "stop.mjs"),
11111
+ join11(p.hooksDir, "shield.mjs"),
11089
11112
  p.configPath,
11090
11113
  p.settingsPath
11091
11114
  ];
@@ -11097,25 +11120,25 @@ function unlockProtected() {
11097
11120
  for (const f of protectedTargets()) unlockFile(f);
11098
11121
  }
11099
11122
  function globalPaths() {
11100
- const home = homedir8();
11101
- const sgDir = join10(home, ".solongate");
11102
- const hooksDir = join10(sgDir, "hooks");
11103
- const claudeDir = join10(home, ".claude");
11123
+ const home = homedir9();
11124
+ const sgDir = join11(home, ".solongate");
11125
+ const hooksDir = join11(sgDir, "hooks");
11126
+ const claudeDir = join11(home, ".claude");
11104
11127
  return {
11105
11128
  home,
11106
11129
  sgDir,
11107
11130
  hooksDir,
11108
11131
  claudeDir,
11109
- settingsPath: join10(claudeDir, "settings.json"),
11110
- backupPath: join10(claudeDir, "settings.solongate.bak"),
11111
- configPath: join10(sgDir, "cloud-guard.json")
11132
+ settingsPath: join11(claudeDir, "settings.json"),
11133
+ backupPath: join11(claudeDir, "settings.solongate.bak"),
11134
+ configPath: join11(sgDir, "cloud-guard.json")
11112
11135
  };
11113
11136
  }
11114
11137
  function readHook(filename) {
11115
- return readFileSync8(join10(HOOKS_DIR, filename), "utf-8");
11138
+ return readFileSync8(join11(HOOKS_DIR, filename), "utf-8");
11116
11139
  }
11117
11140
  function readGuard() {
11118
- const bundled = join10(HOOKS_DIR, "guard.bundled.mjs");
11141
+ const bundled = join11(HOOKS_DIR, "guard.bundled.mjs");
11119
11142
  return existsSync6(bundled) ? readFileSync8(bundled, "utf-8") : readHook("guard.mjs");
11120
11143
  }
11121
11144
  function ask(question) {
@@ -11130,13 +11153,13 @@ function runGlobalRestore() {
11130
11153
  unlockProtected();
11131
11154
  removeClaudeShim();
11132
11155
  if (existsSync6(p.backupPath)) {
11133
- writeFileSync5(p.settingsPath, readFileSync8(p.backupPath, "utf-8"));
11156
+ writeFileSync6(p.settingsPath, readFileSync8(p.backupPath, "utf-8"));
11134
11157
  console.log(` Restored ${p.settingsPath} from backup.`);
11135
11158
  } else if (existsSync6(p.settingsPath)) {
11136
11159
  try {
11137
11160
  const s = JSON.parse(readFileSync8(p.settingsPath, "utf-8"));
11138
11161
  delete s.hooks;
11139
- writeFileSync5(p.settingsPath, JSON.stringify(s, null, 2) + "\n");
11162
+ writeFileSync6(p.settingsPath, JSON.stringify(s, null, 2) + "\n");
11140
11163
  console.log(` Removed SolonGate hooks from ${p.settingsPath}.`);
11141
11164
  } catch {
11142
11165
  }
@@ -11170,7 +11193,7 @@ function shimTargets() {
11170
11193
  return [];
11171
11194
  }
11172
11195
  }
11173
- return [".bashrc", ".zshrc", ".profile"].map((f) => join10(homedir8(), f)).filter((f) => existsSync6(f));
11196
+ return [".bashrc", ".zshrc", ".profile"].map((f) => join11(homedir9(), f)).filter((f) => existsSync6(f));
11174
11197
  }
11175
11198
  function writeShimBlock(file, block2) {
11176
11199
  const re = new RegExp(escapeRe(SHIM_BEGIN) + "[\\s\\S]*?" + escapeRe(SHIM_END) + "\\r?\\n?", "g");
@@ -11180,8 +11203,8 @@ function writeShimBlock(file, block2) {
11180
11203
  if (content.length && !content.endsWith("\n")) content += "\n";
11181
11204
  content += block2 + "\n";
11182
11205
  }
11183
- mkdirSync4(dirname(file), { recursive: true });
11184
- writeFileSync5(file, content);
11206
+ mkdirSync5(dirname(file), { recursive: true });
11207
+ writeFileSync6(file, content);
11185
11208
  }
11186
11209
  function installClaudeShim(shieldPath) {
11187
11210
  const real = resolveRealClaude();
@@ -11232,22 +11255,22 @@ async function runGlobalInstall(opts = {}) {
11232
11255
  process.exit(1);
11233
11256
  }
11234
11257
  const apiUrl = opts.apiUrl || process.env["SOLONGATE_API_URL"] || "https://api.solongate.com";
11235
- mkdirSync4(p.hooksDir, { recursive: true });
11236
- mkdirSync4(p.claudeDir, { recursive: true });
11258
+ mkdirSync5(p.hooksDir, { recursive: true });
11259
+ mkdirSync5(p.claudeDir, { recursive: true });
11237
11260
  unlockProtected();
11238
- writeFileSync5(join10(p.hooksDir, "guard.mjs"), readGuard());
11239
- writeFileSync5(join10(p.hooksDir, "audit.mjs"), readHook("audit.mjs"));
11240
- writeFileSync5(join10(p.hooksDir, "stop.mjs"), readHook("stop.mjs"));
11241
- writeFileSync5(join10(p.hooksDir, "shield.mjs"), readHook("shield.mjs"));
11261
+ writeFileSync6(join11(p.hooksDir, "guard.mjs"), readGuard());
11262
+ writeFileSync6(join11(p.hooksDir, "audit.mjs"), readHook("audit.mjs"));
11263
+ writeFileSync6(join11(p.hooksDir, "stop.mjs"), readHook("stop.mjs"));
11264
+ writeFileSync6(join11(p.hooksDir, "shield.mjs"), readHook("shield.mjs"));
11242
11265
  console.log(` Installed hooks \u2192 ${p.hooksDir}`);
11243
- installClaudeShim(join10(p.hooksDir, "shield.mjs"));
11244
- writeFileSync5(p.configPath, JSON.stringify({ apiKey, apiUrl }, null, 2) + "\n");
11266
+ installClaudeShim(join11(p.hooksDir, "shield.mjs"));
11267
+ writeFileSync6(p.configPath, JSON.stringify({ apiKey, apiUrl }, null, 2) + "\n");
11245
11268
  console.log(` Wrote ${p.configPath}`);
11246
11269
  let existing = {};
11247
11270
  if (existsSync6(p.settingsPath)) {
11248
11271
  const raw = readFileSync8(p.settingsPath, "utf-8");
11249
11272
  if (!existsSync6(p.backupPath)) {
11250
- writeFileSync5(p.backupPath, raw);
11273
+ writeFileSync6(p.backupPath, raw);
11251
11274
  console.log(` Backed up existing settings \u2192 ${p.backupPath}`);
11252
11275
  }
11253
11276
  try {
@@ -11256,9 +11279,9 @@ async function runGlobalInstall(opts = {}) {
11256
11279
  existing = {};
11257
11280
  }
11258
11281
  }
11259
- const guardAbs = join10(p.hooksDir, "guard.mjs").replace(/\\/g, "/");
11260
- const auditAbs = join10(p.hooksDir, "audit.mjs").replace(/\\/g, "/");
11261
- const stopAbs = join10(p.hooksDir, "stop.mjs").replace(/\\/g, "/");
11282
+ const guardAbs = join11(p.hooksDir, "guard.mjs").replace(/\\/g, "/");
11283
+ const auditAbs = join11(p.hooksDir, "audit.mjs").replace(/\\/g, "/");
11284
+ const stopAbs = join11(p.hooksDir, "stop.mjs").replace(/\\/g, "/");
11262
11285
  const nodeBin = process.execPath.replace(/\\/g, "/");
11263
11286
  const call = process.platform === "win32" ? "& " : "";
11264
11287
  const hookCmd = (script) => `${call}"${nodeBin}" "${script}" claude-code "Claude Code"`;
@@ -11270,7 +11293,7 @@ async function runGlobalInstall(opts = {}) {
11270
11293
  Stop: [{ matcher: "", hooks: [{ type: "command", command: hookCmd(stopAbs) }] }]
11271
11294
  }
11272
11295
  };
11273
- writeFileSync5(p.settingsPath, JSON.stringify(merged, null, 2) + "\n");
11296
+ writeFileSync6(p.settingsPath, JSON.stringify(merged, null, 2) + "\n");
11274
11297
  console.log(` Registered global hooks \u2192 ${p.settingsPath}`);
11275
11298
  if (process.env["SOLONGATE_OS_LOCK"] === "1") {
11276
11299
  lockProtected();
@@ -11452,9 +11475,9 @@ import { spawn as spawn3 } from "child_process";
11452
11475
  import { URL as URL2 } from "url";
11453
11476
  import { readFileSync as readFileSync9, existsSync as existsSync7, readdirSync, statSync as statSync4 } from "fs";
11454
11477
  import { resolve as resolve5 } from "path";
11455
- import { homedir as homedir9 } from "os";
11478
+ import { homedir as homedir10 } from "os";
11456
11479
  function findCacheFile() {
11457
- const dir = resolve5(homedir9(), ".solongate");
11480
+ const dir = resolve5(homedir10(), ".solongate");
11458
11481
  const envSel = process.env.SOLONGATE_AGENT_ID;
11459
11482
  if (envSel) {
11460
11483
  const f = resolve5(dir, ".policy-cache-" + envSel.replace(/[^a-zA-Z0-9_-]/g, "_") + ".json");
@@ -11769,8 +11792,8 @@ __export(logs_server_exports, {
11769
11792
  });
11770
11793
  import { createServer as createServer2 } from "http";
11771
11794
  import { readFileSync as readFileSync10, statSync as statSync5 } from "fs";
11772
- import { resolve as resolve6, join as join11, isAbsolute } from "path";
11773
- import { homedir as homedir10 } from "os";
11795
+ import { resolve as resolve6, join as join12, isAbsolute } from "path";
11796
+ import { homedir as homedir11 } from "os";
11774
11797
  import { readdirSync as readdirSync2 } from "fs";
11775
11798
  function allowedOrigins() {
11776
11799
  const base = [
@@ -11787,15 +11810,15 @@ function resolveLocalLogDir(rawPath) {
11787
11810
  const dir = String(rawPath || "").trim().replace(/[\\/]+$/, "");
11788
11811
  if (!dir) return null;
11789
11812
  if (isAbsolute(dir)) return dir;
11790
- return resolve6(homedir10(), ".solongate", "local-logs");
11813
+ return resolve6(homedir11(), ".solongate", "local-logs");
11791
11814
  }
11792
11815
  async function findLogDir() {
11793
- const base = resolve6(homedir10(), ".solongate");
11816
+ const base = resolve6(homedir11(), ".solongate");
11794
11817
  try {
11795
11818
  const files = readdirSync2(base).filter((f) => f.startsWith(".policy-cache-") && f.endsWith(".json"));
11796
11819
  for (const f of files) {
11797
11820
  try {
11798
- const c2 = JSON.parse(readFileSync10(join11(base, f), "utf-8"));
11821
+ const c2 = JSON.parse(readFileSync10(join12(base, f), "utf-8"));
11799
11822
  const p = c2?.security?.localLogs?.path;
11800
11823
  if (typeof p === "string" && p.trim()) return { dir: resolveLocalLogDir(p), configured: p };
11801
11824
  } catch {
@@ -11804,7 +11827,7 @@ async function findLogDir() {
11804
11827
  } catch {
11805
11828
  }
11806
11829
  try {
11807
- const cfgRaw = readFileSync10(join11(base, "cloud-guard.json"), "utf-8");
11830
+ const cfgRaw = readFileSync10(join12(base, "cloud-guard.json"), "utf-8");
11808
11831
  const { apiKey, apiUrl } = JSON.parse(cfgRaw);
11809
11832
  if (apiKey) {
11810
11833
  const url = `${apiUrl || "https://api.solongate.com"}/api/v1/policies/active`;
@@ -11833,7 +11856,7 @@ function setCors(req, res) {
11833
11856
  }
11834
11857
  function fileInfo(dir) {
11835
11858
  if (!dir) return { file: null, exists: false, size: 0, mtimeMs: 0 };
11836
- const file = join11(dir, LOG_FILENAME);
11859
+ const file = join12(dir, LOG_FILENAME);
11837
11860
  try {
11838
11861
  const st = statSync5(file);
11839
11862
  return { file, exists: true, size: st.size, mtimeMs: st.mtimeMs };
@@ -11946,7 +11969,7 @@ var init_logs_server = __esm({
11946
11969
 
11947
11970
  // src/inject.ts
11948
11971
  var inject_exports = {};
11949
- import { readFileSync as readFileSync11, writeFileSync as writeFileSync6, existsSync as existsSync8, copyFileSync } from "fs";
11972
+ import { readFileSync as readFileSync11, writeFileSync as writeFileSync7, existsSync as existsSync8, copyFileSync } from "fs";
11950
11973
  import { resolve as resolve7 } from "path";
11951
11974
  import { execSync } from "child_process";
11952
11975
  function parseInjectArgs(argv) {
@@ -12254,7 +12277,7 @@ async function main2() {
12254
12277
  log3("");
12255
12278
  log3(` Backup: ${backupPath}`);
12256
12279
  }
12257
- writeFileSync6(entryFile, result.modified);
12280
+ writeFileSync7(entryFile, result.modified);
12258
12281
  log3("");
12259
12282
  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");
12260
12283
  log3(" \u2502 SolonGate SDK injected successfully! \u2502");
@@ -12283,8 +12306,8 @@ var init_inject = __esm({
12283
12306
 
12284
12307
  // src/create.ts
12285
12308
  var create_exports = {};
12286
- import { mkdirSync as mkdirSync5, writeFileSync as writeFileSync7, existsSync as existsSync9 } from "fs";
12287
- import { resolve as resolve8, join as join12 } from "path";
12309
+ import { mkdirSync as mkdirSync6, writeFileSync as writeFileSync8, existsSync as existsSync9 } from "fs";
12310
+ import { resolve as resolve8, join as join13 } from "path";
12288
12311
  import { execSync as execSync2 } from "child_process";
12289
12312
  function withSpinner(message, fn) {
12290
12313
  const frames = ["\u28FE", "\u28FD", "\u28FB", "\u28BF", "\u287F", "\u28DF", "\u28EF", "\u28F7"];
@@ -12363,8 +12386,8 @@ EXAMPLES
12363
12386
  `);
12364
12387
  }
12365
12388
  function createProject(dir, name, _policy) {
12366
- writeFileSync7(
12367
- join12(dir, "package.json"),
12389
+ writeFileSync8(
12390
+ join13(dir, "package.json"),
12368
12391
  JSON.stringify(
12369
12392
  {
12370
12393
  name,
@@ -12393,8 +12416,8 @@ function createProject(dir, name, _policy) {
12393
12416
  2
12394
12417
  ) + "\n"
12395
12418
  );
12396
- writeFileSync7(
12397
- join12(dir, "tsconfig.json"),
12419
+ writeFileSync8(
12420
+ join13(dir, "tsconfig.json"),
12398
12421
  JSON.stringify(
12399
12422
  {
12400
12423
  compilerOptions: {
@@ -12414,9 +12437,9 @@ function createProject(dir, name, _policy) {
12414
12437
  2
12415
12438
  ) + "\n"
12416
12439
  );
12417
- mkdirSync5(join12(dir, "src"), { recursive: true });
12418
- writeFileSync7(
12419
- join12(dir, "src", "index.ts"),
12440
+ mkdirSync6(join13(dir, "src"), { recursive: true });
12441
+ writeFileSync8(
12442
+ join13(dir, "src", "index.ts"),
12420
12443
  `#!/usr/bin/env node
12421
12444
 
12422
12445
  console.log = (...args: unknown[]) => {
@@ -12457,8 +12480,8 @@ console.log('');
12457
12480
  console.log('Press Ctrl+C to stop.');
12458
12481
  `
12459
12482
  );
12460
- writeFileSync7(
12461
- join12(dir, ".mcp.json"),
12483
+ writeFileSync8(
12484
+ join13(dir, ".mcp.json"),
12462
12485
  JSON.stringify(
12463
12486
  {
12464
12487
  mcpServers: {
@@ -12475,13 +12498,13 @@ console.log('Press Ctrl+C to stop.');
12475
12498
  2
12476
12499
  ) + "\n"
12477
12500
  );
12478
- writeFileSync7(
12479
- join12(dir, ".env"),
12501
+ writeFileSync8(
12502
+ join13(dir, ".env"),
12480
12503
  `SOLONGATE_API_KEY=sg_live_YOUR_KEY_HERE
12481
12504
  `
12482
12505
  );
12483
- writeFileSync7(
12484
- join12(dir, ".gitignore"),
12506
+ writeFileSync8(
12507
+ join13(dir, ".gitignore"),
12485
12508
  `node_modules/
12486
12509
  dist/
12487
12510
  *.solongate-backup
@@ -12500,7 +12523,7 @@ async function main3() {
12500
12523
  process.exit(1);
12501
12524
  }
12502
12525
  withSpinner(`Setting up ${opts.name}...`, () => {
12503
- mkdirSync5(dir, { recursive: true });
12526
+ mkdirSync6(dir, { recursive: true });
12504
12527
  createProject(dir, opts.name, opts.policy);
12505
12528
  });
12506
12529
  if (!opts.noInstall) {
@@ -12574,7 +12597,7 @@ var init_create = __esm({
12574
12597
 
12575
12598
  // src/pull-push.ts
12576
12599
  var pull_push_exports = {};
12577
- import { readFileSync as readFileSync12, writeFileSync as writeFileSync8, existsSync as existsSync10 } from "fs";
12600
+ import { readFileSync as readFileSync12, writeFileSync as writeFileSync9, existsSync as existsSync10 } from "fs";
12578
12601
  import { resolve as resolve9 } from "path";
12579
12602
  function loadEnv() {
12580
12603
  if (process.env.SOLONGATE_API_KEY) return;
@@ -12769,7 +12792,7 @@ async function pull(apiKey, file, policyId) {
12769
12792
  const policy = await fetchCloudPolicy(apiKey, API_URL, policyId);
12770
12793
  const { id: _id, ...policyWithoutId } = policy;
12771
12794
  const json = JSON.stringify(policyWithoutId, null, 2) + "\n";
12772
- writeFileSync8(file, json, "utf-8");
12795
+ writeFileSync9(file, json, "utf-8");
12773
12796
  log5("");
12774
12797
  log5(green2(" Saved to: ") + file);
12775
12798
  log5(` ${dim2("Name:")} ${policy.name}`);
package/dist/tui/index.js CHANGED
@@ -2214,6 +2214,9 @@ function RegexTest({ re }) {
2214
2214
  // src/tui/panels/Audit.tsx
2215
2215
  import { Box as Box6, Text as Text6, useInput as useInput5 } from "ink";
2216
2216
  import TextInput4 from "ink-text-input";
2217
+ import { mkdirSync as mkdirSync2, writeFileSync as writeFileSync3 } from "fs";
2218
+ import { homedir as homedir5 } from "os";
2219
+ import { join as join5 } from "path";
2217
2220
  import { useState as useState6 } from "react";
2218
2221
  import { Fragment as Fragment4, jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
2219
2222
  var DECISIONS = [void 0, "DENY", "ALLOW"];
@@ -2266,8 +2269,10 @@ var AUDIT_HELP = [
2266
2269
  ["g", "signal filter: all \u2192 dlp \u2192 ratelimit"],
2267
2270
  ["t / n", "tool / agent filter (type, enter done)"],
2268
2271
  ["/", "free-text search"],
2269
- ["x", "delete the selected entry (press x twice)"],
2270
- ["X", "delete ALL logs of the current source (press X twice)"],
2272
+ ["x", "delete ONLY the selected entry (press x twice)"],
2273
+ ["X", "delete ALL matched logs of the source (press X twice)"],
2274
+ ["e", "export this page \u2192 ~/.solongate/audit-export-<src>.jsonl"],
2275
+ ["E", "export ALL matched rows (cloud: up to 10k)"],
2271
2276
  ["c", "clear every filter (incl. session)"]
2272
2277
  ]
2273
2278
  ],
@@ -2342,26 +2347,25 @@ function AuditPanel({ active: active2, focused }) {
2342
2347
  usePoll(cloudQ.reloadQuiet, 6e3, active2 && source === "cloud" && view === "logs" && !editing && page === 0);
2343
2348
  const localQ = useLoader(() => source === "local" ? Promise.resolve(loadLocalRows()) : Promise.resolve(null), [source]);
2344
2349
  usePoll(localQ.reloadQuiet, 6e3, active2 && source === "local" && view === "logs" && !editing && page === 0);
2350
+ const q = search.trim().toLowerCase();
2351
+ const localFiltered = (localQ.data ?? []).filter((r) => {
2352
+ if (DECISIONS[di] && r.decision !== DECISIONS[di]) return false;
2353
+ if (SIGNALS[gi] === "dlp" && r.dlp.length === 0) return false;
2354
+ if (SIGNALS[gi] === "ratelimit" && !r.burst) return false;
2355
+ if (tool && !r.tool.toLowerCase().includes(tool.toLowerCase())) return false;
2356
+ if (agent && (r.agent ?? "").toLowerCase() !== agent.toLowerCase()) return false;
2357
+ if (sessFilter && r.session !== sessFilter) return false;
2358
+ if (q && !`${r.tool} ${r.agent ?? ""} ${r.reason ?? ""} ${r.args ?? ""}`.toLowerCase().includes(q)) return false;
2359
+ return true;
2360
+ });
2345
2361
  let pageRows = [];
2346
2362
  let total = 0;
2347
2363
  if (source === "cloud") {
2348
2364
  pageRows = (cloudQ.data?.entries ?? []).map(cloudRow).sort((a, b) => b.at - a.at);
2349
2365
  total = cloudQ.data?.total ?? 0;
2350
2366
  } else {
2351
- const all = localQ.data ?? [];
2352
- const q = search.trim().toLowerCase();
2353
- const filtered = all.filter((r) => {
2354
- if (DECISIONS[di] && r.decision !== DECISIONS[di]) return false;
2355
- if (SIGNALS[gi] === "dlp" && r.dlp.length === 0) return false;
2356
- if (SIGNALS[gi] === "ratelimit" && !r.burst) return false;
2357
- if (tool && !r.tool.toLowerCase().includes(tool.toLowerCase())) return false;
2358
- if (agent && (r.agent ?? "").toLowerCase() !== agent.toLowerCase()) return false;
2359
- if (sessFilter && r.session !== sessFilter) return false;
2360
- if (q && !`${r.tool} ${r.agent ?? ""} ${r.reason ?? ""} ${r.args ?? ""}`.toLowerCase().includes(q)) return false;
2361
- return true;
2362
- });
2363
- total = filtered.length;
2364
- pageRows = filtered.slice(page * PAGE, page * PAGE + PAGE);
2367
+ total = localFiltered.length;
2368
+ pageRows = localFiltered.slice(page * PAGE, page * PAGE + PAGE);
2365
2369
  }
2366
2370
  const pages = Math.max(1, Math.ceil(total / PAGE));
2367
2371
  const current = pageRows[Math.min(sel, Math.max(0, pageRows.length - 1))];
@@ -2428,6 +2432,23 @@ function AuditPanel({ active: active2, focused }) {
2428
2432
  toTop();
2429
2433
  }).catch((e) => setMsg({ text: "\u2717 " + (e instanceof Error ? e.message : String(e)), level: "bad" }));
2430
2434
  };
2435
+ const doExport = (kind) => {
2436
+ setMsg({ text: "exporting\u2026", level: "ok" });
2437
+ const run = async () => {
2438
+ const dir = join5(homedir5(), ".solongate");
2439
+ const file = join5(dir, `audit-export-${source}.jsonl`);
2440
+ let rows2;
2441
+ if (kind === "page") rows2 = pageRows;
2442
+ else if (source === "cloud") {
2443
+ const r = await api.audit.list({ ...query, limit: 1e4, offset: 0 });
2444
+ rows2 = r.entries.map(cloudRow).sort((a, b) => b.at - a.at);
2445
+ } else rows2 = localFiltered;
2446
+ mkdirSync2(dir, { recursive: true });
2447
+ writeFileSync3(file, rows2.map((x) => JSON.stringify(x)).join("\n") + (rows2.length ? "\n" : ""));
2448
+ return { n: rows2.length, file };
2449
+ };
2450
+ run().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" }));
2451
+ };
2431
2452
  useInput5(
2432
2453
  (input, key) => {
2433
2454
  if (showHelp) {
@@ -2516,7 +2537,7 @@ function AuditPanel({ active: active2, focused }) {
2516
2537
  if (!current) return;
2517
2538
  if (confirm?.kind !== "one" || confirm.key !== current.id) {
2518
2539
  setConfirm({ kind: "one", key: current.id });
2519
- setMsg({ text: `delete ${current.decision} ${current.tool} (${ago(current.at)} ago)? press x again`, level: "bad" });
2540
+ setMsg({ text: `x = delete ONLY the selected entry: ${current.decision} ${current.tool} (${ago(current.at)} ago) \u2014 press x again`, level: "bad" });
2520
2541
  return;
2521
2542
  }
2522
2543
  setConfirm(null);
@@ -2524,12 +2545,14 @@ function AuditPanel({ active: active2, focused }) {
2524
2545
  } else if (input === "X") {
2525
2546
  if (confirm?.kind !== "all") {
2526
2547
  setConfirm({ kind: "all", key: "all" });
2527
- setMsg({ text: `DELETE ALL ${source} logs (${total} entries)? press X again`, level: "bad" });
2548
+ setMsg({ text: `\u26A0 X = delete ALL ${source} logs \u2014 every one of the ${total} matched entries! press X again`, level: "bad" });
2528
2549
  return;
2529
2550
  }
2530
2551
  setConfirm(null);
2531
2552
  doDelete("all");
2532
- } else if (input === "t") setEditing("tool");
2553
+ } else if (input === "e") doExport("page");
2554
+ else if (input === "E") doExport("all");
2555
+ else if (input === "t") setEditing("tool");
2533
2556
  else if (input === "n") setEditing("agent");
2534
2557
  else if (input === "/") setEditing("search");
2535
2558
  else if (input === "c") {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solongate/proxy",
3
- "version": "0.81.27",
3
+ "version": "0.81.28",
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": {