@wrongstack/core 0.298.0 → 0.298.1
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/defaults/index.js +65 -61
- package/dist/index.js +149 -155
- package/dist/infrastructure/index.js +1 -1
- package/dist/plugin/index.js +38 -49
- package/dist/plugins/auto-review-plugin.d.ts +1 -11
- package/dist/security/auto-approve-policy.d.ts +37 -0
- package/dist/security/index.js +64 -60
- package/dist/security/permission-helpers.d.ts +93 -0
- package/dist/security/permission-policy.d.ts +2 -52
- package/dist/storage/index.js +1 -1
- package/dist/types/config/autonomy.d.ts +3 -4
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +46 -0
- package/dist/utils/sage-output-block.js +48 -0
- package/instructions/llm/chimera-review.md +4 -6
- package/package.json +8 -4
- package/skills/auto-review/SKILL.md +11 -76
- package/skills/chimera/SKILL.md +23 -53
package/dist/defaults/index.js
CHANGED
|
@@ -29956,7 +29956,68 @@ function isClearlyDestructiveBashCommand(command, projectRoot) {
|
|
|
29956
29956
|
return false;
|
|
29957
29957
|
}
|
|
29958
29958
|
|
|
29959
|
-
// src/security/
|
|
29959
|
+
// src/security/auto-approve-policy.ts
|
|
29960
|
+
var AutoApprovePermissionPolicy = class _AutoApprovePermissionPolicy {
|
|
29961
|
+
allowedCapabilities;
|
|
29962
|
+
constructor(allowedCapabilities) {
|
|
29963
|
+
this.allowedCapabilities = allowedCapabilities ?? [
|
|
29964
|
+
ToolCapabilities.FS_READ,
|
|
29965
|
+
ToolCapabilities.NET_OUTBOUND
|
|
29966
|
+
];
|
|
29967
|
+
}
|
|
29968
|
+
static isMcpTool(name) {
|
|
29969
|
+
return name.startsWith("mcp__");
|
|
29970
|
+
}
|
|
29971
|
+
async evaluate(tool) {
|
|
29972
|
+
const caps = tool.capabilities ?? [];
|
|
29973
|
+
const hasAllowedCap = caps.some((c) => this.allowedCapabilities.includes(c));
|
|
29974
|
+
const isMcp = _AutoApprovePermissionPolicy.isMcpTool(tool.name);
|
|
29975
|
+
const mcpProxyAllowed = this.allowedCapabilities.includes(ToolCapabilities.MCP_PROXY);
|
|
29976
|
+
const dangerousNotAllowed = getDangerousCapabilities(tool).filter(
|
|
29977
|
+
(c) => !this.allowedCapabilities.includes(c)
|
|
29978
|
+
);
|
|
29979
|
+
const blocked = tool.permission === "deny" || isMcp && !mcpProxyAllowed || !hasAllowedCap || dangerousNotAllowed.length > 0;
|
|
29980
|
+
if (blocked) {
|
|
29981
|
+
const reason = isMcp && !mcpProxyAllowed ? `MCP tool ${tool.name} is not auto-approved for subagents \u2014 ask the leader to allow mcp.proxy explicitly` : tool.permission === "deny" ? "tool default deny" : dangerousNotAllowed.length > 0 ? `tool requires un-granted dangerous capability (needs: ${dangerousNotAllowed.join(", ")}, allowed: ${this.allowedCapabilities.join(", ")})` : `tool lacks allowed capability (has: ${caps.join(", ") || "none"}, allowed: ${this.allowedCapabilities.join(", ")})`;
|
|
29982
|
+
return {
|
|
29983
|
+
permission: "deny",
|
|
29984
|
+
source: "subagent_guard",
|
|
29985
|
+
reason
|
|
29986
|
+
};
|
|
29987
|
+
}
|
|
29988
|
+
return { permission: "auto", source: "yolo" };
|
|
29989
|
+
}
|
|
29990
|
+
async trust() {
|
|
29991
|
+
}
|
|
29992
|
+
async deny() {
|
|
29993
|
+
}
|
|
29994
|
+
denyOnce() {
|
|
29995
|
+
}
|
|
29996
|
+
allowOnce() {
|
|
29997
|
+
}
|
|
29998
|
+
async explain(tool) {
|
|
29999
|
+
const decision = await this.evaluate(tool);
|
|
30000
|
+
return {
|
|
30001
|
+
toolName: tool.name,
|
|
30002
|
+
subject: null,
|
|
30003
|
+
steps: [
|
|
30004
|
+
{
|
|
30005
|
+
rule: "subagent auto",
|
|
30006
|
+
matched: decision.permission === "auto",
|
|
30007
|
+
decision: decision.permission,
|
|
30008
|
+
source: decision.source,
|
|
30009
|
+
detail: decision.reason ?? `subagent policy: ${decision.permission}`
|
|
30010
|
+
}
|
|
30011
|
+
],
|
|
30012
|
+
winnerIndex: 0,
|
|
30013
|
+
decision
|
|
30014
|
+
};
|
|
30015
|
+
}
|
|
30016
|
+
async reload() {
|
|
30017
|
+
}
|
|
30018
|
+
};
|
|
30019
|
+
|
|
30020
|
+
// src/security/permission-helpers.ts
|
|
29960
30021
|
function matchesTrust(patterns, subject) {
|
|
29961
30022
|
return patterns.includes(subject) || matchAny(patterns, subject);
|
|
29962
30023
|
}
|
|
@@ -30051,6 +30112,8 @@ function shellCommandReadsSensitivePath(command) {
|
|
|
30051
30112
|
}
|
|
30052
30113
|
return false;
|
|
30053
30114
|
}
|
|
30115
|
+
|
|
30116
|
+
// src/security/permission-policy.ts
|
|
30054
30117
|
var DefaultPermissionPolicy = class {
|
|
30055
30118
|
policy = {};
|
|
30056
30119
|
loaded = false;
|
|
@@ -30793,65 +30856,6 @@ var DefaultPermissionPolicy = class {
|
|
|
30793
30856
|
return void 0;
|
|
30794
30857
|
}
|
|
30795
30858
|
};
|
|
30796
|
-
var AutoApprovePermissionPolicy = class _AutoApprovePermissionPolicy {
|
|
30797
|
-
allowedCapabilities;
|
|
30798
|
-
constructor(allowedCapabilities) {
|
|
30799
|
-
this.allowedCapabilities = allowedCapabilities ?? [
|
|
30800
|
-
ToolCapabilities.FS_READ,
|
|
30801
|
-
ToolCapabilities.NET_OUTBOUND
|
|
30802
|
-
];
|
|
30803
|
-
}
|
|
30804
|
-
static isMcpTool(name) {
|
|
30805
|
-
return name.startsWith("mcp__");
|
|
30806
|
-
}
|
|
30807
|
-
async evaluate(tool) {
|
|
30808
|
-
const caps = tool.capabilities ?? [];
|
|
30809
|
-
const hasAllowedCap = caps.some((c) => this.allowedCapabilities.includes(c));
|
|
30810
|
-
const isMcp = _AutoApprovePermissionPolicy.isMcpTool(tool.name);
|
|
30811
|
-
const mcpProxyAllowed = this.allowedCapabilities.includes(ToolCapabilities.MCP_PROXY);
|
|
30812
|
-
const dangerousNotAllowed = getDangerousCapabilities(tool).filter(
|
|
30813
|
-
(c) => !this.allowedCapabilities.includes(c)
|
|
30814
|
-
);
|
|
30815
|
-
const blocked = tool.permission === "deny" || isMcp && !mcpProxyAllowed || !hasAllowedCap || dangerousNotAllowed.length > 0;
|
|
30816
|
-
if (blocked) {
|
|
30817
|
-
const reason = isMcp && !mcpProxyAllowed ? `MCP tool ${tool.name} is not auto-approved for subagents \u2014 ask the leader to allow mcp.proxy explicitly` : tool.permission === "deny" ? "tool default deny" : dangerousNotAllowed.length > 0 ? `tool requires un-granted dangerous capability (needs: ${dangerousNotAllowed.join(", ")}, allowed: ${this.allowedCapabilities.join(", ")})` : `tool lacks allowed capability (has: ${caps.join(", ") || "none"}, allowed: ${this.allowedCapabilities.join(", ")})`;
|
|
30818
|
-
return {
|
|
30819
|
-
permission: "deny",
|
|
30820
|
-
source: "subagent_guard",
|
|
30821
|
-
reason
|
|
30822
|
-
};
|
|
30823
|
-
}
|
|
30824
|
-
return { permission: "auto", source: "yolo" };
|
|
30825
|
-
}
|
|
30826
|
-
async trust() {
|
|
30827
|
-
}
|
|
30828
|
-
async deny() {
|
|
30829
|
-
}
|
|
30830
|
-
denyOnce() {
|
|
30831
|
-
}
|
|
30832
|
-
allowOnce() {
|
|
30833
|
-
}
|
|
30834
|
-
async explain(tool) {
|
|
30835
|
-
const decision = await this.evaluate(tool);
|
|
30836
|
-
return {
|
|
30837
|
-
toolName: tool.name,
|
|
30838
|
-
subject: null,
|
|
30839
|
-
steps: [
|
|
30840
|
-
{
|
|
30841
|
-
rule: "subagent auto",
|
|
30842
|
-
matched: decision.permission === "auto",
|
|
30843
|
-
decision: decision.permission,
|
|
30844
|
-
source: decision.source,
|
|
30845
|
-
detail: decision.reason ?? `subagent policy: ${decision.permission}`
|
|
30846
|
-
}
|
|
30847
|
-
],
|
|
30848
|
-
winnerIndex: 0,
|
|
30849
|
-
decision
|
|
30850
|
-
};
|
|
30851
|
-
}
|
|
30852
|
-
async reload() {
|
|
30853
|
-
}
|
|
30854
|
-
};
|
|
30855
30859
|
|
|
30856
30860
|
// src/security/secret-vault.ts
|
|
30857
30861
|
import { createCipheriv, createDecipheriv, randomBytes as randomBytes3, scryptSync } from "node:crypto";
|
|
@@ -31631,7 +31635,7 @@ var CONFIG_BEHAVIOR_DEFAULTS = {
|
|
|
31631
31635
|
// DEFAULT_STATUSLINE_MODE (packages/tui/src/components/settings-picker-model.ts).
|
|
31632
31636
|
statuslineMode: "minimum",
|
|
31633
31637
|
thinkingWord: DEFAULT_TUI_THINKING_WORD,
|
|
31634
|
-
showAgentSwarmPanel:
|
|
31638
|
+
showAgentSwarmPanel: "bottom"
|
|
31635
31639
|
},
|
|
31636
31640
|
circuitBreaker: { ...DEFAULT_CIRCUIT_BREAKER_CONFIG },
|
|
31637
31641
|
modelRuntime: {
|
package/dist/index.js
CHANGED
|
@@ -3524,7 +3524,7 @@ var CONFIG_BEHAVIOR_DEFAULTS = {
|
|
|
3524
3524
|
// DEFAULT_STATUSLINE_MODE (packages/tui/src/components/settings-picker-model.ts).
|
|
3525
3525
|
statuslineMode: "minimum",
|
|
3526
3526
|
thinkingWord: DEFAULT_TUI_THINKING_WORD,
|
|
3527
|
-
showAgentSwarmPanel:
|
|
3527
|
+
showAgentSwarmPanel: "bottom"
|
|
3528
3528
|
},
|
|
3529
3529
|
circuitBreaker: { ...DEFAULT_CIRCUIT_BREAKER_CONFIG },
|
|
3530
3530
|
modelRuntime: {
|
|
@@ -15021,6 +15021,49 @@ function quoteWin32CmdArg(arg) {
|
|
|
15021
15021
|
return `"${arg}"`;
|
|
15022
15022
|
}
|
|
15023
15023
|
|
|
15024
|
+
// src/utils/sage-output-block.ts
|
|
15025
|
+
var SAGE_INJECTOR_HEADINGS = /* @__PURE__ */ new Set([
|
|
15026
|
+
"--- SAGE: task-aware project knowledge (Memory Injector) ---",
|
|
15027
|
+
"--- SAGE: related project knowledge (Memory Injector) ---"
|
|
15028
|
+
]);
|
|
15029
|
+
var SAGE_MEMORY_LINE = /^- \[[^\]]+\](?:\[[^\]]+\])* <memory id="[^"]+">.*<\/memory>(?: .*)?$/;
|
|
15030
|
+
var SAGE_MEMORY_LINE_TRUNCATED = /^- \[[^\]]+\](?:\[[^\]]+\])* <memory id="[^"]+">.*…$/;
|
|
15031
|
+
function splitSageOutputBlock(output) {
|
|
15032
|
+
if (!output.includes("--- SAGE: ")) return { body: output, sageLines: [] };
|
|
15033
|
+
const lines = output.split("\n");
|
|
15034
|
+
for (let sageIdx = lines.length - 1; sageIdx >= 0; sageIdx--) {
|
|
15035
|
+
if (!SAGE_INJECTOR_HEADINGS.has(lines[sageIdx] ?? "")) continue;
|
|
15036
|
+
const candidate = lines.slice(sageIdx);
|
|
15037
|
+
if (candidate.length < 2) continue;
|
|
15038
|
+
const memoryLines = candidate.slice(1).filter((line) => line.trim().length > 0);
|
|
15039
|
+
if (memoryLines.length === 0) continue;
|
|
15040
|
+
const bodyOk = memoryLines.every(
|
|
15041
|
+
(line, index) => SAGE_MEMORY_LINE.test(line) || index === memoryLines.length - 1 && SAGE_MEMORY_LINE_TRUNCATED.test(line)
|
|
15042
|
+
);
|
|
15043
|
+
if (!bodyOk) continue;
|
|
15044
|
+
let end = candidate.length;
|
|
15045
|
+
while (end > 1 && candidate[end - 1].trim().length === 0) end--;
|
|
15046
|
+
return {
|
|
15047
|
+
body: lines.slice(0, sageIdx).join("\n").trimEnd(),
|
|
15048
|
+
sageLines: candidate.slice(0, end)
|
|
15049
|
+
};
|
|
15050
|
+
}
|
|
15051
|
+
return { body: output, sageLines: [] };
|
|
15052
|
+
}
|
|
15053
|
+
function capSageLines(sageLines, maxChars) {
|
|
15054
|
+
if (sageLines.length < 2) return [];
|
|
15055
|
+
const header = sageLines[0];
|
|
15056
|
+
if (header.length >= maxChars) return [];
|
|
15057
|
+
const out = [header];
|
|
15058
|
+
let used = header.length;
|
|
15059
|
+
for (const line of sageLines.slice(1)) {
|
|
15060
|
+
if (used + 1 + line.length > maxChars) break;
|
|
15061
|
+
out.push(line);
|
|
15062
|
+
used += 1 + line.length;
|
|
15063
|
+
}
|
|
15064
|
+
return out.length > 1 ? out : [];
|
|
15065
|
+
}
|
|
15066
|
+
|
|
15024
15067
|
// src/chronicle/sqlite-query.ts
|
|
15025
15068
|
var MAX_LIMIT = 1e4;
|
|
15026
15069
|
function encodeCursor2(cursor) {
|
|
@@ -50667,51 +50710,6 @@ ${text2}` : text2;
|
|
|
50667
50710
|
|
|
50668
50711
|
// src/core/agent-tools.ts
|
|
50669
50712
|
init_error();
|
|
50670
|
-
|
|
50671
|
-
// src/utils/sage-output-block.ts
|
|
50672
|
-
var SAGE_INJECTOR_HEADINGS = /* @__PURE__ */ new Set([
|
|
50673
|
-
"--- SAGE: task-aware project knowledge (Memory Injector) ---",
|
|
50674
|
-
"--- SAGE: related project knowledge (Memory Injector) ---"
|
|
50675
|
-
]);
|
|
50676
|
-
var SAGE_MEMORY_LINE = /^- \[[^\]]+\](?:\[[^\]]+\])* <memory id="[^"]+">.*<\/memory>(?: .*)?$/;
|
|
50677
|
-
var SAGE_MEMORY_LINE_TRUNCATED = /^- \[[^\]]+\](?:\[[^\]]+\])* <memory id="[^"]+">.*…$/;
|
|
50678
|
-
function splitSageOutputBlock(output) {
|
|
50679
|
-
if (!output.includes("--- SAGE: ")) return { body: output, sageLines: [] };
|
|
50680
|
-
const lines = output.split("\n");
|
|
50681
|
-
for (let sageIdx = lines.length - 1; sageIdx >= 0; sageIdx--) {
|
|
50682
|
-
if (!SAGE_INJECTOR_HEADINGS.has(lines[sageIdx] ?? "")) continue;
|
|
50683
|
-
const candidate = lines.slice(sageIdx);
|
|
50684
|
-
if (candidate.length < 2) continue;
|
|
50685
|
-
const memoryLines = candidate.slice(1).filter((line) => line.trim().length > 0);
|
|
50686
|
-
if (memoryLines.length === 0) continue;
|
|
50687
|
-
const bodyOk = memoryLines.every(
|
|
50688
|
-
(line, index) => SAGE_MEMORY_LINE.test(line) || index === memoryLines.length - 1 && SAGE_MEMORY_LINE_TRUNCATED.test(line)
|
|
50689
|
-
);
|
|
50690
|
-
if (!bodyOk) continue;
|
|
50691
|
-
let end = candidate.length;
|
|
50692
|
-
while (end > 1 && candidate[end - 1].trim().length === 0) end--;
|
|
50693
|
-
return {
|
|
50694
|
-
body: lines.slice(0, sageIdx).join("\n").trimEnd(),
|
|
50695
|
-
sageLines: candidate.slice(0, end)
|
|
50696
|
-
};
|
|
50697
|
-
}
|
|
50698
|
-
return { body: output, sageLines: [] };
|
|
50699
|
-
}
|
|
50700
|
-
function capSageLines(sageLines, maxChars) {
|
|
50701
|
-
if (sageLines.length < 2) return [];
|
|
50702
|
-
const header = sageLines[0];
|
|
50703
|
-
if (header.length >= maxChars) return [];
|
|
50704
|
-
const out = [header];
|
|
50705
|
-
let used = header.length;
|
|
50706
|
-
for (const line of sageLines.slice(1)) {
|
|
50707
|
-
if (used + 1 + line.length > maxChars) break;
|
|
50708
|
-
out.push(line);
|
|
50709
|
-
used += 1 + line.length;
|
|
50710
|
-
}
|
|
50711
|
-
return out.length > 1 ? out : [];
|
|
50712
|
-
}
|
|
50713
|
-
|
|
50714
|
-
// src/core/agent-tools.ts
|
|
50715
50713
|
var DIFF_TOOL_NAMES = /* @__PURE__ */ new Set(["edit", "write", "replace", "patch", "diff"]);
|
|
50716
50714
|
var DIFF_TOOL_EVENT_PREVIEW_MAX = 16e3;
|
|
50717
50715
|
var SAGE_EVENT_MAX = 2e3;
|
|
@@ -62589,7 +62587,68 @@ function isClearlyDestructiveBashCommand(command, projectRoot) {
|
|
|
62589
62587
|
return false;
|
|
62590
62588
|
}
|
|
62591
62589
|
|
|
62592
|
-
// src/security/
|
|
62590
|
+
// src/security/auto-approve-policy.ts
|
|
62591
|
+
var AutoApprovePermissionPolicy = class _AutoApprovePermissionPolicy {
|
|
62592
|
+
allowedCapabilities;
|
|
62593
|
+
constructor(allowedCapabilities) {
|
|
62594
|
+
this.allowedCapabilities = allowedCapabilities ?? [
|
|
62595
|
+
ToolCapabilities.FS_READ,
|
|
62596
|
+
ToolCapabilities.NET_OUTBOUND
|
|
62597
|
+
];
|
|
62598
|
+
}
|
|
62599
|
+
static isMcpTool(name) {
|
|
62600
|
+
return name.startsWith("mcp__");
|
|
62601
|
+
}
|
|
62602
|
+
async evaluate(tool) {
|
|
62603
|
+
const caps = tool.capabilities ?? [];
|
|
62604
|
+
const hasAllowedCap = caps.some((c) => this.allowedCapabilities.includes(c));
|
|
62605
|
+
const isMcp = _AutoApprovePermissionPolicy.isMcpTool(tool.name);
|
|
62606
|
+
const mcpProxyAllowed = this.allowedCapabilities.includes(ToolCapabilities.MCP_PROXY);
|
|
62607
|
+
const dangerousNotAllowed = getDangerousCapabilities(tool).filter(
|
|
62608
|
+
(c) => !this.allowedCapabilities.includes(c)
|
|
62609
|
+
);
|
|
62610
|
+
const blocked = tool.permission === "deny" || isMcp && !mcpProxyAllowed || !hasAllowedCap || dangerousNotAllowed.length > 0;
|
|
62611
|
+
if (blocked) {
|
|
62612
|
+
const reason = isMcp && !mcpProxyAllowed ? `MCP tool ${tool.name} is not auto-approved for subagents \u2014 ask the leader to allow mcp.proxy explicitly` : tool.permission === "deny" ? "tool default deny" : dangerousNotAllowed.length > 0 ? `tool requires un-granted dangerous capability (needs: ${dangerousNotAllowed.join(", ")}, allowed: ${this.allowedCapabilities.join(", ")})` : `tool lacks allowed capability (has: ${caps.join(", ") || "none"}, allowed: ${this.allowedCapabilities.join(", ")})`;
|
|
62613
|
+
return {
|
|
62614
|
+
permission: "deny",
|
|
62615
|
+
source: "subagent_guard",
|
|
62616
|
+
reason
|
|
62617
|
+
};
|
|
62618
|
+
}
|
|
62619
|
+
return { permission: "auto", source: "yolo" };
|
|
62620
|
+
}
|
|
62621
|
+
async trust() {
|
|
62622
|
+
}
|
|
62623
|
+
async deny() {
|
|
62624
|
+
}
|
|
62625
|
+
denyOnce() {
|
|
62626
|
+
}
|
|
62627
|
+
allowOnce() {
|
|
62628
|
+
}
|
|
62629
|
+
async explain(tool) {
|
|
62630
|
+
const decision = await this.evaluate(tool);
|
|
62631
|
+
return {
|
|
62632
|
+
toolName: tool.name,
|
|
62633
|
+
subject: null,
|
|
62634
|
+
steps: [
|
|
62635
|
+
{
|
|
62636
|
+
rule: "subagent auto",
|
|
62637
|
+
matched: decision.permission === "auto",
|
|
62638
|
+
decision: decision.permission,
|
|
62639
|
+
source: decision.source,
|
|
62640
|
+
detail: decision.reason ?? `subagent policy: ${decision.permission}`
|
|
62641
|
+
}
|
|
62642
|
+
],
|
|
62643
|
+
winnerIndex: 0,
|
|
62644
|
+
decision
|
|
62645
|
+
};
|
|
62646
|
+
}
|
|
62647
|
+
async reload() {
|
|
62648
|
+
}
|
|
62649
|
+
};
|
|
62650
|
+
|
|
62651
|
+
// src/security/permission-helpers.ts
|
|
62593
62652
|
function matchesTrust(patterns, subject2) {
|
|
62594
62653
|
return patterns.includes(subject2) || matchAny(patterns, subject2);
|
|
62595
62654
|
}
|
|
@@ -62684,6 +62743,8 @@ function shellCommandReadsSensitivePath(command) {
|
|
|
62684
62743
|
}
|
|
62685
62744
|
return false;
|
|
62686
62745
|
}
|
|
62746
|
+
|
|
62747
|
+
// src/security/permission-policy.ts
|
|
62687
62748
|
var DefaultPermissionPolicy = class {
|
|
62688
62749
|
policy = {};
|
|
62689
62750
|
loaded = false;
|
|
@@ -63426,65 +63487,6 @@ var DefaultPermissionPolicy = class {
|
|
|
63426
63487
|
return void 0;
|
|
63427
63488
|
}
|
|
63428
63489
|
};
|
|
63429
|
-
var AutoApprovePermissionPolicy = class _AutoApprovePermissionPolicy {
|
|
63430
|
-
allowedCapabilities;
|
|
63431
|
-
constructor(allowedCapabilities) {
|
|
63432
|
-
this.allowedCapabilities = allowedCapabilities ?? [
|
|
63433
|
-
ToolCapabilities.FS_READ,
|
|
63434
|
-
ToolCapabilities.NET_OUTBOUND
|
|
63435
|
-
];
|
|
63436
|
-
}
|
|
63437
|
-
static isMcpTool(name) {
|
|
63438
|
-
return name.startsWith("mcp__");
|
|
63439
|
-
}
|
|
63440
|
-
async evaluate(tool) {
|
|
63441
|
-
const caps = tool.capabilities ?? [];
|
|
63442
|
-
const hasAllowedCap = caps.some((c) => this.allowedCapabilities.includes(c));
|
|
63443
|
-
const isMcp = _AutoApprovePermissionPolicy.isMcpTool(tool.name);
|
|
63444
|
-
const mcpProxyAllowed = this.allowedCapabilities.includes(ToolCapabilities.MCP_PROXY);
|
|
63445
|
-
const dangerousNotAllowed = getDangerousCapabilities(tool).filter(
|
|
63446
|
-
(c) => !this.allowedCapabilities.includes(c)
|
|
63447
|
-
);
|
|
63448
|
-
const blocked = tool.permission === "deny" || isMcp && !mcpProxyAllowed || !hasAllowedCap || dangerousNotAllowed.length > 0;
|
|
63449
|
-
if (blocked) {
|
|
63450
|
-
const reason = isMcp && !mcpProxyAllowed ? `MCP tool ${tool.name} is not auto-approved for subagents \u2014 ask the leader to allow mcp.proxy explicitly` : tool.permission === "deny" ? "tool default deny" : dangerousNotAllowed.length > 0 ? `tool requires un-granted dangerous capability (needs: ${dangerousNotAllowed.join(", ")}, allowed: ${this.allowedCapabilities.join(", ")})` : `tool lacks allowed capability (has: ${caps.join(", ") || "none"}, allowed: ${this.allowedCapabilities.join(", ")})`;
|
|
63451
|
-
return {
|
|
63452
|
-
permission: "deny",
|
|
63453
|
-
source: "subagent_guard",
|
|
63454
|
-
reason
|
|
63455
|
-
};
|
|
63456
|
-
}
|
|
63457
|
-
return { permission: "auto", source: "yolo" };
|
|
63458
|
-
}
|
|
63459
|
-
async trust() {
|
|
63460
|
-
}
|
|
63461
|
-
async deny() {
|
|
63462
|
-
}
|
|
63463
|
-
denyOnce() {
|
|
63464
|
-
}
|
|
63465
|
-
allowOnce() {
|
|
63466
|
-
}
|
|
63467
|
-
async explain(tool) {
|
|
63468
|
-
const decision = await this.evaluate(tool);
|
|
63469
|
-
return {
|
|
63470
|
-
toolName: tool.name,
|
|
63471
|
-
subject: null,
|
|
63472
|
-
steps: [
|
|
63473
|
-
{
|
|
63474
|
-
rule: "subagent auto",
|
|
63475
|
-
matched: decision.permission === "auto",
|
|
63476
|
-
decision: decision.permission,
|
|
63477
|
-
source: decision.source,
|
|
63478
|
-
detail: decision.reason ?? `subagent policy: ${decision.permission}`
|
|
63479
|
-
}
|
|
63480
|
-
],
|
|
63481
|
-
winnerIndex: 0,
|
|
63482
|
-
decision
|
|
63483
|
-
};
|
|
63484
|
-
}
|
|
63485
|
-
async reload() {
|
|
63486
|
-
}
|
|
63487
|
-
};
|
|
63488
63490
|
|
|
63489
63491
|
// src/storage/attachment-store.ts
|
|
63490
63492
|
init_atomic_write();
|
|
@@ -75940,57 +75942,49 @@ function parseReviewSeverity(text2) {
|
|
|
75940
75942
|
const result = { critical: 0, high: 0, medium: 0 };
|
|
75941
75943
|
if (!text2) return result;
|
|
75942
75944
|
for (const level of ["critical", "high", "medium"]) {
|
|
75943
|
-
const
|
|
75944
|
-
const countMatch = text2.match(countRe);
|
|
75945
|
+
const countMatch = text2.match(new RegExp(`###\\s*${level}\\s*\\((\\d+)\\)`, "i"));
|
|
75945
75946
|
if (countMatch?.[1]) {
|
|
75946
75947
|
result[level] = Number.parseInt(countMatch[1], 10);
|
|
75947
75948
|
continue;
|
|
75948
75949
|
}
|
|
75949
|
-
const
|
|
75950
|
-
|
|
75951
|
-
|
|
75952
|
-
|
|
75953
|
-
result[level] = items ? items.length : 0;
|
|
75954
|
-
}
|
|
75950
|
+
const section = text2.match(
|
|
75951
|
+
new RegExp(`###\\s*${level}[^\\n]*\\n([\\s\\S]*?)(?=###|$)`, "i")
|
|
75952
|
+
)?.[1];
|
|
75953
|
+
result[level] = section?.match(/^\s*\d+\.\s/gm)?.length ?? 0;
|
|
75955
75954
|
}
|
|
75956
75955
|
return result;
|
|
75957
75956
|
}
|
|
75958
|
-
var SECURITY_KEYWORDS = [
|
|
75959
|
-
"injection",
|
|
75960
|
-
"xss",
|
|
75961
|
-
"csrf",
|
|
75962
|
-
"ssrf",
|
|
75963
|
-
"sql",
|
|
75964
|
-
"secret",
|
|
75965
|
-
"credential",
|
|
75966
|
-
"password",
|
|
75967
|
-
"api key",
|
|
75968
|
-
"token",
|
|
75969
|
-
"auth",
|
|
75970
|
-
"shell injection",
|
|
75971
|
-
"command injection",
|
|
75972
|
-
"innerhtml",
|
|
75973
|
-
"deserialization",
|
|
75974
|
-
"path traversal",
|
|
75975
|
-
"hardcoded",
|
|
75976
|
-
"privilege",
|
|
75977
|
-
"owasp"
|
|
75978
|
-
];
|
|
75979
75957
|
function decideCascadeAgents(text2, severities) {
|
|
75980
75958
|
const agents = /* @__PURE__ */ new Set();
|
|
75981
|
-
if (severities.critical > 0 || severities.high > 0)
|
|
75982
|
-
|
|
75983
|
-
|
|
75984
|
-
|
|
75985
|
-
|
|
75986
|
-
|
|
75987
|
-
|
|
75959
|
+
if (severities.critical > 0 || severities.high > 0) agents.add("bug-hunter");
|
|
75960
|
+
const securityKeywords = [
|
|
75961
|
+
"injection",
|
|
75962
|
+
"xss",
|
|
75963
|
+
"csrf",
|
|
75964
|
+
"ssrf",
|
|
75965
|
+
"sql",
|
|
75966
|
+
"secret",
|
|
75967
|
+
"credential",
|
|
75968
|
+
"password",
|
|
75969
|
+
"api key",
|
|
75970
|
+
"token",
|
|
75971
|
+
"auth",
|
|
75972
|
+
"shell injection",
|
|
75973
|
+
"command injection",
|
|
75974
|
+
"innerhtml",
|
|
75975
|
+
"deserialization",
|
|
75976
|
+
"path traversal",
|
|
75977
|
+
"hardcoded",
|
|
75978
|
+
"privilege",
|
|
75979
|
+
"owasp"
|
|
75980
|
+
];
|
|
75981
|
+
const criticalHighSections = text2.toLowerCase().matchAll(/###\s*(?:critical|high)[^\n]*\n([\s\S]*?)(?=###|$)/gi);
|
|
75982
|
+
for (const section of criticalHighSections) {
|
|
75988
75983
|
const body = section[1] ?? "";
|
|
75989
|
-
if (
|
|
75984
|
+
if (securityKeywords.some((keyword) => body.includes(keyword))) {
|
|
75990
75985
|
agents.add("security-scanner");
|
|
75991
75986
|
break;
|
|
75992
75987
|
}
|
|
75993
|
-
section = criticalHighRe.exec(lower);
|
|
75994
75988
|
}
|
|
75995
75989
|
return [...agents];
|
|
75996
75990
|
}
|
|
@@ -76083,9 +76077,8 @@ function buildAutoReviewCommand(getConfig, getInFlightCount) {
|
|
|
76083
76077
|
"Detects git-tracked file edits and dispatches review subagents",
|
|
76084
76078
|
"with configurable provider/model/fallback.",
|
|
76085
76079
|
"",
|
|
76086
|
-
"
|
|
76087
|
-
"
|
|
76088
|
-
"automatically spawned to investigate.",
|
|
76080
|
+
"Reports are persisted and shown as passive notifications.",
|
|
76081
|
+
"They never wake the leader or spawn mutating follow-up agents.",
|
|
76089
76082
|
"",
|
|
76090
76083
|
"Commands:",
|
|
76091
76084
|
" /auto-review Show current status and config",
|
|
@@ -76100,11 +76093,8 @@ function buildAutoReviewCommand(getConfig, getInFlightCount) {
|
|
|
76100
76093
|
" debounceMs debounce window (default 15000)",
|
|
76101
76094
|
" maxFilesPerBatch max files per review (default 15)",
|
|
76102
76095
|
" maxConcurrentReviews max parallel reviews (default 2)",
|
|
76103
|
-
|
|
76104
|
-
"
|
|
76105
|
-
' findings reach this severity. "high" fires',
|
|
76106
|
-
' on any High+ finding; "critical" only on Critical.',
|
|
76107
|
-
" maxCascadeDepth max fix+re-review cycles (default 2, 0=off)"
|
|
76096
|
+
" cascadeOn off | critical | high (default off)",
|
|
76097
|
+
" maxCascadeDepth max fix+re-review cycles (default 2)"
|
|
76108
76098
|
].join("\n"),
|
|
76109
76099
|
async run(args) {
|
|
76110
76100
|
const cfg = getConfig();
|
|
@@ -76120,7 +76110,6 @@ function buildAutoReviewCommand(getConfig, getInFlightCount) {
|
|
|
76120
76110
|
};
|
|
76121
76111
|
}
|
|
76122
76112
|
const inFlight = getInFlightCount();
|
|
76123
|
-
const cascadeDesc = cfg.cascadeOn === "off" ? "disabled" : `on ${cfg.cascadeOn}+ \u2192 spawns security-scanner/bug-hunter`;
|
|
76124
76113
|
return {
|
|
76125
76114
|
message: [
|
|
76126
76115
|
`\u{1F4CB} Auto Review \u2014 ${cfg.enabled ? "\u2705 enabled" : "\u23F8\uFE0F disabled"}`,
|
|
@@ -76131,7 +76120,7 @@ function buildAutoReviewCommand(getConfig, getInFlightCount) {
|
|
|
76131
76120
|
` Debounce: ${cfg.debounceMs} ms`,
|
|
76132
76121
|
` Max files: ${cfg.maxFilesPerBatch}`,
|
|
76133
76122
|
` Max parallel: ${cfg.maxConcurrentReviews}`,
|
|
76134
|
-
` Cascade: ${
|
|
76123
|
+
` Cascade: ${cfg.cascadeOn === "off" ? "off" : `on ${cfg.cascadeOn}+ \u2192 spawns security-scanner/bug-hunter`}`,
|
|
76135
76124
|
` Max depth: ${cfg.maxCascadeDepth} re-review cycle(s)`,
|
|
76136
76125
|
` In-flight: ${inFlight} review(s)`,
|
|
76137
76126
|
"",
|
|
@@ -77439,7 +77428,9 @@ function createChimeraPlugin() {
|
|
|
77439
77428
|
api.log.info("[chimera] skipped \u2014 changed files already have reviews in progress");
|
|
77440
77429
|
return;
|
|
77441
77430
|
}
|
|
77442
|
-
api.log.info(
|
|
77431
|
+
api.log.info(
|
|
77432
|
+
`[chimera] emitted review_needed event (${emittedBundle.files.length} files)`
|
|
77433
|
+
);
|
|
77443
77434
|
} catch (err) {
|
|
77444
77435
|
api.log.warn(`[chimera] session.ended handler failed: ${toErrorMessage(err)}`);
|
|
77445
77436
|
}
|
|
@@ -87978,6 +87969,7 @@ export {
|
|
|
87978
87969
|
ReplayLogStore,
|
|
87979
87970
|
ReplayProviderRunner,
|
|
87980
87971
|
RunController,
|
|
87972
|
+
SAGE_INJECTOR_HEADINGS,
|
|
87981
87973
|
SECURITY_SCANNER_AGENT,
|
|
87982
87974
|
SEMANTIC_TUNE_KNOBS,
|
|
87983
87975
|
SESSION_MARKER_EVENT_TYPES,
|
|
@@ -88107,6 +88099,7 @@ export {
|
|
|
88107
88099
|
buildWin32CmdShimInvocation,
|
|
88108
88100
|
canCaptureNewLearned,
|
|
88109
88101
|
canonicalProjectRoot,
|
|
88102
|
+
capSageLines,
|
|
88110
88103
|
captureLearnedFromAgentOutput,
|
|
88111
88104
|
captureLearnedFromAgentOutputDetailed,
|
|
88112
88105
|
checkConnectivity,
|
|
@@ -88688,6 +88681,7 @@ export {
|
|
|
88688
88681
|
slugify2 as slugify,
|
|
88689
88682
|
slugifyProjectAgentRole,
|
|
88690
88683
|
smartDefaultFallbackChain,
|
|
88684
|
+
splitSageOutputBlock,
|
|
88691
88685
|
sqliteCachePragmas,
|
|
88692
88686
|
sshManagerServer,
|
|
88693
88687
|
stableStringify3 as stableStringify,
|
|
@@ -3182,7 +3182,7 @@ var CONFIG_BEHAVIOR_DEFAULTS = {
|
|
|
3182
3182
|
// DEFAULT_STATUSLINE_MODE (packages/tui/src/components/settings-picker-model.ts).
|
|
3183
3183
|
statuslineMode: "minimum",
|
|
3184
3184
|
thinkingWord: DEFAULT_TUI_THINKING_WORD,
|
|
3185
|
-
showAgentSwarmPanel:
|
|
3185
|
+
showAgentSwarmPanel: "bottom"
|
|
3186
3186
|
},
|
|
3187
3187
|
circuitBreaker: { ...DEFAULT_CIRCUIT_BREAKER_CONFIG },
|
|
3188
3188
|
modelRuntime: {
|