nexus-agents 2.153.0 → 2.154.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.
@@ -42,7 +42,7 @@ import {
42
42
  } from "./chunk-DHVMSIT5.js";
43
43
 
44
44
  // src/version.ts
45
- var VERSION = true ? "2.153.0" : "dev";
45
+ var VERSION = true ? "2.154.0" : "dev";
46
46
 
47
47
  // src/config/schemas-core.ts
48
48
  import { z } from "zod";
@@ -2132,7 +2132,7 @@ async function runDoctorFix(result) {
2132
2132
  writeLine2("\u2500".repeat(40));
2133
2133
  let fixCount = 0;
2134
2134
  if (!result.dataDirectory.rootExists || result.dataDirectory.subdirectories.some((d) => !d.exists || !d.writable)) {
2135
- const { runSetup } = await import("./setup-command-4WFSYJK2.js");
2135
+ const { runSetup } = await import("./setup-command-OAJCXIMR.js");
2136
2136
  const setupResult = runSetup({
2137
2137
  skipMcp: true,
2138
2138
  skipRules: true,
@@ -2245,4 +2245,4 @@ export {
2245
2245
  startStdioServer,
2246
2246
  closeServer
2247
2247
  };
2248
- //# sourceMappingURL=chunk-EJXJNWV6.js.map
2248
+ //# sourceMappingURL=chunk-25F6LRU2.js.map
@@ -8,7 +8,7 @@ import {
8
8
  checkSqlite,
9
9
  defaultConfig,
10
10
  initDataDirectories
11
- } from "./chunk-EJXJNWV6.js";
11
+ } from "./chunk-25F6LRU2.js";
12
12
  import {
13
13
  BUILT_IN_EXPERTS
14
14
  } from "./chunk-ZM4O442V.js";
@@ -2000,4 +2000,4 @@ export {
2000
2000
  setupCommand,
2001
2001
  setupCommandAsync
2002
2002
  };
2003
- //# sourceMappingURL=chunk-HTXQVLOI.js.map
2003
+ //# sourceMappingURL=chunk-6VYNHHII.js.map
@@ -18,7 +18,7 @@ import {
18
18
  DEFAULT_TASK_TTL_MS,
19
19
  DEFAULT_TOOL_RATE_LIMITS,
20
20
  clampTaskTtl
21
- } from "./chunk-EJXJNWV6.js";
21
+ } from "./chunk-25F6LRU2.js";
22
22
  import {
23
23
  executeExpert
24
24
  } from "./chunk-JYHSZDKL.js";
@@ -44328,7 +44328,8 @@ function persistPrReviewRecord(opts) {
44328
44328
 
44329
44329
  // src/mcp/tools/pr-review-record-producer.ts
44330
44330
  function buildAndPersist(prNumber, baseSha, args) {
44331
- const { input, aggregate, counts, reviewCount, logger: logger58 } = args;
44331
+ const { input, aggregate, counts, reviewCount, logger: logger58, coverage } = args;
44332
+ const coverageSuffix = coverage?.partial === true ? ` [partial coverage: ${String(coverage.reviewedFiles)}/${String(coverage.totalFiles)} files reviewed, dropped: ${coverage.droppedFiles.join(", ")}]` : "";
44332
44333
  if (reviewedDiffWasTruncated(input.prDiff)) {
44333
44334
  logger58.warn(
44334
44335
  "Reviewed diff exceeds the hash byte cap; content past it is unbound in reviewedDiffHash",
@@ -44348,7 +44349,7 @@ function buildAndPersist(prNumber, baseSha, args) {
44348
44349
  error: counts.errorCount,
44349
44350
  total: reviewCount
44350
44351
  },
44351
- summary: `${aggregate.decision} (${String(counts.approveCount)} approve / ${String(counts.requestChangesCount)} request_changes / ${String(counts.abstainCount)} abstain) \u2014 ${input.prTitle}`,
44352
+ summary: `${aggregate.decision} (${String(counts.approveCount)} approve / ${String(counts.requestChangesCount)} request_changes / ${String(counts.abstainCount)} abstain) \u2014 ${input.prTitle}${coverageSuffix}`,
44352
44353
  logger: logger58
44353
44354
  });
44354
44355
  if (record === void 0) {
@@ -44403,6 +44404,133 @@ function persistReviewRecord(args) {
44403
44404
  }
44404
44405
  }
44405
44406
 
44407
+ // src/mcp/tools/pr-review-diff-budget.ts
44408
+ var SENSITIVE_PATH_PATTERNS = Object.freeze([
44409
+ "auth",
44410
+ "crypto",
44411
+ "secret",
44412
+ "credential",
44413
+ "security",
44414
+ "exec",
44415
+ "spawn",
44416
+ "password",
44417
+ "token",
44418
+ ".env",
44419
+ "permission",
44420
+ "sql"
44421
+ ]);
44422
+ function isSensitivePath(path12) {
44423
+ const lower = path12.toLowerCase();
44424
+ return SENSITIVE_PATH_PATTERNS.some((p) => lower.includes(p));
44425
+ }
44426
+ function byteLen(text) {
44427
+ return Buffer.byteLength(text, "utf-8");
44428
+ }
44429
+ function extractPath(fileText) {
44430
+ const nl = fileText.indexOf("\n");
44431
+ const firstLine = nl === -1 ? fileText : fileText.slice(0, nl);
44432
+ const m = /^diff --git a\/(.+?) b\/(.+)$/.exec(firstLine);
44433
+ if (m !== null) return m[2];
44434
+ return firstLine.replace(/^diff --git\s*/, "").trim();
44435
+ }
44436
+ function splitByFile(diff) {
44437
+ if (diff.length === 0) return [];
44438
+ const headerRe = /^diff --git .*$/gm;
44439
+ const starts = [];
44440
+ let m;
44441
+ while ((m = headerRe.exec(diff)) !== null) {
44442
+ starts.push(m.index);
44443
+ }
44444
+ if (starts.length === 0) {
44445
+ return [{ path: "(unstructured)", text: diff, bytes: byteLen(diff) }];
44446
+ }
44447
+ const files = [];
44448
+ const firstStart = starts[0];
44449
+ if (firstStart > 0) {
44450
+ const text = diff.slice(0, firstStart);
44451
+ files.push({ path: "(preamble)", text, bytes: byteLen(text) });
44452
+ }
44453
+ for (let i = 0; i < starts.length; i++) {
44454
+ const start = starts[i];
44455
+ const end = i + 1 < starts.length ? starts[i + 1] : diff.length;
44456
+ const text = diff.slice(start, end);
44457
+ files.push({ path: extractPath(text), text, bytes: byteLen(text) });
44458
+ }
44459
+ return files;
44460
+ }
44461
+ function truncateWithMarker(file, budget) {
44462
+ const marker = `
44463
+ [... TRUNCATED: file ${file.path} is ${String(file.bytes)} bytes, over the ${String(budget)}-byte review budget; showing a partial prefix \u2014 this file is listed in droppedFiles as partially-seen ...]
44464
+ `;
44465
+ const room = Math.max(0, budget - byteLen(marker));
44466
+ const prefix = Buffer.from(file.text, "utf-8").subarray(0, room).toString("utf-8");
44467
+ return prefix + marker;
44468
+ }
44469
+ function securityFirstPack(files, budget) {
44470
+ const sensitive = files.filter((f) => isSensitivePath(f.path));
44471
+ const rest = files.filter((f) => !isSensitivePath(f.path));
44472
+ const ordered = [...sensitive, ...rest];
44473
+ const segments = [];
44474
+ const reviewedFiles = [];
44475
+ const droppedFiles = [];
44476
+ let used = 0;
44477
+ for (let i = 0; i < ordered.length; i++) {
44478
+ const file = ordered[i];
44479
+ if (used + file.bytes <= budget) {
44480
+ segments.push(file.text);
44481
+ reviewedFiles.push(file.path);
44482
+ used += file.bytes;
44483
+ continue;
44484
+ }
44485
+ if (used === 0) {
44486
+ segments.push(truncateWithMarker(file, budget));
44487
+ reviewedFiles.push(file.path);
44488
+ droppedFiles.push(file.path);
44489
+ } else {
44490
+ droppedFiles.push(file.path);
44491
+ }
44492
+ for (let j = i + 1; j < ordered.length; j++) {
44493
+ droppedFiles.push(ordered[j].path);
44494
+ }
44495
+ break;
44496
+ }
44497
+ return {
44498
+ packed: segments.join(""),
44499
+ reviewedFiles,
44500
+ totalFiles: files.length,
44501
+ droppedFiles,
44502
+ partial: droppedFiles.length > 0
44503
+ };
44504
+ }
44505
+ function packDiffForReview(prDiff, budget) {
44506
+ if (prDiff.length <= budget) {
44507
+ return { coverage: void 0, packedDiff: prDiff, note: "" };
44508
+ }
44509
+ const pack = securityFirstPack(splitByFile(prDiff), budget);
44510
+ const coverage = {
44511
+ reviewedFiles: pack.reviewedFiles.length,
44512
+ totalFiles: pack.totalFiles,
44513
+ droppedFiles: pack.droppedFiles,
44514
+ partial: pack.partial,
44515
+ strategy: "budget"
44516
+ };
44517
+ const note = pack.partial ? `> NOTE: partial review \u2014 ${String(pack.reviewedFiles.length)} of ${String(pack.totalFiles)} files reviewed (security-prioritized; lowest-priority dropped): ${pack.droppedFiles.join(", ")}
44518
+
44519
+ ` : "";
44520
+ return { coverage, packedDiff: pack.packed, note };
44521
+ }
44522
+ function applyPartialCoverageGate(aggregate, coverage) {
44523
+ if (coverage?.partial !== true) return aggregate;
44524
+ if (aggregate.decision === "approve" && aggregate.verified) {
44525
+ return {
44526
+ decision: "abstain",
44527
+ verified: false,
44528
+ reason: `no_quorum: partial diff \u2014 ${String(coverage.reviewedFiles)} of ${String(coverage.totalFiles)} files reviewed`
44529
+ };
44530
+ }
44531
+ return aggregate;
44532
+ }
44533
+
44406
44534
  // src/mcp/tools/pr-review-tool.ts
44407
44535
  var PR_REVIEW_ROLES = [
44408
44536
  "architect",
@@ -44412,13 +44540,16 @@ var PR_REVIEW_ROLES = [
44412
44540
  "scope_steward"
44413
44541
  ];
44414
44542
  var MAX_DIFF_LENGTH = 5e4;
44543
+ var MAX_DIFF_INPUT_LENGTH = 2e6;
44415
44544
  var MAX_REPO_CONTEXT_LENGTH = 2e3;
44416
44545
  var MAX_DESCRIPTION_LENGTH = 1e4;
44417
44546
  var PR_REVIEW_ASYNC_HINT = "A pr_review run fans out to 5 live LLM voters and can exceed the synchronous MCP request timeout. Retry with `dispatch: 'async'` to get a jobId immediately, then poll get_job_result({ jobId }) for the result.";
44418
44547
  var PrReviewInputSchema = z91.object({
44419
44548
  prTitle: z91.string().min(1).max(500).describe("PR title"),
44420
44549
  prDescription: z91.string().max(MAX_DESCRIPTION_LENGTH).optional().describe("PR body / description"),
44421
- prDiff: z91.string().min(1).max(MAX_DIFF_LENGTH).describe(`Unified diff text (max ${String(MAX_DIFF_LENGTH)} chars; truncate before calling)`),
44550
+ prDiff: z91.string().min(1).max(MAX_DIFF_INPUT_LENGTH).describe(
44551
+ `Unified diff text (max ${String(MAX_DIFF_INPUT_LENGTH)} chars). No need to truncate before calling: diffs over ${String(MAX_DIFF_LENGTH)} chars are security-prioritized and PARTIALLY reviewed (lowest-priority whole files dropped; coverage reported on the response, and a partial review can block but never verified-approve).`
44552
+ ),
44422
44553
  repoContext: z91.string().max(MAX_REPO_CONTEXT_LENGTH).optional().describe(
44423
44554
  `Optional one-paragraph repo context (architecture, conventions; max ${String(MAX_REPO_CONTEXT_LENGTH)} chars; trim before calling)`
44424
44555
  ),
@@ -44591,19 +44722,36 @@ function summarizeReviews(reviews) {
44591
44722
  errorCount: reviews.filter((r) => r.source === "error").length
44592
44723
  };
44593
44724
  }
44594
- function aggregateWithTelemetry(reviews, errorPolicy, errorCount, logger58) {
44595
- const aggregate = aggregatePrDecisions(reviews, errorPolicy);
44596
- if (aggregate.reason !== void 0) {
44725
+ function resolveAggregate(reviews, input, errorCount, coverage, logger58) {
44726
+ const preGate = aggregatePrDecisions(reviews, input.errorPolicy);
44727
+ if (preGate.reason !== void 0) {
44597
44728
  logger58.warn("pr_review degraded to no_quorum under absolute_quorum (#4132)", {
44598
- reason: aggregate.reason,
44729
+ reason: preGate.reason,
44599
44730
  errorCount
44600
44731
  });
44601
44732
  }
44733
+ const aggregate = applyPartialCoverageGate(preGate, coverage);
44734
+ if (aggregate !== preGate) {
44735
+ logger58.warn(
44736
+ "pr_review partial review barred from verified-approve \u2014 degraded to no_quorum (#4140)",
44737
+ { reason: aggregate.reason }
44738
+ );
44739
+ }
44602
44740
  return aggregate;
44603
44741
  }
44742
+ function preparePanelProposal(input, logger58) {
44743
+ const { coverage, packedDiff, note } = packDiffForReview(input.prDiff, MAX_DIFF_LENGTH);
44744
+ const body = coverage === void 0 ? input : { ...input, prDiff: packedDiff };
44745
+ if (coverage?.partial === true) {
44746
+ logger58.warn(
44747
+ `pr_review diff over budget \u2014 reviewed ${String(coverage.reviewedFiles)} of ${String(coverage.totalFiles)} files, dropped ${String(coverage.droppedFiles.length)}`
44748
+ );
44749
+ }
44750
+ return { proposal: note + buildPrReviewProposal(body), coverage };
44751
+ }
44604
44752
  async function executePrReviewBody(input, logger58, gatewayAdapters) {
44605
44753
  const start = Date.now();
44606
- const proposal = buildPrReviewProposal(input);
44754
+ const { proposal, coverage } = preparePanelProposal(input, logger58);
44607
44755
  const voteResults = await collectRealVotes({
44608
44756
  roles: PR_REVIEW_ROLES,
44609
44757
  proposal,
@@ -44613,7 +44761,7 @@ async function executePrReviewBody(input, logger58, gatewayAdapters) {
44613
44761
  });
44614
44762
  const reviews = voteResults.map(toPrReviewVote);
44615
44763
  const counts = summarizeReviews(reviews);
44616
- const aggregate = aggregateWithTelemetry(reviews, input.errorPolicy, counts.errorCount, logger58);
44764
+ const aggregate = resolveAggregate(reviews, input, counts.errorCount, coverage, logger58);
44617
44765
  let costSummary;
44618
44766
  try {
44619
44767
  costSummary = recordDecisionCost({
@@ -44631,7 +44779,8 @@ async function executePrReviewBody(input, logger58, gatewayAdapters) {
44631
44779
  aggregate,
44632
44780
  counts,
44633
44781
  reviewCount: reviews.length,
44634
- logger: logger58
44782
+ logger: logger58,
44783
+ ...coverage !== void 0 ? { coverage } : {}
44635
44784
  });
44636
44785
  const response = {
44637
44786
  summary: aggregate.decision,
@@ -44640,7 +44789,8 @@ async function executePrReviewBody(input, logger58, gatewayAdapters) {
44640
44789
  reviews,
44641
44790
  totalDurationMs: Date.now() - start,
44642
44791
  ...costSummary !== void 0 ? { costSummary } : {},
44643
- recordOutcome: recordOutcome3
44792
+ recordOutcome: recordOutcome3,
44793
+ ...coverage !== void 0 ? { coverage } : {}
44644
44794
  };
44645
44795
  return toolSuccess(JSON.stringify(response, null, 2));
44646
44796
  }
@@ -51296,4 +51446,4 @@ export {
51296
51446
  shutdownFeedbackSubscriber,
51297
51447
  createEventBusBridge
51298
51448
  };
51299
- //# sourceMappingURL=chunk-C6S6L5WB.js.map
51449
+ //# sourceMappingURL=chunk-KNVO4P4W.js.map