@oh-my-pi/pi-coding-agent 8.1.0 → 8.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (402) hide show
  1. package/CHANGELOG.md +21 -1
  2. package/docs/session.md +111 -46
  3. package/examples/custom-tools/hello/index.ts +1 -1
  4. package/examples/custom-tools/todo/index.ts +3 -4
  5. package/examples/extensions/api-demo.ts +0 -1
  6. package/examples/extensions/chalk-logger.ts +2 -3
  7. package/examples/extensions/hello.ts +0 -1
  8. package/examples/extensions/pirate.ts +0 -1
  9. package/examples/extensions/plan-mode.ts +15 -16
  10. package/examples/extensions/todo.ts +3 -4
  11. package/examples/extensions/tools.ts +1 -2
  12. package/examples/extensions/with-deps/index.ts +0 -1
  13. package/examples/hooks/auto-commit-on-exit.ts +1 -2
  14. package/examples/hooks/confirm-destructive.ts +0 -1
  15. package/examples/hooks/custom-compaction.ts +1 -2
  16. package/examples/hooks/dirty-repo-guard.ts +0 -1
  17. package/examples/hooks/file-trigger.ts +3 -4
  18. package/examples/hooks/git-checkpoint.ts +0 -1
  19. package/examples/hooks/handoff.ts +3 -4
  20. package/examples/hooks/permission-gate.ts +1 -2
  21. package/examples/hooks/protected-paths.ts +1 -2
  22. package/examples/hooks/qna.ts +2 -3
  23. package/examples/hooks/snake.ts +4 -5
  24. package/examples/hooks/status-line.ts +0 -1
  25. package/examples/sdk/01-minimal.ts +2 -3
  26. package/examples/sdk/02-custom-model.ts +2 -3
  27. package/examples/sdk/03-custom-prompt.ts +3 -4
  28. package/examples/sdk/04-skills.ts +2 -3
  29. package/examples/sdk/06-extensions.ts +1 -2
  30. package/examples/sdk/06-hooks.ts +6 -7
  31. package/examples/sdk/07-context-files.ts +0 -1
  32. package/examples/sdk/08-prompt-templates.ts +0 -1
  33. package/examples/sdk/08-slash-commands.ts +0 -1
  34. package/examples/sdk/09-api-keys-and-oauth.ts +0 -1
  35. package/examples/sdk/10-settings.ts +0 -1
  36. package/examples/sdk/11-sessions.ts +0 -1
  37. package/package.json +51 -23
  38. package/scripts/format-prompts.ts +0 -1
  39. package/src/capability/context-file.ts +2 -3
  40. package/src/capability/extension-module.ts +2 -3
  41. package/src/capability/extension.ts +2 -3
  42. package/src/capability/fs.ts +20 -21
  43. package/src/capability/hook.ts +2 -3
  44. package/src/capability/index.ts +15 -16
  45. package/src/capability/instruction.ts +2 -3
  46. package/src/capability/mcp.ts +2 -3
  47. package/src/capability/prompt.ts +2 -3
  48. package/src/capability/rule.ts +2 -3
  49. package/src/capability/settings.ts +1 -2
  50. package/src/capability/skill.ts +2 -3
  51. package/src/capability/slash-command.ts +2 -3
  52. package/src/capability/ssh.ts +2 -3
  53. package/src/capability/system-prompt.ts +2 -3
  54. package/src/capability/tool.ts +2 -3
  55. package/src/cli/args.ts +5 -6
  56. package/src/cli/config-cli.ts +6 -7
  57. package/src/cli/file-processor.ts +19 -17
  58. package/src/cli/jupyter-cli.ts +105 -0
  59. package/src/cli/list-models.ts +10 -11
  60. package/src/cli/plugin-cli.ts +20 -21
  61. package/src/cli/session-picker.ts +2 -3
  62. package/src/cli/setup-cli.ts +2 -3
  63. package/src/cli/stats-cli.ts +2 -3
  64. package/src/cli/update-cli.ts +25 -22
  65. package/src/commit/agentic/agent.ts +21 -23
  66. package/src/commit/agentic/fallback.ts +9 -9
  67. package/src/commit/agentic/index.ts +30 -38
  68. package/src/commit/agentic/state.ts +1 -6
  69. package/src/commit/agentic/tools/analyze-file.ts +15 -15
  70. package/src/commit/agentic/tools/git-file-diff.ts +3 -3
  71. package/src/commit/agentic/tools/git-hunk.ts +7 -7
  72. package/src/commit/agentic/tools/git-overview.ts +5 -5
  73. package/src/commit/agentic/tools/index.ts +14 -14
  74. package/src/commit/agentic/tools/propose-changelog.ts +6 -6
  75. package/src/commit/agentic/tools/propose-commit.ts +8 -8
  76. package/src/commit/agentic/tools/recent-commits.ts +2 -2
  77. package/src/commit/agentic/tools/split-commit.ts +19 -23
  78. package/src/commit/agentic/topo-sort.ts +1 -1
  79. package/src/commit/agentic/trivial.ts +3 -3
  80. package/src/commit/agentic/validation.ts +12 -12
  81. package/src/commit/analysis/conventional.ts +7 -11
  82. package/src/commit/analysis/index.ts +4 -4
  83. package/src/commit/analysis/scope.ts +4 -4
  84. package/src/commit/analysis/summary.ts +7 -9
  85. package/src/commit/analysis/validation.ts +1 -1
  86. package/src/commit/changelog/detect.ts +6 -6
  87. package/src/commit/changelog/generate.ts +7 -9
  88. package/src/commit/changelog/index.ts +13 -13
  89. package/src/commit/changelog/parse.ts +2 -2
  90. package/src/commit/cli.ts +1 -1
  91. package/src/commit/git/diff.ts +3 -3
  92. package/src/commit/git/index.ts +19 -24
  93. package/src/commit/index.ts +1 -1
  94. package/src/commit/map-reduce/index.ts +9 -9
  95. package/src/commit/map-reduce/map-phase.ts +19 -34
  96. package/src/commit/map-reduce/reduce-phase.ts +9 -11
  97. package/src/commit/message.ts +2 -2
  98. package/src/commit/model-selection.ts +3 -7
  99. package/src/commit/pipeline.ts +20 -22
  100. package/src/commit/utils/exclusions.ts +3 -3
  101. package/src/config/file-lock.ts +17 -7
  102. package/src/config/keybindings.ts +6 -8
  103. package/src/config/model-registry.ts +55 -37
  104. package/src/config/model-resolver.ts +18 -19
  105. package/src/config/prompt-templates.ts +11 -11
  106. package/src/config/settings-manager.ts +50 -34
  107. package/src/config.ts +60 -62
  108. package/src/cursor.ts +11 -9
  109. package/src/discovery/agents-md.ts +11 -12
  110. package/src/discovery/builtin.ts +68 -73
  111. package/src/discovery/claude.ts +41 -42
  112. package/src/discovery/cline.ts +11 -12
  113. package/src/discovery/codex.ts +52 -53
  114. package/src/discovery/cursor.ts +9 -10
  115. package/src/discovery/gemini.ts +17 -22
  116. package/src/discovery/github.ts +13 -14
  117. package/src/discovery/helpers.ts +35 -34
  118. package/src/discovery/index.ts +16 -18
  119. package/src/discovery/mcp-json.ts +8 -9
  120. package/src/discovery/ssh.ts +8 -9
  121. package/src/discovery/vscode.ts +4 -5
  122. package/src/discovery/windsurf.ts +6 -7
  123. package/src/exa/company.ts +1 -2
  124. package/src/exa/index.ts +2 -3
  125. package/src/exa/linkedin.ts +1 -2
  126. package/src/exa/mcp-client.ts +14 -16
  127. package/src/exa/render.ts +10 -11
  128. package/src/exa/researcher.ts +1 -2
  129. package/src/exa/search.ts +1 -2
  130. package/src/exa/types.ts +0 -1
  131. package/src/exa/websets.ts +1 -2
  132. package/src/exec/bash-executor.ts +3 -4
  133. package/src/exec/exec.ts +0 -1
  134. package/src/export/custom-share.ts +5 -6
  135. package/src/export/html/index.ts +24 -21
  136. package/src/export/ttsr.ts +2 -3
  137. package/src/extensibility/custom-commands/bundled/review/index.ts +7 -8
  138. package/src/extensibility/custom-commands/loader.ts +17 -14
  139. package/src/extensibility/custom-commands/types.ts +1 -2
  140. package/src/extensibility/custom-tools/loader.ts +10 -11
  141. package/src/extensibility/custom-tools/types.ts +6 -7
  142. package/src/extensibility/custom-tools/wrapper.ts +2 -3
  143. package/src/extensibility/extensions/loader.ts +75 -53
  144. package/src/extensibility/extensions/runner.ts +11 -12
  145. package/src/extensibility/extensions/types.ts +19 -26
  146. package/src/extensibility/extensions/wrapper.ts +3 -4
  147. package/src/extensibility/hooks/index.ts +1 -1
  148. package/src/extensibility/hooks/loader.ts +8 -9
  149. package/src/extensibility/hooks/runner.ts +7 -8
  150. package/src/extensibility/hooks/tool-wrapper.ts +0 -1
  151. package/src/extensibility/hooks/types.ts +10 -17
  152. package/src/extensibility/plugins/doctor.ts +3 -3
  153. package/src/extensibility/plugins/installer.ts +27 -27
  154. package/src/extensibility/plugins/loader.ts +59 -56
  155. package/src/extensibility/plugins/manager.ts +211 -171
  156. package/src/extensibility/plugins/parser.ts +1 -1
  157. package/src/extensibility/plugins/paths.ts +8 -8
  158. package/src/extensibility/skills.ts +63 -60
  159. package/src/extensibility/slash-commands.ts +10 -10
  160. package/src/index.ts +46 -46
  161. package/src/internal-urls/agent-protocol.ts +21 -11
  162. package/src/internal-urls/artifact-protocol.ts +17 -13
  163. package/src/internal-urls/router.ts +1 -2
  164. package/src/internal-urls/rule-protocol.ts +3 -4
  165. package/src/internal-urls/skill-protocol.ts +3 -4
  166. package/src/ipy/executor.ts +14 -10
  167. package/src/ipy/gateway-coordinator.ts +79 -90
  168. package/src/ipy/kernel.ts +32 -30
  169. package/src/ipy/modules.ts +13 -13
  170. package/src/lsp/client.ts +21 -10
  171. package/src/lsp/clients/biome-client.ts +1 -2
  172. package/src/lsp/clients/index.ts +3 -3
  173. package/src/lsp/clients/lsp-linter-client.ts +4 -5
  174. package/src/lsp/config.ts +15 -15
  175. package/src/lsp/edits.ts +4 -5
  176. package/src/lsp/index.ts +43 -44
  177. package/src/lsp/lspmux.ts +8 -8
  178. package/src/lsp/render.ts +10 -16
  179. package/src/lsp/utils.ts +3 -3
  180. package/src/main.ts +55 -34
  181. package/src/mcp/client.ts +2 -3
  182. package/src/mcp/config.ts +5 -6
  183. package/src/mcp/json-rpc.ts +0 -1
  184. package/src/mcp/loader.ts +3 -4
  185. package/src/mcp/manager.ts +17 -18
  186. package/src/mcp/tool-bridge.ts +4 -9
  187. package/src/mcp/tool-cache.ts +2 -3
  188. package/src/mcp/transports/http.ts +2 -4
  189. package/src/mcp/transports/stdio.ts +1 -2
  190. package/src/migrations.ts +60 -49
  191. package/src/modes/components/armin.ts +4 -5
  192. package/src/modes/components/assistant-message.ts +6 -6
  193. package/src/modes/components/bash-execution.ts +7 -8
  194. package/src/modes/components/bordered-loader.ts +3 -3
  195. package/src/modes/components/branch-summary-message.ts +3 -3
  196. package/src/modes/components/compaction-summary-message.ts +3 -3
  197. package/src/modes/components/countdown-timer.ts +0 -1
  198. package/src/modes/components/custom-message.ts +5 -5
  199. package/src/modes/components/diff.ts +1 -1
  200. package/src/modes/components/dynamic-border.ts +2 -2
  201. package/src/modes/components/extensions/extension-dashboard.ts +6 -7
  202. package/src/modes/components/extensions/extension-list.ts +2 -3
  203. package/src/modes/components/extensions/inspector-panel.ts +3 -4
  204. package/src/modes/components/extensions/state-manager.ts +25 -26
  205. package/src/modes/components/extensions/types.ts +1 -2
  206. package/src/modes/components/footer.ts +47 -43
  207. package/src/modes/components/history-search.ts +2 -2
  208. package/src/modes/components/hook-editor.ts +3 -4
  209. package/src/modes/components/hook-input.ts +2 -3
  210. package/src/modes/components/hook-message.ts +5 -5
  211. package/src/modes/components/hook-selector.ts +2 -3
  212. package/src/modes/components/keybinding-hints.ts +2 -3
  213. package/src/modes/components/login-dialog.ts +2 -2
  214. package/src/modes/components/model-selector.ts +12 -12
  215. package/src/modes/components/oauth-selector.ts +2 -2
  216. package/src/modes/components/plugin-settings.ts +20 -20
  217. package/src/modes/components/python-execution.ts +7 -8
  218. package/src/modes/components/queue-mode-selector.ts +3 -3
  219. package/src/modes/components/read-tool-group.ts +2 -2
  220. package/src/modes/components/session-selector.ts +4 -4
  221. package/src/modes/components/settings-defs.ts +77 -69
  222. package/src/modes/components/settings-selector.ts +16 -16
  223. package/src/modes/components/show-images-selector.ts +2 -2
  224. package/src/modes/components/status-line/segments.ts +4 -4
  225. package/src/modes/components/status-line/separators.ts +1 -1
  226. package/src/modes/components/status-line/types.ts +2 -2
  227. package/src/modes/components/status-line-segment-editor.ts +7 -8
  228. package/src/modes/components/status-line.ts +12 -12
  229. package/src/modes/components/theme-selector.ts +8 -7
  230. package/src/modes/components/thinking-selector.ts +4 -4
  231. package/src/modes/components/todo-display.ts +2 -2
  232. package/src/modes/components/todo-reminder.ts +4 -4
  233. package/src/modes/components/tool-execution.ts +11 -16
  234. package/src/modes/components/tree-selector.ts +11 -11
  235. package/src/modes/components/ttsr-notification.ts +5 -5
  236. package/src/modes/components/user-message-selector.ts +1 -1
  237. package/src/modes/components/user-message.ts +1 -1
  238. package/src/modes/components/visual-truncate.ts +0 -1
  239. package/src/modes/components/welcome.ts +4 -4
  240. package/src/modes/controllers/command-controller.ts +46 -47
  241. package/src/modes/controllers/event-controller.ts +16 -20
  242. package/src/modes/controllers/extension-ui-controller.ts +40 -46
  243. package/src/modes/controllers/input-controller.ts +17 -18
  244. package/src/modes/controllers/selector-controller.ts +103 -91
  245. package/src/modes/index.ts +3 -3
  246. package/src/modes/interactive-mode.ts +27 -29
  247. package/src/modes/print-mode.ts +12 -13
  248. package/src/modes/rpc/rpc-client.ts +7 -8
  249. package/src/modes/rpc/rpc-mode.ts +24 -25
  250. package/src/modes/rpc/rpc-types.ts +3 -4
  251. package/src/modes/theme/mermaid-cache.ts +2 -2
  252. package/src/modes/theme/theme.ts +128 -53
  253. package/src/modes/types.ts +10 -10
  254. package/src/modes/utils/ui-helpers.ts +17 -17
  255. package/src/patch/applicator.ts +18 -19
  256. package/src/patch/diff.ts +1 -2
  257. package/src/patch/fuzzy.ts +1 -2
  258. package/src/patch/index.ts +10 -11
  259. package/src/patch/normalize.ts +4 -4
  260. package/src/patch/normative.ts +1 -2
  261. package/src/patch/parser.ts +8 -9
  262. package/src/patch/shared.ts +12 -13
  263. package/src/sdk.ts +60 -63
  264. package/src/session/agent-session.ts +83 -84
  265. package/src/session/agent-storage.ts +11 -11
  266. package/src/session/artifacts.ts +8 -9
  267. package/src/session/auth-storage.ts +25 -29
  268. package/src/session/compaction/branch-summarization.ts +7 -10
  269. package/src/session/compaction/compaction.ts +8 -19
  270. package/src/session/compaction/utils.ts +6 -9
  271. package/src/session/history-storage.ts +10 -10
  272. package/src/session/messages.ts +4 -5
  273. package/src/session/session-manager.ts +76 -65
  274. package/src/session/session-storage.ts +57 -69
  275. package/src/session/storage-migration.ts +2 -3
  276. package/src/session/streaming-output.ts +2 -2
  277. package/src/ssh/connection-manager.ts +43 -50
  278. package/src/ssh/ssh-executor.ts +2 -2
  279. package/src/ssh/sshfs-mount.ts +11 -18
  280. package/src/system-prompt.ts +27 -34
  281. package/src/task/agents.ts +45 -30
  282. package/src/task/commands.ts +6 -7
  283. package/src/task/discovery.ts +39 -76
  284. package/src/task/executor.ts +14 -15
  285. package/src/task/index.ts +33 -36
  286. package/src/task/output-manager.ts +3 -4
  287. package/src/task/parallel.ts +0 -1
  288. package/src/task/render.ts +19 -20
  289. package/src/task/subprocess-tool-registry.ts +1 -2
  290. package/src/task/worker-protocol.ts +3 -3
  291. package/src/task/worker.ts +32 -38
  292. package/src/task/worktree.ts +19 -19
  293. package/src/tools/ask.ts +8 -9
  294. package/src/tools/bash-interceptor.ts +1 -5
  295. package/src/tools/bash.ts +19 -18
  296. package/src/tools/calculator.ts +12 -12
  297. package/src/tools/complete.ts +3 -4
  298. package/src/tools/context.ts +2 -2
  299. package/src/tools/fetch.ts +23 -26
  300. package/src/tools/find.ts +15 -16
  301. package/src/tools/gemini-image.ts +14 -14
  302. package/src/tools/grep.ts +27 -27
  303. package/src/tools/index.ts +78 -56
  304. package/src/tools/list-limit.ts +1 -1
  305. package/src/tools/ls.ts +7 -7
  306. package/src/tools/notebook.ts +5 -5
  307. package/src/tools/output-meta.ts +3 -4
  308. package/src/tools/output-utils.ts +1 -1
  309. package/src/tools/path-utils.ts +5 -5
  310. package/src/tools/python.ts +36 -37
  311. package/src/tools/read.ts +23 -23
  312. package/src/tools/render-utils.ts +8 -9
  313. package/src/tools/renderers.ts +6 -7
  314. package/src/tools/review.ts +8 -11
  315. package/src/tools/ssh.ts +31 -30
  316. package/src/tools/todo-write.ts +13 -13
  317. package/src/tools/tool-errors.ts +3 -3
  318. package/src/tools/tool-result.ts +3 -8
  319. package/src/tools/write.ts +11 -16
  320. package/src/tui/code-cell.ts +3 -9
  321. package/src/tui/file-list.ts +3 -4
  322. package/src/tui/output-block.ts +1 -2
  323. package/src/tui/status-line.ts +2 -3
  324. package/src/tui/tree-list.ts +2 -3
  325. package/src/tui/types.ts +1 -2
  326. package/src/tui/utils.ts +2 -3
  327. package/src/utils/changelog.ts +9 -10
  328. package/src/utils/clipboard.ts +11 -11
  329. package/src/utils/file-mentions.ts +4 -10
  330. package/src/utils/frontmatter.ts +6 -3
  331. package/src/utils/fuzzy.ts +2 -2
  332. package/src/utils/image-convert.ts +1 -1
  333. package/src/utils/image-resize.ts +1 -1
  334. package/src/utils/mime.ts +2 -2
  335. package/src/utils/shell-snapshot.ts +11 -13
  336. package/src/utils/shell.ts +4 -5
  337. package/src/utils/title-generator.ts +8 -9
  338. package/src/utils/tools-manager.ts +23 -23
  339. package/src/vendor/photon/index.js +1099 -1059
  340. package/src/vendor/photon/photon_rs_bg.wasm +0 -0
  341. package/src/web/scrapers/artifacthub.ts +1 -1
  342. package/src/web/scrapers/arxiv.ts +2 -2
  343. package/src/web/scrapers/bluesky.ts +2 -2
  344. package/src/web/scrapers/cheatsh.ts +1 -1
  345. package/src/web/scrapers/chocolatey.ts +2 -2
  346. package/src/web/scrapers/choosealicense.ts +5 -5
  347. package/src/web/scrapers/cisa-kev.ts +1 -1
  348. package/src/web/scrapers/crossref.ts +2 -2
  349. package/src/web/scrapers/devto.ts +3 -3
  350. package/src/web/scrapers/discogs.ts +3 -4
  351. package/src/web/scrapers/discourse.ts +1 -1
  352. package/src/web/scrapers/dockerhub.ts +1 -1
  353. package/src/web/scrapers/fdroid.ts +2 -2
  354. package/src/web/scrapers/firefox-addons.ts +3 -3
  355. package/src/web/scrapers/flathub.ts +1 -1
  356. package/src/web/scrapers/github.ts +3 -3
  357. package/src/web/scrapers/gitlab.ts +4 -4
  358. package/src/web/scrapers/hackernews.ts +2 -2
  359. package/src/web/scrapers/huggingface.ts +1 -1
  360. package/src/web/scrapers/iacr.ts +2 -2
  361. package/src/web/scrapers/index.ts +0 -1
  362. package/src/web/scrapers/jetbrains-marketplace.ts +1 -1
  363. package/src/web/scrapers/lemmy.ts +2 -2
  364. package/src/web/scrapers/maven.ts +2 -2
  365. package/src/web/scrapers/mdn.ts +2 -4
  366. package/src/web/scrapers/metacpan.ts +2 -2
  367. package/src/web/scrapers/musicbrainz.ts +1 -2
  368. package/src/web/scrapers/npm.ts +1 -1
  369. package/src/web/scrapers/nuget.ts +2 -2
  370. package/src/web/scrapers/nvd.ts +3 -3
  371. package/src/web/scrapers/ollama.ts +7 -9
  372. package/src/web/scrapers/opencorporates.ts +2 -2
  373. package/src/web/scrapers/openlibrary.ts +6 -6
  374. package/src/web/scrapers/orcid.ts +0 -1
  375. package/src/web/scrapers/osv.ts +2 -2
  376. package/src/web/scrapers/packagist.ts +1 -1
  377. package/src/web/scrapers/pubmed.ts +1 -2
  378. package/src/web/scrapers/rawg.ts +2 -2
  379. package/src/web/scrapers/readthedocs.ts +1 -2
  380. package/src/web/scrapers/repology.ts +2 -2
  381. package/src/web/scrapers/rfc.ts +1 -1
  382. package/src/web/scrapers/searchcode.ts +2 -2
  383. package/src/web/scrapers/semantic-scholar.ts +1 -1
  384. package/src/web/scrapers/snapcraft.ts +2 -2
  385. package/src/web/scrapers/sourcegraph.ts +1 -1
  386. package/src/web/scrapers/spdx.ts +3 -3
  387. package/src/web/scrapers/spotify.ts +0 -1
  388. package/src/web/scrapers/twitter.ts +1 -1
  389. package/src/web/scrapers/types.ts +1 -2
  390. package/src/web/scrapers/utils.ts +5 -5
  391. package/src/web/scrapers/wikidata.ts +3 -3
  392. package/src/web/scrapers/youtube.ts +9 -14
  393. package/src/web/search/auth.ts +4 -9
  394. package/src/web/search/index.ts +11 -21
  395. package/src/web/search/providers/anthropic.ts +3 -9
  396. package/src/web/search/providers/exa.ts +6 -10
  397. package/src/web/search/providers/perplexity.ts +5 -5
  398. package/src/web/search/render.ts +16 -18
  399. package/scripts/generate-wasm-b64.ts +0 -24
  400. package/src/commit/map-reduce/.map-phase.ts.kate-swp +0 -0
  401. package/src/task/.executor.ts.kate-swp +0 -0
  402. package/src/vendor/photon/photon_rs_bg.wasm.b64.js +0 -1
@@ -1,27 +1,27 @@
1
- import { mkdir, rm } from "node:fs/promises";
1
+ import * as fs from "node:fs/promises";
2
2
  import * as path from "node:path";
3
3
  import type { AgentTool, AgentToolContext, AgentToolResult, AgentToolUpdateCallback } from "@oh-my-pi/pi-agent-core";
4
- import { renderPromptTemplate } from "@oh-my-pi/pi-coding-agent/config/prompt-templates";
5
- import type { RenderResultOptions } from "@oh-my-pi/pi-coding-agent/extensibility/custom-tools/types";
6
- import { type Theme, theme } from "@oh-my-pi/pi-coding-agent/modes/theme/theme";
7
- import fetchDescription from "@oh-my-pi/pi-coding-agent/prompts/tools/fetch.md" with { type: "text" };
8
- import type { OutputMeta } from "@oh-my-pi/pi-coding-agent/tools/output-meta";
9
- import { ToolAbortError } from "@oh-my-pi/pi-coding-agent/tools/tool-errors";
10
- import { renderOutputBlock, renderStatusLine } from "@oh-my-pi/pi-coding-agent/tui";
11
- import { ensureTool } from "@oh-my-pi/pi-coding-agent/utils/tools-manager";
12
- import { specialHandlers } from "@oh-my-pi/pi-coding-agent/web/scrapers";
13
- import type { RenderResult } from "@oh-my-pi/pi-coding-agent/web/scrapers/types";
14
- import { finalizeOutput, loadPage, MAX_OUTPUT_CHARS } from "@oh-my-pi/pi-coding-agent/web/scrapers/types";
15
- import { convertWithMarkitdown, fetchBinary } from "@oh-my-pi/pi-coding-agent/web/scrapers/utils";
16
4
  import type { Component } from "@oh-my-pi/pi-tui";
17
5
  import { Text } from "@oh-my-pi/pi-tui";
18
6
  import { ptree } from "@oh-my-pi/pi-utils";
19
7
  import { type Static, Type } from "@sinclair/typebox";
20
8
  import { nanoid } from "nanoid";
21
9
  import { parse as parseHtml } from "node-html-parser";
10
+ import { renderPromptTemplate } from "../config/prompt-templates";
11
+ import type { RenderResultOptions } from "../extensibility/custom-tools/types";
12
+ import { type Theme, theme } from "../modes/theme/theme";
13
+ import fetchDescription from "../prompts/tools/fetch.md" with { type: "text" };
14
+ import { renderOutputBlock, renderStatusLine } from "../tui";
15
+ import { ensureTool } from "../utils/tools-manager";
16
+ import { specialHandlers } from "../web/scrapers";
17
+ import type { RenderResult } from "../web/scrapers/types";
18
+ import { finalizeOutput, loadPage, MAX_OUTPUT_CHARS } from "../web/scrapers/types";
19
+ import { convertWithMarkitdown, fetchBinary } from "../web/scrapers/utils";
22
20
  import type { ToolSession } from ".";
23
21
  import { applyListLimit } from "./list-limit";
22
+ import type { OutputMeta } from "./output-meta";
24
23
  import { formatExpandHint } from "./render-utils";
24
+ import { ToolAbortError } from "./tool-errors";
25
25
  import { toolResult } from "./tool-result";
26
26
 
27
27
  // =============================================================================
@@ -450,7 +450,6 @@ async function renderHtmlToText(
450
450
  timeout: number,
451
451
  scratchDir: string,
452
452
  ): Promise<{ content: string; ok: boolean; method: string }> {
453
- await mkdir(scratchDir, { recursive: true });
454
453
  const tmpFile = path.join(scratchDir, `omp-${nanoid()}.html`);
455
454
 
456
455
  try {
@@ -479,7 +478,7 @@ async function renderHtmlToText(
479
478
  return { content: "", ok: false, method: "none" };
480
479
  } finally {
481
480
  try {
482
- await rm(tmpFile, { force: true });
481
+ await fs.rm(tmpFile, { force: true });
483
482
  } catch {}
484
483
  }
485
484
  }
@@ -498,13 +497,13 @@ function isLowQualityOutput(content: string): boolean {
498
497
  "please enable javascript",
499
498
  "browser not supported",
500
499
  ];
501
- if (content.length < 1024 && jsGated.some((t) => lower.includes(t))) {
500
+ if (content.length < 1024 && jsGated.some(t => lower.includes(t))) {
502
501
  return true;
503
502
  }
504
503
 
505
504
  // Mostly navigation (high link/menu density)
506
- const lines = content.split("\n").filter((l) => l.trim());
507
- const shortLines = lines.filter((l) => l.trim().length < 40);
505
+ const lines = content.split("\n").filter(l => l.trim());
506
+ const shortLines = lines.filter(l => l.trim().length < 40);
508
507
  if (lines.length > 10 && shortLines.length / lines.length > 0.7) {
509
508
  return true;
510
509
  }
@@ -695,7 +694,7 @@ async function renderUrl(
695
694
  if (isHtml && !raw) {
696
695
  // 5A: Check for page-specific markdown alternate
697
696
  const alternates = parseAlternateLinks(rawContent, finalUrl);
698
- const markdownAlt = alternates.find((alt) => alt.endsWith(".md") || alt.includes("markdown"));
697
+ const markdownAlt = alternates.find(alt => alt.endsWith(".md") || alt.includes("markdown"));
699
698
  if (markdownAlt) {
700
699
  const resolved = markdownAlt.startsWith("http") ? markdownAlt : new URL(markdownAlt, finalUrl).href;
701
700
  const altResult = await loadPage(resolved, { timeout, signal });
@@ -767,7 +766,7 @@ async function renderUrl(
767
766
  }
768
767
 
769
768
  // 5E: Check for feed alternates
770
- const feedAlternates = alternates.filter((alt) => !alt.endsWith(".md") && !alt.includes("markdown"));
769
+ const feedAlternates = alternates.filter(alt => !alt.endsWith(".md") && !alt.includes("markdown"));
771
770
  for (const altUrl of feedAlternates.slice(0, 2)) {
772
771
  const resolved = altUrl.startsWith("http") ? altUrl : new URL(altUrl, finalUrl).href;
773
772
  const altResult = await loadPage(resolved, { timeout, signal });
@@ -984,7 +983,7 @@ function getDomain(url: string): string {
984
983
 
985
984
  /** Count non-empty lines */
986
985
  function countNonEmptyLines(text: string): number {
987
- return text.split("\n").filter((l) => l.trim()).length;
986
+ return text.split("\n").filter(l => l.trim()).length;
988
987
  }
989
988
 
990
989
  /** Render fetch call (URL preview) */
@@ -1037,7 +1036,7 @@ export function renderFetchResult(
1037
1036
  : contentText;
1038
1037
  const lineCount = countNonEmptyLines(contentBody);
1039
1038
  const charCount = contentBody.trim().length;
1040
- const contentLines = contentBody.split("\n").filter((l) => l.trim());
1039
+ const contentLines = contentBody.split("\n").filter(l => l.trim());
1041
1040
 
1042
1041
  const metadataLines: string[] = [
1043
1042
  `${uiTheme.fg("muted", "Content-Type:")} ${details.contentType || "unknown"}`,
@@ -1061,12 +1060,10 @@ export function renderFetchResult(
1061
1060
 
1062
1061
  const previewLimit = expanded ? 12 : 3;
1063
1062
  const previewList = applyListLimit(contentLines, { headLimit: previewLimit });
1064
- const previewLines = previewList.items.map((line) => truncate(line.trimEnd(), 120, uiTheme.format.ellipsis));
1063
+ const previewLines = previewList.items.map(line => truncate(line.trimEnd(), 120, uiTheme.format.ellipsis));
1065
1064
  const remaining = Math.max(0, contentLines.length - previewLines.length);
1066
1065
  const contentPreviewLines =
1067
- previewLines.length > 0
1068
- ? previewLines.map((line) => uiTheme.fg("dim", line))
1069
- : [uiTheme.fg("dim", "(no content)")];
1066
+ previewLines.length > 0 ? previewLines.map(line => uiTheme.fg("dim", line)) : [uiTheme.fg("dim", "(no content)")];
1070
1067
  if (remaining > 0) {
1071
1068
  const hint = formatExpandHint(uiTheme, expanded, true);
1072
1069
  contentPreviewLines.push(
package/src/tools/find.ts CHANGED
@@ -1,24 +1,23 @@
1
1
  import path from "node:path";
2
2
  import type { AgentTool, AgentToolContext, AgentToolResult, AgentToolUpdateCallback } from "@oh-my-pi/pi-agent-core";
3
3
  import { StringEnum } from "@oh-my-pi/pi-ai";
4
- import { renderPromptTemplate } from "@oh-my-pi/pi-coding-agent/config/prompt-templates";
5
- import type { RenderResultOptions } from "@oh-my-pi/pi-coding-agent/extensibility/custom-tools/types";
6
- import type { Theme } from "@oh-my-pi/pi-coding-agent/modes/theme/theme";
7
- import findDescription from "@oh-my-pi/pi-coding-agent/prompts/tools/find.md" with { type: "text" };
8
- import type { OutputMeta } from "@oh-my-pi/pi-coding-agent/tools/output-meta";
9
- import { ToolAbortError, ToolError, throwIfAborted } from "@oh-my-pi/pi-coding-agent/tools/tool-errors";
10
- import { renderFileList, renderStatusLine, renderTreeList } from "@oh-my-pi/pi-coding-agent/tui";
11
- import { ensureTool } from "@oh-my-pi/pi-coding-agent/utils/tools-manager";
12
4
  import type { Component } from "@oh-my-pi/pi-tui";
13
5
  import { Text } from "@oh-my-pi/pi-tui";
14
6
  import { ptree, untilAborted } from "@oh-my-pi/pi-utils";
15
7
  import type { Static } from "@sinclair/typebox";
16
8
  import { Type } from "@sinclair/typebox";
17
-
9
+ import { renderPromptTemplate } from "../config/prompt-templates";
10
+ import type { RenderResultOptions } from "../extensibility/custom-tools/types";
11
+ import type { Theme } from "../modes/theme/theme";
12
+ import findDescription from "../prompts/tools/find.md" with { type: "text" };
13
+ import { renderFileList, renderStatusLine, renderTreeList } from "../tui";
14
+ import { ensureTool } from "../utils/tools-manager";
18
15
  import type { ToolSession } from ".";
19
16
  import { applyListLimit } from "./list-limit";
17
+ import type { OutputMeta } from "./output-meta";
20
18
  import { resolveToCwd } from "./path-utils";
21
19
  import { formatCount, formatEmptyMessage, formatErrorMessage, PREVIEW_LIMITS } from "./render-utils";
20
+ import { ToolAbortError, ToolError, throwIfAborted } from "./tool-errors";
22
21
  import { toolResult } from "./tool-result";
23
22
  import { type TruncationResult, truncateHead } from "./truncate";
24
23
 
@@ -164,7 +163,7 @@ export class FindTool implements AgentTool<typeof findSchema, FindToolDetails> {
164
163
  }
165
164
 
166
165
  // Relativize paths
167
- const relativized = results.map((p) => {
166
+ const relativized = results.map(p => {
168
167
  if (p.startsWith(searchPath)) {
169
168
  return p.slice(searchPath.length + 1);
170
169
  }
@@ -331,7 +330,7 @@ export class FindTool implements AgentTool<typeof findSchema, FindToolDetails> {
331
330
  const indexed = relativized.map((path, idx) => ({ path, mtime: mtimes[idx] }));
332
331
  indexed.sort((a, b) => b.mtime - a.mtime);
333
332
  relativized.length = 0;
334
- relativized.push(...indexed.map((item) => item.path));
333
+ relativized.push(...indexed.map(item => item.path));
335
334
  }
336
335
 
337
336
  const listLimit = applyListLimit(relativized, { limit: effectiveLimit });
@@ -405,12 +404,12 @@ export const findToolRenderer = {
405
404
  const details = result.details;
406
405
 
407
406
  if (result.isError || details?.error) {
408
- const errorText = details?.error || result.content?.find((c) => c.type === "text")?.text || "Unknown error";
407
+ const errorText = details?.error || result.content?.find(c => c.type === "text")?.text || "Unknown error";
409
408
  return new Text(formatErrorMessage(errorText, uiTheme), 0, 0);
410
409
  }
411
410
 
412
411
  const hasDetailedData = details?.fileCount !== undefined;
413
- const textContent = result.content?.find((c) => c.type === "text")?.text;
412
+ const textContent = result.content?.find(c => c.type === "text")?.text;
414
413
 
415
414
  if (!hasDetailedData) {
416
415
  if (
@@ -422,7 +421,7 @@ export const findToolRenderer = {
422
421
  return new Text(formatEmptyMessage("No files found", uiTheme), 0, 0);
423
422
  }
424
423
 
425
- const lines = textContent.split("\n").filter((l) => l.trim());
424
+ const lines = textContent.split("\n").filter(l => l.trim());
426
425
  const header = renderStatusLine(
427
426
  {
428
427
  icon: "success",
@@ -438,7 +437,7 @@ export const findToolRenderer = {
438
437
  expanded,
439
438
  maxCollapsed: COLLAPSED_LIST_LIMIT,
440
439
  itemType: "file",
441
- renderItem: (line) => uiTheme.fg("accent", line),
440
+ renderItem: line => uiTheme.fg("accent", line),
442
441
  },
443
442
  uiTheme,
444
443
  );
@@ -468,7 +467,7 @@ export const findToolRenderer = {
468
467
 
469
468
  const fileLines = renderFileList(
470
469
  {
471
- files: files.map((entry) => ({ path: entry, isDirectory: entry.endsWith("/") })),
470
+ files: files.map(entry => ({ path: entry, isDirectory: entry.endsWith("/") })),
472
471
  expanded,
473
472
  maxCollapsed: COLLAPSED_LIST_LIMIT,
474
473
  },
@@ -1,15 +1,15 @@
1
- import { tmpdir } from "node:os";
2
- import { join } from "node:path";
1
+ import * as os from "node:os";
2
+ import * as path from "node:path";
3
3
  import { StringEnum } from "@oh-my-pi/pi-ai";
4
- import type { ModelRegistry } from "@oh-my-pi/pi-coding-agent/config/model-registry";
5
- import { renderPromptTemplate } from "@oh-my-pi/pi-coding-agent/config/prompt-templates";
6
- import type { CustomTool } from "@oh-my-pi/pi-coding-agent/extensibility/custom-tools/types";
7
- import geminiImageDescription from "@oh-my-pi/pi-coding-agent/prompts/tools/gemini-image.md" with { type: "text" };
8
- import { detectSupportedImageMimeTypeFromFile } from "@oh-my-pi/pi-coding-agent/utils/mime";
9
- import { getEnv } from "@oh-my-pi/pi-coding-agent/web/search/auth";
10
4
  import { untilAborted } from "@oh-my-pi/pi-utils";
11
5
  import { type Static, Type } from "@sinclair/typebox";
12
6
  import { nanoid } from "nanoid";
7
+ import type { ModelRegistry } from "../config/model-registry";
8
+ import { renderPromptTemplate } from "../config/prompt-templates";
9
+ import type { CustomTool } from "../extensibility/custom-tools/types";
10
+ import geminiImageDescription from "../prompts/tools/gemini-image.md" with { type: "text" };
11
+ import { detectSupportedImageMimeTypeFromFile } from "../utils/mime";
12
+ import { getEnv } from "../web/search/auth";
13
13
  import { resolveReadPath } from "./path-utils";
14
14
 
15
15
  const DEFAULT_MODEL = "gemini-3-pro-image-preview";
@@ -151,7 +151,7 @@ function assemblePrompt(params: GeminiImageParams): string {
151
151
  if (params.style) parts.push(params.style);
152
152
 
153
153
  // Join with periods for sentence structure
154
- let prompt = `${parts.map((p) => p.replace(/[.!,;:]+$/, "")).join(". ")}.`;
154
+ let prompt = `${parts.map(p => p.replace(/[.!,;:]+$/, "")).join(". ")}.`;
155
155
 
156
156
  // Text rendering specs
157
157
  if (params.text) {
@@ -160,7 +160,7 @@ function assemblePrompt(params: GeminiImageParams): string {
160
160
 
161
161
  // Edit mode: changes and preserve directives
162
162
  if (params.changes?.length) {
163
- prompt += `\n\nChanges:\n${params.changes.map((c) => `- ${c}`).join("\n")}`;
163
+ prompt += `\n\nChanges:\n${params.changes.map(c => `- ${c}`).join("\n")}`;
164
164
  if (params.preserve) {
165
165
  prompt += `\n\nPreserve: ${params.preserve}`;
166
166
  }
@@ -330,8 +330,8 @@ function collectOpenRouterResponseText(message: OpenRouterMessage | undefined):
330
330
  }
331
331
  if (Array.isArray(message.content)) {
332
332
  const texts = message.content
333
- .filter((part) => part.type === "text")
334
- .map((part) => part.text)
333
+ .filter(part => part.type === "text")
334
+ .map(part => part.text)
335
335
  .filter((text): text is string => Boolean(text));
336
336
  const combined = texts.join("\n").trim();
337
337
  return combined.length > 0 ? combined : undefined;
@@ -489,7 +489,7 @@ function getExtensionForMime(mimeType: string): string {
489
489
  async function saveImageToTemp(image: InlineImageData): Promise<string> {
490
490
  const ext = getExtensionForMime(image.mimeType);
491
491
  const filename = `omp-image-${nanoid()}.${ext}`;
492
- const filepath = join(tmpdir(), filename);
492
+ const filepath = path.join(os.tmpdir(), filename);
493
493
  await Bun.write(filepath, Buffer.from(image.data, "base64"));
494
494
  return filepath;
495
495
  }
@@ -515,7 +515,7 @@ function buildResponseSummary(
515
515
  }
516
516
 
517
517
  function collectResponseText(parts: GeminiPart[]): string | undefined {
518
- const texts = parts.map((part) => part.text).filter((text): text is string => Boolean(text));
518
+ const texts = parts.map(part => part.text).filter((text): text is string => Boolean(text));
519
519
  const combined = texts.join("\n").trim();
520
520
  return combined.length > 0 ? combined : undefined;
521
521
  }
package/src/tools/grep.ts CHANGED
@@ -1,24 +1,24 @@
1
1
  import nodePath from "node:path";
2
2
  import type { AgentTool, AgentToolContext, AgentToolResult, AgentToolUpdateCallback } from "@oh-my-pi/pi-agent-core";
3
3
  import { StringEnum } from "@oh-my-pi/pi-ai";
4
- import { renderPromptTemplate } from "@oh-my-pi/pi-coding-agent/config/prompt-templates";
5
- import type { RenderResultOptions } from "@oh-my-pi/pi-coding-agent/extensibility/custom-tools/types";
6
- import type { Theme } from "@oh-my-pi/pi-coding-agent/modes/theme/theme";
7
- import grepDescription from "@oh-my-pi/pi-coding-agent/prompts/tools/grep.md" with { type: "text" };
8
- import type { OutputMeta } from "@oh-my-pi/pi-coding-agent/tools/output-meta";
9
- import { ToolAbortError, ToolError } from "@oh-my-pi/pi-coding-agent/tools/tool-errors";
10
- import { renderFileList, renderStatusLine, renderTreeList } from "@oh-my-pi/pi-coding-agent/tui";
11
- import { ensureTool } from "@oh-my-pi/pi-coding-agent/utils/tools-manager";
12
- import { untilAborted } from "@oh-my-pi/pi-coding-agent/utils/utils";
13
4
  import type { Component } from "@oh-my-pi/pi-tui";
14
5
  import { Text } from "@oh-my-pi/pi-tui";
15
6
  import { ptree, readLines } from "@oh-my-pi/pi-utils";
16
7
  import { Type } from "@sinclair/typebox";
17
8
  import { $ } from "bun";
9
+ import { renderPromptTemplate } from "../config/prompt-templates";
10
+ import type { RenderResultOptions } from "../extensibility/custom-tools/types";
11
+ import type { Theme } from "../modes/theme/theme";
12
+ import grepDescription from "../prompts/tools/grep.md" with { type: "text" };
13
+ import { renderFileList, renderStatusLine, renderTreeList } from "../tui";
14
+ import { ensureTool } from "../utils/tools-manager";
15
+ import { untilAborted } from "../utils/utils";
18
16
  import type { ToolSession } from ".";
19
17
  import { applyListLimit } from "./list-limit";
18
+ import type { OutputMeta } from "./output-meta";
20
19
  import { resolveToCwd } from "./path-utils";
21
20
  import { formatCount, formatEmptyMessage, formatErrorMessage, PREVIEW_LIMITS } from "./render-utils";
21
+ import { ToolAbortError, ToolError } from "./tool-errors";
22
22
  import { toolResult } from "./tool-result";
23
23
  import { DEFAULT_MAX_COLUMN, type TruncationResult, truncateHead, truncateLine } from "./truncate";
24
24
 
@@ -73,8 +73,8 @@ export interface GrepOperations {
73
73
  }
74
74
 
75
75
  const defaultGrepOperations: GrepOperations = {
76
- isDirectory: async (p) => (await Bun.file(p).stat()).isDirectory(),
77
- readFile: (p) => Bun.file(p).text(),
76
+ isDirectory: async p => (await Bun.file(p).stat()).isDirectory(),
77
+ readFile: p => Bun.file(p).text(),
78
78
  };
79
79
 
80
80
  export interface GrepToolOptions {
@@ -287,7 +287,7 @@ export class GrepTool implements AgentTool<typeof grepSchema, GrepToolDetails> {
287
287
 
288
288
  // For simple output modes (files_with_matches, count), process text directly
289
289
  if (effectiveOutputMode === "files_with_matches" || effectiveOutputMode === "count") {
290
- const stdout = await child.text().catch((x) => {
290
+ const stdout = await child.text().catch(x => {
291
291
  if (x instanceof ptree.Exception && x.exitCode === 1) {
292
292
  return "";
293
293
  }
@@ -303,7 +303,7 @@ export class GrepTool implements AgentTool<typeof grepSchema, GrepToolDetails> {
303
303
  const lines = stdout
304
304
  .trim()
305
305
  .split("\n")
306
- .filter((line) => line.length > 0);
306
+ .filter(line => line.length > 0);
307
307
 
308
308
  if (lines.length === 0) {
309
309
  const details: GrepToolDetails = {
@@ -371,7 +371,7 @@ export class GrepTool implements AgentTool<typeof grepSchema, GrepToolDetails> {
371
371
 
372
372
  // For count mode, format as "path:count"
373
373
  if (effectiveOutputMode === "count") {
374
- const formatted = processedLines.map((line) => {
374
+ const formatted = processedLines.map(line => {
375
375
  const separatorIndex = line.lastIndexOf(":");
376
376
  const relative = formatPath(separatorIndex === -1 ? line : line.slice(0, separatorIndex));
377
377
  const count = separatorIndex === -1 ? "0" : line.slice(separatorIndex + 1);
@@ -383,7 +383,7 @@ export class GrepTool implements AgentTool<typeof grepSchema, GrepToolDetails> {
383
383
  matchCount: simpleMatchCount,
384
384
  fileCount,
385
385
  files: simpleFileList,
386
- fileMatches: simpleFileList.map((path) => ({
386
+ fileMatches: simpleFileList.map(path => ({
387
387
  path,
388
388
  count: simpleFileMatchCounts.get(path) ?? 0,
389
389
  })),
@@ -401,7 +401,7 @@ export class GrepTool implements AgentTool<typeof grepSchema, GrepToolDetails> {
401
401
  }
402
402
 
403
403
  // For files_with_matches, format paths
404
- const formatted = processedLines.map((line) => formatPath(line));
404
+ const formatted = processedLines.map(line => formatPath(line));
405
405
  const output = formatted.join("\n");
406
406
  const details: GrepToolDetails = {
407
407
  scopePath,
@@ -547,7 +547,7 @@ export class GrepTool implements AgentTool<typeof grepSchema, GrepToolDetails> {
547
547
  matchCount,
548
548
  fileCount: files.size,
549
549
  files: fileList,
550
- fileMatches: fileList.map((path) => ({
550
+ fileMatches: fileList.map(path => ({
551
551
  path,
552
552
  count: fileMatchCounts.get(path) ?? 0,
553
553
  })),
@@ -632,18 +632,18 @@ export const grepToolRenderer = {
632
632
  const details = result.details;
633
633
 
634
634
  if (result.isError || details?.error) {
635
- const errorText = details?.error || result.content?.find((c) => c.type === "text")?.text || "Unknown error";
635
+ const errorText = details?.error || result.content?.find(c => c.type === "text")?.text || "Unknown error";
636
636
  return new Text(formatErrorMessage(errorText, uiTheme), 0, 0);
637
637
  }
638
638
 
639
639
  const hasDetailedData = details?.matchCount !== undefined || details?.fileCount !== undefined;
640
640
 
641
641
  if (!hasDetailedData) {
642
- const textContent = result.content?.find((c) => c.type === "text")?.text;
642
+ const textContent = result.content?.find(c => c.type === "text")?.text;
643
643
  if (!textContent || textContent === "No matches found") {
644
644
  return new Text(formatEmptyMessage("No matches found", uiTheme), 0, 0);
645
645
  }
646
- const lines = textContent.split("\n").filter((line) => line.trim() !== "");
646
+ const lines = textContent.split("\n").filter(line => line.trim() !== "");
647
647
  const description = args?.pattern ?? undefined;
648
648
  const header = renderStatusLine(
649
649
  { icon: "success", title: "Grep", description, meta: [formatCount("item", lines.length)] },
@@ -655,7 +655,7 @@ export const grepToolRenderer = {
655
655
  expanded,
656
656
  maxCollapsed: COLLAPSED_TEXT_LIMIT,
657
657
  itemType: "item",
658
- renderItem: (line) => uiTheme.fg("toolOutput", line),
658
+ renderItem: line => uiTheme.fg("toolOutput", line),
659
659
  },
660
660
  uiTheme,
661
661
  );
@@ -699,15 +699,15 @@ export const grepToolRenderer = {
699
699
  );
700
700
 
701
701
  if (mode === "content") {
702
- const textContent = result.content?.find((c) => c.type === "text")?.text ?? "";
703
- const contentLines = textContent.split("\n").filter((line) => line.trim().length > 0);
702
+ const textContent = result.content?.find(c => c.type === "text")?.text ?? "";
703
+ const contentLines = textContent.split("\n").filter(line => line.trim().length > 0);
704
704
  const matchLines = renderTreeList(
705
705
  {
706
706
  items: contentLines,
707
707
  expanded,
708
708
  maxCollapsed: COLLAPSED_TEXT_LIMIT,
709
709
  itemType: "match",
710
- renderItem: (line) => uiTheme.fg("toolOutput", line),
710
+ renderItem: line => uiTheme.fg("toolOutput", line),
711
711
  },
712
712
  uiTheme,
713
713
  );
@@ -715,11 +715,11 @@ export const grepToolRenderer = {
715
715
  }
716
716
 
717
717
  const fileEntries: Array<{ path: string; count?: number }> = details?.fileMatches?.length
718
- ? details.fileMatches.map((entry) => ({ path: entry.path, count: entry.count }))
719
- : files.map((path) => ({ path }));
718
+ ? details.fileMatches.map(entry => ({ path: entry.path, count: entry.count }))
719
+ : files.map(path => ({ path }));
720
720
  const fileLines = renderFileList(
721
721
  {
722
- files: fileEntries.map((entry) => ({
722
+ files: fileEntries.map(entry => ({
723
723
  path: entry.path,
724
724
  isDirectory: entry.path.endsWith("/"),
725
725
  meta: entry.count !== undefined ? `(${entry.count} match${entry.count !== 1 ? "es" : ""})` : undefined,
@@ -1,6 +1,38 @@
1
+ import type { AgentTool } from "@oh-my-pi/pi-agent-core";
2
+ import { logger } from "@oh-my-pi/pi-utils";
3
+ import type { BashInterceptorRule } from "../config/settings-manager";
4
+ import type { InternalUrlRouter } from "../internal-urls";
5
+ import { getPreludeDocs, warmPythonEnvironment } from "../ipy/executor";
6
+ import { checkPythonKernelAvailability } from "../ipy/kernel";
7
+ import { LspTool } from "../lsp";
8
+ import { EditTool } from "../patch";
9
+ import type { ArtifactManager } from "../session/artifacts";
10
+ import { TaskTool } from "../task";
11
+ import type { AgentOutputManager } from "../task/output-manager";
12
+ import type { EventBus } from "../utils/event-bus";
13
+ import { time } from "../utils/timings";
14
+ import { WebSearchTool } from "../web/search";
15
+ import { AskTool } from "./ask";
16
+ import { BashTool } from "./bash";
17
+ import { CalculatorTool } from "./calculator";
18
+ import { CompleteTool } from "./complete";
19
+ import { FetchTool } from "./fetch";
20
+ import { FindTool } from "./find";
21
+ import { GrepTool } from "./grep";
22
+ import { LsTool } from "./ls";
23
+ import { NotebookTool } from "./notebook";
24
+ import { wrapToolsWithMetaNotice } from "./output-meta";
25
+ import { PythonTool } from "./python";
26
+ import { ReadTool } from "./read";
27
+ import { reportFindingTool } from "./review";
28
+ import { loadSshTool } from "./ssh";
29
+ import { TodoWriteTool } from "./todo-write";
30
+ import { WriteTool } from "./write";
31
+
1
32
  // Exa MCP tools (22 tools)
2
- export { exaTools } from "@oh-my-pi/pi-coding-agent/exa";
3
- export type { ExaRenderDetails, ExaSearchResponse, ExaSearchResult } from "@oh-my-pi/pi-coding-agent/exa/types";
33
+
34
+ export { exaTools } from "../exa";
35
+ export type { ExaRenderDetails, ExaSearchResponse, ExaSearchResult } from "../exa/types";
4
36
  export {
5
37
  type FileDiagnosticsResult,
6
38
  type FileFormatResult,
@@ -11,9 +43,9 @@ export {
11
43
  type LspWarmupOptions,
12
44
  type LspWarmupResult,
13
45
  warmupLspServers,
14
- } from "@oh-my-pi/pi-coding-agent/lsp";
15
- export { EditTool, type EditToolDetails } from "@oh-my-pi/pi-coding-agent/patch";
16
- export { BUNDLED_AGENTS, TaskTool } from "@oh-my-pi/pi-coding-agent/task";
46
+ } from "../lsp";
47
+ export { EditTool, type EditToolDetails } from "../patch";
48
+ export { BUNDLED_AGENTS, TaskTool } from "../task";
17
49
  export {
18
50
  companyWebSearchTools,
19
51
  exaWebSearchTools,
@@ -31,7 +63,7 @@ export {
31
63
  webSearchCustomTool,
32
64
  webSearchDeepTool,
33
65
  webSearchLinkedinTool,
34
- } from "@oh-my-pi/pi-coding-agent/web/search";
66
+ } from "../web/search";
35
67
  export { AskTool, type AskToolDetails } from "./ask";
36
68
  export { BashTool, type BashToolDetails, type BashToolOptions } from "./bash";
37
69
  export { CalculatorTool, type CalculatorToolDetails } from "./calculator";
@@ -59,36 +91,6 @@ export {
59
91
  } from "./truncate";
60
92
  export { WriteTool, type WriteToolDetails } from "./write";
61
93
 
62
- import type { AgentTool } from "@oh-my-pi/pi-agent-core";
63
- import type { BashInterceptorRule } from "@oh-my-pi/pi-coding-agent/config/settings-manager";
64
- import type { InternalUrlRouter } from "@oh-my-pi/pi-coding-agent/internal-urls";
65
- import { getPreludeDocs, warmPythonEnvironment } from "@oh-my-pi/pi-coding-agent/ipy/executor";
66
- import { checkPythonKernelAvailability } from "@oh-my-pi/pi-coding-agent/ipy/kernel";
67
- import { LspTool } from "@oh-my-pi/pi-coding-agent/lsp";
68
- import { EditTool } from "@oh-my-pi/pi-coding-agent/patch";
69
- import type { ArtifactManager } from "@oh-my-pi/pi-coding-agent/session/artifacts";
70
- import { TaskTool } from "@oh-my-pi/pi-coding-agent/task";
71
- import type { AgentOutputManager } from "@oh-my-pi/pi-coding-agent/task/output-manager";
72
- import type { EventBus } from "@oh-my-pi/pi-coding-agent/utils/event-bus";
73
- import { WebSearchTool } from "@oh-my-pi/pi-coding-agent/web/search";
74
- import { logger } from "@oh-my-pi/pi-utils";
75
- import { AskTool } from "./ask";
76
- import { BashTool } from "./bash";
77
- import { CalculatorTool } from "./calculator";
78
- import { CompleteTool } from "./complete";
79
- import { FetchTool } from "./fetch";
80
- import { FindTool } from "./find";
81
- import { GrepTool } from "./grep";
82
- import { LsTool } from "./ls";
83
- import { NotebookTool } from "./notebook";
84
- import { wrapToolsWithMetaNotice } from "./output-meta";
85
- import { PythonTool } from "./python";
86
- import { ReadTool } from "./read";
87
- import { reportFindingTool } from "./review";
88
- import { loadSshTool } from "./ssh";
89
- import { TodoWriteTool } from "./todo-write";
90
- import { WriteTool } from "./write";
91
-
92
94
  /** Tool type (AgentTool from pi-ai) */
93
95
  export type Tool = AgentTool<any, any, any>;
94
96
 
@@ -153,26 +155,26 @@ type ToolFactory = (session: ToolSession) => Tool | null | Promise<Tool | null>;
153
155
 
154
156
  export const BUILTIN_TOOLS: Record<string, ToolFactory> = {
155
157
  ask: AskTool.createIf,
156
- bash: (s) => new BashTool(s),
157
- python: (s) => new PythonTool(s),
158
- calc: (s) => new CalculatorTool(s),
158
+ bash: s => new BashTool(s),
159
+ python: s => new PythonTool(s),
160
+ calc: s => new CalculatorTool(s),
159
161
  ssh: loadSshTool,
160
- edit: (s) => new EditTool(s),
161
- find: (s) => new FindTool(s),
162
- grep: (s) => new GrepTool(s),
163
- ls: (s) => new LsTool(s),
162
+ edit: s => new EditTool(s),
163
+ find: s => new FindTool(s),
164
+ grep: s => new GrepTool(s),
165
+ ls: s => new LsTool(s),
164
166
  lsp: LspTool.createIf,
165
- notebook: (s) => new NotebookTool(s),
166
- read: (s) => new ReadTool(s),
167
+ notebook: s => new NotebookTool(s),
168
+ read: s => new ReadTool(s),
167
169
  task: TaskTool.create,
168
- todo_write: (s) => new TodoWriteTool(s),
169
- fetch: (s) => new FetchTool(s),
170
- web_search: (s) => new WebSearchTool(s),
171
- write: (s) => new WriteTool(s),
170
+ todo_write: s => new TodoWriteTool(s),
171
+ fetch: s => new FetchTool(s),
172
+ web_search: s => new WebSearchTool(s),
173
+ write: s => new WriteTool(s),
172
174
  };
173
175
 
174
176
  export const HIDDEN_TOOLS: Record<string, ToolFactory> = {
175
- complete: (s) => new CompleteTool(s),
177
+ complete: s => new CompleteTool(s),
176
178
  report_finding: () => reportFindingTool,
177
179
  };
178
180
 
@@ -212,6 +214,7 @@ function getPythonModeFromEnv(): PythonToolMode | null {
212
214
  * Create tools from BUILTIN_TOOLS registry.
213
215
  */
214
216
  export async function createTools(session: ToolSession, toolNames?: string[]): Promise<Tool[]> {
217
+ time("createTools:start");
215
218
  const includeComplete = session.requireCompleteTool === true;
216
219
  const enableLsp = session.enableLsp ?? true;
217
220
  const requestedTools = toolNames && toolNames.length > 0 ? [...new Set(toolNames)] : undefined;
@@ -221,18 +224,21 @@ export async function createTools(session: ToolSession, toolNames?: string[]): P
221
224
  pythonMode !== "bash-only" &&
222
225
  (requestedTools === undefined || requestedTools.includes("python") || pythonMode === "ipy-only");
223
226
  const isTestEnv = process.env.BUN_ENV === "test" || process.env.NODE_ENV === "test";
227
+ const skipPythonWarm = isTestEnv || process.env.OMP_PYTHON_SKIP_CHECK === "1";
224
228
  if (shouldCheckPython) {
225
229
  const availability = await checkPythonKernelAvailability(session.cwd);
230
+ time("createTools:pythonCheck");
226
231
  pythonAvailable = availability.ok;
227
232
  if (!availability.ok) {
228
233
  logger.warn("Python kernel unavailable, falling back to bash", {
229
234
  reason: availability.reason,
230
235
  });
231
- } else if (!isTestEnv && getPreludeDocs().length === 0) {
236
+ } else if (!skipPythonWarm && getPreludeDocs().length === 0) {
232
237
  const sessionFile = session.getSessionFile?.() ?? undefined;
233
238
  const warmSessionId = sessionFile ? `session:${sessionFile}:cwd:${session.cwd}` : `cwd:${session.cwd}`;
234
239
  try {
235
240
  await warmPythonEnvironment(session.cwd, warmSessionId, session.settings?.getPythonSharedGateway?.());
241
+ time("createTools:warmPython");
236
242
  } catch (err) {
237
243
  logger.warn("Failed to warm Python environment", {
238
244
  error: err instanceof Error ? err.message : String(err),
@@ -264,22 +270,38 @@ export async function createTools(session: ToolSession, toolNames?: string[]): P
264
270
  requestedTools.push("complete");
265
271
  }
266
272
 
267
- const filteredRequestedTools = requestedTools?.filter((name) => name in allTools && isToolAllowed(name));
273
+ const filteredRequestedTools = requestedTools?.filter(name => name in allTools && isToolAllowed(name));
268
274
 
269
275
  const entries =
270
276
  filteredRequestedTools !== undefined
271
- ? filteredRequestedTools.map((name) => [name, allTools[name]] as const)
277
+ ? filteredRequestedTools.map(name => [name, allTools[name]] as const)
272
278
  : [
273
279
  ...Object.entries(BUILTIN_TOOLS).filter(([name]) => isToolAllowed(name)),
274
280
  ...(includeComplete ? ([["complete", HIDDEN_TOOLS.complete]] as const) : []),
275
281
  ];
276
- const results = await Promise.all(entries.map(([, factory]) => factory(session)));
277
- const tools = results.filter((t): t is Tool => t !== null);
282
+ time("createTools:beforeFactories");
283
+ const slowTools: Array<{ name: string; ms: number }> = [];
284
+ const results = await Promise.all(
285
+ entries.map(async ([name, factory]) => {
286
+ const start = performance.now();
287
+ const tool = await factory(session);
288
+ const elapsed = performance.now() - start;
289
+ if (elapsed > 5) {
290
+ slowTools.push({ name, ms: Math.round(elapsed) });
291
+ }
292
+ return { name, tool };
293
+ }),
294
+ );
295
+ time("createTools:afterFactories");
296
+ if (slowTools.length > 0 && process.env.OMP_TIMING === "1") {
297
+ logger.debug("Tool factory timings", { slowTools });
298
+ }
299
+ const tools = results.filter(r => r.tool !== null).map(r => r.tool as Tool);
278
300
  const wrappedTools = wrapToolsWithMetaNotice(tools);
279
301
 
280
302
  if (filteredRequestedTools !== undefined) {
281
303
  const allowed = new Set(filteredRequestedTools);
282
- return wrappedTools.filter((tool) => allowed.has(tool.name));
304
+ return wrappedTools.filter(tool => allowed.has(tool.name));
283
305
  }
284
306
 
285
307
  return wrappedTools;