@oh-my-pi/pi-coding-agent 8.0.20 → 8.2.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 (421) hide show
  1. package/CHANGELOG.md +125 -0
  2. package/docs/session.md +111 -46
  3. package/examples/custom-tools/hello/index.ts +1 -1
  4. package/examples/custom-tools/todo/index.ts +3 -4
  5. package/examples/extensions/api-demo.ts +0 -1
  6. package/examples/extensions/chalk-logger.ts +2 -3
  7. package/examples/extensions/hello.ts +0 -1
  8. package/examples/extensions/pirate.ts +0 -1
  9. package/examples/extensions/plan-mode.ts +15 -16
  10. package/examples/extensions/todo.ts +3 -4
  11. package/examples/extensions/tools.ts +1 -2
  12. package/examples/extensions/with-deps/index.ts +0 -1
  13. package/examples/hooks/auto-commit-on-exit.ts +1 -2
  14. package/examples/hooks/confirm-destructive.ts +0 -1
  15. package/examples/hooks/custom-compaction.ts +1 -2
  16. package/examples/hooks/dirty-repo-guard.ts +0 -1
  17. package/examples/hooks/file-trigger.ts +3 -4
  18. package/examples/hooks/git-checkpoint.ts +0 -1
  19. package/examples/hooks/handoff.ts +3 -4
  20. package/examples/hooks/permission-gate.ts +1 -2
  21. package/examples/hooks/protected-paths.ts +1 -2
  22. package/examples/hooks/qna.ts +2 -3
  23. package/examples/hooks/snake.ts +4 -5
  24. package/examples/hooks/status-line.ts +0 -1
  25. package/examples/sdk/01-minimal.ts +2 -3
  26. package/examples/sdk/02-custom-model.ts +2 -3
  27. package/examples/sdk/03-custom-prompt.ts +3 -4
  28. package/examples/sdk/04-skills.ts +2 -3
  29. package/examples/sdk/06-extensions.ts +1 -2
  30. package/examples/sdk/06-hooks.ts +6 -7
  31. package/examples/sdk/07-context-files.ts +0 -1
  32. package/examples/sdk/08-prompt-templates.ts +0 -1
  33. package/examples/sdk/08-slash-commands.ts +0 -1
  34. package/examples/sdk/09-api-keys-and-oauth.ts +0 -1
  35. package/examples/sdk/10-settings.ts +0 -1
  36. package/examples/sdk/11-sessions.ts +0 -1
  37. package/package.json +54 -23
  38. package/scripts/format-prompts.ts +0 -1
  39. package/src/capability/context-file.ts +3 -4
  40. package/src/capability/extension-module.ts +3 -4
  41. package/src/capability/extension.ts +3 -4
  42. package/src/capability/fs.ts +20 -21
  43. package/src/capability/hook.ts +3 -4
  44. package/src/capability/index.ts +15 -16
  45. package/src/capability/instruction.ts +3 -4
  46. package/src/capability/mcp.ts +3 -4
  47. package/src/capability/prompt.ts +3 -4
  48. package/src/capability/rule.ts +3 -4
  49. package/src/capability/settings.ts +2 -3
  50. package/src/capability/skill.ts +3 -4
  51. package/src/capability/slash-command.ts +3 -4
  52. package/src/capability/ssh.ts +3 -4
  53. package/src/capability/system-prompt.ts +3 -4
  54. package/src/capability/tool.ts +3 -4
  55. package/src/cli/args.ts +5 -6
  56. package/src/cli/config-cli.ts +6 -7
  57. package/src/cli/file-processor.ts +19 -17
  58. package/src/cli/jupyter-cli.ts +105 -0
  59. package/src/cli/list-models.ts +10 -11
  60. package/src/cli/plugin-cli.ts +20 -25
  61. package/src/cli/session-picker.ts +2 -3
  62. package/src/cli/setup-cli.ts +2 -3
  63. package/src/cli/stats-cli.ts +2 -3
  64. package/src/cli/update-cli.ts +25 -22
  65. package/src/commit/agentic/agent.ts +307 -0
  66. package/src/commit/agentic/fallback.ts +96 -0
  67. package/src/commit/agentic/index.ts +351 -0
  68. package/src/commit/agentic/prompts/analyze-file.md +22 -0
  69. package/src/commit/agentic/prompts/session-user.md +26 -0
  70. package/src/commit/agentic/prompts/split-confirm.md +1 -0
  71. package/src/commit/agentic/prompts/system.md +40 -0
  72. package/src/commit/agentic/state.ts +69 -0
  73. package/src/commit/agentic/tools/analyze-file.ts +131 -0
  74. package/src/commit/agentic/tools/git-file-diff.ts +194 -0
  75. package/src/commit/agentic/tools/git-hunk.ts +50 -0
  76. package/src/commit/agentic/tools/git-overview.ts +84 -0
  77. package/src/commit/agentic/tools/index.ts +56 -0
  78. package/src/commit/agentic/tools/propose-changelog.ts +128 -0
  79. package/src/commit/agentic/tools/propose-commit.ts +154 -0
  80. package/src/commit/agentic/tools/recent-commits.ts +81 -0
  81. package/src/commit/agentic/tools/split-commit.ts +280 -0
  82. package/src/commit/agentic/topo-sort.ts +44 -0
  83. package/src/commit/agentic/trivial.ts +51 -0
  84. package/src/commit/agentic/validation.ts +200 -0
  85. package/src/commit/analysis/conventional.ts +165 -0
  86. package/src/commit/analysis/index.ts +4 -0
  87. package/src/commit/analysis/scope.ts +242 -0
  88. package/src/commit/analysis/summary.ts +112 -0
  89. package/src/commit/analysis/validation.ts +66 -0
  90. package/src/commit/changelog/detect.ts +36 -0
  91. package/src/commit/changelog/generate.ts +110 -0
  92. package/src/commit/changelog/index.ts +233 -0
  93. package/src/commit/changelog/parse.ts +44 -0
  94. package/src/commit/cli.ts +93 -0
  95. package/src/commit/git/diff.ts +148 -0
  96. package/src/commit/git/errors.ts +11 -0
  97. package/src/commit/git/index.ts +212 -0
  98. package/src/commit/git/operations.ts +53 -0
  99. package/src/commit/index.ts +5 -0
  100. package/src/commit/map-reduce/index.ts +63 -0
  101. package/src/commit/map-reduce/map-phase.ts +178 -0
  102. package/src/commit/map-reduce/reduce-phase.ts +145 -0
  103. package/src/commit/map-reduce/utils.ts +9 -0
  104. package/src/commit/message.ts +11 -0
  105. package/src/commit/model-selection.ts +80 -0
  106. package/src/commit/pipeline.ts +240 -0
  107. package/src/commit/prompts/analysis-system.md +155 -0
  108. package/src/commit/prompts/analysis-user.md +41 -0
  109. package/src/commit/prompts/changelog-system.md +56 -0
  110. package/src/commit/prompts/changelog-user.md +19 -0
  111. package/src/commit/prompts/file-observer-system.md +26 -0
  112. package/src/commit/prompts/file-observer-user.md +9 -0
  113. package/src/commit/prompts/reduce-system.md +60 -0
  114. package/src/commit/prompts/reduce-user.md +17 -0
  115. package/src/commit/prompts/summary-retry.md +4 -0
  116. package/src/commit/prompts/summary-system.md +52 -0
  117. package/src/commit/prompts/summary-user.md +13 -0
  118. package/src/commit/prompts/types-description.md +2 -0
  119. package/src/commit/types.ts +109 -0
  120. package/src/commit/utils/exclusions.ts +42 -0
  121. package/src/config/file-lock.ts +121 -0
  122. package/src/config/keybindings.ts +6 -8
  123. package/src/config/model-registry.ts +65 -38
  124. package/src/config/model-resolver.ts +18 -19
  125. package/src/config/prompt-templates.ts +11 -11
  126. package/src/config/settings-manager.ts +141 -50
  127. package/src/config.ts +64 -66
  128. package/src/cursor.ts +11 -9
  129. package/src/discovery/agents-md.ts +11 -12
  130. package/src/discovery/builtin.ts +68 -73
  131. package/src/discovery/claude.ts +41 -42
  132. package/src/discovery/cline.ts +11 -12
  133. package/src/discovery/codex.ts +52 -53
  134. package/src/discovery/cursor.ts +9 -10
  135. package/src/discovery/gemini.ts +17 -22
  136. package/src/discovery/github.ts +13 -14
  137. package/src/discovery/helpers.ts +35 -34
  138. package/src/discovery/index.ts +22 -24
  139. package/src/discovery/mcp-json.ts +8 -9
  140. package/src/discovery/ssh.ts +8 -9
  141. package/src/discovery/vscode.ts +4 -5
  142. package/src/discovery/windsurf.ts +6 -7
  143. package/src/exa/company.ts +1 -2
  144. package/src/exa/index.ts +2 -3
  145. package/src/exa/linkedin.ts +1 -2
  146. package/src/exa/mcp-client.ts +14 -16
  147. package/src/exa/render.ts +10 -11
  148. package/src/exa/researcher.ts +1 -2
  149. package/src/exa/search.ts +1 -2
  150. package/src/exa/types.ts +0 -1
  151. package/src/exa/websets.ts +1 -2
  152. package/src/exec/bash-executor.ts +3 -4
  153. package/src/exec/exec.ts +0 -1
  154. package/src/export/custom-share.ts +5 -6
  155. package/src/export/html/index.ts +24 -21
  156. package/src/export/ttsr.ts +2 -3
  157. package/src/extensibility/custom-commands/bundled/review/index.ts +7 -8
  158. package/src/extensibility/custom-commands/loader.ts +18 -15
  159. package/src/extensibility/custom-commands/types.ts +2 -3
  160. package/src/extensibility/custom-tools/loader.ts +11 -12
  161. package/src/extensibility/custom-tools/types.ts +7 -8
  162. package/src/extensibility/custom-tools/wrapper.ts +2 -3
  163. package/src/extensibility/extensions/loader.ts +76 -54
  164. package/src/extensibility/extensions/runner.ts +11 -12
  165. package/src/extensibility/extensions/types.ts +20 -27
  166. package/src/extensibility/extensions/wrapper.ts +3 -4
  167. package/src/extensibility/hooks/index.ts +1 -1
  168. package/src/extensibility/hooks/loader.ts +9 -10
  169. package/src/extensibility/hooks/runner.ts +7 -8
  170. package/src/extensibility/hooks/tool-wrapper.ts +0 -1
  171. package/src/extensibility/hooks/types.ts +11 -18
  172. package/src/extensibility/plugins/doctor.ts +3 -3
  173. package/src/extensibility/plugins/installer.ts +27 -27
  174. package/src/extensibility/plugins/loader.ts +59 -56
  175. package/src/extensibility/plugins/manager.ts +211 -171
  176. package/src/extensibility/plugins/parser.ts +1 -1
  177. package/src/extensibility/plugins/paths.ts +8 -8
  178. package/src/extensibility/skills.ts +63 -60
  179. package/src/extensibility/slash-commands.ts +10 -10
  180. package/src/index.ts +54 -54
  181. package/src/internal-urls/agent-protocol.ts +21 -11
  182. package/src/internal-urls/artifact-protocol.ts +17 -13
  183. package/src/internal-urls/router.ts +1 -2
  184. package/src/internal-urls/rule-protocol.ts +3 -4
  185. package/src/internal-urls/skill-protocol.ts +3 -4
  186. package/src/ipy/executor.ts +109 -9
  187. package/src/ipy/gateway-coordinator.ts +79 -90
  188. package/src/ipy/kernel.ts +32 -30
  189. package/src/ipy/modules.ts +13 -13
  190. package/src/lsp/client.ts +21 -10
  191. package/src/lsp/clients/biome-client.ts +1 -2
  192. package/src/lsp/clients/index.ts +3 -3
  193. package/src/lsp/clients/lsp-linter-client.ts +4 -5
  194. package/src/lsp/config.ts +15 -15
  195. package/src/lsp/edits.ts +4 -5
  196. package/src/lsp/index.ts +43 -44
  197. package/src/lsp/lspmux.ts +8 -8
  198. package/src/lsp/render.ts +99 -61
  199. package/src/lsp/utils.ts +3 -3
  200. package/src/main.ts +71 -37
  201. package/src/mcp/client.ts +2 -3
  202. package/src/mcp/config.ts +5 -6
  203. package/src/mcp/json-rpc.ts +0 -1
  204. package/src/mcp/loader.ts +6 -7
  205. package/src/mcp/manager.ts +17 -18
  206. package/src/mcp/tool-bridge.ts +4 -9
  207. package/src/mcp/tool-cache.ts +2 -3
  208. package/src/mcp/transports/http.ts +2 -4
  209. package/src/mcp/transports/stdio.ts +1 -2
  210. package/src/migrations.ts +63 -52
  211. package/src/modes/components/armin.ts +4 -5
  212. package/src/modes/components/assistant-message.ts +33 -5
  213. package/src/modes/components/bash-execution.ts +7 -8
  214. package/src/modes/components/bordered-loader.ts +3 -3
  215. package/src/modes/components/branch-summary-message.ts +3 -3
  216. package/src/modes/components/compaction-summary-message.ts +3 -3
  217. package/src/modes/components/countdown-timer.ts +0 -1
  218. package/src/modes/components/custom-message.ts +5 -5
  219. package/src/modes/components/diff.ts +1 -1
  220. package/src/modes/components/dynamic-border.ts +2 -2
  221. package/src/modes/components/extensions/extension-dashboard.ts +6 -7
  222. package/src/modes/components/extensions/extension-list.ts +2 -3
  223. package/src/modes/components/extensions/inspector-panel.ts +3 -4
  224. package/src/modes/components/extensions/state-manager.ts +25 -26
  225. package/src/modes/components/extensions/types.ts +1 -2
  226. package/src/modes/components/footer.ts +47 -43
  227. package/src/modes/components/history-search.ts +2 -2
  228. package/src/modes/components/hook-editor.ts +3 -4
  229. package/src/modes/components/hook-input.ts +2 -3
  230. package/src/modes/components/hook-message.ts +5 -5
  231. package/src/modes/components/hook-selector.ts +2 -3
  232. package/src/modes/components/keybinding-hints.ts +2 -3
  233. package/src/modes/components/login-dialog.ts +2 -2
  234. package/src/modes/components/model-selector.ts +12 -12
  235. package/src/modes/components/oauth-selector.ts +2 -2
  236. package/src/modes/components/plugin-settings.ts +20 -20
  237. package/src/modes/components/python-execution.ts +7 -8
  238. package/src/modes/components/queue-mode-selector.ts +3 -3
  239. package/src/modes/components/read-tool-group.ts +2 -2
  240. package/src/modes/components/session-selector.ts +4 -4
  241. package/src/modes/components/settings-defs.ts +77 -69
  242. package/src/modes/components/settings-selector.ts +16 -16
  243. package/src/modes/components/show-images-selector.ts +2 -2
  244. package/src/modes/components/status-line/segments.ts +4 -4
  245. package/src/modes/components/status-line/separators.ts +1 -1
  246. package/src/modes/components/status-line/types.ts +2 -2
  247. package/src/modes/components/status-line-segment-editor.ts +7 -8
  248. package/src/modes/components/status-line.ts +12 -12
  249. package/src/modes/components/theme-selector.ts +8 -7
  250. package/src/modes/components/thinking-selector.ts +4 -4
  251. package/src/modes/components/todo-display.ts +2 -2
  252. package/src/modes/components/todo-reminder.ts +4 -4
  253. package/src/modes/components/tool-execution.ts +16 -19
  254. package/src/modes/components/tree-selector.ts +12 -12
  255. package/src/modes/components/ttsr-notification.ts +5 -5
  256. package/src/modes/components/user-message-selector.ts +1 -1
  257. package/src/modes/components/user-message.ts +1 -1
  258. package/src/modes/components/visual-truncate.ts +0 -1
  259. package/src/modes/components/welcome.ts +4 -4
  260. package/src/modes/controllers/command-controller.ts +46 -47
  261. package/src/modes/controllers/event-controller.ts +16 -20
  262. package/src/modes/controllers/extension-ui-controller.ts +40 -46
  263. package/src/modes/controllers/input-controller.ts +17 -18
  264. package/src/modes/controllers/selector-controller.ts +103 -91
  265. package/src/modes/index.ts +3 -3
  266. package/src/modes/interactive-mode.ts +31 -31
  267. package/src/modes/print-mode.ts +12 -13
  268. package/src/modes/rpc/rpc-client.ts +7 -8
  269. package/src/modes/rpc/rpc-mode.ts +24 -28
  270. package/src/modes/rpc/rpc-types.ts +3 -4
  271. package/src/modes/theme/mermaid-cache.ts +89 -0
  272. package/src/modes/theme/theme.ts +130 -53
  273. package/src/modes/types.ts +10 -10
  274. package/src/modes/utils/ui-helpers.ts +17 -17
  275. package/src/patch/applicator.ts +18 -19
  276. package/src/patch/diff.ts +1 -2
  277. package/src/patch/fuzzy.ts +1 -2
  278. package/src/patch/index.ts +11 -18
  279. package/src/patch/normalize.ts +4 -4
  280. package/src/patch/normative.ts +1 -2
  281. package/src/patch/parser.ts +8 -9
  282. package/src/patch/shared.ts +43 -16
  283. package/src/prompts/tools/task.md +2 -0
  284. package/src/sdk.ts +100 -65
  285. package/src/session/agent-session.ts +84 -85
  286. package/src/session/agent-storage.ts +43 -39
  287. package/src/session/artifacts.ts +32 -10
  288. package/src/session/auth-storage.ts +50 -39
  289. package/src/session/compaction/branch-summarization.ts +7 -10
  290. package/src/session/compaction/compaction.ts +8 -19
  291. package/src/session/compaction/utils.ts +6 -9
  292. package/src/session/history-storage.ts +10 -10
  293. package/src/session/messages.ts +4 -5
  294. package/src/session/session-manager.ts +76 -65
  295. package/src/session/session-storage.ts +57 -69
  296. package/src/session/storage-migration.ts +14 -56
  297. package/src/session/streaming-output.ts +2 -2
  298. package/src/ssh/connection-manager.ts +43 -50
  299. package/src/ssh/ssh-executor.ts +2 -2
  300. package/src/ssh/sshfs-mount.ts +11 -18
  301. package/src/system-prompt.ts +28 -35
  302. package/src/task/agents.ts +45 -30
  303. package/src/task/commands.ts +6 -7
  304. package/src/task/discovery.ts +39 -76
  305. package/src/task/executor.ts +14 -15
  306. package/src/task/index.ts +40 -34
  307. package/src/task/output-manager.ts +93 -0
  308. package/src/task/parallel.ts +0 -1
  309. package/src/task/render.ts +24 -30
  310. package/src/task/subprocess-tool-registry.ts +1 -2
  311. package/src/task/worker-protocol.ts +3 -3
  312. package/src/task/worker.ts +33 -39
  313. package/src/task/worktree.ts +19 -19
  314. package/src/tools/ask.ts +41 -20
  315. package/src/tools/bash-interceptor.ts +1 -5
  316. package/src/tools/bash.ts +91 -97
  317. package/src/tools/calculator.ts +49 -47
  318. package/src/tools/complete.ts +4 -5
  319. package/src/tools/context.ts +2 -2
  320. package/src/tools/fetch.ts +84 -124
  321. package/src/tools/find.ts +94 -98
  322. package/src/tools/gemini-image.ts +14 -14
  323. package/src/tools/grep.ts +100 -116
  324. package/src/tools/index.ts +80 -55
  325. package/src/tools/list-limit.ts +1 -1
  326. package/src/tools/ls.ts +44 -70
  327. package/src/tools/notebook.ts +51 -67
  328. package/src/tools/output-meta.ts +3 -4
  329. package/src/tools/output-utils.ts +2 -2
  330. package/src/tools/path-utils.ts +5 -5
  331. package/src/tools/python.ts +104 -217
  332. package/src/tools/read.ts +92 -33
  333. package/src/tools/render-utils.ts +8 -23
  334. package/src/tools/renderers.ts +6 -7
  335. package/src/tools/review.ts +8 -11
  336. package/src/tools/ssh.ts +69 -49
  337. package/src/tools/todo-write.ts +37 -25
  338. package/src/tools/tool-errors.ts +3 -3
  339. package/src/tools/tool-result.ts +3 -8
  340. package/src/tools/write.ts +99 -75
  341. package/src/tui/code-cell.ts +109 -0
  342. package/src/tui/file-list.ts +47 -0
  343. package/src/tui/index.ts +11 -0
  344. package/src/tui/output-block.ts +72 -0
  345. package/src/tui/status-line.ts +39 -0
  346. package/src/tui/tree-list.ts +55 -0
  347. package/src/tui/types.ts +16 -0
  348. package/src/tui/utils.ts +48 -0
  349. package/src/utils/changelog.ts +9 -10
  350. package/src/utils/clipboard.ts +11 -11
  351. package/src/utils/file-mentions.ts +4 -10
  352. package/src/utils/frontmatter.ts +6 -3
  353. package/src/utils/fuzzy.ts +2 -2
  354. package/src/utils/image-convert.ts +1 -1
  355. package/src/utils/image-resize.ts +1 -1
  356. package/src/utils/mime.ts +2 -2
  357. package/src/utils/shell-snapshot.ts +11 -13
  358. package/src/utils/shell.ts +4 -5
  359. package/src/utils/title-generator.ts +8 -9
  360. package/src/utils/tools-manager.ts +23 -23
  361. package/src/vendor/photon/index.js +1099 -1059
  362. package/src/vendor/photon/photon_rs_bg.wasm +0 -0
  363. package/src/web/scrapers/artifacthub.ts +1 -1
  364. package/src/web/scrapers/arxiv.ts +2 -2
  365. package/src/web/scrapers/bluesky.ts +2 -2
  366. package/src/web/scrapers/cheatsh.ts +1 -1
  367. package/src/web/scrapers/chocolatey.ts +2 -2
  368. package/src/web/scrapers/choosealicense.ts +5 -5
  369. package/src/web/scrapers/cisa-kev.ts +1 -1
  370. package/src/web/scrapers/crossref.ts +2 -2
  371. package/src/web/scrapers/devto.ts +3 -3
  372. package/src/web/scrapers/discogs.ts +3 -4
  373. package/src/web/scrapers/discourse.ts +1 -1
  374. package/src/web/scrapers/dockerhub.ts +1 -1
  375. package/src/web/scrapers/fdroid.ts +2 -2
  376. package/src/web/scrapers/firefox-addons.ts +3 -3
  377. package/src/web/scrapers/flathub.ts +1 -1
  378. package/src/web/scrapers/github.ts +3 -3
  379. package/src/web/scrapers/gitlab.ts +4 -4
  380. package/src/web/scrapers/hackernews.ts +2 -2
  381. package/src/web/scrapers/huggingface.ts +1 -1
  382. package/src/web/scrapers/iacr.ts +2 -2
  383. package/src/web/scrapers/index.ts +0 -1
  384. package/src/web/scrapers/jetbrains-marketplace.ts +1 -1
  385. package/src/web/scrapers/lemmy.ts +2 -2
  386. package/src/web/scrapers/maven.ts +2 -2
  387. package/src/web/scrapers/mdn.ts +2 -4
  388. package/src/web/scrapers/metacpan.ts +2 -2
  389. package/src/web/scrapers/musicbrainz.ts +1 -2
  390. package/src/web/scrapers/npm.ts +1 -1
  391. package/src/web/scrapers/nuget.ts +2 -2
  392. package/src/web/scrapers/nvd.ts +3 -3
  393. package/src/web/scrapers/ollama.ts +7 -9
  394. package/src/web/scrapers/opencorporates.ts +2 -2
  395. package/src/web/scrapers/openlibrary.ts +6 -6
  396. package/src/web/scrapers/orcid.ts +0 -1
  397. package/src/web/scrapers/osv.ts +2 -2
  398. package/src/web/scrapers/packagist.ts +1 -1
  399. package/src/web/scrapers/pubmed.ts +1 -2
  400. package/src/web/scrapers/rawg.ts +2 -2
  401. package/src/web/scrapers/readthedocs.ts +1 -2
  402. package/src/web/scrapers/repology.ts +2 -2
  403. package/src/web/scrapers/rfc.ts +1 -1
  404. package/src/web/scrapers/searchcode.ts +2 -2
  405. package/src/web/scrapers/semantic-scholar.ts +1 -1
  406. package/src/web/scrapers/snapcraft.ts +2 -2
  407. package/src/web/scrapers/sourcegraph.ts +1 -1
  408. package/src/web/scrapers/spdx.ts +3 -3
  409. package/src/web/scrapers/spotify.ts +0 -1
  410. package/src/web/scrapers/twitter.ts +1 -1
  411. package/src/web/scrapers/types.ts +1 -2
  412. package/src/web/scrapers/utils.ts +5 -5
  413. package/src/web/scrapers/wikidata.ts +3 -3
  414. package/src/web/scrapers/youtube.ts +9 -14
  415. package/src/web/search/auth.ts +5 -10
  416. package/src/web/search/index.ts +11 -21
  417. package/src/web/search/providers/anthropic.ts +3 -9
  418. package/src/web/search/providers/exa.ts +6 -10
  419. package/src/web/search/providers/perplexity.ts +5 -5
  420. package/src/web/search/render.ts +129 -175
  421. package/tsconfig.json +0 -42
@@ -3,16 +3,15 @@
3
3
  *
4
4
  * Agents are embedded at build time via Bun's import with { type: "text" }.
5
5
  */
6
-
7
- import { renderPromptTemplate } from "@oh-my-pi/pi-coding-agent/config/prompt-templates";
8
- import { parseAgentFields } from "@oh-my-pi/pi-coding-agent/discovery/helpers";
9
- import exploreMd from "@oh-my-pi/pi-coding-agent/prompts/agents/explore.md" with { type: "text" };
6
+ import { renderPromptTemplate } from "../config/prompt-templates";
7
+ import { parseAgentFields } from "../discovery/helpers";
8
+ import exploreMd from "../prompts/agents/explore.md" with { type: "text" };
10
9
  // Embed agent markdown files at build time
11
- import agentFrontmatterTemplate from "@oh-my-pi/pi-coding-agent/prompts/agents/frontmatter.md" with { type: "text" };
12
- import planMd from "@oh-my-pi/pi-coding-agent/prompts/agents/plan.md" with { type: "text" };
13
- import reviewerMd from "@oh-my-pi/pi-coding-agent/prompts/agents/reviewer.md" with { type: "text" };
14
- import taskMd from "@oh-my-pi/pi-coding-agent/prompts/agents/task.md" with { type: "text" };
15
- import { parseFrontmatter } from "@oh-my-pi/pi-coding-agent/utils/frontmatter";
10
+ import agentFrontmatterTemplate from "../prompts/agents/frontmatter.md" with { type: "text" };
11
+ import planMd from "../prompts/agents/plan.md" with { type: "text" };
12
+ import reviewerMd from "../prompts/agents/reviewer.md" with { type: "text" };
13
+ import taskMd from "../prompts/agents/task.md" with { type: "text" };
14
+ import { parseFrontmatter } from "../utils/frontmatter";
16
15
  import type { AgentDefinition, AgentSource } from "./types";
17
16
 
18
17
  interface AgentFrontmatter {
@@ -69,30 +68,56 @@ const EMBEDDED_AGENT_DEFS: EmbeddedAgentDef[] = [
69
68
  },
70
69
  ];
71
70
 
72
- const EMBEDDED_AGENTS: { name: string; content: string }[] = EMBEDDED_AGENT_DEFS.map((def) => ({
71
+ const EMBEDDED_AGENTS: { name: string; content: string }[] = EMBEDDED_AGENT_DEFS.map(def => ({
73
72
  name: def.fileName,
74
73
  content: buildAgentContent(def),
75
74
  }));
76
75
 
76
+ export class AgentParsingError extends Error {
77
+ constructor(
78
+ error: Error,
79
+ public readonly source?: unknown,
80
+ ) {
81
+ super(`Failed to parse agent: ${error.message}`, { cause: error });
82
+ this.name = "AgentParsingError";
83
+ }
84
+
85
+ toString(): string {
86
+ const details: string[] = [this.message];
87
+ if (this.source !== undefined) {
88
+ details.push(`Source: ${JSON.stringify(this.source)}`);
89
+ }
90
+ if (this.cause && typeof this.cause === "object" && "stack" in this.cause && this.cause.stack) {
91
+ details.push(`Stack:\n${this.cause.stack}`);
92
+ } else if (this.stack) {
93
+ details.push(`Stack:\n${this.stack}`);
94
+ }
95
+ return details.join("\n\n");
96
+ }
97
+ }
98
+
77
99
  /**
78
100
  * Parse an agent from embedded content.
79
101
  */
80
- function parseAgent(fileName: string, content: string, source: AgentSource): AgentDefinition | null {
102
+ export function parseAgent(
103
+ filePath: string,
104
+ content: string,
105
+ source: AgentSource,
106
+ level: "fatal" | "warn" | "off" = "fatal",
107
+ ): AgentDefinition {
81
108
  const { frontmatter, body } = parseFrontmatter(content, {
82
- source: `embedded:${fileName}`,
83
- level: "fatal",
109
+ location: filePath,
110
+ level,
84
111
  });
85
112
  const fields = parseAgentFields(frontmatter);
86
-
87
113
  if (!fields) {
88
- return null;
114
+ throw new AgentParsingError(new Error("Invalid agent fields"), filePath);
89
115
  }
90
-
91
116
  return {
92
117
  ...fields,
93
118
  systemPrompt: body,
94
119
  source,
95
- filePath: `embedded:${fileName}`,
120
+ filePath,
96
121
  };
97
122
  }
98
123
 
@@ -107,25 +132,15 @@ export function loadBundledAgents(): AgentDefinition[] {
107
132
  if (bundledAgentsCache !== null) {
108
133
  return bundledAgentsCache;
109
134
  }
110
-
111
- const agents: AgentDefinition[] = [];
112
-
113
- for (const { name, content } of EMBEDDED_AGENTS) {
114
- const agent = parseAgent(name, content, "bundled");
115
- if (agent) {
116
- agents.push(agent);
117
- }
118
- }
119
-
120
- bundledAgentsCache = agents;
121
- return agents;
135
+ bundledAgentsCache = EMBEDDED_AGENTS.map(({ name, content }) => parseAgent(`embedded:${name}`, content, "bundled"));
136
+ return bundledAgentsCache;
122
137
  }
123
138
 
124
139
  /**
125
140
  * Get a bundled agent by name.
126
141
  */
127
142
  export function getBundledAgent(name: string): AgentDefinition | undefined {
128
- return loadBundledAgents().find((a) => a.name === name);
143
+ return loadBundledAgents().find(a => a.name === name);
129
144
  }
130
145
 
131
146
  /**
@@ -3,14 +3,13 @@
3
3
  *
4
4
  * Commands are embedded at build time via Bun's import with { type: "text" }.
5
5
  */
6
-
7
6
  import * as path from "node:path";
8
- import { type SlashCommand, slashCommandCapability } from "@oh-my-pi/pi-coding-agent/capability/slash-command";
9
- import { renderPromptTemplate } from "@oh-my-pi/pi-coding-agent/config/prompt-templates";
10
- import { loadCapability } from "@oh-my-pi/pi-coding-agent/discovery";
7
+ import { type SlashCommand, slashCommandCapability } from "../capability/slash-command";
8
+ import { renderPromptTemplate } from "../config/prompt-templates";
9
+ import { loadCapability } from "../discovery";
11
10
  // Embed command markdown files at build time
12
- import initMd from "@oh-my-pi/pi-coding-agent/prompts/agents/init.md" with { type: "text" };
13
- import { parseFrontmatter } from "@oh-my-pi/pi-coding-agent/utils/frontmatter";
11
+ import initMd from "../prompts/agents/init.md" with { type: "text" };
12
+ import { parseFrontmatter } from "../utils/frontmatter";
14
13
 
15
14
  const EMBEDDED_COMMANDS: { name: string; content: string }[] = [
16
15
  { name: "init.md", content: renderPromptTemplate(initMd) },
@@ -116,7 +115,7 @@ export async function discoverCommands(cwd: string): Promise<WorkflowCommand[]>
116
115
  * Get a command by name.
117
116
  */
118
117
  export function getCommand(commands: WorkflowCommand[], name: string): WorkflowCommand | undefined {
119
- return commands.find((c) => c.name === name);
118
+ return commands.find(c => c.name === name);
120
119
  }
121
120
 
122
121
  /**
@@ -11,13 +11,11 @@
11
11
  *
12
12
  * Agent files use markdown with YAML frontmatter.
13
13
  */
14
-
15
- import * as fs from "node:fs";
14
+ import * as fs from "node:fs/promises";
16
15
  import * as path from "node:path";
17
- import { findAllNearestProjectConfigDirs, getConfigDirs } from "@oh-my-pi/pi-coding-agent/config";
18
- import { parseAgentFields } from "@oh-my-pi/pi-coding-agent/discovery/helpers";
19
- import { parseFrontmatter } from "@oh-my-pi/pi-coding-agent/utils/frontmatter";
20
- import { loadBundledAgents } from "./agents";
16
+ import { logger } from "@oh-my-pi/pi-utils";
17
+ import { findAllNearestProjectConfigDirs, getConfigDirs } from "../config";
18
+ import { loadBundledAgents, parseAgent } from "./agents";
21
19
  import type { AgentDefinition, AgentSource } from "./types";
22
20
 
23
21
  /** Result of agent discovery */
@@ -29,55 +27,23 @@ export interface DiscoveryResult {
29
27
  /**
30
28
  * Load agents from a directory.
31
29
  */
32
- function loadAgentsFromDir(dir: string, source: AgentSource): AgentDefinition[] {
33
- const agents: AgentDefinition[] = [];
34
-
35
- if (!fs.existsSync(dir)) {
36
- return agents;
37
- }
38
-
39
- let entries: fs.Dirent[];
40
- try {
41
- entries = fs.readdirSync(dir, { withFileTypes: true });
42
- } catch {
43
- return agents;
44
- }
45
-
46
- for (const entry of entries) {
47
- if (!entry.name.endsWith(".md")) continue;
48
-
49
- const filePath = path.resolve(dir, entry.name);
50
-
51
- // Handle both regular files and symlinks
52
- try {
53
- if (!fs.statSync(filePath).isFile()) continue;
54
- } catch {
55
- continue;
56
- }
57
-
58
- let content: string;
59
- try {
60
- content = fs.readFileSync(filePath, "utf-8");
61
- } catch {
62
- continue;
63
- }
64
-
65
- const { frontmatter, body } = parseFrontmatter(content, { source: filePath });
66
- const fields = parseAgentFields(frontmatter);
67
-
68
- if (!fields) {
69
- continue;
70
- }
71
-
72
- agents.push({
73
- ...fields,
74
- systemPrompt: body,
75
- source,
76
- filePath,
30
+ async function loadAgentsFromDir(dir: string, source: AgentSource): Promise<AgentDefinition[]> {
31
+ const entries = await fs.readdir(dir, { withFileTypes: true }).catch(() => []);
32
+ const files = entries
33
+ .filter(entry => (entry.isFile() || entry.isSymbolicLink()) && entry.name.endsWith(".md"))
34
+ .sort((a, b) => a.name.localeCompare(b.name))
35
+ .map(file => {
36
+ const filePath = path.join(dir, file.name);
37
+ return fs
38
+ .readFile(filePath, "utf-8")
39
+ .then(content => parseAgent(filePath, content, source, "warn"))
40
+ .catch(error => {
41
+ logger.warn("Failed to read agent file", { filePath, error });
42
+ return null;
43
+ });
77
44
  });
78
- }
79
45
 
80
- return agents;
46
+ return (await Promise.all(files)).filter(Boolean) as AgentDefinition[];
81
47
  }
82
48
 
83
49
  /**
@@ -89,62 +55,59 @@ function loadAgentsFromDir(dir: string, source: AgentSource): AgentDefinition[]
89
55
  */
90
56
  export async function discoverAgents(cwd: string): Promise<DiscoveryResult> {
91
57
  const resolvedCwd = path.resolve(cwd);
92
- const agentSources = Array.from(new Set(getConfigDirs("", { project: false }).map((entry) => entry.source)));
58
+ const agentSources = Array.from(new Set(getConfigDirs("", { project: false }).map(entry => entry.source)));
93
59
 
94
60
  // Get user directories (priority order: .omp, .pi, .claude, ...)
95
61
  const userDirs = getConfigDirs("agents", { project: false })
96
- .filter((entry) => agentSources.includes(entry.source))
97
- .map((entry) => ({
62
+ .filter(entry => agentSources.includes(entry.source))
63
+ .map(entry => ({
98
64
  ...entry,
99
65
  path: path.resolve(entry.path),
100
66
  }));
101
67
 
102
68
  // Get project directories by walking up from cwd (priority order)
103
69
  const projectDirs = (await findAllNearestProjectConfigDirs("agents", resolvedCwd))
104
- .filter((entry) => agentSources.includes(entry.source))
105
- .map((entry) => ({
70
+ .filter(entry => agentSources.includes(entry.source))
71
+ .map(entry => ({
106
72
  ...entry,
107
73
  path: path.resolve(entry.path),
108
74
  }));
109
75
 
110
76
  const orderedSources = agentSources.filter(
111
- (source) =>
112
- userDirs.some((entry) => entry.source === source) || projectDirs.some((entry) => entry.source === source),
77
+ source => userDirs.some(entry => entry.source === source) || projectDirs.some(entry => entry.source === source),
113
78
  );
114
79
 
115
80
  const orderedDirs: Array<{ dir: string; source: AgentSource }> = [];
116
81
  for (const source of orderedSources) {
117
- const project = projectDirs.find((entry) => entry.source === source);
82
+ const project = projectDirs.find(entry => entry.source === source);
118
83
  if (project) orderedDirs.push({ dir: project.path, source: "project" });
119
- const user = userDirs.find((entry) => entry.source === source);
84
+ const user = userDirs.find(entry => entry.source === source);
120
85
  if (user) orderedDirs.push({ dir: user.path, source: "user" });
121
86
  }
122
87
 
123
- const agents: AgentDefinition[] = [];
124
88
  const seen = new Set<string>();
125
-
126
- for (const { dir, source } of orderedDirs) {
127
- for (const agent of loadAgentsFromDir(dir, source)) {
128
- if (seen.has(agent.name)) continue;
129
- agents.push(agent);
89
+ const loadedAgents = (await Promise.all(orderedDirs.map(({ dir, source }) => loadAgentsFromDir(dir, source))))
90
+ .flat()
91
+ .filter(agent => {
92
+ if (seen.has(agent.name)) return false;
130
93
  seen.add(agent.name);
131
- }
132
- }
94
+ return true;
95
+ });
133
96
 
134
- for (const agent of loadBundledAgents()) {
135
- if (seen.has(agent.name)) continue;
136
- agents.push(agent);
97
+ const bundledAgents = loadBundledAgents().filter(agent => {
98
+ if (seen.has(agent.name)) return false;
137
99
  seen.add(agent.name);
138
- }
100
+ return true;
101
+ });
139
102
 
140
103
  const projectAgentsDir = projectDirs.length > 0 ? projectDirs[0].path : null;
141
104
 
142
- return { agents, projectAgentsDir };
105
+ return { agents: [...loadedAgents, ...bundledAgents], projectAgentsDir };
143
106
  }
144
107
 
145
108
  /**
146
109
  * Get an agent by name from discovered agents.
147
110
  */
148
111
  export function getAgent(agents: AgentDefinition[], name: string): AgentDefinition | undefined {
149
- return agents.find((a) => a.name === name);
112
+ return agents.find(a => a.name === name);
150
113
  }
@@ -3,20 +3,19 @@
3
3
  *
4
4
  * Runs each subagent in a Bun Worker and forwards AgentEvents for progress tracking.
5
5
  */
6
-
7
6
  import path from "node:path";
8
7
  import type { AgentEvent, ThinkingLevel } from "@oh-my-pi/pi-agent-core";
9
- import type { ModelRegistry } from "@oh-my-pi/pi-coding-agent/config/model-registry";
10
- import { formatModelString, parseModelPattern } from "@oh-my-pi/pi-coding-agent/config/model-resolver";
11
- import { checkPythonKernelAvailability } from "@oh-my-pi/pi-coding-agent/ipy/kernel";
12
- import { LspTool } from "@oh-my-pi/pi-coding-agent/lsp/index";
13
- import type { LspParams } from "@oh-my-pi/pi-coding-agent/lsp/types";
14
- import { callTool } from "@oh-my-pi/pi-coding-agent/mcp/client";
15
- import type { MCPManager } from "@oh-my-pi/pi-coding-agent/mcp/manager";
16
- import type { AuthStorage } from "@oh-my-pi/pi-coding-agent/session/auth-storage";
17
- import { PythonTool, type PythonToolParams } from "@oh-my-pi/pi-coding-agent/tools/python";
18
- import type { EventBus } from "@oh-my-pi/pi-coding-agent/utils/event-bus";
19
8
  import type { ToolSession } from "..";
9
+ import type { ModelRegistry } from "../config/model-registry";
10
+ import { formatModelString, parseModelPattern } from "../config/model-resolver";
11
+ import { checkPythonKernelAvailability } from "../ipy/kernel";
12
+ import { LspTool } from "../lsp";
13
+ import type { LspParams } from "../lsp/types";
14
+ import { callTool } from "../mcp/client";
15
+ import type { MCPManager } from "../mcp/manager";
16
+ import type { AuthStorage } from "../session/auth-storage";
17
+ import { PythonTool, type PythonToolParams } from "../tools/python";
18
+ import type { EventBus } from "../utils/event-bus";
20
19
  import { subprocessToolRegistry } from "./subprocess-tool-registry";
21
20
  import {
22
21
  type AgentDefinition,
@@ -171,7 +170,7 @@ function getUsageTokens(usage: unknown): number {
171
170
  * falling back to empty strings if not.
172
171
  */
173
172
  function extractMCPToolMetadata(mcpManager: MCPManager): MCPToolMetadata[] {
174
- return mcpManager.getTools().map((tool) => {
173
+ return mcpManager.getTools().map(tool => {
175
174
  // MCPTool and DeferredMCPTool have these properties
176
175
  const mcpTool = tool as { mcpToolName?: string; mcpServerName?: string };
177
176
  return {
@@ -264,7 +263,7 @@ export async function runSubprocess(options: ExecutorOptions): Promise<SingleRes
264
263
 
265
264
  const pythonToolMode = options.settingsManager?.getPythonToolMode?.() ?? "ipy-only";
266
265
  if (toolNames?.includes("exec")) {
267
- const expanded = toolNames.filter((name) => name !== "exec");
266
+ const expanded = toolNames.filter(name => name !== "exec");
268
267
  if (pythonToolMode === "bash-only") {
269
268
  expanded.push("bash");
270
269
  } else if (pythonToolMode === "ipy-only") {
@@ -706,11 +705,11 @@ export async function runSubprocess(options: ExecutorOptions): Promise<SingleRes
706
705
  message: string;
707
706
  }
708
707
 
709
- const done = await new Promise<Extract<SubagentWorkerResponse, { type: "done" }>>((resolve) => {
708
+ const done = await new Promise<Extract<SubagentWorkerResponse, { type: "done" }>>(resolve => {
710
709
  const cleanup = () => {
711
710
  listenerController.abort();
712
711
  };
713
- finalize = (message) => {
712
+ finalize = message => {
714
713
  if (resolved) return;
715
714
  resolved = true;
716
715
  cleanup();
package/src/task/index.ts CHANGED
@@ -12,21 +12,23 @@
12
12
  * - Progress tracking via JSON events
13
13
  * - Session artifacts for debugging
14
14
  */
15
-
16
- import { mkdir, rm, stat } from "node:fs/promises";
17
- import { tmpdir } from "node:os";
15
+ import * as fs from "node:fs/promises";
16
+ import * as os from "node:os";
18
17
  import path from "node:path";
19
18
  import type { AgentTool, AgentToolResult, AgentToolUpdateCallback } from "@oh-my-pi/pi-agent-core";
20
19
  import type { Usage } from "@oh-my-pi/pi-ai";
21
- import { renderPromptTemplate } from "@oh-my-pi/pi-coding-agent/config/prompt-templates";
22
- import type { Theme } from "@oh-my-pi/pi-coding-agent/modes/theme/theme";
23
- import taskDescriptionTemplate from "@oh-my-pi/pi-coding-agent/prompts/tools/task.md" with { type: "text" };
24
- import { formatDuration } from "@oh-my-pi/pi-coding-agent/tools/render-utils";
25
20
  import { $ } from "bun";
26
21
  import { nanoid } from "nanoid";
27
22
  import type { ToolSession } from "..";
23
+ import { renderPromptTemplate } from "../config/prompt-templates";
24
+ import type { Theme } from "../modes/theme/theme";
25
+ import taskDescriptionTemplate from "../prompts/tools/task.md" with { type: "text" };
26
+ import { formatDuration } from "../tools/render-utils";
27
+ // Import review tools for side effects (registers subagent tool handlers)
28
+ import "../tools/review";
28
29
  import { discoverAgents, getAgent } from "./discovery";
29
30
  import { runSubprocess } from "./executor";
31
+ import { AgentOutputManager } from "./output-manager";
30
32
  import { mapWithConcurrencyLimit } from "./parallel";
31
33
  import { renderCall, renderResult } from "./render";
32
34
  import { renderTemplate } from "./template";
@@ -48,9 +50,6 @@ import {
48
50
  getRepoRoot,
49
51
  } from "./worktree";
50
52
 
51
- // Import review tools for side effects (registers subagent tool handlers)
52
- import "../tools/review";
53
-
54
53
  /** Format byte count for display */
55
54
  function formatBytes(bytes: number): string {
56
55
  if (bytes < 1024) return `${bytes}B`;
@@ -101,6 +100,7 @@ function addUsageTotals(target: Usage, usage: Partial<Usage>): void {
101
100
  export { loadBundledAgents as BUNDLED_AGENTS } from "./agents";
102
101
  export { discoverCommands, expandCommand, getCommand } from "./commands";
103
102
  export { discoverAgents, getAgent } from "./discovery";
103
+ export { AgentOutputManager } from "./output-manager";
104
104
  export type { AgentDefinition, AgentProgress, SingleResult, TaskParams, TaskToolDetails } from "./types";
105
105
  export { taskSchema } from "./types";
106
106
 
@@ -172,7 +172,7 @@ export class TaskTool implements AgentTool<typeof taskSchema, TaskToolDetails, T
172
172
  // Validate agent exists
173
173
  const agent = getAgent(agents, agentName);
174
174
  if (!agent) {
175
- const available = agents.map((a) => a.name).join(", ") || "none";
175
+ const available = agents.map(a => a.name).join(", ") || "none";
176
176
  return {
177
177
  content: [
178
178
  {
@@ -266,7 +266,7 @@ export class TaskTool implements AgentTool<typeof taskSchema, TaskToolDetails, T
266
266
  problems.push(`Missing task ids at indexes: ${missingTaskIndexes.join(", ")}`);
267
267
  }
268
268
  if (duplicateIds.length > 0) {
269
- const details = duplicateIds.map((entry) => `${entry.id} (indexes ${entry.indexes.join(", ")})`).join("; ");
269
+ const details = duplicateIds.map(entry => `${entry.id} (indexes ${entry.indexes.join(", ")})`).join("; ");
270
270
  problems.push(`Duplicate task ids detected (case-insensitive): ${details}`);
271
271
  }
272
272
  return {
@@ -306,9 +306,8 @@ export class TaskTool implements AgentTool<typeof taskSchema, TaskToolDetails, T
306
306
  // Derive artifacts directory
307
307
  const sessionFile = this.session.getSessionFile();
308
308
  const artifactsDir = sessionFile ? sessionFile.slice(0, -6) : null;
309
- const tempArtifactsDir = artifactsDir ? null : path.join(tmpdir(), `omp-task-${nanoid()}`);
309
+ const tempArtifactsDir = artifactsDir ? null : path.join(os.tmpdir(), `omp-task-${nanoid()}`);
310
310
  const effectiveArtifactsDir = artifactsDir || tempArtifactsDir!;
311
- await mkdir(effectiveArtifactsDir, { recursive: true });
312
311
 
313
312
  // Initialize progress tracking
314
313
  const progressMap = new Map<number, AgentProgress>();
@@ -347,7 +346,7 @@ export class TaskTool implements AgentTool<typeof taskSchema, TaskToolDetails, T
347
346
 
348
347
  // Check spawn restrictions from parent
349
348
  const parentSpawns = this.session.getSessionSpawns() ?? "*";
350
- const allowedSpawns = parentSpawns.split(",").map((s) => s.trim());
349
+ const allowedSpawns = parentSpawns.split(",").map(s => s.trim());
351
350
  const isSpawnAllowed = (): boolean => {
352
351
  if (parentSpawns === "") return false; // Empty = deny all
353
352
  if (parentSpawns === "*") return true; // Wildcard = allow all
@@ -367,7 +366,14 @@ export class TaskTool implements AgentTool<typeof taskSchema, TaskToolDetails, T
367
366
  }
368
367
 
369
368
  // Build full prompts with context prepended
370
- const tasksWithContext = tasks.map((t) => renderTemplate(context, t));
369
+ // Allocate unique IDs across the session to prevent artifact collisions
370
+ const outputManager =
371
+ this.session.agentOutputManager ?? new AgentOutputManager(this.session.getArtifactsDir ?? (() => null));
372
+ const uniqueIds = await outputManager.allocateBatch(tasks.map(t => t.id));
373
+ const tasksWithUniqueIds = tasks.map((t, i) => ({ ...t, id: uniqueIds[i] }));
374
+
375
+ // Build full prompts with context prepended
376
+ const tasksWithContext = tasksWithUniqueIds.map(t => renderTemplate(context, t));
371
377
 
372
378
  // Initialize progress for all tasks
373
379
  for (let i = 0; i < tasksWithContext.length; i++) {
@@ -410,7 +416,7 @@ export class TaskTool implements AgentTool<typeof taskSchema, TaskToolDetails, T
410
416
  enableLsp: false,
411
417
  signal,
412
418
  eventBus: undefined,
413
- onProgress: (progress) => {
419
+ onProgress: progress => {
414
420
  progressMap.set(index, {
415
421
  ...structuredClone(progress),
416
422
  args: tasksWithContext[index]?.args,
@@ -450,7 +456,7 @@ export class TaskTool implements AgentTool<typeof taskSchema, TaskToolDetails, T
450
456
  enableLsp: false,
451
457
  signal,
452
458
  eventBus: undefined,
453
- onProgress: (progress) => {
459
+ onProgress: progress => {
454
460
  progressMap.set(index, {
455
461
  ...structuredClone(progress),
456
462
  args: tasksWithContext[index]?.args,
@@ -556,29 +562,29 @@ export class TaskTool implements AgentTool<typeof taskSchema, TaskToolDetails, T
556
562
  let patchApplySummary = "";
557
563
  let patchesApplied: boolean | null = null;
558
564
  if (isIsolated) {
559
- const patchesInOrder = results.map((result) => result.patchPath).filter(Boolean) as string[];
560
- const missingPatch = results.some((result) => !result.patchPath);
565
+ const patchesInOrder = results.map(result => result.patchPath).filter(Boolean) as string[];
566
+ const missingPatch = results.some(result => !result.patchPath);
561
567
  if (!repoRoot || missingPatch) {
562
568
  patchesApplied = false;
563
569
  } else {
564
570
  const patchStats = await Promise.all(
565
- patchesInOrder.map(async (patchPath) => ({
571
+ patchesInOrder.map(async patchPath => ({
566
572
  patchPath,
567
- size: (await stat(patchPath)).size,
573
+ size: (await fs.stat(patchPath)).size,
568
574
  })),
569
575
  );
570
- const nonEmptyPatches = patchStats.filter((patch) => patch.size > 0).map((patch) => patch.patchPath);
576
+ const nonEmptyPatches = patchStats.filter(patch => patch.size > 0).map(patch => patch.patchPath);
571
577
  if (nonEmptyPatches.length === 0) {
572
578
  patchesApplied = true;
573
579
  } else {
574
580
  const patchTexts = await Promise.all(
575
- nonEmptyPatches.map(async (patchPath) => Bun.file(patchPath).text()),
581
+ nonEmptyPatches.map(async patchPath => Bun.file(patchPath).text()),
576
582
  );
577
- const combinedPatch = patchTexts.map((text) => (text.endsWith("\n") ? text : `${text}\n`)).join("");
583
+ const combinedPatch = patchTexts.map(text => (text.endsWith("\n") ? text : `${text}\n`)).join("");
578
584
  if (!combinedPatch.trim()) {
579
585
  patchesApplied = true;
580
586
  } else {
581
- const combinedPatchPath = path.join(tmpdir(), `omp-task-combined-${nanoid()}.patch`);
587
+ const combinedPatchPath = path.join(os.tmpdir(), `omp-task-combined-${nanoid()}.patch`);
582
588
  try {
583
589
  await Bun.write(combinedPatchPath, combinedPatch);
584
590
  const checkResult = await $`git apply --check --binary ${combinedPatchPath}`
@@ -595,7 +601,7 @@ export class TaskTool implements AgentTool<typeof taskSchema, TaskToolDetails, T
595
601
  patchesApplied = applyResult.exitCode === 0;
596
602
  }
597
603
  } finally {
598
- await rm(combinedPatchPath, { force: true });
604
+ await fs.rm(combinedPatchPath, { force: true });
599
605
  }
600
606
  }
601
607
  }
@@ -608,18 +614,18 @@ export class TaskTool implements AgentTool<typeof taskSchema, TaskToolDetails, T
608
614
  "<system-notification>Patches were not applied and must be handled manually.</system-notification>";
609
615
  const patchList =
610
616
  patchPaths.length > 0
611
- ? `\n\nPatch artifacts:\n${patchPaths.map((patch) => `- ${patch}`).join("\n")}`
617
+ ? `\n\nPatch artifacts:\n${patchPaths.map(patch => `- ${patch}`).join("\n")}`
612
618
  : "";
613
619
  patchApplySummary = `\n\n${notification}${patchList}`;
614
620
  }
615
621
  }
616
622
 
617
623
  // Build final output - match plugin format
618
- const successCount = results.filter((r) => r.exitCode === 0).length;
619
- const cancelledCount = results.filter((r) => r.aborted).length;
624
+ const successCount = results.filter(r => r.exitCode === 0).length;
625
+ const cancelledCount = results.filter(r => r.aborted).length;
620
626
  const totalDuration = Date.now() - startTime;
621
627
 
622
- const summaries = results.map((r) => {
628
+ const summaries = results.map(r => {
623
629
  const status = r.aborted ? "cancelled" : r.exitCode === 0 ? "completed" : `failed (exit ${r.exitCode})`;
624
630
  const output = r.output.trim() || r.stderr.trim() || "(no output)";
625
631
  const preview = output.split("\n").slice(0, 5).join("\n");
@@ -629,10 +635,10 @@ export class TaskTool implements AgentTool<typeof taskSchema, TaskToolDetails, T
629
635
  return `[${r.agent}] ${status}${meta} ${r.id}\n${preview}`;
630
636
  });
631
637
 
632
- const outputIds = results.filter((r) => !r.aborted || r.output.trim()).map((r) => r.id);
638
+ const outputIds = results.filter(r => !r.aborted || r.output.trim()).map(r => r.id);
633
639
  const outputHint =
634
640
  outputIds.length > 0
635
- ? `\n\nUse read with agent:// for full logs: ${outputIds.map((id) => `agent://${id}`).join(", ")}`
641
+ ? `\n\nUse read with agent:// for full logs: ${outputIds.map(id => `agent://${id}`).join(", ")}`
636
642
  : "";
637
643
  const schemaNote = schemaOverridden
638
644
  ? `\n\nNote: Agent '${agentName}' has a fixed output schema; your 'output' parameter was ignored.\nRequired schema: ${JSON.stringify(agent.output)}`
@@ -646,7 +652,7 @@ export class TaskTool implements AgentTool<typeof taskSchema, TaskToolDetails, T
646
652
  const shouldCleanupTempArtifacts =
647
653
  tempArtifactsDir && (!isIsolated || patchesApplied === true || patchesApplied === null);
648
654
  if (shouldCleanupTempArtifacts) {
649
- await rm(tempArtifactsDir, { recursive: true, force: true });
655
+ await fs.rm(tempArtifactsDir, { recursive: true, force: true });
650
656
  }
651
657
 
652
658
  return {