@intrect/openswarm 0.9.3 → 0.10.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.
Files changed (374) hide show
  1. package/README.md +76 -1
  2. package/config.example.yaml +6 -0
  3. package/dist/adapters/agenticLoop.d.ts +24 -0
  4. package/dist/adapters/agenticLoop.d.ts.map +1 -1
  5. package/dist/adapters/agenticLoop.js +130 -11
  6. package/dist/adapters/agenticLoop.js.map +1 -1
  7. package/dist/adapters/applyPatch.d.ts +21 -0
  8. package/dist/adapters/applyPatch.d.ts.map +1 -0
  9. package/dist/adapters/applyPatch.js +175 -0
  10. package/dist/adapters/applyPatch.js.map +1 -0
  11. package/dist/adapters/base.d.ts.map +1 -1
  12. package/dist/adapters/base.js +7 -0
  13. package/dist/adapters/base.js.map +1 -1
  14. package/dist/adapters/codex.js +10 -0
  15. package/dist/adapters/codex.js.map +1 -1
  16. package/dist/adapters/codexResponses.d.ts +8 -0
  17. package/dist/adapters/codexResponses.d.ts.map +1 -1
  18. package/dist/adapters/codexResponses.js +86 -8
  19. package/dist/adapters/codexResponses.js.map +1 -1
  20. package/dist/adapters/errorClassification.d.ts +8 -0
  21. package/dist/adapters/errorClassification.d.ts.map +1 -0
  22. package/dist/adapters/errorClassification.js +54 -0
  23. package/dist/adapters/errorClassification.js.map +1 -0
  24. package/dist/adapters/gpt.d.ts.map +1 -1
  25. package/dist/adapters/gpt.js +12 -1
  26. package/dist/adapters/gpt.js.map +1 -1
  27. package/dist/adapters/local.d.ts.map +1 -1
  28. package/dist/adapters/local.js +9 -1
  29. package/dist/adapters/local.js.map +1 -1
  30. package/dist/adapters/openrouter.d.ts.map +1 -1
  31. package/dist/adapters/openrouter.js +9 -1
  32. package/dist/adapters/openrouter.js.map +1 -1
  33. package/dist/adapters/rateLimitError.d.ts +29 -0
  34. package/dist/adapters/rateLimitError.d.ts.map +1 -0
  35. package/dist/adapters/rateLimitError.js +64 -0
  36. package/dist/adapters/rateLimitError.js.map +1 -0
  37. package/dist/adapters/resultParsing.d.ts.map +1 -1
  38. package/dist/adapters/resultParsing.js +18 -0
  39. package/dist/adapters/resultParsing.js.map +1 -1
  40. package/dist/adapters/tools.d.ts +3 -0
  41. package/dist/adapters/tools.d.ts.map +1 -1
  42. package/dist/adapters/tools.js +148 -11
  43. package/dist/adapters/tools.js.map +1 -1
  44. package/dist/adapters/types.d.ts +15 -0
  45. package/dist/adapters/types.d.ts.map +1 -1
  46. package/dist/adapters/webTools.d.ts.map +1 -1
  47. package/dist/adapters/webTools.js +44 -21
  48. package/dist/adapters/webTools.js.map +1 -1
  49. package/dist/agents/agentPair.d.ts +9 -0
  50. package/dist/agents/agentPair.d.ts.map +1 -1
  51. package/dist/agents/agentPair.js.map +1 -1
  52. package/dist/agents/auditor.d.ts.map +1 -1
  53. package/dist/agents/auditor.js +3 -0
  54. package/dist/agents/auditor.js.map +1 -1
  55. package/dist/agents/documenter.d.ts.map +1 -1
  56. package/dist/agents/documenter.js +3 -0
  57. package/dist/agents/documenter.js.map +1 -1
  58. package/dist/agents/draftAnalyzer.d.ts +30 -7
  59. package/dist/agents/draftAnalyzer.d.ts.map +1 -1
  60. package/dist/agents/draftAnalyzer.js +181 -30
  61. package/dist/agents/draftAnalyzer.js.map +1 -1
  62. package/dist/agents/multiLensReview.d.ts +49 -0
  63. package/dist/agents/multiLensReview.d.ts.map +1 -0
  64. package/dist/agents/multiLensReview.js +148 -0
  65. package/dist/agents/multiLensReview.js.map +1 -0
  66. package/dist/agents/pairPipeline.d.ts +7 -1
  67. package/dist/agents/pairPipeline.d.ts.map +1 -1
  68. package/dist/agents/pairPipeline.js +110 -66
  69. package/dist/agents/pairPipeline.js.map +1 -1
  70. package/dist/agents/pipelineFormat.d.ts.map +1 -1
  71. package/dist/agents/pipelineFormat.js +4 -0
  72. package/dist/agents/pipelineFormat.js.map +1 -1
  73. package/dist/agents/reviewer.d.ts +16 -0
  74. package/dist/agents/reviewer.d.ts.map +1 -1
  75. package/dist/agents/reviewer.js +30 -0
  76. package/dist/agents/reviewer.js.map +1 -1
  77. package/dist/agents/skillDocumenter.d.ts.map +1 -1
  78. package/dist/agents/skillDocumenter.js +3 -0
  79. package/dist/agents/skillDocumenter.js.map +1 -1
  80. package/dist/agents/tester.d.ts.map +1 -1
  81. package/dist/agents/tester.js +3 -0
  82. package/dist/agents/tester.js.map +1 -1
  83. package/dist/agents/worker.d.ts +14 -0
  84. package/dist/agents/worker.d.ts.map +1 -1
  85. package/dist/agents/worker.js +123 -22
  86. package/dist/agents/worker.js.map +1 -1
  87. package/dist/automation/autonomousRunner.d.ts +12 -0
  88. package/dist/automation/autonomousRunner.d.ts.map +1 -1
  89. package/dist/automation/autonomousRunner.js +218 -29
  90. package/dist/automation/autonomousRunner.js.map +1 -1
  91. package/dist/automation/runnerExecution.d.ts +15 -0
  92. package/dist/automation/runnerExecution.d.ts.map +1 -1
  93. package/dist/automation/runnerExecution.js +77 -1
  94. package/dist/automation/runnerExecution.js.map +1 -1
  95. package/dist/automation/runnerState.d.ts +7 -0
  96. package/dist/automation/runnerState.d.ts.map +1 -1
  97. package/dist/automation/runnerState.js +23 -1
  98. package/dist/automation/runnerState.js.map +1 -1
  99. package/dist/automation/runnerTypes.d.ts +2 -0
  100. package/dist/automation/runnerTypes.d.ts.map +1 -1
  101. package/dist/automation/scheduler.d.ts +12 -0
  102. package/dist/automation/scheduler.d.ts.map +1 -1
  103. package/dist/automation/scheduler.js +29 -2
  104. package/dist/automation/scheduler.js.map +1 -1
  105. package/dist/automation/taskSource.d.ts +9 -1
  106. package/dist/automation/taskSource.d.ts.map +1 -1
  107. package/dist/automation/taskSource.js +13 -2
  108. package/dist/automation/taskSource.js.map +1 -1
  109. package/dist/cli/auditPM.d.ts +40 -0
  110. package/dist/cli/auditPM.d.ts.map +1 -0
  111. package/dist/cli/auditPM.js +152 -0
  112. package/dist/cli/auditPM.js.map +1 -0
  113. package/dist/cli/designPipeline.d.ts +30 -0
  114. package/dist/cli/designPipeline.d.ts.map +1 -0
  115. package/dist/cli/designPipeline.js +113 -0
  116. package/dist/cli/designPipeline.js.map +1 -0
  117. package/dist/cli/mcpCommand.d.ts +22 -0
  118. package/dist/cli/mcpCommand.d.ts.map +1 -0
  119. package/dist/cli/mcpCommand.js +93 -0
  120. package/dist/cli/mcpCommand.js.map +1 -0
  121. package/dist/cli/projectHandler.d.ts.map +1 -1
  122. package/dist/cli/projectHandler.js +4 -2
  123. package/dist/cli/projectHandler.js.map +1 -1
  124. package/dist/cli/reviewAudit.d.ts +130 -0
  125. package/dist/cli/reviewAudit.d.ts.map +1 -0
  126. package/dist/cli/reviewAudit.js +283 -0
  127. package/dist/cli/reviewAudit.js.map +1 -0
  128. package/dist/cli/reviewCommand.d.ts +53 -0
  129. package/dist/cli/reviewCommand.d.ts.map +1 -0
  130. package/dist/cli/reviewCommand.js +207 -0
  131. package/dist/cli/reviewCommand.js.map +1 -0
  132. package/dist/cli/reviewMaxCommand.d.ts +35 -0
  133. package/dist/cli/reviewMaxCommand.d.ts.map +1 -0
  134. package/dist/cli/reviewMaxCommand.js +278 -0
  135. package/dist/cli/reviewMaxCommand.js.map +1 -0
  136. package/dist/cli/reviewProgress.d.ts +34 -0
  137. package/dist/cli/reviewProgress.d.ts.map +1 -0
  138. package/dist/cli/reviewProgress.js +109 -0
  139. package/dist/cli/reviewProgress.js.map +1 -0
  140. package/dist/cli/scheduleCommand.d.ts +15 -0
  141. package/dist/cli/scheduleCommand.d.ts.map +1 -0
  142. package/dist/cli/scheduleCommand.js +68 -0
  143. package/dist/cli/scheduleCommand.js.map +1 -0
  144. package/dist/cli.js +182 -26
  145. package/dist/cli.js.map +1 -1
  146. package/dist/core/config.d.ts +24 -0
  147. package/dist/core/config.d.ts.map +1 -1
  148. package/dist/core/config.js +42 -0
  149. package/dist/core/config.js.map +1 -1
  150. package/dist/core/providerOverride.d.ts.map +1 -1
  151. package/dist/core/providerOverride.js +16 -13
  152. package/dist/core/providerOverride.js.map +1 -1
  153. package/dist/core/service.d.ts.map +1 -1
  154. package/dist/core/service.js +11 -0
  155. package/dist/core/service.js.map +1 -1
  156. package/dist/core/types.d.ts +38 -0
  157. package/dist/core/types.d.ts.map +1 -1
  158. package/dist/discord/discordHandlers.d.ts.map +1 -1
  159. package/dist/discord/discordHandlers.js +1 -0
  160. package/dist/discord/discordHandlers.js.map +1 -1
  161. package/dist/index.js +4 -0
  162. package/dist/index.js.map +1 -1
  163. package/dist/linear/linear.d.ts +21 -0
  164. package/dist/linear/linear.d.ts.map +1 -1
  165. package/dist/linear/linear.js +109 -4
  166. package/dist/linear/linear.js.map +1 -1
  167. package/dist/linear/projectUpdater.js +3 -1
  168. package/dist/linear/projectUpdater.js.map +1 -1
  169. package/dist/locale/prompts/en.d.ts.map +1 -1
  170. package/dist/locale/prompts/en.js +104 -11
  171. package/dist/locale/prompts/en.js.map +1 -1
  172. package/dist/locale/prompts/ko.d.ts.map +1 -1
  173. package/dist/locale/prompts/ko.js +103 -11
  174. package/dist/locale/prompts/ko.js.map +1 -1
  175. package/dist/locale/types.d.ts +12 -0
  176. package/dist/locale/types.d.ts.map +1 -1
  177. package/dist/mcp/mcpClient.d.ts +28 -1
  178. package/dist/mcp/mcpClient.d.ts.map +1 -1
  179. package/dist/mcp/mcpClient.js +74 -3
  180. package/dist/mcp/mcpClient.js.map +1 -1
  181. package/dist/orchestration/decisionEngine.d.ts +20 -0
  182. package/dist/orchestration/decisionEngine.d.ts.map +1 -1
  183. package/dist/orchestration/decisionEngine.js +23 -0
  184. package/dist/orchestration/decisionEngine.js.map +1 -1
  185. package/dist/orchestration/taskScheduler.d.ts.map +1 -1
  186. package/dist/orchestration/taskScheduler.js +12 -1
  187. package/dist/orchestration/taskScheduler.js.map +1 -1
  188. package/dist/support/chatBackend.d.ts +18 -0
  189. package/dist/support/chatBackend.d.ts.map +1 -1
  190. package/dist/support/chatBackend.js +92 -8
  191. package/dist/support/chatBackend.js.map +1 -1
  192. package/dist/support/chatSession.d.ts +51 -0
  193. package/dist/support/chatSession.d.ts.map +1 -0
  194. package/dist/support/chatSession.js +134 -0
  195. package/dist/support/chatSession.js.map +1 -0
  196. package/dist/support/chatTui.d.ts.map +1 -1
  197. package/dist/support/chatTui.js +6 -75
  198. package/dist/support/chatTui.js.map +1 -1
  199. package/dist/support/concurrencyPool.d.ts +18 -0
  200. package/dist/support/concurrencyPool.d.ts.map +1 -0
  201. package/dist/support/concurrencyPool.js +46 -0
  202. package/dist/support/concurrencyPool.js.map +1 -0
  203. package/dist/support/dashboardHtml.d.ts +1 -1
  204. package/dist/support/dashboardHtml.d.ts.map +1 -1
  205. package/dist/support/dashboardHtml.js +0 -28
  206. package/dist/support/dashboardHtml.js.map +1 -1
  207. package/dist/support/editParser.d.ts +26 -0
  208. package/dist/support/editParser.d.ts.map +1 -1
  209. package/dist/support/editParser.js +43 -0
  210. package/dist/support/editParser.js.map +1 -1
  211. package/dist/support/goalCommand.d.ts +35 -0
  212. package/dist/support/goalCommand.d.ts.map +1 -0
  213. package/dist/support/goalCommand.js +112 -0
  214. package/dist/support/goalCommand.js.map +1 -0
  215. package/dist/support/index.d.ts +0 -1
  216. package/dist/support/index.d.ts.map +1 -1
  217. package/dist/support/index.js +0 -1
  218. package/dist/support/index.js.map +1 -1
  219. package/dist/support/web.d.ts.map +1 -1
  220. package/dist/support/web.js +0 -7
  221. package/dist/support/web.js.map +1 -1
  222. package/dist/taskState/store.d.ts +5 -0
  223. package/dist/taskState/store.d.ts.map +1 -1
  224. package/dist/taskState/store.js +16 -0
  225. package/dist/taskState/store.js.map +1 -1
  226. package/dist/telemetry/telemetry.d.ts +42 -0
  227. package/dist/telemetry/telemetry.d.ts.map +1 -0
  228. package/dist/telemetry/telemetry.js +138 -0
  229. package/dist/telemetry/telemetry.js.map +1 -0
  230. package/dist/tui/App.d.ts +20 -0
  231. package/dist/tui/App.d.ts.map +1 -0
  232. package/dist/tui/App.js +52 -0
  233. package/dist/tui/App.js.map +1 -0
  234. package/dist/tui/chatModel.d.ts +81 -0
  235. package/dist/tui/chatModel.d.ts.map +1 -0
  236. package/dist/tui/chatModel.js +129 -0
  237. package/dist/tui/chatModel.js.map +1 -0
  238. package/dist/tui/components/AuditBoard.d.ts +10 -0
  239. package/dist/tui/components/AuditBoard.d.ts.map +1 -0
  240. package/dist/tui/components/AuditBoard.js +50 -0
  241. package/dist/tui/components/AuditBoard.js.map +1 -0
  242. package/dist/tui/components/ChatInput.d.ts +14 -0
  243. package/dist/tui/components/ChatInput.d.ts.map +1 -0
  244. package/dist/tui/components/ChatInput.js +46 -0
  245. package/dist/tui/components/ChatInput.js.map +1 -0
  246. package/dist/tui/components/ChatLog.d.ts +12 -0
  247. package/dist/tui/components/ChatLog.d.ts.map +1 -0
  248. package/dist/tui/components/ChatLog.js +47 -0
  249. package/dist/tui/components/ChatLog.js.map +1 -0
  250. package/dist/tui/components/CommandPalette.d.ts +6 -0
  251. package/dist/tui/components/CommandPalette.d.ts.map +1 -0
  252. package/dist/tui/components/CommandPalette.js +14 -0
  253. package/dist/tui/components/CommandPalette.js.map +1 -0
  254. package/dist/tui/components/ContextBar.d.ts +9 -0
  255. package/dist/tui/components/ContextBar.d.ts.map +1 -0
  256. package/dist/tui/components/ContextBar.js +18 -0
  257. package/dist/tui/components/ContextBar.js.map +1 -0
  258. package/dist/tui/components/DataTable.d.ts +6 -0
  259. package/dist/tui/components/DataTable.d.ts.map +1 -0
  260. package/dist/tui/components/DataTable.js +13 -0
  261. package/dist/tui/components/DataTable.js.map +1 -0
  262. package/dist/tui/components/HelpBar.d.ts +2 -0
  263. package/dist/tui/components/HelpBar.d.ts.map +1 -0
  264. package/dist/tui/components/HelpBar.js +8 -0
  265. package/dist/tui/components/HelpBar.js.map +1 -0
  266. package/dist/tui/components/LiveLog.d.ts +6 -0
  267. package/dist/tui/components/LiveLog.d.ts.map +1 -0
  268. package/dist/tui/components/LiveLog.js +10 -0
  269. package/dist/tui/components/LiveLog.js.map +1 -0
  270. package/dist/tui/components/LogLine.d.ts +4 -0
  271. package/dist/tui/components/LogLine.d.ts.map +1 -0
  272. package/dist/tui/components/LogLine.js +8 -0
  273. package/dist/tui/components/LogLine.js.map +1 -0
  274. package/dist/tui/components/SelectList.d.ts +6 -0
  275. package/dist/tui/components/SelectList.d.ts.map +1 -0
  276. package/dist/tui/components/SelectList.js +15 -0
  277. package/dist/tui/components/SelectList.js.map +1 -0
  278. package/dist/tui/components/StageTimeline.d.ts +7 -0
  279. package/dist/tui/components/StageTimeline.d.ts.map +1 -0
  280. package/dist/tui/components/StageTimeline.js +18 -0
  281. package/dist/tui/components/StageTimeline.js.map +1 -0
  282. package/dist/tui/components/StatusBar.d.ts +7 -0
  283. package/dist/tui/components/StatusBar.d.ts.map +1 -0
  284. package/dist/tui/components/StatusBar.js +8 -0
  285. package/dist/tui/components/StatusBar.js.map +1 -0
  286. package/dist/tui/components/SubagentTree.d.ts +10 -0
  287. package/dist/tui/components/SubagentTree.d.ts.map +1 -0
  288. package/dist/tui/components/SubagentTree.js +12 -0
  289. package/dist/tui/components/SubagentTree.js.map +1 -0
  290. package/dist/tui/components/TabBar.d.ts +5 -0
  291. package/dist/tui/components/TabBar.d.ts.map +1 -0
  292. package/dist/tui/components/TabBar.js +9 -0
  293. package/dist/tui/components/TabBar.js.map +1 -0
  294. package/dist/tui/components/WorkingIndicator.d.ts +6 -0
  295. package/dist/tui/components/WorkingIndicator.d.ts.map +1 -0
  296. package/dist/tui/components/WorkingIndicator.js +20 -0
  297. package/dist/tui/components/WorkingIndicator.js.map +1 -0
  298. package/dist/tui/hooks/useMonitor.d.ts +8 -0
  299. package/dist/tui/hooks/useMonitor.d.ts.map +1 -0
  300. package/dist/tui/hooks/useMonitor.js +42 -0
  301. package/dist/tui/hooks/useMonitor.js.map +1 -0
  302. package/dist/tui/hooks/usePipelineEvents.d.ts +6 -0
  303. package/dist/tui/hooks/usePipelineEvents.d.ts.map +1 -0
  304. package/dist/tui/hooks/usePipelineEvents.js +21 -0
  305. package/dist/tui/hooks/usePipelineEvents.js.map +1 -0
  306. package/dist/tui/hooks/useTerminalSize.d.ts +6 -0
  307. package/dist/tui/hooks/useTerminalSize.d.ts.map +1 -0
  308. package/dist/tui/hooks/useTerminalSize.js +26 -0
  309. package/dist/tui/hooks/useTerminalSize.js.map +1 -0
  310. package/dist/tui/index.d.ts +22 -0
  311. package/dist/tui/index.d.ts.map +1 -0
  312. package/dist/tui/index.js +18 -0
  313. package/dist/tui/index.js.map +1 -0
  314. package/dist/tui/inputDebug.d.ts +20 -0
  315. package/dist/tui/inputDebug.d.ts.map +1 -0
  316. package/dist/tui/inputDebug.js +42 -0
  317. package/dist/tui/inputDebug.js.map +1 -0
  318. package/dist/tui/loadingMessages.d.ts +11 -0
  319. package/dist/tui/loadingMessages.d.ts.map +1 -0
  320. package/dist/tui/loadingMessages.js +39 -0
  321. package/dist/tui/loadingMessages.js.map +1 -0
  322. package/dist/tui/logFormat.d.ts +10 -0
  323. package/dist/tui/logFormat.d.ts.map +1 -0
  324. package/dist/tui/logFormat.js +86 -0
  325. package/dist/tui/logFormat.js.map +1 -0
  326. package/dist/tui/markdown.d.ts +3 -0
  327. package/dist/tui/markdown.d.ts.map +1 -0
  328. package/dist/tui/markdown.js +33 -0
  329. package/dist/tui/markdown.js.map +1 -0
  330. package/dist/tui/monitorApi.d.ts +6 -0
  331. package/dist/tui/monitorApi.d.ts.map +1 -0
  332. package/dist/tui/monitorApi.js +35 -0
  333. package/dist/tui/monitorApi.js.map +1 -0
  334. package/dist/tui/monitorRows.d.ts +43 -0
  335. package/dist/tui/monitorRows.d.ts.map +1 -0
  336. package/dist/tui/monitorRows.js +65 -0
  337. package/dist/tui/monitorRows.js.map +1 -0
  338. package/dist/tui/panels/ChatPanel.d.ts +16 -0
  339. package/dist/tui/panels/ChatPanel.d.ts.map +1 -0
  340. package/dist/tui/panels/ChatPanel.js +305 -0
  341. package/dist/tui/panels/ChatPanel.js.map +1 -0
  342. package/dist/tui/panels/LogsPanel.d.ts +8 -0
  343. package/dist/tui/panels/LogsPanel.d.ts.map +1 -0
  344. package/dist/tui/panels/LogsPanel.js +19 -0
  345. package/dist/tui/panels/LogsPanel.js.map +1 -0
  346. package/dist/tui/panels/MonitorPanel.d.ts +8 -0
  347. package/dist/tui/panels/MonitorPanel.d.ts.map +1 -0
  348. package/dist/tui/panels/MonitorPanel.js +19 -0
  349. package/dist/tui/panels/MonitorPanel.js.map +1 -0
  350. package/dist/tui/panels/PipelinePanel.d.ts +6 -0
  351. package/dist/tui/panels/PipelinePanel.d.ts.map +1 -0
  352. package/dist/tui/panels/PipelinePanel.js +22 -0
  353. package/dist/tui/panels/PipelinePanel.js.map +1 -0
  354. package/dist/tui/pipelineEvents.d.ts +21 -0
  355. package/dist/tui/pipelineEvents.d.ts.map +1 -0
  356. package/dist/tui/pipelineEvents.js +30 -0
  357. package/dist/tui/pipelineEvents.js.map +1 -0
  358. package/dist/tui/sse.d.ts +24 -0
  359. package/dist/tui/sse.d.ts.map +1 -0
  360. package/dist/tui/sse.js +78 -0
  361. package/dist/tui/sse.js.map +1 -0
  362. package/dist/tui/subagentTree.d.ts +10 -0
  363. package/dist/tui/subagentTree.d.ts.map +1 -0
  364. package/dist/tui/subagentTree.js +30 -0
  365. package/dist/tui/subagentTree.js.map +1 -0
  366. package/dist/tui/tabs.d.ts +10 -0
  367. package/dist/tui/tabs.d.ts.map +1 -0
  368. package/dist/tui/tabs.js +26 -0
  369. package/dist/tui/tabs.js.map +1 -0
  370. package/dist/tui/theme.d.ts +29 -0
  371. package/dist/tui/theme.d.ts.map +1 -0
  372. package/dist/tui/theme.js +34 -0
  373. package/dist/tui/theme.js.map +1 -0
  374. package/package.json +13 -3
@@ -0,0 +1,148 @@
1
+ // ============================================
2
+ // OpenSwarm - Multi-Lens Reviewer Fan-out (INT-2230)
3
+ // ============================================
4
+ //
5
+ // PoC: verify one worker result through several independent review "lenses" in
6
+ // parallel, then merge into a single ReviewResult. Each lens is just a focused
7
+ // prompt injected into `taskDescription` — no extra adapter/infra needed — so the
8
+ // existing reviewer agent runs N times, each told to concentrate on one concern
9
+ // (correctness / security / regression-risk). The merge takes the WORST decision
10
+ // and unions the issues/suggestions/recommendedActions so nothing a lens caught
11
+ // is dropped. Gated + opt-in (config.review.multiLens.enabled, default false) to
12
+ // avoid multiplying usage on every task.
13
+ import { runReviewer } from './reviewer.js';
14
+ import { runPool } from '../support/concurrencyPool.js';
15
+ import { RateLimitError } from '../adapters/rateLimitError.js';
16
+ /** The three default lenses a fan-out review runs in parallel. */
17
+ export const REVIEW_LENSES = [
18
+ {
19
+ key: 'correctness',
20
+ focus: 'logic errors, unhandled edge cases, off-by-one, wrong assumptions, error handling',
21
+ },
22
+ {
23
+ key: 'security',
24
+ focus: 'injection, unsafe input, leaked secrets/keys, auth gaps, unsafe deserialization',
25
+ },
26
+ {
27
+ key: 'regression-risk',
28
+ focus: 'breaks existing behavior, changes a shared contract, missing/!updated tests, side effects on callers',
29
+ },
30
+ ];
31
+ /**
32
+ * Append a lens directive to the base task description so the reviewer
33
+ * concentrates on one concern. Other concerns are explicitly delegated to the
34
+ * sibling lenses so a single reviewer doesn't try to cover everything.
35
+ */
36
+ export function buildLensTaskDescription(base, lens) {
37
+ return `${base}\n\n## Review lens: ${lens.key}\nFocus your review specifically on: ${lens.focus}. Other concerns are secondary — another reviewer covers them.`;
38
+ }
39
+ // Merge
40
+ /** Severity ordering: reject is worst, approve is best. */
41
+ const DECISION_RANK = {
42
+ approve: 0,
43
+ revise: 1,
44
+ reject: 2,
45
+ };
46
+ /** First non-empty line of a feedback blob, trimmed (one-line lens summary). */
47
+ function firstLine(text) {
48
+ if (!text)
49
+ return '';
50
+ for (const line of text.split('\n')) {
51
+ const trimmed = line.trim();
52
+ if (trimmed)
53
+ return trimmed;
54
+ }
55
+ return '';
56
+ }
57
+ /** Stable dedup of strings by trimmed/lowercased value, keeping first original. */
58
+ function dedupStrings(values) {
59
+ const seen = new Set();
60
+ const out = [];
61
+ for (const v of values) {
62
+ const key = v.trim().toLowerCase();
63
+ if (!key || seen.has(key))
64
+ continue;
65
+ seen.add(key);
66
+ out.push(v);
67
+ }
68
+ return out;
69
+ }
70
+ /**
71
+ * Combine several lens reviews into one verdict:
72
+ * - decision = the WORST across lenses (reject > revise > approve)
73
+ * - issues / suggestions / recommendedActions = deduped union
74
+ * - feedback = one line per lens result, joined
75
+ * Empty input yields a clean approve (nothing flagged).
76
+ */
77
+ export function mergeReviewResults(results) {
78
+ if (results.length === 0) {
79
+ return { decision: 'approve', feedback: '', issues: [], suggestions: [], recommendedActions: [] };
80
+ }
81
+ let decision = 'approve';
82
+ for (const r of results) {
83
+ if (DECISION_RANK[r.decision] > DECISION_RANK[decision])
84
+ decision = r.decision;
85
+ }
86
+ const issues = dedupStrings(results.flatMap((r) => r.issues ?? []));
87
+ const suggestions = dedupStrings(results.flatMap((r) => r.suggestions ?? []));
88
+ const actionSeen = new Set();
89
+ const recommendedActions = [];
90
+ for (const action of results.flatMap((r) => r.recommendedActions ?? [])) {
91
+ const key = `${action.type}|${action.location ?? ''}|${action.title}`;
92
+ if (actionSeen.has(key))
93
+ continue;
94
+ actionSeen.add(key);
95
+ recommendedActions.push(action);
96
+ }
97
+ const feedback = results
98
+ .map((r) => firstLine(r.feedback))
99
+ .filter(Boolean)
100
+ .join('\n');
101
+ return { decision, feedback, issues, suggestions, recommendedActions };
102
+ }
103
+ // Gating
104
+ /**
105
+ * Decide whether a task is worth the extra cost of multi-lens fan-out. Triggers
106
+ * on a wide change surface, high priority (1=Urgent, 2=High), or an explicit
107
+ * `deep-review` label. Threshold defaults to 3 changed files.
108
+ */
109
+ export function shouldFanoutReview(task, opts) {
110
+ const fileThreshold = opts?.fileThreshold ?? 3;
111
+ const fileCount = task.filesChanged?.length ?? 0;
112
+ if (fileCount >= fileThreshold)
113
+ return true;
114
+ if (task.priority != null && task.priority <= 2)
115
+ return true;
116
+ return !!task.labels?.includes('deep-review');
117
+ }
118
+ // Fan-out
119
+ /**
120
+ * Run every lens in parallel and merge. Each lens calls the reviewer with a
121
+ * lens-scoped task description. A lens that fails for a non-rate-limit reason is
122
+ * skipped (its slot carries an error from the pool). A RateLimitError from ANY
123
+ * lens propagates so the pipeline's existing usage-limit handling / claude
124
+ * fallback can take over (INT-2192) instead of silently dropping a lens.
125
+ * `deps` is injectable for tests.
126
+ */
127
+ export async function runMultiLensReview(options, deps) {
128
+ const review = deps?.review ?? runReviewer;
129
+ const lenses = deps?.lenses ?? REVIEW_LENSES;
130
+ const concurrency = deps?.concurrency ?? lenses.length;
131
+ const settled = await runPool(lenses, concurrency, async (lens) => {
132
+ const result = await review({
133
+ ...options,
134
+ taskDescription: buildLensTaskDescription(options.taskDescription, lens),
135
+ });
136
+ // Tag the feedback with the lens so the merged summary reads "[correctness] …".
137
+ return { ...result, feedback: `[${lens.key}] ${firstLine(result.feedback)}` };
138
+ });
139
+ // A rate limit on any lens means the quota is exhausted — propagate so the
140
+ // pipeline pauses / falls back rather than merging a partial review.
141
+ for (const s of settled) {
142
+ if (s.error instanceof RateLimitError)
143
+ throw s.error;
144
+ }
145
+ const ok = settled.filter((s) => s.value !== undefined).map((s) => s.value);
146
+ return mergeReviewResults(ok);
147
+ }
148
+ //# sourceMappingURL=multiLensReview.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"multiLensReview.js","sourceRoot":"","sources":["../../src/agents/multiLensReview.ts"],"names":[],"mappings":"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"}
@@ -51,6 +51,8 @@ export interface PipelineConfig {
51
51
  relevantFiles: string[];
52
52
  suggestedApproach: string;
53
53
  projectStats?: string;
54
+ completionCriteria?: string[];
55
+ sufficient?: boolean;
54
56
  impactAnalysis?: import('../knowledge/types.js').ImpactAnalysis;
55
57
  registrySnapshot?: Array<{
56
58
  filePath: string;
@@ -76,7 +78,9 @@ export interface PipelineResult {
76
78
  success: boolean;
77
79
  sessionId: string;
78
80
  stages: StageResult[];
79
- finalStatus: 'approved' | 'rejected' | 'failed' | 'cancelled' | 'decomposed';
81
+ finalStatus: 'approved' | 'rejected' | 'failed' | 'cancelled' | 'decomposed' | 'rate_limited' | 'infra_error';
82
+ /** Unix timestamp (ms) when the rate-limit quota resets — set when finalStatus is 'rate_limited'. */
83
+ rateLimitResetsAt?: number;
80
84
  totalDuration: number;
81
85
  /** Total number of completed iterations */
82
86
  iterations: number;
@@ -146,6 +150,8 @@ export declare class PairPipeline extends EventEmitter {
146
150
  private matchesProfile;
147
151
  private getProfileForTask;
148
152
  private getModelForRole;
153
+ /** Reasoning effort from the matched jobProfile (heavy tasks reason harder). */
154
+ private getEffortForTask;
149
155
  /**
150
156
  * Run pipeline
151
157
  *
@@ -1 +1 @@
1
- {"version":3,"file":"pairPipeline.d.ts","sourceRoot":"","sources":["../../src/agents/pairPipeline.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"pairPipeline.d.ts","sourceRoot":"","sources":["../../src/agents/pairPipeline.ts"],"names":[],"mappings":"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"}
@@ -19,6 +19,8 @@ import * as documenterAgent from './documenter.js';
19
19
  import * as auditorAgent from './auditor.js';
20
20
  import * as skillDocumenterAgent from './skillDocumenter.js';
21
21
  import { createStuckDetector } from '../support/stuckDetector.js';
22
+ import { RateLimitError } from '../adapters/rateLimitError.js';
23
+ import { isInfraError } from '../adapters/errorClassification.js';
22
24
  /**
23
25
  * Build a consistent task prefix for logging across all pipeline stages.
24
26
  * Format: "ProjectName | INT-XXX | worktree/abc123" or "ProjectName | INT-XXX"
@@ -94,6 +96,10 @@ export class PairPipeline extends EventEmitter {
94
96
  const profile = this.getProfileForTask(task);
95
97
  return profile?.roles?.[stage] || this.config.roles?.[stage]?.model;
96
98
  }
99
+ /** Reasoning effort from the matched jobProfile (heavy tasks reason harder). */
100
+ getEffortForTask(task) {
101
+ return this.getProfileForTask(task)?.effort;
102
+ }
97
103
  // ============================================
98
104
  // Main Execution
99
105
  // ============================================
@@ -187,9 +193,23 @@ export class PairPipeline extends EventEmitter {
187
193
  // Cancellation (project disable / manual stop) is not a failure — surface it
188
194
  // as 'cancelled' so the scheduler doesn't count it failed or trigger a retry.
189
195
  const cancelled = error instanceof PipelineCancelledError || !!this.abortSignal?.aborted;
196
+ // A 429/usage-limit propagates up here from any stage (worker/reviewer/…).
197
+ // Surface it as its own finalStatus so the runner pauses until quota resets
198
+ // instead of counting a failure and spamming Linear comments. (INT-1906)
199
+ const rateLimited = !cancelled && error instanceof RateLimitError;
200
+ // An infra/CLI failure (worker/reviewer never ran: non-zero exit, auth,
201
+ // spawn, timeout) is not a task failure — surface it distinctly so the
202
+ // runner does a backoff retry instead of counting it toward STUCK. (INT-2010)
203
+ const infra = !cancelled && !rateLimited && isInfraError(error);
190
204
  if (cancelled) {
191
205
  console.log(`[${context.taskPrefix}] Pipeline cancelled`);
192
206
  }
207
+ else if (rateLimited) {
208
+ console.warn(`[${context.taskPrefix}] Pipeline rate-limited: ${error.message}`);
209
+ }
210
+ else if (infra) {
211
+ console.warn(`[${context.taskPrefix}] Pipeline infra error (not counted toward STUCK): ${error instanceof Error ? error.message : String(error)}`);
212
+ }
193
213
  else {
194
214
  console.error('[%s] Error:', context.taskPrefix, error);
195
215
  }
@@ -198,7 +218,10 @@ export class PairPipeline extends EventEmitter {
198
218
  success: false,
199
219
  sessionId: session.id,
200
220
  stages,
201
- finalStatus: cancelled ? 'cancelled' : 'failed',
221
+ finalStatus: cancelled ? 'cancelled' : rateLimited ? 'rate_limited' : infra ? 'infra_error' : 'failed',
222
+ rateLimitResetsAt: rateLimited && error.resetsAt
223
+ ? error.resetsAt * 1000
224
+ : undefined,
202
225
  totalDuration: Date.now() - startTime,
203
226
  iterations: context.currentIteration,
204
227
  workerResult: context.workerResult,
@@ -233,6 +256,8 @@ export class PairPipeline extends EventEmitter {
233
256
  relevantFiles: draft.relevantFiles,
234
257
  suggestedApproach: draft.suggestedApproach,
235
258
  projectStats: draft.projectStats,
259
+ completionCriteria: draft.completionCriteria,
260
+ sufficient: draft.sufficient,
236
261
  };
237
262
  if (draft.impactAnalysis) {
238
263
  wc.impactAnalysis = draft.impactAnalysis;
@@ -352,11 +377,15 @@ export class PairPipeline extends EventEmitter {
352
377
  this.emit('log', { line: `[verbose] Worker context: ${modCount} affected modules, ${briefCount} file briefs` });
353
378
  }
354
379
  // Self-repair feedback: objective lint/test errors (reflection trail)
355
- // are always carried forward — they are ground truth and survive a
356
- // fresh-context reset. Subjective reviewer feedback is dropped on fresh
357
- // context and only included when it was the latest revise reason.
380
+ // are always carried forward — ground truth that survives a fresh-context
381
+ // reset. The reviewer's revision prompt is ALSO preserved across fresh
382
+ // context (INT-1705): it carries the task requirement (e.g. "wire it into
383
+ // the heartbeat / add the call site"), not chat pollution — dropping it
384
+ // made the worker repeat the same partial impl forever. Fresh context
385
+ // still clears the worker's own chat history; only the reviewer's task
386
+ // signal is kept.
358
387
  const reflectionPart = buildReflectionFeedback(context.reflection);
359
- const includeReview = !useFreshContext && context.feedbackSource === 'review' && !!context.reviewResult;
388
+ const includeReview = context.feedbackSource === 'review' && !!context.reviewResult;
360
389
  const reviewPart = includeReview
361
390
  ? reviewerAgent.buildRevisionPrompt(context.reviewResult)
362
391
  : undefined;
@@ -367,9 +396,20 @@ export class PairPipeline extends EventEmitter {
367
396
  projectPath: context.projectPath,
368
397
  previousFeedback: combinedFeedback,
369
398
  timeoutMs: this.config.roles?.worker?.timeoutMs ?? 0,
370
- model: overrides?.model ?? this.config.roles?.worker?.model,
399
+ // getModelForRole gives the matched jobProfile's model precedence (config's
400
+ // light/heavy → gpt-5.5/5.4), falling back to roles.worker.model. Reading
401
+ // roles.worker.model directly here silently dropped the jobProfile model, so a
402
+ // codex worker fell through to the CLI's config.toml default (Codex-Spark). (INT-1599)
403
+ model: overrides?.model ?? this.getModelForRole('worker', context.task),
371
404
  maxTurns: this.config.roles?.worker?.maxTurns,
372
405
  adapterName: this.config.roles?.worker?.adapter,
406
+ reasoningEffort: this.getEffortForTask(context.task),
407
+ // No-edit guard (re-applied from stranded feat/v0.7.0 commit 2eea3bc):
408
+ // reasoning workers frequently end with analysis only and never call
409
+ // edit_file. Without this the guard defaults to 0 (disabled) — measured:
410
+ // codex spark AND gpt-5.5 both read 30-37× and shipped 0 edits. Push the
411
+ // worker to actually edit before concluding.
412
+ nudgeMaxOnNoEdit: 3,
373
413
  issueIdentifier: context.task.issueIdentifier || context.task.issueId,
374
414
  projectName: context.task.linearProject?.name,
375
415
  onLog,
@@ -413,24 +453,25 @@ export class PairPipeline extends EventEmitter {
413
453
  throw new Error('Worker result required for reviewer');
414
454
  }
415
455
  // Pre-check disabled - Haiku format compliance issues causing false rejections
416
- // Proceed directly to full Sonnet review for reliability
417
- // Reduce review depth when worker confidence is very high
418
- let reviewerMaxTurns = this.config.roles?.reviewer?.maxTurns;
419
- if (context.workerResult?.confidencePercent && context.workerResult.confidencePercent > 90) {
420
- const cappedTurns = Math.min(reviewerMaxTurns ?? 10, 5);
421
- console.log(`[${prefix}] High worker confidence (${context.workerResult.confidencePercent}%), limiting reviewer to ${cappedTurns} turns`);
422
- reviewerMaxTurns = cappedTurns;
423
- }
424
- console.log(`[${prefix}] Running full review (Sonnet)...`);
456
+ // Proceed directly to full review for reliability.
457
+ // NOTE: the old "high worker confidence fewer reviewer turns" shortcut was
458
+ // removed (INT-1914): worker confidence is self-reported, so a confidently
459
+ // scaffolded task was getting LESS review — exactly the wrong incentive. The
460
+ // completion-criteria hard gate is the real check now.
461
+ const reviewerMaxTurns = this.config.roles?.reviewer?.maxTurns;
462
+ console.log(`[${prefix}] Running full review...`);
425
463
  result = await reviewerAgent.runReviewer({
426
464
  taskTitle: context.task.title,
427
465
  taskDescription: context.task.description || '',
428
466
  workerResult: context.workerResult,
429
467
  projectPath: context.projectPath,
430
468
  timeoutMs: this.config.roles?.reviewer?.timeoutMs ?? 0,
431
- model: this.config.roles?.reviewer?.model,
469
+ // jobProfile model precedence (see worker stage above). (INT-1599)
470
+ model: this.getModelForRole('reviewer', context.task),
432
471
  maxTurns: reviewerMaxTurns,
433
472
  adapterName: this.config.roles?.reviewer?.adapter,
473
+ reasoningEffort: this.getEffortForTask(context.task),
474
+ completionCriteria: this.config.draftAnalysis?.completionCriteria,
434
475
  processContext: { taskId: context.task.id, stage: 'reviewer' },
435
476
  signal: this.abortSignal,
436
477
  });
@@ -777,6 +818,58 @@ export class PairPipeline extends EventEmitter {
777
818
  continue;
778
819
  }
779
820
  }
821
+ // ========== TESTER (before reviewer — INT-1703) ==========
822
+ // Run the tester first so the reviewer judges code + test outcomes
823
+ // together, and so a failing test drives INT-1679 self-repair WITHOUT
824
+ // spending a reviewer pass. Runs exactly once per iteration.
825
+ if (hasTester) {
826
+ // Skip tester if no code files changed (configurable, default true)
827
+ const skipIfNoCode = this.config.skipTesterIfNoCodeChange ?? true;
828
+ const codeExtensions = /\.(ts|tsx|js|jsx|py|rs|go|java|rb|c|cpp|h|hpp)$/;
829
+ const changedFiles = context.workerResult?.filesChanged || [];
830
+ const hasCodeChange = changedFiles.some(f => codeExtensions.test(f));
831
+ if (skipIfNoCode && !hasCodeChange) {
832
+ console.log(`[${context.taskPrefix}] Skipping tester: no code files changed (${changedFiles.length} files: ${changedFiles.join(', ') || 'none'})`);
833
+ }
834
+ else {
835
+ const testerResult = await this.runStage('tester', context);
836
+ stages.push(testerResult);
837
+ if (!testerResult.success && !this.config.continueOnTestFail) {
838
+ // Test failure is objective ground truth → record into the reflection
839
+ // trail and drive a bounded self-repair retry (INT-1679).
840
+ console.log(`[${context.taskPrefix}] Tester failed, retrying...`);
841
+ agentPair.trackFailure(context.session.id); // Track for fresh context decision
842
+ const failedTests = context.testerResult?.failedTests ?? [];
843
+ const testErrors = failedTests.length > 0
844
+ ? failedTests
845
+ : [context.testerResult?.error || `Tests failed (${context.testerResult?.testsFailed ?? 0} failing)`];
846
+ const { progressed } = recordReflection(context.reflection, {
847
+ iteration: context.currentIteration,
848
+ source: 'test',
849
+ errors: testErrors,
850
+ });
851
+ if (context.testerResult) {
852
+ context.reviewResult = {
853
+ decision: 'revise',
854
+ feedback: testerAgent.buildTestFixPrompt(context.testerResult),
855
+ issues: context.testerResult.failedTests,
856
+ suggestions: context.testerResult.suggestions,
857
+ };
858
+ }
859
+ context.feedbackSource = 'objective';
860
+ this.emit('iteration:fail', {
861
+ iteration: context.currentIteration,
862
+ stage: 'tester',
863
+ context,
864
+ });
865
+ agentPair.updateSessionStatus(context.session.id, 'revising');
866
+ if (this.shouldAbortSelfRepair(context, progressed, 'test')) {
867
+ return { success: false };
868
+ }
869
+ continue;
870
+ }
871
+ } // end else (has code change)
872
+ }
780
873
  // ========== REVIEWER ==========
781
874
  if (hasReviewer) {
782
875
  agentPair.updateSessionStatus(context.session.id, 'reviewing');
@@ -825,58 +918,9 @@ export class PairPipeline extends EventEmitter {
825
918
  agentPair.updateSessionStatus(context.session.id, 'revising');
826
919
  continue;
827
920
  }
828
- // approve → proceed to Tester
921
+ // approve → done (tester already ran before the reviewer — INT-1703)
829
922
  agentPair.resetFailureStreak(context.session.id); // Reset on approval
830
923
  }
831
- // ========== TESTER ==========
832
- if (hasTester) {
833
- // Skip tester if no code files changed (configurable, default true)
834
- const skipIfNoCode = this.config.skipTesterIfNoCodeChange ?? true;
835
- const codeExtensions = /\.(ts|tsx|js|jsx|py|rs|go|java|rb|c|cpp|h|hpp)$/;
836
- const changedFiles = context.workerResult?.filesChanged || [];
837
- const hasCodeChange = changedFiles.some(f => codeExtensions.test(f));
838
- if (skipIfNoCode && !hasCodeChange) {
839
- console.log(`[${context.taskPrefix}] Skipping tester: no code files changed (${changedFiles.length} files: ${changedFiles.join(', ') || 'none'})`);
840
- }
841
- else {
842
- const testerResult = await this.runStage('tester', context);
843
- stages.push(testerResult);
844
- if (!testerResult.success && !this.config.continueOnTestFail) {
845
- // Test failure is objective ground truth → record into the reflection
846
- // trail and drive a bounded self-repair retry.
847
- console.log(`[${context.taskPrefix}] Tester failed, retrying...`);
848
- agentPair.trackFailure(context.session.id); // Track for fresh context decision
849
- const failedTests = context.testerResult?.failedTests ?? [];
850
- const testErrors = failedTests.length > 0
851
- ? failedTests
852
- : [context.testerResult?.error || `Tests failed (${context.testerResult?.testsFailed ?? 0} failing)`];
853
- const { progressed } = recordReflection(context.reflection, {
854
- iteration: context.currentIteration,
855
- source: 'test',
856
- errors: testErrors,
857
- });
858
- if (context.testerResult) {
859
- context.reviewResult = {
860
- decision: 'revise',
861
- feedback: testerAgent.buildTestFixPrompt(context.testerResult),
862
- issues: context.testerResult.failedTests,
863
- suggestions: context.testerResult.suggestions,
864
- };
865
- }
866
- context.feedbackSource = 'objective';
867
- this.emit('iteration:fail', {
868
- iteration: context.currentIteration,
869
- stage: 'tester',
870
- context,
871
- });
872
- agentPair.updateSessionStatus(context.session.id, 'revising');
873
- if (this.shouldAbortSelfRepair(context, progressed, 'test')) {
874
- return { success: false };
875
- }
876
- continue;
877
- }
878
- } // end else (has code change)
879
- }
880
924
  // ========== ALL PASSED ==========
881
925
  console.log(`[${context.taskPrefix}] Iteration ${context.currentIteration} completed successfully`);
882
926
  this.emit('iteration:complete', {