@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.
@@ -29956,7 +29956,68 @@ function isClearlyDestructiveBashCommand(command, projectRoot) {
29956
29956
  return false;
29957
29957
  }
29958
29958
 
29959
- // src/security/permission-policy.ts
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: true
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: true
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/permission-policy.ts
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 countRe = new RegExp(`###\\s*${level}\\s*\\((\\d+)\\)`, "i");
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 sectionRe = new RegExp(`###\\s*${level}[^\\n]*\\n([\\s\\S]*?)(?=###|$)`, "i");
75950
- const sectionMatch = text2.match(sectionRe);
75951
- if (sectionMatch?.[1]) {
75952
- const items = sectionMatch[1].match(/^\s*\d+\.\s/gm);
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
- agents.add("bug-hunter");
75983
- }
75984
- const lower = text2.toLowerCase();
75985
- const criticalHighRe = /###\s*(?:critical|high)[^\n]*\n([\s\S]*?)(?=###|$)/gi;
75986
- let section = criticalHighRe.exec(lower);
75987
- while (section !== null) {
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 (SECURITY_KEYWORDS.some((kw) => body.includes(kw))) {
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
- "When a review report contains findings at or above the cascadeOn",
76087
- "threshold, follow-up agents (security-scanner, bug-hunter) are",
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
- ' cascadeOn "off" | "critical" | "high" (default off)',
76104
- " Spawns security-scanner/bug-hunter when",
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: ${cascadeDesc}`,
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(`[chimera] emitted review_needed event (${emittedBundle.files.length} files)`);
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: true
3185
+ showAgentSwarmPanel: "bottom"
3186
3186
  },
3187
3187
  circuitBreaker: { ...DEFAULT_CIRCUIT_BREAKER_CONFIG },
3188
3188
  modelRuntime: {