@oh-my-pi/pi-coding-agent 6.9.69 → 8.0.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 (502) hide show
  1. package/CHANGELOG.md +219 -51
  2. package/README.md +1 -1
  3. package/docs/hooks.md +2 -2
  4. package/docs/sdk.md +1 -1
  5. package/examples/sdk/04-skills.ts +1 -1
  6. package/package.json +10 -10
  7. package/scripts/format-prompts.ts +143 -0
  8. package/scripts/generate-template.ts +1 -1
  9. package/src/cli/args.ts +3 -3
  10. package/src/cli/config-cli.ts +4 -4
  11. package/src/cli/file-processor.ts +3 -3
  12. package/src/cli/list-models.ts +2 -2
  13. package/src/cli/plugin-cli.ts +3 -3
  14. package/src/cli/session-picker.ts +2 -2
  15. package/src/cli/setup-cli.ts +2 -2
  16. package/src/cli/stats-cli.ts +1 -1
  17. package/src/cli/update-cli.ts +2 -2
  18. package/src/{core → config}/keybindings.ts +1 -1
  19. package/src/{core → config}/model-registry.ts +8 -1
  20. package/src/{core → config}/model-resolver.ts +3 -3
  21. package/src/{core → config}/prompt-templates.ts +2 -2
  22. package/src/{core → config}/settings-manager.ts +6 -6
  23. package/src/{core/cursor/exec-bridge.ts → cursor.ts} +4 -4
  24. package/src/discovery/agents-md.ts +4 -4
  25. package/src/discovery/builtin.ts +17 -17
  26. package/src/discovery/claude.ts +12 -12
  27. package/src/discovery/cline.ts +6 -6
  28. package/src/discovery/codex.ts +21 -21
  29. package/src/discovery/cursor.ts +9 -9
  30. package/src/discovery/gemini.ts +9 -9
  31. package/src/discovery/github.ts +6 -6
  32. package/src/discovery/helpers.ts +4 -4
  33. package/src/discovery/index.ts +16 -16
  34. package/src/discovery/mcp-json.ts +4 -4
  35. package/src/discovery/ssh.ts +4 -4
  36. package/src/discovery/vscode.ts +4 -4
  37. package/src/discovery/windsurf.ts +6 -6
  38. package/src/{core/tools/exa → exa}/company.ts +2 -3
  39. package/src/{core/tools/exa → exa}/index.ts +2 -2
  40. package/src/{core/tools/exa → exa}/linkedin.ts +2 -3
  41. package/src/{core/tools/exa → exa}/mcp-client.ts +2 -2
  42. package/src/{core/tools/exa → exa}/render.ts +3 -3
  43. package/src/{core/tools/exa → exa}/researcher.ts +1 -1
  44. package/src/{core/tools/exa → exa}/search.ts +2 -10
  45. package/src/{core/tools/exa → exa}/websets.ts +1 -1
  46. package/src/{core → exec}/bash-executor.ts +23 -7
  47. package/src/{core → export}/custom-share.ts +1 -1
  48. package/src/{core/export-html → export/html}/index.ts +3 -3
  49. package/src/{core → export}/ttsr.ts +2 -2
  50. package/src/{core → extensibility}/custom-commands/bundled/review/index.ts +4 -4
  51. package/src/{core → extensibility}/custom-commands/loader.ts +3 -3
  52. package/src/{core → extensibility}/custom-commands/types.ts +1 -1
  53. package/src/{core → extensibility}/custom-tools/loader.ts +9 -9
  54. package/src/{core → extensibility}/custom-tools/types.ts +6 -6
  55. package/src/{core → extensibility}/custom-tools/wrapper.ts +1 -1
  56. package/src/{core → extensibility}/extensions/loader.ts +8 -8
  57. package/src/{core → extensibility}/extensions/runner.ts +3 -3
  58. package/src/{core → extensibility}/extensions/types.ts +15 -15
  59. package/src/{core → extensibility}/extensions/wrapper.ts +1 -1
  60. package/src/{core → extensibility}/hooks/index.ts +1 -1
  61. package/src/{core → extensibility}/hooks/loader.ts +7 -7
  62. package/src/{core → extensibility}/hooks/runner.ts +4 -4
  63. package/src/{core → extensibility}/hooks/types.ts +9 -9
  64. package/src/{core → extensibility}/plugins/doctor.ts +1 -1
  65. package/src/{core → extensibility}/plugins/installer.ts +2 -3
  66. package/src/{core → extensibility}/plugins/paths.ts +1 -1
  67. package/src/{core → extensibility}/skills.ts +8 -48
  68. package/src/{core → extensibility}/slash-commands.ts +6 -6
  69. package/src/index.ts +127 -128
  70. package/src/internal-urls/agent-protocol.ts +126 -0
  71. package/src/internal-urls/artifact-protocol.ts +93 -0
  72. package/src/internal-urls/index.ts +28 -0
  73. package/src/internal-urls/json-query.ts +126 -0
  74. package/src/internal-urls/router.ts +69 -0
  75. package/src/internal-urls/rule-protocol.ts +56 -0
  76. package/src/internal-urls/skill-protocol.ts +112 -0
  77. package/src/internal-urls/types.ts +48 -0
  78. package/src/{core/python-executor.ts → ipy/executor.ts} +74 -13
  79. package/src/{core/python-gateway-coordinator.ts → ipy/gateway-coordinator.ts} +40 -270
  80. package/src/{core/python-kernel.ts → ipy/kernel.ts} +38 -10
  81. package/src/{core/python-prelude.py → ipy/prelude.py} +201 -8
  82. package/src/ipy/prelude.ts +3 -0
  83. package/src/{core/tools/lsp → lsp}/client.ts +7 -6
  84. package/src/{core/tools/lsp → lsp}/clients/biome-client.ts +1 -1
  85. package/src/{core/tools/lsp → lsp}/clients/index.ts +1 -1
  86. package/src/{core/tools/lsp → lsp}/clients/lsp-linter-client.ts +4 -4
  87. package/src/{core/tools/lsp → lsp}/config.ts +1 -1
  88. package/src/{core/tools/lsp → lsp}/index.ts +29 -17
  89. package/src/{core/tools/lsp → lsp}/render.ts +2 -2
  90. package/src/{core/tools/lsp → lsp}/types.ts +14 -16
  91. package/src/{core/tools/lsp → lsp}/utils.ts +1 -1
  92. package/src/main.ts +12 -12
  93. package/src/{core/mcp → mcp}/config.ts +8 -8
  94. package/src/{core/mcp → mcp}/loader.ts +5 -6
  95. package/src/{core/mcp → mcp}/manager.ts +2 -2
  96. package/src/{core/mcp → mcp}/tool-bridge.ts +35 -6
  97. package/src/{core/mcp → mcp}/tool-cache.ts +1 -1
  98. package/src/{core/mcp → mcp}/transports/http.ts +7 -1
  99. package/src/{core/mcp → mcp}/transports/stdio.ts +1 -1
  100. package/src/{core/mcp → mcp}/types.ts +1 -1
  101. package/src/migrations.ts +2 -2
  102. package/src/modes/{interactive/components → components}/armin.ts +1 -1
  103. package/src/modes/{interactive/components → components}/assistant-message.ts +1 -1
  104. package/src/modes/{interactive/components → components}/bash-execution.ts +37 -29
  105. package/src/modes/{interactive/components → components}/bordered-loader.ts +1 -1
  106. package/src/modes/{interactive/components → components}/branch-summary-message.ts +2 -2
  107. package/src/modes/{interactive/components → components}/compaction-summary-message.ts +2 -2
  108. package/src/modes/{interactive/components → components}/custom-message.ts +3 -3
  109. package/src/modes/{interactive/components → components}/diff.ts +1 -1
  110. package/src/modes/{interactive/components → components}/dynamic-border.ts +1 -1
  111. package/src/modes/{interactive/components → components}/extensions/extension-dashboard.ts +3 -3
  112. package/src/modes/{interactive/components → components}/extensions/extension-list.ts +2 -2
  113. package/src/modes/{interactive/components → components}/extensions/inspector-panel.ts +1 -1
  114. package/src/modes/{interactive/components → components}/extensions/state-manager.ts +11 -17
  115. package/src/modes/{interactive/components → components}/extensions/types.ts +1 -1
  116. package/src/modes/{interactive/components → components}/footer.ts +3 -3
  117. package/src/modes/{interactive/components → components}/history-search.ts +2 -2
  118. package/src/modes/{interactive/components → components}/hook-editor.ts +1 -1
  119. package/src/modes/{interactive/components → components}/hook-input.ts +1 -1
  120. package/src/modes/{interactive/components → components}/hook-message.ts +3 -3
  121. package/src/modes/{interactive/components → components}/hook-selector.ts +1 -1
  122. package/src/modes/{interactive/components → components}/keybinding-hints.ts +2 -2
  123. package/src/modes/{interactive/components → components}/login-dialog.ts +1 -1
  124. package/src/modes/{interactive/components → components}/model-selector.ts +5 -5
  125. package/src/modes/{interactive/components → components}/oauth-selector.ts +2 -2
  126. package/src/modes/{interactive/components → components}/plugin-settings.ts +3 -3
  127. package/src/modes/{interactive/components → components}/python-execution.ts +35 -24
  128. package/src/modes/{interactive/components → components}/queue-mode-selector.ts +1 -1
  129. package/src/modes/{interactive/components → components}/read-tool-group.ts +2 -2
  130. package/src/modes/{interactive/components → components}/session-selector.ts +3 -3
  131. package/src/modes/{interactive/components → components}/settings-defs.ts +2 -2
  132. package/src/modes/{interactive/components → components}/settings-selector.ts +2 -2
  133. package/src/modes/{interactive/components → components}/show-images-selector.ts +1 -1
  134. package/src/modes/{interactive/components → components}/status-line/segments.ts +2 -2
  135. package/src/modes/{interactive/components → components}/status-line/separators.ts +1 -1
  136. package/src/modes/{interactive/components → components}/status-line/types.ts +2 -2
  137. package/src/modes/{interactive/components → components}/status-line-segment-editor.ts +2 -2
  138. package/src/modes/{interactive/components → components}/status-line.ts +3 -3
  139. package/src/modes/{interactive/components → components}/theme-selector.ts +1 -1
  140. package/src/modes/{interactive/components → components}/thinking-selector.ts +1 -1
  141. package/src/modes/{interactive/components → components}/todo-display.ts +3 -4
  142. package/src/modes/{interactive/components → components}/todo-reminder.ts +2 -2
  143. package/src/modes/{interactive/components → components}/tool-execution.ts +8 -8
  144. package/src/modes/{interactive/components → components}/tree-selector.ts +3 -3
  145. package/src/modes/{interactive/components → components}/ttsr-notification.ts +2 -2
  146. package/src/modes/{interactive/components → components}/user-message-selector.ts +1 -1
  147. package/src/modes/{interactive/components → components}/user-message.ts +1 -1
  148. package/src/modes/{interactive/components → components}/welcome.ts +2 -2
  149. package/src/modes/{interactive/controllers → controllers}/command-controller.ts +381 -30
  150. package/src/modes/{interactive/controllers → controllers}/event-controller.ts +9 -9
  151. package/src/modes/{interactive/controllers → controllers}/extension-ui-controller.ts +8 -8
  152. package/src/modes/{interactive/controllers → controllers}/input-controller.ts +61 -13
  153. package/src/modes/{interactive/controllers → controllers}/selector-controller.ts +16 -16
  154. package/src/modes/index.ts +1 -1
  155. package/src/modes/{interactive/interactive-mode.ts → interactive-mode.ts} +20 -15
  156. package/src/modes/print-mode.ts +1 -1
  157. package/src/modes/rpc/rpc-client.ts +3 -3
  158. package/src/modes/rpc/rpc-mode.ts +3 -3
  159. package/src/modes/rpc/rpc-types.ts +3 -3
  160. package/src/modes/{interactive/theme → theme}/theme.ts +1 -1
  161. package/src/modes/{interactive/types.ts → types.ts} +10 -10
  162. package/src/modes/{interactive/utils → utils}/ui-helpers.ts +20 -27
  163. package/src/{core/tools/patch → patch}/applicator.ts +1 -1
  164. package/src/{core/tools/patch → patch}/diff.ts +1 -1
  165. package/src/{core/tools/patch → patch}/index.ts +31 -36
  166. package/src/{core/tools/patch → patch}/shared.ts +9 -6
  167. package/src/prompts/agents/explore.md +83 -46
  168. package/src/prompts/agents/init.md +9 -4
  169. package/src/prompts/agents/plan.md +8 -7
  170. package/src/prompts/agents/reviewer.md +36 -18
  171. package/src/prompts/agents/task.md +4 -4
  172. package/src/prompts/compaction/branch-summary-preamble.md +0 -1
  173. package/src/prompts/review-request.md +0 -1
  174. package/src/prompts/system/custom-system-prompt.md +2 -14
  175. package/src/prompts/system/file-operations.md +0 -2
  176. package/src/prompts/system/system-prompt.md +182 -171
  177. package/src/prompts/system/web-search.md +26 -0
  178. package/src/prompts/tools/ask.md +31 -24
  179. package/src/prompts/tools/bash.md +20 -17
  180. package/src/prompts/tools/calculator.md +9 -5
  181. package/src/prompts/tools/fetch.md +16 -0
  182. package/src/prompts/tools/find.md +15 -5
  183. package/src/prompts/tools/gemini-image.md +21 -6
  184. package/src/prompts/tools/grep.md +28 -12
  185. package/src/prompts/tools/lsp.md +35 -14
  186. package/src/prompts/tools/patch.md +39 -41
  187. package/src/prompts/tools/python.md +59 -77
  188. package/src/prompts/tools/read.md +23 -22
  189. package/src/prompts/tools/replace.md +19 -12
  190. package/src/prompts/tools/ssh.md +21 -28
  191. package/src/prompts/tools/task.md +54 -44
  192. package/src/prompts/tools/todo-write.md +52 -163
  193. package/src/prompts/tools/web-search.md +16 -9
  194. package/src/prompts/tools/write.md +13 -2
  195. package/src/{core/sdk.ts → sdk.ts} +65 -34
  196. package/src/{core → session}/agent-session.ts +157 -41
  197. package/src/{core → session}/agent-storage.ts +2 -2
  198. package/src/session/artifacts.ts +110 -0
  199. package/src/{core → session}/auth-storage.ts +525 -203
  200. package/src/{core → session}/compaction/branch-summarization.ts +5 -5
  201. package/src/{core → session}/compaction/compaction.ts +6 -6
  202. package/src/{core → session}/compaction/utils.ts +3 -3
  203. package/src/{core → session}/history-storage.ts +1 -1
  204. package/src/{core → session}/messages.ts +6 -8
  205. package/src/{core → session}/session-manager.ts +2 -2
  206. package/src/{core → session}/storage-migration.ts +2 -2
  207. package/src/session/streaming-output.ts +177 -0
  208. package/src/{core/ssh → ssh}/connection-manager.ts +1 -1
  209. package/src/{core/ssh → ssh}/ssh-executor.ts +19 -4
  210. package/src/{core/ssh → ssh}/sshfs-mount.ts +1 -1
  211. package/src/{core/system-prompt.ts → system-prompt.ts} +8 -37
  212. package/src/{core/tools/task → task}/agents.ts +8 -8
  213. package/src/{core/tools/task → task}/commands.ts +5 -6
  214. package/src/{core/tools/task → task}/discovery.ts +3 -3
  215. package/src/{core/tools/task → task}/executor.ts +34 -44
  216. package/src/{core/tools/task → task}/index.ts +206 -50
  217. package/src/{core/tools/task → task}/render.ts +80 -23
  218. package/src/{core/tools/task → task}/subprocess-tool-registry.ts +1 -1
  219. package/src/task/template.ts +47 -0
  220. package/src/{core/tools/task → task}/types.ts +19 -27
  221. package/src/{core/tools/task → task}/worker-protocol.ts +8 -4
  222. package/src/{core/tools/task → task}/worker.ts +34 -29
  223. package/src/task/worktree.ts +166 -0
  224. package/src/{core/tools → tools}/ask.ts +13 -21
  225. package/src/{core/tools → tools}/bash-interceptor.ts +1 -1
  226. package/src/{core/tools → tools}/bash.ts +61 -63
  227. package/src/{core/tools → tools}/calculator.ts +4 -4
  228. package/src/{core/tools → tools}/complete.ts +1 -1
  229. package/src/{core/tools → tools}/context.ts +2 -2
  230. package/src/{core/tools/web-fetch.ts → tools/fetch.ts} +97 -76
  231. package/src/{core/tools → tools}/find.ts +96 -107
  232. package/src/{core/tools → tools}/gemini-image.ts +420 -29
  233. package/src/{core/tools → tools}/grep.ts +155 -164
  234. package/src/{core/tools → tools}/index.ts +63 -56
  235. package/src/tools/list-limit.ts +40 -0
  236. package/src/{core/tools → tools}/ls.ts +44 -35
  237. package/src/{core/tools → tools}/notebook.ts +3 -3
  238. package/src/tools/output-meta.ts +443 -0
  239. package/src/tools/output-utils.ts +63 -0
  240. package/src/{core/tools → tools}/python.ts +106 -89
  241. package/src/tools/read.ts +882 -0
  242. package/src/{core/tools → tools}/render-utils.ts +1 -1
  243. package/src/{core/tools → tools}/renderers.ts +8 -10
  244. package/src/{core/tools → tools}/review.ts +2 -2
  245. package/src/{core/tools → tools}/ssh.ts +56 -59
  246. package/src/{core/tools → tools}/todo-write.ts +12 -23
  247. package/src/tools/tool-errors.ts +95 -0
  248. package/src/tools/tool-result.ts +92 -0
  249. package/src/{core/tools → tools}/truncate.ts +2 -2
  250. package/src/{core/tools → tools}/write.ts +15 -13
  251. package/src/utils/changelog.ts +1 -1
  252. package/src/{core → utils}/file-mentions.ts +4 -4
  253. package/src/utils/image-convert.ts +1 -1
  254. package/src/utils/image-resize.ts +1 -1
  255. package/src/utils/shell.ts +1 -1
  256. package/src/{core → utils}/title-generator.ts +4 -4
  257. package/src/utils/tools-manager.ts +1 -1
  258. package/src/{core/tools/web-scrapers → web/scrapers}/choosealicense.ts +1 -1
  259. package/src/{core/tools/web-scrapers → web/scrapers}/twitter.ts +3 -2
  260. package/src/{core/tools/web-scrapers → web/scrapers}/types.ts +4 -2
  261. package/src/{core/tools/web-scrapers → web/scrapers}/utils.ts +1 -1
  262. package/src/{core/tools/web-scrapers → web/scrapers}/youtube.ts +14 -13
  263. package/src/{core/tools/web-search → web/search}/auth.ts +4 -4
  264. package/src/{core/tools/web-search → web/search}/index.ts +22 -71
  265. package/src/{core/tools/web-search → web/search}/providers/anthropic.ts +7 -10
  266. package/src/{core/tools/web-search → web/search}/providers/exa.ts +2 -2
  267. package/src/{core/tools/web-search → web/search}/providers/perplexity.ts +4 -16
  268. package/src/{core/tools/web-search → web/search}/render.ts +3 -3
  269. package/scripts/migrate-sessions.sh +0 -93
  270. package/src/core/index.ts +0 -56
  271. package/src/core/python-prelude.ts +0 -3
  272. package/src/core/ssh-executor.ts +0 -5
  273. package/src/core/streaming-output.ts +0 -115
  274. package/src/core/tools/output.ts +0 -519
  275. package/src/core/tools/read.ts +0 -717
  276. package/src/core/tools/task/template.ts +0 -37
  277. package/src/prompts/tools/output.md +0 -47
  278. package/src/prompts/tools/web-fetch.md +0 -9
  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/tools/lsp → lsp}/defaults.json +0 -0
  299. /package/src/{core/tools/lsp → lsp}/edits.ts +0 -0
  300. /package/src/{core/tools/lsp → lsp}/lspmux.ts +0 -0
  301. /package/src/{core/tools/lsp → lsp}/rust-analyzer.ts +0 -0
  302. /package/src/{core/mcp → mcp}/client.ts +0 -0
  303. /package/src/{core/mcp → mcp}/index.ts +0 -0
  304. /package/src/{core/mcp → mcp}/json-rpc.ts +0 -0
  305. /package/src/{core/mcp → mcp}/transports/index.ts +0 -0
  306. /package/src/modes/{interactive/components → components}/countdown-timer.ts +0 -0
  307. /package/src/modes/{interactive/components → components}/custom-editor.ts +0 -0
  308. /package/src/modes/{interactive/components → components}/extensions/index.ts +0 -0
  309. /package/src/modes/{interactive/components → components}/index.ts +0 -0
  310. /package/src/modes/{interactive/components → components}/status-line/index.ts +0 -0
  311. /package/src/modes/{interactive/components → components}/status-line/presets.ts +0 -0
  312. /package/src/modes/{interactive/components → components}/visual-truncate.ts +0 -0
  313. /package/src/modes/{interactive/theme → theme}/dark.json +0 -0
  314. /package/src/modes/{interactive/theme → theme}/defaults/alabaster.json +0 -0
  315. /package/src/modes/{interactive/theme → theme}/defaults/amethyst.json +0 -0
  316. /package/src/modes/{interactive/theme → theme}/defaults/anthracite.json +0 -0
  317. /package/src/modes/{interactive/theme → theme}/defaults/basalt.json +0 -0
  318. /package/src/modes/{interactive/theme → theme}/defaults/birch.json +0 -0
  319. /package/src/modes/{interactive/theme → theme}/defaults/dark-abyss.json +0 -0
  320. /package/src/modes/{interactive/theme → theme}/defaults/dark-arctic.json +0 -0
  321. /package/src/modes/{interactive/theme → theme}/defaults/dark-aurora.json +0 -0
  322. /package/src/modes/{interactive/theme → theme}/defaults/dark-catppuccin.json +0 -0
  323. /package/src/modes/{interactive/theme → theme}/defaults/dark-cavern.json +0 -0
  324. /package/src/modes/{interactive/theme → theme}/defaults/dark-copper.json +0 -0
  325. /package/src/modes/{interactive/theme → theme}/defaults/dark-cosmos.json +0 -0
  326. /package/src/modes/{interactive/theme → theme}/defaults/dark-cyberpunk.json +0 -0
  327. /package/src/modes/{interactive/theme → theme}/defaults/dark-dracula.json +0 -0
  328. /package/src/modes/{interactive/theme → theme}/defaults/dark-eclipse.json +0 -0
  329. /package/src/modes/{interactive/theme → theme}/defaults/dark-ember.json +0 -0
  330. /package/src/modes/{interactive/theme → theme}/defaults/dark-equinox.json +0 -0
  331. /package/src/modes/{interactive/theme → theme}/defaults/dark-forest.json +0 -0
  332. /package/src/modes/{interactive/theme → theme}/defaults/dark-github.json +0 -0
  333. /package/src/modes/{interactive/theme → theme}/defaults/dark-gruvbox.json +0 -0
  334. /package/src/modes/{interactive/theme → theme}/defaults/dark-lavender.json +0 -0
  335. /package/src/modes/{interactive/theme → theme}/defaults/dark-lunar.json +0 -0
  336. /package/src/modes/{interactive/theme → theme}/defaults/dark-midnight.json +0 -0
  337. /package/src/modes/{interactive/theme → theme}/defaults/dark-monochrome.json +0 -0
  338. /package/src/modes/{interactive/theme → theme}/defaults/dark-monokai.json +0 -0
  339. /package/src/modes/{interactive/theme → theme}/defaults/dark-nebula.json +0 -0
  340. /package/src/modes/{interactive/theme → theme}/defaults/dark-nord.json +0 -0
  341. /package/src/modes/{interactive/theme → theme}/defaults/dark-ocean.json +0 -0
  342. /package/src/modes/{interactive/theme → theme}/defaults/dark-one.json +0 -0
  343. /package/src/modes/{interactive/theme → theme}/defaults/dark-rainforest.json +0 -0
  344. /package/src/modes/{interactive/theme → theme}/defaults/dark-reef.json +0 -0
  345. /package/src/modes/{interactive/theme → theme}/defaults/dark-retro.json +0 -0
  346. /package/src/modes/{interactive/theme → theme}/defaults/dark-rose-pine.json +0 -0
  347. /package/src/modes/{interactive/theme → theme}/defaults/dark-sakura.json +0 -0
  348. /package/src/modes/{interactive/theme → theme}/defaults/dark-slate.json +0 -0
  349. /package/src/modes/{interactive/theme → theme}/defaults/dark-solarized.json +0 -0
  350. /package/src/modes/{interactive/theme → theme}/defaults/dark-solstice.json +0 -0
  351. /package/src/modes/{interactive/theme → theme}/defaults/dark-starfall.json +0 -0
  352. /package/src/modes/{interactive/theme → theme}/defaults/dark-sunset.json +0 -0
  353. /package/src/modes/{interactive/theme → theme}/defaults/dark-swamp.json +0 -0
  354. /package/src/modes/{interactive/theme → theme}/defaults/dark-synthwave.json +0 -0
  355. /package/src/modes/{interactive/theme → theme}/defaults/dark-taiga.json +0 -0
  356. /package/src/modes/{interactive/theme → theme}/defaults/dark-terminal.json +0 -0
  357. /package/src/modes/{interactive/theme → theme}/defaults/dark-tokyo-night.json +0 -0
  358. /package/src/modes/{interactive/theme → theme}/defaults/dark-tundra.json +0 -0
  359. /package/src/modes/{interactive/theme → theme}/defaults/dark-twilight.json +0 -0
  360. /package/src/modes/{interactive/theme → theme}/defaults/dark-volcanic.json +0 -0
  361. /package/src/modes/{interactive/theme → theme}/defaults/graphite.json +0 -0
  362. /package/src/modes/{interactive/theme → theme}/defaults/index.ts +0 -0
  363. /package/src/modes/{interactive/theme → theme}/defaults/light-arctic.json +0 -0
  364. /package/src/modes/{interactive/theme → theme}/defaults/light-aurora-day.json +0 -0
  365. /package/src/modes/{interactive/theme → theme}/defaults/light-canyon.json +0 -0
  366. /package/src/modes/{interactive/theme → theme}/defaults/light-catppuccin.json +0 -0
  367. /package/src/modes/{interactive/theme → theme}/defaults/light-cirrus.json +0 -0
  368. /package/src/modes/{interactive/theme → theme}/defaults/light-coral.json +0 -0
  369. /package/src/modes/{interactive/theme → theme}/defaults/light-cyberpunk.json +0 -0
  370. /package/src/modes/{interactive/theme → theme}/defaults/light-dawn.json +0 -0
  371. /package/src/modes/{interactive/theme → theme}/defaults/light-dunes.json +0 -0
  372. /package/src/modes/{interactive/theme → theme}/defaults/light-eucalyptus.json +0 -0
  373. /package/src/modes/{interactive/theme → theme}/defaults/light-forest.json +0 -0
  374. /package/src/modes/{interactive/theme → theme}/defaults/light-frost.json +0 -0
  375. /package/src/modes/{interactive/theme → theme}/defaults/light-github.json +0 -0
  376. /package/src/modes/{interactive/theme → theme}/defaults/light-glacier.json +0 -0
  377. /package/src/modes/{interactive/theme → theme}/defaults/light-gruvbox.json +0 -0
  378. /package/src/modes/{interactive/theme → theme}/defaults/light-haze.json +0 -0
  379. /package/src/modes/{interactive/theme → theme}/defaults/light-honeycomb.json +0 -0
  380. /package/src/modes/{interactive/theme → theme}/defaults/light-lagoon.json +0 -0
  381. /package/src/modes/{interactive/theme → theme}/defaults/light-lavender.json +0 -0
  382. /package/src/modes/{interactive/theme → theme}/defaults/light-meadow.json +0 -0
  383. /package/src/modes/{interactive/theme → theme}/defaults/light-mint.json +0 -0
  384. /package/src/modes/{interactive/theme → theme}/defaults/light-monochrome.json +0 -0
  385. /package/src/modes/{interactive/theme → theme}/defaults/light-ocean.json +0 -0
  386. /package/src/modes/{interactive/theme → theme}/defaults/light-one.json +0 -0
  387. /package/src/modes/{interactive/theme → theme}/defaults/light-opal.json +0 -0
  388. /package/src/modes/{interactive/theme → theme}/defaults/light-orchard.json +0 -0
  389. /package/src/modes/{interactive/theme → theme}/defaults/light-paper.json +0 -0
  390. /package/src/modes/{interactive/theme → theme}/defaults/light-prism.json +0 -0
  391. /package/src/modes/{interactive/theme → theme}/defaults/light-retro.json +0 -0
  392. /package/src/modes/{interactive/theme → theme}/defaults/light-sand.json +0 -0
  393. /package/src/modes/{interactive/theme → theme}/defaults/light-savanna.json +0 -0
  394. /package/src/modes/{interactive/theme → theme}/defaults/light-solarized.json +0 -0
  395. /package/src/modes/{interactive/theme → theme}/defaults/light-soleil.json +0 -0
  396. /package/src/modes/{interactive/theme → theme}/defaults/light-sunset.json +0 -0
  397. /package/src/modes/{interactive/theme → theme}/defaults/light-synthwave.json +0 -0
  398. /package/src/modes/{interactive/theme → theme}/defaults/light-tokyo-night.json +0 -0
  399. /package/src/modes/{interactive/theme → theme}/defaults/light-wetland.json +0 -0
  400. /package/src/modes/{interactive/theme → theme}/defaults/light-zenith.json +0 -0
  401. /package/src/modes/{interactive/theme → theme}/defaults/limestone.json +0 -0
  402. /package/src/modes/{interactive/theme → theme}/defaults/mahogany.json +0 -0
  403. /package/src/modes/{interactive/theme → theme}/defaults/marble.json +0 -0
  404. /package/src/modes/{interactive/theme → theme}/defaults/obsidian.json +0 -0
  405. /package/src/modes/{interactive/theme → theme}/defaults/onyx.json +0 -0
  406. /package/src/modes/{interactive/theme → theme}/defaults/pearl.json +0 -0
  407. /package/src/modes/{interactive/theme → theme}/defaults/porcelain.json +0 -0
  408. /package/src/modes/{interactive/theme → theme}/defaults/quartz.json +0 -0
  409. /package/src/modes/{interactive/theme → theme}/defaults/sandstone.json +0 -0
  410. /package/src/modes/{interactive/theme → theme}/defaults/titanium.json +0 -0
  411. /package/src/modes/{interactive/theme → theme}/light.json +0 -0
  412. /package/src/modes/{interactive/theme → theme}/theme-schema.json +0 -0
  413. /package/src/{core/tools/patch → patch}/fuzzy.ts +0 -0
  414. /package/src/{core/tools/patch → patch}/normalize.ts +0 -0
  415. /package/src/{core/tools/patch → patch}/normative.ts +0 -0
  416. /package/src/{core/tools/patch → patch}/parser.ts +0 -0
  417. /package/src/{core/tools/patch → patch}/types.ts +0 -0
  418. /package/src/{core → session}/compaction/index.ts +0 -0
  419. /package/src/{core → session}/session-storage.ts +0 -0
  420. /package/src/{core/tools/task → task}/name-generator.ts +0 -0
  421. /package/src/{core/tools/task → task}/omp-command.ts +0 -0
  422. /package/src/{core/tools/task → task}/parallel.ts +0 -0
  423. /package/src/{core/tools → tools}/jtd-to-json-schema.ts +0 -0
  424. /package/src/{core/tools → tools}/path-utils.ts +0 -0
  425. /package/src/{core → utils}/event-bus.ts +0 -0
  426. /package/src/{core → utils}/frontmatter.ts +0 -0
  427. /package/src/{core → utils}/terminal-notify.ts +0 -0
  428. /package/src/{core → utils}/timings.ts +0 -0
  429. /package/src/{core → utils}/utils.ts +0 -0
  430. /package/src/{core/tools/web-scrapers → web/scrapers}/artifacthub.ts +0 -0
  431. /package/src/{core/tools/web-scrapers → web/scrapers}/arxiv.ts +0 -0
  432. /package/src/{core/tools/web-scrapers → web/scrapers}/aur.ts +0 -0
  433. /package/src/{core/tools/web-scrapers → web/scrapers}/biorxiv.ts +0 -0
  434. /package/src/{core/tools/web-scrapers → web/scrapers}/bluesky.ts +0 -0
  435. /package/src/{core/tools/web-scrapers → web/scrapers}/brew.ts +0 -0
  436. /package/src/{core/tools/web-scrapers → web/scrapers}/cheatsh.ts +0 -0
  437. /package/src/{core/tools/web-scrapers → web/scrapers}/chocolatey.ts +0 -0
  438. /package/src/{core/tools/web-scrapers → web/scrapers}/cisa-kev.ts +0 -0
  439. /package/src/{core/tools/web-scrapers → web/scrapers}/clojars.ts +0 -0
  440. /package/src/{core/tools/web-scrapers → web/scrapers}/coingecko.ts +0 -0
  441. /package/src/{core/tools/web-scrapers → web/scrapers}/crates-io.ts +0 -0
  442. /package/src/{core/tools/web-scrapers → web/scrapers}/crossref.ts +0 -0
  443. /package/src/{core/tools/web-scrapers → web/scrapers}/devto.ts +0 -0
  444. /package/src/{core/tools/web-scrapers → web/scrapers}/discogs.ts +0 -0
  445. /package/src/{core/tools/web-scrapers → web/scrapers}/discourse.ts +0 -0
  446. /package/src/{core/tools/web-scrapers → web/scrapers}/dockerhub.ts +0 -0
  447. /package/src/{core/tools/web-scrapers → web/scrapers}/fdroid.ts +0 -0
  448. /package/src/{core/tools/web-scrapers → web/scrapers}/firefox-addons.ts +0 -0
  449. /package/src/{core/tools/web-scrapers → web/scrapers}/flathub.ts +0 -0
  450. /package/src/{core/tools/web-scrapers → web/scrapers}/github-gist.ts +0 -0
  451. /package/src/{core/tools/web-scrapers → web/scrapers}/github.ts +0 -0
  452. /package/src/{core/tools/web-scrapers → web/scrapers}/gitlab.ts +0 -0
  453. /package/src/{core/tools/web-scrapers → web/scrapers}/go-pkg.ts +0 -0
  454. /package/src/{core/tools/web-scrapers → web/scrapers}/hackage.ts +0 -0
  455. /package/src/{core/tools/web-scrapers → web/scrapers}/hackernews.ts +0 -0
  456. /package/src/{core/tools/web-scrapers → web/scrapers}/hex.ts +0 -0
  457. /package/src/{core/tools/web-scrapers → web/scrapers}/huggingface.ts +0 -0
  458. /package/src/{core/tools/web-scrapers → web/scrapers}/iacr.ts +0 -0
  459. /package/src/{core/tools/web-scrapers → web/scrapers}/index.ts +0 -0
  460. /package/src/{core/tools/web-scrapers → web/scrapers}/jetbrains-marketplace.ts +0 -0
  461. /package/src/{core/tools/web-scrapers → web/scrapers}/lemmy.ts +0 -0
  462. /package/src/{core/tools/web-scrapers → web/scrapers}/lobsters.ts +0 -0
  463. /package/src/{core/tools/web-scrapers → web/scrapers}/mastodon.ts +0 -0
  464. /package/src/{core/tools/web-scrapers → web/scrapers}/maven.ts +0 -0
  465. /package/src/{core/tools/web-scrapers → web/scrapers}/mdn.ts +0 -0
  466. /package/src/{core/tools/web-scrapers → web/scrapers}/metacpan.ts +0 -0
  467. /package/src/{core/tools/web-scrapers → web/scrapers}/musicbrainz.ts +0 -0
  468. /package/src/{core/tools/web-scrapers → web/scrapers}/npm.ts +0 -0
  469. /package/src/{core/tools/web-scrapers → web/scrapers}/nuget.ts +0 -0
  470. /package/src/{core/tools/web-scrapers → web/scrapers}/nvd.ts +0 -0
  471. /package/src/{core/tools/web-scrapers → web/scrapers}/ollama.ts +0 -0
  472. /package/src/{core/tools/web-scrapers → web/scrapers}/open-vsx.ts +0 -0
  473. /package/src/{core/tools/web-scrapers → web/scrapers}/opencorporates.ts +0 -0
  474. /package/src/{core/tools/web-scrapers → web/scrapers}/openlibrary.ts +0 -0
  475. /package/src/{core/tools/web-scrapers → web/scrapers}/orcid.ts +0 -0
  476. /package/src/{core/tools/web-scrapers → web/scrapers}/osv.ts +0 -0
  477. /package/src/{core/tools/web-scrapers → web/scrapers}/packagist.ts +0 -0
  478. /package/src/{core/tools/web-scrapers → web/scrapers}/pub-dev.ts +0 -0
  479. /package/src/{core/tools/web-scrapers → web/scrapers}/pubmed.ts +0 -0
  480. /package/src/{core/tools/web-scrapers → web/scrapers}/pypi.ts +0 -0
  481. /package/src/{core/tools/web-scrapers → web/scrapers}/rawg.ts +0 -0
  482. /package/src/{core/tools/web-scrapers → web/scrapers}/readthedocs.ts +0 -0
  483. /package/src/{core/tools/web-scrapers → web/scrapers}/reddit.ts +0 -0
  484. /package/src/{core/tools/web-scrapers → web/scrapers}/repology.ts +0 -0
  485. /package/src/{core/tools/web-scrapers → web/scrapers}/rfc.ts +0 -0
  486. /package/src/{core/tools/web-scrapers → web/scrapers}/rubygems.ts +0 -0
  487. /package/src/{core/tools/web-scrapers → web/scrapers}/searchcode.ts +0 -0
  488. /package/src/{core/tools/web-scrapers → web/scrapers}/sec-edgar.ts +0 -0
  489. /package/src/{core/tools/web-scrapers → web/scrapers}/semantic-scholar.ts +0 -0
  490. /package/src/{core/tools/web-scrapers → web/scrapers}/snapcraft.ts +0 -0
  491. /package/src/{core/tools/web-scrapers → web/scrapers}/sourcegraph.ts +0 -0
  492. /package/src/{core/tools/web-scrapers → web/scrapers}/spdx.ts +0 -0
  493. /package/src/{core/tools/web-scrapers → web/scrapers}/spotify.ts +0 -0
  494. /package/src/{core/tools/web-scrapers → web/scrapers}/stackoverflow.ts +0 -0
  495. /package/src/{core/tools/web-scrapers → web/scrapers}/terraform.ts +0 -0
  496. /package/src/{core/tools/web-scrapers → web/scrapers}/tldr.ts +0 -0
  497. /package/src/{core/tools/web-scrapers → web/scrapers}/vimeo.ts +0 -0
  498. /package/src/{core/tools/web-scrapers → web/scrapers}/vscode-marketplace.ts +0 -0
  499. /package/src/{core/tools/web-scrapers → web/scrapers}/w3c.ts +0 -0
  500. /package/src/{core/tools/web-scrapers → web/scrapers}/wikidata.ts +0 -0
  501. /package/src/{core/tools/web-scrapers → web/scrapers}/wikipedia.ts +0 -0
  502. /package/src/{core/tools/web-search → web/search}/types.ts +0 -0
@@ -0,0 +1,166 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { cp, mkdir, rm } from "node:fs/promises";
3
+ import { homedir, tmpdir } from "node:os";
4
+ import path from "node:path";
5
+ import { $ } from "bun";
6
+
7
+ export interface WorktreeBaseline {
8
+ repoRoot: string;
9
+ staged: string;
10
+ unstaged: string;
11
+ untracked: string[];
12
+ }
13
+
14
+ export function getEncodedProjectName(cwd: string): string {
15
+ return `--${cwd.replace(/^[/\\]/, "").replace(/[/\\:]/g, "-")}--`;
16
+ }
17
+
18
+ export async function getRepoRoot(cwd: string): Promise<string> {
19
+ const result = await $`git rev-parse --show-toplevel`.cwd(cwd).quiet().nothrow();
20
+ if (result.exitCode !== 0) {
21
+ throw new Error("Git repository not found for isolated task execution.");
22
+ }
23
+ const repoRoot = result.text().trim();
24
+ if (!repoRoot) {
25
+ throw new Error("Git repository root could not be resolved for isolated task execution.");
26
+ }
27
+ return repoRoot;
28
+ }
29
+
30
+ export async function ensureWorktree(baseCwd: string, id: string): Promise<string> {
31
+ const repoRoot = await getRepoRoot(baseCwd);
32
+ const encodedProject = getEncodedProjectName(repoRoot);
33
+ const worktreeDir = path.join(homedir(), ".omp", "wt", encodedProject, id);
34
+ await mkdir(path.dirname(worktreeDir), { recursive: true });
35
+ await $`git worktree remove -f ${worktreeDir}`.cwd(repoRoot).quiet().nothrow();
36
+ await rm(worktreeDir, { recursive: true, force: true });
37
+ await $`git worktree add --detach ${worktreeDir} HEAD`.cwd(repoRoot).quiet();
38
+ return worktreeDir;
39
+ }
40
+
41
+ export async function captureBaseline(repoRoot: string): Promise<WorktreeBaseline> {
42
+ const staged = await $`git diff --cached --binary`.cwd(repoRoot).quiet().text();
43
+ const unstaged = await $`git diff --binary`.cwd(repoRoot).quiet().text();
44
+ const untrackedRaw = await $`git ls-files --others --exclude-standard`.cwd(repoRoot).quiet().text();
45
+ const untracked = untrackedRaw
46
+ .split("\n")
47
+ .map((line) => line.trim())
48
+ .filter((line) => line.length > 0);
49
+
50
+ return {
51
+ repoRoot,
52
+ staged,
53
+ unstaged,
54
+ untracked,
55
+ };
56
+ }
57
+
58
+ async function writeTempPatchFile(patch: string): Promise<string> {
59
+ const tempPath = path.join(tmpdir(), `omp-task-patch-${randomUUID()}.patch`);
60
+ await Bun.write(tempPath, patch);
61
+ return tempPath;
62
+ }
63
+
64
+ async function applyPatch(
65
+ cwd: string,
66
+ patch: string,
67
+ options?: { cached?: boolean; env?: Record<string, string> },
68
+ ): Promise<void> {
69
+ if (!patch.trim()) return;
70
+ const tempPath = await writeTempPatchFile(patch);
71
+ try {
72
+ const command = options?.cached ? $`git apply --cached --binary ${tempPath}` : $`git apply --binary ${tempPath}`;
73
+ let runner = command.cwd(cwd).quiet();
74
+ if (options?.env) {
75
+ runner = runner.env(options.env);
76
+ }
77
+ await runner;
78
+ } finally {
79
+ await rm(tempPath, { force: true });
80
+ }
81
+ }
82
+
83
+ export async function applyBaseline(worktreeDir: string, baseline: WorktreeBaseline): Promise<void> {
84
+ await applyPatch(worktreeDir, baseline.staged, { cached: true });
85
+ await applyPatch(worktreeDir, baseline.staged);
86
+ await applyPatch(worktreeDir, baseline.unstaged);
87
+
88
+ for (const entry of baseline.untracked) {
89
+ const source = path.join(baseline.repoRoot, entry);
90
+ const destination = path.join(worktreeDir, entry);
91
+ const exists = await Bun.file(source).exists();
92
+ if (!exists) continue;
93
+ await mkdir(path.dirname(destination), { recursive: true });
94
+ await cp(source, destination, { recursive: true });
95
+ }
96
+ }
97
+
98
+ async function applyPatchToIndex(cwd: string, patch: string, indexFile: string): Promise<void> {
99
+ if (!patch.trim()) return;
100
+ const tempPath = await writeTempPatchFile(patch);
101
+ try {
102
+ await $`git apply --cached --binary ${tempPath}`
103
+ .cwd(cwd)
104
+ .env({
105
+ GIT_INDEX_FILE: indexFile,
106
+ })
107
+ .quiet();
108
+ } finally {
109
+ await rm(tempPath, { force: true });
110
+ }
111
+ }
112
+
113
+ async function listUntracked(cwd: string): Promise<string[]> {
114
+ const raw = await $`git ls-files --others --exclude-standard`.cwd(cwd).quiet().text();
115
+ return raw
116
+ .split("\n")
117
+ .map((line) => line.trim())
118
+ .filter((line) => line.length > 0);
119
+ }
120
+
121
+ export async function captureDeltaPatch(worktreeDir: string, baseline: WorktreeBaseline): Promise<string> {
122
+ const tempIndex = path.join(tmpdir(), `omp-task-index-${randomUUID()}`);
123
+ try {
124
+ await $`git read-tree HEAD`.cwd(worktreeDir).env({
125
+ GIT_INDEX_FILE: tempIndex,
126
+ });
127
+ await applyPatchToIndex(worktreeDir, baseline.staged, tempIndex);
128
+ await applyPatchToIndex(worktreeDir, baseline.unstaged, tempIndex);
129
+ const diff = await $`git diff --binary`
130
+ .cwd(worktreeDir)
131
+ .env({
132
+ GIT_INDEX_FILE: tempIndex,
133
+ })
134
+ .quiet()
135
+ .text();
136
+
137
+ const currentUntracked = await listUntracked(worktreeDir);
138
+ const baselineUntracked = new Set(baseline.untracked);
139
+ const newUntracked = currentUntracked.filter((entry) => !baselineUntracked.has(entry));
140
+
141
+ if (newUntracked.length === 0) return diff;
142
+
143
+ const untrackedDiffs = await Promise.all(
144
+ newUntracked.map((entry) =>
145
+ $`git diff --binary --no-index /dev/null ${entry}`.cwd(worktreeDir).quiet().nothrow().text(),
146
+ ),
147
+ );
148
+ return `${diff}${diff && !diff.endsWith("\n") ? "\n" : ""}${untrackedDiffs.join("\n")}`;
149
+ } finally {
150
+ await rm(tempIndex, { force: true });
151
+ }
152
+ }
153
+
154
+ export async function cleanupWorktree(dir: string): Promise<void> {
155
+ try {
156
+ const commonDirRaw = await $`git rev-parse --git-common-dir`.cwd(dir).quiet().nothrow().text();
157
+ const commonDir = commonDirRaw.trim();
158
+ if (commonDir) {
159
+ const resolvedCommon = path.resolve(dir, commonDir);
160
+ const repoRoot = path.dirname(resolvedCommon);
161
+ await $`git worktree remove -f ${dir}`.cwd(repoRoot).quiet().nothrow();
162
+ }
163
+ } finally {
164
+ await rm(dir, { recursive: true, force: true });
165
+ }
166
+ }
@@ -19,10 +19,10 @@ import type { AgentTool, AgentToolContext, AgentToolResult, AgentToolUpdateCallb
19
19
  import type { Component } from "@oh-my-pi/pi-tui";
20
20
  import { Text } from "@oh-my-pi/pi-tui";
21
21
  import { Type } from "@sinclair/typebox";
22
- import { type Theme, theme } from "../../modes/interactive/theme/theme";
23
- import askDescription from "../../prompts/tools/ask.md" with { type: "text" };
24
- import type { RenderResultOptions } from "../custom-tools/types";
25
- import { renderPromptTemplate } from "../prompt-templates";
22
+ import { renderPromptTemplate } from "$c/config/prompt-templates";
23
+ import type { RenderResultOptions } from "$c/extensibility/custom-tools/types";
24
+ import { type Theme, theme } from "$c/modes/theme/theme";
25
+ import askDescription from "$c/prompts/tools/ask.md" with { type: "text" };
26
26
  import type { ToolSession } from "./index";
27
27
  import { ToolUIKit } from "./render-utils";
28
28
 
@@ -31,29 +31,21 @@ import { ToolUIKit } from "./render-utils";
31
31
  // =============================================================================
32
32
 
33
33
  const OptionItem = Type.Object({
34
- label: Type.String({ description: "Display label for this option" }),
34
+ label: Type.String({ description: "Display label" }),
35
35
  });
36
36
 
37
37
  const QuestionItem = Type.Object({
38
- id: Type.String({ description: "Short identifier for this question (e.g., 'auth', 'cache')" }),
39
- question: Type.String({ description: "The question text" }),
40
- options: Type.Array(OptionItem, { description: "Options for this question" }),
41
- multi: Type.Optional(Type.Boolean({ description: "Allow multiple selections for this question" })),
38
+ id: Type.String({ description: "Question ID, e.g. 'auth', 'cache'" }),
39
+ question: Type.String({ description: "Question text" }),
40
+ options: Type.Array(OptionItem, { description: "Available options" }),
41
+ multi: Type.Optional(Type.Boolean({ description: "Allow multiple selections" })),
42
42
  });
43
43
 
44
44
  const askSchema = Type.Object({
45
- question: Type.Optional(Type.String({ description: "The question to ask the user" })),
46
- options: Type.Optional(Type.Array(OptionItem, { description: "Available options for the user to choose from." })),
47
- multi: Type.Optional(
48
- Type.Boolean({
49
- description: "Allow multiple options to be selected (default: false)",
50
- }),
51
- ),
52
- questions: Type.Optional(
53
- Type.Array(QuestionItem, {
54
- description: "Multiple questions to ask in sequence, each with their own options",
55
- }),
56
- ),
45
+ question: Type.Optional(Type.String({ description: "Question to ask" })),
46
+ options: Type.Optional(Type.Array(OptionItem, { description: "Available options" })),
47
+ multi: Type.Optional(Type.Boolean({ description: "Allow multiple selections (default: false)" })),
48
+ questions: Type.Optional(Type.Array(QuestionItem, { description: "Multiple questions in sequence" })),
57
49
  });
58
50
 
59
51
  /** Result for a single question */
@@ -6,7 +6,7 @@
6
6
  * the specialized tools instead.
7
7
  */
8
8
 
9
- import { type BashInterceptorRule, DEFAULT_BASH_INTERCEPTOR_RULES } from "../settings-manager";
9
+ import { type BashInterceptorRule, DEFAULT_BASH_INTERCEPTOR_RULES } from "$c/config/settings-manager";
10
10
 
11
11
  export interface InterceptionResult {
12
12
  /** If true, the bash command should be blocked */
@@ -3,30 +3,33 @@ import type { AgentTool, AgentToolContext, AgentToolResult, AgentToolUpdateCallb
3
3
  import type { Component } from "@oh-my-pi/pi-tui";
4
4
  import { Text, truncateToWidth } from "@oh-my-pi/pi-tui";
5
5
  import { Type } from "@sinclair/typebox";
6
- import { truncateToVisualLines } from "../../modes/interactive/components/visual-truncate";
7
- import type { Theme } from "../../modes/interactive/theme/theme";
8
- import bashDescription from "../../prompts/tools/bash.md" with { type: "text" };
9
- import { type BashExecutorOptions, executeBash } from "../bash-executor";
10
- import type { RenderResultOptions } from "../custom-tools/types";
11
- import { renderPromptTemplate } from "../prompt-templates";
6
+ import { renderPromptTemplate } from "$c/config/prompt-templates";
7
+ import { type BashExecutorOptions, executeBash } from "$c/exec/bash-executor";
8
+ import type { RenderResultOptions } from "$c/extensibility/custom-tools/types";
9
+ import { truncateToVisualLines } from "$c/modes/components/visual-truncate";
10
+ import type { Theme } from "$c/modes/theme/theme";
11
+ import bashDescription from "$c/prompts/tools/bash.md" with { type: "text" };
12
+ import type { OutputMeta } from "$c/tools/output-meta";
13
+ import { ToolError } from "$c/tools/tool-errors";
14
+
12
15
  import { checkBashInterception, checkSimpleLsInterception } from "./bash-interceptor";
13
16
  import type { ToolSession } from "./index";
17
+ import { allocateOutputArtifact, createTailBuffer } from "./output-utils";
14
18
  import { resolveToCwd } from "./path-utils";
15
19
  import { ToolUIKit } from "./render-utils";
16
- import { formatTailTruncationNotice, type TruncationResult, truncateTail } from "./truncate";
20
+ import { toolResult } from "./tool-result";
21
+ import { DEFAULT_MAX_BYTES } from "./truncate";
17
22
 
18
23
  export const BASH_DEFAULT_PREVIEW_LINES = 10;
19
24
 
20
25
  const bashSchema = Type.Object({
21
- command: Type.String({ description: "Bash command to execute" }),
22
- timeout: Type.Optional(Type.Number({ description: "Timeout in seconds (optional, no default timeout)" })),
23
- cwd: Type.Optional(Type.String({ description: "Working directory for the command (default: current directory)" })),
26
+ command: Type.String({ description: "Command to execute" }),
27
+ timeout: Type.Optional(Type.Number({ description: "Timeout in seconds (default: 300)" })),
28
+ cwd: Type.Optional(Type.String({ description: "Working directory (default: cwd)" })),
24
29
  });
25
30
 
26
31
  export interface BashToolDetails {
27
- truncation?: TruncationResult;
28
- fullOutputPath?: string;
29
- fullOutput?: string;
32
+ meta?: OutputMeta;
30
33
  }
31
34
 
32
35
  export interface BashToolOptions {}
@@ -51,7 +54,7 @@ export class BashTool implements AgentTool<typeof bashSchema, BashToolDetails> {
51
54
 
52
55
  public async execute(
53
56
  _toolCallId: string,
54
- { command, timeout, cwd }: { command: string; timeout?: number; cwd?: string },
57
+ { command, timeout: rawTimeout = 300, cwd }: { command: string; timeout?: number; cwd?: string },
55
58
  signal?: AbortSignal,
56
59
  onUpdate?: AgentToolUpdateCallback<BashToolDetails>,
57
60
  ctx?: AgentToolContext,
@@ -61,12 +64,12 @@ export class BashTool implements AgentTool<typeof bashSchema, BashToolDetails> {
61
64
  const rules = this.session.settings?.getBashInterceptorRules?.();
62
65
  const interception = checkBashInterception(command, ctx?.toolNames ?? [], rules);
63
66
  if (interception.block) {
64
- throw new Error(interception.message);
67
+ throw new ToolError(interception.message ?? "Command blocked");
65
68
  }
66
69
  if (this.session.settings?.getBashInterceptorSimpleLsEnabled?.() !== false) {
67
70
  const lsInterception = checkSimpleLsInterception(command, ctx?.toolNames ?? []);
68
71
  if (lsInterception.block) {
69
- throw new Error(lsInterception.message);
72
+ throw new ToolError(lsInterception.message ?? "Command blocked");
70
73
  }
71
74
  }
72
75
  }
@@ -76,26 +79,39 @@ export class BashTool implements AgentTool<typeof bashSchema, BashToolDetails> {
76
79
  try {
77
80
  cwdStat = await Bun.file(commandCwd).stat();
78
81
  } catch {
79
- throw new Error(`Working directory does not exist: ${commandCwd}`);
82
+ throw new ToolError(`Working directory does not exist: ${commandCwd}`);
80
83
  }
81
84
  if (!cwdStat.isDirectory()) {
82
- throw new Error(`Working directory is not a directory: ${commandCwd}`);
85
+ throw new ToolError(`Working directory is not a directory: ${commandCwd}`);
83
86
  }
84
87
 
85
- // Track output for streaming updates
86
- let currentOutput = "";
88
+ // Auto-convert milliseconds to seconds if value > 1000 (16+ min is unreasonable)
89
+ let timeoutSec = rawTimeout > 1000 ? rawTimeout / 1000 : rawTimeout;
90
+ // Clamp to reasonable range: 1s - 3600s (1 hour)
91
+ timeoutSec = Math.max(1, Math.min(3600, timeoutSec));
92
+ const timeoutMs = timeoutSec * 1000;
93
+
94
+ // Track output for streaming updates (tail only)
95
+ const tailBuffer = createTailBuffer(DEFAULT_MAX_BYTES);
96
+
97
+ // Set up artifacts environment and allocation
98
+ const artifactsDir = this.session.getArtifactsDir?.();
99
+ const extraEnv = artifactsDir ? { ARTIFACTS: artifactsDir } : undefined;
100
+ const { artifactPath, artifactId } = await allocateOutputArtifact(this.session, "bash");
87
101
 
88
102
  const executorOptions: BashExecutorOptions = {
89
103
  cwd: commandCwd,
90
- timeout: timeout ? timeout * 1000 : undefined, // Convert to milliseconds
104
+ timeout: timeoutMs,
91
105
  signal,
106
+ env: extraEnv,
107
+ artifactPath,
108
+ artifactId,
92
109
  onChunk: (chunk) => {
93
- currentOutput += chunk;
110
+ tailBuffer.append(chunk);
94
111
  if (onUpdate) {
95
- const truncation = truncateTail(currentOutput);
96
112
  onUpdate({
97
- content: [{ type: "text", text: truncation.content || "" }],
98
- details: truncation.truncated ? { truncation, fullOutput: currentOutput } : {},
113
+ content: [{ type: "text", text: tailBuffer.text() }],
114
+ details: {},
99
115
  });
100
116
  }
101
117
  },
@@ -104,33 +120,18 @@ export class BashTool implements AgentTool<typeof bashSchema, BashToolDetails> {
104
120
  // Handle errors
105
121
  const result = await executeBash(command, executorOptions);
106
122
  if (result.cancelled) {
107
- throw new Error(result.output || "Command aborted");
123
+ throw new ToolError(result.output || "Command aborted");
108
124
  }
109
125
 
110
- // Apply tail truncation for final output
111
- const truncation = truncateTail(result.output);
112
- let outputText = truncation.content || "(no output)";
113
-
114
- let details: BashToolDetails | undefined;
115
-
116
- if (truncation.truncated) {
117
- details = {
118
- truncation,
119
- fullOutputPath: result.fullOutputPath,
120
- fullOutput: currentOutput,
121
- };
122
- outputText += formatTailTruncationNotice(truncation, {
123
- fullOutputPath: result.fullOutputPath,
124
- originalContent: result.output,
125
- });
126
- }
126
+ const outputText = result.output || "(no output)";
127
+ const details: BashToolDetails = {};
128
+ const resultBuilder = toolResult(details).text(outputText).truncationFromSummary(result, { direction: "tail" });
127
129
 
128
130
  if (result.exitCode !== 0 && result.exitCode !== undefined) {
129
- outputText += `\n\nCommand exited with code ${result.exitCode}`;
130
- throw new Error(outputText);
131
+ throw new ToolError(`${outputText}\n\nCommand exited with code ${result.exitCode}`);
131
132
  }
132
133
 
133
- return { content: [{ type: "text", text: outputText }], details };
134
+ return resultBuilder.done();
134
135
  }
135
136
  }
136
137
 
@@ -147,6 +148,8 @@ interface BashRenderArgs {
147
148
  interface BashRenderContext {
148
149
  /** Raw output text */
149
150
  output?: string;
151
+ /** Whether output came from artifact storage */
152
+ isFullOutput?: boolean;
150
153
  /** Whether output is expanded */
151
154
  expanded?: boolean;
152
155
  /** Number of preview lines when collapsed */
@@ -198,38 +201,33 @@ export const bashToolRenderer = {
198
201
  const ui = new ToolUIKit(uiTheme);
199
202
  const { renderContext } = options;
200
203
  const details = result.details;
201
-
202
204
  const expanded = renderContext?.expanded ?? options.expanded;
203
205
  const previewLines = renderContext?.previewLines ?? BASH_DEFAULT_PREVIEW_LINES;
204
206
 
205
207
  // Get output from context (preferred) or fall back to result content
206
208
  const output = renderContext?.output ?? (result.content?.find((c) => c.type === "text")?.text ?? "").trim();
207
- const fullOutput = details?.fullOutput;
208
- const displayOutput = expanded ? (fullOutput ?? output) : output;
209
- const showingFullOutput = expanded && fullOutput !== undefined;
209
+ const displayOutput = output;
210
+ const showingFullOutput = expanded && renderContext?.isFullOutput === true;
210
211
 
211
212
  // Build truncation warning lines (static, doesn't depend on width)
212
- const truncation = details?.truncation;
213
- const fullOutputPath = details?.fullOutputPath;
213
+ const truncation = details?.meta?.truncation;
214
214
  const timeoutSeconds = renderContext?.timeout;
215
215
  const timeoutLine =
216
216
  typeof timeoutSeconds === "number"
217
217
  ? uiTheme.fg("dim", ui.wrapBrackets(`Timeout: ${timeoutSeconds}s`))
218
218
  : undefined;
219
219
  let warningLine: string | undefined;
220
- if (fullOutputPath || (truncation?.truncated && !showingFullOutput)) {
220
+ if (truncation && !showingFullOutput) {
221
221
  const warnings: string[] = [];
222
- if (fullOutputPath) {
223
- warnings.push(`Full output: ${fullOutputPath}`);
222
+ if (truncation?.artifactId) {
223
+ warnings.push(`Full output: artifact://${truncation.artifactId}`);
224
224
  }
225
- if (truncation?.truncated && !showingFullOutput) {
226
- if (truncation.truncatedBy === "lines") {
227
- warnings.push(`Truncated: showing ${truncation.outputLines} of ${truncation.totalLines} lines`);
228
- } else {
229
- warnings.push(
230
- `Truncated: ${truncation.outputLines} lines shown (${ui.formatBytes(truncation.maxBytes)} limit)`,
231
- );
232
- }
225
+ if (truncation.truncatedBy === "lines") {
226
+ warnings.push(`Truncated: showing ${truncation.outputLines} of ${truncation.totalLines} lines`);
227
+ } else {
228
+ warnings.push(
229
+ `Truncated: ${truncation.outputLines} lines shown (${ui.formatBytes(truncation.outputBytes)} limit)`,
230
+ );
233
231
  }
234
232
  if (warnings.length > 0) {
235
233
  warningLine = uiTheme.fg("warning", ui.wrapBrackets(warnings.join(". ")));
@@ -3,10 +3,10 @@ import type { Component } from "@oh-my-pi/pi-tui";
3
3
  import { Text } from "@oh-my-pi/pi-tui";
4
4
  import { untilAborted } from "@oh-my-pi/pi-utils";
5
5
  import { Type } from "@sinclair/typebox";
6
- import type { Theme } from "../../modes/interactive/theme/theme";
7
- import calculatorDescription from "../../prompts/tools/calculator.md" with { type: "text" };
8
- import type { RenderResultOptions } from "../custom-tools/types";
9
- import { renderPromptTemplate } from "../prompt-templates";
6
+ import { renderPromptTemplate } from "$c/config/prompt-templates";
7
+ import type { RenderResultOptions } from "$c/extensibility/custom-tools/types";
8
+ import type { Theme } from "$c/modes/theme/theme";
9
+ import calculatorDescription from "$c/prompts/tools/calculator.md" with { type: "text" };
10
10
  import type { ToolSession } from "./index";
11
11
  import {
12
12
  formatCount,
@@ -9,9 +9,9 @@ import { StringEnum } from "@oh-my-pi/pi-ai";
9
9
  import type { Static, TObject } from "@sinclair/typebox";
10
10
  import { Type } from "@sinclair/typebox";
11
11
  import Ajv, { type ErrorObject, type ValidateFunction } from "ajv";
12
+ import { subprocessToolRegistry } from "$c/task/subprocess-tool-registry";
12
13
  import type { ToolSession } from "./index";
13
14
  import { jtdToJsonSchema } from "./jtd-to-json-schema";
14
- import { subprocessToolRegistry } from "./task/subprocess-tool-registry";
15
15
 
16
16
  export interface CompleteDetails {
17
17
  data: unknown;
@@ -1,6 +1,6 @@
1
1
  import type { AgentToolContext, ToolCallContext } from "@oh-my-pi/pi-agent-core";
2
- import type { CustomToolContext } from "../custom-tools/types";
3
- import type { ExtensionUIContext } from "../extensions/types";
2
+ import type { CustomToolContext } from "$c/extensibility/custom-tools/types";
3
+ import type { ExtensionUIContext } from "$c/extensibility/extensions/types";
4
4
 
5
5
  declare module "@oh-my-pi/pi-agent-core" {
6
6
  interface AgentToolContext extends CustomToolContext {