@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
@@ -3,9 +3,10 @@
3
3
  *
4
4
  * Tree-based rendering with collapsed/expanded states for web search results.
5
5
  */
6
-
7
- import type { RenderResultOptions } from "@oh-my-pi/pi-coding-agent/extensibility/custom-tools/types";
8
- import type { Theme } from "@oh-my-pi/pi-coding-agent/modes/theme/theme";
6
+ import type { Component } from "@oh-my-pi/pi-tui";
7
+ import { Text } from "@oh-my-pi/pi-tui";
8
+ import type { RenderResultOptions } from "../../extensibility/custom-tools/types";
9
+ import type { Theme } from "../../modes/theme/theme";
9
10
  import {
10
11
  formatAge,
11
12
  formatCount,
@@ -17,9 +18,8 @@ import {
17
18
  PREVIEW_LIMITS,
18
19
  TRUNCATE_LENGTHS,
19
20
  truncate,
20
- } from "@oh-my-pi/pi-coding-agent/tools/render-utils";
21
- import type { Component } from "@oh-my-pi/pi-tui";
22
- import { Text } from "@oh-my-pi/pi-tui";
21
+ } from "../../tools/render-utils";
22
+ import { renderOutputBlock, renderStatusLine, renderTreeList } from "../../tui";
23
23
  import type { WebSearchResponse } from "./types";
24
24
 
25
25
  const MAX_COLLAPSED_ANSWER_LINES = PREVIEW_LIMITS.COLLAPSED_LINES;
@@ -27,15 +27,15 @@ const MAX_EXPANDED_ANSWER_LINES = PREVIEW_LIMITS.EXPANDED_LINES;
27
27
  const MAX_ANSWER_LINE_LEN = TRUNCATE_LENGTHS.LINE;
28
28
  const MAX_SNIPPET_LINES = 2;
29
29
  const MAX_SNIPPET_LINE_LEN = TRUNCATE_LENGTHS.LINE;
30
- const MAX_RELATED_QUESTIONS = 6;
30
+ const MAX_COLLAPSED_ITEMS = PREVIEW_LIMITS.COLLAPSED_ITEMS;
31
31
  const MAX_QUERY_PREVIEW = 2;
32
32
  const MAX_QUERY_LEN = 90;
33
33
  const MAX_REQUEST_ID_LEN = 36;
34
34
 
35
35
  function renderFallbackText(contentText: string, expanded: boolean, theme: Theme): Component {
36
- const lines = contentText.split("\n").filter((line) => line.trim());
36
+ const lines = contentText.split("\n").filter(line => line.trim());
37
37
  const maxLines = expanded ? lines.length : 6;
38
- const displayLines = lines.slice(0, maxLines).map((line) => truncate(line.trim(), 110, theme.format.ellipsis));
38
+ const displayLines = lines.slice(0, maxLines).map(line => truncate(line.trim(), 110, theme.format.ellipsis));
39
39
  const remaining = lines.length - displayLines.length;
40
40
 
41
41
  const headerIcon = formatStatusIcon("warning", theme);
@@ -70,6 +70,7 @@ export function renderWebSearchResult(
70
70
  result: { content: Array<{ type: string; text?: string }>; details?: WebSearchRenderDetails },
71
71
  options: RenderResultOptions,
72
72
  theme: Theme,
73
+ args?: { query?: string; provider?: string },
73
74
  ): Component {
74
75
  const { expanded } = options;
75
76
  const details = result.details;
@@ -79,7 +80,7 @@ export function renderWebSearchResult(
79
80
  return new Text(theme.fg("error", `Error: ${details.error}`), 0, 0);
80
81
  }
81
82
 
82
- const rawText = result.content?.find((block) => block.type === "text")?.text?.trim() ?? "";
83
+ const rawText = result.content?.find(block => block.type === "text")?.text?.trim() ?? "";
83
84
  const response = details?.response;
84
85
  if (!response) {
85
86
  return renderFallbackText(rawText, expanded, theme);
@@ -90,24 +91,23 @@ export function renderWebSearchResult(
90
91
  const citations = Array.isArray(response.citations) ? response.citations : [];
91
92
  const citationCount = citations.length;
92
93
  const related = Array.isArray(response.relatedQuestions)
93
- ? response.relatedQuestions.filter((item) => typeof item === "string")
94
+ ? response.relatedQuestions.filter(item => typeof item === "string")
94
95
  : [];
95
96
  const relatedCount = related.length;
96
97
  const searchQueries = Array.isArray(response.searchQueries)
97
- ? response.searchQueries.filter((item) => typeof item === "string")
98
+ ? response.searchQueries.filter(item => typeof item === "string")
98
99
  : [];
99
100
  const provider = response.provider;
100
101
 
101
102
  // Get answer text
102
103
  const answerText = typeof response.answer === "string" ? response.answer.trim() : "";
103
104
  const contentText = answerText || rawText;
104
- const totalAnswerLines = contentText ? contentText.split("\n").filter((l) => l.trim()).length : 0;
105
+ const totalAnswerLines = contentText ? contentText.split("\n").filter(l => l.trim()).length : 0;
105
106
  const answerLimit = expanded ? MAX_EXPANDED_ANSWER_LINES : MAX_COLLAPSED_ANSWER_LINES;
106
107
  const answerPreview = contentText
107
108
  ? getPreviewLines(contentText, answerLimit, MAX_ANSWER_LINE_LEN, theme.format.ellipsis)
108
109
  : [];
109
110
 
110
- // Build header: status icon Web Search (provider) · counts
111
111
  const providerLabel =
112
112
  provider === "anthropic"
113
113
  ? "Anthropic"
@@ -116,144 +116,110 @@ export function renderWebSearchResult(
116
116
  : provider === "exa"
117
117
  ? "Exa"
118
118
  : "Unknown";
119
- const headerIcon = formatStatusIcon(sourceCount > 0 ? "success" : "warning", theme);
120
- const hasMore =
121
- totalAnswerLines > answerPreview.length ||
122
- sourceCount > 0 ||
123
- citationCount > 0 ||
124
- relatedCount > 0 ||
125
- searchQueries.length > 0;
126
- const expandHint = formatExpandHint(theme, expanded, hasMore);
127
- let text = `${headerIcon} ${theme.fg("dim", `(${providerLabel})`)}${theme.sep.dot}${theme.fg(
128
- "dim",
129
- formatCount("source", sourceCount),
130
- )}${expandHint}`;
131
-
132
- if (!expanded) {
133
- const answerTitle = `${theme.fg("accent", theme.status.info)} ${theme.fg("accent", "Answer")}`;
134
- text += `\n ${theme.fg("dim", theme.tree.branch)} ${answerTitle}`;
135
-
136
- const remaining = totalAnswerLines - answerPreview.length;
137
- const allLines: Array<{ text: string; style: "dim" | "muted" }> = [];
138
-
139
- if (answerPreview.length === 0) {
140
- allLines.push({ text: "No answer text returned", style: "muted" });
141
- } else {
142
- for (const line of answerPreview) {
143
- allLines.push({ text: line, style: "dim" });
144
- }
145
- }
146
- if (remaining > 0) {
147
- allLines.push({ text: formatMoreItems(remaining, "line", theme), style: "muted" });
148
- }
149
-
150
- for (let i = 0; i < allLines.length; i++) {
151
- const { text: lineText, style } = allLines[i];
152
- const isLastLine = i === allLines.length - 1;
153
- const lineBranch = isLastLine ? theme.tree.last : theme.tree.branch;
154
- text += `\n ${theme.fg("dim", theme.tree.vertical)} ${theme.fg("dim", lineBranch)} ${theme.fg(style, lineText)}`;
155
- }
156
-
157
- const summary = [
158
- formatCount("source", sourceCount),
159
- formatCount("citation", citationCount),
160
- formatCount("related question", relatedCount),
161
- ].join(theme.sep.dot);
162
- text += `\n ${theme.fg("dim", theme.tree.last)} ${theme.fg("muted", summary)}`;
163
- return new Text(text, 0, 0);
164
- }
119
+ const queryPreview = args?.query
120
+ ? truncate(args.query, 80, theme.format.ellipsis)
121
+ : searchQueries[0]
122
+ ? truncate(searchQueries[0], 80, theme.format.ellipsis)
123
+ : undefined;
124
+ const header = renderStatusLine(
125
+ {
126
+ icon: sourceCount > 0 ? "success" : "warning",
127
+ title: "Web Search",
128
+ description: providerLabel,
129
+ meta: [formatCount("source", sourceCount)],
130
+ },
131
+ theme,
132
+ );
165
133
 
134
+ const remainingAnswer = totalAnswerLines - answerPreview.length;
166
135
  const answerLines = answerPreview.length > 0 ? answerPreview : ["No answer text returned"];
167
- const answerSectionLines = answerLines.map((line) =>
168
- line === "No answer text returned" ? theme.fg("muted", line) : theme.fg("text", line),
136
+ const answerTree = renderTreeList(
137
+ {
138
+ items: answerLines,
139
+ expanded: true,
140
+ maxCollapsed: answerLines.length,
141
+ itemType: "line",
142
+ renderItem: line => (line === "No answer text returned" ? theme.fg("muted", line) : theme.fg("dim", line)),
143
+ },
144
+ theme,
169
145
  );
170
- const remainingAnswer = totalAnswerLines - answerPreview.length;
171
146
  if (remainingAnswer > 0) {
172
- answerSectionLines.push(theme.fg("muted", formatMoreItems(remainingAnswer, "line", theme)));
147
+ answerTree.push(theme.fg("muted", formatMoreItems(remainingAnswer, "line", theme)));
173
148
  }
174
149
 
175
- const sourceLines: string[] = [];
176
- if (sourceCount === 0) {
177
- sourceLines.push(theme.fg("muted", "No sources returned"));
178
- } else {
179
- for (const src of sources) {
180
- const titleText =
181
- typeof src.title === "string" && src.title.trim()
182
- ? src.title
183
- : typeof src.url === "string" && src.url.trim()
184
- ? src.url
185
- : "Untitled";
186
- const title = truncate(titleText, 70, theme.format.ellipsis);
187
- const url = typeof src.url === "string" ? src.url : "";
188
- const domain = url ? getDomain(url) : "";
189
- const age = formatAge(src.ageSeconds) || (typeof src.publishedDate === "string" ? src.publishedDate : "");
190
- const metaParts: string[] = [];
191
- if (domain) {
192
- metaParts.push(theme.fg("dim", `(${domain})`));
193
- }
194
- if (typeof src.author === "string" && src.author.trim()) {
195
- metaParts.push(theme.fg("muted", src.author));
196
- }
197
- if (age) {
198
- metaParts.push(theme.fg("muted", age));
199
- }
200
- const metaSep = theme.fg("dim", theme.sep.dot);
201
- const metaSuffix = metaParts.length > 0 ? ` ${metaParts.join(metaSep)}` : "";
202
- sourceLines.push(`${theme.fg("accent", title)}${metaSuffix}`);
203
-
204
- const snippetText = typeof src.snippet === "string" ? src.snippet : "";
205
- if (snippetText.trim()) {
206
- const snippetLines = getPreviewLines(
207
- snippetText,
208
- MAX_SNIPPET_LINES,
209
- MAX_SNIPPET_LINE_LEN,
210
- theme.format.ellipsis,
211
- );
212
- for (const snippetLine of snippetLines) {
213
- sourceLines.push(theme.fg("muted", `${theme.format.dash} ${snippetLine}`));
150
+ const sourceTree = renderTreeList(
151
+ {
152
+ items: sources,
153
+ expanded,
154
+ maxCollapsed: MAX_COLLAPSED_ITEMS,
155
+ itemType: "source",
156
+ renderItem: src => {
157
+ const titleText =
158
+ typeof src.title === "string" && src.title.trim()
159
+ ? src.title
160
+ : typeof src.url === "string" && src.url.trim()
161
+ ? src.url
162
+ : "Untitled";
163
+ const title = truncate(titleText, 70, theme.format.ellipsis);
164
+ const url = typeof src.url === "string" ? src.url : "";
165
+ const domain = url ? getDomain(url) : "";
166
+ const age = formatAge(src.ageSeconds) || (typeof src.publishedDate === "string" ? src.publishedDate : "");
167
+ const metaParts: string[] = [];
168
+ if (domain) metaParts.push(theme.fg("dim", `(${domain})`));
169
+ if (typeof src.author === "string" && src.author.trim()) metaParts.push(theme.fg("muted", src.author));
170
+ if (age) metaParts.push(theme.fg("muted", age));
171
+ const metaSep = theme.fg("dim", theme.sep.dot);
172
+ const metaSuffix = metaParts.length > 0 ? ` ${metaParts.join(metaSep)}` : "";
173
+ const lines: string[] = [`${theme.fg("accent", title)}${metaSuffix}`];
174
+ const snippetText = typeof src.snippet === "string" ? src.snippet : "";
175
+ if (snippetText.trim()) {
176
+ const snippetLines = getPreviewLines(
177
+ snippetText,
178
+ MAX_SNIPPET_LINES,
179
+ MAX_SNIPPET_LINE_LEN,
180
+ theme.format.ellipsis,
181
+ );
182
+ for (const snippetLine of snippetLines) {
183
+ lines.push(theme.fg("muted", `${theme.format.dash} ${snippetLine}`));
184
+ }
214
185
  }
215
- }
216
-
217
- if (url) {
218
- sourceLines.push(theme.fg("mdLinkUrl", url));
219
- }
220
- }
221
- }
186
+ if (url) lines.push(theme.fg("mdLinkUrl", url));
187
+ return lines;
188
+ },
189
+ },
190
+ theme,
191
+ );
222
192
 
223
- const relatedLines: string[] = [];
224
- if (relatedCount === 0) {
225
- relatedLines.push(theme.fg("muted", "No related questions"));
226
- } else {
227
- const maxRelated = Math.min(MAX_RELATED_QUESTIONS, related.length);
228
- for (let i = 0; i < maxRelated; i++) {
229
- relatedLines.push(theme.fg("muted", `${theme.format.dash} ${related[i]}`));
230
- }
231
- if (relatedCount > maxRelated) {
232
- relatedLines.push(theme.fg("muted", formatMoreItems(relatedCount - maxRelated, "question", theme)));
233
- }
193
+ const relatedLines = related.length > 0 ? related : ["No related questions"];
194
+ const relatedTree = renderTreeList(
195
+ {
196
+ items: relatedLines,
197
+ expanded,
198
+ maxCollapsed: MAX_COLLAPSED_ITEMS,
199
+ itemType: "question",
200
+ renderItem: line => theme.fg("muted", line === "No related questions" ? line : `${theme.format.dash} ${line}`),
201
+ },
202
+ theme,
203
+ );
204
+ if (!expanded && relatedCount > MAX_COLLAPSED_ITEMS) {
205
+ relatedTree.push(theme.fg("muted", formatMoreItems(relatedCount - MAX_COLLAPSED_ITEMS, "question", theme)));
234
206
  }
235
207
 
236
208
  const metaLines: string[] = [];
237
209
  metaLines.push(`${theme.fg("muted", "Provider:")} ${theme.fg("text", providerLabel)}`);
238
- if (response.model) {
239
- metaLines.push(`${theme.fg("muted", "Model:")} ${theme.fg("text", response.model)}`);
240
- }
210
+ if (response.model) metaLines.push(`${theme.fg("muted", "Model:")} ${theme.fg("text", response.model)}`);
241
211
  metaLines.push(`${theme.fg("muted", "Sources:")} ${theme.fg("text", String(sourceCount))}`);
242
- if (citationCount > 0) {
212
+ if (citationCount > 0)
243
213
  metaLines.push(`${theme.fg("muted", "Citations:")} ${theme.fg("text", String(citationCount))}`);
244
- }
245
- if (relatedCount > 0) {
246
- metaLines.push(`${theme.fg("muted", "Related:")} ${theme.fg("text", String(relatedCount))}`);
247
- }
214
+ if (relatedCount > 0) metaLines.push(`${theme.fg("muted", "Related:")} ${theme.fg("text", String(relatedCount))}`);
248
215
  if (response.usage) {
249
216
  const usageParts: string[] = [];
250
217
  if (response.usage.inputTokens !== undefined) usageParts.push(`in ${response.usage.inputTokens}`);
251
218
  if (response.usage.outputTokens !== undefined) usageParts.push(`out ${response.usage.outputTokens}`);
252
219
  if (response.usage.totalTokens !== undefined) usageParts.push(`total ${response.usage.totalTokens}`);
253
220
  if (response.usage.searchRequests !== undefined) usageParts.push(`search ${response.usage.searchRequests}`);
254
- if (usageParts.length > 0) {
221
+ if (usageParts.length > 0)
255
222
  metaLines.push(`${theme.fg("muted", "Usage:")} ${theme.fg("text", usageParts.join(theme.sep.dot))}`);
256
- }
257
223
  }
258
224
  if (response.requestId) {
259
225
  metaLines.push(
@@ -264,55 +230,42 @@ export function renderWebSearchResult(
264
230
  );
265
231
  }
266
232
  if (searchQueries.length > 0) {
267
- metaLines.push(`${theme.fg("muted", "Search queries:")} ${theme.fg("text", String(searchQueries.length))}`);
268
- const queryPreview = searchQueries.slice(0, MAX_QUERY_PREVIEW);
269
- for (const q of queryPreview) {
270
- metaLines.push(theme.fg("muted", `${theme.format.dash} ${truncate(q, MAX_QUERY_LEN, theme.format.ellipsis)}`));
271
- }
272
- if (searchQueries.length > MAX_QUERY_PREVIEW) {
273
- metaLines.push(theme.fg("muted", formatMoreItems(searchQueries.length - MAX_QUERY_PREVIEW, "query", theme)));
274
- }
233
+ const queriesPreview = searchQueries.slice(0, MAX_QUERY_PREVIEW);
234
+ const queryList = queriesPreview.map(q => truncate(q, MAX_QUERY_LEN, theme.format.ellipsis));
235
+ const suffix = searchQueries.length > queriesPreview.length ? theme.format.ellipsis : "";
236
+ metaLines.push(`${theme.fg("muted", "Queries:")} ${theme.fg("text", queryList.join("; "))}${suffix}`);
275
237
  }
276
238
 
277
- const sections: Array<{ title: string; icon: string; lines: string[] }> = [
239
+ const sections = [
240
+ ...(queryPreview
241
+ ? [
242
+ {
243
+ lines: [`${theme.fg("muted", "Query:")} ${theme.fg("text", queryPreview)}`],
244
+ },
245
+ ]
246
+ : []),
247
+ { label: theme.fg("toolTitle", "Answer"), lines: answerTree },
278
248
  {
279
- title: "Answer",
280
- icon: formatStatusIcon("info", theme),
281
- lines: answerSectionLines,
282
- },
283
- {
284
- title: "Sources",
285
- icon: formatStatusIcon(sourceCount > 0 ? "success" : "warning", theme),
286
- lines: sourceLines,
287
- },
288
- {
289
- title: "Related",
290
- icon: formatStatusIcon(relatedCount > 0 ? "info" : "warning", theme),
291
- lines: relatedLines,
292
- },
293
- {
294
- title: "Meta",
295
- icon: formatStatusIcon("info", theme),
296
- lines: metaLines,
249
+ label: theme.fg("toolTitle", "Sources"),
250
+ lines: sourceTree.length > 0 ? sourceTree : [theme.fg("muted", "No sources returned")],
297
251
  },
252
+ { label: theme.fg("toolTitle", "Related"), lines: relatedTree },
253
+ { label: theme.fg("toolTitle", "Metadata"), lines: metaLines },
298
254
  ];
299
255
 
300
- for (let i = 0; i < sections.length; i++) {
301
- const section = sections[i];
302
- const isLast = i === sections.length - 1;
303
- const branch = isLast ? theme.tree.last : theme.tree.branch;
304
- const indent = isLast ? " " : `${theme.tree.vertical} `;
305
-
306
- text += `\n ${theme.fg("dim", branch)} ${section.icon} ${theme.fg("accent", section.title)}`;
307
- for (let j = 0; j < section.lines.length; j++) {
308
- const line = section.lines[j];
309
- const isLastLine = j === section.lines.length - 1;
310
- const lineBranch = isLastLine ? theme.tree.last : theme.tree.branch;
311
- text += `\n ${theme.fg("dim", indent)}${theme.fg("dim", lineBranch)} ${line}`;
312
- }
313
- }
314
-
315
- return new Text(text, 0, 0);
256
+ return {
257
+ render: (width: number) =>
258
+ renderOutputBlock(
259
+ {
260
+ header,
261
+ state: sourceCount > 0 ? "success" : "warning",
262
+ sections,
263
+ width,
264
+ },
265
+ theme,
266
+ ),
267
+ invalidate: () => {},
268
+ };
316
269
  }
317
270
 
318
271
  /** Render web search call (query preview) */
@@ -322,11 +275,12 @@ export function renderWebSearchCall(
322
275
  ): Component {
323
276
  const provider = args.provider ?? "auto";
324
277
  const query = truncate(args.query, 80, theme.format.ellipsis);
325
- const text = `${theme.fg("toolTitle", "Web Search")} ${theme.fg("dim", `(${provider})`)} ${theme.fg("muted", query)}`;
278
+ const text = renderStatusLine({ icon: "pending", title: "Web Search", description: query, meta: [provider] }, theme);
326
279
  return new Text(text, 0, 0);
327
280
  }
328
281
 
329
282
  export const webSearchToolRenderer = {
330
283
  renderCall: renderWebSearchCall,
331
284
  renderResult: renderWebSearchResult,
285
+ mergeCallAndResult: true,
332
286
  };
package/tsconfig.json DELETED
@@ -1,42 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ES2024",
4
- "module": "ESNext",
5
- "lib": [
6
- "ES2024"
7
- ],
8
- "strict": true,
9
- "esModuleInterop": true,
10
- "skipLibCheck": true,
11
- "forceConsistentCasingInFileNames": true,
12
- "moduleResolution": "Bundler",
13
- "resolveJsonModule": true,
14
- "allowImportingTsExtensions": true,
15
- "experimentalDecorators": true,
16
- "emitDecoratorMetadata": true,
17
- "useDefineForClassFields": false,
18
- "types": [
19
- "bun",
20
- "node"
21
- ],
22
- "noEmit": true,
23
- "baseUrl": ".",
24
- "paths": {
25
- "@oh-my-pi/pi-coding-agent": [
26
- "./src/index.ts"
27
- ],
28
- "@oh-my-pi/pi-coding-agent/*": [
29
- "./src/*"
30
- ]
31
- }
32
- },
33
- "include": [
34
- "src/**/*.ts"
35
- ],
36
- "exclude": [
37
- "node_modules",
38
- "dist",
39
- "**/*.test.ts",
40
- "test/**"
41
- ]
42
- }