@solongate/proxy 0.81.21 → 0.81.23

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
@@ -7356,7 +7356,6 @@ function LivePanel({ active: active2 }) {
7356
7356
  const [actionMsg, setActionMsg] = useState2(null);
7357
7357
  const notifiedRef = useRef2(/* @__PURE__ */ new Set());
7358
7358
  const openedAtRef = useRef2(Date.now());
7359
- const activePolicyRef = useRef2(null);
7360
7359
  const [mode, setMode] = useState2("stream");
7361
7360
  const [pickIdx, setPickIdx] = useState2(0);
7362
7361
  const [detail, setDetail] = useState2(null);
@@ -7680,18 +7679,14 @@ function LivePanel({ active: active2 }) {
7680
7679
  }
7681
7680
  setActionMsg({ text: act === "whitelist" ? "whitelisting\u2026" : "blocking\u2026", level: "ok", until: Date.now() + 4e3 });
7682
7681
  try {
7682
+ const a = await api.policies.active();
7683
+ const pid = a.policy?.id ?? null;
7684
+ if (!pid) throw new Error("no active policy \u2014 rule NOT added. Activate a policy first (Policies section).");
7683
7685
  let res;
7684
7686
  if (e.source === "cloud") {
7685
7687
  const realId = e.id.slice(2);
7686
7688
  res = act === "whitelist" ? await api.audit.whitelist(realId) : await api.audit.block(realId);
7687
7689
  } else {
7688
- let pid = activePolicyRef.current;
7689
- if (!pid) {
7690
- const a = await api.policies.active();
7691
- pid = a.policy?.id ?? null;
7692
- activePolicyRef.current = pid;
7693
- }
7694
- if (!pid) throw new Error("no active policy resolves for this machine");
7695
7690
  const t = extractTarget(e.detail);
7696
7691
  res = await api.policies.addRule(pid, { toolPattern: e.tool, kind: t?.kind ?? "tool", value: t?.value, effect: act === "whitelist" ? "ALLOW" : "DENY" });
7697
7692
  }
@@ -8198,6 +8193,9 @@ function ruleSummary(r) {
8198
8193
  function PoliciesPanel({ focused }) {
8199
8194
  const list6 = useLoader(() => api.policies.list());
8200
8195
  const policies = list6.data?.policies ?? [];
8196
+ const activeQ = useLoader(() => api.policies.active());
8197
+ const activeId = activeQ.data?.policy?.id ?? null;
8198
+ const activeBy = activeQ.data?.matched_by;
8201
8199
  const [view, setView] = useState3("list");
8202
8200
  const [pi, setPi] = useState3(0);
8203
8201
  const [ri, setRi] = useState3(0);
@@ -8270,6 +8268,20 @@ function PoliciesPanel({ focused }) {
8270
8268
  else if (key.return || key.rightArrow) {
8271
8269
  setStatus(null);
8272
8270
  setView("rules");
8271
+ } else if (input === "a") {
8272
+ if (selected) {
8273
+ setStatus("Activating\u2026");
8274
+ void api.policies.setActive(selected.id).then(() => {
8275
+ setStatus(`\u2713 "${selected.name}" is now the ACTIVE policy (pinned) \xB7 reaches agents in ~30s`);
8276
+ activeQ.reload();
8277
+ }).catch((e) => setStatus("\u2717 " + (e instanceof Error ? e.message : String(e))));
8278
+ }
8279
+ } else if (input === "x") {
8280
+ setStatus("Deactivating\u2026");
8281
+ void api.policies.setActive(null).then(() => {
8282
+ setStatus("\u2713 active policy: NONE \u2014 no rules enforced, w/b grants are refused");
8283
+ activeQ.reload();
8284
+ }).catch((e) => setStatus("\u2717 " + (e instanceof Error ? e.message : String(e))));
8273
8285
  }
8274
8286
  return;
8275
8287
  }
@@ -8350,8 +8362,19 @@ function PoliciesPanel({ focused }) {
8350
8362
  { isActive: focused && !editing }
8351
8363
  );
8352
8364
  if (view === "list") {
8365
+ const activeName = activeId ? policies.find((p) => p.id === activeId)?.name ?? activeId : null;
8353
8366
  return /* @__PURE__ */ jsx3(DataView, { loading: list6.loading && !list6.data, error: list6.error, empty: !!list6.data && policies.length === 0, emptyText: "No policies.", children: /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", children: [
8354
- /* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: focused ? "\u2191\u2193 select \xB7 enter open" : "press \u2192 to browse" }),
8367
+ /* @__PURE__ */ jsxs3(Box3, { children: [
8368
+ /* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: "active: " }),
8369
+ activeQ.loading && !activeQ.data ? /* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: "\u2026" }) : activeName ? /* @__PURE__ */ jsxs3(Fragment3, { children: [
8370
+ /* @__PURE__ */ jsxs3(Text3, { color: theme.ok, bold: true, children: [
8371
+ "\u25CF ",
8372
+ truncate2(activeName, 28)
8373
+ ] }),
8374
+ /* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: activeBy ? ` (${activeBy})` : "" })
8375
+ ] }) : /* @__PURE__ */ jsx3(Text3, { color: theme.bad, bold: true, children: "\u25CB NONE \u2014 nothing enforced, grants refused" })
8376
+ ] }),
8377
+ /* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: focused ? "\u2191\u2193 select \xB7 enter open \xB7 a activate \xB7 x deactivate (none)" : "press \u2192 to browse" }),
8355
8378
  /* @__PURE__ */ jsx3(Box3, { marginTop: 1, flexDirection: "column", children: policies.map((p, i) => /* @__PURE__ */ jsxs3(Text3, { color: i === pi ? theme.accentBright : void 0, bold: i === pi, children: [
8356
8379
  (i === pi ? "\u25B8 " : " ") + truncate2(p.name, 26).padEnd(27),
8357
8380
  /* @__PURE__ */ jsxs3(Text3, { color: theme.dim, children: [
@@ -8360,8 +8383,10 @@ function PoliciesPanel({ focused }) {
8360
8383
  p.rules.length,
8361
8384
  " rules \xB7 v",
8362
8385
  p.version
8363
- ] })
8364
- ] }, p.id)) })
8386
+ ] }),
8387
+ p.id === activeId ? /* @__PURE__ */ jsx3(Text3, { color: theme.ok, bold: true, children: " \u25CF ACTIVE" }) : null
8388
+ ] }, p.id)) }),
8389
+ status ? /* @__PURE__ */ jsx3(Text3, { color: status.startsWith("\u2717") ? theme.bad : theme.ok, children: status }) : null
8365
8390
  ] }) });
8366
8391
  }
8367
8392
  const dirtyTag = dirty ? /* @__PURE__ */ jsx3(Text3, { color: theme.warn, children: " \u25CF unsaved (s save \xB7 x discard)" }) : null;
@@ -9608,7 +9633,7 @@ var init_App = __esm({
9608
9633
  HELP = [
9609
9634
  ["Global", [["\u2191\u2193", "move between sections"], ["\u2192 / enter", "open a section"], ["\u2190 / esc", "back to the menu"], ["?", "this help"], ["q", "quit"]]],
9610
9635
  ["Live", [["\u2191\u2193", "select a stream row"], ["enter", "full entry content"], ["w", "whitelist the selected DENY"], ["b", "block the selected ALLOW"], ["d / x / r", "filter denies / dlp / rate-limit"], ["f", "local / cloud filter"], ["/", "search"], ["s", "sessions (\u2191\u2193 pick, enter open)"], ["space", "copy mode (freeze)"]]],
9611
- ["Policies", [["\u2191\u2193", "browse / select"], ["enter", "open rules \u2192 open a rule"], ["space", "toggle a rule on/off"], ["e", "flip effect"], ["n", "new rule"], ["d", "delete rule"], ["m", "flip mode"], ["D", "dry-run the draft"], ["v", "versions / rollback"], ["s", "save"], ["x", "discard"]]],
9636
+ ["Policies", [["\u2191\u2193", "browse / select"], ["a", "activate (pin) selected policy"], ["x", "deactivate \u2014 no active policy"], ["enter", "open rules \u2192 open a rule"], ["space", "toggle a rule on/off"], ["e", "flip effect"], ["n", "new rule"], ["d", "delete rule"], ["m", "flip mode"], ["D", "dry-run the draft"], ["v", "versions / rollback"], ["s", "save"], ["x", "discard"]]],
9612
9637
  ["Rate limit / DLP", [["\u2191\u2193", "field / pattern"], ["\u2190\u2192", "adjust (shift = \xB110)"], ["space", "toggle pattern"], ["m", "mode"], ["a / d", "add / remove custom"], ["g", "ghost mode"], ["P", "self-protection"], ["s", "save"]]],
9613
9638
  ["Audit", [["\u2191\u2193", "select (list scrolls)"], ["enter", "full entry detail"], ["f / g", "decision / signal filter"], ["t / n / /", "tool / agent / search"], ["c", "clear filters"]]],
9614
9639
  ["Settings", [["\u2191\u2193", "move"], ["enter / space", "toggle \xB7 edit \xB7 add"], ["e", "webhook events"], ["d d", "delete"], ["r", "refresh"]]]
package/dist/tui/index.js CHANGED
@@ -800,7 +800,6 @@ function LivePanel({ active: active2 }) {
800
800
  const [actionMsg, setActionMsg] = useState2(null);
801
801
  const notifiedRef = useRef2(/* @__PURE__ */ new Set());
802
802
  const openedAtRef = useRef2(Date.now());
803
- const activePolicyRef = useRef2(null);
804
803
  const [mode, setMode] = useState2("stream");
805
804
  const [pickIdx, setPickIdx] = useState2(0);
806
805
  const [detail, setDetail] = useState2(null);
@@ -1124,18 +1123,14 @@ function LivePanel({ active: active2 }) {
1124
1123
  }
1125
1124
  setActionMsg({ text: act === "whitelist" ? "whitelisting\u2026" : "blocking\u2026", level: "ok", until: Date.now() + 4e3 });
1126
1125
  try {
1126
+ const a = await api.policies.active();
1127
+ const pid = a.policy?.id ?? null;
1128
+ if (!pid) throw new Error("no active policy \u2014 rule NOT added. Activate a policy first (Policies section).");
1127
1129
  let res;
1128
1130
  if (e.source === "cloud") {
1129
1131
  const realId = e.id.slice(2);
1130
1132
  res = act === "whitelist" ? await api.audit.whitelist(realId) : await api.audit.block(realId);
1131
1133
  } else {
1132
- let pid = activePolicyRef.current;
1133
- if (!pid) {
1134
- const a = await api.policies.active();
1135
- pid = a.policy?.id ?? null;
1136
- activePolicyRef.current = pid;
1137
- }
1138
- if (!pid) throw new Error("no active policy resolves for this machine");
1139
1134
  const t = extractTarget(e.detail);
1140
1135
  res = await api.policies.addRule(pid, { toolPattern: e.tool, kind: t?.kind ?? "tool", value: t?.value, effect: act === "whitelist" ? "ALLOW" : "DENY" });
1141
1136
  }
@@ -1591,6 +1586,9 @@ function ruleSummary(r) {
1591
1586
  function PoliciesPanel({ focused }) {
1592
1587
  const list5 = useLoader(() => api.policies.list());
1593
1588
  const policies = list5.data?.policies ?? [];
1589
+ const activeQ = useLoader(() => api.policies.active());
1590
+ const activeId = activeQ.data?.policy?.id ?? null;
1591
+ const activeBy = activeQ.data?.matched_by;
1594
1592
  const [view, setView] = useState3("list");
1595
1593
  const [pi, setPi] = useState3(0);
1596
1594
  const [ri, setRi] = useState3(0);
@@ -1663,6 +1661,20 @@ function PoliciesPanel({ focused }) {
1663
1661
  else if (key.return || key.rightArrow) {
1664
1662
  setStatus(null);
1665
1663
  setView("rules");
1664
+ } else if (input === "a") {
1665
+ if (selected) {
1666
+ setStatus("Activating\u2026");
1667
+ void api.policies.setActive(selected.id).then(() => {
1668
+ setStatus(`\u2713 "${selected.name}" is now the ACTIVE policy (pinned) \xB7 reaches agents in ~30s`);
1669
+ activeQ.reload();
1670
+ }).catch((e) => setStatus("\u2717 " + (e instanceof Error ? e.message : String(e))));
1671
+ }
1672
+ } else if (input === "x") {
1673
+ setStatus("Deactivating\u2026");
1674
+ void api.policies.setActive(null).then(() => {
1675
+ setStatus("\u2713 active policy: NONE \u2014 no rules enforced, w/b grants are refused");
1676
+ activeQ.reload();
1677
+ }).catch((e) => setStatus("\u2717 " + (e instanceof Error ? e.message : String(e))));
1666
1678
  }
1667
1679
  return;
1668
1680
  }
@@ -1743,8 +1755,19 @@ function PoliciesPanel({ focused }) {
1743
1755
  { isActive: focused && !editing }
1744
1756
  );
1745
1757
  if (view === "list") {
1758
+ const activeName = activeId ? policies.find((p) => p.id === activeId)?.name ?? activeId : null;
1746
1759
  return /* @__PURE__ */ jsx3(DataView, { loading: list5.loading && !list5.data, error: list5.error, empty: !!list5.data && policies.length === 0, emptyText: "No policies.", children: /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", children: [
1747
- /* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: focused ? "\u2191\u2193 select \xB7 enter open" : "press \u2192 to browse" }),
1760
+ /* @__PURE__ */ jsxs3(Box3, { children: [
1761
+ /* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: "active: " }),
1762
+ activeQ.loading && !activeQ.data ? /* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: "\u2026" }) : activeName ? /* @__PURE__ */ jsxs3(Fragment3, { children: [
1763
+ /* @__PURE__ */ jsxs3(Text3, { color: theme.ok, bold: true, children: [
1764
+ "\u25CF ",
1765
+ truncate(activeName, 28)
1766
+ ] }),
1767
+ /* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: activeBy ? ` (${activeBy})` : "" })
1768
+ ] }) : /* @__PURE__ */ jsx3(Text3, { color: theme.bad, bold: true, children: "\u25CB NONE \u2014 nothing enforced, grants refused" })
1769
+ ] }),
1770
+ /* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: focused ? "\u2191\u2193 select \xB7 enter open \xB7 a activate \xB7 x deactivate (none)" : "press \u2192 to browse" }),
1748
1771
  /* @__PURE__ */ jsx3(Box3, { marginTop: 1, flexDirection: "column", children: policies.map((p, i) => /* @__PURE__ */ jsxs3(Text3, { color: i === pi ? theme.accentBright : void 0, bold: i === pi, children: [
1749
1772
  (i === pi ? "\u25B8 " : " ") + truncate(p.name, 26).padEnd(27),
1750
1773
  /* @__PURE__ */ jsxs3(Text3, { color: theme.dim, children: [
@@ -1753,8 +1776,10 @@ function PoliciesPanel({ focused }) {
1753
1776
  p.rules.length,
1754
1777
  " rules \xB7 v",
1755
1778
  p.version
1756
- ] })
1757
- ] }, p.id)) })
1779
+ ] }),
1780
+ p.id === activeId ? /* @__PURE__ */ jsx3(Text3, { color: theme.ok, bold: true, children: " \u25CF ACTIVE" }) : null
1781
+ ] }, p.id)) }),
1782
+ status ? /* @__PURE__ */ jsx3(Text3, { color: status.startsWith("\u2717") ? theme.bad : theme.ok, children: status }) : null
1758
1783
  ] }) });
1759
1784
  }
1760
1785
  const dirtyTag = dirty ? /* @__PURE__ */ jsx3(Text3, { color: theme.warn, children: " \u25CF unsaved (s save \xB7 x discard)" }) : null;
@@ -2880,7 +2905,7 @@ function App() {
2880
2905
  var HELP = [
2881
2906
  ["Global", [["\u2191\u2193", "move between sections"], ["\u2192 / enter", "open a section"], ["\u2190 / esc", "back to the menu"], ["?", "this help"], ["q", "quit"]]],
2882
2907
  ["Live", [["\u2191\u2193", "select a stream row"], ["enter", "full entry content"], ["w", "whitelist the selected DENY"], ["b", "block the selected ALLOW"], ["d / x / r", "filter denies / dlp / rate-limit"], ["f", "local / cloud filter"], ["/", "search"], ["s", "sessions (\u2191\u2193 pick, enter open)"], ["space", "copy mode (freeze)"]]],
2883
- ["Policies", [["\u2191\u2193", "browse / select"], ["enter", "open rules \u2192 open a rule"], ["space", "toggle a rule on/off"], ["e", "flip effect"], ["n", "new rule"], ["d", "delete rule"], ["m", "flip mode"], ["D", "dry-run the draft"], ["v", "versions / rollback"], ["s", "save"], ["x", "discard"]]],
2908
+ ["Policies", [["\u2191\u2193", "browse / select"], ["a", "activate (pin) selected policy"], ["x", "deactivate \u2014 no active policy"], ["enter", "open rules \u2192 open a rule"], ["space", "toggle a rule on/off"], ["e", "flip effect"], ["n", "new rule"], ["d", "delete rule"], ["m", "flip mode"], ["D", "dry-run the draft"], ["v", "versions / rollback"], ["s", "save"], ["x", "discard"]]],
2884
2909
  ["Rate limit / DLP", [["\u2191\u2193", "field / pattern"], ["\u2190\u2192", "adjust (shift = \xB110)"], ["space", "toggle pattern"], ["m", "mode"], ["a / d", "add / remove custom"], ["g", "ghost mode"], ["P", "self-protection"], ["s", "save"]]],
2885
2910
  ["Audit", [["\u2191\u2193", "select (list scrolls)"], ["enter", "full entry detail"], ["f / g", "decision / signal filter"], ["t / n / /", "tool / agent / search"], ["c", "clear filters"]]],
2886
2911
  ["Settings", [["\u2191\u2193", "move"], ["enter / space", "toggle \xB7 edit \xB7 add"], ["e", "webhook events"], ["d d", "delete"], ["r", "refresh"]]]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solongate/proxy",
3
- "version": "0.81.21",
3
+ "version": "0.81.23",
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": {