@node9/proxy 1.29.0 → 1.30.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/cli.js +845 -650
- package/dist/cli.mjs +817 -623
- package/dist/dashboard.mjs +9 -2
- package/dist/index.js +64 -149
- package/dist/index.mjs +61 -146
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -51,11 +51,17 @@ __export(audit_exports, {
|
|
|
51
51
|
appendHookDebug: () => appendHookDebug,
|
|
52
52
|
appendLocalAudit: () => appendLocalAudit,
|
|
53
53
|
appendToLog: () => appendToLog,
|
|
54
|
+
buildArgsPreview: () => buildArgsPreview,
|
|
55
|
+
generateEventId: () => generateEventId,
|
|
54
56
|
redactSecrets: () => redactSecrets
|
|
55
57
|
});
|
|
56
58
|
import fs from "fs";
|
|
57
59
|
import path from "path";
|
|
58
60
|
import os from "os";
|
|
61
|
+
import crypto from "crypto";
|
|
62
|
+
function generateEventId() {
|
|
63
|
+
return `${Date.now().toString(36)}-${crypto.randomBytes(6).toString("hex")}`;
|
|
64
|
+
}
|
|
59
65
|
function isTestCall(toolName, args) {
|
|
60
66
|
if (toolName !== "Bash" && toolName !== "bash") return false;
|
|
61
67
|
const cmd = args?.command;
|
|
@@ -74,6 +80,17 @@ function redactSecrets(text) {
|
|
|
74
80
|
);
|
|
75
81
|
return redacted;
|
|
76
82
|
}
|
|
83
|
+
function buildArgsPreview(args) {
|
|
84
|
+
try {
|
|
85
|
+
const o = args && typeof args === "object" ? args : null;
|
|
86
|
+
const primary = o && (o.command ?? o.file_path ?? o.path ?? o.url ?? o.query);
|
|
87
|
+
const text = typeof primary === "string" ? primary : args ? JSON.stringify(args) : "";
|
|
88
|
+
if (!text) return void 0;
|
|
89
|
+
return redactSecrets(text).slice(0, 120);
|
|
90
|
+
} catch {
|
|
91
|
+
return void 0;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
77
94
|
function appendToLog(logPath, entry) {
|
|
78
95
|
try {
|
|
79
96
|
const dir = path.dirname(logPath);
|
|
@@ -96,11 +113,18 @@ function appendHookDebug(toolName, args, meta, auditHashArgsEnabled) {
|
|
|
96
113
|
});
|
|
97
114
|
}
|
|
98
115
|
function appendLocalAudit(toolName, args, decision, checkedBy, meta, auditHashArgsEnabled) {
|
|
99
|
-
const
|
|
116
|
+
const isDlpRow = checkedBy.toLowerCase().includes("dlp") || Boolean(meta?.dlpPattern);
|
|
117
|
+
const preview = auditHashArgsEnabled && !isDlpRow ? buildArgsPreview(args) : void 0;
|
|
118
|
+
const argsField = auditHashArgsEnabled ? { argsHash: hashArgs(args), ...preview ? { argsPreview: preview } : {} } : { args: args ? JSON.parse(redactSecrets(JSON.stringify(args))) : {} };
|
|
100
119
|
const testRun = isTestCall(toolName, args) || process.env.NODE9_TESTING === "1" ? { testRun: true } : {};
|
|
101
120
|
const ruleNameField = meta?.ruleName ? { ruleName: meta.ruleName } : {};
|
|
102
121
|
const agentToolNameField = meta?.agentToolName ? { agentToolName: meta.agentToolName } : {};
|
|
122
|
+
const dlpFields = meta?.dlpPattern ? { dlpPattern: meta.dlpPattern, dlpSample: meta.dlpSample } : {};
|
|
123
|
+
const cloudLinkField = meta?.cloudRequestId ? { cloudRequestId: meta.cloudRequestId } : {};
|
|
103
124
|
appendToLog(LOCAL_AUDIT_LOG, {
|
|
125
|
+
// eid first: the outbox shipper dedups on it, and a fixed leading field
|
|
126
|
+
// makes the JSONL easy to eyeball.
|
|
127
|
+
eid: generateEventId(),
|
|
104
128
|
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
105
129
|
tool: toolName,
|
|
106
130
|
...agentToolNameField,
|
|
@@ -108,6 +132,8 @@ function appendLocalAudit(toolName, args, decision, checkedBy, meta, auditHashAr
|
|
|
108
132
|
decision,
|
|
109
133
|
checkedBy,
|
|
110
134
|
...ruleNameField,
|
|
135
|
+
...dlpFields,
|
|
136
|
+
...cloudLinkField,
|
|
111
137
|
...testRun,
|
|
112
138
|
agent: meta?.agent,
|
|
113
139
|
mcpServer: meta?.mcpServer,
|
|
@@ -216,7 +242,13 @@ var ConfigFileSchema = z.object({
|
|
|
216
242
|
allowGlobalPause: z.boolean().optional(),
|
|
217
243
|
auditHashArgs: z.boolean().optional(),
|
|
218
244
|
agentPolicy: z.enum(["require_approval", "block_on_rules"]).optional(),
|
|
219
|
-
cloudSyncIntervalHours: z.number().positive().optional()
|
|
245
|
+
cloudSyncIntervalHours: z.number().positive().optional(),
|
|
246
|
+
// Outbox shipper (audit.log → SaaS batch ingest). enabled defaults
|
|
247
|
+
// to true; set false to fall back to local-only auditing.
|
|
248
|
+
shipper: z.object({
|
|
249
|
+
enabled: z.boolean().optional(),
|
|
250
|
+
intervalSeconds: z.number().min(5).optional()
|
|
251
|
+
}).optional()
|
|
220
252
|
}).optional(),
|
|
221
253
|
policy: z.object({
|
|
222
254
|
sandboxPaths: z.array(z.string()).optional(),
|
|
@@ -284,7 +316,7 @@ import mvdanSh from "mvdan-sh";
|
|
|
284
316
|
import pm from "picomatch";
|
|
285
317
|
import safeRegex2 from "safe-regex2";
|
|
286
318
|
import safeRegex3 from "safe-regex2";
|
|
287
|
-
import
|
|
319
|
+
import crypto2 from "crypto";
|
|
288
320
|
var ASSIGNMENT_CONTEXT_RE = /\b(?:password|passwd|secret|token|api[_-]?key|auth(?:_key|_token)?|credential|private[_-]?key|access[_-]?key|client[_-]?secret)\s*[=:]\s*/i;
|
|
289
321
|
function isAssignmentContext(text) {
|
|
290
322
|
return ASSIGNMENT_CONTEXT_RE.test(text);
|
|
@@ -2817,7 +2849,7 @@ assertBuiltinShieldRegexesAreSafe();
|
|
|
2817
2849
|
var LOOP_MAX_RECORDS = 500;
|
|
2818
2850
|
function computeArgsHash(args) {
|
|
2819
2851
|
const str = JSON.stringify(args ?? "");
|
|
2820
|
-
return
|
|
2852
|
+
return crypto2.createHash("sha256").update(str).digest("hex").slice(0, 16);
|
|
2821
2853
|
}
|
|
2822
2854
|
function evaluateLoopWindow(records, tool, args, threshold, windowMs, now) {
|
|
2823
2855
|
const hash = computeArgsHash(args);
|
|
@@ -2930,7 +2962,8 @@ var DEFAULT_CONFIG = {
|
|
|
2930
2962
|
flightRecorder: true,
|
|
2931
2963
|
auditHashArgs: true,
|
|
2932
2964
|
approvers: { native: true, browser: false, cloud: false, terminal: true },
|
|
2933
|
-
cloudSyncIntervalHours: 5
|
|
2965
|
+
cloudSyncIntervalHours: 5,
|
|
2966
|
+
shipper: { enabled: true, intervalSeconds: 20 }
|
|
2934
2967
|
},
|
|
2935
2968
|
policy: {
|
|
2936
2969
|
sandboxPaths: ["/tmp/**", "**/sandbox/**", "**/test-results/**"],
|
|
@@ -3225,7 +3258,8 @@ function getConfig(cwd) {
|
|
|
3225
3258
|
const projectConfig = tryLoadConfig(projectPath);
|
|
3226
3259
|
const mergedSettings = {
|
|
3227
3260
|
...DEFAULT_CONFIG.settings,
|
|
3228
|
-
approvers: { ...DEFAULT_CONFIG.settings.approvers }
|
|
3261
|
+
approvers: { ...DEFAULT_CONFIG.settings.approvers },
|
|
3262
|
+
shipper: { ...DEFAULT_CONFIG.settings.shipper }
|
|
3229
3263
|
};
|
|
3230
3264
|
const mergedPolicy = {
|
|
3231
3265
|
sandboxPaths: [...DEFAULT_CONFIG.policy.sandboxPaths],
|
|
@@ -3256,6 +3290,7 @@ function getConfig(cwd) {
|
|
|
3256
3290
|
if (s.enableHookLogDebug !== void 0)
|
|
3257
3291
|
mergedSettings.enableHookLogDebug = s.enableHookLogDebug;
|
|
3258
3292
|
if (s.approvers) mergedSettings.approvers = { ...mergedSettings.approvers, ...s.approvers };
|
|
3293
|
+
if (s.shipper) mergedSettings.shipper = { ...mergedSettings.shipper, ...s.shipper };
|
|
3259
3294
|
if (s.approvalTimeoutMs !== void 0) mergedSettings.approvalTimeoutMs = s.approvalTimeoutMs;
|
|
3260
3295
|
if (s.approvalTimeoutSeconds !== void 0 && s.approvalTimeoutMs === void 0)
|
|
3261
3296
|
mergedSettings.approvalTimeoutMs = s.approvalTimeoutSeconds * 1e3;
|
|
@@ -4251,91 +4286,6 @@ init_audit();
|
|
|
4251
4286
|
import fs9 from "fs";
|
|
4252
4287
|
import os8 from "os";
|
|
4253
4288
|
import path11 from "path";
|
|
4254
|
-
var DLP_SAMPLE_MAX_LEN = 200;
|
|
4255
|
-
var DLP_PATTERN_MAX_LEN = 100;
|
|
4256
|
-
var KNOWN_CHECKED_BY = /* @__PURE__ */ new Set([
|
|
4257
|
-
"dlp-block",
|
|
4258
|
-
"observe-mode-dlp-would-block",
|
|
4259
|
-
"dlp-review-flagged",
|
|
4260
|
-
"loop-detected",
|
|
4261
|
-
"audit-mode",
|
|
4262
|
-
"local-policy",
|
|
4263
|
-
"smart-rule-block",
|
|
4264
|
-
// Smart-rule block was downgraded to review because the daemon was
|
|
4265
|
-
// running and we're not in CI. The block attempt is still recorded;
|
|
4266
|
-
// the user got a popup. Distinct from 'smart-rule-block' so the
|
|
4267
|
-
// dashboard can show "block rule overridden" separately from a hard
|
|
4268
|
-
// block that fired with no human in the loop.
|
|
4269
|
-
"smart-rule-block-override",
|
|
4270
|
-
"persistent",
|
|
4271
|
-
"trust",
|
|
4272
|
-
"observe-mode",
|
|
4273
|
-
"observe-mode-would-block"
|
|
4274
|
-
]);
|
|
4275
|
-
function validateApiUrl(raw) {
|
|
4276
|
-
let u;
|
|
4277
|
-
try {
|
|
4278
|
-
u = new URL(raw);
|
|
4279
|
-
} catch {
|
|
4280
|
-
return null;
|
|
4281
|
-
}
|
|
4282
|
-
if (u.username || u.password) return null;
|
|
4283
|
-
if (u.protocol === "https:") return u;
|
|
4284
|
-
if (u.protocol === "http:") {
|
|
4285
|
-
const h = u.hostname;
|
|
4286
|
-
if (h === "127.0.0.1" || h === "localhost" || h === "::1" || h === "[::1]") return u;
|
|
4287
|
-
}
|
|
4288
|
-
return null;
|
|
4289
|
-
}
|
|
4290
|
-
function auditLocalAllow(toolName, args, checkedBy, creds, meta, dlpInfo, containsSensitiveArgs = false, riskMetadata) {
|
|
4291
|
-
const validated = validateApiUrl(creds.apiUrl);
|
|
4292
|
-
if (!validated) {
|
|
4293
|
-
try {
|
|
4294
|
-
fs9.appendFileSync(
|
|
4295
|
-
HOOK_DEBUG_LOG,
|
|
4296
|
-
`[audit] refused to send: invalid apiUrl scheme/host (got "${String(creds.apiUrl).slice(0, 200)}")
|
|
4297
|
-
`
|
|
4298
|
-
);
|
|
4299
|
-
} catch {
|
|
4300
|
-
}
|
|
4301
|
-
return Promise.resolve();
|
|
4302
|
-
}
|
|
4303
|
-
const safeArgs = containsSensitiveArgs ? { tool: toolName, redacted: true } : args;
|
|
4304
|
-
const dlpSample = dlpInfo && typeof dlpInfo.redactedSample === "string" ? dlpInfo.redactedSample.slice(0, DLP_SAMPLE_MAX_LEN) : void 0;
|
|
4305
|
-
const dlpPattern = dlpInfo && typeof dlpInfo.pattern === "string" ? dlpInfo.pattern.slice(0, DLP_PATTERN_MAX_LEN) : void 0;
|
|
4306
|
-
const safeCheckedBy = KNOWN_CHECKED_BY.has(checkedBy) ? checkedBy : "unknown";
|
|
4307
|
-
const cleanedRiskMetadata = riskMetadata ? Object.fromEntries(
|
|
4308
|
-
Object.entries(riskMetadata).filter(([, v]) => typeof v === "string" && v.length > 0)
|
|
4309
|
-
) : void 0;
|
|
4310
|
-
const hasRiskMetadata = cleanedRiskMetadata && Object.keys(cleanedRiskMetadata).length > 0;
|
|
4311
|
-
return fetch(`${validated.toString().replace(/\/$/, "")}/audit`, {
|
|
4312
|
-
method: "POST",
|
|
4313
|
-
headers: { "Content-Type": "application/json", Authorization: `Bearer ${creds.apiKey}` },
|
|
4314
|
-
body: JSON.stringify({
|
|
4315
|
-
toolName,
|
|
4316
|
-
args: safeArgs,
|
|
4317
|
-
checkedBy: safeCheckedBy,
|
|
4318
|
-
...dlpInfo && { dlpPattern, dlpSample },
|
|
4319
|
-
...hasRiskMetadata && { riskMetadata: cleanedRiskMetadata },
|
|
4320
|
-
// session_id (Claude Code + Gemini CLI) groups all audit rows from one
|
|
4321
|
-
// agent run; transcript_path is the authoritative pointer to the
|
|
4322
|
-
// session log (survives Gemini resume drift). Both optional —
|
|
4323
|
-
// unsupported agents (MCP-mediated) leave them undefined.
|
|
4324
|
-
...meta?.sessionId && { runId: meta.sessionId },
|
|
4325
|
-
...meta?.transcriptPath && { transcriptPath: meta.transcriptPath },
|
|
4326
|
-
context: {
|
|
4327
|
-
agent: meta?.agent,
|
|
4328
|
-
mcpServer: meta?.mcpServer,
|
|
4329
|
-
hostname: os8.hostname(),
|
|
4330
|
-
cwd: process.cwd(),
|
|
4331
|
-
platform: os8.platform()
|
|
4332
|
-
}
|
|
4333
|
-
}),
|
|
4334
|
-
signal: AbortSignal.timeout(5e3)
|
|
4335
|
-
}).then(() => {
|
|
4336
|
-
}).catch(() => {
|
|
4337
|
-
});
|
|
4338
|
-
}
|
|
4339
4289
|
async function initNode9SaaS(toolName, args, creds, meta, riskMetadata, agentPolicy, forceReview) {
|
|
4340
4290
|
const controller = new AbortController();
|
|
4341
4291
|
const timeout = setTimeout(() => controller.abort(), 1e4);
|
|
@@ -4641,17 +4591,11 @@ async function _authorizeHeadlessCore(toolName, args, meta, options) {
|
|
|
4641
4591
|
args,
|
|
4642
4592
|
"deny",
|
|
4643
4593
|
isObserveMode ? "observe-mode-dlp-would-block" : "dlp-block",
|
|
4644
|
-
|
|
4645
|
-
|
|
4646
|
-
|
|
4647
|
-
|
|
4648
|
-
|
|
4649
|
-
toolName,
|
|
4650
|
-
args,
|
|
4651
|
-
isObserveMode ? "observe-mode-dlp-would-block" : "dlp-block",
|
|
4652
|
-
creds,
|
|
4653
|
-
meta,
|
|
4654
|
-
{ pattern: dlpMatch.patternName, redactedSample: dlpMatch.redactedSample },
|
|
4594
|
+
{
|
|
4595
|
+
...meta,
|
|
4596
|
+
dlpPattern: dlpMatch.patternName,
|
|
4597
|
+
dlpSample: dlpMatch.redactedSample
|
|
4598
|
+
},
|
|
4655
4599
|
true
|
|
4656
4600
|
);
|
|
4657
4601
|
if (isWriteTool(toolName) && filePath) {
|
|
@@ -4707,9 +4651,6 @@ async function _authorizeHeadlessCore(toolName, args, meta, options) {
|
|
|
4707
4651
|
const policyResult = await evaluatePolicy2(toolName, args, meta?.agent, options?.cwd);
|
|
4708
4652
|
if (policyResult.decision === "review") {
|
|
4709
4653
|
appendLocalAudit(toolName, args, "allow", "audit-mode", meta, hashAuditArgs);
|
|
4710
|
-
if (approvers.cloud && creds?.apiKey) {
|
|
4711
|
-
await auditLocalAllow(toolName, args, "audit-mode", creds, meta);
|
|
4712
|
-
}
|
|
4713
4654
|
}
|
|
4714
4655
|
}
|
|
4715
4656
|
return { approved: true, checkedBy: "audit" };
|
|
@@ -4722,8 +4663,6 @@ async function _authorizeHeadlessCore(toolName, args, meta, options) {
|
|
|
4722
4663
|
const reason = `It looks like you've called "${toolName}" ${loopResult.count} times with identical arguments in the last ${ld.windowSeconds}s. Are you stuck? Step back and reconsider your approach \u2014 what are you actually trying to accomplish, and is there a different way to get there?`;
|
|
4723
4664
|
if (!isManual)
|
|
4724
4665
|
appendLocalAudit(toolName, args, "deny", "loop-detected", meta, hashAuditArgs);
|
|
4725
|
-
if (approvers.cloud && creds?.apiKey)
|
|
4726
|
-
auditLocalAllow(toolName, args, "loop-detected", creds, meta, void 0, true);
|
|
4727
4666
|
return {
|
|
4728
4667
|
approved: false,
|
|
4729
4668
|
reason,
|
|
@@ -4742,15 +4681,15 @@ async function _authorizeHeadlessCore(toolName, args, meta, options) {
|
|
|
4742
4681
|
};
|
|
4743
4682
|
}
|
|
4744
4683
|
if (policyResult.decision === "allow") {
|
|
4745
|
-
if (
|
|
4746
|
-
|
|
4747
|
-
|
|
4748
|
-
|
|
4749
|
-
|
|
4750
|
-
|
|
4751
|
-
|
|
4752
|
-
|
|
4753
|
-
|
|
4684
|
+
if (!isManual)
|
|
4685
|
+
appendLocalAudit(
|
|
4686
|
+
toolName,
|
|
4687
|
+
args,
|
|
4688
|
+
"allow",
|
|
4689
|
+
"local-policy",
|
|
4690
|
+
{ ...meta, ruleName: policyResult.ruleName },
|
|
4691
|
+
hashAuditArgs
|
|
4692
|
+
);
|
|
4754
4693
|
return { approved: true, checkedBy: "local-policy" };
|
|
4755
4694
|
}
|
|
4756
4695
|
if (policyResult.decision === "block") {
|
|
@@ -4783,23 +4722,6 @@ async function _authorizeHeadlessCore(toolName, args, meta, options) {
|
|
|
4783
4722
|
{ ...meta, ruleName: policyResult.ruleName },
|
|
4784
4723
|
hashAuditArgs
|
|
4785
4724
|
);
|
|
4786
|
-
if (approvers.cloud && creds?.apiKey)
|
|
4787
|
-
auditLocalAllow(
|
|
4788
|
-
toolName,
|
|
4789
|
-
args,
|
|
4790
|
-
"smart-rule-block-override",
|
|
4791
|
-
creds,
|
|
4792
|
-
meta,
|
|
4793
|
-
void 0,
|
|
4794
|
-
false,
|
|
4795
|
-
{
|
|
4796
|
-
ruleName: policyResult.ruleName,
|
|
4797
|
-
ruleDescription: policyResult.ruleDescription,
|
|
4798
|
-
blockedByLabel: policyResult.blockedByLabel,
|
|
4799
|
-
matchedField: policyResult.matchedField,
|
|
4800
|
-
matchedWord: policyResult.matchedWord
|
|
4801
|
-
}
|
|
4802
|
-
);
|
|
4803
4725
|
const baseLabel = policyResult.blockedByLabel || "Smart Rule";
|
|
4804
4726
|
const OVERRIDE_PREFIX = "\u26A0\uFE0F Override block rule: ";
|
|
4805
4727
|
if (!baseLabel.startsWith(OVERRIDE_PREFIX)) {
|
|
@@ -4824,14 +4746,6 @@ async function _authorizeHeadlessCore(toolName, args, meta, options) {
|
|
|
4824
4746
|
{ ...meta, ruleName: policyResult.ruleName },
|
|
4825
4747
|
hashAuditArgs
|
|
4826
4748
|
);
|
|
4827
|
-
if (approvers.cloud && creds?.apiKey)
|
|
4828
|
-
auditLocalAllow(toolName, args, "smart-rule-block", creds, meta, void 0, false, {
|
|
4829
|
-
ruleName: policyResult.ruleName,
|
|
4830
|
-
ruleDescription: policyResult.ruleDescription,
|
|
4831
|
-
blockedByLabel: policyResult.blockedByLabel,
|
|
4832
|
-
matchedField: policyResult.matchedField,
|
|
4833
|
-
matchedWord: policyResult.matchedWord
|
|
4834
|
-
});
|
|
4835
4749
|
return {
|
|
4836
4750
|
approved: false,
|
|
4837
4751
|
reason: policyResult.reason ?? "Action explicitly blocked by Smart Policy.",
|
|
@@ -4860,8 +4774,6 @@ async function _authorizeHeadlessCore(toolName, args, meta, options) {
|
|
|
4860
4774
|
if (policyRuleDescription) riskMetadata.ruleDescription = policyRuleDescription.slice(0, 200);
|
|
4861
4775
|
const persistent = policyResult.ruleName ? null : getPersistentDecision(toolName);
|
|
4862
4776
|
if (persistent === "allow") {
|
|
4863
|
-
if (approvers.cloud && creds?.apiKey)
|
|
4864
|
-
await auditLocalAllow(toolName, args, "persistent", creds, meta);
|
|
4865
4777
|
if (!isManual) appendLocalAudit(toolName, args, "allow", "persistent", meta, hashAuditArgs);
|
|
4866
4778
|
return { approved: true, checkedBy: "persistent" };
|
|
4867
4779
|
}
|
|
@@ -4894,8 +4806,6 @@ async function _authorizeHeadlessCore(toolName, args, meta, options) {
|
|
|
4894
4806
|
}
|
|
4895
4807
|
}
|
|
4896
4808
|
if (!taintWarning && getActiveTrustSession(toolName, args)) {
|
|
4897
|
-
if (approvers.cloud && creds?.apiKey)
|
|
4898
|
-
await auditLocalAllow(toolName, args, "trust", creds, meta);
|
|
4899
4809
|
if (!isManual) appendLocalAudit(toolName, args, "allow", "trust", meta, hashAuditArgs);
|
|
4900
4810
|
return { approved: true, checkedBy: "trust" };
|
|
4901
4811
|
}
|
|
@@ -5140,7 +5050,12 @@ REASON: Action blocked because no approval channels are available. (Native/Brows
|
|
|
5140
5050
|
args,
|
|
5141
5051
|
finalResult.approved ? "allow" : "deny",
|
|
5142
5052
|
finalResult.checkedBy || finalResult.blockedBy || "unknown",
|
|
5143
|
-
|
|
5053
|
+
// cloudRequestId links this row to the BE-origin AuditLog row the
|
|
5054
|
+
// /intercept handshake created — the shipper hands it to the SaaS so
|
|
5055
|
+
// the BE enriches that row instead of inserting a duplicate. Matters
|
|
5056
|
+
// for EVERY racer outcome, not just cloud wins: a native-popup
|
|
5057
|
+
// decision on a cloud-pending request would otherwise count twice.
|
|
5058
|
+
cloudRequestId ? { ...meta, cloudRequestId } : meta,
|
|
5144
5059
|
hashAuditArgs
|
|
5145
5060
|
);
|
|
5146
5061
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@node9/proxy",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.30.0",
|
|
4
4
|
"description": "The Sudo Command for AI Agents. Execution Security for Claude Code, Codex, Gemini, Cursor, Opencode, Pi, and any MCP server.",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|