@cjhyy/code-shell 0.1.0-alpha.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.
Files changed (441) hide show
  1. package/CHANGELOG.md +109 -0
  2. package/LICENSE +21 -0
  3. package/README.md +177 -0
  4. package/dist/agent/coordinator.d.ts +49 -0
  5. package/dist/anthropic-NENYS535.js +9 -0
  6. package/dist/anthropic-XMTTVNSH.cjs +9 -0
  7. package/dist/arena/arena.d.ts +43 -0
  8. package/dist/arena/context/context-tools.d.ts +16 -0
  9. package/dist/arena/detect-mode.d.ts +20 -0
  10. package/dist/arena/digest-builder.d.ts +25 -0
  11. package/dist/arena/index.cjs +103 -0
  12. package/dist/arena/index.d.ts +29 -0
  13. package/dist/arena/index.js +103 -0
  14. package/dist/arena/iterate/convergence.d.ts +25 -0
  15. package/dist/arena/iterate/formats/index.d.ts +22 -0
  16. package/dist/arena/iterate/index.d.ts +11 -0
  17. package/dist/arena/iterate/iterative-arena.d.ts +23 -0
  18. package/dist/arena/iterate/parse.d.ts +42 -0
  19. package/dist/arena/iterate/phases/argue.d.ts +22 -0
  20. package/dist/arena/iterate/phases/revise.d.ts +16 -0
  21. package/dist/arena/iterate/phases/tournament.d.ts +34 -0
  22. package/dist/arena/iterate/tools/web-tools.d.ts +13 -0
  23. package/dist/arena/iterate/types.d.ts +152 -0
  24. package/dist/arena/ledger.d.ts +47 -0
  25. package/dist/arena/lenses/architecture.d.ts +5 -0
  26. package/dist/arena/lenses/engineering.d.ts +5 -0
  27. package/dist/arena/lenses/general.d.ts +5 -0
  28. package/dist/arena/lenses/index.d.ts +16 -0
  29. package/dist/arena/lenses/product.d.ts +5 -0
  30. package/dist/arena/model-presets.d.ts +14 -0
  31. package/dist/arena/phases/adjudication.d.ts +24 -0
  32. package/dist/arena/phases/build-consensus.d.ts +29 -0
  33. package/dist/arena/phases/claim-registry.d.ts +26 -0
  34. package/dist/arena/phases/cross-review.d.ts +45 -0
  35. package/dist/arena/phases/debate-rounds.d.ts +27 -0
  36. package/dist/arena/phases/participant-research.d.ts +38 -0
  37. package/dist/arena/phases/planning-detail-expansion.d.ts +38 -0
  38. package/dist/arena/planner.d.ts +27 -0
  39. package/dist/arena/providers/docs.d.ts +6 -0
  40. package/dist/arena/providers/git.d.ts +8 -0
  41. package/dist/arena/providers/index.d.ts +16 -0
  42. package/dist/arena/providers/none.d.ts +7 -0
  43. package/dist/arena/providers/repo.d.ts +6 -0
  44. package/dist/arena/render/session.d.ts +17 -0
  45. package/dist/arena/render/terminal.d.ts +33 -0
  46. package/dist/arena/strategies/discussion.d.ts +25 -0
  47. package/dist/arena/strategies/index.d.ts +15 -0
  48. package/dist/arena/strategies/language-wrapper.d.ts +17 -0
  49. package/dist/arena/strategies/lens-wrapper.d.ts +16 -0
  50. package/dist/arena/strategies/planning.d.ts +30 -0
  51. package/dist/arena/strategies/review.d.ts +26 -0
  52. package/dist/arena/strategies/utils.d.ts +34 -0
  53. package/dist/arena/tools/selector.d.ts +17 -0
  54. package/dist/arena/transitions.d.ts +48 -0
  55. package/dist/arena/types.d.ts +499 -0
  56. package/dist/arena-46QQ6BZQ.js +261 -0
  57. package/dist/arena-HZZZ2GJH.cjs +261 -0
  58. package/dist/bootstrap/setup.d.ts +14 -0
  59. package/dist/bootstrap/state.d.ts +160 -0
  60. package/dist/bridge-4ZRXVWBN.js +98 -0
  61. package/dist/bridge-W476QDFH.cjs +98 -0
  62. package/dist/chunk-3EAEC566.cjs +136 -0
  63. package/dist/chunk-3EUDE77E.cjs +1252 -0
  64. package/dist/chunk-3QR52LL5.cjs +105 -0
  65. package/dist/chunk-4PKZPFCD.js +136 -0
  66. package/dist/chunk-4RRUP4MM.js +86 -0
  67. package/dist/chunk-4SFPFHMG.js +132 -0
  68. package/dist/chunk-5LHVI777.cjs +246 -0
  69. package/dist/chunk-6JOOLG6F.js +104 -0
  70. package/dist/chunk-6ZIROYXX.js +207 -0
  71. package/dist/chunk-7RMAR2Y3.js +6511 -0
  72. package/dist/chunk-BE6IPRDM.js +224 -0
  73. package/dist/chunk-BHGIJ2DJ.js +41 -0
  74. package/dist/chunk-BMH65OVB.cjs +224 -0
  75. package/dist/chunk-C7JBCO5V.js +80 -0
  76. package/dist/chunk-CSO5EOEP.cjs +132 -0
  77. package/dist/chunk-DI7RDLOS.js +47 -0
  78. package/dist/chunk-DICG4AB7.cjs +73 -0
  79. package/dist/chunk-EL2RL5DG.cjs +101 -0
  80. package/dist/chunk-FGZGCFJX.cjs +207 -0
  81. package/dist/chunk-FUOKLKR2.js +101 -0
  82. package/dist/chunk-FVP7XJGS.cjs +4577 -0
  83. package/dist/chunk-HD7MT5XU.cjs +86 -0
  84. package/dist/chunk-IJSHQGMP.cjs +45 -0
  85. package/dist/chunk-IMMTBZ33.cjs +63 -0
  86. package/dist/chunk-J5XW6UYL.js +291 -0
  87. package/dist/chunk-JT2WSQSR.cjs +335 -0
  88. package/dist/chunk-KO2FPF7G.js +93 -0
  89. package/dist/chunk-LRAY5IYC.cjs +291 -0
  90. package/dist/chunk-NG73UR3L.cjs +285 -0
  91. package/dist/chunk-NZ4DQ72D.cjs +664 -0
  92. package/dist/chunk-O6F2EF2Z.js +73 -0
  93. package/dist/chunk-OG4MIQJ6.js +335 -0
  94. package/dist/chunk-QHDYFC5U.cjs +6511 -0
  95. package/dist/chunk-R32DJSJE.cjs +41 -0
  96. package/dist/chunk-S74VVJBF.js +285 -0
  97. package/dist/chunk-SK62UVS6.js +105 -0
  98. package/dist/chunk-SQZHPD3S.js +4577 -0
  99. package/dist/chunk-UK2SU23S.cjs +93 -0
  100. package/dist/chunk-VKGNCYRL.js +258 -0
  101. package/dist/chunk-WFQF3RT4.cjs +104 -0
  102. package/dist/chunk-WHRTARDJ.cjs +258 -0
  103. package/dist/chunk-WRZJUQ5Z.js +664 -0
  104. package/dist/chunk-X4HAERTQ.js +63 -0
  105. package/dist/chunk-XHC2JMEC.cjs +80 -0
  106. package/dist/chunk-YZ25SSWJ.js +222 -0
  107. package/dist/chunk-ZJV3YSY3.cjs +222 -0
  108. package/dist/chunk-ZRSSGYA5.js +246 -0
  109. package/dist/chunk-ZXYDDJEJ.js +1252 -0
  110. package/dist/cli/commands/arena.d.ts +29 -0
  111. package/dist/cli/commands/builtin/advanced-commands.d.ts +5 -0
  112. package/dist/cli/commands/builtin/core-commands.d.ts +5 -0
  113. package/dist/cli/commands/builtin/extra-commands.d.ts +6 -0
  114. package/dist/cli/commands/builtin/git-commands.d.ts +5 -0
  115. package/dist/cli/commands/builtin/more-commands.d.ts +7 -0
  116. package/dist/cli/commands/builtin/permissions-command.d.ts +5 -0
  117. package/dist/cli/commands/builtin/utility-commands.d.ts +5 -0
  118. package/dist/cli/commands/registry.d.ts +64 -0
  119. package/dist/cli/commands/repl.d.ts +21 -0
  120. package/dist/cli/commands/run.d.ts +21 -0
  121. package/dist/cli/commands/runs.d.ts +14 -0
  122. package/dist/cli/cost-tracker.d.ts +57 -0
  123. package/dist/cli/exit.d.ts +12 -0
  124. package/dist/cli/input/ndjson-reader.d.ts +31 -0
  125. package/dist/cli/input-compiler.d.ts +5 -0
  126. package/dist/cli/main.cjs +19674 -0
  127. package/dist/cli/main.d.ts +5 -0
  128. package/dist/cli/main.js +19674 -0
  129. package/dist/cli/onboarding.d.ts +26 -0
  130. package/dist/cli/output/renderer.d.ts +28 -0
  131. package/dist/cli/output/terminal-ui.d.ts +50 -0
  132. package/dist/cli/updater.d.ts +10 -0
  133. package/dist/compaction-44I55TLI.cjs +32 -0
  134. package/dist/compaction-CCHWA4G6.js +32 -0
  135. package/dist/context/compaction.d.ts +83 -0
  136. package/dist/context/manager.d.ts +99 -0
  137. package/dist/context/token-counter.d.ts +27 -0
  138. package/dist/coordinator-5HY7ALO2.js +7 -0
  139. package/dist/coordinator-INDLPVMF.cjs +7 -0
  140. package/dist/cost-tracker-IWYAUPXH.js +9 -0
  141. package/dist/cost-tracker-JXTJQQWE.cjs +9 -0
  142. package/dist/cron/scheduler.d.ts +34 -0
  143. package/dist/devtools-KIY3LWQJ.js +6 -0
  144. package/dist/devtools-LRP47DDV.cjs +6 -0
  145. package/dist/engine/cost-store.d.ts +22 -0
  146. package/dist/engine/engine.d.ts +101 -0
  147. package/dist/engine/model-facade.d.ts +24 -0
  148. package/dist/engine/query.d.ts +50 -0
  149. package/dist/engine/streaming-tool-queue.d.ts +34 -0
  150. package/dist/engine/token-budget.d.ts +22 -0
  151. package/dist/engine/tool-summary.d.ts +13 -0
  152. package/dist/engine/turn-loop.d.ts +62 -0
  153. package/dist/engine/turn-state.d.ts +14 -0
  154. package/dist/exceptions.d.ts +44 -0
  155. package/dist/file-history-HZWO2WQ5.js +7 -0
  156. package/dist/file-history-UQQILIY7.cjs +7 -0
  157. package/dist/git/utils.d.ts +35 -0
  158. package/dist/git/worktree.d.ts +36 -0
  159. package/dist/hooks/events.d.ts +35 -0
  160. package/dist/hooks/registry.d.ts +15 -0
  161. package/dist/index.cjs +336 -0
  162. package/dist/index.d.ts +64 -0
  163. package/dist/index.js +336 -0
  164. package/dist/ink/Ansi.d.ts +10 -0
  165. package/dist/ink/bidi.d.ts +15 -0
  166. package/dist/ink/clearTerminal.d.ts +13 -0
  167. package/dist/ink/colorize.d.ts +16 -0
  168. package/dist/ink/components/AlternateScreen.d.ts +21 -0
  169. package/dist/ink/components/App.d.ts +70 -0
  170. package/dist/ink/components/AppContext.d.ts +11 -0
  171. package/dist/ink/components/Box.d.ts +49 -0
  172. package/dist/ink/components/Button.d.ts +36 -0
  173. package/dist/ink/components/ClockContext.d.ts +9 -0
  174. package/dist/ink/components/CursorDeclarationContext.d.ts +22 -0
  175. package/dist/ink/components/ErrorOverview.d.ts +5 -0
  176. package/dist/ink/components/Link.d.ts +7 -0
  177. package/dist/ink/components/Newline.d.ts +12 -0
  178. package/dist/ink/components/NoSelect.d.ts +19 -0
  179. package/dist/ink/components/RawAnsi.d.ts +16 -0
  180. package/dist/ink/components/ScrollBox.d.ts +78 -0
  181. package/dist/ink/components/Spacer.d.ts +5 -0
  182. package/dist/ink/components/StdinContext.d.ts +27 -0
  183. package/dist/ink/components/TerminalFocusContext.d.ts +10 -0
  184. package/dist/ink/components/TerminalSizeContext.d.ts +5 -0
  185. package/dist/ink/components/Text.d.ts +55 -0
  186. package/dist/ink/constants.d.ts +1 -0
  187. package/dist/ink/cursor.d.ts +8 -0
  188. package/dist/ink/devtools.d.ts +5 -0
  189. package/dist/ink/dom.d.ts +76 -0
  190. package/dist/ink/events/click-event.d.ts +31 -0
  191. package/dist/ink/events/dispatcher.d.ts +40 -0
  192. package/dist/ink/events/emitter.d.ts +5 -0
  193. package/dist/ink/events/event-handlers.d.ts +46 -0
  194. package/dist/ink/events/event.d.ts +5 -0
  195. package/dist/ink/events/focus-event.d.ts +13 -0
  196. package/dist/ink/events/input-event.d.ts +30 -0
  197. package/dist/ink/events/keyboard-event.d.ts +19 -0
  198. package/dist/ink/events/paste-event.d.ts +8 -0
  199. package/dist/ink/events/resize-event.d.ts +9 -0
  200. package/dist/ink/events/terminal-event.d.ts +54 -0
  201. package/dist/ink/events/terminal-focus-event.d.ts +13 -0
  202. package/dist/ink/focus.d.ts +43 -0
  203. package/dist/ink/frame.d.ts +94 -0
  204. package/dist/ink/get-max-width.d.ts +17 -0
  205. package/dist/ink/hit-test.d.ts +33 -0
  206. package/dist/ink/hooks/use-animation-frame.d.ts +26 -0
  207. package/dist/ink/hooks/use-app.d.ts +5 -0
  208. package/dist/ink/hooks/use-declared-cursor.d.ts +26 -0
  209. package/dist/ink/hooks/use-input.d.ts +37 -0
  210. package/dist/ink/hooks/use-interval.d.ts +18 -0
  211. package/dist/ink/hooks/use-search-highlight.d.ts +30 -0
  212. package/dist/ink/hooks/use-selection.d.ts +39 -0
  213. package/dist/ink/hooks/use-stdin.d.ts +5 -0
  214. package/dist/ink/hooks/use-tab-status.d.ts +13 -0
  215. package/dist/ink/hooks/use-terminal-focus.d.ts +10 -0
  216. package/dist/ink/hooks/use-terminal-title.d.ts +12 -0
  217. package/dist/ink/hooks/use-terminal-viewport.d.ts +29 -0
  218. package/dist/ink/index.d.ts +20 -0
  219. package/dist/ink/ink.d.ts +369 -0
  220. package/dist/ink/instances.d.ts +3 -0
  221. package/dist/ink/layout/engine.d.ts +2 -0
  222. package/dist/ink/layout/geometry.d.ts +30 -0
  223. package/dist/ink/layout/node.d.ts +125 -0
  224. package/dist/ink/layout/yoga.d.ts +56 -0
  225. package/dist/ink/line-width-cache.d.ts +1 -0
  226. package/dist/ink/log-update.d.ts +17 -0
  227. package/dist/ink/measure-element.d.ts +16 -0
  228. package/dist/ink/measure-text.d.ts +6 -0
  229. package/dist/ink/node-cache.d.ts +20 -0
  230. package/dist/ink/optimizer.d.ts +15 -0
  231. package/dist/ink/output.d.ts +119 -0
  232. package/dist/ink/parse-keypress.d.ts +111 -0
  233. package/dist/ink/reconciler.d.ts +11 -0
  234. package/dist/ink/render-border.d.ts +24 -0
  235. package/dist/ink/render-node-to-output.d.ts +45 -0
  236. package/dist/ink/render-to-screen.d.ts +46 -0
  237. package/dist/ink/renderer.d.ts +14 -0
  238. package/dist/ink/root.d.ts +74 -0
  239. package/dist/ink/screen.d.ts +269 -0
  240. package/dist/ink/searchHighlight.d.ts +20 -0
  241. package/dist/ink/selection.d.ts +229 -0
  242. package/dist/ink/squash-text-nodes.d.ts +22 -0
  243. package/dist/ink/stringWidth.d.ts +1 -0
  244. package/dist/ink/styles.d.ts +306 -0
  245. package/dist/ink/supports-hyperlinks.d.ts +13 -0
  246. package/dist/ink/tabstops.d.ts +1 -0
  247. package/dist/ink/terminal-focus-state.d.ts +6 -0
  248. package/dist/ink/terminal-querier.d.ts +129 -0
  249. package/dist/ink/terminal.d.ts +46 -0
  250. package/dist/ink/termio/ansi.d.ts +65 -0
  251. package/dist/ink/termio/csi.d.ts +165 -0
  252. package/dist/ink/termio/dec.d.ts +37 -0
  253. package/dist/ink/termio/esc.d.ts +12 -0
  254. package/dist/ink/termio/osc.d.ts +173 -0
  255. package/dist/ink/termio/parser.d.ts +35 -0
  256. package/dist/ink/termio/sgr.d.ts +8 -0
  257. package/dist/ink/termio/tokenize.d.ts +45 -0
  258. package/dist/ink/termio/types.d.ts +190 -0
  259. package/dist/ink/termio.d.ts +24 -0
  260. package/dist/ink/useTerminalNotification.d.ts +28 -0
  261. package/dist/ink/warn.d.ts +1 -0
  262. package/dist/ink/widest-line.d.ts +1 -0
  263. package/dist/ink/wrap-text.d.ts +2 -0
  264. package/dist/ink/wrapAnsi.d.ts +7 -0
  265. package/dist/llm/client-base.d.ts +22 -0
  266. package/dist/llm/client-factory.d.ts +10 -0
  267. package/dist/llm/model-pool.d.ts +60 -0
  268. package/dist/llm/providers/anthropic.d.ts +19 -0
  269. package/dist/llm/providers/openai.d.ts +19 -0
  270. package/dist/llm/types.d.ts +21 -0
  271. package/dist/loader-DXFSUB4R.cjs +91 -0
  272. package/dist/loader-J5UID6CV.js +91 -0
  273. package/dist/logging/logger.d.ts +19 -0
  274. package/dist/lsp/client.d.ts +41 -0
  275. package/dist/lsp/manager.d.ts +40 -0
  276. package/dist/lsp/servers.d.ts +16 -0
  277. package/dist/manager-ETWDOCHN.cjs +9 -0
  278. package/dist/manager-HGMQNEJB.cjs +11 -0
  279. package/dist/manager-HUAQOORS.js +9 -0
  280. package/dist/manager-VJIZ2CQC.js +11 -0
  281. package/dist/mcp-manager-G4G2QASE.cjs +8 -0
  282. package/dist/mcp-manager-OKXHHWYR.js +8 -0
  283. package/dist/memory-AP747G5H.js +7 -0
  284. package/dist/memory-BH3BYUN5.cjs +7 -0
  285. package/dist/native-ts/yoga-layout/enums.d.ts +117 -0
  286. package/dist/native-ts/yoga-layout/index.d.ts +270 -0
  287. package/dist/onboarding-6WEPV7C2.js +11 -0
  288. package/dist/onboarding-QM5DY2TU.cjs +11 -0
  289. package/dist/openai-5HQGBL4L.js +9 -0
  290. package/dist/openai-656VWUQW.cjs +9 -0
  291. package/dist/plugins/loader.d.ts +72 -0
  292. package/dist/plugins/types.d.ts +4 -0
  293. package/dist/preset/index.d.ts +60 -0
  294. package/dist/product/define.d.ts +60 -0
  295. package/dist/product/index.cjs +23 -0
  296. package/dist/product/index.d.ts +5 -0
  297. package/dist/product/index.js +23 -0
  298. package/dist/product/types.d.ts +116 -0
  299. package/dist/prompt/composer.d.ts +42 -0
  300. package/dist/prompt/instruction-scanner.d.ts +54 -0
  301. package/dist/prompt/section-cache.d.ts +15 -0
  302. package/dist/prompt/section-loader.d.ts +26 -0
  303. package/dist/protocol/client.d.ts +64 -0
  304. package/dist/protocol/index.d.ts +4 -0
  305. package/dist/protocol/server.d.ts +49 -0
  306. package/dist/protocol/transport.d.ts +36 -0
  307. package/dist/protocol/types.d.ts +150 -0
  308. package/dist/react-compiler-runtime-shim.d.ts +1 -0
  309. package/dist/remote/bridge.d.ts +37 -0
  310. package/dist/run/ArtifactTracker.d.ts +38 -0
  311. package/dist/run/CheckpointWriter.d.ts +53 -0
  312. package/dist/run/EngineRunner.d.ts +70 -0
  313. package/dist/run/Evaluator.d.ts +56 -0
  314. package/dist/run/FileRunStore.d.ts +39 -0
  315. package/dist/run/Heartbeat.d.ts +54 -0
  316. package/dist/run/RunApprovalBackend.d.ts +53 -0
  317. package/dist/run/RunLock.d.ts +40 -0
  318. package/dist/run/RunManager.d.ts +76 -0
  319. package/dist/run/RunQueue.d.ts +27 -0
  320. package/dist/run/RunStore.d.ts +25 -0
  321. package/dist/run/factory.d.ts +57 -0
  322. package/dist/run/index.cjs +50 -0
  323. package/dist/run/index.d.ts +17 -0
  324. package/dist/run/index.js +50 -0
  325. package/dist/run/types.d.ts +136 -0
  326. package/dist/services/analytics.d.ts +29 -0
  327. package/dist/services/auto-dream.d.ts +35 -0
  328. package/dist/services/compact.d.ts +56 -0
  329. package/dist/services/diagnostics.d.ts +41 -0
  330. package/dist/services/extract-memories.d.ts +27 -0
  331. package/dist/services/index.d.ts +11 -0
  332. package/dist/services/notifier.d.ts +25 -0
  333. package/dist/services/oauth.d.ts +27 -0
  334. package/dist/services/session-memory.d.ts +37 -0
  335. package/dist/session/file-history.d.ts +41 -0
  336. package/dist/session/memory.d.ts +45 -0
  337. package/dist/session/session-manager.d.ts +23 -0
  338. package/dist/session/transcript.d.ts +39 -0
  339. package/dist/session-manager-JIIBCFTC.js +8 -0
  340. package/dist/session-manager-UQKB564H.cjs +8 -0
  341. package/dist/settings/manager.d.ts +27 -0
  342. package/dist/settings/schema.d.ts +676 -0
  343. package/dist/skills/index.d.ts +7 -0
  344. package/dist/skills/matcher.d.ts +21 -0
  345. package/dist/skills/scanner.d.ts +30 -0
  346. package/dist/skills-63RBYQRX.js +13 -0
  347. package/dist/skills-V3BPLW3D.cjs +13 -0
  348. package/dist/token-counter-CHAXW5O7.cjs +13 -0
  349. package/dist/token-counter-DSOZGZ5Q.js +13 -0
  350. package/dist/tool-summary-5P2GKRA4.cjs +31 -0
  351. package/dist/tool-summary-J2ICNMWP.js +31 -0
  352. package/dist/tool-system/builtin/agent.d.ts +35 -0
  353. package/dist/tool-system/builtin/arena.d.ts +18 -0
  354. package/dist/tool-system/builtin/ask-user.d.ts +12 -0
  355. package/dist/tool-system/builtin/bash.d.ts +6 -0
  356. package/dist/tool-system/builtin/brief.d.ts +6 -0
  357. package/dist/tool-system/builtin/config.d.ts +6 -0
  358. package/dist/tool-system/builtin/cron.d.ts +10 -0
  359. package/dist/tool-system/builtin/edit.d.ts +6 -0
  360. package/dist/tool-system/builtin/file-cache.d.ts +11 -0
  361. package/dist/tool-system/builtin/glob.d.ts +6 -0
  362. package/dist/tool-system/builtin/grep.d.ts +6 -0
  363. package/dist/tool-system/builtin/index.d.ts +10 -0
  364. package/dist/tool-system/builtin/lsp.d.ts +6 -0
  365. package/dist/tool-system/builtin/mcp-tools.d.ts +10 -0
  366. package/dist/tool-system/builtin/notebook-edit.d.ts +6 -0
  367. package/dist/tool-system/builtin/plan.d.ts +18 -0
  368. package/dist/tool-system/builtin/powershell.d.ts +6 -0
  369. package/dist/tool-system/builtin/read.d.ts +6 -0
  370. package/dist/tool-system/builtin/remote-trigger.d.ts +6 -0
  371. package/dist/tool-system/builtin/repl.d.ts +6 -0
  372. package/dist/tool-system/builtin/send-message.d.ts +6 -0
  373. package/dist/tool-system/builtin/skill.d.ts +6 -0
  374. package/dist/tool-system/builtin/sleep.d.ts +6 -0
  375. package/dist/tool-system/builtin/task.d.ts +51 -0
  376. package/dist/tool-system/builtin/tool-search.d.ts +12 -0
  377. package/dist/tool-system/builtin/web-fetch.d.ts +6 -0
  378. package/dist/tool-system/builtin/web-search.d.ts +6 -0
  379. package/dist/tool-system/builtin/worktree.d.ts +10 -0
  380. package/dist/tool-system/builtin/write.d.ts +6 -0
  381. package/dist/tool-system/executor.d.ts +25 -0
  382. package/dist/tool-system/mcp-manager.d.ts +50 -0
  383. package/dist/tool-system/permission.d.ts +69 -0
  384. package/dist/tool-system/registry.d.ts +24 -0
  385. package/dist/tool-system/validation.d.ts +5 -0
  386. package/dist/types.d.ts +260 -0
  387. package/dist/ui/App.d.ts +14 -0
  388. package/dist/ui/components/AgentBlock.d.ts +32 -0
  389. package/dist/ui/components/BabyHand.d.ts +1 -0
  390. package/dist/ui/components/Banner.d.ts +8 -0
  391. package/dist/ui/components/CodeBlock.d.ts +7 -0
  392. package/dist/ui/components/CommandInput.d.ts +13 -0
  393. package/dist/ui/components/ContextUsageBar.d.ts +7 -0
  394. package/dist/ui/components/DiffView.d.ts +6 -0
  395. package/dist/ui/components/DogLogo.d.ts +1 -0
  396. package/dist/ui/components/FullscreenLayout.d.ts +51 -0
  397. package/dist/ui/components/KunHead.d.ts +1 -0
  398. package/dist/ui/components/KunLogo.d.ts +1 -0
  399. package/dist/ui/components/MessageContent.d.ts +22 -0
  400. package/dist/ui/components/PermissionDialog.d.ts +8 -0
  401. package/dist/ui/components/PermissionPrompt.d.ts +8 -0
  402. package/dist/ui/components/ScrollView.d.ts +34 -0
  403. package/dist/ui/components/Spinner.d.ts +8 -0
  404. package/dist/ui/components/SpinnerWithVerb.d.ts +13 -0
  405. package/dist/ui/components/StatusLine.d.ts +22 -0
  406. package/dist/ui/components/StructuredDiff.d.ts +8 -0
  407. package/dist/ui/components/TaskList.d.ts +6 -0
  408. package/dist/ui/components/TextInput.d.ts +9 -0
  409. package/dist/ui/components/ThemedBox.d.ts +19 -0
  410. package/dist/ui/components/ThemedText.d.ts +26 -0
  411. package/dist/ui/components/ToolCall.d.ts +21 -0
  412. package/dist/ui/components/VirtualMessageList.d.ts +24 -0
  413. package/dist/ui/hooks/useCostSummary.d.ts +1 -0
  414. package/dist/ui/index.d.ts +12 -0
  415. package/dist/ui/input-history.d.ts +61 -0
  416. package/dist/ui/store.d.ts +82 -0
  417. package/dist/ui/terminal-renderer.d.ts +45 -0
  418. package/dist/ui/theme.d.ts +36 -0
  419. package/dist/ui/vim-mode.d.ts +25 -0
  420. package/dist/updater-AVD4LKTQ.js +183 -0
  421. package/dist/updater-URVNPDPW.cjs +183 -0
  422. package/dist/utils/debug.d.ts +57 -0
  423. package/dist/utils/earlyInput.d.ts +43 -0
  424. package/dist/utils/env.d.ts +24 -0
  425. package/dist/utils/envUtils.d.ts +51 -0
  426. package/dist/utils/execFileNoThrow.d.ts +39 -0
  427. package/dist/utils/format.d.ts +44 -0
  428. package/dist/utils/fullscreen.d.ts +47 -0
  429. package/dist/utils/intl.d.ts +22 -0
  430. package/dist/utils/lockfile.d.ts +15 -0
  431. package/dist/utils/log.d.ts +56 -0
  432. package/dist/utils/semver.d.ts +5 -0
  433. package/dist/utils/sliceAnsi.d.ts +12 -0
  434. package/dist/utils/systemTheme.d.ts +40 -0
  435. package/dist/utils/theme.d.ts +91 -0
  436. package/dist/utils/toolDisplay.d.ts +31 -0
  437. package/dist/utils/truncate.d.ts +40 -0
  438. package/dist/voice/index.d.ts +35 -0
  439. package/dist/voice-KTZ7PAGO.js +80 -0
  440. package/dist/voice-KZE25GKB.cjs +80 -0
  441. package/package.json +130 -0
@@ -0,0 +1,4577 @@
1
+ import {
2
+ logger
3
+ } from "./chunk-X4HAERTQ.js";
4
+ import {
5
+ LLMError
6
+ } from "./chunk-FUOKLKR2.js";
7
+ import {
8
+ init_esm_shims
9
+ } from "./chunk-DI7RDLOS.js";
10
+
11
+ // src/llm/client-factory.ts
12
+ init_esm_shims();
13
+ var PROVIDER_REGISTRY = /* @__PURE__ */ new Map();
14
+ function registerProvider(name, cls) {
15
+ PROVIDER_REGISTRY.set(name, cls);
16
+ }
17
+ async function createLLMClient(config) {
18
+ let Cls = PROVIDER_REGISTRY.get(config.provider);
19
+ if (!Cls) {
20
+ if (config.provider === "anthropic") {
21
+ const { AnthropicClient } = await import("./anthropic-NENYS535.js");
22
+ registerProvider("anthropic", AnthropicClient);
23
+ Cls = AnthropicClient;
24
+ } else if (config.provider === "openai") {
25
+ const { OpenAIClient } = await import("./openai-5HQGBL4L.js");
26
+ registerProvider("openai", OpenAIClient);
27
+ Cls = OpenAIClient;
28
+ }
29
+ }
30
+ if (!Cls) {
31
+ throw new LLMError(
32
+ `Unknown LLM provider: ${config.provider}. Available: ${[...PROVIDER_REGISTRY.keys()].join(", ")}`
33
+ );
34
+ }
35
+ return new Cls(config);
36
+ }
37
+
38
+ // src/arena/types.ts
39
+ init_esm_shims();
40
+ var ARENA_MODE_DEFAULTS = {
41
+ review: { maxDiscussionRounds: 3, convergenceThreshold: 200 },
42
+ discussion: { maxDiscussionRounds: 4, convergenceThreshold: 300 },
43
+ planning: { maxDiscussionRounds: 5, convergenceThreshold: 400 }
44
+ };
45
+ var DEFAULT_EXECUTION_LIMITS = {
46
+ maxClaimsForReview: 12,
47
+ maxContestedClaimsForDebate: 5,
48
+ maxRequestedChecksPerClaimPerRound: 2,
49
+ maxReviewersPerClaim: 2,
50
+ maxRoadmapPhases: 6,
51
+ maxExpandedPhasesPerRun: 6
52
+ };
53
+ function isStrategyPlanning(s) {
54
+ return typeof s.detailExpansionUserPrompt === "function";
55
+ }
56
+ function isStrategyV2(s) {
57
+ return typeof s.verificationReviewUserPrompt === "function";
58
+ }
59
+
60
+ // src/arena/strategies/review.ts
61
+ init_esm_shims();
62
+
63
+ // src/arena/strategies/utils.ts
64
+ init_esm_shims();
65
+ function asString(v) {
66
+ if (typeof v === "string") return v;
67
+ if (v == null) return "";
68
+ if (typeof v === "number" || typeof v === "boolean") return String(v);
69
+ return "";
70
+ }
71
+ function sanitizeForPrompt(text) {
72
+ if (!text) return "";
73
+ return text.replace(/<\/?(?:system|assistant|user|system-reminder)[^>]*>/gi, "").replace(/^(?:IGNORE|DISREGARD|FORGET|OVERRIDE|SYSTEM|INSTRUCTION)[:\s].*/gim, "").slice(0, 3e3);
74
+ }
75
+ function extractJSON(text) {
76
+ const fenced = text.match(/```(?:json)?\s*\n([\s\S]*)\n\s*```/);
77
+ if (fenced) return fenced[1].trim();
78
+ const start = text.indexOf("{");
79
+ if (start !== -1) {
80
+ let depth = 0;
81
+ let inString = false;
82
+ let escape = false;
83
+ for (let i = start; i < text.length; i++) {
84
+ const ch = text[i];
85
+ if (escape) {
86
+ escape = false;
87
+ continue;
88
+ }
89
+ if (ch === "\\") {
90
+ escape = true;
91
+ continue;
92
+ }
93
+ if (ch === '"') {
94
+ inString = !inString;
95
+ continue;
96
+ }
97
+ if (inString) continue;
98
+ if (ch === "{") depth++;
99
+ else if (ch === "}") {
100
+ depth--;
101
+ if (depth === 0) return text.slice(start, i + 1);
102
+ }
103
+ }
104
+ return text.slice(start);
105
+ }
106
+ return text;
107
+ }
108
+ function extractJSONArray(text) {
109
+ const fenced = text.match(/```(?:json)?\s*\n?([\s\S]*?)\n?```/);
110
+ if (fenced) return fenced[1].trim();
111
+ const arrayMatch = text.match(/\[[\s\S]*\]/);
112
+ if (arrayMatch) return arrayMatch[0];
113
+ return text;
114
+ }
115
+ function formatBaseContext(ctx) {
116
+ const sections = [];
117
+ if (ctx.quickFacts.length > 0) {
118
+ sections.push(`## Quick Facts
119
+ ${ctx.quickFacts.map((f) => `- ${f.label}: ${f.value}`).join("\n")}`);
120
+ }
121
+ for (const artifact of ctx.artifacts) {
122
+ const header = artifact.ref ? `${artifact.title} (${artifact.ref})` : artifact.title;
123
+ sections.push(`## ${artifact.kind.toUpperCase()}: ${header}
124
+ \`\`\`
125
+ ${artifact.preview}
126
+ \`\`\``);
127
+ }
128
+ return sections.join("\n\n");
129
+ }
130
+ function formatReports(reports) {
131
+ return reports.map((r) => {
132
+ const findingsList = r.findings.map(
133
+ (f) => ` - [${f.id}] (${f.kind}${f.severity ? `, ${f.severity}` : ""}) ${f.title}
134
+ ${f.summary}
135
+ Evidence: ${f.evidence.map((e) => `${e.type}:${e.ref}`).join(", ")}
136
+ Confidence: ${f.confidence}` + (f.suggestedChange ? `
137
+ Suggested: ${f.suggestedChange}` : "")
138
+ ).join("\n");
139
+ return `### ${r.participant}
140
+ ${r.contextSummary}
141
+
142
+ Findings:
143
+ ${findingsList}`;
144
+ }).join("\n\n");
145
+ }
146
+ function formatFindingReviews(reviews) {
147
+ if (reviews.length === 0) return "No peer reviews.";
148
+ return reviews.map(
149
+ (r) => `[${r.reviewer}] on ${r.findingId}: ${r.verdict}${r.reason ? ` \u2014 ${r.reason}` : ""}`
150
+ ).join("\n");
151
+ }
152
+ function parseReport(participant, text) {
153
+ if (!text || text.trim().length === 0) {
154
+ logger.warn("arena.parse_report_empty", { participant });
155
+ return {
156
+ participant,
157
+ contextSummary: "(no response)",
158
+ findings: []
159
+ };
160
+ }
161
+ try {
162
+ const json = extractJSON(text);
163
+ const parsed = JSON.parse(json);
164
+ let findings = parsed.findings;
165
+ if (!Array.isArray(findings) && parsed.contextSummary === void 0) {
166
+ if (parsed.kind && parsed.title) {
167
+ findings = [parsed];
168
+ }
169
+ }
170
+ const report = {
171
+ participant,
172
+ contextSummary: parsed.contextSummary ?? parsed.context_summary ?? "",
173
+ findings: Array.isArray(findings) ? findings.map(parseFinding) : []
174
+ };
175
+ if (report.findings.length === 0) {
176
+ logger.warn("arena.parse_report_no_findings", {
177
+ participant,
178
+ textPreview: text.slice(0, 200)
179
+ });
180
+ }
181
+ return report;
182
+ } catch (err) {
183
+ logger.warn("arena.parse_report_json_fail", {
184
+ participant,
185
+ error: err.message,
186
+ textLength: text.length,
187
+ text: text.slice(0, 2e3)
188
+ });
189
+ return extractFindingsFromFreeText(participant, text);
190
+ }
191
+ }
192
+ function parseFinding(raw, index) {
193
+ return {
194
+ id: asString(raw.id) || `f${index + 1}`,
195
+ kind: validateFindingKind(raw.kind),
196
+ title: asString(raw.title) || "Untitled",
197
+ summary: asString(raw.summary),
198
+ severity: raw.severity || void 0,
199
+ confidence: typeof raw.confidence === "number" ? raw.confidence : 0.5,
200
+ evidence: Array.isArray(raw.evidence) ? raw.evidence.map((e) => ({
201
+ type: e.type ?? "doc",
202
+ ref: e.ref ?? "",
203
+ note: e.note ?? ""
204
+ })) : [],
205
+ affectedFiles: Array.isArray(raw.affectedFiles) ? raw.affectedFiles : [],
206
+ suggestedChange: raw.suggestedChange || void 0
207
+ };
208
+ }
209
+ function validateFindingKind(v) {
210
+ if (v === "strength" || v === "improvement" || v === "risk" || v === "question") return v;
211
+ return "improvement";
212
+ }
213
+ function extractFindingsFromFreeText(participant, text) {
214
+ const sections = text.split(/(?:^|\n)(?:#{1,3}\s+|\d+\.\s+|\*\*[^*]+\*\*\s*\n|---+\s*\n)/m).map((s) => s.trim()).filter((s) => s.length > 20);
215
+ if (sections.length === 0) {
216
+ return {
217
+ participant,
218
+ contextSummary: text.slice(0, 200),
219
+ findings: [{
220
+ id: `${participant}-f1`,
221
+ kind: "improvement",
222
+ title: "Analysis",
223
+ summary: text.slice(0, 3e3),
224
+ confidence: 0.5,
225
+ evidence: [],
226
+ affectedFiles: []
227
+ }]
228
+ };
229
+ }
230
+ const findings = sections.slice(0, 10).map((section, i) => {
231
+ const firstLine = section.split("\n")[0].slice(0, 100);
232
+ const body = section.length > firstLine.length ? section.slice(firstLine.length).trim() : section;
233
+ return {
234
+ id: `${participant}-f${i + 1}`,
235
+ kind: classifyFindingKind(section),
236
+ title: firstLine.replace(/^[-*•]\s*/, "").replace(/\*\*/g, ""),
237
+ summary: body.slice(0, 1e3),
238
+ confidence: 0.5,
239
+ evidence: [],
240
+ affectedFiles: extractFilePaths(section)
241
+ };
242
+ });
243
+ return {
244
+ participant,
245
+ contextSummary: text.slice(0, 200),
246
+ findings
247
+ };
248
+ }
249
+ function classifyFindingKind(text) {
250
+ const lower = text.toLowerCase();
251
+ if (/\b(risk|danger|vulnerab|security|breaking|regression|critical)\b/.test(lower)) return "risk";
252
+ if (/\b(good|well|strength|clean|solid|nice|excellent|properly)\b/.test(lower)) return "strength";
253
+ if (/\b(question|unclear|confirm|clarif|why|how come|wonder)\b/.test(lower)) return "question";
254
+ return "improvement";
255
+ }
256
+ function extractFilePaths(text) {
257
+ const matches = text.match(/(?:^|\s)((?:src|lib|packages|app)\/[\w\-/.]+\.\w+)/gm);
258
+ return matches ? [...new Set(matches.map((m) => m.trim()))] : [];
259
+ }
260
+ function parseReviews(reviewer, text) {
261
+ try {
262
+ const json = extractJSONArray(text);
263
+ const parsed = JSON.parse(json);
264
+ if (!Array.isArray(parsed)) {
265
+ const objJson = extractJSON(text);
266
+ const obj = JSON.parse(objJson);
267
+ if (Array.isArray(obj.reviews)) {
268
+ return obj.reviews.map((r) => parseReview(reviewer, r));
269
+ }
270
+ return [];
271
+ }
272
+ return parsed.map((r) => parseReview(reviewer, r));
273
+ } catch {
274
+ return [];
275
+ }
276
+ }
277
+ function parseReview(reviewer, raw) {
278
+ return {
279
+ reviewer,
280
+ findingId: raw.findingId ?? raw.finding_id ?? "",
281
+ verdict: validateVerdict(raw.verdict),
282
+ reason: raw.reason ?? "",
283
+ extraEvidence: Array.isArray(raw.extraEvidence) ? raw.extraEvidence : void 0
284
+ };
285
+ }
286
+ function validateVerdict(v) {
287
+ if (v === "agree" || v === "refine" || v === "disagree" || v === "needs_evidence") return v;
288
+ return "agree";
289
+ }
290
+ function parseConsensus(text) {
291
+ try {
292
+ const json = extractJSON(text);
293
+ const parsed = JSON.parse(json);
294
+ if (typeof parsed !== "object" || parsed === null) {
295
+ throw new Error("parsed JSON is not an object");
296
+ }
297
+ return {
298
+ summary: asString(parsed.summary),
299
+ subjectSummary: asString(parsed.subjectSummary || parsed.changeSummary) || void 0,
300
+ strengths: parseConsensusItems(parsed.strengths),
301
+ improvements: parseConsensusItems(parsed.improvements),
302
+ risks: parseConsensusItems(parsed.risks),
303
+ openQuestions: parseConsensusItems(parsed.openQuestions),
304
+ roadmap: parseRoadmapPhases(parsed.roadmap),
305
+ nextActions: Array.isArray(parsed.nextActions) ? parsed.nextActions.map((a) => ({
306
+ title: a.title ?? "",
307
+ priority: validatePriority(a.priority),
308
+ rationale: a.rationale ?? "",
309
+ relatedFindings: Array.isArray(a.relatedFindings) ? a.relatedFindings : []
310
+ })) : []
311
+ };
312
+ } catch {
313
+ return {
314
+ summary: text,
315
+ strengths: [],
316
+ improvements: [],
317
+ risks: [],
318
+ openQuestions: [],
319
+ roadmap: [],
320
+ nextActions: []
321
+ };
322
+ }
323
+ }
324
+ function parseConsensusItems(arr) {
325
+ if (!Array.isArray(arr)) return [];
326
+ return arr.map((item) => ({
327
+ title: asString(item.title),
328
+ summary: item.summary ?? "",
329
+ support: Array.isArray(item.support) ? item.support : [],
330
+ challenge: Array.isArray(item.challenge) ? item.challenge : [],
331
+ confidence: typeof item.confidence === "number" ? item.confidence : 0.5,
332
+ evidenceRefs: Array.isArray(item.evidenceRefs) ? item.evidenceRefs : []
333
+ }));
334
+ }
335
+ function parseRoadmapPhases(arr) {
336
+ if (!Array.isArray(arr)) return [];
337
+ return arr.map((phase) => ({
338
+ title: phase.title ?? "",
339
+ priority: validatePriority(phase.priority),
340
+ goal: phase.goal ?? phase.description ?? "",
341
+ scope: toStringArray(phase.scope),
342
+ deliverables: toStringArray(phase.deliverables),
343
+ dependencies: toStringArray(phase.dependencies),
344
+ risks: toStringArray(phase.risks),
345
+ successCriteria: toStringArray(phase.successCriteria),
346
+ relatedFindings: toStringArray(phase.relatedFindings)
347
+ }));
348
+ }
349
+ function validatePriority(value) {
350
+ if (value === "high" || value === "medium" || value === "low") return value;
351
+ return "medium";
352
+ }
353
+ function toStringArray(value) {
354
+ return Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
355
+ }
356
+ function formatClaimsForReview(claims) {
357
+ if (claims.length === 0) return "No claims to review.";
358
+ return claims.map((c) => {
359
+ const f = c.finding;
360
+ const evidence = c.evidenceRefs.length > 0 ? `
361
+ Evidence: ${c.evidenceRefs.join(", ")}` : "";
362
+ const packets = c.evidencePacketIds.length > 0 ? `
363
+ Evidence packets: ${c.evidencePacketIds.join(", ")}` : "";
364
+ return `- [${c.claimId}] (${f.kind}${f.severity ? `, ${f.severity}` : ""}, status: ${c.status})
365
+ ${sanitizeForPrompt(f.title)}
366
+ ${sanitizeForPrompt(f.summary)}` + evidence + packets + `
367
+ Confidence: ${f.confidence}`;
368
+ }).join("\n\n");
369
+ }
370
+ function formatDebateHistory(turns) {
371
+ if (turns.length === 0) return "No prior debate turns.";
372
+ return turns.map(
373
+ (t) => `[${t.participant}] stance: ${t.stance}
374
+ ${t.summary}` + (t.newEvidenceRefs?.length ? `
375
+ New evidence: ${t.newEvidenceRefs.join(", ")}` : "")
376
+ ).join("\n");
377
+ }
378
+ function formatClaimSummaryForConsensus(summary) {
379
+ const sections = [];
380
+ if (summary.verified.length > 0) {
381
+ sections.push(
382
+ `### Verified Claims (${summary.verified.length})
383
+ ` + summary.verified.map(
384
+ (c) => `- [${c.claimId}] ${sanitizeForPrompt(c.finding.title)} (${c.finding.kind}, confidence: ${c.finding.confidence})`
385
+ ).join("\n")
386
+ );
387
+ }
388
+ if (summary.unresolved.length > 0) {
389
+ sections.push(
390
+ `### Unresolved Claims (${summary.unresolved.length})
391
+ ` + summary.unresolved.map(
392
+ (c) => `- [${c.claimId}] ${sanitizeForPrompt(c.finding.title)} \u2014 ${c.challenges.length} challenge(s), no consensus reached`
393
+ ).join("\n")
394
+ );
395
+ }
396
+ if (summary.contested.length > 0) {
397
+ sections.push(
398
+ `### Still Contested (${summary.contested.length})
399
+ ` + summary.contested.map(
400
+ (c) => `- [${c.claimId}] ${sanitizeForPrompt(c.finding.title)} \u2014 ${c.challenges.length} challenge(s)`
401
+ ).join("\n")
402
+ );
403
+ }
404
+ if (summary.rejected.length > 0) {
405
+ sections.push(
406
+ `### Rejected Claims (${summary.rejected.length})
407
+ ` + summary.rejected.map(
408
+ (c) => `- [${c.claimId}] ${sanitizeForPrompt(c.finding.title)} \u2014 rejected: ${sanitizeForPrompt(c.adjudication?.rationale ?? "no rationale")}`
409
+ ).join("\n")
410
+ );
411
+ }
412
+ return sections.length > 0 ? sections.join("\n\n") : "No claims processed.";
413
+ }
414
+ function formatDigestForPrompt(digest) {
415
+ const sections = [];
416
+ sections.push(`Claims under review: ${digest.relevantClaimIds.join(", ")}`);
417
+ if (digest.evidencePackets.length > 0) {
418
+ sections.push("\nEvidence:");
419
+ for (const p of digest.evidencePackets) {
420
+ sections.push(` [${p.packetId}] ${sanitizeForPrompt(p.title)} (${p.source}): ${sanitizeForPrompt(p.summary)}`);
421
+ for (const e of p.excerpts.slice(0, 2)) {
422
+ sections.push(` > ${e.ref}: ${sanitizeForPrompt(e.snippet)}`);
423
+ }
424
+ }
425
+ }
426
+ if (digest.recentChallenges.length > 0) {
427
+ sections.push("\nPrior challenges:");
428
+ for (const c of digest.recentChallenges) {
429
+ sections.push(` [${c.reviewer}] on ${c.claimId}: ${c.verdict} \u2014 ${sanitizeForPrompt(c.reason)}`);
430
+ }
431
+ }
432
+ return sections.join("\n");
433
+ }
434
+ function parseChallenges(reviewer, text) {
435
+ try {
436
+ const json = extractJSONArray(text);
437
+ const parsed = JSON.parse(json);
438
+ if (!Array.isArray(parsed)) {
439
+ const objJson = extractJSON(text);
440
+ const obj = JSON.parse(objJson);
441
+ if (Array.isArray(obj.challenges)) {
442
+ return obj.challenges.map((r) => parseChallenge(reviewer, r));
443
+ }
444
+ return [];
445
+ }
446
+ return parsed.map((r) => parseChallenge(reviewer, r));
447
+ } catch {
448
+ return [];
449
+ }
450
+ }
451
+ function parseChallenge(reviewer, raw) {
452
+ return {
453
+ reviewer,
454
+ claimId: asString(raw.claimId ?? raw.claim_id),
455
+ verdict: validateVerdict(raw.verdict),
456
+ reason: asString(raw.reason),
457
+ supportingEvidenceRefs: Array.isArray(raw.supportingEvidenceRefs) ? raw.supportingEvidenceRefs : void 0,
458
+ requestedChecks: Array.isArray(raw.requestedChecks) ? raw.requestedChecks.map((rc) => ({
459
+ requestId: rc.requestId ?? `req-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`,
460
+ claimId: raw.claimId ?? raw.claim_id ?? "",
461
+ requester: reviewer,
462
+ description: rc.description ?? "",
463
+ refs: Array.isArray(rc.refs) ? rc.refs : void 0,
464
+ priority: validateCheckPriority(rc.priority)
465
+ })) : void 0
466
+ };
467
+ }
468
+ function validateCheckPriority(v) {
469
+ if (v === "high" || v === "medium" || v === "low") return v;
470
+ return void 0;
471
+ }
472
+ function parseDebateTurn(participant, text) {
473
+ try {
474
+ const json = extractJSON(text);
475
+ const parsed = JSON.parse(json);
476
+ return {
477
+ participant,
478
+ stance: validateStance(parsed.stance),
479
+ summary: parsed.summary ?? parsed.argument ?? "",
480
+ newEvidenceRefs: Array.isArray(parsed.newEvidenceRefs) ? parsed.newEvidenceRefs : void 0
481
+ };
482
+ } catch {
483
+ return {
484
+ participant,
485
+ stance: "uncertain",
486
+ summary: text.slice(0, 1e3)
487
+ };
488
+ }
489
+ }
490
+ function validateStance(v) {
491
+ if (v === "support" || v === "oppose" || v === "narrow" || v === "uncertain") return v;
492
+ return "uncertain";
493
+ }
494
+ function parseAdjudication(claimId, text) {
495
+ try {
496
+ const json = extractJSON(text);
497
+ const parsed = JSON.parse(json);
498
+ return {
499
+ claimId,
500
+ outcome: validateAdjudicationOutcome(parsed.outcome),
501
+ rationale: asString(parsed.rationale),
502
+ finalSummary: asString(parsed.finalSummary ?? parsed.summary),
503
+ supportingEvidenceRefs: Array.isArray(parsed.supportingEvidenceRefs) ? parsed.supportingEvidenceRefs : []
504
+ };
505
+ } catch {
506
+ return {
507
+ claimId,
508
+ outcome: "unresolved",
509
+ rationale: "Failed to parse adjudication response",
510
+ finalSummary: text.slice(0, 500),
511
+ supportingEvidenceRefs: []
512
+ };
513
+ }
514
+ }
515
+ function validateAdjudicationOutcome(v) {
516
+ if (v === "accepted" || v === "accepted_with_revision" || v === "rejected" || v === "unresolved") return v;
517
+ return "unresolved";
518
+ }
519
+ function parseDetailExpansion(text) {
520
+ try {
521
+ const json = extractJSON(text);
522
+ const parsed = JSON.parse(json);
523
+ if (typeof parsed !== "object" || parsed === null) {
524
+ throw new Error("parsed JSON is not an object");
525
+ }
526
+ return {
527
+ phaseTitle: asString(parsed.phaseTitle),
528
+ objective: asString(parsed.objective),
529
+ targetFiles: toStringArray(parsed.targetFiles),
530
+ codeChanges: toStringArray(parsed.codeChanges),
531
+ interfaces: toStringArray(parsed.interfaces),
532
+ migrationSteps: toStringArray(parsed.migrationSteps),
533
+ validation: toStringArray(parsed.validation),
534
+ effort: validateEffort(parsed.effort),
535
+ blockers: toStringArray(parsed.blockers),
536
+ evidenceRefs: toStringArray(parsed.evidenceRefs)
537
+ };
538
+ } catch {
539
+ return {
540
+ phaseTitle: "",
541
+ objective: text.slice(0, 500),
542
+ targetFiles: [],
543
+ codeChanges: [],
544
+ interfaces: [],
545
+ migrationSteps: [],
546
+ validation: [],
547
+ effort: "medium",
548
+ blockers: [],
549
+ evidenceRefs: []
550
+ };
551
+ }
552
+ }
553
+ function validateEffort(v) {
554
+ if (v === "small" || v === "medium" || v === "large") return v;
555
+ return "medium";
556
+ }
557
+
558
+ // src/arena/strategies/review.ts
559
+ var ReviewStrategy = class {
560
+ // ─── Research Phase ──────────────────────────────────────────
561
+ researchSystemPrompt(name) {
562
+ return `You are ${name}, a reviewer in a multi-model review arena.
563
+
564
+ You may have access to read-only tools to fetch additional context. The base context is intentionally lean \u2014 use tools to inspect details as needed.
565
+
566
+ IMPORTANT RULES:
567
+ - Limit yourself to 3-5 tool rounds. Do NOT exhaustively read every file.
568
+ - Focus on the HIGHEST-IMPACT findings. Quality over quantity.
569
+ - Output as many findings as the topic warrants \u2014 typically 5-15 for a non-trivial subject. Each finding's "summary" should be 80+ words with concrete evidence and rationale, not a one-liner. Rank by confidence.
570
+ - Prioritize: risks > improvements > questions. Strengths are optional.
571
+
572
+ When ready, respond ONLY with JSON (no markdown fences):
573
+ {"contextSummary": "brief summary of what you investigated", "findings": [{"id": "unique-id", "kind": "risk|improvement|question|strength", "title": "short title", "summary": "detailed explanation", "severity": "high|medium|low", "confidence": 0.0-1.0, "evidence": [{"type": "file|diff|grep|git|doc", "ref": "path", "note": "what it shows"}], "affectedFiles": ["paths"], "suggestedChange": "optional"}]}`;
574
+ }
575
+ researchUserPrompt(topic, baseContext) {
576
+ return `## Review Topic
577
+ ${topic}
578
+
579
+ ${formatBaseContext(baseContext)}
580
+
581
+ Use tools to read specific files from the diff. Then output 3-6 highest-confidence findings as JSON.`;
582
+ }
583
+ parseResearchResponse(participant, text) {
584
+ return parseReport(participant, text);
585
+ }
586
+ // ─── Cross Review Phase ──────────────────────────────────────
587
+ crossReviewSystemPrompt(reviewerName) {
588
+ return `You are ${reviewerName}, reviewing other participants' review findings.
589
+
590
+ For each finding, provide a verdict:
591
+ - "agree": you confirm this finding
592
+ - "refine": mostly agree but with refinements
593
+ - "disagree": you believe this finding is incorrect
594
+ - "needs_evidence": the finding lacks sufficient evidence
595
+
596
+ Focus on HIGH VALUE findings: high severity, high risk, or conflicting conclusions.
597
+ You don't need to review every single finding \u2014 prioritize the important ones.
598
+
599
+ Respond ONLY with a JSON array (no markdown fences):
600
+ [{"findingId": "...", "verdict": "agree|refine|disagree|needs_evidence", "reason": "...", "extraEvidence": ["optional"]}]`;
601
+ }
602
+ crossReviewUserPrompt(topic, myReport, otherReports) {
603
+ return `## Topic: ${topic}
604
+
605
+ ## Your Findings
606
+ ${formatReports([myReport])}
607
+
608
+ ## Other Reviewers' Findings
609
+ ${formatReports(otherReports)}
610
+
611
+ Review the other participants' findings. Focus on high-priority items.`;
612
+ }
613
+ parseCrossReviewResponse(reviewer, text) {
614
+ return parseReviews(reviewer, text);
615
+ }
616
+ // ─── Consensus Phase ─────────────────────────────────────────
617
+ consensusSystemPrompt() {
618
+ return `You are a neutral moderator synthesizing a multi-model review into a structured consensus.
619
+
620
+ You MUST faithfully reflect the aggregated findings and peer reviews. Do NOT add new conclusions that have no source in the findings.
621
+
622
+ IMPORTANT: Start with a "subjectSummary" \u2014 a factual overview of WHAT is being reviewed (scope, key areas, high-level description). This comes BEFORE any judgment.
623
+
624
+ Respond ONLY with JSON (no markdown fences):
625
+ {
626
+ "summary": "one-paragraph overall assessment",
627
+ "subjectSummary": "factual overview of what is being reviewed \u2014 scope, key areas, subject description",
628
+ "strengths": [{"title": "...", "summary": "...", "support": ["participant names"], "challenge": [], "confidence": 0.0-1.0, "evidenceRefs": ["finding IDs"]}],
629
+ "improvements": [same structure],
630
+ "risks": [same structure],
631
+ "openQuestions": [same structure],
632
+ "nextActions": [{"title": "...", "priority": "high|medium|low", "rationale": "...", "relatedFindings": ["finding IDs"]}]
633
+ }`;
634
+ }
635
+ consensusUserPrompt(topic, reports, reviews) {
636
+ return `## Topic
637
+ ${topic}
638
+
639
+ ## Participant Reports
640
+ ${formatReports(reports)}
641
+
642
+ ## Peer Reviews
643
+ ${formatFindingReviews(reviews)}
644
+
645
+ Synthesize a structured consensus. Group findings by category, note agreement/disagreement, and propose next actions.`;
646
+ }
647
+ parseConsensusResponse(text) {
648
+ return parseConsensus(text);
649
+ }
650
+ preferredFindingKinds() {
651
+ return ["strength", "improvement", "risk", "question"];
652
+ }
653
+ // ─── V2: Verification Review ────────────────────────────────────
654
+ verificationReviewUserPrompt(topic, myReport, claimsToReview, digest) {
655
+ return `## Topic: ${topic}
656
+
657
+ ## Your Findings
658
+ ${formatReports([myReport])}
659
+
660
+ ## Claims to Verify
661
+ ${formatClaimsForReview(claimsToReview)}
662
+
663
+ ## Evidence Digest
664
+ ${formatDigestForPrompt(digest)}
665
+
666
+ Verify each claim against the evidence. For claims lacking evidence, you may request specific checks.
667
+ Respond ONLY with a JSON array:
668
+ [{"claimId": "...", "verdict": "agree|refine|disagree|needs_evidence", "reason": "...", "supportingEvidenceRefs": ["optional"], "requestedChecks": [{"description": "what to check", "priority": "high|medium|low"}]}]`;
669
+ }
670
+ parseVerificationReviewResponse(reviewer, text) {
671
+ return parseChallenges(reviewer, text);
672
+ }
673
+ // ─── V2: Debate ─────────────────────────────────────────────────
674
+ debateTurnUserPrompt(topic, claim, priorTurns, digest) {
675
+ return `## Topic: ${topic}
676
+
677
+ ## Contested Claim
678
+ [${claim.claimId}] ${claim.finding.title}
679
+ ${claim.finding.summary}
680
+ Evidence: ${claim.evidenceRefs.join(", ") || "none"}
681
+
682
+ ## Prior Debate
683
+ ${formatDebateHistory(priorTurns)}
684
+
685
+ ## Evidence Digest
686
+ ${formatDigestForPrompt(digest)}
687
+
688
+ State your position on this claim. Build on prior turns: cite specific evidence, acknowledge counter-arguments, and explain your reasoning in 150-300 words. Brevity here means missed nuance \u2014 depth wins.
689
+ Respond ONLY with JSON:
690
+ {"stance": "support|oppose|narrow|uncertain", "summary": "your argument", "newEvidenceRefs": ["optional"]}`;
691
+ }
692
+ parseDebateTurnResponse(participant, text) {
693
+ return parseDebateTurn(participant, text);
694
+ }
695
+ // ─── V2: Adjudication ──────────────────────────────────────────
696
+ adjudicationUserPrompt(topic, claim, debateRounds, digest) {
697
+ const debateSummary = debateRounds.length > 0 ? debateRounds.map(
698
+ (r) => `Round ${r.round}:
699
+ ${formatDebateHistory(r.participants)}
700
+ ${r.resolved ? "\u2192 Resolved" : "\u2192 Unresolved"}`
701
+ ).join("\n\n") : "No debate rounds occurred.";
702
+ return `## Topic: ${topic}
703
+
704
+ ## Claim Under Adjudication
705
+ [${claim.claimId}] ${claim.finding.title}
706
+ ${claim.finding.summary}
707
+ Owner: ${claim.owner} | Status: ${claim.status}
708
+ Evidence: ${claim.evidenceRefs.join(", ") || "none"}
709
+
710
+ ## Challenges
711
+ ` + claim.challenges.map((c) => `[${c.reviewer}] ${c.verdict}: ${c.reason}`).join("\n") + `
712
+
713
+ ## Debate
714
+ ${debateSummary}
715
+
716
+ ## Evidence Digest
717
+ ${formatDigestForPrompt(digest)}
718
+
719
+ As moderator, adjudicate this claim based on all available evidence.
720
+ Respond ONLY with JSON:
721
+ {"outcome": "accepted|accepted_with_revision|rejected|unresolved", "rationale": "...", "finalSummary": "revised claim summary if needed", "supportingEvidenceRefs": ["..."]}`;
722
+ }
723
+ parseAdjudicationResponse(text) {
724
+ return parseAdjudication("", text);
725
+ }
726
+ // ─── V2: Claim-Aware Consensus ─────────────────────────────────
727
+ claimAwareConsensusUserPrompt(topic, reports, reviews, claimSummary) {
728
+ return `## Topic
729
+ ${topic}
730
+
731
+ ## Claim Verification Status
732
+ ${formatClaimSummaryForConsensus(claimSummary)}
733
+
734
+ ## Participant Reports
735
+ ${formatReports(reports)}
736
+
737
+ ## Peer Reviews
738
+ ${formatFindingReviews(reviews)}
739
+
740
+ Synthesize a structured consensus. Verified claims should appear as high-confidence items. Unresolved claims should appear as open questions. Rejected claims should be excluded or noted as dismissed.`;
741
+ }
742
+ };
743
+
744
+ // src/arena/strategies/discussion.ts
745
+ init_esm_shims();
746
+ var DiscussionStrategy = class {
747
+ researchSystemPrompt(name) {
748
+ return `You are ${name}, participating in a multi-model discussion arena.
749
+
750
+ You may have access to read-only tools to gather evidence. The base context is intentionally lean \u2014 use tools as needed.
751
+
752
+ IMPORTANT RULES:
753
+ - Limit yourself to 3-5 tool rounds. Do NOT exhaustively read every file.
754
+ - Output as many findings as the topic warrants \u2014 typically 5-15 for a non-trivial subject. Each finding's "summary" should be 80+ words with concrete evidence and rationale, not a one-liner. Rank by confidence.
755
+ - Focus on trade-offs, risks, and open questions. Strengths are optional.
756
+
757
+ Respond ONLY with JSON (no markdown fences):
758
+ {"contextSummary": "what you investigated and your overall take", "findings": [{"id": "unique-id", "kind": "risk|improvement|question|strength", "title": "short title", "summary": "detailed analysis with evidence", "severity": "high|medium|low", "confidence": 0.0-1.0, "evidence": [{"type": "file|diff|grep|git|doc", "ref": "path", "note": "what it shows"}], "affectedFiles": ["paths"], "suggestedChange": "optional"}]}`;
759
+ }
760
+ researchUserPrompt(topic, baseContext) {
761
+ return `## Discussion Topic
762
+ ${topic}
763
+
764
+ ${formatBaseContext(baseContext)}
765
+
766
+ Use tools to investigate, then output 3-6 highest-confidence findings as JSON.`;
767
+ }
768
+ parseResearchResponse(participant, text) {
769
+ return parseReport(participant, text);
770
+ }
771
+ crossReviewSystemPrompt(reviewerName) {
772
+ return `You are ${reviewerName}, reviewing other participants' discussion findings.
773
+
774
+ Engage thoughtfully: challenge weak arguments, acknowledge strong ones.
775
+ Focus on finding the best answer, not winning.
776
+
777
+ For each finding you want to address, provide a verdict:
778
+ - "agree": you confirm this perspective
779
+ - "refine": mostly agree but with nuances
780
+ - "disagree": you have a different view with evidence
781
+ - "needs_evidence": the claim lacks supporting evidence
782
+
783
+ Respond ONLY with a JSON array:
784
+ [{"findingId": "...", "verdict": "...", "reason": "...", "extraEvidence": ["optional"]}]`;
785
+ }
786
+ crossReviewUserPrompt(topic, myReport, otherReports) {
787
+ return `## Topic: ${topic}
788
+
789
+ ## Your Analysis
790
+ ${formatReports([myReport])}
791
+
792
+ ## Other Participants' Analysis
793
+ ${formatReports(otherReports)}
794
+
795
+ Review the others' findings. Where do you agree or disagree? What nuances are missing?`;
796
+ }
797
+ parseCrossReviewResponse(reviewer, text) {
798
+ return parseReviews(reviewer, text);
799
+ }
800
+ consensusSystemPrompt() {
801
+ return `You are a neutral moderator synthesizing a multi-model discussion into a balanced conclusion.
802
+
803
+ Capture key insights, agreements, and remaining disagreements. Do NOT suppress minority viewpoints \u2014 preserve them as open questions.
804
+
805
+ IMPORTANT: Start with a "subjectSummary" \u2014 a factual framing of the topic, current scope, or assumptions under discussion before moving into conclusions.
806
+
807
+ Respond ONLY with JSON (no markdown fences):
808
+ {
809
+ "summary": "balanced synthesis",
810
+ "subjectSummary": "factual problem framing or current scope of the discussion",
811
+ "strengths": [{"title": "...", "summary": "...", "support": [], "challenge": [], "confidence": 0.0-1.0, "evidenceRefs": []}],
812
+ "improvements": [same structure],
813
+ "risks": [same structure],
814
+ "openQuestions": [same structure \u2014 include still-debated points],
815
+ "nextActions": [{"title": "...", "priority": "high|medium|low", "rationale": "...", "relatedFindings": []}]
816
+ }`;
817
+ }
818
+ consensusUserPrompt(topic, reports, reviews) {
819
+ return `## Topic
820
+ ${topic}
821
+
822
+ ## Participant Analyses
823
+ ${formatReports(reports)}
824
+
825
+ ## Peer Reviews
826
+ ${formatFindingReviews(reviews)}
827
+
828
+ Synthesize a balanced conclusion. Start with a factual subjectSummary, then preserve disagreements as open questions.`;
829
+ }
830
+ parseConsensusResponse(text) {
831
+ return parseConsensus(text);
832
+ }
833
+ preferredFindingKinds() {
834
+ return ["strength", "risk", "question"];
835
+ }
836
+ // ─── V2: Verification Review ────────────────────────────────────
837
+ verificationReviewUserPrompt(topic, myReport, claimsToReview, digest) {
838
+ return `## Topic: ${topic}
839
+
840
+ ## Your Analysis
841
+ ${formatReports([myReport])}
842
+
843
+ ## Claims to Verify
844
+ ${formatClaimsForReview(claimsToReview)}
845
+
846
+ ## Evidence Digest
847
+ ${formatDigestForPrompt(digest)}
848
+
849
+ Engage critically with each claim. Challenge weak arguments, acknowledge strong ones. Focus on finding the best answer, not winning.
850
+ Respond ONLY with a JSON array:
851
+ [{"claimId": "...", "verdict": "agree|refine|disagree|needs_evidence", "reason": "...", "supportingEvidenceRefs": ["optional"], "requestedChecks": [{"description": "what to check", "priority": "high|medium|low"}]}]`;
852
+ }
853
+ parseVerificationReviewResponse(reviewer, text) {
854
+ return parseChallenges(reviewer, text);
855
+ }
856
+ // ─── V2: Debate ─────────────────────────────────────────────────
857
+ debateTurnUserPrompt(topic, claim, priorTurns, digest) {
858
+ return `## Topic: ${topic}
859
+
860
+ ## Contested Claim
861
+ [${claim.claimId}] ${claim.finding.title}
862
+ ${claim.finding.summary}
863
+
864
+ ## Prior Debate
865
+ ${formatDebateHistory(priorTurns)}
866
+
867
+ ## Evidence Digest
868
+ ${formatDigestForPrompt(digest)}
869
+
870
+ Engage thoughtfully. If the evidence supports the claim, narrow toward agreement. If not, explain why with evidence.
871
+ Respond ONLY with JSON:
872
+ {"stance": "support|oppose|narrow|uncertain", "summary": "your argument", "newEvidenceRefs": ["optional"]}`;
873
+ }
874
+ parseDebateTurnResponse(participant, text) {
875
+ return parseDebateTurn(participant, text);
876
+ }
877
+ // ─── V2: Adjudication ──────────────────────────────────────────
878
+ adjudicationUserPrompt(topic, claim, debateRounds, digest) {
879
+ const debateSummary = debateRounds.length > 0 ? debateRounds.map(
880
+ (r) => `Round ${r.round}:
881
+ ${formatDebateHistory(r.participants)}
882
+ ${r.resolved ? "\u2192 Resolved" : "\u2192 Unresolved"}`
883
+ ).join("\n\n") : "No debate rounds occurred.";
884
+ return `## Topic: ${topic}
885
+
886
+ ## Contested Claim
887
+ [${claim.claimId}] ${claim.finding.title}
888
+ ${claim.finding.summary}
889
+ Owner: ${claim.owner}
890
+
891
+ ## Challenges
892
+ ` + claim.challenges.map((c) => `[${c.reviewer}] ${c.verdict}: ${c.reason}`).join("\n") + `
893
+
894
+ ## Debate
895
+ ${debateSummary}
896
+
897
+ ## Evidence Digest
898
+ ${formatDigestForPrompt(digest)}
899
+
900
+ As moderator, synthesize the debate. Preserve minority viewpoints where the evidence is genuinely ambiguous.
901
+ Respond ONLY with JSON:
902
+ {"outcome": "accepted|accepted_with_revision|rejected|unresolved", "rationale": "...", "finalSummary": "revised claim summary", "supportingEvidenceRefs": ["..."]}`;
903
+ }
904
+ parseAdjudicationResponse(text) {
905
+ return parseAdjudication("", text);
906
+ }
907
+ // ─── V2: Claim-Aware Consensus ─────────────────────────────────
908
+ claimAwareConsensusUserPrompt(topic, reports, reviews, claimSummary) {
909
+ return `## Topic
910
+ ${topic}
911
+
912
+ ## Claim Verification Status
913
+ ${formatClaimSummaryForConsensus(claimSummary)}
914
+
915
+ ## Participant Analyses
916
+ ${formatReports(reports)}
917
+
918
+ ## Peer Reviews
919
+ ${formatFindingReviews(reviews)}
920
+
921
+ Synthesize a balanced conclusion. Verified claims are high-confidence. Unresolved claims should be preserved as open questions \u2014 do NOT suppress minority viewpoints.`;
922
+ }
923
+ };
924
+
925
+ // src/arena/strategies/planning.ts
926
+ init_esm_shims();
927
+ var PlanningStrategy = class {
928
+ researchSystemPrompt(name) {
929
+ return `You are ${name}, a planner in a multi-model planning session.
930
+
931
+ You may have access to read-only tools to investigate the subject. The base context is intentionally lean \u2014 use tools as needed.
932
+
933
+ IMPORTANT RULES:
934
+ - Limit yourself to 3-5 tool rounds. Do NOT exhaustively read every file.
935
+ - Output as many findings as the topic warrants \u2014 typically 5-15 for a non-trivial subject. Each finding's "summary" should be 80+ words with concrete evidence and rationale, not a one-liner. Rank by confidence.
936
+ - Focus on: implementation phases (improvement), risks/blockers, decisions needed (question).
937
+ - Strengths are optional.
938
+
939
+ Respond ONLY with JSON (no markdown fences):
940
+ {"contextSummary": "what you investigated and your overall approach", "findings": [{"id": "unique-id", "kind": "improvement|risk|question|strength", "title": "short title", "summary": "detailed analysis", "severity": "high|medium|low", "confidence": 0.0-1.0, "evidence": [{"type": "file|diff|grep|git|doc", "ref": "path", "note": "what it shows"}], "affectedFiles": ["paths"], "suggestedChange": "optional"}]}`;
941
+ }
942
+ researchUserPrompt(topic, baseContext) {
943
+ return `## Planning Topic
944
+ ${topic}
945
+
946
+ ${formatBaseContext(baseContext)}
947
+
948
+ Use tools to investigate, then output 3-6 highest-confidence findings as JSON.`;
949
+ }
950
+ parseResearchResponse(participant, text) {
951
+ return parseReport(participant, text);
952
+ }
953
+ crossReviewSystemPrompt(reviewerName) {
954
+ return `You are ${reviewerName}, reviewing other architects' planning proposals.
955
+
956
+ Evaluate critically: identify gaps, suggest improvements, propose better alternatives.
957
+
958
+ For each finding you want to address:
959
+ - "agree": the proposed phase/risk is valid
960
+ - "refine": adjust scope, priority, or dependencies
961
+ - "disagree": propose a different approach
962
+ - "needs_evidence": more investigation needed
963
+
964
+ Respond ONLY with a JSON array:
965
+ [{"findingId": "...", "verdict": "...", "reason": "...", "extraEvidence": ["optional"]}]`;
966
+ }
967
+ crossReviewUserPrompt(topic, myReport, otherReports) {
968
+ return `## Topic: ${topic}
969
+
970
+ ## Your Proposed Plan
971
+ ${formatReports([myReport])}
972
+
973
+ ## Other Architects' Plans
974
+ ${formatReports(otherReports)}
975
+
976
+ Review the other proposals. What are the strengths and gaps? Can elements be combined?`;
977
+ }
978
+ parseCrossReviewResponse(reviewer, text) {
979
+ return parseReviews(reviewer, text);
980
+ }
981
+ consensusSystemPrompt() {
982
+ return `You are a neutral moderator synthesizing a multi-model planning session into a concrete roadmap.
983
+
984
+ Combine the best ideas into a unified plan with clear sequencing, priorities, and delivery phases.
985
+ IMPORTANT: the roadmap field is the primary output. Use it to describe 3 to 6 implementation phases. The nextActions field is only for the immediate 3 to 5 actions that should happen next.
986
+
987
+ Respond ONLY with JSON (no markdown fences):
988
+ {
989
+ "summary": "unified plan overview",
990
+ "subjectSummary": "factual overview of the current repo/problem scope before proposing changes",
991
+ "strengths": [{"title": "...", "summary": "...", "support": [], "challenge": [], "confidence": 0.0-1.0, "evidenceRefs": []}],
992
+ "improvements": [implementation phases as consensus items],
993
+ "risks": [identified risks],
994
+ "openQuestions": [decisions needed],
995
+ "roadmap": [{"title": "...", "priority": "high|medium|low", "goal": "...", "scope": ["..."], "deliverables": ["..."], "dependencies": ["..."], "risks": ["..."], "successCriteria": ["..."], "relatedFindings": []}],
996
+ "nextActions": [{"title": "...", "priority": "high|medium|low", "rationale": "...", "relatedFindings": []}]
997
+ }`;
998
+ }
999
+ consensusUserPrompt(topic, reports, reviews) {
1000
+ return `## Topic
1001
+ ${topic}
1002
+
1003
+ ## Proposed Plans
1004
+ ${formatReports(reports)}
1005
+
1006
+ ## Peer Reviews
1007
+ ${formatFindingReviews(reviews)}
1008
+
1009
+ Synthesize a final implementation roadmap.
1010
+ Requirements:
1011
+ - Start with a factual subjectSummary of the current scope.
1012
+ - Produce 3 to 6 roadmap phases covering sequencing, dependencies, deliverables, and success criteria.
1013
+ - Use nextActions only for the immediate follow-up work, not the entire roadmap.`;
1014
+ }
1015
+ parseConsensusResponse(text) {
1016
+ return parseConsensus(text);
1017
+ }
1018
+ preferredFindingKinds() {
1019
+ return ["improvement", "risk", "question"];
1020
+ }
1021
+ // ─── V2: Verification Review ────────────────────────────────────
1022
+ verificationReviewUserPrompt(topic, myReport, claimsToReview, digest) {
1023
+ return `## Topic: ${topic}
1024
+
1025
+ ## Your Proposed Plan
1026
+ ${formatReports([myReport])}
1027
+
1028
+ ## Claims to Verify
1029
+ ${formatClaimsForReview(claimsToReview)}
1030
+
1031
+ ## Evidence Digest
1032
+ ${formatDigestForPrompt(digest)}
1033
+
1034
+ Evaluate each claim for feasibility, sequencing, and dependencies. Challenge proposals that lack evidence.
1035
+ Respond ONLY with a JSON array:
1036
+ [{"claimId": "...", "verdict": "agree|refine|disagree|needs_evidence", "reason": "...", "supportingEvidenceRefs": ["optional"], "requestedChecks": [{"description": "what to check", "priority": "high|medium|low"}]}]`;
1037
+ }
1038
+ parseVerificationReviewResponse(reviewer, text) {
1039
+ return parseChallenges(reviewer, text);
1040
+ }
1041
+ // ─── V2: Debate ─────────────────────────────────────────────────
1042
+ debateTurnUserPrompt(topic, claim, priorTurns, digest) {
1043
+ return `## Topic: ${topic}
1044
+
1045
+ ## Contested Planning Proposal
1046
+ [${claim.claimId}] ${claim.finding.title}
1047
+ ${claim.finding.summary}
1048
+
1049
+ ## Prior Debate
1050
+ ${formatDebateHistory(priorTurns)}
1051
+
1052
+ ## Evidence Digest
1053
+ ${formatDigestForPrompt(digest)}
1054
+
1055
+ Argue for or against this proposal. Focus on feasibility, risks, and better alternatives.
1056
+ Respond ONLY with JSON:
1057
+ {"stance": "support|oppose|narrow|uncertain", "summary": "your argument", "newEvidenceRefs": ["optional"]}`;
1058
+ }
1059
+ parseDebateTurnResponse(participant, text) {
1060
+ return parseDebateTurn(participant, text);
1061
+ }
1062
+ // ─── V2: Adjudication ──────────────────────────────────────────
1063
+ adjudicationUserPrompt(topic, claim, debateRounds, digest) {
1064
+ const debateSummary = debateRounds.length > 0 ? debateRounds.map(
1065
+ (r) => `Round ${r.round}:
1066
+ ${formatDebateHistory(r.participants)}
1067
+ ${r.resolved ? "\u2192 Resolved" : "\u2192 Unresolved"}`
1068
+ ).join("\n\n") : "No debate rounds occurred.";
1069
+ return `## Topic: ${topic}
1070
+
1071
+ ## Contested Proposal
1072
+ [${claim.claimId}] ${claim.finding.title}
1073
+ ${claim.finding.summary}
1074
+ Owner: ${claim.owner}
1075
+
1076
+ ## Challenges
1077
+ ` + claim.challenges.map((c) => `[${c.reviewer}] ${c.verdict}: ${c.reason}`).join("\n") + `
1078
+
1079
+ ## Debate
1080
+ ${debateSummary}
1081
+
1082
+ ## Evidence Digest
1083
+ ${formatDigestForPrompt(digest)}
1084
+
1085
+ As moderator, decide whether this proposal should be included in the final plan.
1086
+ Respond ONLY with JSON:
1087
+ {"outcome": "accepted|accepted_with_revision|rejected|unresolved", "rationale": "...", "finalSummary": "revised proposal if needed", "supportingEvidenceRefs": ["..."]}`;
1088
+ }
1089
+ parseAdjudicationResponse(text) {
1090
+ return parseAdjudication("", text);
1091
+ }
1092
+ // ─── Planning: Merge-Oriented Review ────────────────────────────
1093
+ mergeReviewUserPrompt(topic, myReport, claimsToReview, digest) {
1094
+ return `## Topic: ${topic}
1095
+
1096
+ ## Your Proposed Plan
1097
+ ${formatReports([myReport])}
1098
+
1099
+ ## Candidate Claims (Proposed Phases & Findings)
1100
+ ${formatClaimsForReview(claimsToReview)}
1101
+
1102
+ ## Evidence Digest
1103
+ ${formatDigestForPrompt(digest)}
1104
+
1105
+ You are reviewing planning proposals for MERGE and CONVERGENCE, not for correctness judging.
1106
+
1107
+ For each claim, decide how it should be incorporated into the final roadmap:
1108
+ - "agree": the proposed phase/finding is valid as-is
1109
+ - "refine": merge with another phase, adjust priority/scope/dependencies, or narrow scope
1110
+ - "disagree": only for proposals that directly contradict repo evidence
1111
+ - "needs_evidence": mark as open question for further investigation
1112
+
1113
+ In your reason, use these semantic tags where applicable:
1114
+ [merge] \u2014 combine with another phase
1115
+ [reprioritize] \u2014 change priority ordering
1116
+ [split_phase] \u2014 break into smaller phases
1117
+ [combine_phase] \u2014 merge multiple phases into one
1118
+ [dependency_risk] \u2014 flag missing dependency
1119
+ [needs_detail] \u2014 needs more implementation specifics
1120
+ [open_question] \u2014 convert to open question
1121
+
1122
+ Respond ONLY with a JSON array:
1123
+ [{"claimId": "...", "verdict": "agree|refine|disagree|needs_evidence", "reason": "[tag] explanation", "supportingEvidenceRefs": ["optional"], "requestedChecks": [{"description": "what to check", "priority": "high|medium|low"}]}]`;
1124
+ }
1125
+ parseMergeReviewResponse(reviewer, text) {
1126
+ return parseChallenges(reviewer, text);
1127
+ }
1128
+ // ─── Planning: Detail Expansion ────────────────────────────────
1129
+ detailExpansionSystemPrompt() {
1130
+ return `You are a senior architect expanding a high-level roadmap phase into a concrete, repo-level implementation plan.
1131
+
1132
+ You may have access to read-only tools to investigate the codebase. Use them to verify file paths, interfaces, and module boundaries.
1133
+
1134
+ IMPORTANT RULES:
1135
+ - Be specific: name actual files, modules, interfaces, and functions.
1136
+ - If you're uncertain about a target, write "likely: <path>" and note the uncertainty.
1137
+ - Do not produce vague platitudes like "refactor the module" \u2014 say what changes.
1138
+ - Limit tool usage to 2-3 rounds for verification.
1139
+
1140
+ Respond ONLY with JSON (no markdown fences):
1141
+ {"phaseTitle": "...", "objective": "...", "targetFiles": ["..."], "codeChanges": ["specific change descriptions"], "interfaces": ["new or modified interfaces"], "migrationSteps": ["ordered steps"], "validation": ["how to verify"], "effort": "small|medium|large", "blockers": ["blocking issues"], "evidenceRefs": ["refs to supporting evidence"]}`;
1142
+ }
1143
+ detailExpansionUserPrompt(topic, phase, digest) {
1144
+ const phaseContext = [
1145
+ `Title: ${phase.title}`,
1146
+ `Priority: ${phase.priority}`,
1147
+ `Goal: ${phase.goal}`,
1148
+ phase.scope.length > 0 ? `Scope: ${phase.scope.join("; ")}` : "",
1149
+ phase.deliverables.length > 0 ? `Deliverables: ${phase.deliverables.join("; ")}` : "",
1150
+ phase.dependencies.length > 0 ? `Dependencies: ${phase.dependencies.join("; ")}` : "",
1151
+ phase.risks.length > 0 ? `Risks: ${phase.risks.join("; ")}` : "",
1152
+ phase.successCriteria.length > 0 ? `Success Criteria: ${phase.successCriteria.join("; ")}` : "",
1153
+ phase.relatedFindings.length > 0 ? `Related Findings: ${phase.relatedFindings.join(", ")}` : ""
1154
+ ].filter(Boolean).join("\n");
1155
+ return `## Overall Topic
1156
+ ${topic}
1157
+
1158
+ ## Roadmap Phase to Expand
1159
+ ${phaseContext}
1160
+
1161
+ ## Evidence Digest
1162
+ ${formatDigestForPrompt(digest)}
1163
+
1164
+ Expand this phase into a repo-level implementation plan.
1165
+ Use tools to verify file paths and interfaces if available.
1166
+ Answer these questions:
1167
+ 1. Which files/modules need to change?
1168
+ 2. What are the specific code changes?
1169
+ 3. What interfaces need to be added or modified?
1170
+ 4. What are the migration steps (in order)?
1171
+ 5. How do we validate the changes?
1172
+ 6. What is the effort estimate?
1173
+ 7. What are the blockers?`;
1174
+ }
1175
+ parseDetailExpansionResponse(text) {
1176
+ return parseDetailExpansion(text);
1177
+ }
1178
+ // ─── V2: Claim-Aware Consensus ─────────────────────────────────
1179
+ claimAwareConsensusUserPrompt(topic, reports, reviews, claimSummary) {
1180
+ return `## Topic
1181
+ ${topic}
1182
+
1183
+ ## Claim Verification Status
1184
+ ${formatClaimSummaryForConsensus(claimSummary)}
1185
+
1186
+ ## Proposed Plans
1187
+ ${formatReports(reports)}
1188
+
1189
+ ## Peer Reviews
1190
+ ${formatFindingReviews(reviews)}
1191
+
1192
+ Synthesize a final implementation roadmap.
1193
+ Requirements:
1194
+ - Verified claims should form the backbone of the roadmap.
1195
+ - Unresolved claims should appear as open questions or conditional phases.
1196
+ - Produce 3 to 6 roadmap phases with sequencing, dependencies, deliverables, and success criteria.
1197
+ - Use nextActions only for immediate follow-up work.`;
1198
+ }
1199
+ };
1200
+
1201
+ // src/arena/lenses/index.ts
1202
+ init_esm_shims();
1203
+
1204
+ // src/arena/lenses/engineering.ts
1205
+ init_esm_shims();
1206
+ var engineeringLens = {
1207
+ name: "engineering",
1208
+ label: "Engineering",
1209
+ participantRole: "a software engineer focused on code quality, correctness, and maintainability",
1210
+ reviewerRole: "an engineering peer reviewer evaluating technical rigor and code health",
1211
+ moderatorRole: "a tech lead synthesizing engineering perspectives into actionable conclusions",
1212
+ summaryLabel: "Engineering Assessment",
1213
+ criteria: [
1214
+ "Code correctness and edge case handling",
1215
+ "Error handling and resilience",
1216
+ "Performance and scalability implications",
1217
+ "API design and interface clarity",
1218
+ "Test coverage and testability",
1219
+ "Maintainability and readability",
1220
+ "Security considerations",
1221
+ "Backward compatibility"
1222
+ ],
1223
+ preferredFindingKinds: ["risk", "improvement", "strength", "question"]
1224
+ };
1225
+
1226
+ // src/arena/lenses/product.ts
1227
+ init_esm_shims();
1228
+ var productLens = {
1229
+ name: "product",
1230
+ label: "Product",
1231
+ participantRole: "a product analyst focused on user value, completeness, and edge cases",
1232
+ reviewerRole: "a product reviewer evaluating requirements coverage and user impact",
1233
+ moderatorRole: "a product lead synthesizing product perspectives into prioritized insights",
1234
+ summaryLabel: "Product Assessment",
1235
+ criteria: [
1236
+ "Requirements completeness and coverage",
1237
+ "User experience and usability",
1238
+ "Edge cases and boundary conditions",
1239
+ "Acceptance criteria clarity",
1240
+ "Feature scope \u2014 too broad or too narrow",
1241
+ "User journey coherence",
1242
+ "Metric and success criteria definition",
1243
+ "Stakeholder alignment"
1244
+ ],
1245
+ preferredFindingKinds: ["question", "improvement", "risk", "strength"]
1246
+ };
1247
+
1248
+ // src/arena/lenses/architecture.ts
1249
+ init_esm_shims();
1250
+ var architectureLens = {
1251
+ name: "architecture",
1252
+ label: "Architecture",
1253
+ participantRole: "a system architect focused on boundaries, modularity, and evolution paths",
1254
+ reviewerRole: "an architecture reviewer evaluating structural decisions and trade-offs",
1255
+ moderatorRole: "a chief architect synthesizing architectural perspectives into design guidance",
1256
+ summaryLabel: "Architecture Assessment",
1257
+ criteria: [
1258
+ "Module boundaries and responsibility separation",
1259
+ "Coupling and cohesion",
1260
+ "Extensibility and evolution path",
1261
+ "Dependency management",
1262
+ "Data flow and state management",
1263
+ "API surface area and abstraction levels",
1264
+ "Migration and backward compatibility strategy",
1265
+ "Operational concerns (monitoring, debugging, deployment)"
1266
+ ],
1267
+ preferredFindingKinds: ["improvement", "risk", "question", "strength"]
1268
+ };
1269
+
1270
+ // src/arena/lenses/general.ts
1271
+ init_esm_shims();
1272
+ var generalLens = {
1273
+ name: "general",
1274
+ label: "General",
1275
+ participantRole: "an analyst providing a broad, balanced perspective",
1276
+ reviewerRole: "a peer reviewer evaluating clarity, logic, and completeness",
1277
+ moderatorRole: "a neutral moderator synthesizing diverse perspectives into balanced conclusions",
1278
+ summaryLabel: "General Assessment",
1279
+ criteria: [
1280
+ "Logical coherence and consistency",
1281
+ "Completeness of analysis",
1282
+ "Trade-off identification",
1283
+ "Assumption clarity",
1284
+ "Evidence quality",
1285
+ "Actionability of recommendations"
1286
+ ],
1287
+ preferredFindingKinds: ["strength", "risk", "question", "improvement"]
1288
+ };
1289
+
1290
+ // src/arena/lenses/index.ts
1291
+ var LENS_MAP = {
1292
+ engineering: engineeringLens,
1293
+ product: productLens,
1294
+ architecture: architectureLens,
1295
+ general: generalLens
1296
+ };
1297
+ function getLens(name) {
1298
+ return LENS_MAP[name];
1299
+ }
1300
+ function resolveLenses(refs) {
1301
+ return refs.map((ref) => LENS_MAP[ref.name]);
1302
+ }
1303
+ function buildLensPrompt(lenses, phase) {
1304
+ if (lenses.length === 0) return "";
1305
+ const roleKey = phase === "participant" ? "participantRole" : phase === "reviewer" ? "reviewerRole" : "moderatorRole";
1306
+ const roles = lenses.map((l) => l[roleKey]);
1307
+ const allCriteria = lenses.flatMap((l) => l.criteria);
1308
+ const uniqueCriteria = [...new Set(allCriteria)];
1309
+ const roleDesc = lenses.length === 1 ? `You are ${roles[0]}.` : `You combine multiple perspectives: ${roles.join("; ")}.`;
1310
+ return [
1311
+ roleDesc,
1312
+ "",
1313
+ "Evaluation criteria (prioritized):",
1314
+ ...uniqueCriteria.map((c) => `- ${c}`)
1315
+ ].join("\n");
1316
+ }
1317
+ var LENS_NAMES = ["engineering", "product", "architecture", "general"];
1318
+
1319
+ // src/arena/strategies/index.ts
1320
+ init_esm_shims();
1321
+
1322
+ // src/arena/strategies/lens-wrapper.ts
1323
+ init_esm_shims();
1324
+ function withLens(strategy, plan) {
1325
+ const lenses = resolveLenses(plan.lenses);
1326
+ if (lenses.length === 0) return strategy;
1327
+ const participantLensPrompt = buildLensPrompt(lenses, "participant");
1328
+ const reviewerLensPrompt = buildLensPrompt(lenses, "reviewer");
1329
+ const moderatorLensPrompt = buildLensPrompt(lenses, "moderator");
1330
+ const participantPlanPrompt = buildPlanPrompt(plan, "participant");
1331
+ const reviewerPlanPrompt = buildPlanPrompt(plan, "reviewer");
1332
+ const moderatorPlanPrompt = buildPlanPrompt(plan, "moderator");
1333
+ return {
1334
+ researchSystemPrompt(name) {
1335
+ return [
1336
+ strategy.researchSystemPrompt(name),
1337
+ "",
1338
+ "\u2500\u2500 Analysis Perspective \u2500\u2500",
1339
+ participantLensPrompt,
1340
+ "",
1341
+ "\u2500\u2500 Scenario Support \u2500\u2500",
1342
+ participantPlanPrompt
1343
+ ].join("\n");
1344
+ },
1345
+ researchUserPrompt(topic, ctx) {
1346
+ return [formatPlanBrief(plan), "", strategy.researchUserPrompt(topic, ctx)].join("\n");
1347
+ },
1348
+ parseResearchResponse(participant, text) {
1349
+ return strategy.parseResearchResponse(participant, text);
1350
+ },
1351
+ crossReviewSystemPrompt(reviewerName) {
1352
+ return [
1353
+ strategy.crossReviewSystemPrompt(reviewerName),
1354
+ "",
1355
+ "\u2500\u2500 Review Perspective \u2500\u2500",
1356
+ reviewerLensPrompt,
1357
+ "",
1358
+ "\u2500\u2500 Scenario Support \u2500\u2500",
1359
+ reviewerPlanPrompt
1360
+ ].join("\n");
1361
+ },
1362
+ crossReviewUserPrompt(topic, my, others) {
1363
+ return [formatPlanBrief(plan), "", strategy.crossReviewUserPrompt(topic, my, others)].join("\n");
1364
+ },
1365
+ parseCrossReviewResponse(reviewer, text) {
1366
+ return strategy.parseCrossReviewResponse(reviewer, text);
1367
+ },
1368
+ consensusSystemPrompt() {
1369
+ return [
1370
+ strategy.consensusSystemPrompt(),
1371
+ "",
1372
+ "\u2500\u2500 Moderator Perspective \u2500\u2500",
1373
+ moderatorLensPrompt,
1374
+ "",
1375
+ "\u2500\u2500 Scenario Support \u2500\u2500",
1376
+ moderatorPlanPrompt
1377
+ ].join("\n");
1378
+ },
1379
+ consensusUserPrompt(topic, reports, reviews) {
1380
+ return [formatPlanBrief(plan), "", strategy.consensusUserPrompt(topic, reports, reviews)].join("\n");
1381
+ },
1382
+ parseConsensusResponse(text) {
1383
+ return strategy.parseConsensusResponse(text);
1384
+ },
1385
+ preferredFindingKinds() {
1386
+ const modeKinds = strategy.preferredFindingKinds();
1387
+ const lensKinds = lenses.flatMap((l) => l.preferredFindingKinds);
1388
+ const planKinds = plan.outputShape.emphasize;
1389
+ const seen = /* @__PURE__ */ new Set();
1390
+ const result = [];
1391
+ for (const k of [...planKinds, ...modeKinds, ...lensKinds]) {
1392
+ if (!seen.has(k)) {
1393
+ seen.add(k);
1394
+ result.push(k);
1395
+ }
1396
+ }
1397
+ return result;
1398
+ },
1399
+ // ─── V2 forwarding (conditional) ─────────────────────────────
1400
+ ...isStrategyV2(strategy) ? {
1401
+ verificationReviewUserPrompt(topic, myReport, claims, digest) {
1402
+ return [formatPlanBrief(plan), "", strategy.verificationReviewUserPrompt(topic, myReport, claims, digest)].join("\n");
1403
+ },
1404
+ parseVerificationReviewResponse(reviewer, text) {
1405
+ return strategy.parseVerificationReviewResponse(reviewer, text);
1406
+ },
1407
+ debateTurnUserPrompt(topic, claim, priorTurns, digest) {
1408
+ return [formatPlanBrief(plan), "", strategy.debateTurnUserPrompt(topic, claim, priorTurns, digest)].join("\n");
1409
+ },
1410
+ parseDebateTurnResponse(participant, text) {
1411
+ return strategy.parseDebateTurnResponse(participant, text);
1412
+ },
1413
+ adjudicationUserPrompt(topic, claim, rounds, digest) {
1414
+ return [formatPlanBrief(plan), "", strategy.adjudicationUserPrompt(topic, claim, rounds, digest)].join("\n");
1415
+ },
1416
+ parseAdjudicationResponse(text) {
1417
+ return strategy.parseAdjudicationResponse(text);
1418
+ },
1419
+ claimAwareConsensusUserPrompt(topic, reports, reviews, claimSummary) {
1420
+ return [formatPlanBrief(plan), "", strategy.claimAwareConsensusUserPrompt(topic, reports, reviews, claimSummary)].join("\n");
1421
+ }
1422
+ } : {},
1423
+ // ─── Planning forwarding (conditional) ──────────────────────
1424
+ ...isStrategyPlanning(strategy) ? {
1425
+ mergeReviewUserPrompt(topic, myReport, claims, digest) {
1426
+ return [formatPlanBrief(plan), "", strategy.mergeReviewUserPrompt(topic, myReport, claims, digest)].join("\n");
1427
+ },
1428
+ parseMergeReviewResponse(reviewer, text) {
1429
+ return strategy.parseMergeReviewResponse(reviewer, text);
1430
+ },
1431
+ detailExpansionSystemPrompt() {
1432
+ return [
1433
+ strategy.detailExpansionSystemPrompt(),
1434
+ "",
1435
+ "\u2500\u2500 Moderator Perspective \u2500\u2500",
1436
+ moderatorLensPrompt
1437
+ ].join("\n");
1438
+ },
1439
+ detailExpansionUserPrompt(topic, phase, digest) {
1440
+ return [formatPlanBrief(plan), "", strategy.detailExpansionUserPrompt(topic, phase, digest)].join("\n");
1441
+ },
1442
+ parseDetailExpansionResponse(text) {
1443
+ return strategy.parseDetailExpansionResponse(text);
1444
+ }
1445
+ } : {}
1446
+ };
1447
+ }
1448
+ function buildPlanPrompt(plan, phase) {
1449
+ const sources = plan.sources.map((s) => s.kind).join(", ");
1450
+ const targets = formatTargets(plan.subject.targets);
1451
+ const emphasis = formatEmphasis(plan.outputShape.emphasize);
1452
+ const notes = [
1453
+ `Subject: ${plan.subject.kind} \u2014 ${plan.subject.label}${targets ? ` (${targets})` : ""}`,
1454
+ `Evidence sources: ${sources || "none"}`,
1455
+ `Overview label: ${plan.outputShape.overviewLabel}`,
1456
+ `Emphasize these finding types first: ${emphasis}`,
1457
+ "Only draw conclusions from available evidence. When evidence is thin, narrow the claim or call it out explicitly.",
1458
+ ...buildScenarioNotes(plan, phase)
1459
+ ];
1460
+ return notes.map((line) => `- ${line}`).join("\n");
1461
+ }
1462
+ function formatPlanBrief(plan) {
1463
+ const targets = formatTargets(plan.subject.targets);
1464
+ const lenses = plan.lenses.map((l) => l.name).join(", ");
1465
+ const sources = plan.sources.map((s) => s.kind).join(", ");
1466
+ return [
1467
+ "## Arena Plan",
1468
+ `- Mode: ${plan.mode}`,
1469
+ `- Subject: ${plan.subject.kind} \u2014 ${plan.subject.label}${targets ? ` (${targets})` : ""}`,
1470
+ `- Lenses: ${lenses || "general"}`,
1471
+ `- Sources: ${sources || "none"}`,
1472
+ `- Output focus: ${formatEmphasis(plan.outputShape.emphasize)}`,
1473
+ `- Overview label: ${plan.outputShape.overviewLabel}`
1474
+ ].join("\n");
1475
+ }
1476
+ function buildScenarioNotes(plan, phase) {
1477
+ const notes = [];
1478
+ switch (plan.subject.kind) {
1479
+ case "changes":
1480
+ notes.push(
1481
+ phase === "participant" ? "Treat this as a change-focused analysis: inspect behavioral impact, regressions, interfaces, and compatibility." : phase === "reviewer" ? "Challenge findings that are not grounded in changed behavior, affected files, or nearby code paths." : "Summarize the concrete impact of the changes before giving judgment."
1482
+ );
1483
+ break;
1484
+ case "files":
1485
+ notes.push(
1486
+ phase === "participant" ? "Stay anchored to the named files/modules and their immediate call sites instead of drifting into unrelated areas." : phase === "reviewer" ? "Prioritize corrections to claims that overgeneralize beyond the named files/modules." : "Keep the conclusion scoped to the named files/modules and their direct implications."
1487
+ );
1488
+ break;
1489
+ case "docs":
1490
+ notes.push(
1491
+ phase === "participant" ? "Treat this as a document-centric scene: look for ambiguity, missing acceptance criteria, edge cases, and implementation gaps." : phase === "reviewer" ? "Challenge findings that skip over unclear requirements, contradictory wording, or unsupported feasibility assumptions." : "Synthesize the document review around completeness, feasibility, and decision-ready gaps."
1492
+ );
1493
+ break;
1494
+ case "topic":
1495
+ notes.push(
1496
+ phase === "participant" ? "Treat this as a topic discussion: surface assumptions, trade-offs, and decision criteria instead of pretending there is hard repo evidence." : phase === "reviewer" ? "Push back on overconfident claims and preserve unresolved trade-offs as open questions." : "Preserve disagreement where needed and make assumptions explicit."
1497
+ );
1498
+ break;
1499
+ case "mixed":
1500
+ notes.push(
1501
+ phase === "participant" ? "This is a mixed scene: reconcile code, docs, and topic-level evidence instead of analyzing each source in isolation." : phase === "reviewer" ? "Check whether claims actually connect the different evidence sources, rather than citing only one side." : "Unify the conclusion across repo facts, documents, and higher-level reasoning."
1502
+ );
1503
+ break;
1504
+ }
1505
+ const sourceKinds = new Set(plan.sources.map((s) => s.kind));
1506
+ if (sourceKinds.has("docs") && sourceKinds.has("repo")) {
1507
+ notes.push(
1508
+ phase === "moderator" ? "If documents and repo evidence diverge, call out the mismatch explicitly instead of collapsing it into a single conclusion." : "Cross-check document claims against the current repo structure when possible."
1509
+ );
1510
+ } else if (sourceKinds.has("web")) {
1511
+ notes.push(
1512
+ phase === "moderator" ? "Separate external references from local repo facts in the synthesis." : "Keep external research distinct from local evidence and label it clearly."
1513
+ );
1514
+ } else if (sourceKinds.has("none")) {
1515
+ notes.push("No external evidence is expected here; reason from the prompt and make assumptions visible.");
1516
+ }
1517
+ if (plan.mode === "planning") {
1518
+ notes.push(
1519
+ phase === "moderator" ? "When enough evidence exists, turn the conclusion into a staged roadmap with sequencing, dependencies, and success criteria." : "Prefer findings that help phase work, sequence dependencies, or expose migration/blocker risks."
1520
+ );
1521
+ }
1522
+ return notes;
1523
+ }
1524
+ function formatEmphasis(kinds) {
1525
+ return kinds.length > 0 ? kinds.join(", ") : "risk, improvement";
1526
+ }
1527
+ function formatTargets(targets) {
1528
+ return Array.isArray(targets) && targets.length > 0 ? targets.join(", ") : "";
1529
+ }
1530
+
1531
+ // src/arena/strategies/index.ts
1532
+ var STRATEGY_MAP = {
1533
+ review: () => new ReviewStrategy(),
1534
+ discussion: () => new DiscussionStrategy(),
1535
+ planning: () => new PlanningStrategy()
1536
+ };
1537
+ function getStrategy(mode) {
1538
+ return STRATEGY_MAP[mode]();
1539
+ }
1540
+ function getStrategyForPlan(plan) {
1541
+ const base = STRATEGY_MAP[plan.mode]();
1542
+ return withLens(base, plan);
1543
+ }
1544
+
1545
+ // src/arena/planner.ts
1546
+ init_esm_shims();
1547
+ var PLANNER_SYSTEM_PROMPT = `You are the planner for a multi-model collaborative analysis tool called Arena.
1548
+
1549
+ Given a user's natural language request, produce an execution plan. You must determine:
1550
+
1551
+ 1. **mode** \u2014 how to collaborate:
1552
+ - "review": find issues, verify quality, give a structured verdict
1553
+ - "discussion": explore trade-offs, compare viewpoints, preserve disagreements
1554
+ - "planning": build a roadmap, identify phases, dependencies, and risks
1555
+
1556
+ 2. **lenses** \u2014 from what analytical perspectives (can be multiple):
1557
+ - "engineering": code quality, correctness, performance, maintainability
1558
+ - "product": user value, requirements completeness, acceptance criteria, UX
1559
+ - "architecture": system boundaries, modularity, coupling, evolution paths
1560
+ - "general": broad analysis, logic, trade-offs (use as fallback)
1561
+
1562
+ 3. **sources** \u2014 where to gather evidence (can be multiple):
1563
+ - "git": diffs, commit history, branch comparison, changed files
1564
+ - "repo": directory structure, source code files, symbol search
1565
+ - "docs": markdown/text documents, PRDs, design docs
1566
+ - "web": external information, standards, competitor analysis
1567
+ - "none": pure topic discussion, no external evidence needed
1568
+
1569
+ 4. **subject** \u2014 what is being analyzed:
1570
+ - kind: "changes" (code changes), "files" (specific files), "docs" (documents), "topic" (abstract topic), "mixed"
1571
+ - label: human-readable description
1572
+ - targets: specific file paths, branch names, or doc names if applicable
1573
+
1574
+ 5. **outputShape** \u2014 what to emphasize in the output
1575
+
1576
+ Respond ONLY with JSON, no markdown fences:
1577
+ {
1578
+ "mode": "review|discussion|planning",
1579
+ "lenses": [{"name": "engineering|product|architecture|general", "weight": 1.0}],
1580
+ "sources": [{"kind": "git|repo|docs|web|none", "targets": ["optional specific targets"]}],
1581
+ "subject": {"kind": "changes|files|docs|topic|mixed", "label": "description", "targets": ["optional"]},
1582
+ "outputShape": {"overviewLabel": "e.g. What Changed / Current Scope / Problem Framing", "emphasize": ["risk", "improvement"]},
1583
+ "confidence": "high|medium|low",
1584
+ "followUpQuestion": "question if confidence is low, or null"
1585
+ }`;
1586
+ async function planArena(topic, llmConfig, flags, signal) {
1587
+ if (flags?.mode && flags?.base) {
1588
+ return buildExplicitPlan(topic, flags);
1589
+ }
1590
+ try {
1591
+ signal?.throwIfAborted();
1592
+ const client = await createLLMClient({
1593
+ ...llmConfig,
1594
+ enableStreaming: false,
1595
+ maxTokens: 1024
1596
+ });
1597
+ const response = await client.createMessage({
1598
+ systemPrompt: PLANNER_SYSTEM_PROMPT,
1599
+ messages: [{ role: "user", content: `<user_request>
1600
+ ${topic}
1601
+ </user_request>
1602
+
1603
+ Analyze the user request above and output the arena plan as JSON.` }],
1604
+ maxTokens: 1024,
1605
+ signal
1606
+ });
1607
+ const plan = parsePlanResponse(response.text, topic);
1608
+ if (flags?.mode) plan.mode = flags.mode;
1609
+ if (flags?.base) {
1610
+ plan.sources = [{ kind: "git", targets: [flags.base, flags.head ?? "HEAD"] }];
1611
+ plan.subject = { kind: "changes", label: `${flags.base}...${flags.head ?? "HEAD"}`, targets: [flags.base, flags.head ?? "HEAD"] };
1612
+ }
1613
+ logger.info("arena.planner", { plan });
1614
+ return plan;
1615
+ } catch (err) {
1616
+ logger.warn("arena.planner_fallback", { error: err.message });
1617
+ return buildFallbackPlan(topic, flags);
1618
+ }
1619
+ }
1620
+ function parsePlanResponse(text, topic) {
1621
+ const fenced = text.match(/```(?:json)?\s*\n?([\s\S]*?)\n?```/);
1622
+ const jsonStr = fenced ? fenced[1].trim() : text.match(/\{[\s\S]*\}/)?.[0] ?? text;
1623
+ try {
1624
+ const parsed = JSON.parse(jsonStr);
1625
+ return {
1626
+ mode: validateMode(parsed.mode),
1627
+ lenses: parseLenses(parsed.lenses),
1628
+ sources: parseSources(parsed.sources),
1629
+ subject: parseSubject(parsed.subject, topic),
1630
+ outputShape: parseOutputShape(parsed.outputShape, parsed.mode),
1631
+ confidence: validateConfidence(parsed.confidence),
1632
+ followUpQuestion: parsed.followUpQuestion || void 0
1633
+ };
1634
+ } catch {
1635
+ return buildFallbackPlan(topic);
1636
+ }
1637
+ }
1638
+ function buildExplicitPlan(topic, flags) {
1639
+ return {
1640
+ mode: flags.mode,
1641
+ lenses: [{ name: "engineering", weight: 1 }],
1642
+ sources: [
1643
+ { kind: "git", targets: [flags.base, flags.head ?? "HEAD"] },
1644
+ { kind: "repo" }
1645
+ ],
1646
+ subject: {
1647
+ kind: "changes",
1648
+ label: `${flags.base}...${flags.head ?? "HEAD"}`,
1649
+ targets: [flags.base, flags.head ?? "HEAD"]
1650
+ },
1651
+ outputShape: {
1652
+ overviewLabel: "What Changed",
1653
+ emphasize: ["risk", "improvement"]
1654
+ },
1655
+ confidence: "high"
1656
+ };
1657
+ }
1658
+ function buildFallbackPlan(topic, flags) {
1659
+ if (flags?.base) {
1660
+ return {
1661
+ mode: flags.mode ?? "review",
1662
+ lenses: [{ name: "engineering", weight: 1 }],
1663
+ sources: [{ kind: "git" }, { kind: "repo" }],
1664
+ subject: { kind: "changes", label: topic, targets: [flags.base, flags.head ?? "HEAD"] },
1665
+ outputShape: {
1666
+ overviewLabel: "What Changed",
1667
+ emphasize: ["risk", "improvement"]
1668
+ },
1669
+ confidence: "low"
1670
+ };
1671
+ }
1672
+ const lower = topic.toLowerCase();
1673
+ const hasDoc = /\b(prd|doc|docs|spec|rfc|design doc|requirement|proposal)\b/i.test(topic) || /(文档|需求|方案)/.test(topic);
1674
+ const hasRoadmap = /\b(roadmap|plan|planning|strategy|migration|refactor)\b/i.test(topic) || /(演进|路线图|规划|重构)/.test(topic);
1675
+ const hasFeasibility = /\b(feasibility|feasible|can we|should we|trade-?off)\b/i.test(topic) || /(可行|能不能|值不值得|取舍)/.test(topic);
1676
+ const hasReview = /\b(review|pr|diff|patch|change)\b/i.test(topic) || /(改动|评审|审查)/.test(topic);
1677
+ const hasRepo = /\b(repo|repository|codebase|module|architecture)\b/i.test(topic) || /(代码库|仓库|模块|架构)/.test(topic);
1678
+ if (hasRoadmap) {
1679
+ return {
1680
+ mode: "planning",
1681
+ lenses: hasDoc ? [{ name: "architecture", weight: 1 }, { name: "product", weight: 0.7 }] : [{ name: "architecture", weight: 1 }, { name: "engineering", weight: 0.8 }],
1682
+ sources: hasDoc ? [{ kind: "docs" }, ...hasRepo ? [{ kind: "repo" }] : []] : [{ kind: "repo" }, { kind: "docs" }],
1683
+ subject: { kind: hasDoc ? "mixed" : "topic", label: topic },
1684
+ outputShape: {
1685
+ overviewLabel: "Current Scope",
1686
+ emphasize: ["improvement", "risk", "question"]
1687
+ },
1688
+ confidence: "low"
1689
+ };
1690
+ }
1691
+ if (hasDoc && hasFeasibility) {
1692
+ return {
1693
+ mode: "discussion",
1694
+ lenses: [{ name: "product", weight: 1 }, { name: "engineering", weight: 0.8 }],
1695
+ sources: hasRepo ? [{ kind: "docs" }, { kind: "repo" }] : [{ kind: "docs" }],
1696
+ subject: { kind: hasRepo ? "mixed" : "docs", label: topic },
1697
+ outputShape: {
1698
+ overviewLabel: "Problem Framing",
1699
+ emphasize: ["question", "risk", "improvement"]
1700
+ },
1701
+ confidence: "low"
1702
+ };
1703
+ }
1704
+ if (hasDoc) {
1705
+ return {
1706
+ mode: hasReview ? "review" : "discussion",
1707
+ lenses: [{ name: "product", weight: 1 }, { name: "architecture", weight: 0.6 }],
1708
+ sources: hasRepo ? [{ kind: "docs" }, { kind: "repo" }] : [{ kind: "docs" }],
1709
+ subject: { kind: hasRepo ? "mixed" : "docs", label: topic },
1710
+ outputShape: {
1711
+ overviewLabel: hasReview ? "Current Scope" : "Problem Framing",
1712
+ emphasize: ["question", "improvement", "risk"]
1713
+ },
1714
+ confidence: "low"
1715
+ };
1716
+ }
1717
+ if (hasFeasibility) {
1718
+ return {
1719
+ mode: "discussion",
1720
+ lenses: hasRepo ? [{ name: "product", weight: 1 }, { name: "engineering", weight: 0.8 }] : [{ name: "general", weight: 1 }, { name: "product", weight: 0.6 }],
1721
+ sources: hasRepo ? [{ kind: "repo" }, { kind: "docs" }] : [{ kind: "none" }],
1722
+ subject: { kind: hasRepo ? "topic" : "topic", label: topic },
1723
+ outputShape: {
1724
+ overviewLabel: "Problem Framing",
1725
+ emphasize: ["question", "risk", "improvement"]
1726
+ },
1727
+ confidence: "low"
1728
+ };
1729
+ }
1730
+ if (hasReview || /\b(commit|branch|diff|patch|bug|fix|回归)\b/i.test(lower)) {
1731
+ return {
1732
+ mode: "review",
1733
+ lenses: [{ name: "engineering", weight: 1 }],
1734
+ sources: [{ kind: "git" }, { kind: "repo" }],
1735
+ subject: { kind: "changes", label: topic },
1736
+ outputShape: {
1737
+ overviewLabel: "What Changed",
1738
+ emphasize: ["risk", "improvement", "question"]
1739
+ },
1740
+ confidence: "low"
1741
+ };
1742
+ }
1743
+ return {
1744
+ mode: flags?.mode ?? "review",
1745
+ lenses: [{ name: hasRepo ? "architecture" : "general", weight: 1 }],
1746
+ sources: hasRepo ? [{ kind: "repo" }, { kind: "docs" }] : [{ kind: "none" }],
1747
+ subject: { kind: "topic", label: topic },
1748
+ outputShape: {
1749
+ overviewLabel: hasRepo ? "Current Scope" : "Problem Framing",
1750
+ emphasize: hasRepo ? ["improvement", "risk", "question"] : ["question", "risk", "improvement"]
1751
+ },
1752
+ confidence: "low"
1753
+ };
1754
+ }
1755
+ function validateMode(v) {
1756
+ if (v === "review" || v === "discussion" || v === "planning") return v;
1757
+ return "review";
1758
+ }
1759
+ function validateConfidence(v) {
1760
+ if (v === "high" || v === "medium" || v === "low") return v;
1761
+ return "medium";
1762
+ }
1763
+ function parseLenses(v) {
1764
+ if (!Array.isArray(v) || v.length === 0) {
1765
+ return [{ name: "general", weight: 1 }];
1766
+ }
1767
+ const result = v.filter((item) => LENS_NAMES.includes(item?.name)).map((item) => ({
1768
+ name: item.name,
1769
+ weight: typeof item.weight === "number" ? item.weight : 1
1770
+ }));
1771
+ return result.length > 0 ? result : [{ name: "general", weight: 1 }];
1772
+ }
1773
+ function parseSources(v) {
1774
+ if (!Array.isArray(v) || v.length === 0) {
1775
+ return [{ kind: "none" }];
1776
+ }
1777
+ const validKinds = ["git", "repo", "docs", "web", "none"];
1778
+ const result = v.filter((item) => validKinds.includes(item?.kind)).map((item) => ({
1779
+ kind: item.kind,
1780
+ targets: Array.isArray(item.targets) ? item.targets : void 0
1781
+ }));
1782
+ return result.length > 0 ? result : [{ kind: "none" }];
1783
+ }
1784
+ function parseSubject(v, topic) {
1785
+ if (!v || typeof v !== "object") {
1786
+ return { kind: "topic", label: topic };
1787
+ }
1788
+ const obj = v;
1789
+ const validKinds = ["changes", "files", "docs", "topic", "mixed"];
1790
+ return {
1791
+ kind: validKinds.includes(obj.kind) ? obj.kind : "topic",
1792
+ label: obj.label ?? topic,
1793
+ targets: Array.isArray(obj.targets) ? obj.targets : void 0
1794
+ };
1795
+ }
1796
+ var VALID_EMPHASIZE = /* @__PURE__ */ new Set(["strength", "improvement", "risk", "question"]);
1797
+ function parseOutputShape(v, mode) {
1798
+ if (v && typeof v === "object") {
1799
+ const obj = v;
1800
+ return {
1801
+ overviewLabel: obj.overviewLabel ?? "Overview",
1802
+ emphasize: Array.isArray(obj.emphasize) ? obj.emphasize.filter((k) => VALID_EMPHASIZE.has(k)) : ["risk", "improvement"]
1803
+ };
1804
+ }
1805
+ switch (mode) {
1806
+ case "review":
1807
+ return { overviewLabel: "What Changed", emphasize: ["risk", "improvement"] };
1808
+ case "discussion":
1809
+ return { overviewLabel: "Problem Framing", emphasize: ["strength", "risk", "question"] };
1810
+ case "planning":
1811
+ return { overviewLabel: "Current Scope", emphasize: ["improvement", "risk"] };
1812
+ default:
1813
+ return { overviewLabel: "Overview", emphasize: ["risk", "improvement"] };
1814
+ }
1815
+ }
1816
+
1817
+ // src/arena/providers/index.ts
1818
+ init_esm_shims();
1819
+
1820
+ // src/arena/providers/git.ts
1821
+ init_esm_shims();
1822
+ import { execFileSync } from "child_process";
1823
+ var MAX_DIFF_CHARS = 2e4;
1824
+ var MAX_CHANGED_FILES = 30;
1825
+ var gitProvider = {
1826
+ kind: "git",
1827
+ collect(plan, _topic) {
1828
+ const artifacts = [];
1829
+ const targets = plan.sources.find((s) => s.kind === "git")?.targets;
1830
+ const baseRef = sanitizeRef(targets?.[0]);
1831
+ const headRef = sanitizeRef(targets?.[1]) ?? "HEAD";
1832
+ const isCompare = !!baseRef;
1833
+ const currentBranch = git(["rev-parse", "--abbrev-ref", "HEAD"]);
1834
+ if (currentBranch) {
1835
+ artifacts.push({
1836
+ id: "git-branch",
1837
+ kind: "doc",
1838
+ source: "git",
1839
+ title: "Current Branch",
1840
+ preview: currentBranch
1841
+ });
1842
+ }
1843
+ const logArgs = isCompare ? ["log", "--oneline", `${baseRef}..${headRef}`, "--max-count=20"] : ["log", "--oneline", "-10"];
1844
+ const log = git(logArgs);
1845
+ if (log) {
1846
+ artifacts.push({
1847
+ id: "git-log",
1848
+ kind: "doc",
1849
+ source: "git",
1850
+ title: "Commit Log",
1851
+ preview: log
1852
+ });
1853
+ }
1854
+ const statArgs = isCompare ? ["diff", "--stat", `${baseRef}...${headRef}`] : ["diff", "--stat", "HEAD"];
1855
+ let stat = git(statArgs);
1856
+ if (!stat && !isCompare) stat = git(["diff", "--stat", "--cached"]);
1857
+ if (stat) {
1858
+ artifacts.push({
1859
+ id: "git-diffstat",
1860
+ kind: "doc",
1861
+ source: "git",
1862
+ title: "Diff Stat",
1863
+ preview: stat
1864
+ });
1865
+ }
1866
+ const filesArgs = isCompare ? ["diff", "--name-status", `${baseRef}...${headRef}`] : ["diff", "--name-status", "HEAD"];
1867
+ let changedFiles = git(filesArgs);
1868
+ if (!changedFiles && !isCompare) changedFiles = git(["diff", "--name-status", "--cached"]);
1869
+ if (changedFiles) {
1870
+ const allChanged = changedFiles.split("\n").filter(Boolean);
1871
+ const limited = allChanged.slice(0, MAX_CHANGED_FILES);
1872
+ if (allChanged.length > MAX_CHANGED_FILES) {
1873
+ limited.push(`... and ${allChanged.length - MAX_CHANGED_FILES} more files`);
1874
+ }
1875
+ artifacts.push({
1876
+ id: "git-changed-files",
1877
+ kind: "doc",
1878
+ source: "git",
1879
+ title: "Changed Files",
1880
+ preview: limited.join("\n"),
1881
+ metadata: { totalCount: allChanged.length }
1882
+ });
1883
+ const paths = allChanged.map((line) => line.split(" ").slice(1).join(" ")).filter(Boolean);
1884
+ const dirCounts = clusterByDirectory(paths);
1885
+ if (dirCounts.length > 0) {
1886
+ artifacts.push({
1887
+ id: "git-dir-clusters",
1888
+ kind: "doc",
1889
+ source: "git",
1890
+ title: "Changes by Directory",
1891
+ preview: dirCounts.slice(0, 15).map(([dir, count]) => ` ${dir}/ (${count} files)`).join("\n")
1892
+ });
1893
+ }
1894
+ }
1895
+ const diffArgs = isCompare ? ["diff", `${baseRef}...${headRef}`] : ["diff", "HEAD"];
1896
+ let diff = git(diffArgs);
1897
+ if (!diff && !isCompare) diff = git(["diff", "--cached"]);
1898
+ if (diff) {
1899
+ const truncated = diff.length > MAX_DIFF_CHARS;
1900
+ const preview = truncated ? diff.slice(0, MAX_DIFF_CHARS).slice(0, diff.slice(0, MAX_DIFF_CHARS).lastIndexOf("\n")) : diff;
1901
+ artifacts.push({
1902
+ id: "git-diff",
1903
+ kind: "diff",
1904
+ source: "git",
1905
+ title: "Diff",
1906
+ preview: preview + (truncated ? `
1907
+
1908
+ ... TRUNCATED (${diff.length} chars total). Use read_file to inspect specific files.` : ""),
1909
+ metadata: { totalChars: diff.length, truncated }
1910
+ });
1911
+ }
1912
+ if (!diff && !stat) {
1913
+ const status = git(["status", "--short"]);
1914
+ if (status) {
1915
+ artifacts.push({
1916
+ id: "git-status",
1917
+ kind: "doc",
1918
+ source: "git",
1919
+ title: "Git Status",
1920
+ preview: status
1921
+ });
1922
+ }
1923
+ }
1924
+ logger.info("arena.provider.git", {
1925
+ artifactCount: artifacts.length,
1926
+ hasCompare: isCompare
1927
+ });
1928
+ return artifacts;
1929
+ }
1930
+ };
1931
+ function git(args) {
1932
+ try {
1933
+ return execFileSync("git", args, {
1934
+ encoding: "utf-8",
1935
+ maxBuffer: 1024 * 1024,
1936
+ timeout: 1e4
1937
+ }).trim();
1938
+ } catch {
1939
+ return "";
1940
+ }
1941
+ }
1942
+ function sanitizeRef(ref) {
1943
+ if (!ref) return void 0;
1944
+ let cleaned = ref.replace(/\.{2,}/g, "");
1945
+ cleaned = cleaned.replace(/[^a-zA-Z0-9/_\-~^.]/g, "");
1946
+ return cleaned || void 0;
1947
+ }
1948
+ function clusterByDirectory(paths) {
1949
+ const counts = /* @__PURE__ */ new Map();
1950
+ for (const p of paths) {
1951
+ const parts = p.split("/");
1952
+ const dir = parts.length > 2 ? parts.slice(0, 2).join("/") : parts[0];
1953
+ counts.set(dir, (counts.get(dir) ?? 0) + 1);
1954
+ }
1955
+ return [...counts.entries()].sort((a, b) => b[1] - a[1]);
1956
+ }
1957
+
1958
+ // src/arena/providers/repo.ts
1959
+ init_esm_shims();
1960
+ import { existsSync, readdirSync, statSync, readFileSync } from "fs";
1961
+ import { join } from "path";
1962
+ import { execFileSync as execFileSync2 } from "child_process";
1963
+ var MAX_FILE_CHARS = 8e3;
1964
+ var repoProvider = {
1965
+ kind: "repo",
1966
+ collect(plan, topic) {
1967
+ const artifacts = [];
1968
+ const targets = plan.sources.find((s) => s.kind === "repo")?.targets ?? [];
1969
+ const tree = buildTree(".", 2);
1970
+ if (tree) {
1971
+ artifacts.push({
1972
+ id: "repo-tree",
1973
+ kind: "tree",
1974
+ source: "repo",
1975
+ title: "Project Structure",
1976
+ preview: tree
1977
+ });
1978
+ }
1979
+ for (const target of targets) {
1980
+ if (!existsSync(target)) continue;
1981
+ const st = statSync(target);
1982
+ if (st.isDirectory()) {
1983
+ const dirTree = buildTree(target, 3);
1984
+ if (dirTree) {
1985
+ artifacts.push({
1986
+ id: `repo-tree-${target}`,
1987
+ kind: "tree",
1988
+ source: "repo",
1989
+ title: `Directory: ${target}`,
1990
+ preview: dirTree
1991
+ });
1992
+ }
1993
+ for (const file of collectEntryFiles(target).slice(0, 3)) {
1994
+ const content = safeReadFile(file);
1995
+ if (content) {
1996
+ artifacts.push({
1997
+ id: `repo-file-${file}`,
1998
+ kind: "file",
1999
+ source: "repo",
2000
+ title: file,
2001
+ ref: file,
2002
+ preview: truncate(content)
2003
+ });
2004
+ }
2005
+ }
2006
+ } else {
2007
+ const content = safeReadFile(target);
2008
+ if (content) {
2009
+ artifacts.push({
2010
+ id: `repo-file-${target}`,
2011
+ kind: "file",
2012
+ source: "repo",
2013
+ title: target,
2014
+ ref: target,
2015
+ preview: truncate(content)
2016
+ });
2017
+ }
2018
+ }
2019
+ }
2020
+ if (targets.length === 0) {
2021
+ const hints = extractSearchHints(topic);
2022
+ for (const hint of hints.slice(0, 5)) {
2023
+ const grepResult = safeGrep(hint);
2024
+ if (grepResult) {
2025
+ const files = grepResult.split("\n").filter(Boolean).slice(0, 10);
2026
+ for (const file of files) {
2027
+ if (!artifacts.some((a) => a.ref === file)) {
2028
+ artifacts.push({
2029
+ id: `repo-grep-${hint}-${file}`,
2030
+ kind: "grep",
2031
+ source: "repo",
2032
+ title: `Match: ${hint} \u2192 ${file}`,
2033
+ ref: file,
2034
+ preview: file
2035
+ });
2036
+ }
2037
+ }
2038
+ }
2039
+ }
2040
+ }
2041
+ const hasGitSource = plan.sources.some((s) => s.kind === "git");
2042
+ if (!hasGitSource) {
2043
+ const recentLog = gitLog();
2044
+ if (recentLog) {
2045
+ artifacts.push({
2046
+ id: "repo-recent-activity",
2047
+ kind: "doc",
2048
+ source: "repo",
2049
+ title: "Recent Git Activity",
2050
+ preview: recentLog
2051
+ });
2052
+ }
2053
+ }
2054
+ logger.info("arena.provider.repo", { artifactCount: artifacts.length });
2055
+ return artifacts;
2056
+ }
2057
+ };
2058
+ function buildTree(dir, maxDepth, depth = 0, prefix = "") {
2059
+ if (depth >= maxDepth) return "";
2060
+ try {
2061
+ const entries = readdirSync(dir).filter(
2062
+ (e) => !e.startsWith(".") && e !== "node_modules" && e !== "dist" && e !== "__pycache__"
2063
+ );
2064
+ const lines = [];
2065
+ for (const entry of entries.slice(0, 30)) {
2066
+ const fullPath = join(dir, entry);
2067
+ const isDir = statSync(fullPath).isDirectory();
2068
+ lines.push(`${prefix}${isDir ? "/" : ""} ${entry}`);
2069
+ if (isDir && depth < maxDepth - 1) {
2070
+ lines.push(buildTree(fullPath, maxDepth, depth + 1, prefix + " "));
2071
+ }
2072
+ }
2073
+ return lines.filter(Boolean).join("\n");
2074
+ } catch {
2075
+ return "";
2076
+ }
2077
+ }
2078
+ function collectEntryFiles(dir) {
2079
+ const files = [];
2080
+ try {
2081
+ const entries = readdirSync(dir);
2082
+ const priority = ["index.ts", "index.js", "main.ts", "main.js", "mod.ts", "__init__.py"];
2083
+ for (const p of priority) {
2084
+ if (entries.includes(p)) files.push(join(dir, p));
2085
+ }
2086
+ for (const entry of entries) {
2087
+ const full = join(dir, entry);
2088
+ if (/\.(ts|js|tsx|jsx|py)$/.test(entry) && !files.includes(full)) {
2089
+ files.push(full);
2090
+ }
2091
+ }
2092
+ } catch {
2093
+ }
2094
+ return files;
2095
+ }
2096
+ function safeReadFile(filePath) {
2097
+ try {
2098
+ if (!existsSync(filePath)) return null;
2099
+ const st = statSync(filePath);
2100
+ if (st.size > 5e5) return null;
2101
+ return readFileSync(filePath, "utf-8");
2102
+ } catch {
2103
+ return null;
2104
+ }
2105
+ }
2106
+ function truncate(content) {
2107
+ if (content.length <= MAX_FILE_CHARS) return content;
2108
+ const t = content.slice(0, MAX_FILE_CHARS);
2109
+ const lastNl = t.lastIndexOf("\n");
2110
+ return t.slice(0, lastNl) + `
2111
+ ... (truncated, ${content.length} chars total)`;
2112
+ }
2113
+ function safeGrep(pattern) {
2114
+ try {
2115
+ const result = execFileSync2("grep", [
2116
+ "-rl",
2117
+ "--include=*.ts",
2118
+ "--include=*.js",
2119
+ "--include=*.py",
2120
+ "--include=*.md",
2121
+ "-i",
2122
+ pattern,
2123
+ "."
2124
+ ], { encoding: "utf-8", maxBuffer: 1024 * 1024, timeout: 1e4 });
2125
+ return result.trim();
2126
+ } catch {
2127
+ return "";
2128
+ }
2129
+ }
2130
+ function gitLog() {
2131
+ try {
2132
+ return execFileSync2("git", ["log", "--oneline", "-10"], {
2133
+ encoding: "utf-8",
2134
+ maxBuffer: 1024 * 1024,
2135
+ timeout: 1e4
2136
+ }).trim();
2137
+ } catch {
2138
+ return "";
2139
+ }
2140
+ }
2141
+ function extractSearchHints(topic) {
2142
+ const stopWords = /* @__PURE__ */ new Set([
2143
+ "the",
2144
+ "a",
2145
+ "an",
2146
+ "is",
2147
+ "are",
2148
+ "was",
2149
+ "were",
2150
+ "be",
2151
+ "been",
2152
+ "have",
2153
+ "has",
2154
+ "do",
2155
+ "does",
2156
+ "did",
2157
+ "will",
2158
+ "would",
2159
+ "could",
2160
+ "should",
2161
+ "may",
2162
+ "might",
2163
+ "to",
2164
+ "of",
2165
+ "in",
2166
+ "for",
2167
+ "on",
2168
+ "with",
2169
+ "at",
2170
+ "by",
2171
+ "from",
2172
+ "about",
2173
+ "and",
2174
+ "but",
2175
+ "or",
2176
+ "not",
2177
+ "this",
2178
+ "that",
2179
+ "my",
2180
+ "your",
2181
+ "what",
2182
+ "how",
2183
+ "review",
2184
+ "discuss",
2185
+ "plan",
2186
+ "help",
2187
+ "please",
2188
+ "look",
2189
+ "check",
2190
+ "\u4E00\u4E0B",
2191
+ "\u770B\u770B",
2192
+ "\u5E2E",
2193
+ "\u6211",
2194
+ "\u7684",
2195
+ "\u662F\u5426",
2196
+ "\u600E\u4E48",
2197
+ "\u5982\u4F55",
2198
+ "\u8BA8\u8BBA",
2199
+ "\u89C4\u5212",
2200
+ "\u5BA1\u67E5"
2201
+ ]);
2202
+ return topic.split(/[\s,;:]+/).map((w) => w.toLowerCase().replace(/[^a-z0-9_\-/]/g, "")).filter((w) => w.length > 2 && !stopWords.has(w));
2203
+ }
2204
+
2205
+ // src/arena/providers/docs.ts
2206
+ init_esm_shims();
2207
+ import { existsSync as existsSync2, readFileSync as readFileSync2, readdirSync as readdirSync2, statSync as statSync2 } from "fs";
2208
+ import { join as join2, extname } from "path";
2209
+ var MAX_DOC_CHARS = 1e4;
2210
+ var DOC_EXTENSIONS = /* @__PURE__ */ new Set([".md", ".txt", ".rst", ".adoc", ".org"]);
2211
+ var docsProvider = {
2212
+ kind: "docs",
2213
+ collect(plan, topic) {
2214
+ const artifacts = [];
2215
+ const sourceSpec = plan.sources.find((s) => s.kind === "docs");
2216
+ const targets = sourceSpec?.targets ?? [];
2217
+ for (const target of targets) {
2218
+ const content = safeReadDoc(target);
2219
+ if (content) {
2220
+ artifacts.push({
2221
+ id: `doc-${target}`,
2222
+ kind: "doc",
2223
+ source: "docs",
2224
+ title: target,
2225
+ ref: target,
2226
+ preview: truncate2(content)
2227
+ });
2228
+ }
2229
+ }
2230
+ if (targets.length === 0) {
2231
+ const docDirs = ["docs", "doc", "design", "specs", "proposals", "."];
2232
+ const found = /* @__PURE__ */ new Set();
2233
+ for (const dir of docDirs) {
2234
+ if (!existsSync2(dir)) continue;
2235
+ const docs = findDocFiles(dir, 2);
2236
+ for (const docPath of docs) {
2237
+ if (found.has(docPath)) continue;
2238
+ found.add(docPath);
2239
+ const name = docPath.toLowerCase();
2240
+ const topicLower = topic.toLowerCase();
2241
+ const keywords = topicLower.split(/\s+/).filter((w) => w.length > 2);
2242
+ const isRelevant = keywords.some((kw) => name.includes(kw));
2243
+ if (isRelevant || found.size <= 5) {
2244
+ const content = safeReadDoc(docPath);
2245
+ if (content) {
2246
+ artifacts.push({
2247
+ id: `doc-${docPath}`,
2248
+ kind: "doc",
2249
+ source: "docs",
2250
+ title: docPath,
2251
+ ref: docPath,
2252
+ preview: truncate2(content)
2253
+ });
2254
+ }
2255
+ }
2256
+ }
2257
+ }
2258
+ }
2259
+ logger.info("arena.provider.docs", { artifactCount: artifacts.length });
2260
+ return artifacts;
2261
+ }
2262
+ };
2263
+ function findDocFiles(dir, maxDepth, depth = 0) {
2264
+ if (depth >= maxDepth) return [];
2265
+ const files = [];
2266
+ try {
2267
+ const entries = readdirSync2(dir);
2268
+ for (const entry of entries) {
2269
+ if (entry.startsWith(".") || entry === "node_modules") continue;
2270
+ const full = join2(dir, entry);
2271
+ const st = statSync2(full);
2272
+ if (st.isFile() && DOC_EXTENSIONS.has(extname(entry).toLowerCase())) {
2273
+ files.push(full);
2274
+ } else if (st.isDirectory() && depth < maxDepth - 1) {
2275
+ files.push(...findDocFiles(full, maxDepth, depth + 1));
2276
+ }
2277
+ }
2278
+ } catch {
2279
+ }
2280
+ return files;
2281
+ }
2282
+ function safeReadDoc(filePath) {
2283
+ try {
2284
+ if (!existsSync2(filePath)) return null;
2285
+ const st = statSync2(filePath);
2286
+ if (st.size > 5e5) return null;
2287
+ return readFileSync2(filePath, "utf-8");
2288
+ } catch {
2289
+ return null;
2290
+ }
2291
+ }
2292
+ function truncate2(content) {
2293
+ if (content.length <= MAX_DOC_CHARS) return content;
2294
+ const t = content.slice(0, MAX_DOC_CHARS);
2295
+ const lastNl = t.lastIndexOf("\n");
2296
+ return t.slice(0, lastNl) + `
2297
+ ... (truncated, ${content.length} chars total)`;
2298
+ }
2299
+
2300
+ // src/arena/providers/none.ts
2301
+ init_esm_shims();
2302
+ var noneProvider = {
2303
+ kind: "none",
2304
+ collect(_plan, _topic) {
2305
+ return [];
2306
+ }
2307
+ };
2308
+
2309
+ // src/arena/providers/index.ts
2310
+ var PROVIDER_MAP = {
2311
+ git: gitProvider,
2312
+ repo: repoProvider,
2313
+ docs: docsProvider,
2314
+ web: noneProvider,
2315
+ // web deferred to Phase 4 — falls back to none for now
2316
+ none: noneProvider
2317
+ };
2318
+ function collectEvidence(plan, topic) {
2319
+ const artifacts = [];
2320
+ const quickFacts = [];
2321
+ const seenSources = /* @__PURE__ */ new Set();
2322
+ for (const sourceSpec of plan.sources) {
2323
+ if (seenSources.has(sourceSpec.kind)) continue;
2324
+ seenSources.add(sourceSpec.kind);
2325
+ const provider = PROVIDER_MAP[sourceSpec.kind];
2326
+ if (!provider) continue;
2327
+ const collected = provider.collect(plan, topic);
2328
+ artifacts.push(...collected);
2329
+ logger.info("arena.evidence_collected", {
2330
+ source: sourceSpec.kind,
2331
+ count: collected.length
2332
+ });
2333
+ }
2334
+ const branchArtifact = artifacts.find((a) => a.id === "git-branch");
2335
+ if (branchArtifact) quickFacts.push({ label: "Branch", value: branchArtifact.preview });
2336
+ const changedFilesArtifact = artifacts.find((a) => a.id === "git-changed-files");
2337
+ if (changedFilesArtifact?.metadata?.totalCount) {
2338
+ quickFacts.push({ label: "Changed Files", value: String(changedFilesArtifact.metadata.totalCount) });
2339
+ }
2340
+ const docCount = artifacts.filter((a) => a.source === "docs").length;
2341
+ if (docCount > 0) quickFacts.push({ label: "Documents", value: String(docCount) });
2342
+ quickFacts.push({ label: "Sources", value: [...seenSources].join(", ") });
2343
+ quickFacts.push({ label: "Lenses", value: plan.lenses.map((l) => l.name).join(", ") });
2344
+ return { artifacts, quickFacts };
2345
+ }
2346
+
2347
+ // src/arena/tools/selector.ts
2348
+ init_esm_shims();
2349
+
2350
+ // src/arena/context/context-tools.ts
2351
+ init_esm_shims();
2352
+ import { readFileSync as readFileSync3, existsSync as existsSync3, readdirSync as readdirSync3, statSync as statSync3 } from "fs";
2353
+ import { execFileSync as execFileSync3 } from "child_process";
2354
+ import { resolve, join as join3 } from "path";
2355
+ var MAX_TOOL_RESULT = 15e3;
2356
+ var MAX_TOOL_ROUNDS = 5;
2357
+ var REPO_ROOT = resolve(".");
2358
+ var CONTEXT_TOOLS = [
2359
+ {
2360
+ name: "read_file",
2361
+ description: "Read a file from the repository. Use this when you need to see the full source of a file referenced in the context, or to check surrounding code (callers, type definitions, etc.).",
2362
+ inputSchema: {
2363
+ type: "object",
2364
+ properties: {
2365
+ path: { type: "string", description: "Relative file path from repo root" },
2366
+ offset: { type: "number", description: "Start line (1-based, optional)" },
2367
+ limit: { type: "number", description: "Max lines to read (optional, default 200)" }
2368
+ },
2369
+ required: ["path"]
2370
+ }
2371
+ },
2372
+ {
2373
+ name: "grep_code",
2374
+ description: "Search for a pattern across the codebase. Use this to find callers, references, type definitions, or usages of symbols.",
2375
+ inputSchema: {
2376
+ type: "object",
2377
+ properties: {
2378
+ pattern: { type: "string", description: "Regex pattern to search for" },
2379
+ glob: { type: "string", description: "File glob filter, e.g. '*.ts' (optional)" }
2380
+ },
2381
+ required: ["pattern"]
2382
+ }
2383
+ },
2384
+ {
2385
+ name: "list_files",
2386
+ description: "List files in a directory. Use this to understand project structure around relevant files.",
2387
+ inputSchema: {
2388
+ type: "object",
2389
+ properties: {
2390
+ path: { type: "string", description: "Directory path relative to repo root (default: '.')" }
2391
+ },
2392
+ required: []
2393
+ }
2394
+ },
2395
+ {
2396
+ name: "git_show",
2397
+ description: "Show a git object (commit, file at a ref, etc.). Use for inspecting specific commits or viewing a file at a different branch/commit.",
2398
+ inputSchema: {
2399
+ type: "object",
2400
+ properties: {
2401
+ ref: { type: "string", description: "Git ref, e.g. 'HEAD~3', 'main:src/foo.ts', commit hash" }
2402
+ },
2403
+ required: ["ref"]
2404
+ }
2405
+ },
2406
+ {
2407
+ name: "git_blame",
2408
+ description: "Show git blame for a file. Use to understand who changed what and when.",
2409
+ inputSchema: {
2410
+ type: "object",
2411
+ properties: {
2412
+ path: { type: "string", description: "File path" },
2413
+ lines: { type: "string", description: "Line range, e.g. '10,20' (optional)" }
2414
+ },
2415
+ required: ["path"]
2416
+ }
2417
+ }
2418
+ ];
2419
+ function executeContextTool(tc) {
2420
+ try {
2421
+ switch (tc.toolName) {
2422
+ case "read_file":
2423
+ return executeReadFile(tc.args);
2424
+ case "grep_code":
2425
+ return executeGrepCode(tc.args);
2426
+ case "list_files":
2427
+ return executeListFiles(tc.args);
2428
+ case "git_show":
2429
+ return executeGitShow(tc.args);
2430
+ case "git_blame":
2431
+ return executeGitBlame(tc.args);
2432
+ default:
2433
+ return `Unknown tool: ${tc.toolName}`;
2434
+ }
2435
+ } catch (err) {
2436
+ return `Tool error: ${err.message}`;
2437
+ }
2438
+ }
2439
+ function validatePath(filePath) {
2440
+ const resolved = resolve(filePath);
2441
+ if (resolved === REPO_ROOT || resolved.startsWith(REPO_ROOT + "/")) {
2442
+ return resolved;
2443
+ }
2444
+ return null;
2445
+ }
2446
+ function executeReadFile(args) {
2447
+ const filePath = args.path;
2448
+ if (!validatePath(filePath)) return `Error: path outside repository: ${filePath}`;
2449
+ if (!existsSync3(filePath)) return `Error: file not found: ${filePath}`;
2450
+ const raw = readFileSync3(filePath, "utf-8");
2451
+ const lines = raw.split("\n");
2452
+ const offset = Math.max(0, (args.offset ?? 1) - 1);
2453
+ const limit = args.limit ?? 200;
2454
+ const slice = lines.slice(offset, offset + limit);
2455
+ const numbered = slice.map((l, i) => `${offset + i + 1} ${l}`).join("\n");
2456
+ return truncateResult(numbered);
2457
+ }
2458
+ function executeGrepCode(args) {
2459
+ const pattern = args.pattern;
2460
+ const glob = args.glob;
2461
+ const grepArgs = ["-rn", "-E", "--"];
2462
+ if (glob) {
2463
+ grepArgs.splice(1, 0, `--include=${glob}`);
2464
+ }
2465
+ grepArgs.push(pattern, ".");
2466
+ const result = execFileSafe("grep", grepArgs, 80);
2467
+ return result || "No matches found.";
2468
+ }
2469
+ function executeListFiles(args) {
2470
+ const dir = args.path || ".";
2471
+ if (!validatePath(dir)) return `Error: path outside repository: ${dir}`;
2472
+ try {
2473
+ const entries = readdirSync3(dir);
2474
+ const lines = [];
2475
+ for (const entry of entries.slice(0, 50)) {
2476
+ const fullPath = join3(dir, entry);
2477
+ try {
2478
+ const st = statSync3(fullPath);
2479
+ const type = st.isDirectory() ? "d" : "-";
2480
+ const size = st.isDirectory() ? "" : ` ${st.size}`;
2481
+ lines.push(`${type} ${entry}${size}`);
2482
+ } catch {
2483
+ lines.push(`? ${entry}`);
2484
+ }
2485
+ }
2486
+ return lines.join("\n") || `Empty directory: ${dir}`;
2487
+ } catch {
2488
+ return `Directory not found: ${dir}`;
2489
+ }
2490
+ }
2491
+ function executeGitShow(args) {
2492
+ const ref = sanitizeGitRef(args.ref);
2493
+ if (!ref) return "Error: invalid git ref";
2494
+ const result = execFileSafe("git", ["show", "--", ref], 200);
2495
+ return truncateResult(result || `Could not resolve: ${ref}`);
2496
+ }
2497
+ function executeGitBlame(args) {
2498
+ const filePath = args.path;
2499
+ if (!validatePath(filePath)) return `Error: path outside repository: ${filePath}`;
2500
+ const lines = args.lines;
2501
+ const gitArgs = ["blame"];
2502
+ if (lines && /^\d+,\d+$/.test(lines)) {
2503
+ gitArgs.push(`-L`, lines);
2504
+ }
2505
+ gitArgs.push("--", filePath);
2506
+ const result = execFileSafe("git", gitArgs, 50);
2507
+ return result || `Could not blame: ${filePath}`;
2508
+ }
2509
+ function sanitizeGitRef(ref) {
2510
+ if (!ref || ref.length > 200) return null;
2511
+ const cleaned = ref.replace(/[^a-zA-Z0-9/_\-~^.:]/g, "");
2512
+ if (/\.\.\/|;\s|&&|\|\||`|\$\(/.test(cleaned)) return null;
2513
+ return cleaned || null;
2514
+ }
2515
+ function execFileSafe(cmd, args, maxLines) {
2516
+ try {
2517
+ const raw = execFileSync3(cmd, args, {
2518
+ encoding: "utf-8",
2519
+ maxBuffer: 512 * 1024,
2520
+ timeout: 1e4
2521
+ }).trim();
2522
+ if (maxLines) {
2523
+ const lines = raw.split("\n");
2524
+ if (lines.length > maxLines) {
2525
+ return lines.slice(0, maxLines).join("\n") + `
2526
+ ... (${lines.length - maxLines} more lines)`;
2527
+ }
2528
+ }
2529
+ return raw;
2530
+ } catch {
2531
+ return "";
2532
+ }
2533
+ }
2534
+ function truncateResult(text) {
2535
+ if (text.length <= MAX_TOOL_RESULT) return text;
2536
+ return text.slice(0, MAX_TOOL_RESULT) + "\n... (truncated)";
2537
+ }
2538
+
2539
+ // src/arena/tools/selector.ts
2540
+ var TOOL_PACKS = {
2541
+ repo_readonly: {
2542
+ name: "repo_readonly",
2543
+ toolNames: ["read_file", "grep_code", "list_files"]
2544
+ },
2545
+ git: {
2546
+ name: "git",
2547
+ toolNames: ["read_file", "grep_code", "list_files", "git_show", "git_blame"]
2548
+ },
2549
+ docs: {
2550
+ name: "docs",
2551
+ toolNames: ["read_file", "list_files"]
2552
+ },
2553
+ no_tools: {
2554
+ name: "no_tools",
2555
+ toolNames: []
2556
+ }
2557
+ };
2558
+ var SOURCE_TO_PACK = {
2559
+ git: "git",
2560
+ repo: "repo_readonly",
2561
+ docs: "docs",
2562
+ web: "no_tools",
2563
+ // web tools not yet available in arena context
2564
+ none: "no_tools"
2565
+ };
2566
+ function selectTools(plan) {
2567
+ const toolNames = /* @__PURE__ */ new Set();
2568
+ for (const source of plan.sources) {
2569
+ const packName = source.toolPack ?? SOURCE_TO_PACK[source.kind] ?? "no_tools";
2570
+ const pack = TOOL_PACKS[packName] ?? TOOL_PACKS.no_tools;
2571
+ for (const name of pack.toolNames) {
2572
+ toolNames.add(name);
2573
+ }
2574
+ }
2575
+ if (toolNames.size === 0) return [];
2576
+ return CONTEXT_TOOLS.filter((t) => toolNames.has(t.name));
2577
+ }
2578
+ function hasTools(plan) {
2579
+ return plan.sources.some((s) => {
2580
+ const packName = SOURCE_TO_PACK[s.kind];
2581
+ const pack = TOOL_PACKS[packName];
2582
+ return pack && pack.toolNames.length > 0;
2583
+ });
2584
+ }
2585
+
2586
+ // src/arena/phases/participant-research.ts
2587
+ init_esm_shims();
2588
+ import { createHash } from "crypto";
2589
+ async function runParticipantResearch(options) {
2590
+ const results = await runParticipantResearchWithDossiers(options);
2591
+ return results.map((r) => r.report);
2592
+ }
2593
+ async function runParticipantResearchWithDossiers(options) {
2594
+ const { participants, strategy, topic, baseContext, enableContextTools, contextTools, signal, onProgress } = options;
2595
+ const tools = enableContextTools ? contextTools ?? CONTEXT_TOOLS : void 0;
2596
+ const tasks = participants.map(async (p) => {
2597
+ onProgress?.({ type: "research_start", participant: p.name });
2598
+ const client = await createLLMClient({
2599
+ ...p.llm,
2600
+ enableStreaming: false
2601
+ });
2602
+ const messages = [
2603
+ {
2604
+ role: "user",
2605
+ content: strategy.researchUserPrompt(topic, baseContext)
2606
+ }
2607
+ ];
2608
+ let finalText = "";
2609
+ let totalRounds = 0;
2610
+ const toolTraces = [];
2611
+ const evidencePackets = [];
2612
+ const MAX_MESSAGES = 30;
2613
+ for (let round = 0; round <= MAX_TOOL_ROUNDS; round++) {
2614
+ totalRounds = round;
2615
+ if (messages.length >= MAX_MESSAGES) {
2616
+ logger.warn("arena.research_message_limit", {
2617
+ participant: p.name,
2618
+ messageCount: messages.length,
2619
+ round
2620
+ });
2621
+ break;
2622
+ }
2623
+ const response = await client.createMessage({
2624
+ systemPrompt: strategy.researchSystemPrompt(p.name),
2625
+ messages,
2626
+ tools,
2627
+ signal
2628
+ });
2629
+ const toolNames = (response.toolCalls ?? []).map((tc) => tc.toolName);
2630
+ const hasTools2 = response.toolCalls && response.toolCalls.length > 0;
2631
+ logger.info("arena.research_round", {
2632
+ participant: p.name,
2633
+ round,
2634
+ toolCount: response.toolCalls?.length ?? 0,
2635
+ toolNames,
2636
+ textLen: response.text?.length ?? 0,
2637
+ stopReason: response.stopReason ?? "unknown"
2638
+ });
2639
+ if (!hasTools2) {
2640
+ finalText = response.text;
2641
+ break;
2642
+ }
2643
+ onProgress?.({
2644
+ type: "context_lookup",
2645
+ participant: p.name,
2646
+ tools: response.toolCalls.map((tc) => `${tc.toolName}(${JSON.stringify(tc.args)})`)
2647
+ });
2648
+ const assistantBlocks = [];
2649
+ if (response.text) {
2650
+ assistantBlocks.push({ type: "text", text: response.text });
2651
+ }
2652
+ for (const tc of response.toolCalls) {
2653
+ assistantBlocks.push({
2654
+ type: "tool_use",
2655
+ id: tc.id,
2656
+ name: tc.toolName,
2657
+ input: tc.args
2658
+ });
2659
+ }
2660
+ messages.push({ role: "assistant", content: assistantBlocks });
2661
+ const resultBlocks = [];
2662
+ for (const tc of response.toolCalls) {
2663
+ const result = executeContextTool(tc);
2664
+ const trace = {
2665
+ round,
2666
+ toolName: tc.toolName,
2667
+ args: tc.args,
2668
+ resultRef: buildResultRef(tc),
2669
+ keptAsEvidence: result.length > 50 && !result.startsWith("Error:") && !result.startsWith("Tool error:") && !result.startsWith("Unknown tool:")
2670
+ };
2671
+ toolTraces.push(trace);
2672
+ if (trace.keptAsEvidence) {
2673
+ const packet = buildEvidencePacketFromTool(p.name, tc, result, inferSourceKind(tc.toolName));
2674
+ evidencePackets.push(packet);
2675
+ }
2676
+ resultBlocks.push({
2677
+ type: "tool_result",
2678
+ tool_use_id: tc.id,
2679
+ content: result
2680
+ });
2681
+ }
2682
+ messages.push({ role: "user", content: resultBlocks });
2683
+ }
2684
+ if (!finalText) {
2685
+ logger.warn("arena.research_force_conclude", {
2686
+ participant: p.name,
2687
+ totalRounds,
2688
+ messageCount: messages.length
2689
+ });
2690
+ const forceResponse = await client.createMessage({
2691
+ systemPrompt: strategy.researchSystemPrompt(p.name),
2692
+ messages: [
2693
+ ...messages,
2694
+ {
2695
+ role: "user",
2696
+ content: "You have gathered enough context. Based on ALL the tool results above, output your findings NOW.\n\nRespond ONLY with JSON \u2014 output your highest-confidence findings (typically 5-15 for a substantive topic; each finding's `summary` should be 80+ words with concrete evidence). Do NOT request any more tools. Just output the JSON."
2697
+ }
2698
+ ]
2699
+ });
2700
+ logger.info("arena.research_force_conclude_response", {
2701
+ participant: p.name,
2702
+ textLen: forceResponse.text?.length ?? 0,
2703
+ stopReason: forceResponse.stopReason ?? "unknown"
2704
+ });
2705
+ finalText = forceResponse.text;
2706
+ }
2707
+ logger.info("arena.research_raw_response", {
2708
+ participant: p.name,
2709
+ textLength: finalText.length,
2710
+ text: finalText
2711
+ });
2712
+ if (!finalText || finalText.trim().length === 0) {
2713
+ logger.warn("arena.research_failed", {
2714
+ participant: p.name,
2715
+ totalRounds,
2716
+ messageCount: messages.length
2717
+ });
2718
+ const failedReport = {
2719
+ participant: p.name,
2720
+ contextSummary: `(research failed: model returned empty response after ${totalRounds} tool rounds)`,
2721
+ findings: []
2722
+ };
2723
+ const failedDossier = {
2724
+ participant: p.name,
2725
+ contextSummary: failedReport.contextSummary,
2726
+ findings: [],
2727
+ toolTrace: toolTraces,
2728
+ evidencePackets,
2729
+ findingEvidenceLinks: []
2730
+ };
2731
+ onProgress?.({ type: "research_done", participant: p.name, report: failedReport });
2732
+ return { report: failedReport, dossier: failedDossier };
2733
+ }
2734
+ const report = strategy.parseResearchResponse(p.name, finalText);
2735
+ const findingEvidenceLinks = buildFindingEvidenceLinks(report, evidencePackets);
2736
+ const dossier = {
2737
+ participant: p.name,
2738
+ contextSummary: report.contextSummary,
2739
+ findings: report.findings,
2740
+ toolTrace: toolTraces,
2741
+ evidencePackets,
2742
+ findingEvidenceLinks
2743
+ };
2744
+ onProgress?.({ type: "research_done", participant: p.name, report });
2745
+ return { report, dossier };
2746
+ });
2747
+ return Promise.all(tasks);
2748
+ }
2749
+ function buildResultRef(tc) {
2750
+ if (tc.toolName === "read_file" && tc.args.path) return `file:${tc.args.path}`;
2751
+ if (tc.toolName === "grep_code" && tc.args.pattern) return `grep:${tc.args.pattern}`;
2752
+ if (tc.toolName === "list_files" && tc.args.path) return `dir:${tc.args.path}`;
2753
+ if (tc.toolName === "git_show" && tc.args.ref) return `git:${tc.args.ref}`;
2754
+ if (tc.toolName === "git_blame" && tc.args.path) return `blame:${tc.args.path}`;
2755
+ return `${tc.toolName}:${JSON.stringify(tc.args).slice(0, 60)}`;
2756
+ }
2757
+ function generatePacketId(participant, source, ref, snippet) {
2758
+ const hash = createHash("sha256").update(`${participant}:${source}:${ref}:${snippet.slice(0, 200)}`).digest("hex").slice(0, 12);
2759
+ return `pkt-${hash}`;
2760
+ }
2761
+ function inferSourceKind(toolName) {
2762
+ switch (toolName) {
2763
+ case "git_show":
2764
+ case "git_blame":
2765
+ return "git";
2766
+ case "read_file":
2767
+ case "grep_code":
2768
+ case "list_files":
2769
+ return "repo";
2770
+ default:
2771
+ return "repo";
2772
+ }
2773
+ }
2774
+ function buildEvidencePacketFromTool(participant, tc, result, source) {
2775
+ const ref = buildResultRef(tc);
2776
+ const snippet = result.slice(0, 500);
2777
+ const packetId = generatePacketId(participant, source, ref, snippet);
2778
+ return {
2779
+ packetId,
2780
+ participant,
2781
+ source,
2782
+ title: `${tc.toolName}: ${formatToolArgs(tc.args)}`,
2783
+ refs: [ref],
2784
+ summary: result.slice(0, 200),
2785
+ excerpts: [{
2786
+ ref,
2787
+ snippet,
2788
+ note: `Result of ${tc.toolName} call`
2789
+ }]
2790
+ };
2791
+ }
2792
+ function formatToolArgs(args) {
2793
+ const parts = [];
2794
+ for (const [key, value] of Object.entries(args)) {
2795
+ if (typeof value === "string") parts.push(value.slice(0, 60));
2796
+ else parts.push(`${key}=${JSON.stringify(value)}`);
2797
+ }
2798
+ return parts.join(", ").slice(0, 100);
2799
+ }
2800
+ function buildFindingEvidenceLinks(report, packets) {
2801
+ const links = [];
2802
+ for (const finding of report.findings) {
2803
+ const matchedPacketIds = [];
2804
+ for (const evidence of finding.evidence) {
2805
+ const evidenceRef = `${evidence.type}:${evidence.ref}`;
2806
+ for (const packet of packets) {
2807
+ const matches = packet.refs.some((pRef) => {
2808
+ if (pRef === evidenceRef) return true;
2809
+ if (evidence.ref && pRef.includes(evidence.ref)) return true;
2810
+ return false;
2811
+ });
2812
+ if (matches && !matchedPacketIds.includes(packet.packetId)) {
2813
+ matchedPacketIds.push(packet.packetId);
2814
+ }
2815
+ }
2816
+ }
2817
+ if (matchedPacketIds.length > 0) {
2818
+ links.push({
2819
+ findingId: finding.id,
2820
+ evidencePacketIds: matchedPacketIds
2821
+ });
2822
+ }
2823
+ }
2824
+ return links;
2825
+ }
2826
+
2827
+ // src/arena/phases/claim-registry.ts
2828
+ init_esm_shims();
2829
+ function registerClaims(options) {
2830
+ const { dossiers, ledger, onProgress } = options;
2831
+ const claims = [];
2832
+ for (const dossier of dossiers) {
2833
+ const linkMap = /* @__PURE__ */ new Map();
2834
+ for (const link of dossier.findingEvidenceLinks) {
2835
+ linkMap.set(link.findingId, link.evidencePacketIds);
2836
+ }
2837
+ for (const finding of dossier.findings) {
2838
+ const claimId = `${dossier.participant}:${finding.id}`;
2839
+ const packetIds = linkMap.get(finding.id) ?? [];
2840
+ const evidenceRefs = finding.evidence.map((e) => `${e.type}:${e.ref}`);
2841
+ const claim = {
2842
+ claimId,
2843
+ owner: dossier.participant,
2844
+ finding,
2845
+ evidenceRefs,
2846
+ evidencePacketIds: packetIds,
2847
+ status: "proposed",
2848
+ challenges: [],
2849
+ debateRounds: []
2850
+ };
2851
+ claims.push(claim);
2852
+ ledger.appendClaim(claim);
2853
+ }
2854
+ }
2855
+ onProgress?.({ type: "claims_registered", claimCount: claims.length });
2856
+ return claims;
2857
+ }
2858
+ function selectClaimsForReview(claims, maxClaims) {
2859
+ const severityOrder = { high: 0, medium: 1, low: 2 };
2860
+ const sorted = [...claims].sort((a, b) => {
2861
+ const sevA = severityOrder[a.finding.severity ?? "medium"] ?? 1;
2862
+ const sevB = severityOrder[b.finding.severity ?? "medium"] ?? 1;
2863
+ if (sevA !== sevB) return sevA - sevB;
2864
+ return b.finding.confidence - a.finding.confidence;
2865
+ });
2866
+ return sorted.slice(0, maxClaims);
2867
+ }
2868
+
2869
+ // src/arena/digest-builder.ts
2870
+ init_esm_shims();
2871
+ function buildDigest(ledger, options) {
2872
+ const { round, relevantClaimIds } = options;
2873
+ const claimIdSet = new Set(relevantClaimIds);
2874
+ const snapshot = ledger.getSnapshot();
2875
+ const packetIds = /* @__PURE__ */ new Set();
2876
+ for (const claimId of relevantClaimIds) {
2877
+ const claim = ledger.getClaimById(claimId);
2878
+ if (claim) {
2879
+ for (const pid of claim.evidencePacketIds) {
2880
+ packetIds.add(pid);
2881
+ }
2882
+ }
2883
+ }
2884
+ const evidencePackets = [];
2885
+ for (const pid of packetIds) {
2886
+ const packet = ledger.getPacketById(pid);
2887
+ if (packet) evidencePackets.push(packet);
2888
+ }
2889
+ const toolTraceSummary = [];
2890
+ for (const dossier of snapshot.dossiers) {
2891
+ for (const trace of dossier.toolTrace) {
2892
+ if (trace.keptAsEvidence) {
2893
+ toolTraceSummary.push({
2894
+ participant: dossier.participant,
2895
+ toolName: trace.toolName,
2896
+ ref: trace.resultRef
2897
+ });
2898
+ }
2899
+ }
2900
+ }
2901
+ const recentChallenges = snapshot.challenges.filter((c) => claimIdSet.has(c.claimId));
2902
+ const requestedChecks = snapshot.requestedChecks.filter((c) => claimIdSet.has(c.claimId));
2903
+ const priorAdjudications = snapshot.adjudications.filter((a) => claimIdSet.has(a.claimId));
2904
+ return {
2905
+ round,
2906
+ relevantClaimIds,
2907
+ evidencePackets,
2908
+ toolTraceSummary,
2909
+ recentChallenges,
2910
+ requestedChecks,
2911
+ priorAdjudications
2912
+ };
2913
+ }
2914
+ function sanitize(text) {
2915
+ if (!text) return "";
2916
+ return text.replace(/<\/?(?:system|assistant|user|system-reminder)[^>]*>/gi, "").replace(/^(?:IGNORE|DISREGARD|FORGET|OVERRIDE|SYSTEM|INSTRUCTION)[:\s].*/gim, "").replace(/\n{3,}/g, "\n\n").slice(0, 2e3);
2917
+ }
2918
+ function formatDigest(digest) {
2919
+ const sections = [];
2920
+ sections.push(`## Round ${digest.round} Research Digest`);
2921
+ sections.push(`Claims under consideration: ${digest.relevantClaimIds.join(", ")}`);
2922
+ if (digest.evidencePackets.length > 0) {
2923
+ sections.push("\n### Evidence");
2924
+ for (const packet of digest.evidencePackets) {
2925
+ sections.push(`- [${packet.packetId}] ${sanitize(packet.title)} (${packet.source})`);
2926
+ sections.push(` ${sanitize(packet.summary)}`);
2927
+ for (const excerpt of packet.excerpts.slice(0, 3)) {
2928
+ sections.push(` > ${excerpt.ref}: ${sanitize(excerpt.snippet)}`);
2929
+ if (excerpt.note) sections.push(` Note: ${sanitize(excerpt.note)}`);
2930
+ }
2931
+ }
2932
+ }
2933
+ if (digest.recentChallenges.length > 0) {
2934
+ sections.push("\n### Challenges");
2935
+ for (const c of digest.recentChallenges) {
2936
+ sections.push(`- [${c.reviewer}] on ${c.claimId}: ${c.verdict} \u2014 ${sanitize(c.reason)}`);
2937
+ }
2938
+ }
2939
+ if (digest.requestedChecks.length > 0) {
2940
+ sections.push("\n### Requested Checks");
2941
+ for (const check of digest.requestedChecks) {
2942
+ const pri = check.priority ? ` (${check.priority})` : "";
2943
+ sections.push(`- [${check.requestId}]${pri}: ${sanitize(check.description)}`);
2944
+ }
2945
+ }
2946
+ if (digest.priorAdjudications.length > 0) {
2947
+ sections.push("\n### Prior Adjudications");
2948
+ for (const adj of digest.priorAdjudications) {
2949
+ sections.push(`- ${adj.claimId}: ${adj.outcome} \u2014 ${sanitize(adj.rationale)}`);
2950
+ }
2951
+ }
2952
+ return sections.join("\n");
2953
+ }
2954
+
2955
+ // src/arena/transitions.ts
2956
+ init_esm_shims();
2957
+ var VALID_TRANSITIONS = {
2958
+ proposed: ["under_review"],
2959
+ under_review: ["verified", "contested", "rejected"],
2960
+ contested: ["under_review", "unresolved", "verified", "rejected"],
2961
+ verified: [],
2962
+ rejected: [],
2963
+ unresolved: []
2964
+ };
2965
+ function transitionClaim(claim, to) {
2966
+ const allowed = VALID_TRANSITIONS[claim.status];
2967
+ if (!allowed.includes(to)) {
2968
+ return false;
2969
+ }
2970
+ claim.status = to;
2971
+ return true;
2972
+ }
2973
+ function resolveClaimStatus(claim, challenges, hasPendingChecks) {
2974
+ if (challenges.length === 0) return claim.status;
2975
+ const verdicts = challenges.map((c) => c.verdict);
2976
+ if (verdicts.includes("disagree") || verdicts.includes("needs_evidence")) {
2977
+ return "contested";
2978
+ }
2979
+ if (hasPendingChecks) {
2980
+ return "contested";
2981
+ }
2982
+ if (verdicts.includes("agree")) {
2983
+ return "verified";
2984
+ }
2985
+ return claim.status;
2986
+ }
2987
+ function markUnderReview(claim) {
2988
+ return transitionClaim(claim, "under_review");
2989
+ }
2990
+ function applyReviewResult(claim, challenges, hasPendingChecks) {
2991
+ const nextStatus = resolveClaimStatus(claim, challenges, hasPendingChecks);
2992
+ transitionClaim(claim, nextStatus);
2993
+ }
2994
+ function markUnresolved(claim) {
2995
+ return transitionClaim(claim, "unresolved");
2996
+ }
2997
+ function isTerminal(claim) {
2998
+ return VALID_TRANSITIONS[claim.status].length === 0;
2999
+ }
3000
+ function validTransitions(claim) {
3001
+ return VALID_TRANSITIONS[claim.status];
3002
+ }
3003
+
3004
+ // src/arena/phases/cross-review.ts
3005
+ init_esm_shims();
3006
+ async function runCrossReview(options) {
3007
+ const { participants, strategy, topic, reports, signal, onProgress } = options;
3008
+ onProgress?.({ type: "cross_review_start", round: 1 });
3009
+ const allReviews = [];
3010
+ const tasks = participants.map(async (p) => {
3011
+ const myReport = reports.find((r) => r.participant === p.name);
3012
+ const otherReports = reports.filter((r) => r.participant !== p.name);
3013
+ if (otherReports.length === 0) return [];
3014
+ if (!myReport) return [];
3015
+ const client = await createLLMClient({
3016
+ ...p.llm,
3017
+ enableStreaming: false
3018
+ });
3019
+ const systemPrompt = strategy.crossReviewSystemPrompt(p.name);
3020
+ const userContent = strategy.crossReviewUserPrompt(topic, myReport, otherReports);
3021
+ let response = await client.createMessage({
3022
+ systemPrompt,
3023
+ messages: [{ role: "user", content: userContent }],
3024
+ signal
3025
+ });
3026
+ logger.info("arena.cross_review_raw_response", {
3027
+ participant: p.name,
3028
+ text: response.text,
3029
+ stopReason: response.stopReason
3030
+ });
3031
+ if (response.stopReason === "length") {
3032
+ logger.warn("arena.cross_review_truncated", { participant: p.name });
3033
+ const retryResponse = await client.createMessage({
3034
+ systemPrompt,
3035
+ messages: [
3036
+ { role: "user", content: userContent },
3037
+ { role: "assistant", content: response.text },
3038
+ {
3039
+ role: "user",
3040
+ content: "Your previous response was truncated. Please output the COMPLETE review JSON, using shorter comments. Respond ONLY with JSON."
3041
+ }
3042
+ ],
3043
+ signal
3044
+ });
3045
+ logger.info("arena.cross_review_retry", {
3046
+ participant: p.name,
3047
+ stopReason: retryResponse.stopReason
3048
+ });
3049
+ response = retryResponse;
3050
+ }
3051
+ return strategy.parseCrossReviewResponse(p.name, response.text);
3052
+ });
3053
+ const results = await Promise.all(tasks);
3054
+ for (const reviews of results) {
3055
+ allReviews.push(...reviews);
3056
+ }
3057
+ onProgress?.({ type: "cross_review_done", reviews: allReviews });
3058
+ return allReviews;
3059
+ }
3060
+ async function runVerificationReview(options) {
3061
+ const { participants, strategy, topic, reports, ledger, limits, mode, signal, onProgress } = options;
3062
+ const allClaims = ledger.getAllClaims();
3063
+ const claimsToReview = selectClaimsForReview(allClaims, limits.maxClaimsForReview);
3064
+ for (const claim of claimsToReview) {
3065
+ markUnderReview(claim);
3066
+ }
3067
+ const relevantClaimIds = claimsToReview.map((c) => c.claimId);
3068
+ const digest = buildDigest(ledger, { round: 1, relevantClaimIds });
3069
+ const isPlanningMerge = mode === "planning" && isStrategyPlanning(strategy);
3070
+ if (isPlanningMerge) {
3071
+ onProgress?.({ type: "planning_merge_review_start" });
3072
+ } else {
3073
+ onProgress?.({ type: "verification_start" });
3074
+ }
3075
+ const v2 = isStrategyV2(strategy);
3076
+ const allReviews = [];
3077
+ const allChallenges = [];
3078
+ const tasks = participants.map(async (p) => {
3079
+ const myReport = reports.find((r) => r.participant === p.name);
3080
+ const otherReports = reports.filter((r) => r.participant !== p.name);
3081
+ if (!myReport || otherReports.length === 0) return;
3082
+ const myClaims = claimsToReview.filter((c) => c.owner !== p.name);
3083
+ if (myClaims.length === 0) return;
3084
+ const client = await createLLMClient({
3085
+ ...p.llm,
3086
+ enableStreaming: false
3087
+ });
3088
+ const systemPrompt = strategy.crossReviewSystemPrompt(p.name);
3089
+ if (v2) {
3090
+ const userContent = isPlanningMerge ? strategy.mergeReviewUserPrompt(topic, myReport, myClaims, digest) : strategy.verificationReviewUserPrompt(topic, myReport, myClaims, digest);
3091
+ let response = await client.createMessage({
3092
+ systemPrompt,
3093
+ messages: [{ role: "user", content: userContent }],
3094
+ signal
3095
+ });
3096
+ logger.info("arena.verification_review_raw", {
3097
+ participant: p.name,
3098
+ stopReason: response.stopReason
3099
+ });
3100
+ if (response.stopReason === "length") {
3101
+ const retryResponse = await client.createMessage({
3102
+ systemPrompt,
3103
+ messages: [
3104
+ { role: "user", content: userContent },
3105
+ { role: "assistant", content: response.text },
3106
+ { role: "user", content: "Truncated. Output the COMPLETE JSON array, shorter comments. JSON only." }
3107
+ ],
3108
+ signal
3109
+ });
3110
+ response = retryResponse;
3111
+ }
3112
+ const challenges = isPlanningMerge ? strategy.parseMergeReviewResponse(p.name, response.text) : strategy.parseVerificationReviewResponse(p.name, response.text);
3113
+ for (const challenge of challenges) {
3114
+ allChallenges.push(challenge);
3115
+ ledger.appendChallenge(challenge);
3116
+ }
3117
+ for (const ch of challenges) {
3118
+ allReviews.push({
3119
+ reviewer: ch.reviewer,
3120
+ findingId: ch.claimId,
3121
+ verdict: ch.verdict,
3122
+ reason: ch.reason,
3123
+ extraEvidence: ch.supportingEvidenceRefs
3124
+ });
3125
+ }
3126
+ } else {
3127
+ const userContent = strategy.crossReviewUserPrompt(topic, myReport, otherReports);
3128
+ let response = await client.createMessage({
3129
+ systemPrompt,
3130
+ messages: [{ role: "user", content: userContent }],
3131
+ signal
3132
+ });
3133
+ if (response.stopReason === "length") {
3134
+ const retryResponse = await client.createMessage({
3135
+ systemPrompt,
3136
+ messages: [
3137
+ { role: "user", content: userContent },
3138
+ { role: "assistant", content: response.text },
3139
+ { role: "user", content: "Truncated. Output COMPLETE review JSON. Shorter comments. JSON only." }
3140
+ ],
3141
+ signal
3142
+ });
3143
+ response = retryResponse;
3144
+ }
3145
+ const reviews = strategy.parseCrossReviewResponse(p.name, response.text);
3146
+ allReviews.push(...reviews);
3147
+ for (const review of reviews) {
3148
+ const claim = claimsToReview.find(
3149
+ (c) => c.finding.id === review.findingId || c.claimId === review.findingId
3150
+ );
3151
+ if (claim) {
3152
+ const challenge = {
3153
+ reviewer: review.reviewer,
3154
+ claimId: claim.claimId,
3155
+ verdict: review.verdict,
3156
+ reason: review.reason,
3157
+ supportingEvidenceRefs: review.extraEvidence
3158
+ };
3159
+ allChallenges.push(challenge);
3160
+ ledger.appendChallenge(challenge);
3161
+ }
3162
+ }
3163
+ }
3164
+ });
3165
+ await Promise.all(tasks);
3166
+ for (const claim of claimsToReview) {
3167
+ const claimChallenges = ledger.getChallengesForClaim(claim.claimId);
3168
+ const hasPendingChecks = ledger.getPendingChecksForClaim(claim.claimId).length > 0;
3169
+ applyReviewResult(claim, claimChallenges, hasPendingChecks);
3170
+ }
3171
+ logger.info("arena.verification_done", {
3172
+ reviewCount: allReviews.length,
3173
+ challengeCount: allChallenges.length,
3174
+ claimStatuses: Object.fromEntries(
3175
+ claimsToReview.map((c) => [c.claimId, c.status])
3176
+ )
3177
+ });
3178
+ if (isPlanningMerge) {
3179
+ onProgress?.({ type: "planning_merge_review_done", mergeCount: allChallenges.length });
3180
+ } else {
3181
+ onProgress?.({ type: "verification_done", challengeCount: allChallenges.length });
3182
+ }
3183
+ onProgress?.({ type: "cross_review_done", reviews: allReviews });
3184
+ return { reviews: allReviews, challenges: allChallenges };
3185
+ }
3186
+
3187
+ // src/arena/phases/debate-rounds.ts
3188
+ init_esm_shims();
3189
+ async function runDebateRounds(options) {
3190
+ const { participants, strategy, topic, ledger, limits, maxRounds, signal, onProgress } = options;
3191
+ const contested = ledger.getClaimsByStatus("contested").slice(0, limits.maxContestedClaimsForDebate);
3192
+ if (contested.length === 0) {
3193
+ logger.info("arena.debate_skip", { reason: "no contested claims" });
3194
+ return [];
3195
+ }
3196
+ logger.info("arena.debate_start", {
3197
+ contestedCount: contested.length,
3198
+ maxRounds
3199
+ });
3200
+ const allDebateRounds = [];
3201
+ const v2 = isStrategyV2(strategy);
3202
+ for (const claim of contested) {
3203
+ signal?.throwIfAborted();
3204
+ const claimDebateRounds = await debateClaim({
3205
+ claim,
3206
+ participants,
3207
+ strategy,
3208
+ v2,
3209
+ topic,
3210
+ ledger,
3211
+ maxRounds,
3212
+ signal,
3213
+ onProgress
3214
+ });
3215
+ allDebateRounds.push(...claimDebateRounds);
3216
+ claim.debateRounds.push(...claimDebateRounds);
3217
+ }
3218
+ return allDebateRounds;
3219
+ }
3220
+ async function debateClaim(options) {
3221
+ const { claim, participants, strategy, v2, topic, ledger, maxRounds, signal, onProgress } = options;
3222
+ const owner = participants.find((p) => p.name === claim.owner);
3223
+ const primaryChallenger = findPrimaryChallenger(claim, participants);
3224
+ if (!owner || !primaryChallenger) {
3225
+ logger.warn("arena.debate_skip_claim", {
3226
+ claimId: claim.claimId,
3227
+ reason: "cannot identify debaters"
3228
+ });
3229
+ return [];
3230
+ }
3231
+ const debaters = [owner, primaryChallenger];
3232
+ const rounds = [];
3233
+ const allTurns = [];
3234
+ for (let round = 1; round <= maxRounds; round++) {
3235
+ signal?.throwIfAborted();
3236
+ onProgress?.({ type: "debate_round_start", round, claims: [claim.claimId] });
3237
+ const digest = buildDigest(ledger, {
3238
+ round,
3239
+ relevantClaimIds: [claim.claimId]
3240
+ });
3241
+ const turnPromises = debaters.map(async (p) => {
3242
+ const client = await createLLMClient({
3243
+ ...p.llm,
3244
+ enableStreaming: false
3245
+ });
3246
+ const systemPrompt = strategy.crossReviewSystemPrompt(p.name);
3247
+ let userContent;
3248
+ if (v2) {
3249
+ userContent = strategy.debateTurnUserPrompt(topic, claim, allTurns, digest);
3250
+ } else {
3251
+ userContent = buildFallbackDebatePrompt(topic, claim, allTurns);
3252
+ }
3253
+ const response = await client.createMessage({
3254
+ systemPrompt,
3255
+ messages: [{ role: "user", content: userContent }],
3256
+ signal
3257
+ });
3258
+ logger.info("arena.debate_turn", {
3259
+ participant: p.name,
3260
+ claimId: claim.claimId,
3261
+ round,
3262
+ stopReason: response.stopReason
3263
+ });
3264
+ if (v2) {
3265
+ return strategy.parseDebateTurnResponse(p.name, response.text);
3266
+ }
3267
+ return parseDebateTurn(p.name, response.text);
3268
+ });
3269
+ const turns = await Promise.all(turnPromises);
3270
+ allTurns.push(...turns);
3271
+ const resolved = turns.every((t) => t.stance === "support" || t.stance === "narrow");
3272
+ const resolutionNote = resolved ? `Converged in round ${round}: ${turns.map((t) => `${t.participant}=${t.stance}`).join(", ")}` : void 0;
3273
+ const debateRound = {
3274
+ round,
3275
+ claimId: claim.claimId,
3276
+ participants: turns,
3277
+ resolved,
3278
+ resolutionNote
3279
+ };
3280
+ rounds.push(debateRound);
3281
+ onProgress?.({ type: "debate_round_done", round, resolved: resolved ? 1 : 0 });
3282
+ if (resolved) {
3283
+ logger.info("arena.debate_converged", {
3284
+ claimId: claim.claimId,
3285
+ round
3286
+ });
3287
+ break;
3288
+ }
3289
+ }
3290
+ return rounds;
3291
+ }
3292
+ function findPrimaryChallenger(claim, participants) {
3293
+ const disagreeChallenge = claim.challenges.find((c) => c.verdict === "disagree");
3294
+ const needsEvidenceChallenge = claim.challenges.find((c) => c.verdict === "needs_evidence");
3295
+ const challenge = disagreeChallenge ?? needsEvidenceChallenge ?? claim.challenges[0];
3296
+ if (!challenge) return void 0;
3297
+ return participants.find((p) => p.name === challenge.reviewer);
3298
+ }
3299
+ function buildFallbackDebatePrompt(topic, claim, priorTurns) {
3300
+ const turnsText = priorTurns.length > 0 ? priorTurns.map((t) => `[${t.participant}] ${t.stance}: ${t.summary}`).join("\n") : "No prior turns.";
3301
+ return `## Topic: ${topic}
3302
+
3303
+ ## Contested Claim
3304
+ [${claim.claimId}] ${claim.finding.title}
3305
+ ${claim.finding.summary}
3306
+
3307
+ ## Prior Debate
3308
+ ${turnsText}
3309
+
3310
+ State your position on this claim. Build on prior turns: cite specific evidence, acknowledge counter-arguments, and explain your reasoning in 150-300 words. Brevity here means missed nuance \u2014 depth wins.
3311
+ Respond ONLY with JSON:
3312
+ {"stance": "support|oppose|narrow|uncertain", "summary": "your argument", "newEvidenceRefs": ["optional"]}`;
3313
+ }
3314
+
3315
+ // src/arena/phases/adjudication.ts
3316
+ init_esm_shims();
3317
+ async function runAdjudication(options) {
3318
+ const { concluder, strategy, topic, ledger, signal, onProgress } = options;
3319
+ const allAdjudications = [];
3320
+ const v2 = isStrategyV2(strategy);
3321
+ const contestedClaims = ledger.getClaimsByStatus("contested");
3322
+ const verifiedClaims = ledger.getClaimsByStatus("verified");
3323
+ if (contestedClaims.length === 0 && verifiedClaims.length === 0) {
3324
+ logger.info("arena.adjudication_skip", { reason: "no claims to adjudicate" });
3325
+ return [];
3326
+ }
3327
+ logger.info("arena.adjudication_start", {
3328
+ contested: contestedClaims.length,
3329
+ verified: verifiedClaims.length
3330
+ });
3331
+ const client = await createLLMClient({
3332
+ ...concluder.llm,
3333
+ enableStreaming: false
3334
+ });
3335
+ for (const claim of contestedClaims) {
3336
+ signal?.throwIfAborted();
3337
+ const digest = buildDigest(ledger, {
3338
+ round: 0,
3339
+ // adjudication is post-debate
3340
+ relevantClaimIds: [claim.claimId]
3341
+ });
3342
+ const systemPrompt = strategy.consensusSystemPrompt();
3343
+ let userContent;
3344
+ if (v2) {
3345
+ userContent = strategy.adjudicationUserPrompt(topic, claim, claim.debateRounds, digest);
3346
+ } else {
3347
+ userContent = buildFallbackAdjudicationPrompt(topic, claim);
3348
+ }
3349
+ const response = await client.createMessage({
3350
+ systemPrompt,
3351
+ messages: [{ role: "user", content: userContent }],
3352
+ signal
3353
+ });
3354
+ logger.info("arena.adjudication_response", {
3355
+ claimId: claim.claimId,
3356
+ stopReason: response.stopReason
3357
+ });
3358
+ let adjudication;
3359
+ if (v2) {
3360
+ adjudication = strategy.parseAdjudicationResponse(response.text);
3361
+ adjudication.claimId = claim.claimId;
3362
+ } else {
3363
+ adjudication = parseAdjudication(claim.claimId, response.text);
3364
+ }
3365
+ ledger.appendAdjudication(adjudication);
3366
+ allAdjudications.push(adjudication);
3367
+ applyAdjudicationOutcome(claim, adjudication);
3368
+ }
3369
+ for (const claim of verifiedClaims) {
3370
+ const adjudication = {
3371
+ claimId: claim.claimId,
3372
+ outcome: "accepted",
3373
+ rationale: "Verified by peer review without contest",
3374
+ finalSummary: claim.finding.summary,
3375
+ supportingEvidenceRefs: claim.evidenceRefs
3376
+ };
3377
+ ledger.appendAdjudication(adjudication);
3378
+ allAdjudications.push(adjudication);
3379
+ }
3380
+ const remaining = ledger.getClaimsByStatus("proposed", "under_review");
3381
+ for (const claim of remaining) {
3382
+ markUnresolved(claim);
3383
+ }
3384
+ const accepted = allAdjudications.filter(
3385
+ (a) => a.outcome === "accepted" || a.outcome === "accepted_with_revision"
3386
+ ).length;
3387
+ const unresolved = ledger.getClaimsByStatus("unresolved").length;
3388
+ logger.info("arena.adjudication_done", {
3389
+ total: allAdjudications.length,
3390
+ accepted,
3391
+ unresolved
3392
+ });
3393
+ onProgress?.({ type: "adjudication_done", accepted, unresolved });
3394
+ return allAdjudications;
3395
+ }
3396
+ function applyAdjudicationOutcome(claim, adjudication) {
3397
+ switch (adjudication.outcome) {
3398
+ case "accepted":
3399
+ case "accepted_with_revision":
3400
+ transitionClaim(claim, "verified");
3401
+ break;
3402
+ case "rejected":
3403
+ transitionClaim(claim, "rejected");
3404
+ break;
3405
+ case "unresolved":
3406
+ markUnresolved(claim);
3407
+ break;
3408
+ }
3409
+ }
3410
+ function buildFallbackAdjudicationPrompt(topic, claim) {
3411
+ const challengeText = claim.challenges.length > 0 ? claim.challenges.map((c) => `[${c.reviewer}] ${c.verdict}: ${c.reason}`).join("\n") : "No challenges.";
3412
+ const debateText = claim.debateRounds.length > 0 ? claim.debateRounds.map(
3413
+ (r) => `Round ${r.round}:
3414
+ ` + r.participants.map((t) => ` [${t.participant}] ${t.stance}: ${t.summary}`).join("\n") + `
3415
+ ${r.resolved ? "\u2192 Resolved" : "\u2192 Unresolved"}`
3416
+ ).join("\n\n") : "No debate rounds.";
3417
+ return `## Topic: ${topic}
3418
+
3419
+ ## Claim Under Adjudication
3420
+ [${claim.claimId}] ${claim.finding.title}
3421
+ ${claim.finding.summary}
3422
+ Owner: ${claim.owner} | Status: ${claim.status}
3423
+
3424
+ ## Challenges
3425
+ ${challengeText}
3426
+
3427
+ ## Debate
3428
+ ${debateText}
3429
+
3430
+ As moderator, adjudicate this claim based on all available evidence.
3431
+ Respond ONLY with JSON:
3432
+ {"outcome": "accepted|accepted_with_revision|rejected|unresolved", "rationale": "...", "finalSummary": "revised claim summary if needed", "supportingEvidenceRefs": ["..."]}`;
3433
+ }
3434
+
3435
+ // src/arena/phases/build-consensus.ts
3436
+ init_esm_shims();
3437
+ async function buildConsensus(options) {
3438
+ const { concluder, strategy, topic, reports, reviews, claimSummary, signal, onProgress } = options;
3439
+ onProgress?.({ type: "consensus_start" });
3440
+ const client = await createLLMClient({
3441
+ ...concluder.llm,
3442
+ enableStreaming: false
3443
+ });
3444
+ const systemPrompt = strategy.consensusSystemPrompt();
3445
+ let userContent;
3446
+ const v2 = isStrategyV2(strategy);
3447
+ if (v2 && claimSummary) {
3448
+ userContent = strategy.claimAwareConsensusUserPrompt(topic, reports, reviews, claimSummary);
3449
+ logger.info("arena.consensus_claim_aware", {
3450
+ verified: claimSummary.verified.length,
3451
+ unresolved: claimSummary.unresolved.length,
3452
+ contested: claimSummary.contested.length,
3453
+ rejected: claimSummary.rejected.length
3454
+ });
3455
+ } else {
3456
+ userContent = strategy.consensusUserPrompt(topic, reports, reviews);
3457
+ }
3458
+ const response = await client.createMessage({
3459
+ systemPrompt,
3460
+ messages: [{ role: "user", content: userContent }],
3461
+ signal
3462
+ });
3463
+ logger.info("arena.consensus_raw_response", {
3464
+ text: response.text,
3465
+ stopReason: response.stopReason
3466
+ });
3467
+ if (response.stopReason === "length") {
3468
+ logger.warn("arena.consensus_truncated", {
3469
+ textLen: response.text?.length ?? 0,
3470
+ maxTokens: concluder.llm.maxTokens
3471
+ });
3472
+ const retryResponse = await client.createMessage({
3473
+ systemPrompt,
3474
+ messages: [
3475
+ { role: "user", content: userContent },
3476
+ { role: "assistant", content: response.text },
3477
+ {
3478
+ role: "user",
3479
+ content: "Your previous response was truncated. Please output a COMPLETE but more concise version of the consensus JSON. Keep all sections but use shorter summaries. Respond ONLY with the complete JSON object."
3480
+ }
3481
+ ],
3482
+ signal
3483
+ });
3484
+ logger.info("arena.consensus_retry_response", {
3485
+ textLen: retryResponse.text?.length ?? 0,
3486
+ stopReason: retryResponse.stopReason
3487
+ });
3488
+ if (retryResponse.stopReason === "length") {
3489
+ logger.warn("arena.consensus_still_truncated", {
3490
+ textLen: retryResponse.text?.length ?? 0
3491
+ });
3492
+ }
3493
+ const consensus2 = strategy.parseConsensusResponse(retryResponse.text);
3494
+ onProgress?.({ type: "consensus_done", consensus: consensus2 });
3495
+ return consensus2;
3496
+ }
3497
+ const consensus = strategy.parseConsensusResponse(response.text);
3498
+ onProgress?.({ type: "consensus_done", consensus });
3499
+ return consensus;
3500
+ }
3501
+
3502
+ // src/arena/ledger.ts
3503
+ init_esm_shims();
3504
+ var WARN_CLAIMS = 50;
3505
+ var WARN_PACKETS = 200;
3506
+ var WARN_CHALLENGES = 100;
3507
+ var ArenaLedger = class {
3508
+ ledger;
3509
+ index;
3510
+ constructor() {
3511
+ this.ledger = {
3512
+ dossiers: [],
3513
+ evidencePackets: [],
3514
+ toolTraces: [],
3515
+ claims: [],
3516
+ challenges: [],
3517
+ requestedChecks: [],
3518
+ adjudications: []
3519
+ };
3520
+ this.index = {
3521
+ claimsById: /* @__PURE__ */ new Map(),
3522
+ packetsById: /* @__PURE__ */ new Map(),
3523
+ requestsById: /* @__PURE__ */ new Map()
3524
+ };
3525
+ }
3526
+ // ─── Append operations ──────────────────────────────────────
3527
+ /** Check if ledger is approaching memory limits and log warnings */
3528
+ checkGrowth() {
3529
+ const claims = this.ledger.claims.length;
3530
+ const packets = this.ledger.evidencePackets.length;
3531
+ const challenges = this.ledger.challenges.length;
3532
+ if (claims === WARN_CLAIMS || packets === WARN_PACKETS || challenges === WARN_CHALLENGES) {
3533
+ logger.warn("arena.ledger_growth", { claims, packets, challenges, toolTraces: this.ledger.toolTraces.length });
3534
+ }
3535
+ }
3536
+ appendDossier(dossier) {
3537
+ this.ledger.dossiers.push(dossier);
3538
+ for (const packet of dossier.evidencePackets) {
3539
+ this.appendEvidencePacket(packet);
3540
+ }
3541
+ for (const trace of dossier.toolTrace) {
3542
+ this.ledger.toolTraces.push(trace);
3543
+ }
3544
+ }
3545
+ appendEvidencePacket(packet) {
3546
+ if (!this.index.packetsById.has(packet.packetId)) {
3547
+ this.ledger.evidencePackets.push(packet);
3548
+ this.index.packetsById.set(packet.packetId, packet);
3549
+ }
3550
+ }
3551
+ appendClaim(claim) {
3552
+ this.ledger.claims.push(claim);
3553
+ this.index.claimsById.set(claim.claimId, claim);
3554
+ this.checkGrowth();
3555
+ }
3556
+ appendChallenge(challenge) {
3557
+ this.ledger.challenges.push(challenge);
3558
+ const claim = this.index.claimsById.get(challenge.claimId);
3559
+ if (claim) {
3560
+ claim.challenges.push(challenge);
3561
+ }
3562
+ this.checkGrowth();
3563
+ if (challenge.requestedChecks) {
3564
+ for (const check of challenge.requestedChecks) {
3565
+ this.appendRequestedCheck(check);
3566
+ }
3567
+ }
3568
+ }
3569
+ appendRequestedCheck(check) {
3570
+ if (!this.index.requestsById.has(check.requestId)) {
3571
+ this.ledger.requestedChecks.push(check);
3572
+ this.index.requestsById.set(check.requestId, check);
3573
+ }
3574
+ }
3575
+ appendAdjudication(adjudication) {
3576
+ this.ledger.adjudications.push(adjudication);
3577
+ const claim = this.index.claimsById.get(adjudication.claimId);
3578
+ if (claim) {
3579
+ claim.adjudication = adjudication;
3580
+ }
3581
+ }
3582
+ // ─── Query operations ───────────────────────────────────────
3583
+ /**
3584
+ * Return a read-only reference to the full ledger.
3585
+ *
3586
+ * Note: `Readonly<>` is shallow — inner arrays are still mutable at the
3587
+ * type level. Callers MUST NOT mutate the returned object; use the
3588
+ * append* methods instead. A deep-freeze or structural clone can be
3589
+ * added later if external consumers need a truly immutable snapshot.
3590
+ */
3591
+ getSnapshot() {
3592
+ return this.ledger;
3593
+ }
3594
+ getClaimById(claimId) {
3595
+ return this.index.claimsById.get(claimId);
3596
+ }
3597
+ getPacketById(packetId) {
3598
+ return this.index.packetsById.get(packetId);
3599
+ }
3600
+ getAllClaims() {
3601
+ return this.ledger.claims;
3602
+ }
3603
+ getClaimsByStatus(...statuses) {
3604
+ const set = new Set(statuses);
3605
+ return this.ledger.claims.filter((c) => set.has(c.status));
3606
+ }
3607
+ getClaimsByOwner(owner) {
3608
+ return this.ledger.claims.filter((c) => c.owner === owner);
3609
+ }
3610
+ getChallengesForClaim(claimId) {
3611
+ return this.ledger.challenges.filter((c) => c.claimId === claimId);
3612
+ }
3613
+ getPendingChecks() {
3614
+ return this.ledger.requestedChecks;
3615
+ }
3616
+ getPendingChecksForClaim(claimId) {
3617
+ return this.ledger.requestedChecks.filter((c) => c.claimId === claimId);
3618
+ }
3619
+ getPacketsForClaim(claimId) {
3620
+ const claim = this.index.claimsById.get(claimId);
3621
+ if (!claim) return [];
3622
+ return claim.evidencePacketIds.map((id) => this.index.packetsById.get(id)).filter((p) => p !== void 0);
3623
+ }
3624
+ getDossiers() {
3625
+ return this.ledger.dossiers;
3626
+ }
3627
+ getDossierByParticipant(participant) {
3628
+ const dossiers = this.ledger.dossiers.filter((d) => d.participant === participant);
3629
+ return dossiers[dossiers.length - 1];
3630
+ }
3631
+ };
3632
+
3633
+ // src/arena/arena.ts
3634
+ init_esm_shims();
3635
+
3636
+ // src/arena/phases/planning-detail-expansion.ts
3637
+ init_esm_shims();
3638
+ var MAX_EXPANSION_TOOL_ROUNDS = 3;
3639
+ async function runDetailExpansion(options) {
3640
+ const { concluder, strategy, topic, phases, ledger, limits, signal, onProgress } = options;
3641
+ const tools = options.enableContextTools !== false ? options.contextTools ?? CONTEXT_TOOLS : void 0;
3642
+ const toExpand = phases.slice(0, limits.maxExpandedPhasesPerRun);
3643
+ onProgress?.({ type: "roadmap_expansion_start", phaseCount: toExpand.length });
3644
+ logger.info("arena.detail_expansion_start", { phaseCount: toExpand.length });
3645
+ const details = [];
3646
+ const client = await createLLMClient({
3647
+ ...concluder.llm,
3648
+ enableStreaming: false
3649
+ });
3650
+ const systemPrompt = strategy.detailExpansionSystemPrompt();
3651
+ for (const phase of toExpand) {
3652
+ signal?.throwIfAborted();
3653
+ const relevantClaimIds = phase.relatedFindings ?? [];
3654
+ const digest = buildDigest(ledger, { round: 1, relevantClaimIds });
3655
+ const userContent = strategy.detailExpansionUserPrompt(topic, phase, digest);
3656
+ const messages = [{ role: "user", content: userContent }];
3657
+ let finalText = "";
3658
+ const maxRounds = tools ? Math.min(MAX_EXPANSION_TOOL_ROUNDS, MAX_TOOL_ROUNDS) : 0;
3659
+ for (let round = 0; round <= maxRounds; round++) {
3660
+ const response = await client.createMessage({
3661
+ systemPrompt,
3662
+ messages,
3663
+ tools,
3664
+ signal
3665
+ });
3666
+ const hasTools2 = response.toolCalls && response.toolCalls.length > 0;
3667
+ logger.info("arena.detail_expansion_round", {
3668
+ phase: phase.title,
3669
+ round,
3670
+ toolCount: response.toolCalls?.length ?? 0,
3671
+ stopReason: response.stopReason
3672
+ });
3673
+ if (!hasTools2) {
3674
+ finalText = response.text;
3675
+ break;
3676
+ }
3677
+ const assistantBlocks = [];
3678
+ if (response.text) {
3679
+ assistantBlocks.push({ type: "text", text: response.text });
3680
+ }
3681
+ for (const tc of response.toolCalls) {
3682
+ assistantBlocks.push({
3683
+ type: "tool_use",
3684
+ id: tc.id,
3685
+ name: tc.toolName,
3686
+ input: tc.args
3687
+ });
3688
+ }
3689
+ messages.push({ role: "assistant", content: assistantBlocks });
3690
+ const toolResultBlocks = [];
3691
+ for (const tc of response.toolCalls) {
3692
+ const result = executeContextTool(tc);
3693
+ toolResultBlocks.push({
3694
+ type: "tool_result",
3695
+ tool_use_id: tc.id,
3696
+ content: result.slice(0, 15e3)
3697
+ });
3698
+ }
3699
+ messages.push({ role: "user", content: toolResultBlocks });
3700
+ if (round === maxRounds) {
3701
+ finalText = response.text;
3702
+ }
3703
+ }
3704
+ if (!finalText) {
3705
+ finalText = "";
3706
+ }
3707
+ logger.info("arena.detail_expansion_phase", {
3708
+ phase: phase.title,
3709
+ textLen: finalText.length
3710
+ });
3711
+ const detail = strategy.parseDetailExpansionResponse(finalText);
3712
+ if (!detail.phaseTitle) detail.phaseTitle = phase.title;
3713
+ if (detail.targetFiles.length === 0 && detail.codeChanges.length === 0) {
3714
+ logger.warn("arena.detail_expansion_sparse", {
3715
+ phase: phase.title,
3716
+ objective: detail.objective.slice(0, 200)
3717
+ });
3718
+ }
3719
+ details.push(detail);
3720
+ }
3721
+ logger.info("arena.detail_expansion_done", { detailCount: details.length });
3722
+ onProgress?.({ type: "roadmap_expansion_done", detailCount: details.length });
3723
+ return details;
3724
+ }
3725
+
3726
+ // src/arena/strategies/language-wrapper.ts
3727
+ init_esm_shims();
3728
+ function detectLanguageInstruction(topic) {
3729
+ const nonAscii = topic.replace(/[\x00-\x7F]/g, "");
3730
+ const ratio = nonAscii.length / Math.max(topic.length, 1);
3731
+ if (ratio < 0.15) return "";
3732
+ if (/[\u4e00-\u9fff\u3400-\u4dbf]/.test(topic)) {
3733
+ return "IMPORTANT: The user's query is in Chinese. You MUST respond in Chinese (\u4E2D\u6587). All text output \u2014 summaries, findings, titles, descriptions, rationale \u2014 must be written in Chinese. JSON field values must be in Chinese.";
3734
+ }
3735
+ if (/[\u3040-\u309f\u30a0-\u30ff]/.test(topic)) {
3736
+ return "IMPORTANT: The user's query is in Japanese. You MUST respond in Japanese (\u65E5\u672C\u8A9E). All text output must be in Japanese. JSON field values must be in Japanese.";
3737
+ }
3738
+ if (/[\uac00-\ud7af]/.test(topic)) {
3739
+ return "IMPORTANT: The user's query is in Korean. You MUST respond in Korean (\uD55C\uAD6D\uC5B4). All text output must be in Korean. JSON field values must be in Korean.";
3740
+ }
3741
+ if (/[\u0400-\u04ff]/.test(topic)) {
3742
+ return "IMPORTANT: The user's query is in Russian. You MUST respond in Russian (\u0440\u0443\u0441\u0441\u043A\u0438\u0439). All text output must be in Russian. JSON field values must be in Russian.";
3743
+ }
3744
+ if (/[\u0600-\u06ff]/.test(topic)) {
3745
+ return "IMPORTANT: The user's query is in Arabic. You MUST respond in Arabic (\u0627\u0644\u0639\u0631\u0628\u064A\u0629). All text output must be in Arabic. JSON field values must be in Arabic.";
3746
+ }
3747
+ return "IMPORTANT: Respond in the same language as the user's query. All text output \u2014 summaries, findings, titles, descriptions \u2014 must match the query language.";
3748
+ }
3749
+ function withLanguage(strategy, topic) {
3750
+ const langInstruction = detectLanguageInstruction(topic);
3751
+ if (!langInstruction) return strategy;
3752
+ return {
3753
+ researchSystemPrompt(name) {
3754
+ return `${langInstruction}
3755
+
3756
+ ${strategy.researchSystemPrompt(name)}`;
3757
+ },
3758
+ researchUserPrompt(t, ctx) {
3759
+ return strategy.researchUserPrompt(t, ctx);
3760
+ },
3761
+ parseResearchResponse(participant, text) {
3762
+ return strategy.parseResearchResponse(participant, text);
3763
+ },
3764
+ crossReviewSystemPrompt(reviewerName) {
3765
+ return `${langInstruction}
3766
+
3767
+ ${strategy.crossReviewSystemPrompt(reviewerName)}`;
3768
+ },
3769
+ crossReviewUserPrompt(t, my, others) {
3770
+ return strategy.crossReviewUserPrompt(t, my, others);
3771
+ },
3772
+ parseCrossReviewResponse(reviewer, text) {
3773
+ return strategy.parseCrossReviewResponse(reviewer, text);
3774
+ },
3775
+ consensusSystemPrompt() {
3776
+ return `${langInstruction}
3777
+
3778
+ ${strategy.consensusSystemPrompt()}`;
3779
+ },
3780
+ consensusUserPrompt(t, reports, reviews) {
3781
+ return strategy.consensusUserPrompt(t, reports, reviews);
3782
+ },
3783
+ parseConsensusResponse(text) {
3784
+ return strategy.parseConsensusResponse(text);
3785
+ },
3786
+ preferredFindingKinds() {
3787
+ return strategy.preferredFindingKinds();
3788
+ },
3789
+ // ─── V2 forwarding (conditional) ─────────────────────────────
3790
+ ...isStrategyV2(strategy) ? {
3791
+ verificationReviewUserPrompt(topic2, myReport, claims, digest) {
3792
+ return strategy.verificationReviewUserPrompt(topic2, myReport, claims, digest);
3793
+ },
3794
+ parseVerificationReviewResponse(reviewer, text) {
3795
+ return strategy.parseVerificationReviewResponse(reviewer, text);
3796
+ },
3797
+ debateTurnUserPrompt(topic2, claim, priorTurns, digest) {
3798
+ return strategy.debateTurnUserPrompt(topic2, claim, priorTurns, digest);
3799
+ },
3800
+ parseDebateTurnResponse(participant, text) {
3801
+ return strategy.parseDebateTurnResponse(participant, text);
3802
+ },
3803
+ adjudicationUserPrompt(topic2, claim, rounds, digest) {
3804
+ return strategy.adjudicationUserPrompt(topic2, claim, rounds, digest);
3805
+ },
3806
+ parseAdjudicationResponse(text) {
3807
+ return strategy.parseAdjudicationResponse(text);
3808
+ },
3809
+ claimAwareConsensusUserPrompt(topic2, reports, reviews, claimSummary) {
3810
+ return strategy.claimAwareConsensusUserPrompt(topic2, reports, reviews, claimSummary);
3811
+ }
3812
+ } : {}
3813
+ };
3814
+ }
3815
+
3816
+ // src/arena/arena.ts
3817
+ var Arena = class {
3818
+ config;
3819
+ strategy;
3820
+ limits;
3821
+ constructor(config) {
3822
+ if (config.participants.length < 2) {
3823
+ throw new Error("Arena requires at least 2 participants");
3824
+ }
3825
+ const mode = config.mode ?? "review";
3826
+ const defaults = ARENA_MODE_DEFAULTS[mode];
3827
+ this.config = {
3828
+ mode,
3829
+ maxDiscussionRounds: config.maxDiscussionRounds ?? defaults.maxDiscussionRounds,
3830
+ ...config
3831
+ };
3832
+ this.limits = config.executionLimits ?? DEFAULT_EXECUTION_LIMITS;
3833
+ this.strategy = config.strategy ?? getStrategy(mode);
3834
+ }
3835
+ /**
3836
+ * Run a full arena session.
3837
+ *
3838
+ * @param topic - User's topic/request (natural language)
3839
+ * @param flags - Optional explicit overrides (mode, base, head)
3840
+ */
3841
+ async run(topic, flags) {
3842
+ const participantNames = this.config.participants.map((p) => p.name);
3843
+ const signal = this.config.signal;
3844
+ logger.info("arena.start", { mode: this.config.mode, participants: participantNames });
3845
+ signal?.throwIfAborted();
3846
+ const llmConfig = this.config.participants[0].llm;
3847
+ const plan = await planArena(topic, llmConfig, flags, signal);
3848
+ this.config.onProgress?.({ type: "plan_resolved", plan });
3849
+ logger.info("arena.plan", {
3850
+ mode: plan.mode,
3851
+ lenses: plan.lenses.map((l) => l.name),
3852
+ sources: plan.sources.map((s) => s.kind),
3853
+ subject: plan.subject.label,
3854
+ confidence: plan.confidence
3855
+ });
3856
+ if (!flags?.mode && plan.mode !== this.config.mode) {
3857
+ this.config.mode = plan.mode;
3858
+ }
3859
+ signal?.throwIfAborted();
3860
+ const { artifacts, quickFacts } = collectEvidence(plan, topic);
3861
+ this.config.onProgress?.({ type: "evidence_collected", artifacts });
3862
+ logger.info("arena.evidence", {
3863
+ artifactCount: artifacts.length,
3864
+ sources: plan.sources.map((s) => s.kind)
3865
+ });
3866
+ const baseContext = { plan, artifacts, quickFacts };
3867
+ this.strategy = this.config.strategy ?? getStrategyForPlan(plan);
3868
+ this.strategy = withLanguage(this.strategy, topic);
3869
+ const contextTools = this.config.enableContextTools !== false ? selectTools(plan) : void 0;
3870
+ signal?.throwIfAborted();
3871
+ logger.info("arena.research_phase", { participants: participantNames });
3872
+ const researchResults = await runParticipantResearchWithDossiers({
3873
+ participants: this.config.participants,
3874
+ strategy: this.strategy,
3875
+ topic,
3876
+ baseContext,
3877
+ enableContextTools: this.config.enableContextTools ?? true,
3878
+ contextTools,
3879
+ signal,
3880
+ onProgress: this.config.onProgress
3881
+ });
3882
+ const reports = researchResults.map((r) => r.report);
3883
+ const dossiers = researchResults.map((r) => r.dossier);
3884
+ signal?.throwIfAborted();
3885
+ const ledger = new ArenaLedger();
3886
+ for (const dossier of dossiers) {
3887
+ ledger.appendDossier(dossier);
3888
+ }
3889
+ const claims = registerClaims({
3890
+ dossiers,
3891
+ ledger,
3892
+ onProgress: this.config.onProgress
3893
+ });
3894
+ logger.info("arena.claims_registered", {
3895
+ claimCount: claims.length,
3896
+ byOwner: Object.fromEntries(
3897
+ participantNames.map((name) => [
3898
+ name,
3899
+ claims.filter((c) => c.owner === name).length
3900
+ ])
3901
+ )
3902
+ });
3903
+ signal?.throwIfAborted();
3904
+ const concluderName = this.config.concluder ?? participantNames[0];
3905
+ const concluderMatch = this.config.participants.find((p) => p.name === concluderName);
3906
+ if (!concluderMatch && this.config.concluder) {
3907
+ logger.warn("arena.concluder_not_found", {
3908
+ requested: this.config.concluder,
3909
+ fallback: this.config.participants[0].name
3910
+ });
3911
+ }
3912
+ const concluder = concluderMatch ?? this.config.participants[0];
3913
+ const enableTools = this.config.enableContextTools !== false;
3914
+ if (this.config.mode === "planning") {
3915
+ return this.runPlanningPath({
3916
+ topic,
3917
+ participantNames,
3918
+ plan,
3919
+ baseContext,
3920
+ reports,
3921
+ dossiers,
3922
+ ledger,
3923
+ concluder,
3924
+ contextTools,
3925
+ enableContextTools: enableTools,
3926
+ signal
3927
+ });
3928
+ }
3929
+ return this.runReviewDiscussionPath({
3930
+ topic,
3931
+ participantNames,
3932
+ plan,
3933
+ baseContext,
3934
+ reports,
3935
+ dossiers,
3936
+ ledger,
3937
+ concluder,
3938
+ signal
3939
+ });
3940
+ }
3941
+ /**
3942
+ * Planning path: merge-oriented review → roadmap consensus → detail expansion.
3943
+ *
3944
+ * Planning mode does NOT enter heavy debate/adjudication. Contested findings
3945
+ * are converted to open questions or dependency risks in the roadmap.
3946
+ */
3947
+ async runPlanningPath(ctx) {
3948
+ const {
3949
+ topic,
3950
+ participantNames,
3951
+ plan,
3952
+ baseContext,
3953
+ reports,
3954
+ dossiers,
3955
+ ledger,
3956
+ concluder,
3957
+ contextTools,
3958
+ enableContextTools,
3959
+ signal
3960
+ } = ctx;
3961
+ logger.info("arena.planning_merge_review_phase");
3962
+ const { reviews } = await runVerificationReview({
3963
+ participants: this.config.participants,
3964
+ strategy: this.strategy,
3965
+ topic,
3966
+ reports,
3967
+ ledger,
3968
+ limits: this.limits,
3969
+ mode: "planning",
3970
+ signal,
3971
+ onProgress: this.config.onProgress
3972
+ });
3973
+ signal?.throwIfAborted();
3974
+ const allClaims = ledger.getAllClaims();
3975
+ const claimSummary = {
3976
+ verified: allClaims.filter((c) => c.status === "verified"),
3977
+ contested: allClaims.filter((c) => c.status === "contested"),
3978
+ unresolved: allClaims.filter((c) => c.status === "unresolved"),
3979
+ rejected: allClaims.filter((c) => c.status === "rejected")
3980
+ };
3981
+ logger.info("arena.planning_consensus_phase", { concluder: concluder.name });
3982
+ const consensus = await buildConsensus({
3983
+ concluder,
3984
+ strategy: this.strategy,
3985
+ topic,
3986
+ reports,
3987
+ reviews,
3988
+ claimSummary,
3989
+ signal,
3990
+ onProgress: this.config.onProgress
3991
+ });
3992
+ signal?.throwIfAborted();
3993
+ if (consensus.roadmap.length > 0 && isStrategyPlanning(this.strategy)) {
3994
+ logger.info("arena.detail_expansion_phase", { phaseCount: consensus.roadmap.length });
3995
+ try {
3996
+ const details = await runDetailExpansion({
3997
+ concluder,
3998
+ strategy: this.strategy,
3999
+ topic,
4000
+ phases: consensus.roadmap,
4001
+ ledger,
4002
+ limits: this.limits,
4003
+ enableContextTools,
4004
+ contextTools,
4005
+ signal,
4006
+ onProgress: this.config.onProgress
4007
+ });
4008
+ consensus.roadmapDetails = details;
4009
+ } catch (err) {
4010
+ logger.warn("arena.detail_expansion_failed", {
4011
+ error: err.message,
4012
+ phaseCount: consensus.roadmap.length
4013
+ });
4014
+ }
4015
+ }
4016
+ return {
4017
+ topic,
4018
+ mode: this.config.mode,
4019
+ participants: participantNames,
4020
+ plan,
4021
+ baseContext,
4022
+ reports,
4023
+ dossiers,
4024
+ claims: allClaims,
4025
+ reviews,
4026
+ consensus
4027
+ };
4028
+ }
4029
+ /**
4030
+ * Review/Discussion path: verification review → debate → adjudication → consensus.
4031
+ *
4032
+ * This is the heavy trust loop for claim verification.
4033
+ */
4034
+ async runReviewDiscussionPath(ctx) {
4035
+ const { topic, participantNames, plan, baseContext, reports, dossiers, ledger, concluder, signal } = ctx;
4036
+ logger.info("arena.verification_review_phase");
4037
+ const { reviews } = await runVerificationReview({
4038
+ participants: this.config.participants,
4039
+ strategy: this.strategy,
4040
+ topic,
4041
+ reports,
4042
+ ledger,
4043
+ limits: this.limits,
4044
+ signal,
4045
+ onProgress: this.config.onProgress
4046
+ });
4047
+ signal?.throwIfAborted();
4048
+ logger.info("arena.debate_phase");
4049
+ const debateRounds = await runDebateRounds({
4050
+ participants: this.config.participants,
4051
+ strategy: this.strategy,
4052
+ topic,
4053
+ ledger,
4054
+ limits: this.limits,
4055
+ maxRounds: this.config.maxDiscussionRounds,
4056
+ signal,
4057
+ onProgress: this.config.onProgress
4058
+ });
4059
+ signal?.throwIfAborted();
4060
+ logger.info("arena.adjudication_phase", { concluder: concluder.name });
4061
+ const adjudications = await runAdjudication({
4062
+ concluder,
4063
+ strategy: this.strategy,
4064
+ topic,
4065
+ ledger,
4066
+ signal,
4067
+ onProgress: this.config.onProgress
4068
+ });
4069
+ signal?.throwIfAborted();
4070
+ const allClaims = ledger.getAllClaims();
4071
+ const claimSummary = {
4072
+ verified: allClaims.filter((c) => c.status === "verified"),
4073
+ contested: allClaims.filter((c) => c.status === "contested"),
4074
+ unresolved: allClaims.filter((c) => c.status === "unresolved"),
4075
+ rejected: allClaims.filter((c) => c.status === "rejected")
4076
+ };
4077
+ logger.info("arena.consensus_phase", {
4078
+ concluder: concluder.name,
4079
+ verified: claimSummary.verified.length,
4080
+ unresolved: claimSummary.unresolved.length
4081
+ });
4082
+ const consensus = await buildConsensus({
4083
+ concluder,
4084
+ strategy: this.strategy,
4085
+ topic,
4086
+ reports,
4087
+ reviews,
4088
+ claimSummary,
4089
+ signal,
4090
+ onProgress: this.config.onProgress
4091
+ });
4092
+ return {
4093
+ topic,
4094
+ mode: this.config.mode,
4095
+ participants: participantNames,
4096
+ plan,
4097
+ baseContext,
4098
+ reports,
4099
+ dossiers,
4100
+ claims: allClaims,
4101
+ reviews,
4102
+ debateRounds,
4103
+ adjudications,
4104
+ consensus
4105
+ };
4106
+ }
4107
+ };
4108
+
4109
+ // src/arena/model-presets.ts
4110
+ init_esm_shims();
4111
+ var MODEL_PRESETS = {
4112
+ claude: { provider: "openai", model: "anthropic/claude-opus-4.6", maxOutputTokens: 32e3 },
4113
+ "claude-sonnet": { provider: "openai", model: "anthropic/claude-sonnet-4.6", maxOutputTokens: 16e3 },
4114
+ "claude-haiku": { provider: "openai", model: "anthropic/claude-haiku-4.5", maxOutputTokens: 8192 },
4115
+ gpt: { provider: "openai", model: "openai/gpt-5.4", maxOutputTokens: 32e3 },
4116
+ "gpt4o": { provider: "openai", model: "openai/gpt-4o", maxOutputTokens: 16384 },
4117
+ o4: { provider: "openai", model: "openai/o4-mini", maxOutputTokens: 1e5 },
4118
+ o3: { provider: "openai", model: "openai/o3", maxOutputTokens: 1e5 },
4119
+ deepseek: { provider: "openai", model: "deepseek/deepseek-v3.2", maxOutputTokens: 8192 },
4120
+ "deepseek-r1": { provider: "openai", model: "deepseek/deepseek-r1", maxOutputTokens: 8192 },
4121
+ gemini: { provider: "openai", model: "google/gemini-3.1-pro-preview", maxOutputTokens: 65536 },
4122
+ "gemini-2.5": { provider: "openai", model: "google/gemini-2.5-pro", maxOutputTokens: 65536 },
4123
+ "gemini-flash": { provider: "openai", model: "google/gemini-3-flash-preview", maxOutputTokens: 65536 },
4124
+ qwen: { provider: "openai", model: "qwen/qwen3-235b-a22b", maxOutputTokens: 8192 },
4125
+ "qwen-coder": { provider: "openai", model: "qwen/qwen3-coder", maxOutputTokens: 16384 },
4126
+ llama: { provider: "openai", model: "meta-llama/llama-4-maverick", maxOutputTokens: 32e3 },
4127
+ devstral: { provider: "openai", model: "mistralai/devstral-medium", maxOutputTokens: 24e3 }
4128
+ };
4129
+ function getMaxOutputTokens(model) {
4130
+ const byKey = MODEL_PRESETS[model];
4131
+ if (byKey) return byKey.maxOutputTokens;
4132
+ const byModel = Object.values(MODEL_PRESETS).find((p) => p.model === model);
4133
+ return byModel?.maxOutputTokens ?? 8192;
4134
+ }
4135
+
4136
+ // src/arena/render/terminal.ts
4137
+ init_esm_shims();
4138
+ import chalk from "chalk";
4139
+ function formatArenaResult(result) {
4140
+ const modeLabel = result.mode.charAt(0).toUpperCase() + result.mode.slice(1);
4141
+ const lines = [];
4142
+ lines.push("");
4143
+ lines.push(chalk.bold(` \u2550\u2550\u2550 ${modeLabel} Conclusion \u2550\u2550\u2550`));
4144
+ lines.push("");
4145
+ if (result.consensus.summary) {
4146
+ lines.push(` ${result.consensus.summary}`);
4147
+ lines.push("");
4148
+ }
4149
+ if (result.mode === "planning") {
4150
+ lines.push(...formatRoadmapSection(result.consensus.roadmap));
4151
+ if (result.consensus.roadmapDetails && result.consensus.roadmapDetails.length > 0) {
4152
+ lines.push(...formatRoadmapDetailsSection(result.consensus.roadmapDetails));
4153
+ }
4154
+ }
4155
+ for (const section of getOrderedConsensusSections(result)) {
4156
+ lines.push(...formatConsensusSection(section.title, section.items, section.color, section.icon));
4157
+ }
4158
+ if (result.mode !== "planning") {
4159
+ lines.push(...formatRoadmapSection(result.consensus.roadmap));
4160
+ }
4161
+ if (result.consensus.nextActions.length > 0) {
4162
+ lines.push(chalk.bold.white("\n Next Actions:"));
4163
+ for (const action of result.consensus.nextActions) {
4164
+ const pri = action.priority === "high" ? chalk.red("HIGH") : action.priority === "medium" ? chalk.yellow("MED") : chalk.dim("LOW");
4165
+ lines.push(` ${chalk.white("\u2192")} [${pri}${chalk.white("]")} ${action.title}`);
4166
+ if (action.rationale) {
4167
+ lines.push(chalk.dim(` ${action.rationale}`));
4168
+ }
4169
+ }
4170
+ }
4171
+ lines.push("");
4172
+ const planInfo = result.plan ? ` | Lenses: ${result.plan.lenses.map((l) => l.name).join(", ")} | Sources: ${result.plan.sources.map((s) => s.kind).join(", ")}` : "";
4173
+ lines.push(chalk.dim(
4174
+ ` Mode: ${modeLabel} | Findings: ${countFindings(result)} | Models: ${result.participants.join(", ")}` + planInfo
4175
+ ));
4176
+ lines.push("");
4177
+ return lines.join("\n");
4178
+ }
4179
+ function printArenaResult(result) {
4180
+ console.log(formatArenaResult(result));
4181
+ }
4182
+ function formatConsensusSection(title, items, color, icon) {
4183
+ if (items.length === 0) return [];
4184
+ const lines = [];
4185
+ lines.push(color(`
4186
+ ${title}:`));
4187
+ for (const item of items) {
4188
+ lines.push(color(` ${icon} ${item.title}`));
4189
+ if (item.summary) {
4190
+ lines.push(chalk.dim(` ${item.summary}`));
4191
+ }
4192
+ if (item.challenge.length > 0) {
4193
+ lines.push(chalk.dim(` Challenged by: ${item.challenge.join(", ")}`));
4194
+ }
4195
+ }
4196
+ return lines;
4197
+ }
4198
+ function countFindings(result) {
4199
+ return result.reports.reduce((sum, r) => sum + r.findings.length, 0);
4200
+ }
4201
+ function formatRoadmapSection(phases) {
4202
+ if (phases.length === 0) return [];
4203
+ const lines = [];
4204
+ lines.push(chalk.bold.white("\n Roadmap:"));
4205
+ for (const [index, phase] of phases.entries()) {
4206
+ const pri = phase.priority === "high" ? chalk.red("HIGH") : phase.priority === "medium" ? chalk.yellow("MED") : chalk.dim("LOW");
4207
+ lines.push(` ${chalk.white("\u2192")} Phase ${index + 1}: ${phase.title} [${pri}${chalk.white("]")}`);
4208
+ if (phase.goal) {
4209
+ lines.push(chalk.dim(` Goal: ${phase.goal}`));
4210
+ }
4211
+ if (phase.scope.length > 0) {
4212
+ lines.push(chalk.dim(` Scope: ${phase.scope.join("; ")}`));
4213
+ }
4214
+ if (phase.deliverables.length > 0) {
4215
+ lines.push(chalk.dim(` Deliverables: ${phase.deliverables.join("; ")}`));
4216
+ }
4217
+ if (phase.dependencies.length > 0) {
4218
+ lines.push(chalk.dim(` Dependencies: ${phase.dependencies.join("; ")}`));
4219
+ }
4220
+ if (phase.risks.length > 0) {
4221
+ lines.push(chalk.dim(` Risks: ${phase.risks.join("; ")}`));
4222
+ }
4223
+ if (phase.successCriteria.length > 0) {
4224
+ lines.push(chalk.dim(` Success: ${phase.successCriteria.join("; ")}`));
4225
+ }
4226
+ }
4227
+ return lines;
4228
+ }
4229
+ function formatRoadmapDetailsSection(details) {
4230
+ const lines = [];
4231
+ lines.push(chalk.bold.white("\n Implementation Details:"));
4232
+ for (const detail of details) {
4233
+ const effort = detail.effort === "large" ? chalk.red("L") : detail.effort === "medium" ? chalk.yellow("M") : chalk.green("S");
4234
+ lines.push(`
4235
+ ${chalk.white("\u25B8")} ${detail.phaseTitle} [${effort}]`);
4236
+ if (detail.objective) {
4237
+ lines.push(chalk.dim(` ${detail.objective}`));
4238
+ }
4239
+ if (detail.targetFiles.length > 0) {
4240
+ lines.push(chalk.dim(` Files: ${detail.targetFiles.join(", ")}`));
4241
+ }
4242
+ if (detail.codeChanges.length > 0) {
4243
+ for (const change of detail.codeChanges) {
4244
+ lines.push(chalk.dim(` \u2022 ${change}`));
4245
+ }
4246
+ }
4247
+ if (detail.interfaces.length > 0) {
4248
+ lines.push(chalk.dim(` Interfaces: ${detail.interfaces.join("; ")}`));
4249
+ }
4250
+ if (detail.migrationSteps.length > 0) {
4251
+ lines.push(chalk.dim(` Migration:`));
4252
+ for (const [i, step] of detail.migrationSteps.entries()) {
4253
+ lines.push(chalk.dim(` ${i + 1}. ${step}`));
4254
+ }
4255
+ }
4256
+ if (detail.validation.length > 0) {
4257
+ lines.push(chalk.dim(` Validation: ${detail.validation.join("; ")}`));
4258
+ }
4259
+ if (detail.blockers.length > 0) {
4260
+ lines.push(chalk.red(` Blockers: ${detail.blockers.join("; ")}`));
4261
+ }
4262
+ }
4263
+ return lines;
4264
+ }
4265
+ function getOrderedConsensusSections(result) {
4266
+ const VALID_KINDS = /* @__PURE__ */ new Set(["strength", "improvement", "risk", "question"]);
4267
+ const defaultOrder = ["risk", "improvement", "strength", "question"];
4268
+ const emphasize = (result.plan?.outputShape?.emphasize ?? []).filter((k) => VALID_KINDS.has(k));
4269
+ const orderedKinds = dedupeFindingKinds([...emphasize, ...defaultOrder]);
4270
+ return orderedKinds.map((kind) => {
4271
+ switch (kind) {
4272
+ case "strength":
4273
+ return { kind, title: "Strengths", items: result.consensus.strengths, color: chalk.green, icon: "\u2713" };
4274
+ case "improvement":
4275
+ return { kind, title: "Improvements", items: result.consensus.improvements, color: chalk.yellow, icon: "\u2192" };
4276
+ case "risk":
4277
+ return { kind, title: "Risks", items: result.consensus.risks, color: chalk.red, icon: "\u26A0" };
4278
+ case "question":
4279
+ return { kind, title: "Open Questions", items: result.consensus.openQuestions, color: chalk.cyan, icon: "?" };
4280
+ }
4281
+ }).filter((section) => section != null).filter((section) => section.items.length > 0);
4282
+ }
4283
+ function dedupeFindingKinds(kinds) {
4284
+ const seen = /* @__PURE__ */ new Set();
4285
+ const result = [];
4286
+ for (const kind of kinds) {
4287
+ if (!seen.has(kind)) {
4288
+ seen.add(kind);
4289
+ result.push(kind);
4290
+ }
4291
+ }
4292
+ return result;
4293
+ }
4294
+ function createProgressRenderer(sink) {
4295
+ return (event) => {
4296
+ switch (event.type) {
4297
+ case "plan_resolved":
4298
+ sink(chalk.dim(
4299
+ `Plan: ${event.plan.mode} | lenses: ${event.plan.lenses.map((l) => l.name).join(", ")} | sources: ${event.plan.sources.map((s) => s.kind).join(", ")}` + (event.plan.confidence !== "high" ? ` (${event.plan.confidence} confidence)` : "")
4300
+ ));
4301
+ break;
4302
+ case "evidence_collected":
4303
+ sink(chalk.dim(`Evidence: ${event.artifacts.length} artifacts collected`));
4304
+ break;
4305
+ case "research_start":
4306
+ sink(chalk.dim(`\u23F3 ${event.participant} researching...`));
4307
+ break;
4308
+ case "research_done": {
4309
+ const fCount = event.report.findings.length;
4310
+ sink(`${event.participant}: ${chalk.green("done")} (${fCount} findings)`);
4311
+ break;
4312
+ }
4313
+ case "context_lookup":
4314
+ for (const t of event.tools) {
4315
+ sink(chalk.dim(` \u{1F50D} ${event.participant}: ${t}`));
4316
+ }
4317
+ break;
4318
+ case "claims_registered":
4319
+ sink(chalk.dim(`${event.claimCount} claims registered`));
4320
+ break;
4321
+ case "cross_review_start":
4322
+ sink(chalk.dim("\u2500\u2500 Cross Review \u2500\u2500"));
4323
+ break;
4324
+ case "cross_review_done":
4325
+ sink(chalk.dim(`${event.reviews.length} peer reviews collected`));
4326
+ break;
4327
+ case "verification_start":
4328
+ sink(chalk.dim("\u2500\u2500 Verification Review \u2500\u2500"));
4329
+ break;
4330
+ case "verification_done":
4331
+ sink(chalk.dim(`${event.challengeCount} challenges raised`));
4332
+ break;
4333
+ case "debate_round_start":
4334
+ sink(chalk.dim(`\u2500\u2500 Debate Round ${event.round} (${event.claims.length} claims) \u2500\u2500`));
4335
+ break;
4336
+ case "debate_round_done":
4337
+ sink(chalk.dim(`Round ${event.round}: ${event.resolved} resolved`));
4338
+ break;
4339
+ case "adjudication_done":
4340
+ sink(chalk.dim(`Adjudication: ${event.accepted} accepted, ${event.unresolved} unresolved`));
4341
+ break;
4342
+ case "planning_merge_review_start":
4343
+ sink(chalk.dim("\u2500\u2500 Planning Merge Review \u2500\u2500"));
4344
+ break;
4345
+ case "planning_merge_review_done":
4346
+ sink(chalk.dim(`${event.mergeCount} merge suggestions collected`));
4347
+ break;
4348
+ case "roadmap_expansion_start":
4349
+ sink(chalk.dim(`\u2500\u2500 Expanding ${event.phaseCount} roadmap phases \u2500\u2500`));
4350
+ break;
4351
+ case "roadmap_expansion_done":
4352
+ sink(chalk.dim(`${event.detailCount} phase details generated`));
4353
+ break;
4354
+ case "consensus_start":
4355
+ sink(chalk.dim("\u23F3 Building consensus..."));
4356
+ break;
4357
+ case "consensus_done":
4358
+ break;
4359
+ }
4360
+ };
4361
+ }
4362
+ function renderProgress(event) {
4363
+ createProgressRenderer((text) => console.log(` ${text}`))(event);
4364
+ }
4365
+
4366
+ // src/arena/render/session.ts
4367
+ init_esm_shims();
4368
+ function formatArenaResultForSession(result) {
4369
+ const lines = [];
4370
+ const modeLabel = result.mode.charAt(0).toUpperCase() + result.mode.slice(1);
4371
+ lines.push(`## Arena ${modeLabel} Result`);
4372
+ lines.push(`**Topic:** ${result.topic}`);
4373
+ lines.push(`**Models:** ${result.participants.join(" vs ")}`);
4374
+ lines.push("");
4375
+ const c = result.consensus;
4376
+ if (c.subjectSummary) {
4377
+ const overviewLabel = result.plan.outputShape.overviewLabel ?? (result.mode === "review" ? "What Changed" : result.mode === "planning" ? "Current Scope" : "Problem Framing");
4378
+ lines.push(`### ${overviewLabel}`);
4379
+ lines.push(c.subjectSummary);
4380
+ lines.push("");
4381
+ }
4382
+ if (c.summary) {
4383
+ lines.push("### Overall Assessment");
4384
+ lines.push(c.summary);
4385
+ lines.push("");
4386
+ }
4387
+ if (result.mode === "planning" && c.roadmap.length > 0) {
4388
+ lines.push("### Roadmap");
4389
+ for (const [index, phase] of c.roadmap.entries()) {
4390
+ lines.push(...formatRoadmapPhase(index, phase));
4391
+ }
4392
+ lines.push("");
4393
+ if (c.roadmapDetails && c.roadmapDetails.length > 0) {
4394
+ lines.push("### Implementation Details");
4395
+ for (const detail of c.roadmapDetails) {
4396
+ lines.push(...formatPhaseDetail(detail));
4397
+ }
4398
+ lines.push("");
4399
+ }
4400
+ }
4401
+ for (const section of getOrderedConsensusSections2(result)) {
4402
+ lines.push(`### ${section.title}`);
4403
+ for (const item of section.items) {
4404
+ lines.push(`- **${item.title}**: ${item.summary}`);
4405
+ }
4406
+ lines.push("");
4407
+ }
4408
+ if (result.mode !== "planning" && c.roadmap.length > 0) {
4409
+ lines.push("### Roadmap");
4410
+ for (const [index, phase] of c.roadmap.entries()) {
4411
+ lines.push(...formatRoadmapPhase(index, phase));
4412
+ }
4413
+ lines.push("");
4414
+ }
4415
+ if (c.nextActions.length > 0) {
4416
+ lines.push("### Next Actions");
4417
+ for (const action of c.nextActions) {
4418
+ const pri = action.priority === "high" ? "\u{1F534}" : action.priority === "medium" ? "\u{1F7E1}" : "\u26AA";
4419
+ lines.push(`- ${pri} **${action.title}**: ${action.rationale}`);
4420
+ }
4421
+ lines.push("");
4422
+ }
4423
+ if (result.reports.some((r) => r.findings.length > 0)) {
4424
+ lines.push("---");
4425
+ lines.push("### Participant Findings");
4426
+ for (const report of result.reports) {
4427
+ if (report.findings.length === 0) {
4428
+ lines.push(`
4429
+ **${report.participant}**: ${report.contextSummary || "(no findings)"}`);
4430
+ continue;
4431
+ }
4432
+ lines.push(`
4433
+ **${report.participant}** (${report.findings.length} findings)`);
4434
+ if (report.contextSummary) {
4435
+ lines.push(`> ${report.contextSummary}`);
4436
+ }
4437
+ for (const f of report.findings) {
4438
+ const severity = f.severity ? `/${f.severity}` : "";
4439
+ lines.push(`- [${f.kind}${severity}] **${f.title}**: ${f.summary}`);
4440
+ }
4441
+ }
4442
+ }
4443
+ return lines.join("\n");
4444
+ }
4445
+ function formatRoadmapPhase(index, phase) {
4446
+ const pri = phase.priority === "high" ? "High" : phase.priority === "medium" ? "Medium" : "Low";
4447
+ const lines = [`#### Phase ${index + 1}: ${phase.title} (${pri} priority)`];
4448
+ if (phase.goal) {
4449
+ lines.push(`Goal: ${phase.goal}`);
4450
+ }
4451
+ if (phase.scope.length > 0) {
4452
+ lines.push(`Scope: ${phase.scope.join("; ")}`);
4453
+ }
4454
+ if (phase.deliverables.length > 0) {
4455
+ lines.push(`Deliverables: ${phase.deliverables.join("; ")}`);
4456
+ }
4457
+ if (phase.dependencies.length > 0) {
4458
+ lines.push(`Dependencies: ${phase.dependencies.join("; ")}`);
4459
+ }
4460
+ if (phase.risks.length > 0) {
4461
+ lines.push(`Risks: ${phase.risks.join("; ")}`);
4462
+ }
4463
+ if (phase.successCriteria.length > 0) {
4464
+ lines.push(`Success Criteria: ${phase.successCriteria.join("; ")}`);
4465
+ }
4466
+ lines.push("");
4467
+ return lines;
4468
+ }
4469
+ function formatPhaseDetail(detail) {
4470
+ const effort = detail.effort === "large" ? "Large" : detail.effort === "small" ? "Small" : "Medium";
4471
+ const lines = [`#### ${detail.phaseTitle} (${effort} effort)`];
4472
+ if (detail.objective) {
4473
+ lines.push(detail.objective);
4474
+ }
4475
+ if (detail.targetFiles.length > 0) {
4476
+ lines.push(`**Target files:** ${detail.targetFiles.map((f) => "`" + f + "`").join(", ")}`);
4477
+ }
4478
+ if (detail.codeChanges.length > 0) {
4479
+ lines.push("**Code changes:**");
4480
+ for (const change of detail.codeChanges) {
4481
+ lines.push(`- ${change}`);
4482
+ }
4483
+ }
4484
+ if (detail.interfaces.length > 0) {
4485
+ lines.push(`**Interfaces:** ${detail.interfaces.join("; ")}`);
4486
+ }
4487
+ if (detail.migrationSteps.length > 0) {
4488
+ lines.push("**Migration steps:**");
4489
+ for (const [i, step] of detail.migrationSteps.entries()) {
4490
+ lines.push(`${i + 1}. ${step}`);
4491
+ }
4492
+ }
4493
+ if (detail.validation.length > 0) {
4494
+ lines.push(`**Validation:** ${detail.validation.join("; ")}`);
4495
+ }
4496
+ if (detail.blockers.length > 0) {
4497
+ lines.push(`**Blockers:** ${detail.blockers.join("; ")}`);
4498
+ }
4499
+ lines.push("");
4500
+ return lines;
4501
+ }
4502
+ function getOrderedConsensusSections2(result) {
4503
+ const VALID_KINDS = /* @__PURE__ */ new Set(["strength", "improvement", "risk", "question"]);
4504
+ const defaultOrder = ["risk", "improvement", "strength", "question"];
4505
+ const emphasize = (result.plan?.outputShape?.emphasize ?? []).filter((k) => VALID_KINDS.has(k));
4506
+ const orderedKinds = dedupeFindingKinds2([...emphasize, ...defaultOrder]);
4507
+ const sections = orderedKinds.map((kind) => {
4508
+ switch (kind) {
4509
+ case "strength":
4510
+ return { kind, title: "\u2713 Strengths", items: result.consensus.strengths };
4511
+ case "improvement":
4512
+ return { kind, title: "\u2192 Improvements", items: result.consensus.improvements };
4513
+ case "risk":
4514
+ return { kind, title: "\u26A0 Risks", items: result.consensus.risks };
4515
+ case "question":
4516
+ return { kind, title: "? Open Questions", items: result.consensus.openQuestions };
4517
+ }
4518
+ });
4519
+ return sections.filter((section) => section != null).filter((section) => section.items.length > 0);
4520
+ }
4521
+ function dedupeFindingKinds2(kinds) {
4522
+ const seen = /* @__PURE__ */ new Set();
4523
+ const result = [];
4524
+ for (const kind of kinds) {
4525
+ if (!seen.has(kind)) {
4526
+ seen.add(kind);
4527
+ result.push(kind);
4528
+ }
4529
+ }
4530
+ return result;
4531
+ }
4532
+
4533
+ export {
4534
+ registerProvider,
4535
+ createLLMClient,
4536
+ isStrategyV2,
4537
+ ReviewStrategy,
4538
+ DiscussionStrategy,
4539
+ PlanningStrategy,
4540
+ getLens,
4541
+ resolveLenses,
4542
+ buildLensPrompt,
4543
+ LENS_NAMES,
4544
+ getStrategy,
4545
+ getStrategyForPlan,
4546
+ planArena,
4547
+ collectEvidence,
4548
+ selectTools,
4549
+ hasTools,
4550
+ runParticipantResearch,
4551
+ runParticipantResearchWithDossiers,
4552
+ registerClaims,
4553
+ selectClaimsForReview,
4554
+ buildDigest,
4555
+ formatDigest,
4556
+ transitionClaim,
4557
+ resolveClaimStatus,
4558
+ markUnderReview,
4559
+ applyReviewResult,
4560
+ markUnresolved,
4561
+ isTerminal,
4562
+ validTransitions,
4563
+ runCrossReview,
4564
+ runVerificationReview,
4565
+ runDebateRounds,
4566
+ runAdjudication,
4567
+ buildConsensus,
4568
+ ArenaLedger,
4569
+ Arena,
4570
+ MODEL_PRESETS,
4571
+ getMaxOutputTokens,
4572
+ formatArenaResult,
4573
+ printArenaResult,
4574
+ createProgressRenderer,
4575
+ renderProgress,
4576
+ formatArenaResultForSession
4577
+ };