@solongate/proxy 0.71.0 → 0.72.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
@@ -7170,6 +7170,9 @@ function LivePanel({ active: active2 }) {
7170
7170
  const seenRef = useRef2(/* @__PURE__ */ new Set());
7171
7171
  const lastLocalTs = useRef2(0);
7172
7172
  const pausedUntil = useRef2(0);
7173
+ const [frozen, setFrozen] = useState2(false);
7174
+ const frozenRef = useRef2(false);
7175
+ frozenRef.current = frozen;
7173
7176
  const pushLog = useCallback2((msg, level = "ok") => {
7174
7177
  setLog((prev) => [...prev.slice(-59), { ts: Date.now(), msg, level }]);
7175
7178
  }, []);
@@ -7185,8 +7188,9 @@ function LivePanel({ active: active2 }) {
7185
7188
  },
7186
7189
  [pushLog]
7187
7190
  );
7188
- const paused = () => Date.now() < pausedUntil.current;
7191
+ const paused = () => frozenRef.current || Date.now() < pausedUntil.current;
7189
7192
  const pollLocal = useCallback2(() => {
7193
+ if (frozenRef.current) return;
7190
7194
  const lines = tailLines(LOCAL_LOG);
7191
7195
  if (!lines.length) {
7192
7196
  setLocalOn((prev) => prev === null ? false : prev);
@@ -7252,6 +7256,7 @@ function LivePanel({ active: active2 }) {
7252
7256
  const t0 = Date.now();
7253
7257
  try {
7254
7258
  const fd = await api.audit.list({ limit: 50 });
7259
+ if (frozenRef.current) return;
7255
7260
  const ms = Date.now() - t0;
7256
7261
  setLat((l) => [...l, ms].slice(-240));
7257
7262
  const fresh = fd.entries.filter((e) => !seenRef.current.has(e.id));
@@ -7269,7 +7274,8 @@ function LivePanel({ active: active2 }) {
7269
7274
  const pollMedium = useCallback2(async () => {
7270
7275
  if (paused()) return;
7271
7276
  try {
7272
- setS(await api.stats.get());
7277
+ const sd = await api.stats.get();
7278
+ if (!frozenRef.current) setS(sd);
7273
7279
  } catch (e) {
7274
7280
  onApiError(e);
7275
7281
  }
@@ -7277,7 +7283,8 @@ function LivePanel({ active: active2 }) {
7277
7283
  const pollSlow = useCallback2(async () => {
7278
7284
  if (paused()) return;
7279
7285
  try {
7280
- setTsData(await api.stats.timeseries({ period: "24h" }));
7286
+ const td = await api.stats.timeseries({ period: "24h" });
7287
+ if (!frozenRef.current) setTsData(td);
7281
7288
  } catch (e) {
7282
7289
  onApiError(e);
7283
7290
  }
@@ -7323,10 +7330,10 @@ function LivePanel({ active: active2 }) {
7323
7330
  }, [detail]);
7324
7331
  const [tick, setTick] = useState2(0);
7325
7332
  useEffect2(() => {
7326
- if (!active2) return;
7333
+ if (!active2 || frozen) return;
7327
7334
  const t = setInterval(() => setTick((n) => n + 1), 500);
7328
7335
  return () => clearInterval(t);
7329
- }, [active2]);
7336
+ }, [active2, frozen]);
7330
7337
  const startRef = useRef2(Date.now());
7331
7338
  const cols = process.stdout.columns ?? 100;
7332
7339
  const rows = process.stdout.rows ?? 30;
@@ -7448,6 +7455,11 @@ function LivePanel({ active: active2 }) {
7448
7455
  } else if (input === "s" || key.leftArrow) setMode("stream");
7449
7456
  return;
7450
7457
  }
7458
+ if (input === " ") {
7459
+ setFrozen((f) => !f);
7460
+ return;
7461
+ }
7462
+ if (frozen) return;
7451
7463
  if (input === "f") {
7452
7464
  setFilter((f) => FILTERS[(FILTERS.indexOf(f) + 1) % FILTERS.length]);
7453
7465
  setScroll(0);
@@ -7486,7 +7498,7 @@ function LivePanel({ active: active2 }) {
7486
7498
  const titleBar = /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
7487
7499
  /* @__PURE__ */ jsx2(Text2, { backgroundColor: "#1432A0", color: "#AAC8FA", bold: true, children: " SOLONGATE LIVE " }),
7488
7500
  /* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", children: ` ${spin} up ${fmtUp(nowMs - startRef.current)} \xB7 ${hhmmss(nowMs)} \xB7 api ${latNow}ms ` }),
7489
- 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 " }),
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 " }),
7490
7502
  toast && nowMs < toast.until ? /* @__PURE__ */ jsx2(Text2, { backgroundColor: "#123d1f", color: "#7bd88f", bold: true, children: ` ${toast.msg} ` }) : null
7491
7503
  ] });
7492
7504
  if (mode === "detail" && detail) {
@@ -7670,7 +7682,7 @@ function LivePanel({ active: active2 }) {
7670
7682
  /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
7671
7683
  /* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", bold: true, children: " LIVE " }),
7672
7684
  /* @__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"} ` }),
7673
- /* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", children: " f filter \xB7 s sessions \xB7 c copy \xB7 esc menu \xB7 q quit " })
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 " })
7674
7686
  ] })
7675
7687
  ] });
7676
7688
  }
package/dist/tui/index.js CHANGED
@@ -596,6 +596,9 @@ function LivePanel({ active: active2 }) {
596
596
  const seenRef = useRef2(/* @__PURE__ */ new Set());
597
597
  const lastLocalTs = useRef2(0);
598
598
  const pausedUntil = useRef2(0);
599
+ const [frozen, setFrozen] = useState2(false);
600
+ const frozenRef = useRef2(false);
601
+ frozenRef.current = frozen;
599
602
  const pushLog = useCallback2((msg, level = "ok") => {
600
603
  setLog((prev) => [...prev.slice(-59), { ts: Date.now(), msg, level }]);
601
604
  }, []);
@@ -611,8 +614,9 @@ function LivePanel({ active: active2 }) {
611
614
  },
612
615
  [pushLog]
613
616
  );
614
- const paused = () => Date.now() < pausedUntil.current;
617
+ const paused = () => frozenRef.current || Date.now() < pausedUntil.current;
615
618
  const pollLocal = useCallback2(() => {
619
+ if (frozenRef.current) return;
616
620
  const lines = tailLines(LOCAL_LOG);
617
621
  if (!lines.length) {
618
622
  setLocalOn((prev) => prev === null ? false : prev);
@@ -678,6 +682,7 @@ function LivePanel({ active: active2 }) {
678
682
  const t0 = Date.now();
679
683
  try {
680
684
  const fd = await api.audit.list({ limit: 50 });
685
+ if (frozenRef.current) return;
681
686
  const ms = Date.now() - t0;
682
687
  setLat((l) => [...l, ms].slice(-240));
683
688
  const fresh = fd.entries.filter((e) => !seenRef.current.has(e.id));
@@ -695,7 +700,8 @@ function LivePanel({ active: active2 }) {
695
700
  const pollMedium = useCallback2(async () => {
696
701
  if (paused()) return;
697
702
  try {
698
- setS(await api.stats.get());
703
+ const sd = await api.stats.get();
704
+ if (!frozenRef.current) setS(sd);
699
705
  } catch (e) {
700
706
  onApiError(e);
701
707
  }
@@ -703,7 +709,8 @@ function LivePanel({ active: active2 }) {
703
709
  const pollSlow = useCallback2(async () => {
704
710
  if (paused()) return;
705
711
  try {
706
- setTsData(await api.stats.timeseries({ period: "24h" }));
712
+ const td = await api.stats.timeseries({ period: "24h" });
713
+ if (!frozenRef.current) setTsData(td);
707
714
  } catch (e) {
708
715
  onApiError(e);
709
716
  }
@@ -749,10 +756,10 @@ function LivePanel({ active: active2 }) {
749
756
  }, [detail]);
750
757
  const [tick, setTick] = useState2(0);
751
758
  useEffect2(() => {
752
- if (!active2) return;
759
+ if (!active2 || frozen) return;
753
760
  const t = setInterval(() => setTick((n) => n + 1), 500);
754
761
  return () => clearInterval(t);
755
- }, [active2]);
762
+ }, [active2, frozen]);
756
763
  const startRef = useRef2(Date.now());
757
764
  const cols = process.stdout.columns ?? 100;
758
765
  const rows = process.stdout.rows ?? 30;
@@ -874,6 +881,11 @@ function LivePanel({ active: active2 }) {
874
881
  } else if (input === "s" || key.leftArrow) setMode("stream");
875
882
  return;
876
883
  }
884
+ if (input === " ") {
885
+ setFrozen((f) => !f);
886
+ return;
887
+ }
888
+ if (frozen) return;
877
889
  if (input === "f") {
878
890
  setFilter((f) => FILTERS[(FILTERS.indexOf(f) + 1) % FILTERS.length]);
879
891
  setScroll(0);
@@ -912,7 +924,7 @@ function LivePanel({ active: active2 }) {
912
924
  const titleBar = /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
913
925
  /* @__PURE__ */ jsx2(Text2, { backgroundColor: "#1432A0", color: "#AAC8FA", bold: true, children: " SOLONGATE LIVE " }),
914
926
  /* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", children: ` ${spin} up ${fmtUp(nowMs - startRef.current)} \xB7 ${hhmmss(nowMs)} \xB7 api ${latNow}ms ` }),
915
- 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 " }),
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 " }),
916
928
  toast && nowMs < toast.until ? /* @__PURE__ */ jsx2(Text2, { backgroundColor: "#123d1f", color: "#7bd88f", bold: true, children: ` ${toast.msg} ` }) : null
917
929
  ] });
918
930
  if (mode === "detail" && detail) {
@@ -1096,7 +1108,7 @@ function LivePanel({ active: active2 }) {
1096
1108
  /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
1097
1109
  /* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", bold: true, children: " LIVE " }),
1098
1110
  /* @__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"} ` }),
1099
- /* @__PURE__ */ jsx2(Text2, { backgroundColor: BG, color: "#82AAF0", children: " f filter \xB7 s sessions \xB7 c copy \xB7 esc menu \xB7 q quit " })
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 " })
1100
1112
  ] })
1101
1113
  ] });
1102
1114
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solongate/proxy",
3
- "version": "0.71.0",
3
+ "version": "0.72.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": {