@solongate/proxy 0.72.0 → 0.74.0

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
@@ -7030,10 +7030,9 @@ var init_hooks = __esm({
7030
7030
 
7031
7031
  // src/tui/panels/Live.tsx
7032
7032
  import { Box as Box2, Text as Text2, useInput } from "ink";
7033
- import { spawnSync } from "child_process";
7034
- import { closeSync, mkdirSync as mkdirSync3, openSync, readSync, statSync, writeFileSync as writeFileSync3 } from "fs";
7033
+ import { closeSync, openSync, readSync, statSync } from "fs";
7035
7034
  import { homedir as homedir3 } from "os";
7036
- import { dirname, join as join5 } from "path";
7035
+ import { join as join5 } from "path";
7037
7036
  import { useCallback as useCallback2, useEffect as useEffect2, useRef as useRef2, useState as useState2 } from "react";
7038
7037
  import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
7039
7038
  function tailLines(file, maxBytes = 131072) {
@@ -7051,22 +7050,6 @@ function tailLines(file, maxBytes = 131072) {
7051
7050
  return [];
7052
7051
  }
7053
7052
  }
7054
- function copyToClipboard(text) {
7055
- const tools = [
7056
- ["wl-copy", []],
7057
- ["xclip", ["-selection", "clipboard"]],
7058
- ["xsel", ["--clipboard", "--input"]]
7059
- ];
7060
- for (const [cmd, args] of tools) {
7061
- try {
7062
- const r = spawnSync(cmd, args, { input: text, timeout: 2e3 });
7063
- if (r.status === 0) return cmd;
7064
- } catch {
7065
- }
7066
- }
7067
- process.stdout.write(`\x1B]52;c;${Buffer.from(text, "utf-8").toString("base64")}\x07`);
7068
- return null;
7069
- }
7070
7053
  function cloudItem(e) {
7071
7054
  return {
7072
7055
  id: "c:" + e.id,
@@ -7161,7 +7144,6 @@ function LivePanel({ active: active2 }) {
7161
7144
  const [log6, setLog] = useState2([]);
7162
7145
  const [filter, setFilter] = useState2("all");
7163
7146
  const [scroll, setScroll] = useState2(0);
7164
- const [toast, setToast] = useState2(null);
7165
7147
  const [mode, setMode] = useState2("stream");
7166
7148
  const [pickIdx, setPickIdx] = useState2(0);
7167
7149
  const [detail, setDetail] = useState2(null);
@@ -7348,24 +7330,24 @@ function LivePanel({ active: active2 }) {
7348
7330
  const cloudDeduped = cloudBuf.filter((e) => !localKeys.has(`${e.tool}|${e.decision}|${Math.round(e.at / 6e4)}`));
7349
7331
  const mergedAll = [...cloudDeduped, ...localBuf].sort((a, b) => a.at - b.at);
7350
7332
  const points = tsData?.timeseries ?? [];
7351
- const nowMin = Math.floor(nowMs / 6e4);
7352
- const minuteCounts = new Array(60).fill(0);
7353
- const minuteHot = new Array(60).fill(false);
7333
+ const nowSlot = Math.floor(nowMs / 1e4);
7334
+ const slotCounts = new Array(60).fill(0);
7335
+ const slotHot = new Array(60).fill(false);
7354
7336
  for (const e of mergedAll) {
7355
- const idx = 59 - (nowMin - Math.floor(e.at / 6e4));
7337
+ const idx = 59 - (nowSlot - Math.floor(e.at / 1e4));
7356
7338
  if (idx >= 0 && idx < 60) {
7357
- minuteCounts[idx]++;
7358
- if (e.decision !== "ALLOW") minuteHot[idx] = true;
7339
+ slotCounts[idx]++;
7340
+ if (e.decision !== "ALLOW") slotHot[idx] = true;
7359
7341
  }
7360
7342
  }
7361
- const localTraffic = localOn === true && minuteCounts.some((c2) => c2 > 0);
7362
- const traffic = localTraffic ? minuteCounts : points.map((p) => p.total);
7363
- const trafficHot = localTraffic ? minuteHot : points.map((p) => p.denied > 0);
7364
- const trafficLabel = localTraffic ? "calls/min \xB7 60m \xB7 local+cloud" : "24h \xB7 cloud";
7343
+ const localTraffic = localOn === true && slotCounts.some((c2) => c2 > 0);
7344
+ const traffic = localTraffic ? slotCounts : points.map((p) => p.total);
7345
+ const trafficHot = localTraffic ? slotHot : points.map((p) => p.denied > 0);
7346
+ const trafficLabel = localTraffic ? "calls/10s \xB7 last 10m" : "24h \xB7 cloud";
7365
7347
  const rl = ins.layers?.rateLimit;
7366
7348
  const dl = ins.layers?.dlp;
7367
7349
  const gh = ins.layers?.ghost;
7368
- const minuteNow = minuteCounts[59] ?? 0;
7350
+ const minuteNow = mergedAll.filter((e) => nowMs - e.at < 6e4).length;
7369
7351
  const dlpBars = (ins.dlpByPattern ?? []).slice(0, 2);
7370
7352
  const maxDlpBar = dlpBars[0]?.count ?? 1;
7371
7353
  const denialsAll = mergedAll.filter((e) => e.decision !== "ALLOW");
@@ -7470,20 +7452,6 @@ function LivePanel({ active: active2 }) {
7470
7452
  else if (key.upArrow) setScroll((n) => Math.max(0, n - 1));
7471
7453
  else if (key.pageDown) setScroll((n) => Math.min(maxScroll, n + streamRows));
7472
7454
  else if (key.pageUp) setScroll((n) => Math.max(0, n - streamRows));
7473
- else if (input === "c") {
7474
- const dump = visibleDesc.map(
7475
- (e) => `[${new Date(e.at).toISOString()}] ${e.source.toUpperCase().padEnd(5)} ${e.decision.padEnd(6)} ${e.tool.padEnd(16)} ${e.permission.padEnd(5)} ${e.evalMs != null ? String(e.evalMs).padStart(5) + "ms " : " "}${(e.agent ?? "-").padEnd(14)} ${e.session ? e.session.slice(0, 8) : "- "} ${e.detail}`
7476
- ).join("\n");
7477
- try {
7478
- mkdirSync3(dirname(DUMP), { recursive: true });
7479
- writeFileSync3(DUMP, dump + "\n");
7480
- } catch {
7481
- }
7482
- const via = copyToClipboard(dump);
7483
- setToast(
7484
- via ? { msg: `\u2713 ${visibleDesc.length} lines in clipboard (${via})`, until: Date.now() + 4e3 } : { msg: "\u2717 no clipboard tool \u2014 install wl-clipboard or xclip", until: Date.now() + 6e3 }
7485
- );
7486
- }
7487
7455
  },
7488
7456
  { isActive: active2 }
7489
7457
  );
@@ -7498,8 +7466,7 @@ function LivePanel({ active: active2 }) {
7498
7466
  const titleBar = /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
7499
7467
  /* @__PURE__ */ jsx2(Text2, { backgroundColor: "#1432A0", color: "#AAC8FA", bold: true, children: " SOLONGATE LIVE " }),
7500
7468
  /* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", children: ` ${spin} up ${fmtUp(nowMs - startRef.current)} \xB7 ${hhmmss(nowMs)} \xB7 api ${latNow}ms ` }),
7501
- frozen ? /* @__PURE__ */ jsx2(Text2, { backgroundColor: "#123d1f", color: "#7bd88f", bold: true, children: " \u23F5 COPY MODE \u2014 screen frozen, select & copy freely \xB7 space resume " }) : backingOff ? /* @__PURE__ */ jsx2(Text2, { backgroundColor: "#3d2a12", color: "#ffb454", bold: true, children: " RATE LIMITED \xB7 backing off " }) : lastDeny ? /* @__PURE__ */ jsx2(Text2, { backgroundColor: "#3d1220", color: "#ff6b6b", bold: true, children: ` \u26A0 ${hhmmss(lastDeny.at)} ${lastDeny.tool} DENIED ` }) : /* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#4f6db8", children: " \u2713 clean " }),
7502
- toast && nowMs < toast.until ? /* @__PURE__ */ jsx2(Text2, { backgroundColor: "#123d1f", color: "#7bd88f", bold: true, children: ` ${toast.msg} ` }) : null
7469
+ frozen ? /* @__PURE__ */ jsx2(Text2, { backgroundColor: "#123d1f", color: "#7bd88f", bold: true, children: " \u23F5 COPY MODE \u2014 screen frozen, select & copy freely \xB7 space resume " }) : backingOff ? /* @__PURE__ */ jsx2(Text2, { backgroundColor: "#3d2a12", color: "#ffb454", bold: true, children: " RATE LIMITED \xB7 backing off " }) : lastDeny ? /* @__PURE__ */ jsx2(Text2, { backgroundColor: "#3d1220", color: "#ff6b6b", bold: true, children: ` \u26A0 ${hhmmss(lastDeny.at)} ${lastDeny.tool} DENIED ` }) : /* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#4f6db8", children: " \u2713 clean " })
7503
7470
  ] });
7504
7471
  if (mode === "detail" && detail) {
7505
7472
  const d = detailEntries;
@@ -7664,7 +7631,7 @@ function LivePanel({ active: active2 }) {
7664
7631
  PaneTitle,
7665
7632
  {
7666
7633
  label: "TOOL STREAM",
7667
- extra: `newest first \xB7 last ${STREAM_KEEP} \xB7 filter ${filter}${clampedScroll > 0 ? ` \xB7 \u25BC${clampedScroll} older` : ""} \xB7 f filter \xB7 \u2191\u2193 scroll \xB7 c copy \xB7 s sessions`,
7634
+ extra: `newest first \xB7 last ${STREAM_KEEP} \xB7 filter ${filter}${clampedScroll > 0 ? ` \xB7 \u25BC${clampedScroll} older` : ""} \xB7 f filter \xB7 \u2191\u2193 scroll \xB7 s sessions`,
7668
7635
  width: innerW
7669
7636
  }
7670
7637
  ),
@@ -7682,11 +7649,11 @@ function LivePanel({ active: active2 }) {
7682
7649
  /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
7683
7650
  /* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", bold: true, children: " LIVE " }),
7684
7651
  /* @__PURE__ */ jsx2(Text2, { backgroundColor: "#0b1530", color: "#4f6db8", children: ` local ${localOn ? "on" : "off"} \xB7 ${localBuf.length} loc/${cloudBuf.length} cld \xB7 top ${topTools.map(([t, c2]) => `${t}\xD7${c2}`).join(" ") || "\u2014"} ` }),
7685
- /* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", children: " space copy-mode \xB7 f filter \xB7 s sessions \xB7 c quick-copy \xB7 esc menu \xB7 q quit " })
7652
+ /* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", children: " space copy-mode \xB7 f filter \xB7 s sessions \xB7 esc menu \xB7 q quit " })
7686
7653
  ] })
7687
7654
  ] });
7688
7655
  }
7689
- var SPIN, BG, DIM_FLOOR, LOCAL_LOG, RING, DUMP, STREAM_KEEP, hhmmss, fmtUp, FILTERS;
7656
+ var SPIN, BG, DIM_FLOOR, LOCAL_LOG, RING, STREAM_KEEP, hhmmss, fmtUp, FILTERS;
7690
7657
  var init_Live = __esm({
7691
7658
  "src/tui/panels/Live.tsx"() {
7692
7659
  "use strict";
@@ -7698,7 +7665,6 @@ var init_Live = __esm({
7698
7665
  DIM_FLOOR = "#233457";
7699
7666
  LOCAL_LOG = join5(homedir3(), ".solongate", "local-logs", "solongate-audit.jsonl");
7700
7667
  RING = join5(process.cwd(), ".solongate", ".eval-ring.jsonl");
7701
- DUMP = join5(homedir3(), ".solongate", "live-stream.log");
7702
7668
  STREAM_KEEP = 100;
7703
7669
  hhmmss = (ts) => {
7704
7670
  const d = new Date(ts);
@@ -9371,8 +9337,8 @@ __export(global_install_exports, {
9371
9337
  runGlobalRestore: () => runGlobalRestore,
9372
9338
  unlockProtected: () => unlockProtected
9373
9339
  });
9374
- import { readFileSync as readFileSync6, writeFileSync as writeFileSync4, existsSync as existsSync4, mkdirSync as mkdirSync4 } from "fs";
9375
- import { resolve as resolve4, join as join6, dirname as dirname2 } from "path";
9340
+ import { readFileSync as readFileSync6, writeFileSync as writeFileSync3, existsSync as existsSync4, mkdirSync as mkdirSync3 } from "fs";
9341
+ import { resolve as resolve4, join as join6, dirname } from "path";
9376
9342
  import { homedir as homedir4 } from "os";
9377
9343
  import { fileURLToPath } from "url";
9378
9344
  import { createInterface } from "readline";
@@ -9484,13 +9450,13 @@ function runGlobalRestore() {
9484
9450
  unlockProtected();
9485
9451
  removeClaudeShim();
9486
9452
  if (existsSync4(p.backupPath)) {
9487
- writeFileSync4(p.settingsPath, readFileSync6(p.backupPath, "utf-8"));
9453
+ writeFileSync3(p.settingsPath, readFileSync6(p.backupPath, "utf-8"));
9488
9454
  console.log(` Restored ${p.settingsPath} from backup.`);
9489
9455
  } else if (existsSync4(p.settingsPath)) {
9490
9456
  try {
9491
9457
  const s = JSON.parse(readFileSync6(p.settingsPath, "utf-8"));
9492
9458
  delete s.hooks;
9493
- writeFileSync4(p.settingsPath, JSON.stringify(s, null, 2) + "\n");
9459
+ writeFileSync3(p.settingsPath, JSON.stringify(s, null, 2) + "\n");
9494
9460
  console.log(` Removed SolonGate hooks from ${p.settingsPath}.`);
9495
9461
  } catch {
9496
9462
  }
@@ -9534,8 +9500,8 @@ function writeShimBlock(file, block) {
9534
9500
  if (content.length && !content.endsWith("\n")) content += "\n";
9535
9501
  content += block + "\n";
9536
9502
  }
9537
- mkdirSync4(dirname2(file), { recursive: true });
9538
- writeFileSync4(file, content);
9503
+ mkdirSync3(dirname(file), { recursive: true });
9504
+ writeFileSync3(file, content);
9539
9505
  }
9540
9506
  function installClaudeShim(shieldPath) {
9541
9507
  const real = resolveRealClaude();
@@ -9592,22 +9558,22 @@ async function runGlobalInstall(opts = {}) {
9592
9558
  process.exit(1);
9593
9559
  }
9594
9560
  const apiUrl = opts.apiUrl || process.env["SOLONGATE_API_URL"] || "https://api.solongate.com";
9595
- mkdirSync4(p.hooksDir, { recursive: true });
9596
- mkdirSync4(p.claudeDir, { recursive: true });
9561
+ mkdirSync3(p.hooksDir, { recursive: true });
9562
+ mkdirSync3(p.claudeDir, { recursive: true });
9597
9563
  unlockProtected();
9598
- writeFileSync4(join6(p.hooksDir, "guard.mjs"), readGuard());
9599
- writeFileSync4(join6(p.hooksDir, "audit.mjs"), readHook("audit.mjs"));
9600
- writeFileSync4(join6(p.hooksDir, "stop.mjs"), readHook("stop.mjs"));
9601
- writeFileSync4(join6(p.hooksDir, "shield.mjs"), readHook("shield.mjs"));
9564
+ writeFileSync3(join6(p.hooksDir, "guard.mjs"), readGuard());
9565
+ writeFileSync3(join6(p.hooksDir, "audit.mjs"), readHook("audit.mjs"));
9566
+ writeFileSync3(join6(p.hooksDir, "stop.mjs"), readHook("stop.mjs"));
9567
+ writeFileSync3(join6(p.hooksDir, "shield.mjs"), readHook("shield.mjs"));
9602
9568
  console.log(` Installed hooks \u2192 ${p.hooksDir}`);
9603
9569
  removeClaudeShim();
9604
- writeFileSync4(p.configPath, JSON.stringify({ apiKey, apiUrl }, null, 2) + "\n");
9570
+ writeFileSync3(p.configPath, JSON.stringify({ apiKey, apiUrl }, null, 2) + "\n");
9605
9571
  console.log(` Wrote ${p.configPath}`);
9606
9572
  let existing = {};
9607
9573
  if (existsSync4(p.settingsPath)) {
9608
9574
  const raw = readFileSync6(p.settingsPath, "utf-8");
9609
9575
  if (!existsSync4(p.backupPath)) {
9610
- writeFileSync4(p.backupPath, raw);
9576
+ writeFileSync3(p.backupPath, raw);
9611
9577
  console.log(` Backed up existing settings \u2192 ${p.backupPath}`);
9612
9578
  }
9613
9579
  try {
@@ -9628,7 +9594,7 @@ async function runGlobalInstall(opts = {}) {
9628
9594
  Stop: [{ matcher: "", hooks: [{ type: "command", command: `"${nodeBin}" "${stopAbs}" claude-code "Claude Code"` }] }]
9629
9595
  }
9630
9596
  };
9631
- writeFileSync4(p.settingsPath, JSON.stringify(merged, null, 2) + "\n");
9597
+ writeFileSync3(p.settingsPath, JSON.stringify(merged, null, 2) + "\n");
9632
9598
  console.log(` Registered global hooks \u2192 ${p.settingsPath}`);
9633
9599
  if (process.env["SOLONGATE_OS_LOCK"] === "1") {
9634
9600
  lockProtected();
@@ -9642,7 +9608,7 @@ var __dirname, HOOKS_DIR, SHIM_BEGIN, SHIM_END;
9642
9608
  var init_global_install = __esm({
9643
9609
  "src/global-install.ts"() {
9644
9610
  "use strict";
9645
- __dirname = dirname2(fileURLToPath(import.meta.url));
9611
+ __dirname = dirname(fileURLToPath(import.meta.url));
9646
9612
  HOOKS_DIR = resolve4(__dirname, "..", "hooks");
9647
9613
  SHIM_BEGIN = "# >>> SolonGate shield (auto secret redaction) >>>";
9648
9614
  SHIM_END = "# <<< SolonGate shield <<<";
@@ -10292,7 +10258,7 @@ var init_logs_server = __esm({
10292
10258
 
10293
10259
  // src/inject.ts
10294
10260
  var inject_exports = {};
10295
- import { readFileSync as readFileSync9, writeFileSync as writeFileSync5, existsSync as existsSync6, copyFileSync } from "fs";
10261
+ import { readFileSync as readFileSync9, writeFileSync as writeFileSync4, existsSync as existsSync6, copyFileSync } from "fs";
10296
10262
  import { resolve as resolve7 } from "path";
10297
10263
  import { execSync } from "child_process";
10298
10264
  function parseInjectArgs(argv) {
@@ -10600,7 +10566,7 @@ async function main2() {
10600
10566
  log3("");
10601
10567
  log3(` Backup: ${backupPath}`);
10602
10568
  }
10603
- writeFileSync5(entryFile, result.modified);
10569
+ writeFileSync4(entryFile, result.modified);
10604
10570
  log3("");
10605
10571
  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");
10606
10572
  log3(" \u2502 SolonGate SDK injected successfully! \u2502");
@@ -10629,7 +10595,7 @@ var init_inject = __esm({
10629
10595
 
10630
10596
  // src/create.ts
10631
10597
  var create_exports = {};
10632
- import { mkdirSync as mkdirSync5, writeFileSync as writeFileSync6, existsSync as existsSync7 } from "fs";
10598
+ import { mkdirSync as mkdirSync4, writeFileSync as writeFileSync5, existsSync as existsSync7 } from "fs";
10633
10599
  import { resolve as resolve8, join as join8 } from "path";
10634
10600
  import { execSync as execSync2 } from "child_process";
10635
10601
  function withSpinner(message, fn) {
@@ -10709,7 +10675,7 @@ EXAMPLES
10709
10675
  `);
10710
10676
  }
10711
10677
  function createProject(dir, name, _policy) {
10712
- writeFileSync6(
10678
+ writeFileSync5(
10713
10679
  join8(dir, "package.json"),
10714
10680
  JSON.stringify(
10715
10681
  {
@@ -10739,7 +10705,7 @@ function createProject(dir, name, _policy) {
10739
10705
  2
10740
10706
  ) + "\n"
10741
10707
  );
10742
- writeFileSync6(
10708
+ writeFileSync5(
10743
10709
  join8(dir, "tsconfig.json"),
10744
10710
  JSON.stringify(
10745
10711
  {
@@ -10760,8 +10726,8 @@ function createProject(dir, name, _policy) {
10760
10726
  2
10761
10727
  ) + "\n"
10762
10728
  );
10763
- mkdirSync5(join8(dir, "src"), { recursive: true });
10764
- writeFileSync6(
10729
+ mkdirSync4(join8(dir, "src"), { recursive: true });
10730
+ writeFileSync5(
10765
10731
  join8(dir, "src", "index.ts"),
10766
10732
  `#!/usr/bin/env node
10767
10733
 
@@ -10803,7 +10769,7 @@ console.log('');
10803
10769
  console.log('Press Ctrl+C to stop.');
10804
10770
  `
10805
10771
  );
10806
- writeFileSync6(
10772
+ writeFileSync5(
10807
10773
  join8(dir, ".mcp.json"),
10808
10774
  JSON.stringify(
10809
10775
  {
@@ -10821,12 +10787,12 @@ console.log('Press Ctrl+C to stop.');
10821
10787
  2
10822
10788
  ) + "\n"
10823
10789
  );
10824
- writeFileSync6(
10790
+ writeFileSync5(
10825
10791
  join8(dir, ".env"),
10826
10792
  `SOLONGATE_API_KEY=sg_live_YOUR_KEY_HERE
10827
10793
  `
10828
10794
  );
10829
- writeFileSync6(
10795
+ writeFileSync5(
10830
10796
  join8(dir, ".gitignore"),
10831
10797
  `node_modules/
10832
10798
  dist/
@@ -10846,7 +10812,7 @@ async function main3() {
10846
10812
  process.exit(1);
10847
10813
  }
10848
10814
  withSpinner(`Setting up ${opts.name}...`, () => {
10849
- mkdirSync5(dir, { recursive: true });
10815
+ mkdirSync4(dir, { recursive: true });
10850
10816
  createProject(dir, opts.name, opts.policy);
10851
10817
  });
10852
10818
  if (!opts.noInstall) {
@@ -10920,7 +10886,7 @@ var init_create = __esm({
10920
10886
 
10921
10887
  // src/pull-push.ts
10922
10888
  var pull_push_exports = {};
10923
- import { readFileSync as readFileSync10, writeFileSync as writeFileSync7, existsSync as existsSync8 } from "fs";
10889
+ import { readFileSync as readFileSync10, writeFileSync as writeFileSync6, existsSync as existsSync8 } from "fs";
10924
10890
  import { resolve as resolve9 } from "path";
10925
10891
  function loadEnv() {
10926
10892
  if (process.env.SOLONGATE_API_KEY) return;
@@ -11115,7 +11081,7 @@ async function pull(apiKey, file, policyId) {
11115
11081
  const policy = await fetchCloudPolicy(apiKey, API_URL, policyId);
11116
11082
  const { id: _id, ...policyWithoutId } = policy;
11117
11083
  const json = JSON.stringify(policyWithoutId, null, 2) + "\n";
11118
- writeFileSync7(file, json, "utf-8");
11084
+ writeFileSync6(file, json, "utf-8");
11119
11085
  log5("");
11120
11086
  log5(green2(" Saved to: ") + file);
11121
11087
  log5(` ${dim2("Name:")} ${policy.name}`);
package/dist/tui/index.js CHANGED
@@ -126,10 +126,9 @@ function KeyHints({ hints }) {
126
126
 
127
127
  // src/tui/panels/Live.tsx
128
128
  import { Box as Box2, Text as Text2, useInput } from "ink";
129
- import { spawnSync } from "child_process";
130
- import { closeSync, mkdirSync, openSync, readSync, statSync, writeFileSync } from "fs";
129
+ import { closeSync, openSync, readSync, statSync } from "fs";
131
130
  import { homedir as homedir2 } from "os";
132
- import { dirname, join as join2 } from "path";
131
+ import { join as join2 } from "path";
133
132
  import { useCallback as useCallback2, useEffect as useEffect2, useRef as useRef2, useState as useState2 } from "react";
134
133
 
135
134
  // src/api-client/client.ts
@@ -450,7 +449,6 @@ var BG = "#12234f";
450
449
  var DIM_FLOOR = "#233457";
451
450
  var LOCAL_LOG = join2(homedir2(), ".solongate", "local-logs", "solongate-audit.jsonl");
452
451
  var RING = join2(process.cwd(), ".solongate", ".eval-ring.jsonl");
453
- var DUMP = join2(homedir2(), ".solongate", "live-stream.log");
454
452
  var STREAM_KEEP = 100;
455
453
  var hhmmss = (ts) => {
456
454
  const d = new Date(ts);
@@ -476,22 +474,6 @@ function tailLines(file, maxBytes = 131072) {
476
474
  return [];
477
475
  }
478
476
  }
479
- function copyToClipboard(text) {
480
- const tools = [
481
- ["wl-copy", []],
482
- ["xclip", ["-selection", "clipboard"]],
483
- ["xsel", ["--clipboard", "--input"]]
484
- ];
485
- for (const [cmd, args] of tools) {
486
- try {
487
- const r = spawnSync(cmd, args, { input: text, timeout: 2e3 });
488
- if (r.status === 0) return cmd;
489
- } catch {
490
- }
491
- }
492
- process.stdout.write(`\x1B]52;c;${Buffer.from(text, "utf-8").toString("base64")}\x07`);
493
- return null;
494
- }
495
477
  function cloudItem(e) {
496
478
  return {
497
479
  id: "c:" + e.id,
@@ -587,7 +569,6 @@ function LivePanel({ active: active2 }) {
587
569
  const [log, setLog] = useState2([]);
588
570
  const [filter, setFilter] = useState2("all");
589
571
  const [scroll, setScroll] = useState2(0);
590
- const [toast, setToast] = useState2(null);
591
572
  const [mode, setMode] = useState2("stream");
592
573
  const [pickIdx, setPickIdx] = useState2(0);
593
574
  const [detail, setDetail] = useState2(null);
@@ -774,24 +755,24 @@ function LivePanel({ active: active2 }) {
774
755
  const cloudDeduped = cloudBuf.filter((e) => !localKeys.has(`${e.tool}|${e.decision}|${Math.round(e.at / 6e4)}`));
775
756
  const mergedAll = [...cloudDeduped, ...localBuf].sort((a, b) => a.at - b.at);
776
757
  const points = tsData?.timeseries ?? [];
777
- const nowMin = Math.floor(nowMs / 6e4);
778
- const minuteCounts = new Array(60).fill(0);
779
- const minuteHot = new Array(60).fill(false);
758
+ const nowSlot = Math.floor(nowMs / 1e4);
759
+ const slotCounts = new Array(60).fill(0);
760
+ const slotHot = new Array(60).fill(false);
780
761
  for (const e of mergedAll) {
781
- const idx = 59 - (nowMin - Math.floor(e.at / 6e4));
762
+ const idx = 59 - (nowSlot - Math.floor(e.at / 1e4));
782
763
  if (idx >= 0 && idx < 60) {
783
- minuteCounts[idx]++;
784
- if (e.decision !== "ALLOW") minuteHot[idx] = true;
764
+ slotCounts[idx]++;
765
+ if (e.decision !== "ALLOW") slotHot[idx] = true;
785
766
  }
786
767
  }
787
- const localTraffic = localOn === true && minuteCounts.some((c2) => c2 > 0);
788
- const traffic = localTraffic ? minuteCounts : points.map((p) => p.total);
789
- const trafficHot = localTraffic ? minuteHot : points.map((p) => p.denied > 0);
790
- const trafficLabel = localTraffic ? "calls/min \xB7 60m \xB7 local+cloud" : "24h \xB7 cloud";
768
+ const localTraffic = localOn === true && slotCounts.some((c2) => c2 > 0);
769
+ const traffic = localTraffic ? slotCounts : points.map((p) => p.total);
770
+ const trafficHot = localTraffic ? slotHot : points.map((p) => p.denied > 0);
771
+ const trafficLabel = localTraffic ? "calls/10s \xB7 last 10m" : "24h \xB7 cloud";
791
772
  const rl = ins.layers?.rateLimit;
792
773
  const dl = ins.layers?.dlp;
793
774
  const gh = ins.layers?.ghost;
794
- const minuteNow = minuteCounts[59] ?? 0;
775
+ const minuteNow = mergedAll.filter((e) => nowMs - e.at < 6e4).length;
795
776
  const dlpBars = (ins.dlpByPattern ?? []).slice(0, 2);
796
777
  const maxDlpBar = dlpBars[0]?.count ?? 1;
797
778
  const denialsAll = mergedAll.filter((e) => e.decision !== "ALLOW");
@@ -896,20 +877,6 @@ function LivePanel({ active: active2 }) {
896
877
  else if (key.upArrow) setScroll((n) => Math.max(0, n - 1));
897
878
  else if (key.pageDown) setScroll((n) => Math.min(maxScroll, n + streamRows));
898
879
  else if (key.pageUp) setScroll((n) => Math.max(0, n - streamRows));
899
- else if (input === "c") {
900
- const dump = visibleDesc.map(
901
- (e) => `[${new Date(e.at).toISOString()}] ${e.source.toUpperCase().padEnd(5)} ${e.decision.padEnd(6)} ${e.tool.padEnd(16)} ${e.permission.padEnd(5)} ${e.evalMs != null ? String(e.evalMs).padStart(5) + "ms " : " "}${(e.agent ?? "-").padEnd(14)} ${e.session ? e.session.slice(0, 8) : "- "} ${e.detail}`
902
- ).join("\n");
903
- try {
904
- mkdirSync(dirname(DUMP), { recursive: true });
905
- writeFileSync(DUMP, dump + "\n");
906
- } catch {
907
- }
908
- const via = copyToClipboard(dump);
909
- setToast(
910
- via ? { msg: `\u2713 ${visibleDesc.length} lines in clipboard (${via})`, until: Date.now() + 4e3 } : { msg: "\u2717 no clipboard tool \u2014 install wl-clipboard or xclip", until: Date.now() + 6e3 }
911
- );
912
- }
913
880
  },
914
881
  { isActive: active2 }
915
882
  );
@@ -924,8 +891,7 @@ function LivePanel({ active: active2 }) {
924
891
  const titleBar = /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
925
892
  /* @__PURE__ */ jsx2(Text2, { backgroundColor: "#1432A0", color: "#AAC8FA", bold: true, children: " SOLONGATE LIVE " }),
926
893
  /* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", children: ` ${spin} up ${fmtUp(nowMs - startRef.current)} \xB7 ${hhmmss(nowMs)} \xB7 api ${latNow}ms ` }),
927
- frozen ? /* @__PURE__ */ jsx2(Text2, { backgroundColor: "#123d1f", color: "#7bd88f", bold: true, children: " \u23F5 COPY MODE \u2014 screen frozen, select & copy freely \xB7 space resume " }) : backingOff ? /* @__PURE__ */ jsx2(Text2, { backgroundColor: "#3d2a12", color: "#ffb454", bold: true, children: " RATE LIMITED \xB7 backing off " }) : lastDeny ? /* @__PURE__ */ jsx2(Text2, { backgroundColor: "#3d1220", color: "#ff6b6b", bold: true, children: ` \u26A0 ${hhmmss(lastDeny.at)} ${lastDeny.tool} DENIED ` }) : /* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#4f6db8", children: " \u2713 clean " }),
928
- toast && nowMs < toast.until ? /* @__PURE__ */ jsx2(Text2, { backgroundColor: "#123d1f", color: "#7bd88f", bold: true, children: ` ${toast.msg} ` }) : null
894
+ frozen ? /* @__PURE__ */ jsx2(Text2, { backgroundColor: "#123d1f", color: "#7bd88f", bold: true, children: " \u23F5 COPY MODE \u2014 screen frozen, select & copy freely \xB7 space resume " }) : backingOff ? /* @__PURE__ */ jsx2(Text2, { backgroundColor: "#3d2a12", color: "#ffb454", bold: true, children: " RATE LIMITED \xB7 backing off " }) : lastDeny ? /* @__PURE__ */ jsx2(Text2, { backgroundColor: "#3d1220", color: "#ff6b6b", bold: true, children: ` \u26A0 ${hhmmss(lastDeny.at)} ${lastDeny.tool} DENIED ` }) : /* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#4f6db8", children: " \u2713 clean " })
929
895
  ] });
930
896
  if (mode === "detail" && detail) {
931
897
  const d = detailEntries;
@@ -1090,7 +1056,7 @@ function LivePanel({ active: active2 }) {
1090
1056
  PaneTitle,
1091
1057
  {
1092
1058
  label: "TOOL STREAM",
1093
- extra: `newest first \xB7 last ${STREAM_KEEP} \xB7 filter ${filter}${clampedScroll > 0 ? ` \xB7 \u25BC${clampedScroll} older` : ""} \xB7 f filter \xB7 \u2191\u2193 scroll \xB7 c copy \xB7 s sessions`,
1059
+ extra: `newest first \xB7 last ${STREAM_KEEP} \xB7 filter ${filter}${clampedScroll > 0 ? ` \xB7 \u25BC${clampedScroll} older` : ""} \xB7 f filter \xB7 \u2191\u2193 scroll \xB7 s sessions`,
1094
1060
  width: innerW
1095
1061
  }
1096
1062
  ),
@@ -1108,7 +1074,7 @@ function LivePanel({ active: active2 }) {
1108
1074
  /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
1109
1075
  /* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", bold: true, children: " LIVE " }),
1110
1076
  /* @__PURE__ */ jsx2(Text2, { backgroundColor: "#0b1530", color: "#4f6db8", children: ` local ${localOn ? "on" : "off"} \xB7 ${localBuf.length} loc/${cloudBuf.length} cld \xB7 top ${topTools.map(([t, c2]) => `${t}\xD7${c2}`).join(" ") || "\u2014"} ` }),
1111
- /* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", children: " space copy-mode \xB7 f filter \xB7 s sessions \xB7 c quick-copy \xB7 esc menu \xB7 q quit " })
1077
+ /* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", children: " space copy-mode \xB7 f filter \xB7 s sessions \xB7 esc menu \xB7 q quit " })
1112
1078
  ] })
1113
1079
  ] });
1114
1080
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solongate/proxy",
3
- "version": "0.72.0",
3
+ "version": "0.74.0",
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": {