@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
@@ -6,7 +6,7 @@
6
6
  */
7
7
 
8
8
  import { homedir } from "node:os";
9
- import type { Theme } from "../../modes/interactive/theme/theme";
9
+ import type { Theme } from "$c/modes/theme/theme";
10
10
 
11
11
  // =============================================================================
12
12
  // Standardized Display Constants
@@ -5,25 +5,24 @@
5
5
  */
6
6
 
7
7
  import type { Component } from "@oh-my-pi/pi-tui";
8
- import type { Theme } from "../../modes/interactive/theme/theme";
9
- import type { RenderResultOptions } from "../custom-tools/types";
8
+ import type { RenderResultOptions } from "$c/extensibility/custom-tools/types";
9
+ import { lspToolRenderer } from "$c/lsp/render";
10
+ import type { Theme } from "$c/modes/theme/theme";
11
+ import { editToolRenderer } from "$c/patch";
12
+ import { taskToolRenderer } from "$c/task/render";
13
+ import { webSearchToolRenderer } from "$c/web/search/render";
10
14
  import { askToolRenderer } from "./ask";
11
15
  import { bashToolRenderer } from "./bash";
12
16
  import { calculatorToolRenderer } from "./calculator";
17
+ import { fetchToolRenderer } from "./fetch";
13
18
  import { findToolRenderer } from "./find";
14
19
  import { grepToolRenderer } from "./grep";
15
20
  import { lsToolRenderer } from "./ls";
16
- import { lspToolRenderer } from "./lsp/render";
17
21
  import { notebookToolRenderer } from "./notebook";
18
- import { outputToolRenderer } from "./output";
19
- import { editToolRenderer } from "./patch";
20
22
  import { pythonToolRenderer } from "./python";
21
23
  import { readToolRenderer } from "./read";
22
24
  import { sshToolRenderer } from "./ssh";
23
- import { taskToolRenderer } from "./task/render";
24
25
  import { todoWriteToolRenderer } from "./todo-write";
25
- import { webFetchToolRenderer } from "./web-fetch";
26
- import { webSearchToolRenderer } from "./web-search/render";
27
26
  import { writeToolRenderer } from "./write";
28
27
 
29
28
  export interface RenderCallOptions {
@@ -54,12 +53,11 @@ export const toolRenderers: Record<string, ToolRenderer> = {
54
53
  ls: lsToolRenderer as ToolRenderer,
55
54
  lsp: lspToolRenderer as ToolRenderer,
56
55
  notebook: notebookToolRenderer as ToolRenderer,
57
- output: outputToolRenderer as ToolRenderer,
58
56
  read: readToolRenderer as ToolRenderer,
59
57
  ssh: sshToolRenderer as ToolRenderer,
60
58
  task: taskToolRenderer as ToolRenderer,
61
59
  todo_write: todoWriteToolRenderer as ToolRenderer,
62
- web_fetch: webFetchToolRenderer as ToolRenderer,
60
+ fetch: fetchToolRenderer as ToolRenderer,
63
61
  web_search: webSearchToolRenderer as ToolRenderer,
64
62
  write: writeToolRenderer as ToolRenderer,
65
63
  };
@@ -10,7 +10,7 @@ import type { AgentTool } from "@oh-my-pi/pi-agent-core";
10
10
  import type { Component } from "@oh-my-pi/pi-tui";
11
11
  import { Container, Text } from "@oh-my-pi/pi-tui";
12
12
  import { Type } from "@sinclair/typebox";
13
- import type { Theme, ThemeColor } from "../../modes/interactive/theme/theme";
13
+ import type { Theme, ThemeColor } from "$c/modes/theme/theme";
14
14
 
15
15
  export type FindingPriority = "P0" | "P1" | "P2" | "P3";
16
16
 
@@ -151,7 +151,7 @@ export type { ReportFindingDetails };
151
151
 
152
152
  import path from "node:path";
153
153
  import { StringEnum } from "@oh-my-pi/pi-ai";
154
- import { subprocessToolRegistry } from "./task/subprocess-tool-registry";
154
+ import { subprocessToolRegistry } from "$c/task/subprocess-tool-registry";
155
155
 
156
156
  // Register report_finding handler
157
157
  subprocessToolRegistry.register<ReportFindingDetails>("report_finding", {
@@ -2,30 +2,33 @@ import type { AgentTool, AgentToolContext, AgentToolResult, AgentToolUpdateCallb
2
2
  import type { Component } from "@oh-my-pi/pi-tui";
3
3
  import { Text } from "@oh-my-pi/pi-tui";
4
4
  import { Type } from "@sinclair/typebox";
5
- import type { SSHHost } from "../../capability/ssh";
6
- import { sshCapability } from "../../capability/ssh";
7
- import { loadCapability } from "../../discovery/index";
8
- import type { Theme } from "../../modes/interactive/theme/theme";
9
- import sshDescriptionBase from "../../prompts/tools/ssh.md" with { type: "text" };
10
- import type { RenderResultOptions } from "../custom-tools/types";
11
- import { renderPromptTemplate } from "../prompt-templates";
12
- import type { SSHHostInfo } from "../ssh/connection-manager";
13
- import { ensureHostInfo, getHostInfoForHost } from "../ssh/connection-manager";
14
- import { executeSSH } from "../ssh/ssh-executor";
5
+ import type { SSHHost } from "$c/capability/ssh";
6
+ import { sshCapability } from "$c/capability/ssh";
7
+ import { renderPromptTemplate } from "$c/config/prompt-templates";
8
+ import { loadCapability } from "$c/discovery/index";
9
+ import type { RenderResultOptions } from "$c/extensibility/custom-tools/types";
10
+ import type { Theme } from "$c/modes/theme/theme";
11
+ import sshDescriptionBase from "$c/prompts/tools/ssh.md" with { type: "text" };
12
+ import type { SSHHostInfo } from "$c/ssh/connection-manager";
13
+ import { ensureHostInfo, getHostInfoForHost } from "$c/ssh/connection-manager";
14
+ import { executeSSH } from "$c/ssh/ssh-executor";
15
+ import type { OutputMeta } from "$c/tools/output-meta";
16
+ import { ToolError } from "$c/tools/tool-errors";
15
17
  import type { ToolSession } from "./index";
18
+ import { allocateOutputArtifact, createTailBuffer } from "./output-utils";
16
19
  import { ToolUIKit } from "./render-utils";
17
- import { formatTailTruncationNotice, type TruncationResult, truncateTail } from "./truncate";
20
+ import { toolResult } from "./tool-result";
21
+ import { DEFAULT_MAX_BYTES } from "./truncate";
18
22
 
19
23
  const sshSchema = Type.Object({
20
24
  host: Type.String({ description: "Host name from ssh.json or .ssh.json" }),
21
25
  command: Type.String({ description: "Command to execute on the remote host" }),
22
26
  cwd: Type.Optional(Type.String({ description: "Remote working directory (optional)" })),
23
- timeout: Type.Optional(Type.Number({ description: "Timeout in seconds (optional, no default timeout)" })),
27
+ timeout: Type.Optional(Type.Number({ description: "Timeout in seconds (default: 60)" })),
24
28
  });
25
29
 
26
30
  export interface SSHToolDetails {
27
- truncation?: TruncationResult;
28
- fullOutputPath?: string;
31
+ meta?: OutputMeta;
29
32
  }
30
33
 
31
34
  function formatHostEntry(host: SSHHost): string {
@@ -125,11 +128,14 @@ export class SshTool implements AgentTool<typeof sshSchema, SSHToolDetails> {
125
128
  public readonly description: string;
126
129
  public readonly parameters = sshSchema;
127
130
 
131
+ private readonly session: ToolSession;
132
+
128
133
  private readonly allowedHosts: Set<string>;
129
134
  private readonly hostsByName: Map<string, SSHHost>;
130
135
  private readonly hostNames: string[];
131
136
 
132
- constructor(hostNames: string[], hostsByName: Map<string, SSHHost>) {
137
+ constructor(session: ToolSession, hostNames: string[], hostsByName: Map<string, SSHHost>) {
138
+ this.session = session;
133
139
  this.hostNames = hostNames;
134
140
  this.hostsByName = hostsByName;
135
141
  this.allowedHosts = new Set(hostNames);
@@ -143,68 +149,62 @@ export class SshTool implements AgentTool<typeof sshSchema, SSHToolDetails> {
143
149
 
144
150
  public async execute(
145
151
  _toolCallId: string,
146
- { host, command, cwd, timeout }: SshToolParams,
152
+ { host, command, cwd, timeout: rawTimeout = 60 }: SshToolParams,
147
153
  signal?: AbortSignal,
148
154
  onUpdate?: AgentToolUpdateCallback<SSHToolDetails>,
149
155
  _ctx?: AgentToolContext,
150
156
  ): Promise<AgentToolResult<SSHToolDetails>> {
151
157
  if (!this.allowedHosts.has(host)) {
152
- throw new Error(`Unknown SSH host: ${host}. Available hosts: ${this.hostNames.join(", ")}`);
158
+ throw new ToolError(`Unknown SSH host: ${host}. Available hosts: ${this.hostNames.join(", ")}`);
153
159
  }
154
160
 
155
161
  const hostConfig = this.hostsByName.get(host);
156
162
  if (!hostConfig) {
157
- throw new Error(`SSH host not loaded: ${host}`);
163
+ throw new ToolError(`SSH host not loaded: ${host}`);
158
164
  }
159
165
 
160
166
  const hostInfo = await ensureHostInfo(hostConfig);
161
167
  const remoteCommand = buildRemoteCommand(command, cwd, hostInfo);
162
- let currentOutput = "";
168
+
169
+ // Auto-convert milliseconds to seconds if value > 1000 (16+ min is unreasonable)
170
+ let timeoutSec = rawTimeout > 1000 ? rawTimeout / 1000 : rawTimeout;
171
+ // Clamp to reasonable range: 1s - 3600s (1 hour)
172
+ timeoutSec = Math.max(1, Math.min(3600, timeoutSec));
173
+ const timeoutMs = timeoutSec * 1000;
174
+
175
+ const tailBuffer = createTailBuffer(DEFAULT_MAX_BYTES);
176
+ const { artifactPath, artifactId } = await allocateOutputArtifact(this.session, "ssh");
163
177
 
164
178
  const result = await executeSSH(hostConfig, remoteCommand, {
165
- timeout: timeout ? timeout * 1000 : undefined,
179
+ timeout: timeoutMs,
166
180
  signal,
167
181
  compatEnabled: hostInfo.compatEnabled,
182
+ artifactPath,
183
+ artifactId,
168
184
  onChunk: (chunk) => {
169
- currentOutput += chunk;
185
+ tailBuffer.append(chunk);
170
186
  if (onUpdate) {
171
- const truncation = truncateTail(currentOutput);
172
187
  onUpdate({
173
- content: [{ type: "text", text: truncation.content || "" }],
174
- details: {
175
- truncation: truncation.truncated ? truncation : undefined,
176
- },
188
+ content: [{ type: "text", text: tailBuffer.text() }],
189
+ details: {},
177
190
  });
178
191
  }
179
192
  },
180
193
  });
181
194
 
182
195
  if (result.cancelled) {
183
- throw new Error(result.output || "Command aborted");
196
+ throw new ToolError(result.output || "Command aborted");
184
197
  }
185
198
 
186
- const truncation = truncateTail(result.output);
187
- let outputText = truncation.content || "(no output)";
188
-
189
- let details: SSHToolDetails | undefined;
190
-
191
- if (truncation.truncated) {
192
- details = {
193
- truncation,
194
- fullOutputPath: result.fullOutputPath,
195
- };
196
- outputText += formatTailTruncationNotice(truncation, {
197
- fullOutputPath: result.fullOutputPath,
198
- originalContent: result.output,
199
- });
200
- }
199
+ const outputText = result.output || "(no output)";
200
+ const details: SSHToolDetails = {};
201
+ const resultBuilder = toolResult(details).text(outputText).truncationFromSummary(result, { direction: "tail" });
201
202
 
202
203
  if (result.exitCode !== 0 && result.exitCode !== undefined) {
203
- outputText += `\n\nCommand exited with code ${result.exitCode}`;
204
- throw new Error(outputText);
204
+ throw new ToolError(`${outputText}\n\nCommand exited with code ${result.exitCode}`);
205
205
  }
206
206
 
207
- return { content: [{ type: "text", text: outputText }], details: details ?? {} };
207
+ return resultBuilder.done();
208
208
  }
209
209
  }
210
210
 
@@ -213,7 +213,7 @@ export async function loadSshTool(session: ToolSession): Promise<SshTool | null>
213
213
  if (hostNames.length === 0) {
214
214
  return null;
215
215
  }
216
- return new SshTool(hostNames, hostsByName);
216
+ return new SshTool(session, hostNames, hostsByName);
217
217
  }
218
218
 
219
219
  // =============================================================================
@@ -291,21 +291,18 @@ export const sshToolRenderer = {
291
291
  }
292
292
  }
293
293
 
294
- const truncation = details?.truncation;
295
- const fullOutputPath = details?.fullOutputPath;
296
- if (truncation?.truncated || fullOutputPath) {
294
+ const truncation = details?.meta?.truncation;
295
+ if (truncation) {
297
296
  const warnings: string[] = [];
298
- if (fullOutputPath) {
299
- warnings.push(`Full output: ${fullOutputPath}`);
297
+ if (truncation.artifactId) {
298
+ warnings.push(`Full output: artifact://${truncation.artifactId}`);
300
299
  }
301
- if (truncation?.truncated) {
302
- if (truncation.truncatedBy === "lines") {
303
- warnings.push(`Truncated: showing ${truncation.outputLines} of ${truncation.totalLines} lines`);
304
- } else {
305
- warnings.push(
306
- `Truncated: ${truncation.outputLines} lines shown (${ui.formatBytes(truncation.maxBytes)} limit)`,
307
- );
308
- }
300
+ if (truncation.truncatedBy === "lines") {
301
+ warnings.push(`Truncated: showing ${truncation.outputLines} of ${truncation.totalLines} lines`);
302
+ } else {
303
+ warnings.push(
304
+ `Truncated: ${truncation.outputLines} lines shown (${ui.formatBytes(truncation.outputBytes)} limit)`,
305
+ );
309
306
  }
310
307
  lines.push(uiTheme.fg("warning", ui.wrapBrackets(warnings.join(". "))));
311
308
  }
@@ -7,18 +7,17 @@ import { Text } from "@oh-my-pi/pi-tui";
7
7
  import { logger } from "@oh-my-pi/pi-utils";
8
8
  import { Type } from "@sinclair/typebox";
9
9
  import chalk from "chalk";
10
- import type { Theme } from "../../modes/interactive/theme/theme";
11
- import todoWriteDescription from "../../prompts/tools/todo-write.md" with { type: "text" };
12
- import type { RenderResultOptions } from "../custom-tools/types";
13
- import { renderPromptTemplate } from "../prompt-templates";
14
- import type { ToolSession } from "../sdk";
10
+ import { renderPromptTemplate } from "$c/config/prompt-templates";
11
+ import type { RenderResultOptions } from "$c/extensibility/custom-tools/types";
12
+ import type { Theme } from "$c/modes/theme/theme";
13
+ import todoWriteDescription from "$c/prompts/tools/todo-write.md" with { type: "text" };
14
+ import type { ToolSession } from "$c/sdk";
15
15
 
16
16
  const todoWriteSchema = Type.Object({
17
17
  todos: Type.Array(
18
18
  Type.Object({
19
19
  id: Type.Optional(Type.String({ description: "Stable todo id" })),
20
- content: Type.String({ description: "Imperative task description (e.g., 'Run tests')" }),
21
- activeForm: Type.String({ description: "Present continuous form (e.g., 'Running tests')" }),
20
+ content: Type.String({ description: "Task description (e.g., 'Run tests')" }),
22
21
  status: StringEnum(["pending", "in_progress", "completed"]),
23
22
  }),
24
23
  { description: "The updated todo list" },
@@ -30,7 +29,6 @@ type TodoStatus = "pending" | "in_progress" | "completed";
30
29
  export interface TodoItem {
31
30
  id: string;
32
31
  content: string;
33
- activeForm: string;
34
32
  status: TodoStatus;
35
33
  }
36
34
 
@@ -47,7 +45,7 @@ export interface TodoWriteToolDetails {
47
45
 
48
46
  const TODO_FILE_NAME = "todos.json";
49
47
 
50
- type TodoWriteParams = { todos: Array<{ id?: string; content?: string; activeForm?: string; status?: string }> };
48
+ type TodoWriteParams = { todos: Array<{ id?: string; content?: string; status?: string }> };
51
49
 
52
50
  function normalizeTodoStatus(status?: string): TodoStatus {
53
51
  switch (status) {
@@ -62,25 +60,18 @@ function normalizeTodoStatus(status?: string): TodoStatus {
62
60
  }
63
61
  }
64
62
 
65
- function normalizeTodos(
66
- items: Array<{ id?: string; content?: string; activeForm?: string; status?: string }>,
67
- ): TodoItem[] {
63
+ function normalizeTodos(items: Array<{ id?: string; content?: string; status?: string }>): TodoItem[] {
68
64
  return items.map((item) => {
69
- if (!item.content || !item.activeForm) {
70
- throw new Error("Todo content and activeForm are required.");
65
+ if (!item.content) {
66
+ throw new Error("Todo content is required.");
71
67
  }
72
68
  const content = item.content.trim();
73
- const activeForm = item.activeForm.trim();
74
69
  if (!content) {
75
70
  throw new Error("Todo content cannot be empty.");
76
71
  }
77
- if (!activeForm) {
78
- throw new Error("Todo activeForm cannot be empty.");
79
- }
80
72
  return {
81
73
  id: item.id && item.id.trim().length > 0 ? item.id : randomUUID(),
82
74
  content,
83
- activeForm,
84
75
  status: normalizeTodoStatus(item.status),
85
76
  };
86
77
  });
@@ -143,13 +134,11 @@ function formatTodoSummary(todos: TodoItem[]): string {
143
134
 
144
135
  function formatTodoLine(item: TodoItem, uiTheme: Theme, prefix: string): string {
145
136
  const checkbox = uiTheme.checkbox;
146
- const displayText =
147
- item.status === "in_progress" && item.activeForm !== item.content ? item.activeForm : item.content;
148
137
  switch (item.status) {
149
138
  case "completed":
150
139
  return uiTheme.fg("success", `${prefix}${checkbox.checked} ${chalk.strikethrough(item.content)}`);
151
140
  case "in_progress":
152
- return uiTheme.fg("accent", `${prefix}${checkbox.unchecked} ${displayText}`);
141
+ return uiTheme.fg("accent", `${prefix}${checkbox.unchecked} ${item.content}`);
153
142
  default:
154
143
  return uiTheme.fg("dim", `${prefix}${checkbox.unchecked} ${item.content}`);
155
144
  }
@@ -222,7 +211,7 @@ export class TodoWriteTool implements AgentTool<typeof todoWriteSchema, TodoWrit
222
211
  // =============================================================================
223
212
 
224
213
  interface TodoWriteRenderArgs {
225
- todos?: Array<{ id?: string; content?: string; activeForm?: string; status?: string }>;
214
+ todos?: Array<{ id?: string; content?: string; status?: string }>;
226
215
  }
227
216
 
228
217
  export const todoWriteToolRenderer = {
@@ -0,0 +1,95 @@
1
+ /**
2
+ * Standardized error types for tool execution.
3
+ *
4
+ * Tools should throw these instead of returning error text.
5
+ * The agent loop catches and renders them appropriately.
6
+ */
7
+
8
+ /**
9
+ * Base error for tool execution failures.
10
+ * Override render() for custom LLM-facing formatting.
11
+ */
12
+ export class ToolError extends Error {
13
+ constructor(
14
+ message: string,
15
+ readonly context?: Record<string, unknown>,
16
+ ) {
17
+ super(message);
18
+ this.name = "ToolError";
19
+ }
20
+
21
+ /** Render error for LLM consumption. Override for custom formatting. */
22
+ render(): string {
23
+ return this.message;
24
+ }
25
+ }
26
+
27
+ /**
28
+ * Error entry for MultiError.
29
+ */
30
+ export interface ErrorEntry {
31
+ message: string;
32
+ context?: string;
33
+ }
34
+
35
+ /**
36
+ * Error with multiple entries (e.g., multiple validation failures, batch errors).
37
+ */
38
+ export class MultiError extends ToolError {
39
+ readonly errors: ErrorEntry[];
40
+
41
+ constructor(errors: ErrorEntry[]) {
42
+ super(errors.map((e) => e.message).join("; "));
43
+ this.name = "MultiError";
44
+ this.errors = errors;
45
+ }
46
+
47
+ render(): string {
48
+ if (this.errors.length === 1) {
49
+ const e = this.errors[0];
50
+ return e.context ? `${e.context}: ${e.message}` : e.message;
51
+ }
52
+ return this.errors.map((e) => (e.context ? `${e.context}: ${e.message}` : e.message)).join("\n");
53
+ }
54
+
55
+ static from(errors: Array<string | ErrorEntry>): MultiError {
56
+ return new MultiError(errors.map((e) => (typeof e === "string" ? { message: e } : e)));
57
+ }
58
+ }
59
+
60
+ /**
61
+ * Error thrown when a tool operation is aborted (e.g., via AbortSignal).
62
+ */
63
+ export class ToolAbortError extends Error {
64
+ static readonly MESSAGE = "Operation aborted";
65
+
66
+ constructor(message: string = ToolAbortError.MESSAGE) {
67
+ super(message);
68
+ this.name = "ToolAbortError";
69
+ }
70
+ }
71
+
72
+ /**
73
+ * Throw ToolAbortError if the signal is aborted.
74
+ * Use this instead of signal?.throwIfAborted() to get consistent error types.
75
+ */
76
+ export function throwIfAborted(signal?: AbortSignal): void {
77
+ if (signal?.aborted) {
78
+ const reason = signal.reason instanceof Error ? signal.reason : undefined;
79
+ throw reason instanceof ToolAbortError ? reason : new ToolAbortError();
80
+ }
81
+ }
82
+
83
+ /**
84
+ * Render an error for LLM consumption.
85
+ * Handles ToolError.render() and falls back to message/string.
86
+ */
87
+ export function renderError(e: unknown): string {
88
+ if (e instanceof ToolError) {
89
+ return e.render();
90
+ }
91
+ if (e instanceof Error) {
92
+ return e.message;
93
+ }
94
+ return String(e);
95
+ }
@@ -0,0 +1,92 @@
1
+ import type { AgentToolResult } from "@oh-my-pi/pi-agent-core";
2
+ import type { ImageContent, TextContent } from "@oh-my-pi/pi-ai";
3
+ import type { OutputSummary } from "$c/session/streaming-output";
4
+ import type {
5
+ OutputMeta,
6
+ TruncationOptions,
7
+ TruncationSummaryOptions,
8
+ TruncationTextOptions,
9
+ } from "$c/tools/output-meta";
10
+ import { outputMeta } from "$c/tools/output-meta";
11
+ import type { TruncationResult } from "./truncate";
12
+
13
+ type ToolContent = Array<TextContent | ImageContent>;
14
+
15
+ type DetailsWithMeta = { meta?: OutputMeta };
16
+
17
+ export class ToolResultBuilder<TDetails extends DetailsWithMeta> {
18
+ #details: TDetails;
19
+ #meta = outputMeta();
20
+ #content: ToolContent = [];
21
+
22
+ constructor(details?: TDetails) {
23
+ this.#details = details ?? ({} as TDetails);
24
+ }
25
+
26
+ text(text: string): this {
27
+ this.#content = [{ type: "text", text }];
28
+ return this;
29
+ }
30
+
31
+ content(content: ToolContent): this {
32
+ this.#content = content;
33
+ return this;
34
+ }
35
+
36
+ truncation(result: TruncationResult, options: TruncationOptions): this {
37
+ this.#meta.truncation(result, options);
38
+ return this;
39
+ }
40
+
41
+ truncationFromSummary(summary: OutputSummary, options: TruncationSummaryOptions): this {
42
+ this.#meta.truncationFromSummary(summary, options);
43
+ return this;
44
+ }
45
+
46
+ truncationFromText(text: string, options: TruncationTextOptions): this {
47
+ this.#meta.truncationFromText(text, options);
48
+ return this;
49
+ }
50
+
51
+ limits(limits: { matchLimit?: number; resultLimit?: number; headLimit?: number; columnMax?: number }): this {
52
+ this.#meta.limits(limits);
53
+ return this;
54
+ }
55
+
56
+ sourceUrl(value: string): this {
57
+ this.#meta.sourceUrl(value);
58
+ return this;
59
+ }
60
+
61
+ sourcePath(value: string): this {
62
+ this.#meta.sourcePath(value);
63
+ return this;
64
+ }
65
+
66
+ sourceInternal(value: string): this {
67
+ this.#meta.sourceInternal(value);
68
+ return this;
69
+ }
70
+
71
+ diagnostics(summary: string, messages: string[]): this {
72
+ this.#meta.diagnostics(summary, messages);
73
+ return this;
74
+ }
75
+
76
+ done(): AgentToolResult<TDetails> {
77
+ const meta = this.#meta.get();
78
+ if (meta) {
79
+ this.#details.meta = meta;
80
+ }
81
+ const hasDetails = Object.entries(this.#details).some(([, value]) => value !== undefined);
82
+
83
+ return {
84
+ content: this.#content,
85
+ details: hasDetails ? this.#details : undefined,
86
+ };
87
+ }
88
+ }
89
+
90
+ export function toolResult<TDetails extends DetailsWithMeta>(details?: TDetails): ToolResultBuilder<TDetails> {
91
+ return new ToolResultBuilder(details);
92
+ }
@@ -2,14 +2,14 @@
2
2
  * Shared truncation utilities for tool outputs.
3
3
  *
4
4
  * Truncation is based on two independent limits - whichever is hit first wins:
5
- * - Line limit (default: 2000 lines)
5
+ * - Line limit (default: 4000 lines)
6
6
  * - Byte limit (default: 50KB)
7
7
  *
8
8
  * Never returns partial lines (except bash tail truncation edge case
9
9
  * and the read tool's long-line snippet fallback).
10
10
  */
11
11
 
12
- export const DEFAULT_MAX_LINES = 2000;
12
+ export const DEFAULT_MAX_LINES = 3000;
13
13
  export const DEFAULT_MAX_BYTES = 50 * 1024; // 50KB
14
14
  export const DEFAULT_MAX_COLUMN = 1024; // Max chars per grep match line
15
15
 
@@ -9,17 +9,18 @@ import type { Component } from "@oh-my-pi/pi-tui";
9
9
  import { Text } from "@oh-my-pi/pi-tui";
10
10
  import { untilAborted } from "@oh-my-pi/pi-utils";
11
11
  import { Type } from "@sinclair/typebox";
12
- import { getLanguageFromPath, highlightCode, type Theme } from "../../modes/interactive/theme/theme";
13
- import writeDescription from "../../prompts/tools/write.md" with { type: "text" };
14
- import type { RenderResultOptions } from "../custom-tools/types";
15
- import { renderPromptTemplate } from "../prompt-templates";
16
- import type { ToolSession } from "../sdk";
12
+ import { renderPromptTemplate } from "$c/config/prompt-templates";
13
+ import type { RenderResultOptions } from "$c/extensibility/custom-tools/types";
17
14
  import {
18
15
  createLspWritethrough,
19
16
  type FileDiagnosticsResult,
20
17
  type WritethroughCallback,
21
18
  writethroughNoop,
22
- } from "./lsp/index";
19
+ } from "$c/lsp/index";
20
+ import { getLanguageFromPath, highlightCode, type Theme } from "$c/modes/theme/theme";
21
+ import writeDescription from "$c/prompts/tools/write.md" with { type: "text" };
22
+ import type { ToolSession } from "$c/sdk";
23
+ import { type OutputMeta, outputMeta } from "$c/tools/output-meta";
23
24
  import { resolveToCwd } from "./path-utils";
24
25
  import { formatDiagnostics, formatExpandHint, formatStatusIcon, replaceTabs, shortenPath } from "./render-utils";
25
26
  import type { RenderCallOptions } from "./renderers";
@@ -32,6 +33,7 @@ const writeSchema = Type.Object({
32
33
  /** Details returned by the write tool for TUI rendering */
33
34
  export interface WriteToolDetails {
34
35
  diagnostics?: FileDiagnosticsResult;
36
+ meta?: OutputMeta;
35
37
  }
36
38
 
37
39
  const LSP_BATCH_TOOLS = new Set(["edit", "write"]);
@@ -94,7 +96,7 @@ export class WriteTool implements AgentTool<typeof writeSchema, WriteToolDetails
94
96
 
95
97
  const diagnostics = await this.writethrough(absolutePath, content, signal, undefined, batchRequest);
96
98
 
97
- let resultText = `Successfully wrote ${content.length} bytes to ${path}`;
99
+ const resultText = `Successfully wrote ${content.length} bytes to ${path}`;
98
100
  if (!diagnostics) {
99
101
  return {
100
102
  content: [{ type: "text", text: resultText }],
@@ -102,14 +104,14 @@ export class WriteTool implements AgentTool<typeof writeSchema, WriteToolDetails
102
104
  };
103
105
  }
104
106
 
105
- const messages = diagnostics?.messages;
106
- if (messages && messages.length > 0) {
107
- resultText += `\n\nLSP Diagnostics (${diagnostics.summary}):\n`;
108
- resultText += messages.map((d) => ` ${d}`).join("\n");
109
- }
110
107
  return {
111
108
  content: [{ type: "text", text: resultText }],
112
- details: { diagnostics },
109
+ details: {
110
+ diagnostics,
111
+ meta: outputMeta()
112
+ .diagnostics(diagnostics.summary, diagnostics.messages ?? [])
113
+ .get(),
114
+ },
113
115
  };
114
116
  });
115
117
  }
@@ -96,4 +96,4 @@ export function getNewEntries(entries: ChangelogEntry[], lastVersion: string): C
96
96
  }
97
97
 
98
98
  // Re-export getChangelogPath from paths.ts for convenience
99
- export { getChangelogPath } from "../config";
99
+ export { getChangelogPath } from "$c/config";
@@ -8,10 +8,10 @@
8
8
 
9
9
  import path from "node:path";
10
10
  import type { AgentMessage } from "@oh-my-pi/pi-agent-core";
11
- import type { FileMentionMessage } from "./messages";
12
- import { resolveReadPath } from "./tools/path-utils";
13
- import { formatAge } from "./tools/render-utils";
14
- import { DEFAULT_MAX_BYTES, formatSize, truncateHead, truncateStringToBytesFromStart } from "./tools/truncate";
11
+ import type { FileMentionMessage } from "$c/session/messages";
12
+ import { resolveReadPath } from "$c/tools/path-utils";
13
+ import { formatAge } from "$c/tools/render-utils";
14
+ import { DEFAULT_MAX_BYTES, formatSize, truncateHead, truncateStringToBytesFromStart } from "$c/tools/truncate";
15
15
 
16
16
  /** Regex to match @filepath patterns in text */
17
17
  const FILE_MENTION_REGEX = /@([^\s@]+)/g;
@@ -1,4 +1,4 @@
1
- import * as photon from "../vendor/photon";
1
+ import * as photon from "$c/vendor/photon";
2
2
 
3
3
  /**
4
4
  * Convert image to PNG format for terminal display.