@node9/proxy 1.67.5 → 2.1.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 +1568 -1841
- package/dist/cli.mjs +1561 -1834
- package/dist/dashboard.mjs +0 -60
- package/dist/index.js +3 -50
- package/dist/index.mjs +3 -50
- package/dist/scan-ink.mjs +100 -54
- package/package.json +1 -1
package/dist/dashboard.mjs
CHANGED
|
@@ -2596,19 +2596,6 @@ var init_config = __esm({
|
|
|
2596
2596
|
settings: {
|
|
2597
2597
|
mode: "standard",
|
|
2598
2598
|
autoStartDaemon: true,
|
|
2599
|
-
// The undo feature was REMOVED. This default is one of two places that say
|
|
2600
|
-
// so; the other is the pin further down, which overwrites whatever a config
|
|
2601
|
-
// file, the dashboard or the cloud supplies. Setting `enableUndo` anywhere
|
|
2602
|
-
// has no effect — do not restore the advice that used to live here, because
|
|
2603
|
-
// a comment recommending a knob that is silently discarded is the same lie
|
|
2604
|
-
// on disk the pin exists to prevent.
|
|
2605
|
-
//
|
|
2606
|
-
// Why it went: the store was a per-project bare git repo with no size
|
|
2607
|
-
// ceiling, and eviction dropped the index row without deleting the objects.
|
|
2608
|
-
// On one machine it reached 378G (352G of it orphaned tmp_pack_* from an
|
|
2609
|
-
// interrupted `git gc`) and filled the disk. A security tool must not be
|
|
2610
|
-
// what fills a customer's disk. Leftovers: `node9 undo --purge`.
|
|
2611
|
-
enableUndo: false,
|
|
2612
2599
|
enableHookLogDebug: true,
|
|
2613
2600
|
approvalTimeoutMs: 12e4,
|
|
2614
2601
|
// 120-second auto-deny timeout
|
|
@@ -2649,25 +2636,6 @@ var init_config = __esm({
|
|
|
2649
2636
|
"terminal.execute": "command",
|
|
2650
2637
|
"postgres:query": "sql"
|
|
2651
2638
|
},
|
|
2652
|
-
snapshot: {
|
|
2653
|
-
tools: [
|
|
2654
|
-
"str_replace_based_edit_tool",
|
|
2655
|
-
"write_file",
|
|
2656
|
-
"edit_file",
|
|
2657
|
-
"create_file",
|
|
2658
|
-
"edit",
|
|
2659
|
-
"replace",
|
|
2660
|
-
// Claude / canonicalised Hermes — shouldSnapshot lowercases the
|
|
2661
|
-
// incoming name before set-membership, so we list the lowercase
|
|
2662
|
-
// forms of `Bash`/`Write`/`Edit`/`MultiEdit`. Without these,
|
|
2663
|
-
// post-canonicalisation Hermes `patch` / `write_file` (which now
|
|
2664
|
-
// arrive as `Edit` / `Write`) silently skipped snapshotting.
|
|
2665
|
-
"write",
|
|
2666
|
-
"multiedit"
|
|
2667
|
-
],
|
|
2668
|
-
onlyPaths: [],
|
|
2669
|
-
ignorePaths: ["**/node_modules/**", "dist/**", "build/**", ".next/**", "**/*.log"]
|
|
2670
|
-
},
|
|
2671
2639
|
smartRules: [
|
|
2672
2640
|
// ── rm safety (critical — always evaluated first) ──────────────────────
|
|
2673
2641
|
{
|
|
@@ -3919,7 +3887,6 @@ var init_provenance = __esm({
|
|
|
3919
3887
|
});
|
|
3920
3888
|
|
|
3921
3889
|
// src/policy/index.ts
|
|
3922
|
-
import pm2 from "picomatch";
|
|
3923
3890
|
var init_policy = __esm({
|
|
3924
3891
|
"src/policy/index.ts"() {
|
|
3925
3892
|
"use strict";
|
|
@@ -5442,17 +5409,6 @@ function subscribeToSse(onEvent, onResolve, onForensic, onError) {
|
|
|
5442
5409
|
function toActivityEvent(eventName, data) {
|
|
5443
5410
|
const payload = data.activity ?? data;
|
|
5444
5411
|
const ts = normalizeTs(payload.ts);
|
|
5445
|
-
if (eventName === "snapshot") {
|
|
5446
|
-
const rawSummary = payload.argsSummary ?? payload.tool ?? "snapshot";
|
|
5447
|
-
return {
|
|
5448
|
-
kind: "snapshot",
|
|
5449
|
-
id: payload.id ?? `${ts}-snapshot`,
|
|
5450
|
-
ts,
|
|
5451
|
-
hash: payload.hash ?? "",
|
|
5452
|
-
summary: compactPath(rawSummary),
|
|
5453
|
-
fileCount: typeof payload.fileCount === "number" ? payload.fileCount : 0
|
|
5454
|
-
};
|
|
5455
|
-
}
|
|
5456
5412
|
if (eventName !== "activity" && eventName !== "add") return null;
|
|
5457
5413
|
const toolName = payload.tool ?? payload.toolName;
|
|
5458
5414
|
if (!toolName) return null;
|
|
@@ -5843,9 +5799,6 @@ function applyFilter(events, filter) {
|
|
|
5843
5799
|
if (!filter) return events;
|
|
5844
5800
|
const needle = filter.toLowerCase();
|
|
5845
5801
|
return events.filter((e) => {
|
|
5846
|
-
if (e.kind === "snapshot") {
|
|
5847
|
-
return e.hash.toLowerCase().includes(needle) || e.summary.toLowerCase().includes(needle);
|
|
5848
|
-
}
|
|
5849
5802
|
if (e.tool.toLowerCase().includes(needle)) return true;
|
|
5850
5803
|
if (e.agent && e.agent.toLowerCase().includes(needle)) return true;
|
|
5851
5804
|
if (e.preview.toLowerCase().includes(needle)) return true;
|
|
@@ -5856,19 +5809,6 @@ function applyFilter(events, filter) {
|
|
|
5856
5809
|
}
|
|
5857
5810
|
function ActivityRow({ event }) {
|
|
5858
5811
|
const t = localTimeOf(event.ts);
|
|
5859
|
-
if (event.kind === "snapshot") {
|
|
5860
|
-
const filesSuffix = event.fileCount > 0 ? ` \xB7 ${event.fileCount} file${event.fileCount === 1 ? "" : "s"}` : "";
|
|
5861
|
-
return /* @__PURE__ */ jsxs(Text, { wrap: "truncate-end", children: [
|
|
5862
|
-
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
5863
|
-
t,
|
|
5864
|
-
" "
|
|
5865
|
-
] }),
|
|
5866
|
-
/* @__PURE__ */ jsx(Text, { color: COL.agentClaude, children: "\u{1F4F8} snapshot" }),
|
|
5867
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: ` ${event.hash} ` }),
|
|
5868
|
-
/* @__PURE__ */ jsx(Text, { children: event.summary }),
|
|
5869
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: filesSuffix })
|
|
5870
|
-
] });
|
|
5871
|
-
}
|
|
5872
5812
|
const agentLabel = event.agent ? `[${truncate(capitalize(event.agent), 8)}]`.padEnd(10) : " ".repeat(10);
|
|
5873
5813
|
const isLoop = event.checkedBy === "loop-detected";
|
|
5874
5814
|
const verdictIcon = isLoop ? "\u{1F501}" : event.verdict === "block" ? "\u{1F6D1}" : event.verdict === "review" ? "\u{1F7E1}" : event.verdict === "allow" ? "\u2713 " : "\u2026 ";
|
package/dist/index.js
CHANGED
|
@@ -4180,19 +4180,6 @@ var DEFAULT_CONFIG = {
|
|
|
4180
4180
|
settings: {
|
|
4181
4181
|
mode: "standard",
|
|
4182
4182
|
autoStartDaemon: true,
|
|
4183
|
-
// The undo feature was REMOVED. This default is one of two places that say
|
|
4184
|
-
// so; the other is the pin further down, which overwrites whatever a config
|
|
4185
|
-
// file, the dashboard or the cloud supplies. Setting `enableUndo` anywhere
|
|
4186
|
-
// has no effect — do not restore the advice that used to live here, because
|
|
4187
|
-
// a comment recommending a knob that is silently discarded is the same lie
|
|
4188
|
-
// on disk the pin exists to prevent.
|
|
4189
|
-
//
|
|
4190
|
-
// Why it went: the store was a per-project bare git repo with no size
|
|
4191
|
-
// ceiling, and eviction dropped the index row without deleting the objects.
|
|
4192
|
-
// On one machine it reached 378G (352G of it orphaned tmp_pack_* from an
|
|
4193
|
-
// interrupted `git gc`) and filled the disk. A security tool must not be
|
|
4194
|
-
// what fills a customer's disk. Leftovers: `node9 undo --purge`.
|
|
4195
|
-
enableUndo: false,
|
|
4196
4183
|
enableHookLogDebug: true,
|
|
4197
4184
|
approvalTimeoutMs: 12e4,
|
|
4198
4185
|
// 120-second auto-deny timeout
|
|
@@ -4233,25 +4220,6 @@ var DEFAULT_CONFIG = {
|
|
|
4233
4220
|
"terminal.execute": "command",
|
|
4234
4221
|
"postgres:query": "sql"
|
|
4235
4222
|
},
|
|
4236
|
-
snapshot: {
|
|
4237
|
-
tools: [
|
|
4238
|
-
"str_replace_based_edit_tool",
|
|
4239
|
-
"write_file",
|
|
4240
|
-
"edit_file",
|
|
4241
|
-
"create_file",
|
|
4242
|
-
"edit",
|
|
4243
|
-
"replace",
|
|
4244
|
-
// Claude / canonicalised Hermes — shouldSnapshot lowercases the
|
|
4245
|
-
// incoming name before set-membership, so we list the lowercase
|
|
4246
|
-
// forms of `Bash`/`Write`/`Edit`/`MultiEdit`. Without these,
|
|
4247
|
-
// post-canonicalisation Hermes `patch` / `write_file` (which now
|
|
4248
|
-
// arrive as `Edit` / `Write`) silently skipped snapshotting.
|
|
4249
|
-
"write",
|
|
4250
|
-
"multiedit"
|
|
4251
|
-
],
|
|
4252
|
-
onlyPaths: [],
|
|
4253
|
-
ignorePaths: ["**/node_modules/**", "dist/**", "build/**", ".next/**", "**/*.log"]
|
|
4254
|
-
},
|
|
4255
4223
|
smartRules: [
|
|
4256
4224
|
// ── rm safety (critical — always evaluated first) ──────────────────────
|
|
4257
4225
|
{
|
|
@@ -4562,11 +4530,6 @@ function getConfig(cwd) {
|
|
|
4562
4530
|
ignoredTools: [...DEFAULT_CONFIG.policy.ignoredTools],
|
|
4563
4531
|
toolInspection: { ...DEFAULT_CONFIG.policy.toolInspection },
|
|
4564
4532
|
smartRules: [...DEFAULT_CONFIG.policy.smartRules],
|
|
4565
|
-
snapshot: {
|
|
4566
|
-
tools: [...DEFAULT_CONFIG.policy.snapshot.tools],
|
|
4567
|
-
onlyPaths: [...DEFAULT_CONFIG.policy.snapshot.onlyPaths],
|
|
4568
|
-
ignorePaths: [...DEFAULT_CONFIG.policy.snapshot.ignorePaths]
|
|
4569
|
-
},
|
|
4570
4533
|
dlp: { ...DEFAULT_CONFIG.policy.dlp },
|
|
4571
4534
|
egress: {
|
|
4572
4535
|
...DEFAULT_CONFIG.policy.egress,
|
|
@@ -4634,12 +4597,6 @@ function getConfig(cwd) {
|
|
|
4634
4597
|
);
|
|
4635
4598
|
mergedPolicy.smartRules = [...filteredBlocks, ...localRules, ...filteredNonBlocks];
|
|
4636
4599
|
}
|
|
4637
|
-
if (p.snapshot) {
|
|
4638
|
-
const s2 = p.snapshot;
|
|
4639
|
-
if (s2.tools) mergedPolicy.snapshot.tools.push(...s2.tools);
|
|
4640
|
-
if (s2.onlyPaths) mergedPolicy.snapshot.onlyPaths.push(...s2.onlyPaths);
|
|
4641
|
-
if (s2.ignorePaths) mergedPolicy.snapshot.ignorePaths.push(...s2.ignorePaths);
|
|
4642
|
-
}
|
|
4643
4600
|
if (p.dlp) {
|
|
4644
4601
|
const d = p.dlp;
|
|
4645
4602
|
if (d.enabled !== void 0) mergedPolicy.dlp.enabled = d.enabled;
|
|
@@ -4890,11 +4847,13 @@ function getConfig(cwd) {
|
|
|
4890
4847
|
}
|
|
4891
4848
|
const shieldOverrides = readShieldOverrides();
|
|
4892
4849
|
const activeShieldNames = [.../* @__PURE__ */ new Set([...readActiveShields(), ...cloudManagedShields])];
|
|
4850
|
+
const appliedShields = [];
|
|
4893
4851
|
const cloudManagedSet = new Set(cloudManagedShields);
|
|
4894
4852
|
for (const shieldName of activeShieldNames) {
|
|
4895
4853
|
const isCloudMandated = cloudManagedSet.has(shieldName);
|
|
4896
4854
|
const shield = isCloudMandated ? BUILTIN_SHIELDS[shieldName] : getShield(shieldName);
|
|
4897
4855
|
if (!shield) continue;
|
|
4856
|
+
appliedShields.push(shieldName);
|
|
4898
4857
|
const existingRuleNames = new Set(mergedPolicy.smartRules.map((r) => r.name));
|
|
4899
4858
|
const ruleOverrides = isCloudMandated ? {} : shieldOverrides[shieldName] ?? {};
|
|
4900
4859
|
for (const rule of shield.smartRules) {
|
|
@@ -4916,6 +4875,7 @@ function getConfig(cwd) {
|
|
|
4916
4875
|
if (!existingWords.has(word)) mergedPolicy.dangerousWords.push(word);
|
|
4917
4876
|
}
|
|
4918
4877
|
}
|
|
4878
|
+
mergedPolicy.appliedShields = appliedShields.sort();
|
|
4919
4879
|
const existingAdvisoryNames = new Set(mergedPolicy.smartRules.map((r) => r.name));
|
|
4920
4880
|
const cc = mergedPolicy.commandChecks ?? {};
|
|
4921
4881
|
const advisoryKnobKey = (name) => {
|
|
@@ -4974,10 +4934,6 @@ function getConfig(cwd) {
|
|
|
4974
4934
|
mergedPolicy.dangerousWords = [...new Set(mergedPolicy.dangerousWords)];
|
|
4975
4935
|
mergedPolicy.ignoredTools = [...new Set(mergedPolicy.ignoredTools)];
|
|
4976
4936
|
mergedPolicy.skillPinning.roots = [...new Set(mergedPolicy.skillPinning.roots)];
|
|
4977
|
-
mergedPolicy.snapshot.tools = [...new Set(mergedPolicy.snapshot.tools)];
|
|
4978
|
-
mergedPolicy.snapshot.onlyPaths = [...new Set(mergedPolicy.snapshot.onlyPaths)];
|
|
4979
|
-
mergedPolicy.snapshot.ignorePaths = [...new Set(mergedPolicy.snapshot.ignorePaths)];
|
|
4980
|
-
mergedSettings.enableUndo = false;
|
|
4981
4937
|
const result = {
|
|
4982
4938
|
settings: mergedSettings,
|
|
4983
4939
|
policy: mergedPolicy,
|
|
@@ -5040,9 +4996,6 @@ ${error.replace("Invalid config:\n", "")}
|
|
|
5040
4996
|
return sanitized;
|
|
5041
4997
|
}
|
|
5042
4998
|
|
|
5043
|
-
// src/policy/index.ts
|
|
5044
|
-
var import_picomatch2 = __toESM(require("picomatch"));
|
|
5045
|
-
|
|
5046
4999
|
// src/dlp.ts
|
|
5047
5000
|
var import_fs5 = __toESM(require("fs"));
|
|
5048
5001
|
var import_path5 = __toESM(require("path"));
|
package/dist/index.mjs
CHANGED
|
@@ -4150,19 +4150,6 @@ var DEFAULT_CONFIG = {
|
|
|
4150
4150
|
settings: {
|
|
4151
4151
|
mode: "standard",
|
|
4152
4152
|
autoStartDaemon: true,
|
|
4153
|
-
// The undo feature was REMOVED. This default is one of two places that say
|
|
4154
|
-
// so; the other is the pin further down, which overwrites whatever a config
|
|
4155
|
-
// file, the dashboard or the cloud supplies. Setting `enableUndo` anywhere
|
|
4156
|
-
// has no effect — do not restore the advice that used to live here, because
|
|
4157
|
-
// a comment recommending a knob that is silently discarded is the same lie
|
|
4158
|
-
// on disk the pin exists to prevent.
|
|
4159
|
-
//
|
|
4160
|
-
// Why it went: the store was a per-project bare git repo with no size
|
|
4161
|
-
// ceiling, and eviction dropped the index row without deleting the objects.
|
|
4162
|
-
// On one machine it reached 378G (352G of it orphaned tmp_pack_* from an
|
|
4163
|
-
// interrupted `git gc`) and filled the disk. A security tool must not be
|
|
4164
|
-
// what fills a customer's disk. Leftovers: `node9 undo --purge`.
|
|
4165
|
-
enableUndo: false,
|
|
4166
4153
|
enableHookLogDebug: true,
|
|
4167
4154
|
approvalTimeoutMs: 12e4,
|
|
4168
4155
|
// 120-second auto-deny timeout
|
|
@@ -4203,25 +4190,6 @@ var DEFAULT_CONFIG = {
|
|
|
4203
4190
|
"terminal.execute": "command",
|
|
4204
4191
|
"postgres:query": "sql"
|
|
4205
4192
|
},
|
|
4206
|
-
snapshot: {
|
|
4207
|
-
tools: [
|
|
4208
|
-
"str_replace_based_edit_tool",
|
|
4209
|
-
"write_file",
|
|
4210
|
-
"edit_file",
|
|
4211
|
-
"create_file",
|
|
4212
|
-
"edit",
|
|
4213
|
-
"replace",
|
|
4214
|
-
// Claude / canonicalised Hermes — shouldSnapshot lowercases the
|
|
4215
|
-
// incoming name before set-membership, so we list the lowercase
|
|
4216
|
-
// forms of `Bash`/`Write`/`Edit`/`MultiEdit`. Without these,
|
|
4217
|
-
// post-canonicalisation Hermes `patch` / `write_file` (which now
|
|
4218
|
-
// arrive as `Edit` / `Write`) silently skipped snapshotting.
|
|
4219
|
-
"write",
|
|
4220
|
-
"multiedit"
|
|
4221
|
-
],
|
|
4222
|
-
onlyPaths: [],
|
|
4223
|
-
ignorePaths: ["**/node_modules/**", "dist/**", "build/**", ".next/**", "**/*.log"]
|
|
4224
|
-
},
|
|
4225
4193
|
smartRules: [
|
|
4226
4194
|
// ── rm safety (critical — always evaluated first) ──────────────────────
|
|
4227
4195
|
{
|
|
@@ -4532,11 +4500,6 @@ function getConfig(cwd) {
|
|
|
4532
4500
|
ignoredTools: [...DEFAULT_CONFIG.policy.ignoredTools],
|
|
4533
4501
|
toolInspection: { ...DEFAULT_CONFIG.policy.toolInspection },
|
|
4534
4502
|
smartRules: [...DEFAULT_CONFIG.policy.smartRules],
|
|
4535
|
-
snapshot: {
|
|
4536
|
-
tools: [...DEFAULT_CONFIG.policy.snapshot.tools],
|
|
4537
|
-
onlyPaths: [...DEFAULT_CONFIG.policy.snapshot.onlyPaths],
|
|
4538
|
-
ignorePaths: [...DEFAULT_CONFIG.policy.snapshot.ignorePaths]
|
|
4539
|
-
},
|
|
4540
4503
|
dlp: { ...DEFAULT_CONFIG.policy.dlp },
|
|
4541
4504
|
egress: {
|
|
4542
4505
|
...DEFAULT_CONFIG.policy.egress,
|
|
@@ -4604,12 +4567,6 @@ function getConfig(cwd) {
|
|
|
4604
4567
|
);
|
|
4605
4568
|
mergedPolicy.smartRules = [...filteredBlocks, ...localRules, ...filteredNonBlocks];
|
|
4606
4569
|
}
|
|
4607
|
-
if (p.snapshot) {
|
|
4608
|
-
const s2 = p.snapshot;
|
|
4609
|
-
if (s2.tools) mergedPolicy.snapshot.tools.push(...s2.tools);
|
|
4610
|
-
if (s2.onlyPaths) mergedPolicy.snapshot.onlyPaths.push(...s2.onlyPaths);
|
|
4611
|
-
if (s2.ignorePaths) mergedPolicy.snapshot.ignorePaths.push(...s2.ignorePaths);
|
|
4612
|
-
}
|
|
4613
4570
|
if (p.dlp) {
|
|
4614
4571
|
const d = p.dlp;
|
|
4615
4572
|
if (d.enabled !== void 0) mergedPolicy.dlp.enabled = d.enabled;
|
|
@@ -4860,11 +4817,13 @@ function getConfig(cwd) {
|
|
|
4860
4817
|
}
|
|
4861
4818
|
const shieldOverrides = readShieldOverrides();
|
|
4862
4819
|
const activeShieldNames = [.../* @__PURE__ */ new Set([...readActiveShields(), ...cloudManagedShields])];
|
|
4820
|
+
const appliedShields = [];
|
|
4863
4821
|
const cloudManagedSet = new Set(cloudManagedShields);
|
|
4864
4822
|
for (const shieldName of activeShieldNames) {
|
|
4865
4823
|
const isCloudMandated = cloudManagedSet.has(shieldName);
|
|
4866
4824
|
const shield = isCloudMandated ? BUILTIN_SHIELDS[shieldName] : getShield(shieldName);
|
|
4867
4825
|
if (!shield) continue;
|
|
4826
|
+
appliedShields.push(shieldName);
|
|
4868
4827
|
const existingRuleNames = new Set(mergedPolicy.smartRules.map((r) => r.name));
|
|
4869
4828
|
const ruleOverrides = isCloudMandated ? {} : shieldOverrides[shieldName] ?? {};
|
|
4870
4829
|
for (const rule of shield.smartRules) {
|
|
@@ -4886,6 +4845,7 @@ function getConfig(cwd) {
|
|
|
4886
4845
|
if (!existingWords.has(word)) mergedPolicy.dangerousWords.push(word);
|
|
4887
4846
|
}
|
|
4888
4847
|
}
|
|
4848
|
+
mergedPolicy.appliedShields = appliedShields.sort();
|
|
4889
4849
|
const existingAdvisoryNames = new Set(mergedPolicy.smartRules.map((r) => r.name));
|
|
4890
4850
|
const cc = mergedPolicy.commandChecks ?? {};
|
|
4891
4851
|
const advisoryKnobKey = (name) => {
|
|
@@ -4944,10 +4904,6 @@ function getConfig(cwd) {
|
|
|
4944
4904
|
mergedPolicy.dangerousWords = [...new Set(mergedPolicy.dangerousWords)];
|
|
4945
4905
|
mergedPolicy.ignoredTools = [...new Set(mergedPolicy.ignoredTools)];
|
|
4946
4906
|
mergedPolicy.skillPinning.roots = [...new Set(mergedPolicy.skillPinning.roots)];
|
|
4947
|
-
mergedPolicy.snapshot.tools = [...new Set(mergedPolicy.snapshot.tools)];
|
|
4948
|
-
mergedPolicy.snapshot.onlyPaths = [...new Set(mergedPolicy.snapshot.onlyPaths)];
|
|
4949
|
-
mergedPolicy.snapshot.ignorePaths = [...new Set(mergedPolicy.snapshot.ignorePaths)];
|
|
4950
|
-
mergedSettings.enableUndo = false;
|
|
4951
4907
|
const result = {
|
|
4952
4908
|
settings: mergedSettings,
|
|
4953
4909
|
policy: mergedPolicy,
|
|
@@ -5010,9 +4966,6 @@ ${error.replace("Invalid config:\n", "")}
|
|
|
5010
4966
|
return sanitized;
|
|
5011
4967
|
}
|
|
5012
4968
|
|
|
5013
|
-
// src/policy/index.ts
|
|
5014
|
-
import pm2 from "picomatch";
|
|
5015
|
-
|
|
5016
4969
|
// src/dlp.ts
|
|
5017
4970
|
import fs5 from "fs";
|
|
5018
4971
|
import path5 from "path";
|
package/dist/scan-ink.mjs
CHANGED
|
@@ -152,6 +152,18 @@ function rollupByShield(sections, topRulesPerShield = 3) {
|
|
|
152
152
|
}
|
|
153
153
|
return out.sort((a, b) => b.totalCatches - a.totalCatches);
|
|
154
154
|
}
|
|
155
|
+
function originForRule(ruleName, sections, enabled) {
|
|
156
|
+
for (const section of sections) {
|
|
157
|
+
if (section.rules.some((r) => r.name === ruleName)) {
|
|
158
|
+
if (section.sourceType === "default") return "default";
|
|
159
|
+
if (section.sourceType === "shield") {
|
|
160
|
+
const key = section.shieldKey ?? section.id;
|
|
161
|
+
return enabled.has(key) ? `\u2713 shield:${key}` : `needs shield:${key}`;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
return "";
|
|
166
|
+
}
|
|
155
167
|
function relativeDate(timestamp, now = /* @__PURE__ */ new Date()) {
|
|
156
168
|
const t = new Date(timestamp).getTime();
|
|
157
169
|
if (Number.isNaN(t)) return "?";
|
|
@@ -161,6 +173,11 @@ function relativeDate(timestamp, now = /* @__PURE__ */ new Date()) {
|
|
|
161
173
|
return `${days}d`;
|
|
162
174
|
}
|
|
163
175
|
|
|
176
|
+
// src/cli/render/ink/panels/title-count.ts
|
|
177
|
+
function topOf(shown, total) {
|
|
178
|
+
return total > shown ? ` \xB7 top ${shown} of ${total}` : "";
|
|
179
|
+
}
|
|
180
|
+
|
|
164
181
|
// src/cli/render/ink/panels/LeaksPanel.tsx
|
|
165
182
|
import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
166
183
|
var ROW_LIMIT = 4;
|
|
@@ -168,7 +185,10 @@ function LeaksPanel({ summary, width, now = /* @__PURE__ */ new Date() }) {
|
|
|
168
185
|
const leaks = summary.leaks;
|
|
169
186
|
if (leaks.length === 0) return null;
|
|
170
187
|
return /* @__PURE__ */ jsxs5(Box5, { borderStyle: "round", borderColor: "red", paddingX: 1, flexDirection: "column", width, children: [
|
|
171
|
-
/* @__PURE__ */
|
|
188
|
+
/* @__PURE__ */ jsxs5(Text5, { bold: true, color: "red", children: [
|
|
189
|
+
"CREDENTIAL LEAKS",
|
|
190
|
+
/* @__PURE__ */ jsx5(Text5, { dimColor: true, children: topOf(Math.min(leaks.length, ROW_LIMIT), leaks.length) })
|
|
191
|
+
] }),
|
|
172
192
|
leaks.slice(0, ROW_LIMIT).map((leak, i) => /* @__PURE__ */ jsxs5(Box5, { children: [
|
|
173
193
|
/* @__PURE__ */ jsx5(Box5, { width: 5, children: /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: relativeDate(leak.timestamp, now).padStart(4) }) }),
|
|
174
194
|
/* @__PURE__ */ jsx5(Box5, { width: 16, children: /* @__PURE__ */ jsx5(Text5, { color: "red", bold: true, wrap: "truncate-end", children: leak.patternName }) }),
|
|
@@ -188,30 +208,31 @@ function LeaksPanel({ summary, width, now = /* @__PURE__ */ new Date() }) {
|
|
|
188
208
|
// src/cli/render/ink/panels/BlockedPanel.tsx
|
|
189
209
|
import { Box as Box6, Text as Text6 } from "ink";
|
|
190
210
|
import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
191
|
-
function originForRule(ruleName, sections) {
|
|
192
|
-
for (const section of sections) {
|
|
193
|
-
if (section.rules.some((r) => r.name === ruleName)) {
|
|
194
|
-
if (section.sourceType === "default") return "default";
|
|
195
|
-
if (section.sourceType === "shield") {
|
|
196
|
-
return `needs shield:${section.shieldKey ?? section.id}`;
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
return "";
|
|
201
|
-
}
|
|
202
211
|
var ROW_LIMIT2 = 12;
|
|
203
|
-
function BlockedPanel({
|
|
204
|
-
|
|
212
|
+
function BlockedPanel({
|
|
213
|
+
summary,
|
|
214
|
+
width,
|
|
215
|
+
enabledShields = []
|
|
216
|
+
}) {
|
|
217
|
+
const enabled = new Set(enabledShields);
|
|
218
|
+
const allRules = topRulesByVerdict(summary.sections, "block", Number.MAX_SAFE_INTEGER);
|
|
219
|
+
const rules = allRules.slice(0, ROW_LIMIT2);
|
|
205
220
|
if (rules.length === 0) return null;
|
|
221
|
+
const origins = rules.map((r) => originForRule(r.name, summary.sections, enabled));
|
|
222
|
+
const anyNeeds = origins.some((o) => o.startsWith("needs shield:"));
|
|
223
|
+
const footer = enabled.size === 0 ? "\u2192 install node9 + enable shields above" : anyNeeds ? "\u2192 \u2713 marks rules from enabled shields \xB7 enable the rest above" : "\u2192 \u2713 all these rules come from enabled shields";
|
|
206
224
|
return /* @__PURE__ */ jsxs6(Box6, { borderStyle: "round", borderColor: "red", paddingX: 1, flexDirection: "column", width, children: [
|
|
207
|
-
/* @__PURE__ */
|
|
225
|
+
/* @__PURE__ */ jsxs6(Text6, { bold: true, color: "red", children: [
|
|
226
|
+
"WOULD HAVE BLOCKED",
|
|
227
|
+
/* @__PURE__ */ jsx6(Text6, { dimColor: true, children: topOf(rules.length, allRules.length) })
|
|
228
|
+
] }),
|
|
208
229
|
rules.map((rule, i) => /* @__PURE__ */ jsxs6(Box6, { children: [
|
|
209
230
|
/* @__PURE__ */ jsx6(Box6, { width: 3, children: /* @__PURE__ */ jsx6(Text6, { color: "red", children: "\u2717" }) }),
|
|
210
231
|
/* @__PURE__ */ jsx6(Box6, { width: 24, children: /* @__PURE__ */ jsx6(Text6, { bold: true, wrap: "truncate-end", children: rule.name }) }),
|
|
211
232
|
/* @__PURE__ */ jsx6(Box6, { width: 6, children: /* @__PURE__ */ jsx6(Text6, { bold: true, children: `\xD7${rule.count}` }) }),
|
|
212
|
-
/* @__PURE__ */ jsx6(Text6, { dimColor: true, wrap: "truncate-end", children: originForRule(rule.name, summary.sections) })
|
|
233
|
+
/* @__PURE__ */ jsx6(Text6, { dimColor: true, wrap: "truncate-end", children: originForRule(rule.name, summary.sections, enabled) })
|
|
213
234
|
] }, i)),
|
|
214
|
-
/* @__PURE__ */ jsx6(Box6, { children: /* @__PURE__ */ jsx6(Text6, { dimColor: true, wrap: "truncate-end", children:
|
|
235
|
+
/* @__PURE__ */ jsx6(Box6, { children: /* @__PURE__ */ jsx6(Text6, { dimColor: true, wrap: "truncate-end", children: footer }) })
|
|
215
236
|
] });
|
|
216
237
|
}
|
|
217
238
|
|
|
@@ -219,14 +240,19 @@ function BlockedPanel({ summary, width }) {
|
|
|
219
240
|
import { Box as Box7, Text as Text7 } from "ink";
|
|
220
241
|
import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
221
242
|
var ROW_LIMIT3 = 4;
|
|
243
|
+
var ENV_ROW_LIMIT = 3;
|
|
222
244
|
function BlastRadiusPanel({
|
|
223
245
|
blast,
|
|
224
246
|
blastExposures,
|
|
225
247
|
width
|
|
226
248
|
}) {
|
|
227
249
|
if (blastExposures === 0) return null;
|
|
250
|
+
const shown = Math.min(blast.reachable.length, ROW_LIMIT3) + Math.min(blast.envFindings.length, ENV_ROW_LIMIT);
|
|
228
251
|
return /* @__PURE__ */ jsxs7(Box7, { borderStyle: "round", borderColor: "yellow", paddingX: 1, flexDirection: "column", width, children: [
|
|
229
|
-
/* @__PURE__ */
|
|
252
|
+
/* @__PURE__ */ jsxs7(Text7, { bold: true, color: "yellow", children: [
|
|
253
|
+
"BLAST RADIUS",
|
|
254
|
+
/* @__PURE__ */ jsx7(Text7, { dimColor: true, children: topOf(shown, blastExposures) })
|
|
255
|
+
] }),
|
|
230
256
|
blast.reachable.slice(0, ROW_LIMIT3).map((path, i) => {
|
|
231
257
|
const desc = path.description.split(" \u2014 ")[0].split(/—|--/)[0].trim();
|
|
232
258
|
return /* @__PURE__ */ jsxs7(Box7, { children: [
|
|
@@ -251,19 +277,13 @@ function BlastRadiusPanel({
|
|
|
251
277
|
// src/cli/render/ink/panels/ReviewQueuePanel.tsx
|
|
252
278
|
import { Box as Box8, Text as Text8 } from "ink";
|
|
253
279
|
import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
254
|
-
function originForRule2(ruleName, sections) {
|
|
255
|
-
for (const section of sections) {
|
|
256
|
-
if (section.rules.some((r) => r.name === ruleName)) {
|
|
257
|
-
if (section.sourceType === "default") return "default";
|
|
258
|
-
if (section.sourceType === "shield") {
|
|
259
|
-
return `needs shield:${section.shieldKey ?? section.id}`;
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
return "";
|
|
264
|
-
}
|
|
265
280
|
var ROW_LIMIT4 = 5;
|
|
266
|
-
function ReviewQueuePanel({
|
|
281
|
+
function ReviewQueuePanel({
|
|
282
|
+
summary,
|
|
283
|
+
width,
|
|
284
|
+
enabledShields = []
|
|
285
|
+
}) {
|
|
286
|
+
const enabled = new Set(enabledShields);
|
|
267
287
|
const rules = topRulesByVerdict(summary.sections, "review", ROW_LIMIT4);
|
|
268
288
|
if (rules.length === 0) return null;
|
|
269
289
|
return /* @__PURE__ */ jsxs8(Box8, { borderStyle: "round", borderColor: "gray", paddingX: 1, flexDirection: "column", width, children: [
|
|
@@ -271,7 +291,7 @@ function ReviewQueuePanel({ summary, width }) {
|
|
|
271
291
|
rules.map((rule, i) => /* @__PURE__ */ jsxs8(Box8, { children: [
|
|
272
292
|
/* @__PURE__ */ jsx8(Box8, { width: 22, children: /* @__PURE__ */ jsx8(Text8, { wrap: "truncate-end", children: rule.name }) }),
|
|
273
293
|
/* @__PURE__ */ jsx8(Box8, { width: 6, children: /* @__PURE__ */ jsx8(Text8, { bold: true, children: `\xD7${rule.count}` }) }),
|
|
274
|
-
/* @__PURE__ */ jsx8(Text8, { dimColor: true, wrap: "truncate-end", children:
|
|
294
|
+
/* @__PURE__ */ jsx8(Text8, { dimColor: true, wrap: "truncate-end", children: originForRule(rule.name, summary.sections, enabled) })
|
|
275
295
|
] }, i)),
|
|
276
296
|
/* @__PURE__ */ jsxs8(Box8, { children: [
|
|
277
297
|
/* @__PURE__ */ jsx8(Text8, { dimColor: true, wrap: "truncate-end", children: "\u2192 " }),
|
|
@@ -304,7 +324,10 @@ function AgentLoopsPanel({ loopFindings, width }) {
|
|
|
304
324
|
const toolEntries = [...byTool.entries()].sort((a, b) => b[1] - a[1]).slice(0, TOOL_ROW_LIMIT);
|
|
305
325
|
const topStuck = [...loopFindings].sort((a, b) => b.count - a.count).slice(0, STUCK_ROW_LIMIT);
|
|
306
326
|
return /* @__PURE__ */ jsxs9(Box9, { borderStyle: "round", borderColor: "gray", paddingX: 1, flexDirection: "column", width, children: [
|
|
307
|
-
/* @__PURE__ */
|
|
327
|
+
/* @__PURE__ */ jsxs9(Text9, { bold: true, children: [
|
|
328
|
+
"AGENT LOOPS",
|
|
329
|
+
/* @__PURE__ */ jsx9(Text9, { dimColor: true, children: topOf(toolEntries.length, byTool.size) })
|
|
330
|
+
] }),
|
|
308
331
|
toolEntries.map(([tool, repeats]) => {
|
|
309
332
|
const pct = totalRepeats > 0 ? Math.round(repeats / totalRepeats * 100) : 0;
|
|
310
333
|
return /* @__PURE__ */ jsxs9(Box9, { children: [
|
|
@@ -1651,9 +1674,9 @@ var LONG_OUTPUT_THRESHOLD_BYTES = 100 * 1024;
|
|
|
1651
1674
|
|
|
1652
1675
|
// src/cli/render/ink/panels/ShieldsPanel.tsx
|
|
1653
1676
|
import { jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
1654
|
-
function ShieldsPanel({ summary,
|
|
1677
|
+
function ShieldsPanel({ summary, width, enabledShields = [] }) {
|
|
1678
|
+
const enabled = new Set(enabledShields);
|
|
1655
1679
|
const impacts = rollupByShield(summary.sections);
|
|
1656
|
-
const exposed = Math.max(0, 100 - blastScore);
|
|
1657
1680
|
const ranked = [...impacts].sort((a, b) => {
|
|
1658
1681
|
const aDiscount = PROTECTIVE_SHIELD_DISCOUNTS[a.shieldName] ?? 0;
|
|
1659
1682
|
const bDiscount = PROTECTIVE_SHIELD_DISCOUNTS[b.shieldName] ?? 0;
|
|
@@ -1662,30 +1685,30 @@ function ShieldsPanel({ summary, blastScore, width }) {
|
|
|
1662
1685
|
});
|
|
1663
1686
|
const hitShields = ranked.filter((i) => i.totalCatches > 0);
|
|
1664
1687
|
const hitNames = new Set(hitShields.map((i) => i.shieldName));
|
|
1665
|
-
const
|
|
1666
|
-
const
|
|
1667
|
-
const
|
|
1688
|
+
const zeroHitAll = Object.keys(BUILTIN_SHIELDS).filter((name) => !hitNames.has(name)).sort();
|
|
1689
|
+
const zeroHitBuiltins = zeroHitAll.filter((name) => !enabled.has(name));
|
|
1690
|
+
const zeroHitEnabled = zeroHitAll.filter((name) => enabled.has(name));
|
|
1691
|
+
const topRec = hitShields.find(
|
|
1692
|
+
(r) => (PROTECTIVE_SHIELD_DISCOUNTS[r.shieldName] ?? 0) > 0 && !enabled.has(r.shieldName)
|
|
1693
|
+
);
|
|
1694
|
+
const allCovered = !topRec && hitShields.some(
|
|
1695
|
+
(r) => (PROTECTIVE_SHIELD_DISCOUNTS[r.shieldName] ?? 0) > 0 && enabled.has(r.shieldName)
|
|
1696
|
+
);
|
|
1668
1697
|
return /* @__PURE__ */ jsxs10(Box10, { borderStyle: "round", borderColor: "cyan", paddingX: 1, flexDirection: "column", width, children: [
|
|
1669
1698
|
/* @__PURE__ */ jsx10(Text10, { bold: true, color: "cyan", children: "SHIELDS" }),
|
|
1670
1699
|
hitShields.map((impact) => {
|
|
1671
1700
|
const discount = PROTECTIVE_SHIELD_DISCOUNTS[impact.shieldName] ?? 0;
|
|
1672
|
-
const
|
|
1701
|
+
const isOn = enabled.has(impact.shieldName);
|
|
1673
1702
|
const noun = `op${impact.totalCatches !== 1 ? "s" : ""}`;
|
|
1674
1703
|
return /* @__PURE__ */ jsxs10(Box10, { children: [
|
|
1675
1704
|
/* @__PURE__ */ jsx10(Box10, { width: 16, children: /* @__PURE__ */ jsx10(Text10, { bold: true, color: discount > 0 ? "cyan" : void 0, dimColor: discount === 0, children: impact.shieldName }) }),
|
|
1676
1705
|
/* @__PURE__ */ jsx10(Box10, { width: 20, children: /* @__PURE__ */ jsx10(Text10, { dimColor: true, children: `catches ${impact.totalCatches} ${noun}` }) }),
|
|
1677
|
-
|
|
1678
|
-
Text10,
|
|
1679
|
-
{
|
|
1680
|
-
bold: true,
|
|
1681
|
-
color: "green",
|
|
1682
|
-
children: `\u2192 +${bonus} pts (${blastScore} \u2192 ${blastScore + bonus})`
|
|
1683
|
-
}
|
|
1684
|
-
) : null
|
|
1706
|
+
isOn ? /* @__PURE__ */ jsx10(Text10, { bold: true, color: "green", children: `\u2713 enabled` }) : discount > 0 ? /* @__PURE__ */ jsx10(Text10, { bold: true, color: "green", children: `\u2192 blocks these reads in-path` }) : null
|
|
1685
1707
|
] }, impact.shieldName);
|
|
1686
1708
|
}),
|
|
1709
|
+
zeroHitEnabled.length > 0 ? /* @__PURE__ */ jsx10(Box10, { flexDirection: "column", children: /* @__PURE__ */ jsx10(Text10, { dimColor: true, wrap: "truncate-end", children: "\u2713 active: " + zeroHitEnabled.join(" \xB7 ") + " (no hits in this history)" }) }) : null,
|
|
1687
1710
|
zeroHitBuiltins.length > 0 ? /* @__PURE__ */ jsx10(Box10, { flexDirection: "column", children: /* @__PURE__ */ jsx10(Text10, { dimColor: true, wrap: "truncate-end", children: zeroHitBuiltins.join(" \xB7 ") + " (no hits \u2014 install proactively)" }) }) : null,
|
|
1688
|
-
topRec ? /* @__PURE__ */ jsx10(Box10, { children: /* @__PURE__ */ jsx10(Text10, { color: "cyan", bold: true, children: `\u2192 node9 shield enable ${topRec.shieldName} (start here \u2014
|
|
1711
|
+
topRec ? /* @__PURE__ */ jsx10(Box10, { children: /* @__PURE__ */ jsx10(Text10, { color: "cyan", bold: true, children: `\u2192 node9 shield enable ${topRec.shieldName} (start here \u2014 widest coverage)` }) }) : allCovered ? /* @__PURE__ */ jsx10(Box10, { children: /* @__PURE__ */ jsx10(Text10, { color: "green", bold: true, children: "\u2713 recommended shields are enabled" }) }) : null
|
|
1689
1712
|
] });
|
|
1690
1713
|
}
|
|
1691
1714
|
|
|
@@ -1708,7 +1731,7 @@ function StaticScorecard({ input, rangeLabel, now }) {
|
|
|
1708
1731
|
parts.push(`${leakCount} secret${leakCount !== 1 ? "s" : ""} leaked`);
|
|
1709
1732
|
}
|
|
1710
1733
|
if (blockedCount > 0) {
|
|
1711
|
-
parts.push(`${blockedCount} op${blockedCount !== 1 ? "s" : ""} blocked`);
|
|
1734
|
+
parts.push(`${blockedCount} op${blockedCount !== 1 ? "s" : ""} would be blocked`);
|
|
1712
1735
|
}
|
|
1713
1736
|
return `Critical (${parts.join(" + ")})`;
|
|
1714
1737
|
})();
|
|
@@ -1723,14 +1746,27 @@ function StaticScorecard({ input, rangeLabel, now }) {
|
|
|
1723
1746
|
/* @__PURE__ */ jsx11(SeverityBand, { label: criticalLabel, width }),
|
|
1724
1747
|
/* @__PURE__ */ jsxs11(Box11, { flexDirection: "row", gap: 1, children: [
|
|
1725
1748
|
/* @__PURE__ */ jsx11(LeaksPanel, { summary, width: halfWidth, now }),
|
|
1726
|
-
/* @__PURE__ */ jsx11(
|
|
1749
|
+
/* @__PURE__ */ jsx11(
|
|
1750
|
+
BlockedPanel,
|
|
1751
|
+
{
|
|
1752
|
+
summary,
|
|
1753
|
+
width: halfWidth,
|
|
1754
|
+
enabledShields: input.enabledShields
|
|
1755
|
+
}
|
|
1756
|
+
)
|
|
1727
1757
|
] })
|
|
1728
1758
|
] }) : null,
|
|
1729
1759
|
input.blastExposures > 0 ? /* @__PURE__ */ jsxs11(Fragment2, { children: [
|
|
1730
1760
|
/* @__PURE__ */ jsx11(
|
|
1731
1761
|
SeverityBand,
|
|
1732
1762
|
{
|
|
1733
|
-
label:
|
|
1763
|
+
label: (() => {
|
|
1764
|
+
const paths = input.blast.reachable.length;
|
|
1765
|
+
const envs = input.blast.envFindings.length;
|
|
1766
|
+
const pathPart = `${paths} path${paths !== 1 ? "s" : ""}`;
|
|
1767
|
+
const envPart = envs > 0 ? ` + ${envs} env var${envs !== 1 ? "s" : ""}` : "";
|
|
1768
|
+
return `High (${pathPart}${envPart} reachable)`;
|
|
1769
|
+
})(),
|
|
1734
1770
|
width
|
|
1735
1771
|
}
|
|
1736
1772
|
),
|
|
@@ -1747,23 +1783,33 @@ function StaticScorecard({ input, rangeLabel, now }) {
|
|
|
1747
1783
|
const reviewCount = input.reviewCount;
|
|
1748
1784
|
const loopCount = input.scan.loopFindings.length;
|
|
1749
1785
|
if (reviewCount === 0 && loopCount === 0) return null;
|
|
1750
|
-
const { wastePct } = computeLoopWaste(
|
|
1786
|
+
const { wastePct, wastedCalls } = computeLoopWaste(
|
|
1787
|
+
input.scan.loopFindings,
|
|
1788
|
+
input.scan.totalToolCalls
|
|
1789
|
+
);
|
|
1751
1790
|
const parts = [];
|
|
1752
1791
|
if (reviewCount > 0) parts.push(`${reviewCount} op${reviewCount !== 1 ? "s" : ""} flagged`);
|
|
1753
1792
|
if (loopCount > 0)
|
|
1754
1793
|
parts.push(
|
|
1755
|
-
`${loopCount} loop${loopCount !== 1 ? "s" : ""}${
|
|
1794
|
+
`${loopCount} loop${loopCount !== 1 ? "s" : ""}${wastedCalls > 0 ? ` \xB7 ${wastedCalls} wasted calls (${wastePct}% of all calls)` : ""}`
|
|
1756
1795
|
);
|
|
1757
1796
|
return /* @__PURE__ */ jsxs11(Fragment2, { children: [
|
|
1758
1797
|
/* @__PURE__ */ jsx11(SeverityBand, { label: `Medium (${parts.join(" \xB7 ")})`, width }),
|
|
1759
1798
|
/* @__PURE__ */ jsxs11(Box11, { flexDirection: "row", gap: 1, children: [
|
|
1760
|
-
/* @__PURE__ */ jsx11(
|
|
1799
|
+
/* @__PURE__ */ jsx11(
|
|
1800
|
+
ReviewQueuePanel,
|
|
1801
|
+
{
|
|
1802
|
+
summary: input.summary,
|
|
1803
|
+
width: halfWidth,
|
|
1804
|
+
enabledShields: input.enabledShields
|
|
1805
|
+
}
|
|
1806
|
+
),
|
|
1761
1807
|
/* @__PURE__ */ jsx11(AgentLoopsPanel, { loopFindings: input.scan.loopFindings, width: halfWidth })
|
|
1762
1808
|
] })
|
|
1763
1809
|
] });
|
|
1764
1810
|
})(),
|
|
1765
1811
|
/* @__PURE__ */ jsx11(SeverityBand, { label: "Recommended action", width }),
|
|
1766
|
-
/* @__PURE__ */ jsx11(ShieldsPanel, { summary: input.summary,
|
|
1812
|
+
/* @__PURE__ */ jsx11(ShieldsPanel, { summary: input.summary, width, enabledShields: input.enabledShields })
|
|
1767
1813
|
] });
|
|
1768
1814
|
}
|
|
1769
1815
|
function renderScanScorecardInk(input, rangeLabel) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@node9/proxy",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "2.1.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",
|