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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (421) hide show
  1. package/CHANGELOG.md +125 -0
  2. package/docs/session.md +111 -46
  3. package/examples/custom-tools/hello/index.ts +1 -1
  4. package/examples/custom-tools/todo/index.ts +3 -4
  5. package/examples/extensions/api-demo.ts +0 -1
  6. package/examples/extensions/chalk-logger.ts +2 -3
  7. package/examples/extensions/hello.ts +0 -1
  8. package/examples/extensions/pirate.ts +0 -1
  9. package/examples/extensions/plan-mode.ts +15 -16
  10. package/examples/extensions/todo.ts +3 -4
  11. package/examples/extensions/tools.ts +1 -2
  12. package/examples/extensions/with-deps/index.ts +0 -1
  13. package/examples/hooks/auto-commit-on-exit.ts +1 -2
  14. package/examples/hooks/confirm-destructive.ts +0 -1
  15. package/examples/hooks/custom-compaction.ts +1 -2
  16. package/examples/hooks/dirty-repo-guard.ts +0 -1
  17. package/examples/hooks/file-trigger.ts +3 -4
  18. package/examples/hooks/git-checkpoint.ts +0 -1
  19. package/examples/hooks/handoff.ts +3 -4
  20. package/examples/hooks/permission-gate.ts +1 -2
  21. package/examples/hooks/protected-paths.ts +1 -2
  22. package/examples/hooks/qna.ts +2 -3
  23. package/examples/hooks/snake.ts +4 -5
  24. package/examples/hooks/status-line.ts +0 -1
  25. package/examples/sdk/01-minimal.ts +2 -3
  26. package/examples/sdk/02-custom-model.ts +2 -3
  27. package/examples/sdk/03-custom-prompt.ts +3 -4
  28. package/examples/sdk/04-skills.ts +2 -3
  29. package/examples/sdk/06-extensions.ts +1 -2
  30. package/examples/sdk/06-hooks.ts +6 -7
  31. package/examples/sdk/07-context-files.ts +0 -1
  32. package/examples/sdk/08-prompt-templates.ts +0 -1
  33. package/examples/sdk/08-slash-commands.ts +0 -1
  34. package/examples/sdk/09-api-keys-and-oauth.ts +0 -1
  35. package/examples/sdk/10-settings.ts +0 -1
  36. package/examples/sdk/11-sessions.ts +0 -1
  37. package/package.json +54 -23
  38. package/scripts/format-prompts.ts +0 -1
  39. package/src/capability/context-file.ts +3 -4
  40. package/src/capability/extension-module.ts +3 -4
  41. package/src/capability/extension.ts +3 -4
  42. package/src/capability/fs.ts +20 -21
  43. package/src/capability/hook.ts +3 -4
  44. package/src/capability/index.ts +15 -16
  45. package/src/capability/instruction.ts +3 -4
  46. package/src/capability/mcp.ts +3 -4
  47. package/src/capability/prompt.ts +3 -4
  48. package/src/capability/rule.ts +3 -4
  49. package/src/capability/settings.ts +2 -3
  50. package/src/capability/skill.ts +3 -4
  51. package/src/capability/slash-command.ts +3 -4
  52. package/src/capability/ssh.ts +3 -4
  53. package/src/capability/system-prompt.ts +3 -4
  54. package/src/capability/tool.ts +3 -4
  55. package/src/cli/args.ts +5 -6
  56. package/src/cli/config-cli.ts +6 -7
  57. package/src/cli/file-processor.ts +19 -17
  58. package/src/cli/jupyter-cli.ts +105 -0
  59. package/src/cli/list-models.ts +10 -11
  60. package/src/cli/plugin-cli.ts +20 -25
  61. package/src/cli/session-picker.ts +2 -3
  62. package/src/cli/setup-cli.ts +2 -3
  63. package/src/cli/stats-cli.ts +2 -3
  64. package/src/cli/update-cli.ts +25 -22
  65. package/src/commit/agentic/agent.ts +307 -0
  66. package/src/commit/agentic/fallback.ts +96 -0
  67. package/src/commit/agentic/index.ts +351 -0
  68. package/src/commit/agentic/prompts/analyze-file.md +22 -0
  69. package/src/commit/agentic/prompts/session-user.md +26 -0
  70. package/src/commit/agentic/prompts/split-confirm.md +1 -0
  71. package/src/commit/agentic/prompts/system.md +40 -0
  72. package/src/commit/agentic/state.ts +69 -0
  73. package/src/commit/agentic/tools/analyze-file.ts +131 -0
  74. package/src/commit/agentic/tools/git-file-diff.ts +194 -0
  75. package/src/commit/agentic/tools/git-hunk.ts +50 -0
  76. package/src/commit/agentic/tools/git-overview.ts +84 -0
  77. package/src/commit/agentic/tools/index.ts +56 -0
  78. package/src/commit/agentic/tools/propose-changelog.ts +128 -0
  79. package/src/commit/agentic/tools/propose-commit.ts +154 -0
  80. package/src/commit/agentic/tools/recent-commits.ts +81 -0
  81. package/src/commit/agentic/tools/split-commit.ts +280 -0
  82. package/src/commit/agentic/topo-sort.ts +44 -0
  83. package/src/commit/agentic/trivial.ts +51 -0
  84. package/src/commit/agentic/validation.ts +200 -0
  85. package/src/commit/analysis/conventional.ts +165 -0
  86. package/src/commit/analysis/index.ts +4 -0
  87. package/src/commit/analysis/scope.ts +242 -0
  88. package/src/commit/analysis/summary.ts +112 -0
  89. package/src/commit/analysis/validation.ts +66 -0
  90. package/src/commit/changelog/detect.ts +36 -0
  91. package/src/commit/changelog/generate.ts +110 -0
  92. package/src/commit/changelog/index.ts +233 -0
  93. package/src/commit/changelog/parse.ts +44 -0
  94. package/src/commit/cli.ts +93 -0
  95. package/src/commit/git/diff.ts +148 -0
  96. package/src/commit/git/errors.ts +11 -0
  97. package/src/commit/git/index.ts +212 -0
  98. package/src/commit/git/operations.ts +53 -0
  99. package/src/commit/index.ts +5 -0
  100. package/src/commit/map-reduce/index.ts +63 -0
  101. package/src/commit/map-reduce/map-phase.ts +178 -0
  102. package/src/commit/map-reduce/reduce-phase.ts +145 -0
  103. package/src/commit/map-reduce/utils.ts +9 -0
  104. package/src/commit/message.ts +11 -0
  105. package/src/commit/model-selection.ts +80 -0
  106. package/src/commit/pipeline.ts +240 -0
  107. package/src/commit/prompts/analysis-system.md +155 -0
  108. package/src/commit/prompts/analysis-user.md +41 -0
  109. package/src/commit/prompts/changelog-system.md +56 -0
  110. package/src/commit/prompts/changelog-user.md +19 -0
  111. package/src/commit/prompts/file-observer-system.md +26 -0
  112. package/src/commit/prompts/file-observer-user.md +9 -0
  113. package/src/commit/prompts/reduce-system.md +60 -0
  114. package/src/commit/prompts/reduce-user.md +17 -0
  115. package/src/commit/prompts/summary-retry.md +4 -0
  116. package/src/commit/prompts/summary-system.md +52 -0
  117. package/src/commit/prompts/summary-user.md +13 -0
  118. package/src/commit/prompts/types-description.md +2 -0
  119. package/src/commit/types.ts +109 -0
  120. package/src/commit/utils/exclusions.ts +42 -0
  121. package/src/config/file-lock.ts +121 -0
  122. package/src/config/keybindings.ts +6 -8
  123. package/src/config/model-registry.ts +65 -38
  124. package/src/config/model-resolver.ts +18 -19
  125. package/src/config/prompt-templates.ts +11 -11
  126. package/src/config/settings-manager.ts +141 -50
  127. package/src/config.ts +64 -66
  128. package/src/cursor.ts +11 -9
  129. package/src/discovery/agents-md.ts +11 -12
  130. package/src/discovery/builtin.ts +68 -73
  131. package/src/discovery/claude.ts +41 -42
  132. package/src/discovery/cline.ts +11 -12
  133. package/src/discovery/codex.ts +52 -53
  134. package/src/discovery/cursor.ts +9 -10
  135. package/src/discovery/gemini.ts +17 -22
  136. package/src/discovery/github.ts +13 -14
  137. package/src/discovery/helpers.ts +35 -34
  138. package/src/discovery/index.ts +22 -24
  139. package/src/discovery/mcp-json.ts +8 -9
  140. package/src/discovery/ssh.ts +8 -9
  141. package/src/discovery/vscode.ts +4 -5
  142. package/src/discovery/windsurf.ts +6 -7
  143. package/src/exa/company.ts +1 -2
  144. package/src/exa/index.ts +2 -3
  145. package/src/exa/linkedin.ts +1 -2
  146. package/src/exa/mcp-client.ts +14 -16
  147. package/src/exa/render.ts +10 -11
  148. package/src/exa/researcher.ts +1 -2
  149. package/src/exa/search.ts +1 -2
  150. package/src/exa/types.ts +0 -1
  151. package/src/exa/websets.ts +1 -2
  152. package/src/exec/bash-executor.ts +3 -4
  153. package/src/exec/exec.ts +0 -1
  154. package/src/export/custom-share.ts +5 -6
  155. package/src/export/html/index.ts +24 -21
  156. package/src/export/ttsr.ts +2 -3
  157. package/src/extensibility/custom-commands/bundled/review/index.ts +7 -8
  158. package/src/extensibility/custom-commands/loader.ts +18 -15
  159. package/src/extensibility/custom-commands/types.ts +2 -3
  160. package/src/extensibility/custom-tools/loader.ts +11 -12
  161. package/src/extensibility/custom-tools/types.ts +7 -8
  162. package/src/extensibility/custom-tools/wrapper.ts +2 -3
  163. package/src/extensibility/extensions/loader.ts +76 -54
  164. package/src/extensibility/extensions/runner.ts +11 -12
  165. package/src/extensibility/extensions/types.ts +20 -27
  166. package/src/extensibility/extensions/wrapper.ts +3 -4
  167. package/src/extensibility/hooks/index.ts +1 -1
  168. package/src/extensibility/hooks/loader.ts +9 -10
  169. package/src/extensibility/hooks/runner.ts +7 -8
  170. package/src/extensibility/hooks/tool-wrapper.ts +0 -1
  171. package/src/extensibility/hooks/types.ts +11 -18
  172. package/src/extensibility/plugins/doctor.ts +3 -3
  173. package/src/extensibility/plugins/installer.ts +27 -27
  174. package/src/extensibility/plugins/loader.ts +59 -56
  175. package/src/extensibility/plugins/manager.ts +211 -171
  176. package/src/extensibility/plugins/parser.ts +1 -1
  177. package/src/extensibility/plugins/paths.ts +8 -8
  178. package/src/extensibility/skills.ts +63 -60
  179. package/src/extensibility/slash-commands.ts +10 -10
  180. package/src/index.ts +54 -54
  181. package/src/internal-urls/agent-protocol.ts +21 -11
  182. package/src/internal-urls/artifact-protocol.ts +17 -13
  183. package/src/internal-urls/router.ts +1 -2
  184. package/src/internal-urls/rule-protocol.ts +3 -4
  185. package/src/internal-urls/skill-protocol.ts +3 -4
  186. package/src/ipy/executor.ts +109 -9
  187. package/src/ipy/gateway-coordinator.ts +79 -90
  188. package/src/ipy/kernel.ts +32 -30
  189. package/src/ipy/modules.ts +13 -13
  190. package/src/lsp/client.ts +21 -10
  191. package/src/lsp/clients/biome-client.ts +1 -2
  192. package/src/lsp/clients/index.ts +3 -3
  193. package/src/lsp/clients/lsp-linter-client.ts +4 -5
  194. package/src/lsp/config.ts +15 -15
  195. package/src/lsp/edits.ts +4 -5
  196. package/src/lsp/index.ts +43 -44
  197. package/src/lsp/lspmux.ts +8 -8
  198. package/src/lsp/render.ts +99 -61
  199. package/src/lsp/utils.ts +3 -3
  200. package/src/main.ts +71 -37
  201. package/src/mcp/client.ts +2 -3
  202. package/src/mcp/config.ts +5 -6
  203. package/src/mcp/json-rpc.ts +0 -1
  204. package/src/mcp/loader.ts +6 -7
  205. package/src/mcp/manager.ts +17 -18
  206. package/src/mcp/tool-bridge.ts +4 -9
  207. package/src/mcp/tool-cache.ts +2 -3
  208. package/src/mcp/transports/http.ts +2 -4
  209. package/src/mcp/transports/stdio.ts +1 -2
  210. package/src/migrations.ts +63 -52
  211. package/src/modes/components/armin.ts +4 -5
  212. package/src/modes/components/assistant-message.ts +33 -5
  213. package/src/modes/components/bash-execution.ts +7 -8
  214. package/src/modes/components/bordered-loader.ts +3 -3
  215. package/src/modes/components/branch-summary-message.ts +3 -3
  216. package/src/modes/components/compaction-summary-message.ts +3 -3
  217. package/src/modes/components/countdown-timer.ts +0 -1
  218. package/src/modes/components/custom-message.ts +5 -5
  219. package/src/modes/components/diff.ts +1 -1
  220. package/src/modes/components/dynamic-border.ts +2 -2
  221. package/src/modes/components/extensions/extension-dashboard.ts +6 -7
  222. package/src/modes/components/extensions/extension-list.ts +2 -3
  223. package/src/modes/components/extensions/inspector-panel.ts +3 -4
  224. package/src/modes/components/extensions/state-manager.ts +25 -26
  225. package/src/modes/components/extensions/types.ts +1 -2
  226. package/src/modes/components/footer.ts +47 -43
  227. package/src/modes/components/history-search.ts +2 -2
  228. package/src/modes/components/hook-editor.ts +3 -4
  229. package/src/modes/components/hook-input.ts +2 -3
  230. package/src/modes/components/hook-message.ts +5 -5
  231. package/src/modes/components/hook-selector.ts +2 -3
  232. package/src/modes/components/keybinding-hints.ts +2 -3
  233. package/src/modes/components/login-dialog.ts +2 -2
  234. package/src/modes/components/model-selector.ts +12 -12
  235. package/src/modes/components/oauth-selector.ts +2 -2
  236. package/src/modes/components/plugin-settings.ts +20 -20
  237. package/src/modes/components/python-execution.ts +7 -8
  238. package/src/modes/components/queue-mode-selector.ts +3 -3
  239. package/src/modes/components/read-tool-group.ts +2 -2
  240. package/src/modes/components/session-selector.ts +4 -4
  241. package/src/modes/components/settings-defs.ts +77 -69
  242. package/src/modes/components/settings-selector.ts +16 -16
  243. package/src/modes/components/show-images-selector.ts +2 -2
  244. package/src/modes/components/status-line/segments.ts +4 -4
  245. package/src/modes/components/status-line/separators.ts +1 -1
  246. package/src/modes/components/status-line/types.ts +2 -2
  247. package/src/modes/components/status-line-segment-editor.ts +7 -8
  248. package/src/modes/components/status-line.ts +12 -12
  249. package/src/modes/components/theme-selector.ts +8 -7
  250. package/src/modes/components/thinking-selector.ts +4 -4
  251. package/src/modes/components/todo-display.ts +2 -2
  252. package/src/modes/components/todo-reminder.ts +4 -4
  253. package/src/modes/components/tool-execution.ts +16 -19
  254. package/src/modes/components/tree-selector.ts +12 -12
  255. package/src/modes/components/ttsr-notification.ts +5 -5
  256. package/src/modes/components/user-message-selector.ts +1 -1
  257. package/src/modes/components/user-message.ts +1 -1
  258. package/src/modes/components/visual-truncate.ts +0 -1
  259. package/src/modes/components/welcome.ts +4 -4
  260. package/src/modes/controllers/command-controller.ts +46 -47
  261. package/src/modes/controllers/event-controller.ts +16 -20
  262. package/src/modes/controllers/extension-ui-controller.ts +40 -46
  263. package/src/modes/controllers/input-controller.ts +17 -18
  264. package/src/modes/controllers/selector-controller.ts +103 -91
  265. package/src/modes/index.ts +3 -3
  266. package/src/modes/interactive-mode.ts +31 -31
  267. package/src/modes/print-mode.ts +12 -13
  268. package/src/modes/rpc/rpc-client.ts +7 -8
  269. package/src/modes/rpc/rpc-mode.ts +24 -28
  270. package/src/modes/rpc/rpc-types.ts +3 -4
  271. package/src/modes/theme/mermaid-cache.ts +89 -0
  272. package/src/modes/theme/theme.ts +130 -53
  273. package/src/modes/types.ts +10 -10
  274. package/src/modes/utils/ui-helpers.ts +17 -17
  275. package/src/patch/applicator.ts +18 -19
  276. package/src/patch/diff.ts +1 -2
  277. package/src/patch/fuzzy.ts +1 -2
  278. package/src/patch/index.ts +11 -18
  279. package/src/patch/normalize.ts +4 -4
  280. package/src/patch/normative.ts +1 -2
  281. package/src/patch/parser.ts +8 -9
  282. package/src/patch/shared.ts +43 -16
  283. package/src/prompts/tools/task.md +2 -0
  284. package/src/sdk.ts +100 -65
  285. package/src/session/agent-session.ts +84 -85
  286. package/src/session/agent-storage.ts +43 -39
  287. package/src/session/artifacts.ts +32 -10
  288. package/src/session/auth-storage.ts +50 -39
  289. package/src/session/compaction/branch-summarization.ts +7 -10
  290. package/src/session/compaction/compaction.ts +8 -19
  291. package/src/session/compaction/utils.ts +6 -9
  292. package/src/session/history-storage.ts +10 -10
  293. package/src/session/messages.ts +4 -5
  294. package/src/session/session-manager.ts +76 -65
  295. package/src/session/session-storage.ts +57 -69
  296. package/src/session/storage-migration.ts +14 -56
  297. package/src/session/streaming-output.ts +2 -2
  298. package/src/ssh/connection-manager.ts +43 -50
  299. package/src/ssh/ssh-executor.ts +2 -2
  300. package/src/ssh/sshfs-mount.ts +11 -18
  301. package/src/system-prompt.ts +28 -35
  302. package/src/task/agents.ts +45 -30
  303. package/src/task/commands.ts +6 -7
  304. package/src/task/discovery.ts +39 -76
  305. package/src/task/executor.ts +14 -15
  306. package/src/task/index.ts +40 -34
  307. package/src/task/output-manager.ts +93 -0
  308. package/src/task/parallel.ts +0 -1
  309. package/src/task/render.ts +24 -30
  310. package/src/task/subprocess-tool-registry.ts +1 -2
  311. package/src/task/worker-protocol.ts +3 -3
  312. package/src/task/worker.ts +33 -39
  313. package/src/task/worktree.ts +19 -19
  314. package/src/tools/ask.ts +41 -20
  315. package/src/tools/bash-interceptor.ts +1 -5
  316. package/src/tools/bash.ts +91 -97
  317. package/src/tools/calculator.ts +49 -47
  318. package/src/tools/complete.ts +4 -5
  319. package/src/tools/context.ts +2 -2
  320. package/src/tools/fetch.ts +84 -124
  321. package/src/tools/find.ts +94 -98
  322. package/src/tools/gemini-image.ts +14 -14
  323. package/src/tools/grep.ts +100 -116
  324. package/src/tools/index.ts +80 -55
  325. package/src/tools/list-limit.ts +1 -1
  326. package/src/tools/ls.ts +44 -70
  327. package/src/tools/notebook.ts +51 -67
  328. package/src/tools/output-meta.ts +3 -4
  329. package/src/tools/output-utils.ts +2 -2
  330. package/src/tools/path-utils.ts +5 -5
  331. package/src/tools/python.ts +104 -217
  332. package/src/tools/read.ts +92 -33
  333. package/src/tools/render-utils.ts +8 -23
  334. package/src/tools/renderers.ts +6 -7
  335. package/src/tools/review.ts +8 -11
  336. package/src/tools/ssh.ts +69 -49
  337. package/src/tools/todo-write.ts +37 -25
  338. package/src/tools/tool-errors.ts +3 -3
  339. package/src/tools/tool-result.ts +3 -8
  340. package/src/tools/write.ts +99 -75
  341. package/src/tui/code-cell.ts +109 -0
  342. package/src/tui/file-list.ts +47 -0
  343. package/src/tui/index.ts +11 -0
  344. package/src/tui/output-block.ts +72 -0
  345. package/src/tui/status-line.ts +39 -0
  346. package/src/tui/tree-list.ts +55 -0
  347. package/src/tui/types.ts +16 -0
  348. package/src/tui/utils.ts +48 -0
  349. package/src/utils/changelog.ts +9 -10
  350. package/src/utils/clipboard.ts +11 -11
  351. package/src/utils/file-mentions.ts +4 -10
  352. package/src/utils/frontmatter.ts +6 -3
  353. package/src/utils/fuzzy.ts +2 -2
  354. package/src/utils/image-convert.ts +1 -1
  355. package/src/utils/image-resize.ts +1 -1
  356. package/src/utils/mime.ts +2 -2
  357. package/src/utils/shell-snapshot.ts +11 -13
  358. package/src/utils/shell.ts +4 -5
  359. package/src/utils/title-generator.ts +8 -9
  360. package/src/utils/tools-manager.ts +23 -23
  361. package/src/vendor/photon/index.js +1099 -1059
  362. package/src/vendor/photon/photon_rs_bg.wasm +0 -0
  363. package/src/web/scrapers/artifacthub.ts +1 -1
  364. package/src/web/scrapers/arxiv.ts +2 -2
  365. package/src/web/scrapers/bluesky.ts +2 -2
  366. package/src/web/scrapers/cheatsh.ts +1 -1
  367. package/src/web/scrapers/chocolatey.ts +2 -2
  368. package/src/web/scrapers/choosealicense.ts +5 -5
  369. package/src/web/scrapers/cisa-kev.ts +1 -1
  370. package/src/web/scrapers/crossref.ts +2 -2
  371. package/src/web/scrapers/devto.ts +3 -3
  372. package/src/web/scrapers/discogs.ts +3 -4
  373. package/src/web/scrapers/discourse.ts +1 -1
  374. package/src/web/scrapers/dockerhub.ts +1 -1
  375. package/src/web/scrapers/fdroid.ts +2 -2
  376. package/src/web/scrapers/firefox-addons.ts +3 -3
  377. package/src/web/scrapers/flathub.ts +1 -1
  378. package/src/web/scrapers/github.ts +3 -3
  379. package/src/web/scrapers/gitlab.ts +4 -4
  380. package/src/web/scrapers/hackernews.ts +2 -2
  381. package/src/web/scrapers/huggingface.ts +1 -1
  382. package/src/web/scrapers/iacr.ts +2 -2
  383. package/src/web/scrapers/index.ts +0 -1
  384. package/src/web/scrapers/jetbrains-marketplace.ts +1 -1
  385. package/src/web/scrapers/lemmy.ts +2 -2
  386. package/src/web/scrapers/maven.ts +2 -2
  387. package/src/web/scrapers/mdn.ts +2 -4
  388. package/src/web/scrapers/metacpan.ts +2 -2
  389. package/src/web/scrapers/musicbrainz.ts +1 -2
  390. package/src/web/scrapers/npm.ts +1 -1
  391. package/src/web/scrapers/nuget.ts +2 -2
  392. package/src/web/scrapers/nvd.ts +3 -3
  393. package/src/web/scrapers/ollama.ts +7 -9
  394. package/src/web/scrapers/opencorporates.ts +2 -2
  395. package/src/web/scrapers/openlibrary.ts +6 -6
  396. package/src/web/scrapers/orcid.ts +0 -1
  397. package/src/web/scrapers/osv.ts +2 -2
  398. package/src/web/scrapers/packagist.ts +1 -1
  399. package/src/web/scrapers/pubmed.ts +1 -2
  400. package/src/web/scrapers/rawg.ts +2 -2
  401. package/src/web/scrapers/readthedocs.ts +1 -2
  402. package/src/web/scrapers/repology.ts +2 -2
  403. package/src/web/scrapers/rfc.ts +1 -1
  404. package/src/web/scrapers/searchcode.ts +2 -2
  405. package/src/web/scrapers/semantic-scholar.ts +1 -1
  406. package/src/web/scrapers/snapcraft.ts +2 -2
  407. package/src/web/scrapers/sourcegraph.ts +1 -1
  408. package/src/web/scrapers/spdx.ts +3 -3
  409. package/src/web/scrapers/spotify.ts +0 -1
  410. package/src/web/scrapers/twitter.ts +1 -1
  411. package/src/web/scrapers/types.ts +1 -2
  412. package/src/web/scrapers/utils.ts +5 -5
  413. package/src/web/scrapers/wikidata.ts +3 -3
  414. package/src/web/scrapers/youtube.ts +9 -14
  415. package/src/web/search/auth.ts +5 -10
  416. package/src/web/search/index.ts +11 -21
  417. package/src/web/search/providers/anthropic.ts +3 -9
  418. package/src/web/search/providers/exa.ts +6 -10
  419. package/src/web/search/providers/perplexity.ts +5 -5
  420. package/src/web/search/render.ts +129 -175
  421. package/tsconfig.json +0 -42
package/src/tools/grep.ts CHANGED
@@ -1,23 +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 { getLanguageFromPath, 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 { ensureTool } from "@oh-my-pi/pi-coding-agent/utils/tools-manager";
11
- import { untilAborted } from "@oh-my-pi/pi-coding-agent/utils/utils";
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, readLines } from "@oh-my-pi/pi-utils";
15
7
  import { Type } from "@sinclair/typebox";
16
8
  import { $ } from "bun";
17
- import type { ToolSession } from "./index";
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";
16
+ import type { ToolSession } from ".";
18
17
  import { applyListLimit } from "./list-limit";
18
+ import type { OutputMeta } from "./output-meta";
19
19
  import { resolveToCwd } from "./path-utils";
20
- import { PREVIEW_LIMITS, ToolUIKit } from "./render-utils";
20
+ import { formatCount, formatEmptyMessage, formatErrorMessage, PREVIEW_LIMITS } from "./render-utils";
21
+ import { ToolAbortError, ToolError } from "./tool-errors";
21
22
  import { toolResult } from "./tool-result";
22
23
  import { DEFAULT_MAX_COLUMN, type TruncationResult, truncateHead, truncateLine } from "./truncate";
23
24
 
@@ -72,8 +73,8 @@ export interface GrepOperations {
72
73
  }
73
74
 
74
75
  const defaultGrepOperations: GrepOperations = {
75
- isDirectory: async (p) => (await Bun.file(p).stat()).isDirectory(),
76
- readFile: (p) => Bun.file(p).text(),
76
+ isDirectory: async p => (await Bun.file(p).stat()).isDirectory(),
77
+ readFile: p => Bun.file(p).text(),
77
78
  };
78
79
 
79
80
  export interface GrepToolOptions {
@@ -286,7 +287,7 @@ export class GrepTool implements AgentTool<typeof grepSchema, GrepToolDetails> {
286
287
 
287
288
  // For simple output modes (files_with_matches, count), process text directly
288
289
  if (effectiveOutputMode === "files_with_matches" || effectiveOutputMode === "count") {
289
- const stdout = await child.text().catch((x) => {
290
+ const stdout = await child.text().catch(x => {
290
291
  if (x instanceof ptree.Exception && x.exitCode === 1) {
291
292
  return "";
292
293
  }
@@ -302,7 +303,7 @@ export class GrepTool implements AgentTool<typeof grepSchema, GrepToolDetails> {
302
303
  const lines = stdout
303
304
  .trim()
304
305
  .split("\n")
305
- .filter((line) => line.length > 0);
306
+ .filter(line => line.length > 0);
306
307
 
307
308
  if (lines.length === 0) {
308
309
  const details: GrepToolDetails = {
@@ -370,7 +371,7 @@ export class GrepTool implements AgentTool<typeof grepSchema, GrepToolDetails> {
370
371
 
371
372
  // For count mode, format as "path:count"
372
373
  if (effectiveOutputMode === "count") {
373
- const formatted = processedLines.map((line) => {
374
+ const formatted = processedLines.map(line => {
374
375
  const separatorIndex = line.lastIndexOf(":");
375
376
  const relative = formatPath(separatorIndex === -1 ? line : line.slice(0, separatorIndex));
376
377
  const count = separatorIndex === -1 ? "0" : line.slice(separatorIndex + 1);
@@ -382,7 +383,7 @@ export class GrepTool implements AgentTool<typeof grepSchema, GrepToolDetails> {
382
383
  matchCount: simpleMatchCount,
383
384
  fileCount,
384
385
  files: simpleFileList,
385
- fileMatches: simpleFileList.map((path) => ({
386
+ fileMatches: simpleFileList.map(path => ({
386
387
  path,
387
388
  count: simpleFileMatchCounts.get(path) ?? 0,
388
389
  })),
@@ -400,7 +401,7 @@ export class GrepTool implements AgentTool<typeof grepSchema, GrepToolDetails> {
400
401
  }
401
402
 
402
403
  // For files_with_matches, format paths
403
- const formatted = processedLines.map((line) => formatPath(line));
404
+ const formatted = processedLines.map(line => formatPath(line));
404
405
  const output = formatted.join("\n");
405
406
  const details: GrepToolDetails = {
406
407
  scopePath,
@@ -546,7 +547,7 @@ export class GrepTool implements AgentTool<typeof grepSchema, GrepToolDetails> {
546
547
  matchCount,
547
548
  fileCount: files.size,
548
549
  files: fileList,
549
- fileMatches: fileList.map((path) => ({
550
+ fileMatches: fileList.map(path => ({
550
551
  path,
551
552
  count: fileMatchCounts.get(path) ?? 0,
552
553
  })),
@@ -600,10 +601,6 @@ const COLLAPSED_TEXT_LIMIT = PREVIEW_LIMITS.COLLAPSED_LINES * 2;
600
601
  export const grepToolRenderer = {
601
602
  inline: true,
602
603
  renderCall(args: GrepRenderArgs, uiTheme: Theme): Component {
603
- const ui = new ToolUIKit(uiTheme);
604
- const label = ui.title("Grep");
605
- let text = `${uiTheme.format.bullet} ${label} ${uiTheme.fg("accent", args.pattern || "?")}`;
606
-
607
604
  const meta: string[] = [];
608
605
  if (args.path) meta.push(`in ${args.path}`);
609
606
  if (args.glob) meta.push(`glob:${args.glob}`);
@@ -619,8 +616,10 @@ export const grepToolRenderer = {
619
616
  if (args.context !== undefined) meta.push(`context:${args.context}`);
620
617
  if (args.limit !== undefined) meta.push(`limit:${args.limit}`);
621
618
 
622
- text += ui.meta(meta);
623
-
619
+ const text = renderStatusLine(
620
+ { icon: "pending", title: "Grep", description: args.pattern || "?", meta },
621
+ uiTheme,
622
+ );
624
623
  return new Text(text, 0, 0);
625
624
  },
626
625
 
@@ -628,45 +627,39 @@ export const grepToolRenderer = {
628
627
  result: { content: Array<{ type: string; text?: string }>; details?: GrepToolDetails; isError?: boolean },
629
628
  { expanded }: RenderResultOptions,
630
629
  uiTheme: Theme,
630
+ args?: GrepRenderArgs,
631
631
  ): Component {
632
- const ui = new ToolUIKit(uiTheme);
633
632
  const details = result.details;
634
633
 
635
634
  if (result.isError || details?.error) {
636
- const errorText = details?.error || result.content?.find((c) => c.type === "text")?.text || "Unknown error";
637
- return new Text(` ${ui.errorMessage(errorText)}`, 0, 0);
635
+ const errorText = details?.error || result.content?.find(c => c.type === "text")?.text || "Unknown error";
636
+ return new Text(formatErrorMessage(errorText, uiTheme), 0, 0);
638
637
  }
639
638
 
640
639
  const hasDetailedData = details?.matchCount !== undefined || details?.fileCount !== undefined;
641
640
 
642
641
  if (!hasDetailedData) {
643
- const textContent = result.content?.find((c) => c.type === "text")?.text;
642
+ const textContent = result.content?.find(c => c.type === "text")?.text;
644
643
  if (!textContent || textContent === "No matches found") {
645
- return new Text(` ${ui.emptyMessage("No matches found")}`, 0, 0);
646
- }
647
-
648
- const lines = textContent.split("\n").filter((line) => line.trim() !== "");
649
- const maxLines = expanded ? lines.length : Math.min(lines.length, COLLAPSED_TEXT_LIMIT);
650
- const displayLines = lines.slice(0, maxLines);
651
- const remaining = lines.length - maxLines;
652
- const hasMore = remaining > 0;
653
-
654
- const icon = uiTheme.styledSymbol("status.success", "success");
655
- const summary = ui.count("item", lines.length);
656
- const expandHint = ui.expandHint(expanded, hasMore);
657
- let text = ` ${icon} ${uiTheme.fg("dim", summary)}${expandHint}`;
658
-
659
- for (let i = 0; i < displayLines.length; i++) {
660
- const isLast = i === displayLines.length - 1 && remaining === 0;
661
- const branch = isLast ? uiTheme.tree.last : uiTheme.tree.branch;
662
- text += `\n ${uiTheme.fg("dim", branch)} ${uiTheme.fg("toolOutput", displayLines[i])}`;
663
- }
664
-
665
- if (remaining > 0) {
666
- text += `\n ${uiTheme.fg("dim", uiTheme.tree.last)} ${uiTheme.fg("muted", ui.moreItems(remaining, "item"))}`;
644
+ return new Text(formatEmptyMessage("No matches found", uiTheme), 0, 0);
667
645
  }
668
-
669
- return new Text(text, 0, 0);
646
+ const lines = textContent.split("\n").filter(line => line.trim() !== "");
647
+ const description = args?.pattern ?? undefined;
648
+ const header = renderStatusLine(
649
+ { icon: "success", title: "Grep", description, meta: [formatCount("item", lines.length)] },
650
+ uiTheme,
651
+ );
652
+ const listLines = renderTreeList(
653
+ {
654
+ items: lines,
655
+ expanded,
656
+ maxCollapsed: COLLAPSED_TEXT_LIMIT,
657
+ itemType: "item",
658
+ renderItem: line => uiTheme.fg("toolOutput", line),
659
+ },
660
+ uiTheme,
661
+ );
662
+ return new Text([header, ...listLines].join("\n"), 0, 0);
670
663
  }
671
664
 
672
665
  const matchCount = details?.matchCount ?? 0;
@@ -685,79 +678,70 @@ export const grepToolRenderer = {
685
678
  const files = details?.files ?? [];
686
679
 
687
680
  if (matchCount === 0) {
688
- return new Text(` ${ui.emptyMessage("No matches found")}`, 0, 0);
681
+ const header = renderStatusLine(
682
+ { icon: "warning", title: "Grep", description: args?.pattern, meta: ["0 matches"] },
683
+ uiTheme,
684
+ );
685
+ return new Text([header, formatEmptyMessage("No matches found", uiTheme)].join("\n"), 0, 0);
689
686
  }
690
687
 
691
- const icon = uiTheme.styledSymbol("status.success", "success");
692
688
  const summaryParts =
693
689
  mode === "files_with_matches"
694
- ? [ui.count("file", fileCount)]
695
- : [ui.count("match", matchCount), ui.count("file", fileCount)];
696
- const summaryText = summaryParts.join(uiTheme.sep.dot);
697
- const scopeLabel = ui.scope(details?.scopePath);
698
-
699
- const fileEntries: Array<{ path: string; count?: number }> = details?.fileMatches?.length
700
- ? details.fileMatches.map((entry) => ({ path: entry.path, count: entry.count }))
701
- : files.map((path) => ({ path }));
702
- const maxFiles = expanded ? fileEntries.length : Math.min(fileEntries.length, COLLAPSED_LIST_LIMIT);
703
- const hasMoreFiles = fileEntries.length > maxFiles;
704
- const expandHint = ui.expandHint(expanded, hasMoreFiles);
705
-
706
- let text = ` ${icon} ${uiTheme.fg("dim", summaryText)}${ui.truncationSuffix(truncated)}${scopeLabel}${expandHint}`;
690
+ ? [formatCount("file", fileCount)]
691
+ : [formatCount("match", matchCount), formatCount("file", fileCount)];
692
+ const meta = [...summaryParts];
693
+ if (details?.scopePath) meta.push(`in ${details.scopePath}`);
694
+ if (truncated) meta.push(uiTheme.fg("warning", "truncated"));
695
+ const description = args?.pattern ?? undefined;
696
+ const header = renderStatusLine(
697
+ { icon: truncated ? "warning" : "success", title: "Grep", description, meta },
698
+ uiTheme,
699
+ );
707
700
 
708
- const truncationReasons: string[] = [];
709
- if (limits?.matchLimit) {
710
- truncationReasons.push(`limit ${limits.matchLimit.reached} matches`);
711
- }
712
- if (limits?.resultLimit) {
713
- truncationReasons.push(`limit ${limits.resultLimit.reached} results`);
714
- }
715
- if (limits?.headLimit) {
716
- truncationReasons.push(`head limit ${limits.headLimit.reached}`);
717
- }
718
- if (truncation) {
719
- truncationReasons.push(truncation.truncatedBy === "lines" ? "line limit" : "size limit");
720
- }
721
- if (limits?.columnTruncated) {
722
- truncationReasons.push(`line length ${limits.columnTruncated.maxColumn}`);
723
- }
724
- if (truncation?.artifactId) {
725
- truncationReasons.push(`full output: artifact://${truncation.artifactId}`);
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);
704
+ const matchLines = renderTreeList(
705
+ {
706
+ items: contentLines,
707
+ expanded,
708
+ maxCollapsed: COLLAPSED_TEXT_LIMIT,
709
+ itemType: "match",
710
+ renderItem: line => uiTheme.fg("toolOutput", line),
711
+ },
712
+ uiTheme,
713
+ );
714
+ return new Text([header, ...matchLines].join("\n"), 0, 0);
726
715
  }
727
716
 
728
- const hasTruncation = truncationReasons.length > 0;
729
-
730
- if (fileEntries.length > 0) {
731
- for (let i = 0; i < maxFiles; i++) {
732
- const entry = fileEntries[i];
733
- const isLast = i === maxFiles - 1 && !hasMoreFiles && !hasTruncation;
734
- const branch = isLast ? uiTheme.tree.last : uiTheme.tree.branch;
735
- const isDir = entry.path.endsWith("/");
736
- const entryPath = isDir ? entry.path.slice(0, -1) : entry.path;
737
- const lang = isDir ? undefined : getLanguageFromPath(entryPath);
738
- const entryIcon = isDir
739
- ? uiTheme.fg("accent", uiTheme.icon.folder)
740
- : uiTheme.fg("muted", uiTheme.getLangIcon(lang));
741
- const countLabel =
742
- entry.count !== undefined
743
- ? ` ${uiTheme.fg("dim", `(${entry.count} match${entry.count !== 1 ? "es" : ""})`)}`
744
- : "";
745
- text += `\n ${uiTheme.fg("dim", branch)} ${entryIcon} ${uiTheme.fg("accent", entry.path)}${countLabel}`;
746
- }
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 }));
720
+ const fileLines = renderFileList(
721
+ {
722
+ files: fileEntries.map(entry => ({
723
+ path: entry.path,
724
+ isDirectory: entry.path.endsWith("/"),
725
+ meta: entry.count !== undefined ? `(${entry.count} match${entry.count !== 1 ? "es" : ""})` : undefined,
726
+ })),
727
+ expanded,
728
+ maxCollapsed: COLLAPSED_LIST_LIMIT,
729
+ },
730
+ uiTheme,
731
+ );
747
732
 
748
- if (hasMoreFiles) {
749
- const moreFilesBranch = hasTruncation ? uiTheme.tree.branch : uiTheme.tree.last;
750
- text += `\n ${uiTheme.fg("dim", moreFilesBranch)} ${uiTheme.fg(
751
- "muted",
752
- ui.moreItems(fileEntries.length - maxFiles, "file"),
753
- )}`;
754
- }
755
- }
733
+ const truncationReasons: string[] = [];
734
+ if (limits?.matchLimit) truncationReasons.push(`limit ${limits.matchLimit.reached} matches`);
735
+ if (limits?.resultLimit) truncationReasons.push(`limit ${limits.resultLimit.reached} results`);
736
+ if (limits?.headLimit) truncationReasons.push(`head limit ${limits.headLimit.reached}`);
737
+ if (truncation) truncationReasons.push(truncation.truncatedBy === "lines" ? "line limit" : "size limit");
738
+ if (limits?.columnTruncated) truncationReasons.push(`line length ${limits.columnTruncated.maxColumn}`);
739
+ if (truncation?.artifactId) truncationReasons.push(`full output: artifact://${truncation.artifactId}`);
756
740
 
757
- if (hasTruncation) {
758
- text += `\n ${uiTheme.fg("dim", uiTheme.tree.last)} ${uiTheme.fg("warning", `truncated: ${truncationReasons.join(", ")}`)}`;
759
- }
741
+ const extraLines =
742
+ truncationReasons.length > 0 ? [uiTheme.fg("warning", `truncated: ${truncationReasons.join(", ")}`)] : [];
760
743
 
761
- return new Text(text, 0, 0);
744
+ return new Text([header, ...fileLines, ...extraLines].join("\n"), 0, 0);
762
745
  },
746
+ mergeCallAndResult: true,
763
747
  };
@@ -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/index";
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/index";
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/index";
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/index";
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,35 +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/index";
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/index";
71
- import type { EventBus } from "@oh-my-pi/pi-coding-agent/utils/event-bus";
72
- import { WebSearchTool } from "@oh-my-pi/pi-coding-agent/web/search/index";
73
- import { logger } from "@oh-my-pi/pi-utils";
74
- import { AskTool } from "./ask";
75
- import { BashTool } from "./bash";
76
- import { CalculatorTool } from "./calculator";
77
- import { CompleteTool } from "./complete";
78
- import { FetchTool } from "./fetch";
79
- import { FindTool } from "./find";
80
- import { GrepTool } from "./grep";
81
- import { LsTool } from "./ls";
82
- import { NotebookTool } from "./notebook";
83
- import { wrapToolsWithMetaNotice } from "./output-meta";
84
- import { PythonTool } from "./python";
85
- import { ReadTool } from "./read";
86
- import { reportFindingTool } from "./review";
87
- import { loadSshTool } from "./ssh";
88
- import { TodoWriteTool } from "./todo-write";
89
- import { WriteTool } from "./write";
90
-
91
94
  /** Tool type (AgentTool from pi-ai) */
92
95
  export type Tool = AgentTool<any, any, any>;
93
96
 
@@ -125,6 +128,8 @@ export interface ToolSession {
125
128
  mcpManager?: import("../mcp/manager").MCPManager;
126
129
  /** Internal URL router for agent:// and skill:// URLs */
127
130
  internalRouter?: InternalUrlRouter;
131
+ /** Agent output manager for unique agent:// IDs across task invocations */
132
+ agentOutputManager?: AgentOutputManager;
128
133
  /** Settings manager for passing to subagents (avoids SQLite access in workers) */
129
134
  settingsManager?: { serialize: () => import("@oh-my-pi/pi-coding-agent/config/settings-manager").Settings };
130
135
  /** Settings manager (optional) */
@@ -150,26 +155,26 @@ type ToolFactory = (session: ToolSession) => Tool | null | Promise<Tool | null>;
150
155
 
151
156
  export const BUILTIN_TOOLS: Record<string, ToolFactory> = {
152
157
  ask: AskTool.createIf,
153
- bash: (s) => new BashTool(s),
154
- python: (s) => new PythonTool(s),
155
- calc: (s) => new CalculatorTool(s),
158
+ bash: s => new BashTool(s),
159
+ python: s => new PythonTool(s),
160
+ calc: s => new CalculatorTool(s),
156
161
  ssh: loadSshTool,
157
- edit: (s) => new EditTool(s),
158
- find: (s) => new FindTool(s),
159
- grep: (s) => new GrepTool(s),
160
- 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),
161
166
  lsp: LspTool.createIf,
162
- notebook: (s) => new NotebookTool(s),
163
- read: (s) => new ReadTool(s),
167
+ notebook: s => new NotebookTool(s),
168
+ read: s => new ReadTool(s),
164
169
  task: TaskTool.create,
165
- todo_write: (s) => new TodoWriteTool(s),
166
- fetch: (s) => new FetchTool(s),
167
- web_search: (s) => new WebSearchTool(s),
168
- 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),
169
174
  };
170
175
 
171
176
  export const HIDDEN_TOOLS: Record<string, ToolFactory> = {
172
- complete: (s) => new CompleteTool(s),
177
+ complete: s => new CompleteTool(s),
173
178
  report_finding: () => reportFindingTool,
174
179
  };
175
180
 
@@ -209,6 +214,7 @@ function getPythonModeFromEnv(): PythonToolMode | null {
209
214
  * Create tools from BUILTIN_TOOLS registry.
210
215
  */
211
216
  export async function createTools(session: ToolSession, toolNames?: string[]): Promise<Tool[]> {
217
+ time("createTools:start");
212
218
  const includeComplete = session.requireCompleteTool === true;
213
219
  const enableLsp = session.enableLsp ?? true;
214
220
  const requestedTools = toolNames && toolNames.length > 0 ? [...new Set(toolNames)] : undefined;
@@ -218,18 +224,21 @@ export async function createTools(session: ToolSession, toolNames?: string[]): P
218
224
  pythonMode !== "bash-only" &&
219
225
  (requestedTools === undefined || requestedTools.includes("python") || pythonMode === "ipy-only");
220
226
  const isTestEnv = process.env.BUN_ENV === "test" || process.env.NODE_ENV === "test";
227
+ const skipPythonWarm = isTestEnv || process.env.OMP_PYTHON_SKIP_CHECK === "1";
221
228
  if (shouldCheckPython) {
222
229
  const availability = await checkPythonKernelAvailability(session.cwd);
230
+ time("createTools:pythonCheck");
223
231
  pythonAvailable = availability.ok;
224
232
  if (!availability.ok) {
225
233
  logger.warn("Python kernel unavailable, falling back to bash", {
226
234
  reason: availability.reason,
227
235
  });
228
- } else if (!isTestEnv && getPreludeDocs().length === 0) {
236
+ } else if (!skipPythonWarm && getPreludeDocs().length === 0) {
229
237
  const sessionFile = session.getSessionFile?.() ?? undefined;
230
238
  const warmSessionId = sessionFile ? `session:${sessionFile}:cwd:${session.cwd}` : `cwd:${session.cwd}`;
231
239
  try {
232
240
  await warmPythonEnvironment(session.cwd, warmSessionId, session.settings?.getPythonSharedGateway?.());
241
+ time("createTools:warmPython");
233
242
  } catch (err) {
234
243
  logger.warn("Failed to warm Python environment", {
235
244
  error: err instanceof Error ? err.message : String(err),
@@ -261,22 +270,38 @@ export async function createTools(session: ToolSession, toolNames?: string[]): P
261
270
  requestedTools.push("complete");
262
271
  }
263
272
 
264
- const filteredRequestedTools = requestedTools?.filter((name) => name in allTools && isToolAllowed(name));
273
+ const filteredRequestedTools = requestedTools?.filter(name => name in allTools && isToolAllowed(name));
265
274
 
266
275
  const entries =
267
276
  filteredRequestedTools !== undefined
268
- ? filteredRequestedTools.map((name) => [name, allTools[name]] as const)
277
+ ? filteredRequestedTools.map(name => [name, allTools[name]] as const)
269
278
  : [
270
279
  ...Object.entries(BUILTIN_TOOLS).filter(([name]) => isToolAllowed(name)),
271
280
  ...(includeComplete ? ([["complete", HIDDEN_TOOLS.complete]] as const) : []),
272
281
  ];
273
- const results = await Promise.all(entries.map(([, factory]) => factory(session)));
274
- 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);
275
300
  const wrappedTools = wrapToolsWithMetaNotice(tools);
276
301
 
277
302
  if (filteredRequestedTools !== undefined) {
278
303
  const allowed = new Set(filteredRequestedTools);
279
- return wrappedTools.filter((tool) => allowed.has(tool.name));
304
+ return wrappedTools.filter(tool => allowed.has(tool.name));
280
305
  }
281
306
 
282
307
  return wrappedTools;
@@ -1,4 +1,4 @@
1
- import type { LimitsMeta } from "@oh-my-pi/pi-coding-agent/tools/output-meta";
1
+ import type { LimitsMeta } from "./output-meta";
2
2
 
3
3
  export interface ListLimitResult<T> {
4
4
  items: T[];