@solongate/proxy 0.82.27 → 0.82.29

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
@@ -8814,6 +8814,7 @@ function PoliciesPanel({ focused }) {
8814
8814
  const activeQ = useLoader(() => api.policies.active());
8815
8815
  const activeId = activeQ.data?.policy?.id ?? null;
8816
8816
  const activeBy = activeQ.data?.matched_by;
8817
+ const { rows: panelRows } = usePanelSize();
8817
8818
  const [view, setView] = useState3("list");
8818
8819
  const [pi, setPi] = useState3(0);
8819
8820
  const [ri, setRi] = useState3(0);
@@ -8933,7 +8934,12 @@ function PoliciesPanel({ focused }) {
8933
8934
  setView("rule");
8934
8935
  } else if (input === "D") {
8935
8936
  setStatus("Dry-running\u2026");
8936
- void api.policies.dryRun({ rules, mode }).then((res) => setStatus(`dry-run ${res.evaluated} calls \xB7 allow ${res.would_allow} / deny ${res.would_deny} \xB7 newly blocked ${res.newly_blocked} \xB7 newly allowed ${res.newly_allowed}`)).catch((e) => setStatus("\u2717 " + (e instanceof Error ? e.message : String(e))));
8937
+ void api.policies.dryRun({ rules, mode }).then((res) => setStatus(
8938
+ `dry-run: replayed ${res.evaluated} recent calls against ${rules.length} rules
8939
+ would allow ${res.would_allow} would deny ${res.would_deny}
8940
+ newly allowed ${res.newly_allowed} newly blocked ${res.newly_blocked} unchanged ${res.unchanged}` + (res.sample_newly_blocked?.length ? `
8941
+ now blocked e.g.: ${res.sample_newly_blocked.slice(0, 3).map((s) => truncate2(s.tool, 24)).join(", ")}` : "")
8942
+ )).catch((e) => setStatus("\u2717 " + (e instanceof Error ? e.message : String(e))));
8937
8943
  } else if (input === "s") void save();
8938
8944
  else if (input === "x") discard();
8939
8945
  return;
@@ -8960,6 +8966,12 @@ function PoliciesPanel({ focused }) {
8960
8966
  );
8961
8967
  if (view === "list") {
8962
8968
  const activeName = activeId ? policies.find((p) => p.id === activeId)?.name ?? activeId : null;
8969
+ const lHead = 3 + (status ? 1 : 0);
8970
+ const lBudget = Math.max(3, panelRows - lHead);
8971
+ const lStart = Math.min(Math.max(0, pi - Math.floor(lBudget / 2)), Math.max(0, policies.length - lBudget));
8972
+ const lWin = policies.slice(lStart, lStart + lBudget);
8973
+ const lAbove = lStart;
8974
+ const lBelow = Math.max(0, policies.length - (lStart + lBudget));
8963
8975
  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: [
8964
8976
  /* @__PURE__ */ jsxs3(Box3, { children: [
8965
8977
  /* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: "active: " }),
@@ -8971,30 +8983,42 @@ function PoliciesPanel({ focused }) {
8971
8983
  /* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: activeBy ? ` (${activeBy})` : "" })
8972
8984
  ] }) : /* @__PURE__ */ jsx3(Text3, { color: theme.bad, bold: true, children: "\u25CB NONE \u2014 nothing enforced, grants refused" })
8973
8985
  ] }),
8974
- /* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: focused ? "\u2191\u2193 select \xB7 enter open \xB7 a activate \xB7 x deactivate \xB7 ^R refresh" : "press \u2192 to browse" }),
8975
- /* @__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: [
8976
- (i === pi ? "\u25B8 " : " ") + truncate2(p.name, 26).padEnd(27),
8977
- /* @__PURE__ */ jsxs3(Text3, { color: theme.dim, children: [
8978
- p.mode.padEnd(10),
8979
- " ",
8980
- p.rules.length,
8981
- " rules"
8982
- ] }),
8983
- p.id === activeId ? /* @__PURE__ */ jsx3(Text3, { color: theme.ok, bold: true, children: " \u25CF ACTIVE" }) : null
8984
- ] }, p.id)) }),
8986
+ /* @__PURE__ */ jsx3(Text3, { color: theme.dim, wrap: "truncate", children: focused ? `\u2191\u2193 select \xB7 enter open \xB7 a activate \xB7 x deactivate \xB7 ^R refresh${lAbove ? ` \xB7 \u25B2${lAbove}` : ""}${lBelow ? ` \xB7 \u25BC${lBelow}` : ""}` : "press \u2192 to browse" }),
8987
+ /* @__PURE__ */ jsx3(Box3, { marginTop: 1, flexDirection: "column", children: lWin.map((p, wi) => {
8988
+ const i = lStart + wi;
8989
+ return /* @__PURE__ */ jsxs3(Text3, { color: i === pi ? theme.accentBright : void 0, bold: i === pi, children: [
8990
+ (i === pi ? "\u25B8 " : " ") + truncate2(p.name, 26).padEnd(27),
8991
+ /* @__PURE__ */ jsxs3(Text3, { color: theme.dim, children: [
8992
+ p.mode.padEnd(10),
8993
+ " ",
8994
+ p.rules.length,
8995
+ " rules"
8996
+ ] }),
8997
+ p.id === activeId ? /* @__PURE__ */ jsx3(Text3, { color: theme.ok, bold: true, children: " \u25CF ACTIVE" }) : null
8998
+ ] }, p.id);
8999
+ }) }),
8985
9000
  status ? /* @__PURE__ */ jsx3(Text3, { color: status.startsWith("\u2717") ? theme.bad : theme.ok, children: status }) : null
8986
9001
  ] }) });
8987
9002
  }
8988
9003
  const dirtyTag = dirty ? /* @__PURE__ */ jsx3(Text3, { color: theme.warn, children: " \u25CF unsaved (s save \xB7 x discard)" }) : null;
8989
9004
  if (view === "rules") {
9005
+ const rStatusLines = status ? status.split("\n").length : 0;
9006
+ const rHead = 4 + rStatusLines;
9007
+ const rBudget = Math.max(3, panelRows - rHead);
9008
+ const rMaxStart = Math.max(0, rules.length - rBudget);
9009
+ const rStart = Math.min(Math.max(0, ri - Math.floor(rBudget / 2)), rMaxStart);
9010
+ const rWin = rules.slice(rStart, rStart + rBudget);
9011
+ const rAbove = rStart;
9012
+ const rBelow = Math.max(0, rules.length - (rStart + rBudget));
8990
9013
  return /* @__PURE__ */ jsx3(DataView, { loading: detail.loading && !detail.data, error: detail.error, children: /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", children: [
8991
9014
  /* @__PURE__ */ jsxs3(Box3, { children: [
8992
9015
  /* @__PURE__ */ jsx3(Text3, { bold: true, color: theme.accentBright, children: truncate2(selected?.name ?? "", 28) }),
8993
9016
  /* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: " mode: " }),
8994
9017
  /* @__PURE__ */ jsx3(Text3, { color: mode === "whitelist" ? theme.warn : void 0, children: mode }),
9018
+ /* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: ` ${rules.length} rules` }),
8995
9019
  dirtyTag
8996
9020
  ] }),
8997
- /* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: "\u2191\u2193 \xB7 enter edit \xB7 space on/off \xB7 e effect \xB7 n new \xB7 d del \xB7 m mode \xB7 D dry-run \xB7 s save \xB7 \u2190 back" }),
9021
+ /* @__PURE__ */ jsx3(Text3, { color: theme.dim, wrap: "truncate", children: `\u2191\u2193 \xB7 enter edit \xB7 space on/off \xB7 e effect \xB7 n new \xB7 d del \xB7 m mode \xB7 D dry-run \xB7 s save \xB7 \u2190 back${rAbove ? ` \xB7 \u25B2${rAbove}` : ""}${rBelow ? ` \xB7 \u25BC${rBelow}` : ""}` }),
8998
9022
  /* @__PURE__ */ jsx3(Box3, { marginTop: 1, children: /* @__PURE__ */ jsx3(
8999
9023
  Table,
9000
9024
  {
@@ -9003,17 +9027,22 @@ function PoliciesPanel({ focused }) {
9003
9027
  { header: "ON", width: 2 },
9004
9028
  { header: "EFFECT", width: 7 },
9005
9029
  { header: "PRIO", width: 4 },
9006
- { header: "TOOL", width: 20 },
9007
- { header: "CONSTRAINTS", width: 22 }
9030
+ { header: "TOOL", width: 12 },
9031
+ { header: "DESCRIPTION", width: 30 },
9032
+ { header: "CONSTRAINTS", width: 14 }
9008
9033
  ],
9009
- rows: rules.map((r, i) => [
9010
- { value: i === ri ? "\u25B8" : "", color: theme.accentBright },
9011
- { value: r.enabled ? "\u25CF" : "\u25CB", color: r.enabled ? theme.ok : theme.dim },
9012
- { value: r.effect, color: r.effect === "ALLOW" ? theme.ok : theme.bad, dim: !r.enabled },
9013
- { value: String(r.priority), dim: true },
9014
- { value: truncate2(r.toolPattern, 20), color: theme.accent, dim: !r.enabled },
9015
- { value: ruleSummary(r) || truncate2(r.description || "\u2014", 22), dim: true }
9016
- ])
9034
+ rows: rWin.map((r, wi) => {
9035
+ const i = rStart + wi;
9036
+ return [
9037
+ { value: i === ri ? "\u25B8" : "", color: theme.accentBright },
9038
+ { value: r.enabled ? "\u25CF" : "\u25CB", color: r.enabled ? theme.ok : theme.dim },
9039
+ { value: r.effect, color: r.effect === "ALLOW" ? theme.ok : theme.bad, dim: !r.enabled },
9040
+ { value: String(r.priority), dim: true },
9041
+ { value: truncate2(r.toolPattern, 12), color: theme.accent, dim: !r.enabled },
9042
+ { value: truncate2(r.description || "-", 30), dim: !r.enabled },
9043
+ { value: ruleSummary(r) || "-", dim: true }
9044
+ ];
9045
+ })
9017
9046
  }
9018
9047
  ) }),
9019
9048
  rules.length === 0 ? /* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: "(no rules)" }) : null,
@@ -9024,7 +9053,7 @@ function PoliciesPanel({ focused }) {
9024
9053
  return /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", children: [
9025
9054
  /* @__PURE__ */ jsxs3(Box3, { children: [
9026
9055
  /* @__PURE__ */ jsx3(Text3, { bold: true, color: theme.accentBright, children: "Rule " }),
9027
- /* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: truncate2(rule?.id ?? "", 26) }),
9056
+ /* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: rule?.id ?? "" }),
9028
9057
  dirtyTag
9029
9058
  ] }),
9030
9059
  /* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: "\u2191\u2193 field \xB7 enter edit text \xB7 space/\u2192 toggle \xB7 s save \xB7 \u2190 back" }),
package/dist/tui/index.js CHANGED
@@ -1939,6 +1939,7 @@ function PoliciesPanel({ focused }) {
1939
1939
  const activeQ = useLoader(() => api.policies.active());
1940
1940
  const activeId = activeQ.data?.policy?.id ?? null;
1941
1941
  const activeBy = activeQ.data?.matched_by;
1942
+ const { rows: panelRows } = usePanelSize();
1942
1943
  const [view, setView] = useState3("list");
1943
1944
  const [pi, setPi] = useState3(0);
1944
1945
  const [ri, setRi] = useState3(0);
@@ -2058,7 +2059,12 @@ function PoliciesPanel({ focused }) {
2058
2059
  setView("rule");
2059
2060
  } else if (input === "D") {
2060
2061
  setStatus("Dry-running\u2026");
2061
- void api.policies.dryRun({ rules, mode }).then((res) => setStatus(`dry-run ${res.evaluated} calls \xB7 allow ${res.would_allow} / deny ${res.would_deny} \xB7 newly blocked ${res.newly_blocked} \xB7 newly allowed ${res.newly_allowed}`)).catch((e) => setStatus("\u2717 " + (e instanceof Error ? e.message : String(e))));
2062
+ void api.policies.dryRun({ rules, mode }).then((res) => setStatus(
2063
+ `dry-run: replayed ${res.evaluated} recent calls against ${rules.length} rules
2064
+ would allow ${res.would_allow} would deny ${res.would_deny}
2065
+ newly allowed ${res.newly_allowed} newly blocked ${res.newly_blocked} unchanged ${res.unchanged}` + (res.sample_newly_blocked?.length ? `
2066
+ now blocked e.g.: ${res.sample_newly_blocked.slice(0, 3).map((s) => truncate(s.tool, 24)).join(", ")}` : "")
2067
+ )).catch((e) => setStatus("\u2717 " + (e instanceof Error ? e.message : String(e))));
2062
2068
  } else if (input === "s") void save();
2063
2069
  else if (input === "x") discard();
2064
2070
  return;
@@ -2085,6 +2091,12 @@ function PoliciesPanel({ focused }) {
2085
2091
  );
2086
2092
  if (view === "list") {
2087
2093
  const activeName = activeId ? policies.find((p) => p.id === activeId)?.name ?? activeId : null;
2094
+ const lHead = 3 + (status ? 1 : 0);
2095
+ const lBudget = Math.max(3, panelRows - lHead);
2096
+ const lStart = Math.min(Math.max(0, pi - Math.floor(lBudget / 2)), Math.max(0, policies.length - lBudget));
2097
+ const lWin = policies.slice(lStart, lStart + lBudget);
2098
+ const lAbove = lStart;
2099
+ const lBelow = Math.max(0, policies.length - (lStart + lBudget));
2088
2100
  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: [
2089
2101
  /* @__PURE__ */ jsxs3(Box3, { children: [
2090
2102
  /* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: "active: " }),
@@ -2096,30 +2108,42 @@ function PoliciesPanel({ focused }) {
2096
2108
  /* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: activeBy ? ` (${activeBy})` : "" })
2097
2109
  ] }) : /* @__PURE__ */ jsx3(Text3, { color: theme.bad, bold: true, children: "\u25CB NONE \u2014 nothing enforced, grants refused" })
2098
2110
  ] }),
2099
- /* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: focused ? "\u2191\u2193 select \xB7 enter open \xB7 a activate \xB7 x deactivate \xB7 ^R refresh" : "press \u2192 to browse" }),
2100
- /* @__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: [
2101
- (i === pi ? "\u25B8 " : " ") + truncate(p.name, 26).padEnd(27),
2102
- /* @__PURE__ */ jsxs3(Text3, { color: theme.dim, children: [
2103
- p.mode.padEnd(10),
2104
- " ",
2105
- p.rules.length,
2106
- " rules"
2107
- ] }),
2108
- p.id === activeId ? /* @__PURE__ */ jsx3(Text3, { color: theme.ok, bold: true, children: " \u25CF ACTIVE" }) : null
2109
- ] }, p.id)) }),
2111
+ /* @__PURE__ */ jsx3(Text3, { color: theme.dim, wrap: "truncate", children: focused ? `\u2191\u2193 select \xB7 enter open \xB7 a activate \xB7 x deactivate \xB7 ^R refresh${lAbove ? ` \xB7 \u25B2${lAbove}` : ""}${lBelow ? ` \xB7 \u25BC${lBelow}` : ""}` : "press \u2192 to browse" }),
2112
+ /* @__PURE__ */ jsx3(Box3, { marginTop: 1, flexDirection: "column", children: lWin.map((p, wi) => {
2113
+ const i = lStart + wi;
2114
+ return /* @__PURE__ */ jsxs3(Text3, { color: i === pi ? theme.accentBright : void 0, bold: i === pi, children: [
2115
+ (i === pi ? "\u25B8 " : " ") + truncate(p.name, 26).padEnd(27),
2116
+ /* @__PURE__ */ jsxs3(Text3, { color: theme.dim, children: [
2117
+ p.mode.padEnd(10),
2118
+ " ",
2119
+ p.rules.length,
2120
+ " rules"
2121
+ ] }),
2122
+ p.id === activeId ? /* @__PURE__ */ jsx3(Text3, { color: theme.ok, bold: true, children: " \u25CF ACTIVE" }) : null
2123
+ ] }, p.id);
2124
+ }) }),
2110
2125
  status ? /* @__PURE__ */ jsx3(Text3, { color: status.startsWith("\u2717") ? theme.bad : theme.ok, children: status }) : null
2111
2126
  ] }) });
2112
2127
  }
2113
2128
  const dirtyTag = dirty ? /* @__PURE__ */ jsx3(Text3, { color: theme.warn, children: " \u25CF unsaved (s save \xB7 x discard)" }) : null;
2114
2129
  if (view === "rules") {
2130
+ const rStatusLines = status ? status.split("\n").length : 0;
2131
+ const rHead = 4 + rStatusLines;
2132
+ const rBudget = Math.max(3, panelRows - rHead);
2133
+ const rMaxStart = Math.max(0, rules.length - rBudget);
2134
+ const rStart = Math.min(Math.max(0, ri - Math.floor(rBudget / 2)), rMaxStart);
2135
+ const rWin = rules.slice(rStart, rStart + rBudget);
2136
+ const rAbove = rStart;
2137
+ const rBelow = Math.max(0, rules.length - (rStart + rBudget));
2115
2138
  return /* @__PURE__ */ jsx3(DataView, { loading: detail.loading && !detail.data, error: detail.error, children: /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", children: [
2116
2139
  /* @__PURE__ */ jsxs3(Box3, { children: [
2117
2140
  /* @__PURE__ */ jsx3(Text3, { bold: true, color: theme.accentBright, children: truncate(selected?.name ?? "", 28) }),
2118
2141
  /* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: " mode: " }),
2119
2142
  /* @__PURE__ */ jsx3(Text3, { color: mode === "whitelist" ? theme.warn : void 0, children: mode }),
2143
+ /* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: ` ${rules.length} rules` }),
2120
2144
  dirtyTag
2121
2145
  ] }),
2122
- /* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: "\u2191\u2193 \xB7 enter edit \xB7 space on/off \xB7 e effect \xB7 n new \xB7 d del \xB7 m mode \xB7 D dry-run \xB7 s save \xB7 \u2190 back" }),
2146
+ /* @__PURE__ */ jsx3(Text3, { color: theme.dim, wrap: "truncate", children: `\u2191\u2193 \xB7 enter edit \xB7 space on/off \xB7 e effect \xB7 n new \xB7 d del \xB7 m mode \xB7 D dry-run \xB7 s save \xB7 \u2190 back${rAbove ? ` \xB7 \u25B2${rAbove}` : ""}${rBelow ? ` \xB7 \u25BC${rBelow}` : ""}` }),
2123
2147
  /* @__PURE__ */ jsx3(Box3, { marginTop: 1, children: /* @__PURE__ */ jsx3(
2124
2148
  Table,
2125
2149
  {
@@ -2128,17 +2152,22 @@ function PoliciesPanel({ focused }) {
2128
2152
  { header: "ON", width: 2 },
2129
2153
  { header: "EFFECT", width: 7 },
2130
2154
  { header: "PRIO", width: 4 },
2131
- { header: "TOOL", width: 20 },
2132
- { header: "CONSTRAINTS", width: 22 }
2155
+ { header: "TOOL", width: 12 },
2156
+ { header: "DESCRIPTION", width: 30 },
2157
+ { header: "CONSTRAINTS", width: 14 }
2133
2158
  ],
2134
- rows: rules.map((r, i) => [
2135
- { value: i === ri ? "\u25B8" : "", color: theme.accentBright },
2136
- { value: r.enabled ? "\u25CF" : "\u25CB", color: r.enabled ? theme.ok : theme.dim },
2137
- { value: r.effect, color: r.effect === "ALLOW" ? theme.ok : theme.bad, dim: !r.enabled },
2138
- { value: String(r.priority), dim: true },
2139
- { value: truncate(r.toolPattern, 20), color: theme.accent, dim: !r.enabled },
2140
- { value: ruleSummary(r) || truncate(r.description || "\u2014", 22), dim: true }
2141
- ])
2159
+ rows: rWin.map((r, wi) => {
2160
+ const i = rStart + wi;
2161
+ return [
2162
+ { value: i === ri ? "\u25B8" : "", color: theme.accentBright },
2163
+ { value: r.enabled ? "\u25CF" : "\u25CB", color: r.enabled ? theme.ok : theme.dim },
2164
+ { value: r.effect, color: r.effect === "ALLOW" ? theme.ok : theme.bad, dim: !r.enabled },
2165
+ { value: String(r.priority), dim: true },
2166
+ { value: truncate(r.toolPattern, 12), color: theme.accent, dim: !r.enabled },
2167
+ { value: truncate(r.description || "-", 30), dim: !r.enabled },
2168
+ { value: ruleSummary(r) || "-", dim: true }
2169
+ ];
2170
+ })
2142
2171
  }
2143
2172
  ) }),
2144
2173
  rules.length === 0 ? /* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: "(no rules)" }) : null,
@@ -2149,7 +2178,7 @@ function PoliciesPanel({ focused }) {
2149
2178
  return /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", children: [
2150
2179
  /* @__PURE__ */ jsxs3(Box3, { children: [
2151
2180
  /* @__PURE__ */ jsx3(Text3, { bold: true, color: theme.accentBright, children: "Rule " }),
2152
- /* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: truncate(rule?.id ?? "", 26) }),
2181
+ /* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: rule?.id ?? "" }),
2153
2182
  dirtyTag
2154
2183
  ] }),
2155
2184
  /* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: "\u2191\u2193 field \xB7 enter edit text \xB7 space/\u2192 toggle \xB7 s save \xB7 \u2190 back" }),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solongate/proxy",
3
- "version": "0.82.27",
3
+ "version": "0.82.29",
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": {