@solongate/proxy 0.81.32 → 0.81.34
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 +51 -33
- package/dist/tui/index.js +50 -32
- package/dist/tui/local-log.d.ts +5 -0
- package/hooks/.solongate/.eval-ring.jsonl +8 -0
- package/hooks/.solongate/.last-deny +1 -1
- package/hooks/.solongate/.last-eval +1 -1
- package/hooks/.solongate/.last-tool-call +1 -1
- package/hooks/audit.mjs +92 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -6887,6 +6887,15 @@ function clearLocalLog() {
|
|
|
6887
6887
|
return 0;
|
|
6888
6888
|
}
|
|
6889
6889
|
}
|
|
6890
|
+
function reasonSignals(reason) {
|
|
6891
|
+
const r = reason || "";
|
|
6892
|
+
const dlp = [];
|
|
6893
|
+
if (DLP_REASON.test(r)) {
|
|
6894
|
+
const m = r.match(/contain(?:s)? (?:a |an )?(.+?)(?:\.|$)/i);
|
|
6895
|
+
dlp.push(m ? m[1].trim() : "DLP");
|
|
6896
|
+
}
|
|
6897
|
+
return { dlp, burst: RL_REASON.test(r) };
|
|
6898
|
+
}
|
|
6890
6899
|
function parseLocalLines(lines) {
|
|
6891
6900
|
const out2 = [];
|
|
6892
6901
|
for (const line of lines) {
|
|
@@ -6899,11 +6908,13 @@ function parseLocalLines(lines) {
|
|
|
6899
6908
|
}
|
|
6900
6909
|
return out2;
|
|
6901
6910
|
}
|
|
6902
|
-
var LOCAL_LOG;
|
|
6911
|
+
var LOCAL_LOG, DLP_REASON, RL_REASON;
|
|
6903
6912
|
var init_local_log = __esm({
|
|
6904
6913
|
"src/tui/local-log.ts"() {
|
|
6905
6914
|
"use strict";
|
|
6906
6915
|
LOCAL_LOG = join6(homedir4(), ".solongate", "local-logs", "solongate-audit.jsonl");
|
|
6916
|
+
DLP_REASON = /security layer \(dlp\)/i;
|
|
6917
|
+
RL_REASON = /security layer \(rate limit\)|rate[- ]?limit(?:ed)?\b.*exceed|exceeded \d+ calls/i;
|
|
6907
6918
|
}
|
|
6908
6919
|
});
|
|
6909
6920
|
|
|
@@ -8874,22 +8885,26 @@ import { join as join8 } from "path";
|
|
|
8874
8885
|
import { useState as useState6 } from "react";
|
|
8875
8886
|
import { Fragment as Fragment4, jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
8876
8887
|
function loadLocalRows() {
|
|
8877
|
-
return parseLocalLines(tailLines(LOCAL_LOG, LOCAL_MAX_BYTES)).map((j, i) =>
|
|
8878
|
-
|
|
8879
|
-
|
|
8880
|
-
|
|
8881
|
-
|
|
8882
|
-
|
|
8883
|
-
|
|
8884
|
-
|
|
8885
|
-
|
|
8886
|
-
|
|
8887
|
-
|
|
8888
|
-
|
|
8889
|
-
|
|
8890
|
-
|
|
8891
|
-
|
|
8892
|
-
|
|
8888
|
+
return parseLocalLines(tailLines(LOCAL_LOG, LOCAL_MAX_BYTES)).map((j, i) => {
|
|
8889
|
+
const rs = reasonSignals(j.reason);
|
|
8890
|
+
const explicitDlp = j.dlp ? Array.isArray(j.dlp) ? j.dlp.map(String) : ["dlp"] : [];
|
|
8891
|
+
return {
|
|
8892
|
+
id: "l:" + j.at + ":" + i,
|
|
8893
|
+
at: j.at,
|
|
8894
|
+
tool: j.tool ?? "?",
|
|
8895
|
+
decision: j.decision ?? "ALLOW",
|
|
8896
|
+
permission: j.permission ?? "\u2014",
|
|
8897
|
+
trust: j.trust_level ?? "\u2014",
|
|
8898
|
+
agent: j.agent_name ?? null,
|
|
8899
|
+
session: j.session_id ?? null,
|
|
8900
|
+
reason: j.reason ?? null,
|
|
8901
|
+
rule: j.matched_rule_id ?? null,
|
|
8902
|
+
evalMs: j.evaluation_time_ms ?? null,
|
|
8903
|
+
dlp: explicitDlp.length ? explicitDlp : rs.dlp,
|
|
8904
|
+
burst: !!j.rate_limit_burst || rs.burst,
|
|
8905
|
+
args: j.arguments ? JSON.stringify(j.arguments) : null
|
|
8906
|
+
};
|
|
8907
|
+
}).sort((a, b) => b.at - a.at);
|
|
8893
8908
|
}
|
|
8894
8909
|
function AuditPanel({ active: active2, focused }) {
|
|
8895
8910
|
const { cols, rows } = usePanelSize();
|
|
@@ -9446,22 +9461,25 @@ var init_Audit = __esm({
|
|
|
9446
9461
|
SESS_STATUS = [void 0, "active", "idle", "ended"];
|
|
9447
9462
|
PAGE = 500;
|
|
9448
9463
|
LOCAL_MAX_BYTES = 16 * 1024 * 1024;
|
|
9449
|
-
cloudRow = (e) =>
|
|
9450
|
-
|
|
9451
|
-
|
|
9452
|
-
|
|
9453
|
-
|
|
9454
|
-
|
|
9455
|
-
|
|
9456
|
-
|
|
9457
|
-
|
|
9458
|
-
|
|
9459
|
-
|
|
9460
|
-
|
|
9461
|
-
|
|
9462
|
-
|
|
9463
|
-
|
|
9464
|
-
|
|
9464
|
+
cloudRow = (e) => {
|
|
9465
|
+
const rs = reasonSignals(e.reason);
|
|
9466
|
+
return {
|
|
9467
|
+
id: e.id,
|
|
9468
|
+
at: Date.parse(e.created_at),
|
|
9469
|
+
tool: e.tool_name,
|
|
9470
|
+
decision: e.decision,
|
|
9471
|
+
permission: e.permission,
|
|
9472
|
+
trust: e.trust_level,
|
|
9473
|
+
agent: e.agent_name,
|
|
9474
|
+
session: e.session_id,
|
|
9475
|
+
reason: e.reason,
|
|
9476
|
+
rule: e.matched_rule_id,
|
|
9477
|
+
evalMs: e.evaluation_time_ms,
|
|
9478
|
+
dlp: e.dlp_matches?.length ? e.dlp_matches : rs.dlp,
|
|
9479
|
+
burst: !!e.rate_limit_burst || rs.burst,
|
|
9480
|
+
args: e.arguments_summary ? JSON.stringify(e.arguments_summary) : null
|
|
9481
|
+
};
|
|
9482
|
+
};
|
|
9465
9483
|
AUDIT_HELP = [
|
|
9466
9484
|
[
|
|
9467
9485
|
"Logs",
|
package/dist/tui/index.js
CHANGED
|
@@ -217,6 +217,17 @@ function clearLocalLog() {
|
|
|
217
217
|
return 0;
|
|
218
218
|
}
|
|
219
219
|
}
|
|
220
|
+
var DLP_REASON = /security layer \(dlp\)/i;
|
|
221
|
+
var RL_REASON = /security layer \(rate limit\)|rate[- ]?limit(?:ed)?\b.*exceed|exceeded \d+ calls/i;
|
|
222
|
+
function reasonSignals(reason) {
|
|
223
|
+
const r = reason || "";
|
|
224
|
+
const dlp = [];
|
|
225
|
+
if (DLP_REASON.test(r)) {
|
|
226
|
+
const m = r.match(/contain(?:s)? (?:a |an )?(.+?)(?:\.|$)/i);
|
|
227
|
+
dlp.push(m ? m[1].trim() : "DLP");
|
|
228
|
+
}
|
|
229
|
+
return { dlp, burst: RL_REASON.test(r) };
|
|
230
|
+
}
|
|
220
231
|
function parseLocalLines(lines) {
|
|
221
232
|
const out = [];
|
|
222
233
|
for (const line of lines) {
|
|
@@ -2215,39 +2226,46 @@ var SIGNALS = [void 0, "dlp", "ratelimit"];
|
|
|
2215
2226
|
var SESS_STATUS = [void 0, "active", "idle", "ended"];
|
|
2216
2227
|
var PAGE = 500;
|
|
2217
2228
|
var LOCAL_MAX_BYTES = 16 * 1024 * 1024;
|
|
2218
|
-
var cloudRow = (e) =>
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2229
|
+
var cloudRow = (e) => {
|
|
2230
|
+
const rs = reasonSignals(e.reason);
|
|
2231
|
+
return {
|
|
2232
|
+
id: e.id,
|
|
2233
|
+
at: Date.parse(e.created_at),
|
|
2234
|
+
tool: e.tool_name,
|
|
2235
|
+
decision: e.decision,
|
|
2236
|
+
permission: e.permission,
|
|
2237
|
+
trust: e.trust_level,
|
|
2238
|
+
agent: e.agent_name,
|
|
2239
|
+
session: e.session_id,
|
|
2240
|
+
reason: e.reason,
|
|
2241
|
+
rule: e.matched_rule_id,
|
|
2242
|
+
evalMs: e.evaluation_time_ms,
|
|
2243
|
+
dlp: e.dlp_matches?.length ? e.dlp_matches : rs.dlp,
|
|
2244
|
+
burst: !!e.rate_limit_burst || rs.burst,
|
|
2245
|
+
args: e.arguments_summary ? JSON.stringify(e.arguments_summary) : null
|
|
2246
|
+
};
|
|
2247
|
+
};
|
|
2234
2248
|
function loadLocalRows() {
|
|
2235
|
-
return parseLocalLines(tailLines(LOCAL_LOG, LOCAL_MAX_BYTES)).map((j, i) =>
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2249
|
+
return parseLocalLines(tailLines(LOCAL_LOG, LOCAL_MAX_BYTES)).map((j, i) => {
|
|
2250
|
+
const rs = reasonSignals(j.reason);
|
|
2251
|
+
const explicitDlp = j.dlp ? Array.isArray(j.dlp) ? j.dlp.map(String) : ["dlp"] : [];
|
|
2252
|
+
return {
|
|
2253
|
+
id: "l:" + j.at + ":" + i,
|
|
2254
|
+
at: j.at,
|
|
2255
|
+
tool: j.tool ?? "?",
|
|
2256
|
+
decision: j.decision ?? "ALLOW",
|
|
2257
|
+
permission: j.permission ?? "\u2014",
|
|
2258
|
+
trust: j.trust_level ?? "\u2014",
|
|
2259
|
+
agent: j.agent_name ?? null,
|
|
2260
|
+
session: j.session_id ?? null,
|
|
2261
|
+
reason: j.reason ?? null,
|
|
2262
|
+
rule: j.matched_rule_id ?? null,
|
|
2263
|
+
evalMs: j.evaluation_time_ms ?? null,
|
|
2264
|
+
dlp: explicitDlp.length ? explicitDlp : rs.dlp,
|
|
2265
|
+
burst: !!j.rate_limit_burst || rs.burst,
|
|
2266
|
+
args: j.arguments ? JSON.stringify(j.arguments) : null
|
|
2267
|
+
};
|
|
2268
|
+
}).sort((a, b) => b.at - a.at);
|
|
2251
2269
|
}
|
|
2252
2270
|
var AUDIT_HELP = [
|
|
2253
2271
|
[
|
package/dist/tui/local-log.d.ts
CHANGED
|
@@ -21,6 +21,11 @@ export interface LocalLogLine {
|
|
|
21
21
|
export declare function deleteLocalEntry(at: number, tool: string, session?: string | null): number;
|
|
22
22
|
/** Empty the local log file. Returns how many lines were removed. */
|
|
23
23
|
export declare function clearLocalLog(): number;
|
|
24
|
+
/** DLP pattern name + rate-limit-burst flag derived from a decision's reason. */
|
|
25
|
+
export declare function reasonSignals(reason: string | null | undefined): {
|
|
26
|
+
dlp: string[];
|
|
27
|
+
burst: boolean;
|
|
28
|
+
};
|
|
24
29
|
export declare function parseLocalLines(lines: string[]): Array<LocalLogLine & {
|
|
25
30
|
at: number;
|
|
26
31
|
}>;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
{"ms":2,"ts":1784136532559,"tool":"Bash","session":"4aefeb66-3bff-4335-b710-e4f70d3adadf"}
|
|
2
|
+
{"ms":4,"ts":1784136544239,"tool":"Bash","session":"4aefeb66-3bff-4335-b710-e4f70d3adadf"}
|
|
3
|
+
{"ms":2,"ts":1784136555335,"tool":"Bash","session":"4aefeb66-3bff-4335-b710-e4f70d3adadf"}
|
|
4
|
+
{"ms":4,"ts":1784136601528,"tool":"Bash","session":"4aefeb66-3bff-4335-b710-e4f70d3adadf"}
|
|
5
|
+
{"ms":2,"ts":1784137482457,"tool":"Bash","session":"4aefeb66-3bff-4335-b710-e4f70d3adadf"}
|
|
6
|
+
{"ms":4,"ts":1784137524268,"tool":"Bash","session":"4aefeb66-3bff-4335-b710-e4f70d3adadf"}
|
|
7
|
+
{"ms":5,"ts":1784138159970,"tool":"Bash","session":"4aefeb66-3bff-4335-b710-e4f70d3adadf"}
|
|
8
|
+
{"ms":2,"ts":1784138167398,"tool":"Bash","session":"4aefeb66-3bff-4335-b710-e4f70d3adadf"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"tool":"Bash","ts":
|
|
1
|
+
{"tool":"Bash","ts":1784138162061}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"ms":
|
|
1
|
+
{"ms":2,"ts":1784138167398,"tool":"Bash","session":"4aefeb66-3bff-4335-b710-e4f70d3adadf"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
1784138162060
|
package/hooks/audit.mjs
CHANGED
|
@@ -8,10 +8,10 @@ import { readFileSync, existsSync, writeFileSync, mkdirSync, appendFileSync } fr
|
|
|
8
8
|
import { resolve, join, isAbsolute } from 'node:path';
|
|
9
9
|
import { homedir } from 'node:os';
|
|
10
10
|
|
|
11
|
-
// Bump on every audit
|
|
11
|
+
// Bump on every audit hook change. The cloud serves the newest version; the guard
|
|
12
12
|
// hook installs it on its next run (no re-login needed). See guard.mjs
|
|
13
13
|
// fetchAndInstallHook / maybeSelfUpdate.
|
|
14
|
-
const HOOK_VERSION =
|
|
14
|
+
const HOOK_VERSION = 16;
|
|
15
15
|
|
|
16
16
|
function loadEnvKey(dir) {
|
|
17
17
|
try {
|
|
@@ -268,6 +268,81 @@ function loadDlpRedact() {
|
|
|
268
268
|
} catch { return null; }
|
|
269
269
|
}
|
|
270
270
|
|
|
271
|
+
// ── DETECT-mode observation ──
|
|
272
|
+
// In DETECT mode the guard doesn't block (and doesn't log) — the call is ALLOWED
|
|
273
|
+
// and reaches THIS PostToolUse hook. To make "detect" mean observe-AND-record
|
|
274
|
+
// (not silent), we scan the ARGUMENTS for DLP hits and flag rate-limit bursts
|
|
275
|
+
// here, on the ALLOW entry. Block-mode hits are DENIED upstream and carry their
|
|
276
|
+
// own reason, so this only fires for detect-mode ALLOWs. Everything is wrapped
|
|
277
|
+
// fail-safe: any error just omits the field.
|
|
278
|
+
|
|
279
|
+
// Which DLP patterns match the stringified tool arguments (uses the enabled set
|
|
280
|
+
// the guard cached; block+detect both populate dlpRedact). Names only.
|
|
281
|
+
function dlpScanArgs(argsSummary, dlpCfg) {
|
|
282
|
+
try {
|
|
283
|
+
if (!dlpCfg || !Array.isArray(dlpCfg.patterns) || !dlpCfg.patterns.length) return [];
|
|
284
|
+
const text = typeof argsSummary === 'string' ? argsSummary : JSON.stringify(argsSummary || {});
|
|
285
|
+
if (!text) return [];
|
|
286
|
+
const enabled = new Set(dlpCfg.patterns);
|
|
287
|
+
const hits = [];
|
|
288
|
+
for (const p of DLP_PATTERNS) {
|
|
289
|
+
if (!enabled.has(p.name)) continue;
|
|
290
|
+
try { p.re.lastIndex = 0; if (p.re.test(text)) hits.push(p.name); } catch { /* skip */ }
|
|
291
|
+
if (hits.length >= 5) break;
|
|
292
|
+
}
|
|
293
|
+
for (const c of (dlpCfg.custom || [])) {
|
|
294
|
+
try { if (c && c.re && dlpGlobToRe(c.re, 'gi').test(text)) hits.push(c.name || 'custom'); } catch { /* skip */ }
|
|
295
|
+
if (hits.length >= 5) break;
|
|
296
|
+
}
|
|
297
|
+
return hits;
|
|
298
|
+
} catch { return []; }
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// Detect-mode rate-limit config (delivered only when mode === 'detect').
|
|
302
|
+
function loadRateLimitObserve() {
|
|
303
|
+
try {
|
|
304
|
+
const sel = (process.env.SOLONGATE_AGENT_ID || process.argv[2] || 'default').replace(/[^a-zA-Z0-9_-]/g, '_');
|
|
305
|
+
const f = resolve(homedir(), '.solongate', '.policy-cache-' + sel + '.json');
|
|
306
|
+
if (!existsSync(f)) return null;
|
|
307
|
+
const c = JSON.parse(readFileSync(f, 'utf-8'));
|
|
308
|
+
const r = c && c.security && c.security.rateLimitObserve;
|
|
309
|
+
return r && typeof r === 'object' ? r : null;
|
|
310
|
+
} catch { return null; }
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// Sliding-window burst check for DETECT mode. Uses a SEPARATE stamps file from
|
|
314
|
+
// the guard's enforcement file so observation never interferes with blocking.
|
|
315
|
+
// Returns true when this call is at/over an enabled window's limit.
|
|
316
|
+
function rateLimitObserveBurst(agentKey, limits) {
|
|
317
|
+
try {
|
|
318
|
+
if (!limits) return false;
|
|
319
|
+
const key = String(agentKey || 'default').replace(/[^a-zA-Z0-9_-]/g, '_');
|
|
320
|
+
const file = resolve(homedir(), '.solongate', '.ratelimit-observe-' + key + '.json');
|
|
321
|
+
const now = Date.now();
|
|
322
|
+
let stamps = [];
|
|
323
|
+
if (existsSync(file)) { try { stamps = JSON.parse(readFileSync(file, 'utf-8')); } catch { stamps = []; } }
|
|
324
|
+
if (!Array.isArray(stamps)) stamps = [];
|
|
325
|
+
stamps = stamps.filter((t) => typeof t === 'number' && now - t < 86400000);
|
|
326
|
+
if (stamps.length > 50000) stamps = stamps.slice(-50000);
|
|
327
|
+
const windows = [
|
|
328
|
+
{ key: 'perDay', ms: 86400000 },
|
|
329
|
+
{ key: 'perHour', ms: 3600000 },
|
|
330
|
+
{ key: 'perMinute', ms: 60000 },
|
|
331
|
+
];
|
|
332
|
+
let burst = false;
|
|
333
|
+
for (const w of windows) {
|
|
334
|
+
const limit = limits[w.key];
|
|
335
|
+
if (limit > 0) {
|
|
336
|
+
const count = stamps.reduce((n, t) => (now - t < w.ms ? n + 1 : n), 0);
|
|
337
|
+
if (count >= limit) { burst = true; break; }
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
stamps.push(now);
|
|
341
|
+
try { writeFileSync(file, JSON.stringify(stamps)); } catch { /* best-effort */ }
|
|
342
|
+
return burst;
|
|
343
|
+
} catch { return false; }
|
|
344
|
+
}
|
|
345
|
+
|
|
271
346
|
// Local log storage: the user can opt to keep a full copy of every audit entry
|
|
272
347
|
// in a file of their choosing (set from the dashboard survey / Settings, then
|
|
273
348
|
// delivered to us via the same policy cache the guard writes). We append one
|
|
@@ -560,6 +635,17 @@ try { input += readFileSync(0, 'utf-8'); } catch {}
|
|
|
560
635
|
const permission = guessPermission(toolName);
|
|
561
636
|
const evaluationTimeMs = readLastEvalMs(toolName, sessionId);
|
|
562
637
|
|
|
638
|
+
// DETECT-mode observation: record DLP matches / rate-limit bursts on this
|
|
639
|
+
// ALLOW entry so "detect" means observe-AND-log (not silent). Fail-safe —
|
|
640
|
+
// any error leaves the fields off. Only meaningful on ALLOW (block-mode hits
|
|
641
|
+
// are DENIED upstream with their own reason).
|
|
642
|
+
let dlpMatches = [];
|
|
643
|
+
let rateLimitBurst = false;
|
|
644
|
+
if (decision === 'ALLOW') {
|
|
645
|
+
try { dlpMatches = dlpScanArgs(argsSummary, loadDlpRedact()); } catch { dlpMatches = []; }
|
|
646
|
+
try { rateLimitBurst = rateLimitObserveBurst(AGENT_ID, loadRateLimitObserve()); } catch { rateLimitBurst = false; }
|
|
647
|
+
}
|
|
648
|
+
|
|
563
649
|
// Local log storage (opt-in): when ON, logs are kept LOCAL ONLY — we append
|
|
564
650
|
// this entry to the user's chosen file and do NOT send it to the cloud.
|
|
565
651
|
const localLogs = loadLocalLogs();
|
|
@@ -568,6 +654,8 @@ try { input += readFileSync(0, 'utf-8'); } catch {}
|
|
|
568
654
|
ts: new Date().toISOString(),
|
|
569
655
|
tool: toolName, arguments: argsSummary, decision, reason, permission,
|
|
570
656
|
evaluation_time_ms: evaluationTimeMs, agent_id: AGENT_ID, agent_name: AGENT_NAME, session_id: sessionId,
|
|
657
|
+
...(dlpMatches.length ? { dlp: dlpMatches } : {}),
|
|
658
|
+
...(rateLimitBurst ? { rate_limit_burst: true } : {}),
|
|
571
659
|
});
|
|
572
660
|
fetchDone = true;
|
|
573
661
|
maybeExit();
|
|
@@ -594,6 +682,8 @@ try { input += readFileSync(0, 'utf-8'); } catch {}
|
|
|
594
682
|
agent_id: AGENT_ID,
|
|
595
683
|
agent_name: AGENT_NAME,
|
|
596
684
|
session_id: sessionId,
|
|
685
|
+
...(dlpMatches.length ? { dlp: dlpMatches } : {}),
|
|
686
|
+
...(rateLimitBurst ? { rate_limit_burst: true } : {}),
|
|
597
687
|
}),
|
|
598
688
|
signal: AbortSignal.timeout(5000),
|
|
599
689
|
}).catch(() => {}).finally(() => { fetchDone = true; maybeExit(); });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@solongate/proxy",
|
|
3
|
-
"version": "0.81.
|
|
3
|
+
"version": "0.81.34",
|
|
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": {
|