@oh-my-pi/pi-coding-agent 7.0.0 → 8.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (503) hide show
  1. package/CHANGELOG.md +87 -0
  2. package/README.md +1 -1
  3. package/docs/hooks.md +2 -2
  4. package/docs/sdk.md +1 -1
  5. package/package.json +12 -11
  6. package/scripts/format-prompts.ts +143 -0
  7. package/scripts/generate-template.ts +1 -1
  8. package/src/cli/args.ts +3 -3
  9. package/src/cli/config-cli.ts +4 -4
  10. package/src/cli/file-processor.ts +3 -3
  11. package/src/cli/list-models.ts +2 -2
  12. package/src/cli/plugin-cli.ts +3 -3
  13. package/src/cli/session-picker.ts +2 -2
  14. package/src/cli/setup-cli.ts +2 -2
  15. package/src/cli/stats-cli.ts +1 -1
  16. package/src/cli/update-cli.ts +2 -2
  17. package/src/{core → config}/keybindings.ts +1 -1
  18. package/src/{core → config}/model-registry.ts +1 -1
  19. package/src/{core → config}/model-resolver.ts +3 -3
  20. package/src/{core → config}/prompt-templates.ts +2 -2
  21. package/src/{core → config}/settings-manager.ts +6 -6
  22. package/src/{core/cursor/exec-bridge.ts → cursor.ts} +4 -4
  23. package/src/discovery/agents-md.ts +4 -4
  24. package/src/discovery/builtin.ts +17 -17
  25. package/src/discovery/claude.ts +12 -12
  26. package/src/discovery/cline.ts +6 -6
  27. package/src/discovery/codex.ts +21 -21
  28. package/src/discovery/cursor.ts +9 -9
  29. package/src/discovery/gemini.ts +9 -9
  30. package/src/discovery/github.ts +6 -6
  31. package/src/discovery/helpers.ts +4 -4
  32. package/src/discovery/index.ts +16 -16
  33. package/src/discovery/mcp-json.ts +4 -4
  34. package/src/discovery/ssh.ts +4 -4
  35. package/src/discovery/vscode.ts +4 -4
  36. package/src/discovery/windsurf.ts +6 -6
  37. package/src/{core/tools/exa → exa}/company.ts +2 -3
  38. package/src/{core/tools/exa → exa}/index.ts +2 -2
  39. package/src/{core/tools/exa → exa}/linkedin.ts +2 -3
  40. package/src/{core/tools/exa → exa}/mcp-client.ts +2 -2
  41. package/src/{core/tools/exa → exa}/render.ts +3 -3
  42. package/src/{core/tools/exa → exa}/researcher.ts +1 -1
  43. package/src/{core/tools/exa → exa}/search.ts +2 -10
  44. package/src/{core/tools/exa → exa}/websets.ts +1 -1
  45. package/src/{core → exec}/bash-executor.ts +22 -6
  46. package/src/{core → export}/custom-share.ts +1 -1
  47. package/src/{core/export-html → export/html}/index.ts +3 -3
  48. package/src/{core → export}/ttsr.ts +2 -2
  49. package/src/{core → extensibility}/custom-commands/bundled/review/index.ts +4 -4
  50. package/src/{core → extensibility}/custom-commands/loader.ts +3 -3
  51. package/src/{core → extensibility}/custom-commands/types.ts +1 -1
  52. package/src/{core → extensibility}/custom-tools/loader.ts +9 -9
  53. package/src/{core → extensibility}/custom-tools/types.ts +6 -6
  54. package/src/{core → extensibility}/custom-tools/wrapper.ts +1 -1
  55. package/src/{core → extensibility}/extensions/loader.ts +8 -8
  56. package/src/{core → extensibility}/extensions/runner.ts +3 -3
  57. package/src/{core → extensibility}/extensions/types.ts +15 -15
  58. package/src/{core → extensibility}/extensions/wrapper.ts +1 -1
  59. package/src/{core → extensibility}/hooks/index.ts +1 -1
  60. package/src/{core → extensibility}/hooks/loader.ts +7 -7
  61. package/src/{core → extensibility}/hooks/runner.ts +4 -4
  62. package/src/{core → extensibility}/hooks/types.ts +9 -9
  63. package/src/{core → extensibility}/plugins/doctor.ts +1 -1
  64. package/src/{core → extensibility}/plugins/installer.ts +2 -3
  65. package/src/{core → extensibility}/plugins/paths.ts +1 -1
  66. package/src/{core → extensibility}/skills.ts +8 -48
  67. package/src/{core → extensibility}/slash-commands.ts +6 -6
  68. package/src/index.ts +127 -128
  69. package/src/internal-urls/agent-protocol.ts +126 -0
  70. package/src/internal-urls/artifact-protocol.ts +93 -0
  71. package/src/internal-urls/index.ts +28 -0
  72. package/src/internal-urls/json-query.ts +126 -0
  73. package/src/internal-urls/router.ts +69 -0
  74. package/src/internal-urls/rule-protocol.ts +56 -0
  75. package/src/internal-urls/skill-protocol.ts +112 -0
  76. package/src/internal-urls/types.ts +48 -0
  77. package/src/{core/python-executor.ts → ipy/executor.ts} +51 -11
  78. package/src/{core/python-gateway-coordinator.ts → ipy/gateway-coordinator.ts} +41 -325
  79. package/src/{core/python-kernel.ts → ipy/kernel.ts} +38 -10
  80. package/src/ipy/prelude.ts +3 -0
  81. package/src/{core/tools/lsp → lsp}/client.ts +7 -6
  82. package/src/{core/tools/lsp → lsp}/clients/biome-client.ts +1 -1
  83. package/src/{core/tools/lsp → lsp}/clients/index.ts +1 -1
  84. package/src/{core/tools/lsp → lsp}/clients/lsp-linter-client.ts +4 -4
  85. package/src/{core/tools/lsp → lsp}/config.ts +1 -1
  86. package/src/{core/tools/lsp → lsp}/index.ts +16 -15
  87. package/src/{core/tools/lsp → lsp}/render.ts +2 -2
  88. package/src/{core/tools/lsp → lsp}/types.ts +14 -16
  89. package/src/{core/tools/lsp → lsp}/utils.ts +1 -1
  90. package/src/main.ts +12 -12
  91. package/src/{core/mcp → mcp}/config.ts +8 -8
  92. package/src/{core/mcp → mcp}/loader.ts +5 -6
  93. package/src/{core/mcp → mcp}/manager.ts +2 -2
  94. package/src/{core/mcp → mcp}/tool-bridge.ts +35 -6
  95. package/src/{core/mcp → mcp}/tool-cache.ts +1 -1
  96. package/src/{core/mcp → mcp}/transports/http.ts +7 -1
  97. package/src/{core/mcp → mcp}/transports/stdio.ts +1 -1
  98. package/src/{core/mcp → mcp}/types.ts +1 -1
  99. package/src/migrations.ts +2 -2
  100. package/src/modes/{interactive/components → components}/armin.ts +1 -1
  101. package/src/modes/{interactive/components → components}/assistant-message.ts +1 -1
  102. package/src/modes/{interactive/components → components}/bash-execution.ts +37 -29
  103. package/src/modes/{interactive/components → components}/bordered-loader.ts +1 -1
  104. package/src/modes/{interactive/components → components}/branch-summary-message.ts +2 -2
  105. package/src/modes/{interactive/components → components}/compaction-summary-message.ts +2 -2
  106. package/src/modes/{interactive/components → components}/custom-message.ts +3 -3
  107. package/src/modes/{interactive/components → components}/diff.ts +1 -1
  108. package/src/modes/{interactive/components → components}/dynamic-border.ts +1 -1
  109. package/src/modes/{interactive/components → components}/extensions/extension-dashboard.ts +3 -3
  110. package/src/modes/{interactive/components → components}/extensions/extension-list.ts +2 -2
  111. package/src/modes/{interactive/components → components}/extensions/inspector-panel.ts +1 -1
  112. package/src/modes/{interactive/components → components}/extensions/state-manager.ts +11 -17
  113. package/src/modes/{interactive/components → components}/extensions/types.ts +1 -1
  114. package/src/modes/{interactive/components → components}/footer.ts +3 -3
  115. package/src/modes/{interactive/components → components}/history-search.ts +2 -2
  116. package/src/modes/{interactive/components → components}/hook-editor.ts +1 -1
  117. package/src/modes/{interactive/components → components}/hook-input.ts +1 -1
  118. package/src/modes/{interactive/components → components}/hook-message.ts +3 -3
  119. package/src/modes/{interactive/components → components}/hook-selector.ts +1 -1
  120. package/src/modes/{interactive/components → components}/keybinding-hints.ts +2 -2
  121. package/src/modes/{interactive/components → components}/login-dialog.ts +1 -1
  122. package/src/modes/{interactive/components → components}/model-selector.ts +5 -5
  123. package/src/modes/{interactive/components → components}/oauth-selector.ts +2 -2
  124. package/src/modes/{interactive/components → components}/plugin-settings.ts +3 -3
  125. package/src/modes/{interactive/components → components}/python-execution.ts +35 -24
  126. package/src/modes/{interactive/components → components}/queue-mode-selector.ts +1 -1
  127. package/src/modes/{interactive/components → components}/read-tool-group.ts +2 -2
  128. package/src/modes/{interactive/components → components}/session-selector.ts +3 -3
  129. package/src/modes/{interactive/components → components}/settings-defs.ts +2 -2
  130. package/src/modes/{interactive/components → components}/settings-selector.ts +2 -2
  131. package/src/modes/{interactive/components → components}/show-images-selector.ts +1 -1
  132. package/src/modes/{interactive/components → components}/status-line/segments.ts +2 -2
  133. package/src/modes/{interactive/components → components}/status-line/separators.ts +1 -1
  134. package/src/modes/{interactive/components → components}/status-line/types.ts +2 -2
  135. package/src/modes/{interactive/components → components}/status-line-segment-editor.ts +2 -2
  136. package/src/modes/{interactive/components → components}/status-line.ts +3 -3
  137. package/src/modes/{interactive/components → components}/theme-selector.ts +1 -1
  138. package/src/modes/{interactive/components → components}/thinking-selector.ts +1 -1
  139. package/src/modes/{interactive/components → components}/todo-display.ts +3 -4
  140. package/src/modes/{interactive/components → components}/todo-reminder.ts +2 -2
  141. package/src/modes/{interactive/components → components}/tool-execution.ts +8 -8
  142. package/src/modes/{interactive/components → components}/tree-selector.ts +3 -3
  143. package/src/modes/{interactive/components → components}/ttsr-notification.ts +2 -2
  144. package/src/modes/{interactive/components → components}/user-message-selector.ts +1 -1
  145. package/src/modes/{interactive/components → components}/user-message.ts +1 -1
  146. package/src/modes/{interactive/components → components}/welcome.ts +2 -2
  147. package/src/modes/{interactive/controllers → controllers}/command-controller.ts +32 -30
  148. package/src/modes/{interactive/controllers → controllers}/event-controller.ts +9 -9
  149. package/src/modes/{interactive/controllers → controllers}/extension-ui-controller.ts +8 -8
  150. package/src/modes/{interactive/controllers → controllers}/input-controller.ts +6 -6
  151. package/src/modes/{interactive/controllers → controllers}/selector-controller.ts +16 -16
  152. package/src/modes/index.ts +1 -1
  153. package/src/modes/{interactive/interactive-mode.ts → interactive-mode.ts} +14 -14
  154. package/src/modes/print-mode.ts +1 -1
  155. package/src/modes/rpc/rpc-client.ts +3 -3
  156. package/src/modes/rpc/rpc-mode.ts +3 -3
  157. package/src/modes/rpc/rpc-types.ts +3 -3
  158. package/src/modes/{interactive/theme → theme}/theme.ts +1 -1
  159. package/src/modes/{interactive/types.ts → types.ts} +8 -9
  160. package/src/modes/{interactive/utils → utils}/ui-helpers.ts +20 -27
  161. package/src/{core/tools/patch → patch}/applicator.ts +1 -1
  162. package/src/{core/tools/patch → patch}/diff.ts +1 -1
  163. package/src/{core/tools/patch → patch}/index.ts +31 -36
  164. package/src/{core/tools/patch → patch}/shared.ts +9 -6
  165. package/src/prompts/agents/explore.md +83 -46
  166. package/src/prompts/agents/init.md +9 -4
  167. package/src/prompts/agents/plan.md +8 -7
  168. package/src/prompts/agents/reviewer.md +36 -18
  169. package/src/prompts/agents/task.md +4 -4
  170. package/src/prompts/compaction/branch-summary-preamble.md +0 -1
  171. package/src/prompts/review-request.md +0 -1
  172. package/src/prompts/system/custom-system-prompt.md +2 -14
  173. package/src/prompts/system/file-operations.md +0 -2
  174. package/src/prompts/system/system-prompt.md +147 -138
  175. package/src/prompts/system/web-search.md +26 -0
  176. package/src/prompts/tools/ask.md +31 -24
  177. package/src/prompts/tools/bash.md +20 -17
  178. package/src/prompts/tools/calculator.md +9 -5
  179. package/src/prompts/tools/fetch.md +16 -0
  180. package/src/prompts/tools/find.md +15 -5
  181. package/src/prompts/tools/gemini-image.md +21 -6
  182. package/src/prompts/tools/grep.md +28 -12
  183. package/src/prompts/tools/lsp.md +35 -14
  184. package/src/prompts/tools/patch.md +39 -41
  185. package/src/prompts/tools/python.md +59 -76
  186. package/src/prompts/tools/read.md +23 -22
  187. package/src/prompts/tools/replace.md +19 -12
  188. package/src/prompts/tools/ssh.md +21 -28
  189. package/src/prompts/tools/task.md +54 -44
  190. package/src/prompts/tools/todo-write.md +52 -163
  191. package/src/prompts/tools/web-search.md +16 -9
  192. package/src/prompts/tools/write.md +13 -2
  193. package/src/{core/sdk.ts → sdk.ts} +65 -34
  194. package/src/{core → session}/agent-session.ts +45 -37
  195. package/src/{core → session}/agent-storage.ts +2 -2
  196. package/src/session/artifacts.ts +110 -0
  197. package/src/{core → session}/auth-storage.ts +1 -1
  198. package/src/{core → session}/compaction/branch-summarization.ts +5 -5
  199. package/src/{core → session}/compaction/compaction.ts +6 -6
  200. package/src/{core → session}/compaction/utils.ts +3 -3
  201. package/src/{core → session}/history-storage.ts +1 -1
  202. package/src/{core → session}/messages.ts +6 -8
  203. package/src/{core → session}/session-manager.ts +2 -2
  204. package/src/{core → session}/storage-migration.ts +2 -2
  205. package/src/session/streaming-output.ts +177 -0
  206. package/src/{core/ssh → ssh}/connection-manager.ts +1 -1
  207. package/src/{core/ssh → ssh}/ssh-executor.ts +19 -4
  208. package/src/{core/ssh → ssh}/sshfs-mount.ts +1 -1
  209. package/src/{core/system-prompt.ts → system-prompt.ts} +8 -37
  210. package/src/{core/tools/task → task}/agents.ts +8 -8
  211. package/src/{core/tools/task → task}/commands.ts +5 -6
  212. package/src/{core/tools/task → task}/discovery.ts +3 -3
  213. package/src/{core/tools/task → task}/executor.ts +34 -44
  214. package/src/{core/tools/task → task}/index.ts +206 -50
  215. package/src/{core/tools/task → task}/render.ts +80 -23
  216. package/src/{core/tools/task → task}/subprocess-tool-registry.ts +1 -1
  217. package/src/task/template.ts +47 -0
  218. package/src/{core/tools/task → task}/types.ts +19 -27
  219. package/src/{core/tools/task → task}/worker-protocol.ts +8 -4
  220. package/src/{core/tools/task → task}/worker.ts +34 -29
  221. package/src/task/worktree.ts +166 -0
  222. package/src/{core/tools → tools}/ask.ts +13 -21
  223. package/src/{core/tools → tools}/bash-interceptor.ts +1 -1
  224. package/src/{core/tools → tools}/bash.ts +61 -63
  225. package/src/{core/tools → tools}/calculator.ts +4 -4
  226. package/src/{core/tools → tools}/complete.ts +1 -1
  227. package/src/{core/tools → tools}/context.ts +2 -2
  228. package/src/{core/tools/web-fetch.ts → tools/fetch.ts} +97 -76
  229. package/src/{core/tools → tools}/find.ts +80 -104
  230. package/src/{core/tools → tools}/gemini-image.ts +420 -29
  231. package/src/{core/tools → tools}/grep.ts +155 -164
  232. package/src/{core/tools → tools}/index.ts +63 -56
  233. package/src/tools/list-limit.ts +40 -0
  234. package/src/{core/tools → tools}/ls.ts +44 -35
  235. package/src/{core/tools → tools}/notebook.ts +3 -3
  236. package/src/tools/output-meta.ts +443 -0
  237. package/src/tools/output-utils.ts +63 -0
  238. package/src/{core/tools → tools}/python.ts +105 -89
  239. package/src/tools/read.ts +882 -0
  240. package/src/{core/tools → tools}/render-utils.ts +1 -1
  241. package/src/{core/tools → tools}/renderers.ts +8 -10
  242. package/src/{core/tools → tools}/review.ts +2 -2
  243. package/src/{core/tools → tools}/ssh.ts +56 -59
  244. package/src/{core/tools → tools}/todo-write.ts +12 -23
  245. package/src/tools/tool-errors.ts +95 -0
  246. package/src/tools/tool-result.ts +92 -0
  247. package/src/{core/tools → tools}/truncate.ts +2 -2
  248. package/src/{core/tools → tools}/write.ts +15 -13
  249. package/src/utils/changelog.ts +1 -1
  250. package/src/{core → utils}/file-mentions.ts +4 -4
  251. package/src/utils/image-convert.ts +1 -1
  252. package/src/utils/image-resize.ts +1 -1
  253. package/src/utils/shell.ts +1 -1
  254. package/src/{core → utils}/title-generator.ts +4 -4
  255. package/src/utils/tools-manager.ts +1 -1
  256. package/src/{core/tools/web-scrapers → web/scrapers}/choosealicense.ts +1 -1
  257. package/src/{core/tools/web-scrapers → web/scrapers}/twitter.ts +3 -2
  258. package/src/{core/tools/web-scrapers → web/scrapers}/types.ts +4 -2
  259. package/src/{core/tools/web-scrapers → web/scrapers}/utils.ts +1 -1
  260. package/src/{core/tools/web-scrapers → web/scrapers}/youtube.ts +14 -13
  261. package/src/{core/tools/web-search → web/search}/auth.ts +4 -4
  262. package/src/{core/tools/web-search → web/search}/index.ts +22 -71
  263. package/src/{core/tools/web-search → web/search}/providers/anthropic.ts +7 -10
  264. package/src/{core/tools/web-search → web/search}/providers/exa.ts +2 -2
  265. package/src/{core/tools/web-search → web/search}/providers/perplexity.ts +4 -16
  266. package/src/{core/tools/web-search → web/search}/render.ts +3 -3
  267. package/tsconfig.json +25 -0
  268. package/scripts/migrate-sessions.sh +0 -93
  269. package/src/core/index.ts +0 -56
  270. package/src/core/python-prelude.ts +0 -3
  271. package/src/core/ssh-executor.ts +0 -5
  272. package/src/core/streaming-output.ts +0 -115
  273. package/src/core/tools/output.ts +0 -519
  274. package/src/core/tools/read.ts +0 -717
  275. package/src/core/tools/task/template.ts +0 -37
  276. package/src/prompts/tools/output.md +0 -47
  277. package/src/prompts/tools/web-fetch.md +0 -9
  278. package/src/vendor/photon/photon_rs_bg.wasm.b64.js +0 -1
  279. /package/src/{core/tools/exa → exa}/types.ts +0 -0
  280. /package/src/{core → exec}/exec.ts +0 -0
  281. /package/src/{core/export-html → export/html}/template.css +0 -0
  282. /package/src/{core/export-html → export/html}/template.generated.ts +0 -0
  283. /package/src/{core/export-html → export/html}/template.html +0 -0
  284. /package/src/{core/export-html → export/html}/template.js +0 -0
  285. /package/src/{core/export-html → export/html}/template.macro.ts +0 -0
  286. /package/src/{core/export-html → export/html}/vendor/highlight.min.js +0 -0
  287. /package/src/{core/export-html → export/html}/vendor/marked.min.js +0 -0
  288. /package/src/{core → extensibility}/custom-commands/index.ts +0 -0
  289. /package/src/{core → extensibility}/custom-tools/index.ts +0 -0
  290. /package/src/{core → extensibility}/extensions/index.ts +0 -0
  291. /package/src/{core → extensibility}/hooks/tool-wrapper.ts +0 -0
  292. /package/src/{core → extensibility}/plugins/index.ts +0 -0
  293. /package/src/{core → extensibility}/plugins/loader.ts +0 -0
  294. /package/src/{core → extensibility}/plugins/manager.ts +0 -0
  295. /package/src/{core → extensibility}/plugins/parser.ts +0 -0
  296. /package/src/{core → extensibility}/plugins/types.ts +0 -0
  297. /package/src/{core/python-modules.ts → ipy/modules.ts} +0 -0
  298. /package/src/{core/python-prelude.py → ipy/prelude.py} +0 -0
  299. /package/src/{core/tools/lsp → lsp}/defaults.json +0 -0
  300. /package/src/{core/tools/lsp → lsp}/edits.ts +0 -0
  301. /package/src/{core/tools/lsp → lsp}/lspmux.ts +0 -0
  302. /package/src/{core/tools/lsp → lsp}/rust-analyzer.ts +0 -0
  303. /package/src/{core/mcp → mcp}/client.ts +0 -0
  304. /package/src/{core/mcp → mcp}/index.ts +0 -0
  305. /package/src/{core/mcp → mcp}/json-rpc.ts +0 -0
  306. /package/src/{core/mcp → mcp}/transports/index.ts +0 -0
  307. /package/src/modes/{interactive/components → components}/countdown-timer.ts +0 -0
  308. /package/src/modes/{interactive/components → components}/custom-editor.ts +0 -0
  309. /package/src/modes/{interactive/components → components}/extensions/index.ts +0 -0
  310. /package/src/modes/{interactive/components → components}/index.ts +0 -0
  311. /package/src/modes/{interactive/components → components}/status-line/index.ts +0 -0
  312. /package/src/modes/{interactive/components → components}/status-line/presets.ts +0 -0
  313. /package/src/modes/{interactive/components → components}/visual-truncate.ts +0 -0
  314. /package/src/modes/{interactive/theme → theme}/dark.json +0 -0
  315. /package/src/modes/{interactive/theme → theme}/defaults/alabaster.json +0 -0
  316. /package/src/modes/{interactive/theme → theme}/defaults/amethyst.json +0 -0
  317. /package/src/modes/{interactive/theme → theme}/defaults/anthracite.json +0 -0
  318. /package/src/modes/{interactive/theme → theme}/defaults/basalt.json +0 -0
  319. /package/src/modes/{interactive/theme → theme}/defaults/birch.json +0 -0
  320. /package/src/modes/{interactive/theme → theme}/defaults/dark-abyss.json +0 -0
  321. /package/src/modes/{interactive/theme → theme}/defaults/dark-arctic.json +0 -0
  322. /package/src/modes/{interactive/theme → theme}/defaults/dark-aurora.json +0 -0
  323. /package/src/modes/{interactive/theme → theme}/defaults/dark-catppuccin.json +0 -0
  324. /package/src/modes/{interactive/theme → theme}/defaults/dark-cavern.json +0 -0
  325. /package/src/modes/{interactive/theme → theme}/defaults/dark-copper.json +0 -0
  326. /package/src/modes/{interactive/theme → theme}/defaults/dark-cosmos.json +0 -0
  327. /package/src/modes/{interactive/theme → theme}/defaults/dark-cyberpunk.json +0 -0
  328. /package/src/modes/{interactive/theme → theme}/defaults/dark-dracula.json +0 -0
  329. /package/src/modes/{interactive/theme → theme}/defaults/dark-eclipse.json +0 -0
  330. /package/src/modes/{interactive/theme → theme}/defaults/dark-ember.json +0 -0
  331. /package/src/modes/{interactive/theme → theme}/defaults/dark-equinox.json +0 -0
  332. /package/src/modes/{interactive/theme → theme}/defaults/dark-forest.json +0 -0
  333. /package/src/modes/{interactive/theme → theme}/defaults/dark-github.json +0 -0
  334. /package/src/modes/{interactive/theme → theme}/defaults/dark-gruvbox.json +0 -0
  335. /package/src/modes/{interactive/theme → theme}/defaults/dark-lavender.json +0 -0
  336. /package/src/modes/{interactive/theme → theme}/defaults/dark-lunar.json +0 -0
  337. /package/src/modes/{interactive/theme → theme}/defaults/dark-midnight.json +0 -0
  338. /package/src/modes/{interactive/theme → theme}/defaults/dark-monochrome.json +0 -0
  339. /package/src/modes/{interactive/theme → theme}/defaults/dark-monokai.json +0 -0
  340. /package/src/modes/{interactive/theme → theme}/defaults/dark-nebula.json +0 -0
  341. /package/src/modes/{interactive/theme → theme}/defaults/dark-nord.json +0 -0
  342. /package/src/modes/{interactive/theme → theme}/defaults/dark-ocean.json +0 -0
  343. /package/src/modes/{interactive/theme → theme}/defaults/dark-one.json +0 -0
  344. /package/src/modes/{interactive/theme → theme}/defaults/dark-rainforest.json +0 -0
  345. /package/src/modes/{interactive/theme → theme}/defaults/dark-reef.json +0 -0
  346. /package/src/modes/{interactive/theme → theme}/defaults/dark-retro.json +0 -0
  347. /package/src/modes/{interactive/theme → theme}/defaults/dark-rose-pine.json +0 -0
  348. /package/src/modes/{interactive/theme → theme}/defaults/dark-sakura.json +0 -0
  349. /package/src/modes/{interactive/theme → theme}/defaults/dark-slate.json +0 -0
  350. /package/src/modes/{interactive/theme → theme}/defaults/dark-solarized.json +0 -0
  351. /package/src/modes/{interactive/theme → theme}/defaults/dark-solstice.json +0 -0
  352. /package/src/modes/{interactive/theme → theme}/defaults/dark-starfall.json +0 -0
  353. /package/src/modes/{interactive/theme → theme}/defaults/dark-sunset.json +0 -0
  354. /package/src/modes/{interactive/theme → theme}/defaults/dark-swamp.json +0 -0
  355. /package/src/modes/{interactive/theme → theme}/defaults/dark-synthwave.json +0 -0
  356. /package/src/modes/{interactive/theme → theme}/defaults/dark-taiga.json +0 -0
  357. /package/src/modes/{interactive/theme → theme}/defaults/dark-terminal.json +0 -0
  358. /package/src/modes/{interactive/theme → theme}/defaults/dark-tokyo-night.json +0 -0
  359. /package/src/modes/{interactive/theme → theme}/defaults/dark-tundra.json +0 -0
  360. /package/src/modes/{interactive/theme → theme}/defaults/dark-twilight.json +0 -0
  361. /package/src/modes/{interactive/theme → theme}/defaults/dark-volcanic.json +0 -0
  362. /package/src/modes/{interactive/theme → theme}/defaults/graphite.json +0 -0
  363. /package/src/modes/{interactive/theme → theme}/defaults/index.ts +0 -0
  364. /package/src/modes/{interactive/theme → theme}/defaults/light-arctic.json +0 -0
  365. /package/src/modes/{interactive/theme → theme}/defaults/light-aurora-day.json +0 -0
  366. /package/src/modes/{interactive/theme → theme}/defaults/light-canyon.json +0 -0
  367. /package/src/modes/{interactive/theme → theme}/defaults/light-catppuccin.json +0 -0
  368. /package/src/modes/{interactive/theme → theme}/defaults/light-cirrus.json +0 -0
  369. /package/src/modes/{interactive/theme → theme}/defaults/light-coral.json +0 -0
  370. /package/src/modes/{interactive/theme → theme}/defaults/light-cyberpunk.json +0 -0
  371. /package/src/modes/{interactive/theme → theme}/defaults/light-dawn.json +0 -0
  372. /package/src/modes/{interactive/theme → theme}/defaults/light-dunes.json +0 -0
  373. /package/src/modes/{interactive/theme → theme}/defaults/light-eucalyptus.json +0 -0
  374. /package/src/modes/{interactive/theme → theme}/defaults/light-forest.json +0 -0
  375. /package/src/modes/{interactive/theme → theme}/defaults/light-frost.json +0 -0
  376. /package/src/modes/{interactive/theme → theme}/defaults/light-github.json +0 -0
  377. /package/src/modes/{interactive/theme → theme}/defaults/light-glacier.json +0 -0
  378. /package/src/modes/{interactive/theme → theme}/defaults/light-gruvbox.json +0 -0
  379. /package/src/modes/{interactive/theme → theme}/defaults/light-haze.json +0 -0
  380. /package/src/modes/{interactive/theme → theme}/defaults/light-honeycomb.json +0 -0
  381. /package/src/modes/{interactive/theme → theme}/defaults/light-lagoon.json +0 -0
  382. /package/src/modes/{interactive/theme → theme}/defaults/light-lavender.json +0 -0
  383. /package/src/modes/{interactive/theme → theme}/defaults/light-meadow.json +0 -0
  384. /package/src/modes/{interactive/theme → theme}/defaults/light-mint.json +0 -0
  385. /package/src/modes/{interactive/theme → theme}/defaults/light-monochrome.json +0 -0
  386. /package/src/modes/{interactive/theme → theme}/defaults/light-ocean.json +0 -0
  387. /package/src/modes/{interactive/theme → theme}/defaults/light-one.json +0 -0
  388. /package/src/modes/{interactive/theme → theme}/defaults/light-opal.json +0 -0
  389. /package/src/modes/{interactive/theme → theme}/defaults/light-orchard.json +0 -0
  390. /package/src/modes/{interactive/theme → theme}/defaults/light-paper.json +0 -0
  391. /package/src/modes/{interactive/theme → theme}/defaults/light-prism.json +0 -0
  392. /package/src/modes/{interactive/theme → theme}/defaults/light-retro.json +0 -0
  393. /package/src/modes/{interactive/theme → theme}/defaults/light-sand.json +0 -0
  394. /package/src/modes/{interactive/theme → theme}/defaults/light-savanna.json +0 -0
  395. /package/src/modes/{interactive/theme → theme}/defaults/light-solarized.json +0 -0
  396. /package/src/modes/{interactive/theme → theme}/defaults/light-soleil.json +0 -0
  397. /package/src/modes/{interactive/theme → theme}/defaults/light-sunset.json +0 -0
  398. /package/src/modes/{interactive/theme → theme}/defaults/light-synthwave.json +0 -0
  399. /package/src/modes/{interactive/theme → theme}/defaults/light-tokyo-night.json +0 -0
  400. /package/src/modes/{interactive/theme → theme}/defaults/light-wetland.json +0 -0
  401. /package/src/modes/{interactive/theme → theme}/defaults/light-zenith.json +0 -0
  402. /package/src/modes/{interactive/theme → theme}/defaults/limestone.json +0 -0
  403. /package/src/modes/{interactive/theme → theme}/defaults/mahogany.json +0 -0
  404. /package/src/modes/{interactive/theme → theme}/defaults/marble.json +0 -0
  405. /package/src/modes/{interactive/theme → theme}/defaults/obsidian.json +0 -0
  406. /package/src/modes/{interactive/theme → theme}/defaults/onyx.json +0 -0
  407. /package/src/modes/{interactive/theme → theme}/defaults/pearl.json +0 -0
  408. /package/src/modes/{interactive/theme → theme}/defaults/porcelain.json +0 -0
  409. /package/src/modes/{interactive/theme → theme}/defaults/quartz.json +0 -0
  410. /package/src/modes/{interactive/theme → theme}/defaults/sandstone.json +0 -0
  411. /package/src/modes/{interactive/theme → theme}/defaults/titanium.json +0 -0
  412. /package/src/modes/{interactive/theme → theme}/light.json +0 -0
  413. /package/src/modes/{interactive/theme → theme}/theme-schema.json +0 -0
  414. /package/src/{core/tools/patch → patch}/fuzzy.ts +0 -0
  415. /package/src/{core/tools/patch → patch}/normalize.ts +0 -0
  416. /package/src/{core/tools/patch → patch}/normative.ts +0 -0
  417. /package/src/{core/tools/patch → patch}/parser.ts +0 -0
  418. /package/src/{core/tools/patch → patch}/types.ts +0 -0
  419. /package/src/{core → session}/compaction/index.ts +0 -0
  420. /package/src/{core → session}/session-storage.ts +0 -0
  421. /package/src/{core/tools/task → task}/name-generator.ts +0 -0
  422. /package/src/{core/tools/task → task}/omp-command.ts +0 -0
  423. /package/src/{core/tools/task → task}/parallel.ts +0 -0
  424. /package/src/{core/tools → tools}/jtd-to-json-schema.ts +0 -0
  425. /package/src/{core/tools → tools}/path-utils.ts +0 -0
  426. /package/src/{core → utils}/event-bus.ts +0 -0
  427. /package/src/{core → utils}/frontmatter.ts +0 -0
  428. /package/src/{core → utils}/terminal-notify.ts +0 -0
  429. /package/src/{core → utils}/timings.ts +0 -0
  430. /package/src/{core → utils}/utils.ts +0 -0
  431. /package/src/{core/tools/web-scrapers → web/scrapers}/artifacthub.ts +0 -0
  432. /package/src/{core/tools/web-scrapers → web/scrapers}/arxiv.ts +0 -0
  433. /package/src/{core/tools/web-scrapers → web/scrapers}/aur.ts +0 -0
  434. /package/src/{core/tools/web-scrapers → web/scrapers}/biorxiv.ts +0 -0
  435. /package/src/{core/tools/web-scrapers → web/scrapers}/bluesky.ts +0 -0
  436. /package/src/{core/tools/web-scrapers → web/scrapers}/brew.ts +0 -0
  437. /package/src/{core/tools/web-scrapers → web/scrapers}/cheatsh.ts +0 -0
  438. /package/src/{core/tools/web-scrapers → web/scrapers}/chocolatey.ts +0 -0
  439. /package/src/{core/tools/web-scrapers → web/scrapers}/cisa-kev.ts +0 -0
  440. /package/src/{core/tools/web-scrapers → web/scrapers}/clojars.ts +0 -0
  441. /package/src/{core/tools/web-scrapers → web/scrapers}/coingecko.ts +0 -0
  442. /package/src/{core/tools/web-scrapers → web/scrapers}/crates-io.ts +0 -0
  443. /package/src/{core/tools/web-scrapers → web/scrapers}/crossref.ts +0 -0
  444. /package/src/{core/tools/web-scrapers → web/scrapers}/devto.ts +0 -0
  445. /package/src/{core/tools/web-scrapers → web/scrapers}/discogs.ts +0 -0
  446. /package/src/{core/tools/web-scrapers → web/scrapers}/discourse.ts +0 -0
  447. /package/src/{core/tools/web-scrapers → web/scrapers}/dockerhub.ts +0 -0
  448. /package/src/{core/tools/web-scrapers → web/scrapers}/fdroid.ts +0 -0
  449. /package/src/{core/tools/web-scrapers → web/scrapers}/firefox-addons.ts +0 -0
  450. /package/src/{core/tools/web-scrapers → web/scrapers}/flathub.ts +0 -0
  451. /package/src/{core/tools/web-scrapers → web/scrapers}/github-gist.ts +0 -0
  452. /package/src/{core/tools/web-scrapers → web/scrapers}/github.ts +0 -0
  453. /package/src/{core/tools/web-scrapers → web/scrapers}/gitlab.ts +0 -0
  454. /package/src/{core/tools/web-scrapers → web/scrapers}/go-pkg.ts +0 -0
  455. /package/src/{core/tools/web-scrapers → web/scrapers}/hackage.ts +0 -0
  456. /package/src/{core/tools/web-scrapers → web/scrapers}/hackernews.ts +0 -0
  457. /package/src/{core/tools/web-scrapers → web/scrapers}/hex.ts +0 -0
  458. /package/src/{core/tools/web-scrapers → web/scrapers}/huggingface.ts +0 -0
  459. /package/src/{core/tools/web-scrapers → web/scrapers}/iacr.ts +0 -0
  460. /package/src/{core/tools/web-scrapers → web/scrapers}/index.ts +0 -0
  461. /package/src/{core/tools/web-scrapers → web/scrapers}/jetbrains-marketplace.ts +0 -0
  462. /package/src/{core/tools/web-scrapers → web/scrapers}/lemmy.ts +0 -0
  463. /package/src/{core/tools/web-scrapers → web/scrapers}/lobsters.ts +0 -0
  464. /package/src/{core/tools/web-scrapers → web/scrapers}/mastodon.ts +0 -0
  465. /package/src/{core/tools/web-scrapers → web/scrapers}/maven.ts +0 -0
  466. /package/src/{core/tools/web-scrapers → web/scrapers}/mdn.ts +0 -0
  467. /package/src/{core/tools/web-scrapers → web/scrapers}/metacpan.ts +0 -0
  468. /package/src/{core/tools/web-scrapers → web/scrapers}/musicbrainz.ts +0 -0
  469. /package/src/{core/tools/web-scrapers → web/scrapers}/npm.ts +0 -0
  470. /package/src/{core/tools/web-scrapers → web/scrapers}/nuget.ts +0 -0
  471. /package/src/{core/tools/web-scrapers → web/scrapers}/nvd.ts +0 -0
  472. /package/src/{core/tools/web-scrapers → web/scrapers}/ollama.ts +0 -0
  473. /package/src/{core/tools/web-scrapers → web/scrapers}/open-vsx.ts +0 -0
  474. /package/src/{core/tools/web-scrapers → web/scrapers}/opencorporates.ts +0 -0
  475. /package/src/{core/tools/web-scrapers → web/scrapers}/openlibrary.ts +0 -0
  476. /package/src/{core/tools/web-scrapers → web/scrapers}/orcid.ts +0 -0
  477. /package/src/{core/tools/web-scrapers → web/scrapers}/osv.ts +0 -0
  478. /package/src/{core/tools/web-scrapers → web/scrapers}/packagist.ts +0 -0
  479. /package/src/{core/tools/web-scrapers → web/scrapers}/pub-dev.ts +0 -0
  480. /package/src/{core/tools/web-scrapers → web/scrapers}/pubmed.ts +0 -0
  481. /package/src/{core/tools/web-scrapers → web/scrapers}/pypi.ts +0 -0
  482. /package/src/{core/tools/web-scrapers → web/scrapers}/rawg.ts +0 -0
  483. /package/src/{core/tools/web-scrapers → web/scrapers}/readthedocs.ts +0 -0
  484. /package/src/{core/tools/web-scrapers → web/scrapers}/reddit.ts +0 -0
  485. /package/src/{core/tools/web-scrapers → web/scrapers}/repology.ts +0 -0
  486. /package/src/{core/tools/web-scrapers → web/scrapers}/rfc.ts +0 -0
  487. /package/src/{core/tools/web-scrapers → web/scrapers}/rubygems.ts +0 -0
  488. /package/src/{core/tools/web-scrapers → web/scrapers}/searchcode.ts +0 -0
  489. /package/src/{core/tools/web-scrapers → web/scrapers}/sec-edgar.ts +0 -0
  490. /package/src/{core/tools/web-scrapers → web/scrapers}/semantic-scholar.ts +0 -0
  491. /package/src/{core/tools/web-scrapers → web/scrapers}/snapcraft.ts +0 -0
  492. /package/src/{core/tools/web-scrapers → web/scrapers}/sourcegraph.ts +0 -0
  493. /package/src/{core/tools/web-scrapers → web/scrapers}/spdx.ts +0 -0
  494. /package/src/{core/tools/web-scrapers → web/scrapers}/spotify.ts +0 -0
  495. /package/src/{core/tools/web-scrapers → web/scrapers}/stackoverflow.ts +0 -0
  496. /package/src/{core/tools/web-scrapers → web/scrapers}/terraform.ts +0 -0
  497. /package/src/{core/tools/web-scrapers → web/scrapers}/tldr.ts +0 -0
  498. /package/src/{core/tools/web-scrapers → web/scrapers}/vimeo.ts +0 -0
  499. /package/src/{core/tools/web-scrapers → web/scrapers}/vscode-marketplace.ts +0 -0
  500. /package/src/{core/tools/web-scrapers → web/scrapers}/w3c.ts +0 -0
  501. /package/src/{core/tools/web-scrapers → web/scrapers}/wikidata.ts +0 -0
  502. /package/src/{core/tools/web-scrapers → web/scrapers}/wikipedia.ts +0 -0
  503. /package/src/{core/tools/web-search → web/search}/types.ts +0 -0
@@ -13,25 +13,25 @@
13
13
  * - Session artifacts for debugging
14
14
  */
15
15
 
16
- import { mkdir, rm } from "node:fs/promises";
16
+ import { mkdir, rm, stat } from "node:fs/promises";
17
17
  import { tmpdir } from "node:os";
18
18
  import path from "node:path";
19
19
  import type { AgentTool, AgentToolResult, AgentToolUpdateCallback } from "@oh-my-pi/pi-agent-core";
20
20
  import type { Usage } from "@oh-my-pi/pi-ai";
21
+ import { $ } from "bun";
21
22
  import { nanoid } from "nanoid";
22
- import type { Theme } from "../../../modes/interactive/theme/theme";
23
- import taskDescriptionTemplate from "../../../prompts/tools/task.md" with { type: "text" };
24
- import { renderPromptTemplate } from "../../prompt-templates";
23
+ import { renderPromptTemplate } from "$c/config/prompt-templates";
24
+ import type { Theme } from "$c/modes/theme/theme";
25
+ import taskDescriptionTemplate from "$c/prompts/tools/task.md" with { type: "text" };
26
+ import { formatDuration } from "$c/tools/render-utils";
25
27
  import type { ToolSession } from "..";
26
- import { formatDuration } from "../render-utils";
27
28
  import { discoverAgents, getAgent } from "./discovery";
28
29
  import { runSubprocess } from "./executor";
29
30
  import { mapWithConcurrencyLimit } from "./parallel";
30
31
  import { renderCall, renderResult } from "./render";
31
- import { renderTemplate, validateTaskTemplate } from "./template";
32
+ import { renderTemplate } from "./template";
32
33
  import {
33
34
  type AgentProgress,
34
- MAX_AGENTS_IN_DESCRIPTION,
35
35
  MAX_CONCURRENCY,
36
36
  MAX_PARALLEL_TASKS,
37
37
  type SingleResult,
@@ -39,9 +39,17 @@ import {
39
39
  type TaskToolDetails,
40
40
  taskSchema,
41
41
  } from "./types";
42
+ import {
43
+ applyBaseline,
44
+ captureBaseline,
45
+ captureDeltaPatch,
46
+ cleanupWorktree,
47
+ ensureWorktree,
48
+ getRepoRoot,
49
+ } from "./worktree";
42
50
 
43
51
  // Import review tools for side effects (registers subagent tool handlers)
44
- import "../review";
52
+ import "../tools/review";
45
53
 
46
54
  /** Format byte count for display */
47
55
  function formatBytes(bytes: number): string {
@@ -103,8 +111,7 @@ async function buildDescription(cwd: string): Promise<string> {
103
111
  const { agents } = await discoverAgents(cwd);
104
112
 
105
113
  return renderPromptTemplate(taskDescriptionTemplate, {
106
- agents: agents.slice(0, MAX_AGENTS_IN_DESCRIPTION),
107
- moreAgents: agents.length > MAX_AGENTS_IN_DESCRIPTION ? agents.length - MAX_AGENTS_IN_DESCRIPTION : 0,
114
+ agents,
108
115
  MAX_PARALLEL_TASKS,
109
116
  MAX_CONCURRENCY,
110
117
  });
@@ -153,7 +160,8 @@ export class TaskTool implements AgentTool<typeof taskSchema, TaskToolDetails, T
153
160
  ): Promise<AgentToolResult<TaskToolDetails>> {
154
161
  const startTime = Date.now();
155
162
  const { agents, projectAgentsDir } = await discoverAgents(this.session.cwd);
156
- const { agent: agentName, context, model, output: outputSchema } = params;
163
+ const { agent: agentName, context, output: outputSchema, isolated } = params;
164
+ const isIsolated = isolated === true;
157
165
 
158
166
  const isDefaultModelAlias = (value: string | undefined): boolean => {
159
167
  if (!value) return true;
@@ -180,9 +188,9 @@ export class TaskTool implements AgentTool<typeof taskSchema, TaskToolDetails, T
180
188
  };
181
189
  }
182
190
 
183
- const shouldInheritSessionModel = model === undefined && isDefaultModelAlias(agent.model);
184
- const sessionModel = shouldInheritSessionModel ? this.session.getActiveModelString?.() : undefined;
185
- const modelOverride = model ?? sessionModel ?? this.session.getModelString?.();
191
+ const effectiveAgentModel = isDefaultModelAlias(agent.model) ? undefined : agent.model;
192
+ const modelOverride =
193
+ effectiveAgentModel ?? this.session.getActiveModelString?.() ?? this.session.getModelString?.();
186
194
  const thinkingLevelOverride = agent.thinkingLevel;
187
195
 
188
196
  // Output schema priority: agent frontmatter > params > inherited from parent session
@@ -195,7 +203,7 @@ export class TaskTool implements AgentTool<typeof taskSchema, TaskToolDetails, T
195
203
  content: [
196
204
  {
197
205
  type: "text",
198
- text: `No tasks provided. Use: { agent, context, tasks: [{id, description, vars}, ...] }`,
206
+ text: `No tasks provided. Use: { agent, context, tasks: [{id, description, args}, ...] }`,
199
207
  },
200
208
  ],
201
209
  details: {
@@ -271,16 +279,28 @@ export class TaskTool implements AgentTool<typeof taskSchema, TaskToolDetails, T
271
279
  };
272
280
  }
273
281
 
274
- const templateError = validateTaskTemplate(context, tasks);
275
- if (templateError) {
276
- return {
277
- content: [{ type: "text", text: templateError }],
278
- details: {
279
- projectAgentsDir,
280
- results: [],
281
- totalDurationMs: 0,
282
- },
283
- };
282
+ let repoRoot: string | null = null;
283
+ let baseline = null as Awaited<ReturnType<typeof captureBaseline>> | null;
284
+ if (isIsolated) {
285
+ try {
286
+ repoRoot = await getRepoRoot(this.session.cwd);
287
+ baseline = await captureBaseline(repoRoot);
288
+ } catch (err) {
289
+ const message = err instanceof Error ? err.message : String(err);
290
+ return {
291
+ content: [
292
+ {
293
+ type: "text",
294
+ text: `Isolated task execution requires a git repository. ${message}`,
295
+ },
296
+ ],
297
+ details: {
298
+ projectAgentsDir,
299
+ results: [],
300
+ totalDurationMs: Date.now() - startTime,
301
+ },
302
+ };
303
+ }
284
304
  }
285
305
 
286
306
  // Derive artifacts directory
@@ -347,25 +367,19 @@ export class TaskTool implements AgentTool<typeof taskSchema, TaskToolDetails, T
347
367
  }
348
368
 
349
369
  // Build full prompts with context prepended
350
- const contextTemplate = context ?? "";
351
- const tasksWithContext = tasks.map((t) => ({
352
- task: renderTemplate(contextTemplate, t.vars),
353
- description: t.description,
354
- taskId: t.id,
355
- vars: t.vars,
356
- }));
370
+ const tasksWithContext = tasks.map((t) => renderTemplate(context, t));
357
371
 
358
372
  // Initialize progress for all tasks
359
373
  for (let i = 0; i < tasksWithContext.length; i++) {
360
374
  const t = tasksWithContext[i];
361
375
  progressMap.set(i, {
362
376
  index: i,
363
- taskId: t.taskId,
377
+ id: t.id,
364
378
  agent: agentName,
365
379
  agentSource: agent.source,
366
380
  status: "pending",
367
381
  task: t.task,
368
- vars: t.vars,
382
+ args: t.args,
369
383
  recentTools: [],
370
384
  recentOutput: [],
371
385
  toolCount: 0,
@@ -377,18 +391,15 @@ export class TaskTool implements AgentTool<typeof taskSchema, TaskToolDetails, T
377
391
  }
378
392
  emitProgress();
379
393
 
380
- // Execute in parallel with concurrency limit
381
- const { results: partialResults, aborted } = await mapWithConcurrencyLimit(
382
- tasksWithContext,
383
- MAX_CONCURRENCY,
384
- async (task, index) => {
394
+ const runTask = async (task: (typeof tasksWithContext)[number], index: number) => {
395
+ if (!isIsolated) {
385
396
  return runSubprocess({
386
397
  cwd: this.session.cwd,
387
398
  agent,
388
399
  task: task.task,
389
400
  description: task.description,
390
401
  index,
391
- taskId: task.taskId,
402
+ id: task.id,
392
403
  context: undefined, // Already prepended above
393
404
  modelOverride,
394
405
  thinkingLevel: thinkingLevelOverride,
@@ -402,7 +413,7 @@ export class TaskTool implements AgentTool<typeof taskSchema, TaskToolDetails, T
402
413
  onProgress: (progress) => {
403
414
  progressMap.set(index, {
404
415
  ...structuredClone(progress),
405
- vars: tasksWithContext[index]?.vars,
416
+ args: tasksWithContext[index]?.args,
406
417
  });
407
418
  emitProgress();
408
419
  },
@@ -411,7 +422,83 @@ export class TaskTool implements AgentTool<typeof taskSchema, TaskToolDetails, T
411
422
  settingsManager: this.session.settingsManager,
412
423
  mcpManager: this.session.mcpManager,
413
424
  });
414
- },
425
+ }
426
+
427
+ const taskStart = Date.now();
428
+ let worktreeDir: string | undefined;
429
+ try {
430
+ if (!repoRoot || !baseline) {
431
+ throw new Error("Isolated task execution not initialized.");
432
+ }
433
+ worktreeDir = await ensureWorktree(repoRoot, task.id);
434
+ await applyBaseline(worktreeDir, baseline);
435
+ const result = await runSubprocess({
436
+ cwd: this.session.cwd,
437
+ worktree: worktreeDir,
438
+ agent,
439
+ task: task.task,
440
+ description: task.description,
441
+ index,
442
+ id: task.id,
443
+ context: undefined, // Already prepended above
444
+ modelOverride,
445
+ thinkingLevel: thinkingLevelOverride,
446
+ outputSchema: effectiveOutputSchema,
447
+ sessionFile,
448
+ persistArtifacts: !!artifactsDir,
449
+ artifactsDir: effectiveArtifactsDir,
450
+ enableLsp: false,
451
+ signal,
452
+ eventBus: undefined,
453
+ onProgress: (progress) => {
454
+ progressMap.set(index, {
455
+ ...structuredClone(progress),
456
+ args: tasksWithContext[index]?.args,
457
+ });
458
+ emitProgress();
459
+ },
460
+ authStorage: this.session.authStorage,
461
+ modelRegistry: this.session.modelRegistry,
462
+ settingsManager: this.session.settingsManager,
463
+ mcpManager: this.session.mcpManager,
464
+ });
465
+ const patch = await captureDeltaPatch(worktreeDir, baseline);
466
+ const patchPath = path.join(effectiveArtifactsDir, `${task.id}.patch`);
467
+ await Bun.write(patchPath, patch);
468
+ return {
469
+ ...result,
470
+ patchPath,
471
+ };
472
+ } catch (err) {
473
+ const message = err instanceof Error ? err.message : String(err);
474
+ return {
475
+ index,
476
+ id: task.id,
477
+ agent: agent.name,
478
+ agentSource: agent.source,
479
+ task: task.task,
480
+ description: task.description,
481
+ exitCode: 1,
482
+ output: "",
483
+ stderr: message,
484
+ truncated: false,
485
+ durationMs: Date.now() - taskStart,
486
+ tokens: 0,
487
+ modelOverride,
488
+ error: message,
489
+ };
490
+ } finally {
491
+ if (worktreeDir) {
492
+ await cleanupWorktree(worktreeDir);
493
+ }
494
+ }
495
+ };
496
+
497
+ // Execute in parallel with concurrency limit
498
+ const { results: partialResults, aborted } = await mapWithConcurrencyLimit(
499
+ tasksWithContext,
500
+ MAX_CONCURRENCY,
501
+ runTask,
415
502
  signal,
416
503
  );
417
504
 
@@ -420,17 +507,17 @@ export class TaskTool implements AgentTool<typeof taskSchema, TaskToolDetails, T
420
507
  if (result !== undefined) {
421
508
  return {
422
509
  ...result,
423
- vars: tasksWithContext[index]?.vars,
510
+ args: tasksWithContext[index]?.args,
424
511
  };
425
512
  }
426
513
  const task = tasksWithContext[index];
427
514
  return {
428
515
  index,
429
- taskId: task.taskId,
516
+ id: task.id,
430
517
  agent: agentName,
431
518
  agentSource: agent.source,
432
519
  task: task.task,
433
- vars: task.vars,
520
+ args: task.args,
434
521
  description: task.description,
435
522
  exitCode: 1,
436
523
  output: "",
@@ -456,10 +543,75 @@ export class TaskTool implements AgentTool<typeof taskSchema, TaskToolDetails, T
456
543
 
457
544
  // Collect output paths (artifacts already written by executor in real-time)
458
545
  const outputPaths: string[] = [];
546
+ const patchPaths: string[] = [];
459
547
  for (const result of results) {
460
548
  if (result.outputPath) {
461
549
  outputPaths.push(result.outputPath);
462
550
  }
551
+ if (result.patchPath) {
552
+ patchPaths.push(result.patchPath);
553
+ }
554
+ }
555
+
556
+ let patchApplySummary = "";
557
+ let patchesApplied: boolean | null = null;
558
+ if (isIsolated) {
559
+ const patchesInOrder = results.map((result) => result.patchPath).filter(Boolean) as string[];
560
+ const missingPatch = results.some((result) => !result.patchPath);
561
+ if (!repoRoot || missingPatch) {
562
+ patchesApplied = false;
563
+ } else {
564
+ const patchStats = await Promise.all(
565
+ patchesInOrder.map(async (patchPath) => ({
566
+ patchPath,
567
+ size: (await stat(patchPath)).size,
568
+ })),
569
+ );
570
+ const nonEmptyPatches = patchStats.filter((patch) => patch.size > 0).map((patch) => patch.patchPath);
571
+ if (nonEmptyPatches.length === 0) {
572
+ patchesApplied = true;
573
+ } else {
574
+ const patchTexts = await Promise.all(
575
+ nonEmptyPatches.map(async (patchPath) => Bun.file(patchPath).text()),
576
+ );
577
+ const combinedPatch = patchTexts.map((text) => (text.endsWith("\n") ? text : `${text}\n`)).join("");
578
+ if (!combinedPatch.trim()) {
579
+ patchesApplied = true;
580
+ } else {
581
+ const combinedPatchPath = path.join(tmpdir(), `omp-task-combined-${nanoid()}.patch`);
582
+ try {
583
+ await Bun.write(combinedPatchPath, combinedPatch);
584
+ const checkResult = await $`git apply --check --binary ${combinedPatchPath}`
585
+ .cwd(repoRoot)
586
+ .quiet()
587
+ .nothrow();
588
+ if (checkResult.exitCode !== 0) {
589
+ patchesApplied = false;
590
+ } else {
591
+ const applyResult = await $`git apply --binary ${combinedPatchPath}`
592
+ .cwd(repoRoot)
593
+ .quiet()
594
+ .nothrow();
595
+ patchesApplied = applyResult.exitCode === 0;
596
+ }
597
+ } finally {
598
+ await rm(combinedPatchPath, { force: true });
599
+ }
600
+ }
601
+ }
602
+ }
603
+
604
+ if (patchesApplied) {
605
+ patchApplySummary = "\n\nApplied patches: yes";
606
+ } else {
607
+ const notification =
608
+ "<system-notification>Patches were not applied and must be handled manually.</system-notification>";
609
+ const patchList =
610
+ patchPaths.length > 0
611
+ ? `\n\nPatch artifacts:\n${patchPaths.map((patch) => `- ${patch}`).join("\n")}`
612
+ : "";
613
+ patchApplySummary = `\n\n${notification}${patchList}`;
614
+ }
463
615
  }
464
616
 
465
617
  // Build final output - match plugin format
@@ -474,22 +626,26 @@ export class TaskTool implements AgentTool<typeof taskSchema, TaskToolDetails, T
474
626
  const meta = r.outputMeta
475
627
  ? ` [${r.outputMeta.lineCount} lines, ${formatBytes(r.outputMeta.charCount)}]`
476
628
  : "";
477
- return `[${r.agent}] ${status}${meta} ${r.taskId}\n${preview}`;
629
+ return `[${r.agent}] ${status}${meta} ${r.id}\n${preview}`;
478
630
  });
479
631
 
480
- const outputIds = results.filter((r) => !r.aborted || r.output.trim()).map((r) => r.taskId);
632
+ const outputIds = results.filter((r) => !r.aborted || r.output.trim()).map((r) => r.id);
481
633
  const outputHint =
482
- outputIds.length > 0 ? `\n\nUse output tool for full logs: output ids ${outputIds.join(", ")}` : "";
634
+ outputIds.length > 0
635
+ ? `\n\nUse read with agent:// for full logs: ${outputIds.map((id) => `agent://${id}`).join(", ")}`
636
+ : "";
483
637
  const schemaNote = schemaOverridden
484
638
  ? `\n\nNote: Agent '${agentName}' has a fixed output schema; your 'output' parameter was ignored.\nRequired schema: ${JSON.stringify(agent.output)}`
485
639
  : "";
486
640
  const cancelledNote = aborted && cancelledCount > 0 ? ` (${cancelledCount} cancelled)` : "";
487
641
  const summary = `${successCount}/${results.length} succeeded${cancelledNote} [${formatDuration(
488
642
  totalDuration,
489
- )}]\n\n${summaries.join("\n\n---\n\n")}${outputHint}${schemaNote}`;
643
+ )}]\n\n${summaries.join("\n\n---\n\n")}${outputHint}${schemaNote}${patchApplySummary}`;
490
644
 
491
645
  // Cleanup temp directory if used
492
- if (tempArtifactsDir) {
646
+ const shouldCleanupTempArtifacts =
647
+ tempArtifactsDir && (!isIsolated || patchesApplied === true || patchesApplied === null);
648
+ if (shouldCleanupTempArtifacts) {
493
649
  await rm(tempArtifactsDir, { recursive: true, force: true });
494
650
  }
495
651
 
@@ -8,8 +8,8 @@
8
8
  import path from "node:path";
9
9
  import type { Component } from "@oh-my-pi/pi-tui";
10
10
  import { Container, Text } from "@oh-my-pi/pi-tui";
11
- import type { Theme } from "../../../modes/interactive/theme/theme";
12
- import type { RenderResultOptions } from "../../custom-tools/types";
11
+ import type { RenderResultOptions } from "$c/extensibility/custom-tools/types";
12
+ import type { Theme } from "$c/modes/theme/theme";
13
13
  import {
14
14
  formatBadge,
15
15
  formatDuration,
@@ -17,14 +17,14 @@ import {
17
17
  formatStatusIcon,
18
18
  formatTokens,
19
19
  truncate,
20
- } from "../render-utils";
20
+ } from "$c/tools/render-utils";
21
21
  import {
22
22
  type FindingPriority,
23
23
  getPriorityInfo,
24
24
  PRIORITY_LABELS,
25
25
  type ReportFindingDetails,
26
26
  type SubmitReviewDetails,
27
- } from "../review";
27
+ } from "$c/tools/review";
28
28
  import { subprocessToolRegistry } from "./subprocess-tool-registry";
29
29
  import type { AgentProgress, SingleResult, TaskParams, TaskToolDetails } from "./types";
30
30
 
@@ -236,7 +236,7 @@ function renderOutputSection(
236
236
  try {
237
237
  const parsed = JSON.parse(trimmedOutput);
238
238
 
239
- // Collapsed: inline format like Vars
239
+ // Collapsed: inline format like Args
240
240
  if (!expanded) {
241
241
  lines.push(`${continuePrefix}${theme.fg("dim", formatOutputInline(parsed, theme))}`);
242
242
  return lines;
@@ -276,11 +276,25 @@ function renderOutputSection(
276
276
  return lines;
277
277
  }
278
278
 
279
- function formatVarsInline(vars: Record<string, string>, theme: Theme): string {
280
- const entries = Object.entries(vars);
281
- if (entries.length === 0) return "Vars: none";
279
+ function formatArgsInline(args: Record<string, string>, theme: Theme): string {
280
+ const entries = Object.entries(args);
281
+ if (entries.length === 0) return "No arguments";
282
+
283
+ // Single variable: show inline as "Key: value" without tree structure
284
+ if (entries.length === 1) {
285
+ const [key, value] = entries[0];
286
+ const humanKey = humanizeKey(key);
287
+ const displayValue = `"${truncate(value, 32, theme.format.ellipsis)}"`;
288
+ return `${humanKey}: ${displayValue}`;
289
+ }
290
+
282
291
  const pairs = entries.map(([key, value]) => `${key}=${truncate(value, 24, theme.format.ellipsis)}`);
283
- return `Vars: ${pairs.join(", ")}`;
292
+ return `Args: ${pairs.join(", ")}`;
293
+ }
294
+
295
+ /** Convert snake_case or kebab-case to Title Case */
296
+ function humanizeKey(key: string): string {
297
+ return key.replace(/[-_]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
284
298
  }
285
299
 
286
300
  function formatScalarInline(value: unknown, maxLen: number, theme: Theme): string {
@@ -336,22 +350,37 @@ function formatOutputInline(data: unknown, theme: Theme, maxWidth = 80): string
336
350
  return `Output: ${pairs.join(", ")}`;
337
351
  }
338
352
 
339
- function renderVarsSection(
340
- vars: Record<string, string> | undefined,
353
+ function renderArgsSection(
354
+ args: Record<string, string> | undefined,
341
355
  continuePrefix: string,
342
356
  expanded: boolean,
343
357
  theme: Theme,
344
358
  ): string[] {
345
- if (!vars || Object.keys(vars).length === 0) return [];
359
+ if (!args) return [];
360
+ // Filter out auto-injected id and description
361
+ const filteredArgs = Object.fromEntries(
362
+ Object.entries(args).filter(([key]) => key !== "id" && key !== "description"),
363
+ );
364
+ if (Object.keys(filteredArgs).length === 0) return [];
346
365
  const lines: string[] = [];
366
+ const entries = Object.entries(filteredArgs);
347
367
 
348
368
  if (!expanded) {
349
- lines.push(`${continuePrefix}${theme.fg("dim", formatVarsInline(vars, theme))}`);
369
+ lines.push(`${continuePrefix}${theme.fg("dim", formatArgsInline(filteredArgs, theme))}`);
370
+ return lines;
371
+ }
372
+
373
+ // Single variable: show inline as "Key: value" without tree structure
374
+ if (entries.length === 1) {
375
+ const [key, value] = entries[0];
376
+ const humanKey = humanizeKey(key);
377
+ const displayValue = `"${truncate(value, 60, theme.format.ellipsis)}"`;
378
+ lines.push(`${continuePrefix}${theme.fg("dim", `${humanKey}: ${displayValue}`)}`);
350
379
  return lines;
351
380
  }
352
381
 
353
- lines.push(`${continuePrefix}${theme.fg("dim", "Vars")}`);
354
- const tree = renderJsonTreeLines(vars, theme, 4, 16);
382
+ lines.push(`${continuePrefix}${theme.fg("dim", "Args")}`);
383
+ const tree = renderJsonTreeLines(filteredArgs, theme, 4, 16);
355
384
  for (const line of tree.lines) {
356
385
  lines.push(`${continuePrefix} ${line}`);
357
386
  }
@@ -380,6 +409,7 @@ export function renderCall(args: TaskParams, theme: Theme): Component {
380
409
  const branch = theme.fg("dim", theme.tree.branch);
381
410
  const last = theme.fg("dim", theme.tree.last);
382
411
  const vertical = theme.fg("dim", theme.tree.vertical);
412
+ const showIsolated = args.isolated === true;
383
413
 
384
414
  if (hasContext) {
385
415
  lines.push(` ${branch} ${theme.fg("dim", "Context")}`);
@@ -387,11 +417,18 @@ export function renderCall(args: TaskParams, theme: Theme): Component {
387
417
  const content = line ? theme.fg("muted", line) : "";
388
418
  lines.push(` ${vertical} ${content}`);
389
419
  }
390
- lines.push(` ${last} ${theme.fg("dim", "Tasks")}: ${theme.fg("muted", `${args.tasks.length} agents`)}`);
420
+ const taskPrefix = showIsolated ? branch : last;
421
+ lines.push(` ${taskPrefix} ${theme.fg("dim", "Tasks")}: ${theme.fg("muted", `${args.tasks.length} agents`)}`);
422
+ if (showIsolated) {
423
+ lines.push(` ${last} ${theme.fg("dim", "Isolated")}: ${theme.fg("muted", "true")}`);
424
+ }
391
425
  return new Text(lines.join("\n"), 0, 0);
392
426
  }
393
427
 
394
428
  lines.push(`${theme.fg("dim", "Tasks")}: ${theme.fg("muted", `${args.tasks.length} agents`)}`);
429
+ if (showIsolated) {
430
+ lines.push(`${theme.fg("dim", "Isolated")}: ${theme.fg("muted", "true")}`);
431
+ }
395
432
 
396
433
  return new Text(lines.join("\n"), 0, 0);
397
434
  }
@@ -418,9 +455,9 @@ function renderAgentProgress(
418
455
  ? "error"
419
456
  : "accent";
420
457
 
421
- // Main status line: taskId: description [status] · stats · ⟨agent⟩
458
+ // Main status line: id: description [status] · stats · ⟨agent⟩
422
459
  const description = progress.description?.trim();
423
- const titlePart = description ? `${theme.bold(progress.taskId)}: ${description}` : progress.taskId;
460
+ const titlePart = description ? `${theme.bold(progress.id)}: ${description}` : progress.id;
424
461
  let statusLine = `${prefix} ${theme.fg(iconColor, icon)} ${theme.fg("accent", titlePart)}`;
425
462
 
426
463
  // Only show badge for non-running states (spinner already indicates running)
@@ -445,7 +482,7 @@ function renderAgentProgress(
445
482
 
446
483
  lines.push(statusLine);
447
484
 
448
- lines.push(...renderVarsSection(progress.vars, continuePrefix, expanded, theme));
485
+ lines.push(...renderArgsSection(progress.args, continuePrefix, expanded, theme));
449
486
 
450
487
  // Current tool (if running) or most recent completed tool
451
488
  if (progress.status === "running") {
@@ -638,9 +675,9 @@ function renderAgentResult(result: SingleResult, isLast: boolean, expanded: bool
638
675
  const iconColor = success ? "success" : "error";
639
676
  const statusText = aborted ? "aborted" : success ? "done" : "failed";
640
677
 
641
- // Main status line: taskId: description [status] · stats · ⟨agent⟩
678
+ // Main status line: id: description [status] · stats · ⟨agent⟩
642
679
  const description = result.description?.trim();
643
- const titlePart = description ? `${theme.bold(result.taskId)}: ${description}` : result.taskId;
680
+ const titlePart = description ? `${theme.bold(result.id)}: ${description}` : result.id;
644
681
  let statusLine = `${prefix} ${theme.fg(iconColor, icon)} ${theme.fg("accent", titlePart)} ${formatBadge(
645
682
  statusText,
646
683
  iconColor,
@@ -656,7 +693,7 @@ function renderAgentResult(result: SingleResult, isLast: boolean, expanded: bool
656
693
  }
657
694
 
658
695
  lines.push(statusLine);
659
- lines.push(...renderVarsSection(result.vars, continuePrefix, expanded, theme));
696
+ lines.push(...renderArgsSection(result.args, continuePrefix, expanded, theme));
660
697
 
661
698
  // Check for review result (complete with review schema + report_finding)
662
699
  const completeData = result.extractedToolData?.complete as Array<{ data: unknown }> | undefined;
@@ -722,6 +759,10 @@ function renderAgentResult(result: SingleResult, isLast: boolean, expanded: bool
722
759
  lines.push(...renderOutputSection(result.output, continuePrefix, expanded, theme, 3, 12));
723
760
  }
724
761
 
762
+ if (result.patchPath && !aborted && result.exitCode === 0) {
763
+ lines.push(`${continuePrefix}${theme.fg("dim", `Patch: ${result.patchPath}`)}`);
764
+ }
765
+
725
766
  // Error message
726
767
  if (result.error && !success) {
727
768
  lines.push(`${continuePrefix}${theme.fg("error", truncate(result.error, 70, theme.format.ellipsis))}`);
@@ -739,6 +780,7 @@ export function renderResult(
739
780
  theme: Theme,
740
781
  ): Component {
741
782
  const { expanded, isPartial, spinnerFrame } = options;
783
+ const fallbackText = result.content.find((c) => c.type === "text")?.text ?? "";
742
784
  const details = result.details;
743
785
 
744
786
  if (!details) {
@@ -785,7 +827,22 @@ export function renderResult(
785
827
  }
786
828
 
787
829
  if (lines.length === 0) {
788
- return new Text(theme.fg("dim", "No results"), 0, 0);
830
+ const text = fallbackText.trim() ? fallbackText : "No results";
831
+ return new Text(theme.fg("dim", truncate(text, 140, theme.format.ellipsis)), 0, 0);
832
+ }
833
+
834
+ if (fallbackText.trim()) {
835
+ const summaryLines = fallbackText.split("\n");
836
+ const markerIndex = summaryLines.findIndex(
837
+ (line) => line.includes("<system-notification>") || line.startsWith("Applied patches:"),
838
+ );
839
+ if (markerIndex >= 0) {
840
+ const extra = summaryLines.slice(markerIndex);
841
+ for (const line of extra) {
842
+ if (!line.trim()) continue;
843
+ lines.push(theme.fg("dim", line));
844
+ }
845
+ }
789
846
  }
790
847
 
791
848
  const indented = lines.map((line) => (line.trim() ? ` ${line}` : ""));
@@ -8,7 +8,7 @@
8
8
  */
9
9
 
10
10
  import type { Component } from "@oh-my-pi/pi-tui";
11
- import type { Theme } from "../../../modes/interactive/theme/theme";
11
+ import type { Theme } from "$c/modes/theme/theme";
12
12
 
13
13
  /** Event from subprocess tool execution (parsed from JSONL) */
14
14
  export interface SubprocessToolEvent {
@@ -0,0 +1,47 @@
1
+ import type { TaskItem } from "./types";
2
+
3
+ type RenderResult = {
4
+ task: string;
5
+ args: Record<string, string>;
6
+ id: string;
7
+ description: string;
8
+ };
9
+
10
+ export function renderTemplate(template: string, task: TaskItem): RenderResult {
11
+ const { id, description, args } = task;
12
+
13
+ let usedPlaceholder = false;
14
+ const unknownArguments: string[] = [];
15
+ let renderedTask = template.replace(/\{\{(\w+)\}\}/g, (_match, key: string) => {
16
+ const value = args?.[key];
17
+ if (value) {
18
+ usedPlaceholder = true;
19
+ return value;
20
+ }
21
+ switch (key) {
22
+ case "id":
23
+ usedPlaceholder = true;
24
+ return id;
25
+ case "description":
26
+ usedPlaceholder = true;
27
+ return description;
28
+ default:
29
+ unknownArguments.push(key);
30
+ return `{{${key}}}`;
31
+ }
32
+ });
33
+
34
+ if (unknownArguments.length > 0) {
35
+ throw new Error(`Task "${id}" has unknown arguments: ${unknownArguments.join(", ")}`);
36
+ }
37
+
38
+ if (!usedPlaceholder) {
39
+ renderedTask += `\n----------------------\n# ${id}\n${description}`;
40
+ }
41
+ return {
42
+ task: renderedTask,
43
+ args: { id, description, ...args },
44
+ id,
45
+ description,
46
+ };
47
+ }