nexus-agents 2.79.3 → 2.79.4

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.
Files changed (113) hide show
  1. package/README.md +2 -2
  2. package/dist/{child-mcp-config-CTO2MBRM.js → child-mcp-config-DFRYTRBK.js} +2 -2
  3. package/dist/{chunk-HB4MIDHJ.js → chunk-3ENBGGYA.js} +104 -61
  4. package/dist/{chunk-HB4MIDHJ.js.map → chunk-3ENBGGYA.js.map} +1 -1
  5. package/dist/{chunk-6E3NMMEY.js → chunk-3RZWLQSC.js} +2 -2
  6. package/dist/{chunk-6E3NMMEY.js.map → chunk-3RZWLQSC.js.map} +1 -1
  7. package/dist/{chunk-KT5FIBWS.js → chunk-42MM7GKW.js} +2 -2
  8. package/dist/{chunk-3NIPH6UP.js → chunk-45NUO4FE.js} +2 -2
  9. package/dist/{chunk-2YPG6PDG.js → chunk-ACP4YARI.js} +3 -3
  10. package/dist/{chunk-D6TM2VHX.js → chunk-BIH2CBC5.js} +44 -21
  11. package/dist/chunk-BIH2CBC5.js.map +1 -0
  12. package/dist/{chunk-SD76JZBG.js → chunk-BSQ4KTY4.js} +2 -2
  13. package/dist/{chunk-6TFTVW77.js → chunk-BXI6DKBU.js} +3 -3
  14. package/dist/{chunk-PLX6FCFC.js → chunk-DOI7RE3X.js} +2 -2
  15. package/dist/{chunk-SWFJU3W2.js → chunk-DW3UTO43.js} +56 -46
  16. package/dist/{chunk-SWFJU3W2.js.map → chunk-DW3UTO43.js.map} +1 -1
  17. package/dist/{chunk-7XCUZI4G.js → chunk-IPDUZJPH.js} +3 -3
  18. package/dist/{chunk-2UYTFLMO.js → chunk-JMRCMMZ5.js} +2 -2
  19. package/dist/{chunk-GONMG4NM.js → chunk-LFTK5ZQG.js} +2 -2
  20. package/dist/{chunk-DLXT23AC.js → chunk-NJPFN75N.js} +2 -2
  21. package/dist/{chunk-YXWGEIQR.js → chunk-NVSJXN4S.js} +2 -2
  22. package/dist/{chunk-Q5CFPIJ5.js → chunk-NXNNT5XW.js} +3 -3
  23. package/dist/chunk-OFRDE7MK.js +136 -0
  24. package/dist/chunk-OFRDE7MK.js.map +1 -0
  25. package/dist/{chunk-L6SCKLGO.js → chunk-OGV7J5WG.js} +3 -3
  26. package/dist/{chunk-ZVCED4Z4.js → chunk-PAKVXGS2.js} +2 -2
  27. package/dist/{chunk-DNO2INX5.js → chunk-PDCLBWH5.js} +3 -3
  28. package/dist/{chunk-K2QILJG4.js → chunk-PHBRELUK.js} +33 -9
  29. package/dist/chunk-PHBRELUK.js.map +1 -0
  30. package/dist/{chunk-JI7S55R3.js → chunk-SU3Y6LU2.js} +8 -8
  31. package/dist/chunk-SU3Y6LU2.js.map +1 -0
  32. package/dist/{chunk-FJWWSVWB.js → chunk-TN5ZKSGC.js} +2 -2
  33. package/dist/{chunk-5O6XLBPP.js → chunk-UNFS6YBY.js} +2 -2
  34. package/dist/{chunk-HYU4GZY6.js → chunk-UNRTM43V.js} +2 -2
  35. package/dist/{chunk-VIQOVK4E.js → chunk-UOR2JWFH.js} +7 -136
  36. package/dist/chunk-UOR2JWFH.js.map +1 -0
  37. package/dist/{chunk-WDYCIJWN.js → chunk-UQOSVOEU.js} +4 -3
  38. package/dist/{chunk-WDYCIJWN.js.map → chunk-UQOSVOEU.js.map} +1 -1
  39. package/dist/{chunk-FVPYP5DD.js → chunk-UWDVEMYZ.js} +4 -4
  40. package/dist/{cli-circuit-breaker-I74ZQ44Q.js → cli-circuit-breaker-T75HOLZK.js} +4 -4
  41. package/dist/cli.js +46 -45
  42. package/dist/cli.js.map +1 -1
  43. package/dist/{composite-router-V3OC57IE.js → composite-router-OPSK5FCQ.js} +2 -2
  44. package/dist/{consensus-vote-ESFPGEJE.js → consensus-vote-CYUPIJXR.js} +11 -11
  45. package/dist/{context-retriever-MB3D7KS6.js → context-retriever-6AWHCHRP.js} +5 -5
  46. package/dist/{doctor-deep-KQ765XZA.js → doctor-deep-XBPRQ6ZP.js} +3 -3
  47. package/dist/expert-bridge-5YOPK5IT.js +11 -0
  48. package/dist/{factory-BUUXNGIB.js → factory-DN7SJZ5Z.js} +5 -5
  49. package/dist/{factory-LHHYDVZX.js → factory-Y3TMP4OQ.js} +4 -4
  50. package/dist/index.d.ts +24 -2
  51. package/dist/index.js +30 -28
  52. package/dist/index.js.map +1 -1
  53. package/dist/{init-opencode-GXZN2W5S.js → init-opencode-RV6IQEMS.js} +5 -5
  54. package/dist/{issue-triage-RMXPDZ2K.js → issue-triage-UTWKXLKC.js} +4 -4
  55. package/dist/{pr-reviewer-helpers-XCY7HOPE.js → pr-reviewer-helpers-L4L324FQ.js} +2 -2
  56. package/dist/{registry-command-6E4YKAMT.js → registry-command-6KJWW3W7.js} +2 -2
  57. package/dist/{repo-security-plan-AGRU72DL.js → repo-security-plan-HNLMF7J7.js} +3 -3
  58. package/dist/{research-helpers-synthesize-K2UCJQQG.js → research-helpers-synthesize-77TLYSW4.js} +3 -3
  59. package/dist/{routing-memory-3B6DDZ76.js → routing-memory-6DV6ZPAH.js} +2 -2
  60. package/dist/{session-memory-L7EQIY2O.js → session-memory-XZ3NJIR4.js} +3 -3
  61. package/dist/{setup-command-QSAGFMGN.js → setup-command-QOXG36UV.js} +10 -9
  62. package/dist/{setup-config-EQT24DD4.js → setup-config-B4V4QHDP.js} +3 -3
  63. package/dist/{setup-custom-api-IBDV654K.js → setup-custom-api-PJ6TGHJH.js} +4 -4
  64. package/dist/{tool-memory-6HCHQLAN.js → tool-memory-K2QPTPKV.js} +4 -4
  65. package/dist/{weather-report-ER3WUZ7S.js → weather-report-ZB4AKOIA.js} +2 -2
  66. package/package.json +4 -4
  67. package/scripts/postinstall.js +1 -1
  68. package/dist/chunk-D6TM2VHX.js.map +0 -1
  69. package/dist/chunk-JI7S55R3.js.map +0 -1
  70. package/dist/chunk-K2QILJG4.js.map +0 -1
  71. package/dist/chunk-VIQOVK4E.js.map +0 -1
  72. package/dist/expert-bridge-JKLC57IC.js +0 -10
  73. /package/dist/{child-mcp-config-CTO2MBRM.js.map → child-mcp-config-DFRYTRBK.js.map} +0 -0
  74. /package/dist/{chunk-KT5FIBWS.js.map → chunk-42MM7GKW.js.map} +0 -0
  75. /package/dist/{chunk-3NIPH6UP.js.map → chunk-45NUO4FE.js.map} +0 -0
  76. /package/dist/{chunk-2YPG6PDG.js.map → chunk-ACP4YARI.js.map} +0 -0
  77. /package/dist/{chunk-SD76JZBG.js.map → chunk-BSQ4KTY4.js.map} +0 -0
  78. /package/dist/{chunk-6TFTVW77.js.map → chunk-BXI6DKBU.js.map} +0 -0
  79. /package/dist/{chunk-PLX6FCFC.js.map → chunk-DOI7RE3X.js.map} +0 -0
  80. /package/dist/{chunk-7XCUZI4G.js.map → chunk-IPDUZJPH.js.map} +0 -0
  81. /package/dist/{chunk-2UYTFLMO.js.map → chunk-JMRCMMZ5.js.map} +0 -0
  82. /package/dist/{chunk-GONMG4NM.js.map → chunk-LFTK5ZQG.js.map} +0 -0
  83. /package/dist/{chunk-DLXT23AC.js.map → chunk-NJPFN75N.js.map} +0 -0
  84. /package/dist/{chunk-YXWGEIQR.js.map → chunk-NVSJXN4S.js.map} +0 -0
  85. /package/dist/{chunk-Q5CFPIJ5.js.map → chunk-NXNNT5XW.js.map} +0 -0
  86. /package/dist/{chunk-L6SCKLGO.js.map → chunk-OGV7J5WG.js.map} +0 -0
  87. /package/dist/{chunk-ZVCED4Z4.js.map → chunk-PAKVXGS2.js.map} +0 -0
  88. /package/dist/{chunk-DNO2INX5.js.map → chunk-PDCLBWH5.js.map} +0 -0
  89. /package/dist/{chunk-FJWWSVWB.js.map → chunk-TN5ZKSGC.js.map} +0 -0
  90. /package/dist/{chunk-5O6XLBPP.js.map → chunk-UNFS6YBY.js.map} +0 -0
  91. /package/dist/{chunk-HYU4GZY6.js.map → chunk-UNRTM43V.js.map} +0 -0
  92. /package/dist/{chunk-FVPYP5DD.js.map → chunk-UWDVEMYZ.js.map} +0 -0
  93. /package/dist/{cli-circuit-breaker-I74ZQ44Q.js.map → cli-circuit-breaker-T75HOLZK.js.map} +0 -0
  94. /package/dist/{composite-router-V3OC57IE.js.map → composite-router-OPSK5FCQ.js.map} +0 -0
  95. /package/dist/{consensus-vote-ESFPGEJE.js.map → consensus-vote-CYUPIJXR.js.map} +0 -0
  96. /package/dist/{context-retriever-MB3D7KS6.js.map → context-retriever-6AWHCHRP.js.map} +0 -0
  97. /package/dist/{doctor-deep-KQ765XZA.js.map → doctor-deep-XBPRQ6ZP.js.map} +0 -0
  98. /package/dist/{expert-bridge-JKLC57IC.js.map → expert-bridge-5YOPK5IT.js.map} +0 -0
  99. /package/dist/{factory-BUUXNGIB.js.map → factory-DN7SJZ5Z.js.map} +0 -0
  100. /package/dist/{factory-LHHYDVZX.js.map → factory-Y3TMP4OQ.js.map} +0 -0
  101. /package/dist/{init-opencode-GXZN2W5S.js.map → init-opencode-RV6IQEMS.js.map} +0 -0
  102. /package/dist/{issue-triage-RMXPDZ2K.js.map → issue-triage-UTWKXLKC.js.map} +0 -0
  103. /package/dist/{pr-reviewer-helpers-XCY7HOPE.js.map → pr-reviewer-helpers-L4L324FQ.js.map} +0 -0
  104. /package/dist/{registry-command-6E4YKAMT.js.map → registry-command-6KJWW3W7.js.map} +0 -0
  105. /package/dist/{repo-security-plan-AGRU72DL.js.map → repo-security-plan-HNLMF7J7.js.map} +0 -0
  106. /package/dist/{research-helpers-synthesize-K2UCJQQG.js.map → research-helpers-synthesize-77TLYSW4.js.map} +0 -0
  107. /package/dist/{routing-memory-3B6DDZ76.js.map → routing-memory-6DV6ZPAH.js.map} +0 -0
  108. /package/dist/{session-memory-L7EQIY2O.js.map → session-memory-XZ3NJIR4.js.map} +0 -0
  109. /package/dist/{setup-command-QSAGFMGN.js.map → setup-command-QOXG36UV.js.map} +0 -0
  110. /package/dist/{setup-config-EQT24DD4.js.map → setup-config-B4V4QHDP.js.map} +0 -0
  111. /package/dist/{setup-custom-api-IBDV654K.js.map → setup-custom-api-PJ6TGHJH.js.map} +0 -0
  112. /package/dist/{tool-memory-6HCHQLAN.js.map → tool-memory-K2QPTPKV.js.map} +0 -0
  113. /package/dist/{weather-report-ER3WUZ7S.js.map → weather-report-ZB4AKOIA.js.map} +0 -0
@@ -144,7 +144,7 @@ ${findingsSection}
144
144
  ${statsSection}
145
145
 
146
146
  ---
147
- *Reviewed by [nexus-agents](https://github.com/williamzujkowski/nexus-agents) in ${String(result.totalDurationMs)}ms*`;
147
+ *Reviewed by [nexus-agents](https://github.com/nexus-substrate/nexus-agents) in ${String(result.totalDurationMs)}ms*`;
148
148
  }
149
149
  function formatFindingsSection(result) {
150
150
  const allFindings = result.expertReviews.flatMap((r) => r.findings);
@@ -216,4 +216,4 @@ export {
216
216
  formatReviewComment,
217
217
  createFailedReview
218
218
  };
219
- //# sourceMappingURL=chunk-6E3NMMEY.js.map
219
+ //# sourceMappingURL=chunk-3RZWLQSC.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/dogfooding/pr-reviewer-helpers.ts"],"sourcesContent":["/**\n * nexus-agents/dogfooding - PR Reviewer Helpers\n *\n * Helper functions for PR review formatting and aggregation.\n *\n * @module dogfooding/pr-reviewer-helpers\n * (Source: Issue #161, Alignment Roadmap Phase 3)\n */\n\nimport { randomUUID } from 'node:crypto';\nimport type {\n PRMetadata,\n PRReviewResult,\n ExpertReviewResult,\n ReviewFinding,\n ReviewCategory,\n ReviewSeverity,\n ReviewDecision,\n} from './pr-review-types.js';\nimport {\n SEVERITY_ORDER,\n CATEGORY_DISPLAY_NAMES,\n SEVERITY_EMOJI,\n DECISION_EMOJI,\n} from './pr-review-types.js';\n\n// =============================================================================\n// Parsing Helpers\n// =============================================================================\n\nexport function parseSeverity(value: unknown): ReviewSeverity {\n if (typeof value === 'string') {\n const lower = value.toLowerCase();\n if (lower in SEVERITY_ORDER) return lower as ReviewSeverity;\n }\n return 'medium';\n}\n\nexport function parseCategory(value: unknown): ReviewCategory {\n if (typeof value === 'string') {\n const lower = value.toLowerCase();\n if (lower in CATEGORY_DISPLAY_NAMES) return lower as ReviewCategory;\n }\n return 'code_quality';\n}\n\nexport function extractSummary(output: Record<string, unknown>): string {\n if (typeof output.summary === 'string') return output.summary;\n if (typeof output.content === 'string') return output.content;\n if (typeof output.message === 'string') return output.message;\n return 'Review completed';\n}\n\nexport function extractStringField(\n record: Record<string, unknown>,\n ...keys: string[]\n): string | undefined {\n for (const key of keys) {\n const value = record[key];\n if (typeof value === 'string') return value;\n }\n return undefined;\n}\n\n// =============================================================================\n// Finding Parsing\n// =============================================================================\n\nexport function parseFindings(\n output: Record<string, unknown>,\n expertId: string,\n minSeverity: ReviewSeverity\n): ReviewFinding[] {\n const minOrder = SEVERITY_ORDER[minSeverity];\n const sources = collectSources(output);\n\n const findings: ReviewFinding[] = [];\n for (const source of sources) {\n if (!Array.isArray(source)) continue;\n for (const item of source) {\n const finding = parseOneFinding(item, expertId, minOrder);\n if (finding !== null) findings.push(finding);\n }\n }\n return findings;\n}\n\nfunction collectSources(output: Record<string, unknown>): unknown[] {\n return [\n output.findings,\n output.vulnerabilities,\n output.issues,\n (output as { content?: { findings?: unknown } }).content,\n ];\n}\n\nfunction parseOneFinding(item: unknown, expertId: string, minOrder: number): ReviewFinding | null {\n if (typeof item !== 'object' || item === null) return null;\n\n const record = item as Record<string, unknown>;\n const severity = parseSeverity(record.severity);\n if (SEVERITY_ORDER[severity] < minOrder) return null;\n\n return {\n id: randomUUID(),\n category: parseCategory(record.category),\n severity,\n title: extractStringField(record, 'title', 'name') ?? 'Finding',\n description: extractStringField(record, 'description', 'message') ?? '',\n file: typeof record.file === 'string' ? record.file : undefined,\n line: typeof record.line === 'number' ? record.line : undefined,\n suggestion: typeof record.suggestion === 'string' ? record.suggestion : undefined,\n expertId,\n confidence: typeof record.confidence === 'number' ? record.confidence : 0.7,\n };\n}\n\n// =============================================================================\n// Decision Helpers\n// =============================================================================\n\nexport function determineApproval(findings: ReviewFinding[]): boolean {\n const hasBlocking = findings.some((f) => f.severity === 'critical' || f.severity === 'high');\n return !hasBlocking;\n}\n\nexport function determineDecision(\n reviews: ExpertReviewResult[],\n findings: ReviewFinding[]\n): ReviewDecision {\n const hasCritical = findings.some((f) => f.severity === 'critical');\n const hasHigh = findings.some((f) => f.severity === 'high');\n const allApproved = reviews.every((r) => r.approved);\n\n if (hasCritical) return 'request_changes';\n if (hasHigh && !allApproved) return 'request_changes';\n if (findings.length > 0) return 'comment';\n return 'approve';\n}\n\nexport function calculateConsensus(reviews: ExpertReviewResult[]): number {\n if (reviews.length === 0) return 1;\n const approvals = reviews.filter((r) => r.approved).length;\n return approvals / reviews.length;\n}\n\n// =============================================================================\n// Counting Helpers\n// =============================================================================\n\nexport function countBySeverity(findings: ReviewFinding[]): Record<ReviewSeverity, number> {\n const counts: Record<ReviewSeverity, number> = {\n critical: 0,\n high: 0,\n medium: 0,\n low: 0,\n info: 0,\n };\n\n for (const f of findings) {\n counts[f.severity]++;\n }\n\n return counts;\n}\n\nexport function countByCategory(findings: ReviewFinding[]): Record<ReviewCategory, number> {\n const counts: Record<ReviewCategory, number> = {\n security: 0,\n performance: 0,\n code_quality: 0,\n testing: 0,\n documentation: 0,\n architecture: 0,\n };\n\n for (const f of findings) {\n counts[f.category]++;\n }\n\n return counts;\n}\n\nexport function sumFindings(counts: Record<ReviewSeverity, number>): number {\n return Object.values(counts).reduce((a, b) => a + b, 0);\n}\n\n// =============================================================================\n// Summary Generation\n// =============================================================================\n\nexport function generateSummary(\n pr: PRMetadata,\n reviews: ExpertReviewResult[],\n decision: ReviewDecision\n): string {\n const expertSummaries = reviews\n .map((r) => `- **${CATEGORY_DISPLAY_NAMES[r.expertType as ReviewCategory]}**: ${r.summary}`)\n .join('\\n');\n\n return `Reviewed PR #${String(pr.number)}: ${pr.title}\n\n**Decision:** ${decision.replaceAll('_', ' ')}\n**Experts consulted:** ${String(reviews.length)}\n\n${expertSummaries}`;\n}\n\n// =============================================================================\n// GitHub Comment Formatting\n// =============================================================================\n\n/**\n * Formats the review result as a GitHub comment.\n */\nexport function formatReviewComment(result: PRReviewResult): string {\n const emoji = DECISION_EMOJI[result.decision];\n const decisionText = result.decision.replaceAll('_', ' ').toUpperCase();\n\n const findingsSection = formatFindingsSection(result);\n const statsSection = formatStatsSection(result);\n\n return `## ${emoji} Nexus Agents Review: ${decisionText}\n\n${result.summary}\n\n${findingsSection}\n\n${statsSection}\n\n---\n*Reviewed by [nexus-agents](https://github.com/williamzujkowski/nexus-agents) in ${String(result.totalDurationMs)}ms*`;\n}\n\nfunction formatFindingsSection(result: PRReviewResult): string {\n const allFindings = result.expertReviews.flatMap((r) => r.findings);\n\n if (allFindings.length === 0) {\n return '_No issues found._';\n }\n\n const sorted = [...allFindings].sort(\n (a, b) => SEVERITY_ORDER[b.severity] - SEVERITY_ORDER[a.severity]\n );\n\n const lines = ['### Findings', ''];\n\n for (const f of sorted) {\n const emoji = SEVERITY_EMOJI[f.severity];\n const loc =\n f.file !== undefined\n ? ` (\\`${f.file}${f.line !== undefined ? `:${String(f.line)}` : ''}\\`)`\n : '';\n lines.push(`${emoji} **${f.title}**${loc}`);\n lines.push(`> ${f.description}`);\n if (f.suggestion !== undefined) {\n lines.push(`> 💡 ${f.suggestion}`);\n }\n lines.push('');\n }\n\n return lines.join('\\n');\n}\n\nfunction formatStatsSection(result: PRReviewResult): string {\n const { findingsBySeverity } = result;\n const total = sumFindings(findingsBySeverity);\n\n const parts: string[] = [];\n for (const severity of ['critical', 'high', 'medium', 'low', 'info'] as ReviewSeverity[]) {\n const count = findingsBySeverity[severity];\n if (count > 0) {\n parts.push(`${SEVERITY_EMOJI[severity]} ${String(count)} ${severity}`);\n }\n }\n\n return `<details>\n<summary>Review Statistics (${String(total)} findings)</summary>\n\n- Experts: ${String(result.expertCount)}\n- Consensus: ${(result.consensusScore * 100).toFixed(0)}%\n- Duration: ${String(result.totalDurationMs)}ms\n- Findings: ${parts.join(', ') || 'none'}\n\n</details>`;\n}\n\n// =============================================================================\n// Failed Review Factory\n// =============================================================================\n\nexport function createFailedReview(\n expertId: string,\n category: ReviewCategory,\n durationMs: number,\n error: string\n): ExpertReviewResult {\n return {\n expertId,\n expertType: category,\n approved: true, // Don't block on failures\n summary: `Review failed: ${error}`,\n findings: [],\n durationMs,\n confidence: 0,\n };\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/dogfooding/pr-reviewer-helpers.ts"],"sourcesContent":["/**\n * nexus-agents/dogfooding - PR Reviewer Helpers\n *\n * Helper functions for PR review formatting and aggregation.\n *\n * @module dogfooding/pr-reviewer-helpers\n * (Source: Issue #161, Alignment Roadmap Phase 3)\n */\n\nimport { randomUUID } from 'node:crypto';\nimport type {\n PRMetadata,\n PRReviewResult,\n ExpertReviewResult,\n ReviewFinding,\n ReviewCategory,\n ReviewSeverity,\n ReviewDecision,\n} from './pr-review-types.js';\nimport {\n SEVERITY_ORDER,\n CATEGORY_DISPLAY_NAMES,\n SEVERITY_EMOJI,\n DECISION_EMOJI,\n} from './pr-review-types.js';\n\n// =============================================================================\n// Parsing Helpers\n// =============================================================================\n\nexport function parseSeverity(value: unknown): ReviewSeverity {\n if (typeof value === 'string') {\n const lower = value.toLowerCase();\n if (lower in SEVERITY_ORDER) return lower as ReviewSeverity;\n }\n return 'medium';\n}\n\nexport function parseCategory(value: unknown): ReviewCategory {\n if (typeof value === 'string') {\n const lower = value.toLowerCase();\n if (lower in CATEGORY_DISPLAY_NAMES) return lower as ReviewCategory;\n }\n return 'code_quality';\n}\n\nexport function extractSummary(output: Record<string, unknown>): string {\n if (typeof output.summary === 'string') return output.summary;\n if (typeof output.content === 'string') return output.content;\n if (typeof output.message === 'string') return output.message;\n return 'Review completed';\n}\n\nexport function extractStringField(\n record: Record<string, unknown>,\n ...keys: string[]\n): string | undefined {\n for (const key of keys) {\n const value = record[key];\n if (typeof value === 'string') return value;\n }\n return undefined;\n}\n\n// =============================================================================\n// Finding Parsing\n// =============================================================================\n\nexport function parseFindings(\n output: Record<string, unknown>,\n expertId: string,\n minSeverity: ReviewSeverity\n): ReviewFinding[] {\n const minOrder = SEVERITY_ORDER[minSeverity];\n const sources = collectSources(output);\n\n const findings: ReviewFinding[] = [];\n for (const source of sources) {\n if (!Array.isArray(source)) continue;\n for (const item of source) {\n const finding = parseOneFinding(item, expertId, minOrder);\n if (finding !== null) findings.push(finding);\n }\n }\n return findings;\n}\n\nfunction collectSources(output: Record<string, unknown>): unknown[] {\n return [\n output.findings,\n output.vulnerabilities,\n output.issues,\n (output as { content?: { findings?: unknown } }).content,\n ];\n}\n\nfunction parseOneFinding(item: unknown, expertId: string, minOrder: number): ReviewFinding | null {\n if (typeof item !== 'object' || item === null) return null;\n\n const record = item as Record<string, unknown>;\n const severity = parseSeverity(record.severity);\n if (SEVERITY_ORDER[severity] < minOrder) return null;\n\n return {\n id: randomUUID(),\n category: parseCategory(record.category),\n severity,\n title: extractStringField(record, 'title', 'name') ?? 'Finding',\n description: extractStringField(record, 'description', 'message') ?? '',\n file: typeof record.file === 'string' ? record.file : undefined,\n line: typeof record.line === 'number' ? record.line : undefined,\n suggestion: typeof record.suggestion === 'string' ? record.suggestion : undefined,\n expertId,\n confidence: typeof record.confidence === 'number' ? record.confidence : 0.7,\n };\n}\n\n// =============================================================================\n// Decision Helpers\n// =============================================================================\n\nexport function determineApproval(findings: ReviewFinding[]): boolean {\n const hasBlocking = findings.some((f) => f.severity === 'critical' || f.severity === 'high');\n return !hasBlocking;\n}\n\nexport function determineDecision(\n reviews: ExpertReviewResult[],\n findings: ReviewFinding[]\n): ReviewDecision {\n const hasCritical = findings.some((f) => f.severity === 'critical');\n const hasHigh = findings.some((f) => f.severity === 'high');\n const allApproved = reviews.every((r) => r.approved);\n\n if (hasCritical) return 'request_changes';\n if (hasHigh && !allApproved) return 'request_changes';\n if (findings.length > 0) return 'comment';\n return 'approve';\n}\n\nexport function calculateConsensus(reviews: ExpertReviewResult[]): number {\n if (reviews.length === 0) return 1;\n const approvals = reviews.filter((r) => r.approved).length;\n return approvals / reviews.length;\n}\n\n// =============================================================================\n// Counting Helpers\n// =============================================================================\n\nexport function countBySeverity(findings: ReviewFinding[]): Record<ReviewSeverity, number> {\n const counts: Record<ReviewSeverity, number> = {\n critical: 0,\n high: 0,\n medium: 0,\n low: 0,\n info: 0,\n };\n\n for (const f of findings) {\n counts[f.severity]++;\n }\n\n return counts;\n}\n\nexport function countByCategory(findings: ReviewFinding[]): Record<ReviewCategory, number> {\n const counts: Record<ReviewCategory, number> = {\n security: 0,\n performance: 0,\n code_quality: 0,\n testing: 0,\n documentation: 0,\n architecture: 0,\n };\n\n for (const f of findings) {\n counts[f.category]++;\n }\n\n return counts;\n}\n\nexport function sumFindings(counts: Record<ReviewSeverity, number>): number {\n return Object.values(counts).reduce((a, b) => a + b, 0);\n}\n\n// =============================================================================\n// Summary Generation\n// =============================================================================\n\nexport function generateSummary(\n pr: PRMetadata,\n reviews: ExpertReviewResult[],\n decision: ReviewDecision\n): string {\n const expertSummaries = reviews\n .map((r) => `- **${CATEGORY_DISPLAY_NAMES[r.expertType as ReviewCategory]}**: ${r.summary}`)\n .join('\\n');\n\n return `Reviewed PR #${String(pr.number)}: ${pr.title}\n\n**Decision:** ${decision.replaceAll('_', ' ')}\n**Experts consulted:** ${String(reviews.length)}\n\n${expertSummaries}`;\n}\n\n// =============================================================================\n// GitHub Comment Formatting\n// =============================================================================\n\n/**\n * Formats the review result as a GitHub comment.\n */\nexport function formatReviewComment(result: PRReviewResult): string {\n const emoji = DECISION_EMOJI[result.decision];\n const decisionText = result.decision.replaceAll('_', ' ').toUpperCase();\n\n const findingsSection = formatFindingsSection(result);\n const statsSection = formatStatsSection(result);\n\n return `## ${emoji} Nexus Agents Review: ${decisionText}\n\n${result.summary}\n\n${findingsSection}\n\n${statsSection}\n\n---\n*Reviewed by [nexus-agents](https://github.com/nexus-substrate/nexus-agents) in ${String(result.totalDurationMs)}ms*`;\n}\n\nfunction formatFindingsSection(result: PRReviewResult): string {\n const allFindings = result.expertReviews.flatMap((r) => r.findings);\n\n if (allFindings.length === 0) {\n return '_No issues found._';\n }\n\n const sorted = [...allFindings].sort(\n (a, b) => SEVERITY_ORDER[b.severity] - SEVERITY_ORDER[a.severity]\n );\n\n const lines = ['### Findings', ''];\n\n for (const f of sorted) {\n const emoji = SEVERITY_EMOJI[f.severity];\n const loc =\n f.file !== undefined\n ? ` (\\`${f.file}${f.line !== undefined ? `:${String(f.line)}` : ''}\\`)`\n : '';\n lines.push(`${emoji} **${f.title}**${loc}`);\n lines.push(`> ${f.description}`);\n if (f.suggestion !== undefined) {\n lines.push(`> 💡 ${f.suggestion}`);\n }\n lines.push('');\n }\n\n return lines.join('\\n');\n}\n\nfunction formatStatsSection(result: PRReviewResult): string {\n const { findingsBySeverity } = result;\n const total = sumFindings(findingsBySeverity);\n\n const parts: string[] = [];\n for (const severity of ['critical', 'high', 'medium', 'low', 'info'] as ReviewSeverity[]) {\n const count = findingsBySeverity[severity];\n if (count > 0) {\n parts.push(`${SEVERITY_EMOJI[severity]} ${String(count)} ${severity}`);\n }\n }\n\n return `<details>\n<summary>Review Statistics (${String(total)} findings)</summary>\n\n- Experts: ${String(result.expertCount)}\n- Consensus: ${(result.consensusScore * 100).toFixed(0)}%\n- Duration: ${String(result.totalDurationMs)}ms\n- Findings: ${parts.join(', ') || 'none'}\n\n</details>`;\n}\n\n// =============================================================================\n// Failed Review Factory\n// =============================================================================\n\nexport function createFailedReview(\n expertId: string,\n category: ReviewCategory,\n durationMs: number,\n error: string\n): ExpertReviewResult {\n return {\n expertId,\n expertType: category,\n approved: true, // Don't block on failures\n summary: `Review failed: ${error}`,\n findings: [],\n durationMs,\n confidence: 0,\n };\n}\n"],"mappings":"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","names":[]}
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  createLogger
3
- } from "./chunk-WDYCIJWN.js";
3
+ } from "./chunk-UQOSVOEU.js";
4
4
 
5
5
  // src/config/available-models-cache.ts
6
6
  var logger = createLogger({ component: "available-models-cache" });
@@ -150,4 +150,4 @@ export {
150
150
  getDefaultAvailableModelsCache,
151
151
  setDefaultAvailableModelsCache
152
152
  };
153
- //# sourceMappingURL=chunk-KT5FIBWS.js.map
153
+ //# sourceMappingURL=chunk-42MM7GKW.js.map
@@ -4,7 +4,7 @@ import {
4
4
  getErrorMessage,
5
5
  getTimeProvider,
6
6
  ok
7
- } from "./chunk-WDYCIJWN.js";
7
+ } from "./chunk-UQOSVOEU.js";
8
8
 
9
9
  // src/context/session-memory.ts
10
10
  import * as fs from "fs";
@@ -351,4 +351,4 @@ export {
351
351
  SessionMemory,
352
352
  createSessionMemory
353
353
  };
354
- //# sourceMappingURL=chunk-3NIPH6UP.js.map
354
+ //# sourceMappingURL=chunk-45NUO4FE.js.map
@@ -2,14 +2,14 @@ import {
2
2
  CircuitBreakerRegistry,
3
3
  CircuitError,
4
4
  mapCliErrorToCategory
5
- } from "./chunk-DLXT23AC.js";
5
+ } from "./chunk-NJPFN75N.js";
6
6
  import {
7
7
  createLogger,
8
8
  err,
9
9
  getFallbackChainForCategory,
10
10
  getTimeProvider,
11
11
  ok
12
- } from "./chunk-WDYCIJWN.js";
12
+ } from "./chunk-UQOSVOEU.js";
13
13
 
14
14
  // src/cli-adapters/cli-circuit-breaker.ts
15
15
  var CATEGORY_TO_FALLBACK = {
@@ -152,4 +152,4 @@ export {
152
152
  CliCircuitBreakerIntegration,
153
153
  createCliCircuitBreakerIntegration
154
154
  };
155
- //# sourceMappingURL=chunk-2YPG6PDG.js.map
155
+ //# sourceMappingURL=chunk-ACP4YARI.js.map
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  CliCircuitBreaker,
3
3
  DEFAULT_CIRCUIT_BREAKER_CONFIG
4
- } from "./chunk-DLXT23AC.js";
4
+ } from "./chunk-NJPFN75N.js";
5
5
  import {
6
6
  CLI_SUBPROCESS_TIMEOUTS,
7
7
  CLI_TIMEOUTS,
@@ -24,7 +24,7 @@ import {
24
24
  getTimeProvider,
25
25
  isRateLimitText,
26
26
  ok
27
- } from "./chunk-WDYCIJWN.js";
27
+ } from "./chunk-UQOSVOEU.js";
28
28
 
29
29
  // src/cli-adapters/subprocess-adapter.ts
30
30
  import { spawn } from "child_process";
@@ -1267,7 +1267,7 @@ var ClaudeCliAdapter = class extends SubprocessCliAdapter {
1267
1267
  };
1268
1268
 
1269
1269
  // src/cli-adapters/adapters/gemini-adapter.ts
1270
- import { writeFileSync, unlinkSync, mkdtempSync } from "fs";
1270
+ import { writeFileSync, rmSync, mkdtempSync } from "fs";
1271
1271
  import { tmpdir } from "os";
1272
1272
  import { join } from "path";
1273
1273
 
@@ -1653,7 +1653,7 @@ var GeminiCliAdapter = class extends SubprocessCliAdapter {
1653
1653
  args.push("--policy", file);
1654
1654
  cleanup = () => {
1655
1655
  try {
1656
- unlinkSync(file);
1656
+ rmSync(dir, { recursive: true, force: true });
1657
1657
  } catch {
1658
1658
  }
1659
1659
  };
@@ -1709,7 +1709,7 @@ var GeminiCliAdapter = class extends SubprocessCliAdapter {
1709
1709
  };
1710
1710
 
1711
1711
  // src/cli-adapters/adapters/codex-adapter.ts
1712
- import { writeFileSync as writeFileSync2, unlinkSync as unlinkSync2, mkdtempSync as mkdtempSync2 } from "fs";
1712
+ import { writeFileSync as writeFileSync2, rmSync as rmSync2, mkdtempSync as mkdtempSync2 } from "fs";
1713
1713
  import { tmpdir as tmpdir2 } from "os";
1714
1714
  import { join as join2 } from "path";
1715
1715
 
@@ -1930,7 +1930,7 @@ var CodexCliAdapter = class extends SubprocessCliAdapter {
1930
1930
  args.push("-c", `model_instructions_file=${file}`);
1931
1931
  cleanup = () => {
1932
1932
  try {
1933
- unlinkSync2(file);
1933
+ rmSync2(dir, { recursive: true, force: true });
1934
1934
  } catch {
1935
1935
  }
1936
1936
  };
@@ -2146,15 +2146,25 @@ var OpenCodeResponseParser = class {
2146
2146
  parse(raw) {
2147
2147
  const lines = raw.trim().split("\n");
2148
2148
  const state = this.processAllLines(lines);
2149
+ const errorMessage = state.errorMessages.length > 0 ? state.errorMessages.join("; ") : void 0;
2149
2150
  if (state.contentParts.length === 0) {
2151
+ if (errorMessage !== void 0) {
2152
+ return this.buildResponse("", state.sessionId, state.usage, errorMessage);
2153
+ }
2150
2154
  return this.handleEmptyContent(raw, lines.length, state);
2151
2155
  }
2152
- return this.buildResponse(state.contentParts.join(""), state.sessionId, state.usage);
2156
+ return this.buildResponse(
2157
+ state.contentParts.join(""),
2158
+ state.sessionId,
2159
+ state.usage,
2160
+ errorMessage
2161
+ );
2153
2162
  }
2154
2163
  /** Processes all NDJSON lines and returns aggregated state. */
2155
2164
  processAllLines(lines) {
2156
2165
  let sessionId;
2157
2166
  const contentParts = [];
2167
+ const errorMessages = [];
2158
2168
  let usage;
2159
2169
  let hasStepEvents = false;
2160
2170
  let hasAnyRecognizedEvent = false;
@@ -2163,7 +2173,7 @@ var OpenCodeResponseParser = class {
2163
2173
  if (line === void 0 || line.trim() === "") continue;
2164
2174
  const hadEvent = this.processLine(
2165
2175
  line,
2166
- contentParts,
2176
+ { contentParts, errorMessages },
2167
2177
  (id) => sessionId = id,
2168
2178
  (u) => usage = u,
2169
2179
  idx
@@ -2171,7 +2181,14 @@ var OpenCodeResponseParser = class {
2171
2181
  if (hadEvent) hasStepEvents = true;
2172
2182
  if (hadEvent || this.isRecognizedLegacyEvent(line)) hasAnyRecognizedEvent = true;
2173
2183
  }
2174
- return { sessionId, contentParts, usage, hasStepEvents, hasAnyRecognizedEvent };
2184
+ return {
2185
+ sessionId,
2186
+ contentParts,
2187
+ errorMessages,
2188
+ usage,
2189
+ hasStepEvents,
2190
+ hasAnyRecognizedEvent
2191
+ };
2175
2192
  }
2176
2193
  /** Handles the case where no text content was extracted from NDJSON. */
2177
2194
  handleEmptyContent(raw, lineCount, state) {
@@ -2191,11 +2208,12 @@ var OpenCodeResponseParser = class {
2191
2208
  return this.parsePlainJson(raw, state.hasAnyRecognizedEvent);
2192
2209
  }
2193
2210
  /** Builds an OpenCodeCliResponse from parsed components. */
2194
- buildResponse(content, sessionId, usage) {
2211
+ buildResponse(content, sessionId, usage, errorMessage) {
2195
2212
  return {
2196
2213
  content,
2197
2214
  ...sessionId !== void 0 && { sessionId },
2198
- ...usage !== void 0 && { usage }
2215
+ ...usage !== void 0 && { usage },
2216
+ ...errorMessage !== void 0 && { errorMessage }
2199
2217
  };
2200
2218
  }
2201
2219
  /**
@@ -2269,13 +2287,13 @@ var OpenCodeResponseParser = class {
2269
2287
  * Returns true if a real v1.2.x step event was processed (step_start/text/tool_use/step_finish).
2270
2288
  * Legacy events return false since they don't indicate tool-only responses.
2271
2289
  */
2272
- processLine(line, contentParts, setSessionId, setUsage, lineIndex) {
2290
+ processLine(line, collectors, setSessionId, setUsage, lineIndex) {
2273
2291
  try {
2274
2292
  const record = asRecord(JSON.parse(line));
2275
2293
  if (record === null) return false;
2276
- const isReal = this.processRealEvent(record, contentParts, setSessionId, setUsage);
2294
+ const isReal = this.processRealEvent(record, collectors, setSessionId, setUsage);
2277
2295
  if (isReal) return true;
2278
- this.processLegacyEvent(record, contentParts, setSessionId, setUsage);
2296
+ this.processLegacyEvent(record, collectors.contentParts, setSessionId, setUsage);
2279
2297
  return false;
2280
2298
  } catch {
2281
2299
  logger3.debug("Skipped malformed NDJSON line", {
@@ -2286,7 +2304,7 @@ var OpenCodeResponseParser = class {
2286
2304
  }
2287
2305
  }
2288
2306
  /** Processes real opencode v1.2.x event types. Returns true if handled. */
2289
- processRealEvent(record, contentParts, setSessionId, setUsage) {
2307
+ processRealEvent(record, collectors, setSessionId, setUsage) {
2290
2308
  switch (record.type) {
2291
2309
  case "step_start":
2292
2310
  case "tool_use":
@@ -2294,7 +2312,7 @@ var OpenCodeResponseParser = class {
2294
2312
  return true;
2295
2313
  case "text":
2296
2314
  this.handleRealSessionId(record, setSessionId);
2297
- this.pushRealTextContent(record, contentParts);
2315
+ this.pushRealTextContent(record, collectors.contentParts);
2298
2316
  return true;
2299
2317
  case "step_finish":
2300
2318
  this.handleRealSessionId(record, setSessionId);
@@ -2302,20 +2320,25 @@ var OpenCodeResponseParser = class {
2302
2320
  return true;
2303
2321
  case "error":
2304
2322
  this.handleRealSessionId(record, setSessionId);
2305
- this.pushErrorContent(record, contentParts);
2323
+ this.captureErrorMessage(record, collectors.errorMessages);
2306
2324
  return true;
2307
2325
  default:
2308
2326
  return false;
2309
2327
  }
2310
2328
  }
2311
- /** Extracts error message from error event (#1402). */
2312
- pushErrorContent(record, parts) {
2329
+ /**
2330
+ * Captures an error-event message for the response's `errorMessage` field
2331
+ * (#2821). Previously this pushed `[OpenCode error: ...]` into `contentParts`,
2332
+ * which made error-only streams look like successful responses to consensus
2333
+ * voters and the routing learner.
2334
+ */
2335
+ captureErrorMessage(record, errorMessages) {
2313
2336
  const errorObj = asRecord(record.error);
2314
2337
  if (errorObj === null) return;
2315
2338
  const data = asRecord(errorObj.data);
2316
2339
  const message = data !== null && typeof data.message === "string" ? data.message : typeof errorObj.name === "string" ? errorObj.name : "Unknown error";
2317
2340
  logger3.warn("OpenCode returned error event", { message });
2318
- parts.push(`[OpenCode error: ${message}]`);
2341
+ errorMessages.push(message);
2319
2342
  }
2320
2343
  /** Processes legacy assumed event types. */
2321
2344
  processLegacyEvent(record, contentParts, setSessionId, setUsage) {
@@ -3062,4 +3085,4 @@ export {
3062
3085
  isCliAvailable,
3063
3086
  getAvailableClis
3064
3087
  };
3065
- //# sourceMappingURL=chunk-D6TM2VHX.js.map
3088
+ //# sourceMappingURL=chunk-BIH2CBC5.js.map