@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
@@ -1,16 +1,17 @@
1
1
  import * as fs from "node:fs";
2
2
  import * as path from "node:path";
3
- import { getCustomThemesDir } from "@oh-my-pi/pi-coding-agent/config";
4
3
  import type { EditorTheme, MarkdownTheme, SelectListTheme, SymbolTheme } from "@oh-my-pi/pi-tui";
5
- import { logger } from "@oh-my-pi/pi-utils";
4
+ import { adjustHsv, isEnoent, logger } from "@oh-my-pi/pi-utils";
6
5
  import { type Static, Type } from "@sinclair/typebox";
7
6
  import { TypeCompiler } from "@sinclair/typebox/compiler";
8
7
  import chalk from "chalk";
9
8
  import { highlight, supportsLanguage } from "cli-highlight";
9
+ import { getCustomThemesDir } from "../../config";
10
10
  // Embed theme JSON files at build time
11
11
  import darkThemeJson from "./dark.json" with { type: "json" };
12
12
  import { defaultThemes } from "./defaults";
13
13
  import lightThemeJson from "./light.json" with { type: "json" };
14
+ import { getMermaidImage } from "./mermaid-cache";
14
15
 
15
16
  // ============================================================================
16
17
  // Symbol Presets
@@ -1599,16 +1600,18 @@ function getBuiltinThemes(): Record<string, ThemeJson> {
1599
1600
  return BUILTIN_THEMES;
1600
1601
  }
1601
1602
 
1602
- export function getAvailableThemes(): string[] {
1603
+ export async function getAvailableThemes(): Promise<string[]> {
1603
1604
  const themes = new Set<string>(Object.keys(getBuiltinThemes()));
1604
1605
  const customThemesDir = getCustomThemesDir();
1605
- if (fs.existsSync(customThemesDir)) {
1606
- const files = fs.readdirSync(customThemesDir);
1606
+ try {
1607
+ const files = await fs.promises.readdir(customThemesDir);
1607
1608
  for (const file of files) {
1608
1609
  if (file.endsWith(".json")) {
1609
1610
  themes.add(file.slice(0, -5));
1610
1611
  }
1611
1612
  }
1613
+ } catch {
1614
+ // Directory doesn't exist or isn't readable
1612
1615
  }
1613
1616
  return Array.from(themes).sort();
1614
1617
  }
@@ -1618,7 +1621,7 @@ export interface ThemeInfo {
1618
1621
  path: string | undefined;
1619
1622
  }
1620
1623
 
1621
- export function getAvailableThemesWithPaths(): ThemeInfo[] {
1624
+ export async function getAvailableThemesWithPaths(): Promise<ThemeInfo[]> {
1622
1625
  const result: ThemeInfo[] = [];
1623
1626
 
1624
1627
  // Built-in themes (embedded, no file path)
@@ -1628,31 +1631,37 @@ export function getAvailableThemesWithPaths(): ThemeInfo[] {
1628
1631
 
1629
1632
  // Custom themes
1630
1633
  const customThemesDir = getCustomThemesDir();
1631
- if (fs.existsSync(customThemesDir)) {
1632
- for (const file of fs.readdirSync(customThemesDir)) {
1634
+ try {
1635
+ const files = await fs.promises.readdir(customThemesDir);
1636
+ for (const file of files) {
1633
1637
  if (file.endsWith(".json")) {
1634
1638
  const name = file.slice(0, -5);
1635
- if (!result.some((themeInfo) => themeInfo.name === name)) {
1639
+ if (!result.some(themeInfo => themeInfo.name === name)) {
1636
1640
  result.push({ name, path: path.join(customThemesDir, file) });
1637
1641
  }
1638
1642
  }
1639
1643
  }
1644
+ } catch {
1645
+ // Directory doesn't exist or isn't readable
1640
1646
  }
1641
1647
 
1642
1648
  return result.sort((a, b) => a.name.localeCompare(b.name));
1643
1649
  }
1644
1650
 
1645
- function loadThemeJson(name: string): ThemeJson {
1651
+ async function loadThemeJson(name: string): Promise<ThemeJson> {
1646
1652
  const builtinThemes = getBuiltinThemes();
1647
1653
  if (name in builtinThemes) {
1648
1654
  return builtinThemes[name];
1649
1655
  }
1650
1656
  const customThemesDir = getCustomThemesDir();
1651
1657
  const themePath = path.join(customThemesDir, `${name}.json`);
1652
- if (!fs.existsSync(themePath)) {
1653
- throw new Error(`Theme not found: ${name}`);
1658
+ let content: string;
1659
+ try {
1660
+ content = await Bun.file(themePath).text();
1661
+ } catch (err) {
1662
+ if (isEnoent(err)) throw new Error(`Theme not found: ${name}`);
1663
+ throw err;
1654
1664
  }
1655
- const content = fs.readFileSync(themePath, "utf-8");
1656
1665
  let json: unknown;
1657
1666
  try {
1658
1667
  json = JSON.parse(content);
@@ -1677,7 +1686,7 @@ function loadThemeJson(name: string): ThemeJson {
1677
1686
  let errorMessage = `Invalid theme "${name}":\n`;
1678
1687
  if (missingColors.length > 0) {
1679
1688
  errorMessage += `\nMissing required color tokens:\n`;
1680
- errorMessage += missingColors.map((c) => ` - ${c}`).join("\n");
1689
+ errorMessage += missingColors.map(c => ` - ${c}`).join("\n");
1681
1690
  errorMessage += `\n\nPlease add these colors to your theme's "colors" object.`;
1682
1691
  errorMessage += `\nSee the built-in themes (dark.json, light.json) for reference values.`;
1683
1692
  }
@@ -1690,9 +1699,27 @@ function loadThemeJson(name: string): ThemeJson {
1690
1699
  return json as ThemeJson;
1691
1700
  }
1692
1701
 
1693
- function createTheme(themeJson: ThemeJson, mode?: ColorMode, symbolPresetOverride?: SymbolPreset): Theme {
1702
+ interface CreateThemeOptions {
1703
+ mode?: ColorMode;
1704
+ symbolPresetOverride?: SymbolPreset;
1705
+ colorBlindMode?: boolean;
1706
+ }
1707
+
1708
+ /** HSV adjustment to shift green toward blue for colorblind mode (red-green colorblindness) */
1709
+ const COLORBLIND_ADJUSTMENT = { h: 60, s: 0.71 };
1710
+
1711
+ function createTheme(themeJson: ThemeJson, options: CreateThemeOptions = {}): Theme {
1712
+ const { mode, symbolPresetOverride, colorBlindMode } = options;
1694
1713
  const colorMode = mode ?? detectColorMode();
1695
1714
  const resolvedColors = resolveThemeColors(themeJson.colors, themeJson.vars);
1715
+
1716
+ if (colorBlindMode) {
1717
+ const added = resolvedColors.toolDiffAdded;
1718
+ if (typeof added === "string" && added.startsWith("#")) {
1719
+ resolvedColors.toolDiffAdded = adjustHsv(added, COLORBLIND_ADJUSTMENT);
1720
+ }
1721
+ }
1722
+
1696
1723
  const fgColors: Record<ThemeColor, string | number> = {} as Record<ThemeColor, string | number>;
1697
1724
  const bgColors: Record<ThemeBg, string | number> = {} as Record<ThemeBg, string | number>;
1698
1725
  const bgColorKeys: Set<string> = new Set([
@@ -1717,14 +1744,14 @@ function createTheme(themeJson: ThemeJson, mode?: ColorMode, symbolPresetOverrid
1717
1744
  return new Theme(fgColors, bgColors, colorMode, symbolPreset, symbolOverrides);
1718
1745
  }
1719
1746
 
1720
- function loadTheme(name: string, mode?: ColorMode, symbolPresetOverride?: SymbolPreset): Theme {
1721
- const themeJson = loadThemeJson(name);
1722
- return createTheme(themeJson, mode, symbolPresetOverride);
1747
+ async function loadTheme(name: string, options: CreateThemeOptions = {}): Promise<Theme> {
1748
+ const themeJson = await loadThemeJson(name);
1749
+ return createTheme(themeJson, options);
1723
1750
  }
1724
1751
 
1725
- export function getThemeByName(name: string): Theme | undefined {
1752
+ export async function getThemeByName(name: string): Promise<Theme | undefined> {
1726
1753
  try {
1727
- return loadTheme(name);
1754
+ return await loadTheme(name);
1728
1755
  } catch {
1729
1756
  return undefined;
1730
1757
  }
@@ -1756,32 +1783,49 @@ function getDefaultTheme(): string {
1756
1783
  export let theme: Theme;
1757
1784
  let currentThemeName: string | undefined;
1758
1785
  let currentSymbolPresetOverride: SymbolPreset | undefined;
1786
+ let currentColorBlindMode: boolean = false;
1759
1787
  let themeWatcher: fs.FSWatcher | undefined;
1760
1788
  let onThemeChangeCallback: (() => void) | undefined;
1761
1789
 
1762
- export function initTheme(themeName?: string, enableWatcher: boolean = false, symbolPreset?: SymbolPreset): void {
1790
+ function getCurrentThemeOptions(): CreateThemeOptions {
1791
+ return {
1792
+ symbolPresetOverride: currentSymbolPresetOverride,
1793
+ colorBlindMode: currentColorBlindMode,
1794
+ };
1795
+ }
1796
+
1797
+ export async function initTheme(
1798
+ themeName?: string,
1799
+ enableWatcher: boolean = false,
1800
+ symbolPreset?: SymbolPreset,
1801
+ colorBlindMode?: boolean,
1802
+ ): Promise<void> {
1763
1803
  const name = themeName ?? getDefaultTheme();
1764
1804
  currentThemeName = name;
1765
1805
  currentSymbolPresetOverride = symbolPreset;
1806
+ currentColorBlindMode = colorBlindMode ?? false;
1766
1807
  try {
1767
- theme = loadTheme(name, undefined, symbolPreset);
1808
+ theme = await loadTheme(name, getCurrentThemeOptions());
1768
1809
  if (enableWatcher) {
1769
- startThemeWatcher();
1810
+ await startThemeWatcher();
1770
1811
  }
1771
1812
  } catch (err) {
1772
1813
  logger.debug("Theme loading failed, falling back to dark theme", { error: String(err) });
1773
1814
  currentThemeName = "dark";
1774
- theme = loadTheme("dark", undefined, symbolPreset);
1815
+ theme = await loadTheme("dark", getCurrentThemeOptions());
1775
1816
  // Don't start watcher for fallback theme
1776
1817
  }
1777
1818
  }
1778
1819
 
1779
- export function setTheme(name: string, enableWatcher: boolean = false): { success: boolean; error?: string } {
1820
+ export async function setTheme(
1821
+ name: string,
1822
+ enableWatcher: boolean = false,
1823
+ ): Promise<{ success: boolean; error?: string }> {
1780
1824
  currentThemeName = name;
1781
1825
  try {
1782
- theme = loadTheme(name, undefined, currentSymbolPresetOverride);
1826
+ theme = await loadTheme(name, getCurrentThemeOptions());
1783
1827
  if (enableWatcher) {
1784
- startThemeWatcher();
1828
+ await startThemeWatcher();
1785
1829
  }
1786
1830
  if (onThemeChangeCallback) {
1787
1831
  onThemeChangeCallback();
@@ -1790,7 +1834,7 @@ export function setTheme(name: string, enableWatcher: boolean = false): { succes
1790
1834
  } catch (error) {
1791
1835
  // Theme is invalid - fall back to dark theme
1792
1836
  currentThemeName = "dark";
1793
- theme = loadTheme("dark", undefined, currentSymbolPresetOverride);
1837
+ theme = await loadTheme("dark", getCurrentThemeOptions());
1794
1838
  // Don't start watcher for fallback theme
1795
1839
  return {
1796
1840
  success: false,
@@ -1811,14 +1855,14 @@ export function setThemeInstance(themeInstance: Theme): void {
1811
1855
  /**
1812
1856
  * Set the symbol preset override, recreating the theme with the new preset.
1813
1857
  */
1814
- export function setSymbolPreset(preset: SymbolPreset): void {
1858
+ export async function setSymbolPreset(preset: SymbolPreset): Promise<void> {
1815
1859
  currentSymbolPresetOverride = preset;
1816
1860
  if (currentThemeName) {
1817
1861
  try {
1818
- theme = loadTheme(currentThemeName, undefined, preset);
1862
+ theme = await loadTheme(currentThemeName, getCurrentThemeOptions());
1819
1863
  } catch {
1820
1864
  // Fall back to dark theme with new preset
1821
- theme = loadTheme("dark", undefined, preset);
1865
+ theme = await loadTheme("dark", getCurrentThemeOptions());
1822
1866
  }
1823
1867
  if (onThemeChangeCallback) {
1824
1868
  onThemeChangeCallback();
@@ -1833,6 +1877,32 @@ export function getSymbolPresetOverride(): SymbolPreset | undefined {
1833
1877
  return currentSymbolPresetOverride;
1834
1878
  }
1835
1879
 
1880
+ /**
1881
+ * Set color blind mode, recreating the theme with the new setting.
1882
+ * When enabled, uses blue instead of green for diff additions.
1883
+ */
1884
+ export async function setColorBlindMode(enabled: boolean): Promise<void> {
1885
+ currentColorBlindMode = enabled;
1886
+ if (currentThemeName) {
1887
+ try {
1888
+ theme = await loadTheme(currentThemeName, getCurrentThemeOptions());
1889
+ } catch {
1890
+ // Fall back to dark theme
1891
+ theme = await loadTheme("dark", getCurrentThemeOptions());
1892
+ }
1893
+ if (onThemeChangeCallback) {
1894
+ onThemeChangeCallback();
1895
+ }
1896
+ }
1897
+ }
1898
+
1899
+ /**
1900
+ * Get the current color blind mode setting.
1901
+ */
1902
+ export function getColorBlindMode(): boolean {
1903
+ return currentColorBlindMode;
1904
+ }
1905
+
1836
1906
  export function onThemeChange(callback: () => void): void {
1837
1907
  onThemeChangeCallback = callback;
1838
1908
  }
@@ -1851,7 +1921,7 @@ export function isValidSymbolPreset(preset: string): preset is SymbolPreset {
1851
1921
  return preset === "unicode" || preset === "nerd" || preset === "ascii";
1852
1922
  }
1853
1923
 
1854
- function startThemeWatcher(): void {
1924
+ async function startThemeWatcher(): Promise<void> {
1855
1925
  // Stop existing watcher if any
1856
1926
  if (themeWatcher) {
1857
1927
  themeWatcher.close();
@@ -1872,34 +1942,40 @@ function startThemeWatcher(): void {
1872
1942
  }
1873
1943
 
1874
1944
  try {
1875
- themeWatcher = fs.watch(themeFile, (eventType) => {
1945
+ themeWatcher = fs.watch(themeFile, eventType => {
1876
1946
  if (eventType === "change") {
1877
1947
  // Debounce rapid changes
1878
1948
  setTimeout(() => {
1879
- try {
1880
- // Reload the theme with current symbol preset override
1881
- theme = loadTheme(currentThemeName!, undefined, currentSymbolPresetOverride);
1882
- // Notify callback (to invalidate UI)
1883
- if (onThemeChangeCallback) {
1884
- onThemeChangeCallback();
1885
- }
1886
- } catch (err) {
1887
- logger.debug("Theme reload error during file change", { error: String(err) });
1888
- }
1949
+ loadTheme(currentThemeName!, getCurrentThemeOptions())
1950
+ .then(loadedTheme => {
1951
+ theme = loadedTheme;
1952
+ if (onThemeChangeCallback) {
1953
+ onThemeChangeCallback();
1954
+ }
1955
+ })
1956
+ .catch(err => {
1957
+ logger.debug("Theme reload error during file change", { error: String(err) });
1958
+ });
1889
1959
  }, 100);
1890
1960
  } else if (eventType === "rename") {
1891
1961
  // File was deleted or renamed - fall back to default theme
1892
1962
  setTimeout(() => {
1893
1963
  if (!fs.existsSync(themeFile)) {
1894
1964
  currentThemeName = "dark";
1895
- theme = loadTheme("dark");
1965
+ loadTheme("dark", getCurrentThemeOptions())
1966
+ .then(loadedTheme => {
1967
+ theme = loadedTheme;
1968
+ if (onThemeChangeCallback) {
1969
+ onThemeChangeCallback();
1970
+ }
1971
+ })
1972
+ .catch(err => {
1973
+ logger.debug("Theme reload error during rename fallback", { error: String(err) });
1974
+ });
1896
1975
  if (themeWatcher) {
1897
1976
  themeWatcher.close();
1898
1977
  themeWatcher = undefined;
1899
1978
  }
1900
- if (onThemeChangeCallback) {
1901
- onThemeChangeCallback();
1902
- }
1903
1979
  }
1904
1980
  }, 100);
1905
1981
  }
@@ -1970,10 +2046,10 @@ function ansi256ToHex(index: number): string {
1970
2046
  * Get resolved theme colors as CSS-compatible hex strings.
1971
2047
  * Used by HTML export to generate CSS custom properties.
1972
2048
  */
1973
- export function getResolvedThemeColors(themeName?: string): Record<string, string> {
2049
+ export async function getResolvedThemeColors(themeName?: string): Promise<Record<string, string>> {
1974
2050
  const name = themeName ?? getDefaultTheme();
1975
2051
  const isLight = name === "light";
1976
- const themeJson = loadThemeJson(name);
2052
+ const themeJson = await loadThemeJson(name);
1977
2053
  const resolved = resolveThemeColors(themeJson.colors, themeJson.vars);
1978
2054
 
1979
2055
  // Default text color for empty values (terminal uses default fg color)
@@ -2005,14 +2081,14 @@ export function isLightTheme(themeName?: string): boolean {
2005
2081
  * Get explicit export colors from theme JSON, if specified.
2006
2082
  * Returns undefined for each color that isn't explicitly set.
2007
2083
  */
2008
- export function getThemeExportColors(themeName?: string): {
2084
+ export async function getThemeExportColors(themeName?: string): Promise<{
2009
2085
  pageBg?: string;
2010
2086
  cardBg?: string;
2011
2087
  infoBg?: string;
2012
- } {
2088
+ }> {
2013
2089
  const name = themeName ?? getDefaultTheme();
2014
2090
  try {
2015
- const themeJson = loadThemeJson(name);
2091
+ const themeJson = await loadThemeJson(name);
2016
2092
  const exportSection = themeJson.export;
2017
2093
  if (!exportSection) return {};
2018
2094
 
@@ -2224,6 +2300,7 @@ export function getMarkdownTheme(): MarkdownTheme {
2224
2300
  underline: (text: string) => theme.underline(text),
2225
2301
  strikethrough: (text: string) => chalk.strikethrough(text),
2226
2302
  symbols: getSymbolTheme(),
2303
+ getMermaidImage,
2227
2304
  highlightCode: (code: string, lang?: string): string[] => {
2228
2305
  // Validate language before highlighting to avoid stderr spam from cli-highlight
2229
2306
  const validLang = lang && supportsLanguage(lang) ? lang : undefined;
@@ -2235,7 +2312,7 @@ export function getMarkdownTheme(): MarkdownTheme {
2235
2312
  try {
2236
2313
  return highlight(code, opts).split("\n");
2237
2314
  } catch {
2238
- return code.split("\n").map((line) => theme.fg("mdCodeBlock", line));
2315
+ return code.split("\n").map(line => theme.fg("mdCodeBlock", line));
2239
2316
  }
2240
2317
  },
2241
2318
  };
@@ -1,14 +1,14 @@
1
1
  import type { AgentMessage } from "@oh-my-pi/pi-agent-core";
2
2
  import type { AssistantMessage, ImageContent, Message, UsageReport } from "@oh-my-pi/pi-ai";
3
- import type { KeybindingsManager } from "@oh-my-pi/pi-coding-agent/config/keybindings";
4
- import type { SettingsManager } from "@oh-my-pi/pi-coding-agent/config/settings-manager";
5
- import type { ExtensionUIContext } from "@oh-my-pi/pi-coding-agent/extensibility/extensions/index";
6
- import type { CompactOptions } from "@oh-my-pi/pi-coding-agent/extensibility/extensions/types";
7
- import type { MCPManager } from "@oh-my-pi/pi-coding-agent/mcp/index";
8
- import type { AgentSession, AgentSessionEvent } from "@oh-my-pi/pi-coding-agent/session/agent-session";
9
- import type { HistoryStorage } from "@oh-my-pi/pi-coding-agent/session/history-storage";
10
- import type { SessionContext, SessionManager } from "@oh-my-pi/pi-coding-agent/session/session-manager";
11
3
  import type { Component, Container, Loader, Spacer, Text, TUI } from "@oh-my-pi/pi-tui";
4
+ import type { KeybindingsManager } from "../config/keybindings";
5
+ import type { SettingsManager } from "../config/settings-manager";
6
+ import type { ExtensionUIContext } from "../extensibility/extensions";
7
+ import type { CompactOptions } from "../extensibility/extensions/types";
8
+ import type { MCPManager } from "../mcp";
9
+ import type { AgentSession, AgentSessionEvent } from "../session/agent-session";
10
+ import type { HistoryStorage } from "../session/history-storage";
11
+ import type { SessionContext, SessionManager } from "../session/session-manager";
12
12
  import type { AssistantMessageComponent } from "./components/assistant-message";
13
13
  import type { BashExecutionComponent } from "./components/bash-execution";
14
14
  import type { CustomEditor } from "./components/custom-editor";
@@ -132,9 +132,9 @@ export interface InteractiveModeContext {
132
132
  handleExportCommand(text: string): Promise<void>;
133
133
  handleShareCommand(): Promise<void>;
134
134
  handleCopyCommand(): Promise<void>;
135
- handleSessionCommand(): void;
135
+ handleSessionCommand(): Promise<void>;
136
136
  handleUsageCommand(reports?: UsageReport[] | null): Promise<void>;
137
- handleChangelogCommand(): void;
137
+ handleChangelogCommand(): Promise<void>;
138
138
  handleHotkeysCommand(): void;
139
139
  handleDumpCommand(): Promise<void>;
140
140
  handleClearCommand(): Promise<void>;
@@ -1,20 +1,20 @@
1
1
  import type { AgentMessage } from "@oh-my-pi/pi-agent-core";
2
2
  import type { AssistantMessage, Message } from "@oh-my-pi/pi-ai";
3
- import { AssistantMessageComponent } from "@oh-my-pi/pi-coding-agent/modes/components/assistant-message";
4
- import { BashExecutionComponent } from "@oh-my-pi/pi-coding-agent/modes/components/bash-execution";
5
- import { BranchSummaryMessageComponent } from "@oh-my-pi/pi-coding-agent/modes/components/branch-summary-message";
6
- import { CompactionSummaryMessageComponent } from "@oh-my-pi/pi-coding-agent/modes/components/compaction-summary-message";
7
- import { CustomMessageComponent } from "@oh-my-pi/pi-coding-agent/modes/components/custom-message";
8
- import { DynamicBorder } from "@oh-my-pi/pi-coding-agent/modes/components/dynamic-border";
9
- import { PythonExecutionComponent } from "@oh-my-pi/pi-coding-agent/modes/components/python-execution";
10
- import { ReadToolGroupComponent } from "@oh-my-pi/pi-coding-agent/modes/components/read-tool-group";
11
- import { ToolExecutionComponent } from "@oh-my-pi/pi-coding-agent/modes/components/tool-execution";
12
- import { UserMessageComponent } from "@oh-my-pi/pi-coding-agent/modes/components/user-message";
13
- import { theme } from "@oh-my-pi/pi-coding-agent/modes/theme/theme";
14
- import type { CompactionQueuedMessage, InteractiveModeContext } from "@oh-my-pi/pi-coding-agent/modes/types";
15
- import type { CustomMessage } from "@oh-my-pi/pi-coding-agent/session/messages";
16
- import type { SessionContext } from "@oh-my-pi/pi-coding-agent/session/session-manager";
17
3
  import { Spacer, Text, TruncatedText } from "@oh-my-pi/pi-tui";
4
+ import { AssistantMessageComponent } from "../../modes/components/assistant-message";
5
+ import { BashExecutionComponent } from "../../modes/components/bash-execution";
6
+ import { BranchSummaryMessageComponent } from "../../modes/components/branch-summary-message";
7
+ import { CompactionSummaryMessageComponent } from "../../modes/components/compaction-summary-message";
8
+ import { CustomMessageComponent } from "../../modes/components/custom-message";
9
+ import { DynamicBorder } from "../../modes/components/dynamic-border";
10
+ import { PythonExecutionComponent } from "../../modes/components/python-execution";
11
+ import { ReadToolGroupComponent } from "../../modes/components/read-tool-group";
12
+ import { ToolExecutionComponent } from "../../modes/components/tool-execution";
13
+ import { UserMessageComponent } from "../../modes/components/user-message";
14
+ import { theme } from "../../modes/theme/theme";
15
+ import type { CompactionQueuedMessage, InteractiveModeContext } from "../../modes/types";
16
+ import type { CustomMessage } from "../../session/messages";
17
+ import type { SessionContext } from "../../session/session-manager";
18
18
 
19
19
  type TextBlock = { type: "text"; text: string };
20
20
 
@@ -33,7 +33,7 @@ export class UiHelpers {
33
33
  typeof message.content === "string"
34
34
  ? [{ type: "text", text: message.content }]
35
35
  : message.content.filter((content): content is TextBlock => content.type === "text");
36
- return textBlocks.map((block) => block.text).join("");
36
+ return textBlocks.map(block => block.text).join("");
37
37
  }
38
38
 
39
39
  /**
@@ -306,7 +306,7 @@ export class UiHelpers {
306
306
 
307
307
  showNewVersionNotification(newVersion: string): void {
308
308
  this.ctx.chatContainer.addChild(new Spacer(1));
309
- this.ctx.chatContainer.addChild(new DynamicBorder((text) => theme.fg("warning", text)));
309
+ this.ctx.chatContainer.addChild(new DynamicBorder(text => theme.fg("warning", text)));
310
310
  this.ctx.chatContainer.addChild(
311
311
  new Text(
312
312
  theme.bold(theme.fg("warning", "Update Available")) +
@@ -317,7 +317,7 @@ export class UiHelpers {
317
317
  0,
318
318
  ),
319
319
  );
320
- this.ctx.chatContainer.addChild(new DynamicBorder((text) => theme.fg("warning", text)));
320
+ this.ctx.chatContainer.addChild(new DynamicBorder(text => theme.fg("warning", text)));
321
321
  this.ctx.ui.requestRender();
322
322
  }
323
323
 
@@ -4,10 +4,9 @@
4
4
  * Applies parsed diff hunks to file content using fuzzy matching
5
5
  * for robust handling of whitespace and formatting differences.
6
6
  */
7
-
8
- import { mkdirSync, unlinkSync } from "node:fs";
9
- import { dirname } from "node:path";
10
- import { resolveToCwd } from "@oh-my-pi/pi-coding-agent/tools/path-utils";
7
+ import * as fs from "node:fs/promises";
8
+ import * as path from "node:path";
9
+ import { resolveToCwd } from "../tools/path-utils";
11
10
  import { DEFAULT_FUZZY_THRESHOLD, findContextLine, findMatch, seekSequence } from "./fuzzy";
12
11
  import {
13
12
  adjustIndentation,
@@ -51,10 +50,10 @@ export const defaultFileSystem: FileSystem = {
51
50
  await Bun.write(path, content);
52
51
  },
53
52
  async delete(path: string): Promise<void> {
54
- unlinkSync(path);
53
+ await fs.unlink(path);
55
54
  },
56
55
  async mkdir(path: string): Promise<void> {
57
- mkdirSync(path, { recursive: true });
56
+ await fs.mkdir(path, { recursive: true });
58
57
  },
59
58
  };
60
59
 
@@ -204,14 +203,14 @@ function adjustLinesIndentation(patternLines: string[], actualLines: string[], n
204
203
  deltas.push(aIndent - pIndent);
205
204
  }
206
205
 
207
- if (deltas.length > 0 && deltas.every((value) => value === deltas[0])) {
206
+ if (deltas.length > 0 && deltas.every(value => value === deltas[0])) {
208
207
  delta = deltas[0];
209
208
  }
210
209
 
211
210
  // Track which actual lines we've used to handle duplicate content correctly
212
211
  const usedActualLines = new Map<string, number>(); // trimmed content -> count used
213
212
 
214
- return newLines.map((newLine) => {
213
+ return newLines.map(newLine => {
215
214
  if (newLine.trim().length === 0) {
216
215
  return newLine;
217
216
  }
@@ -277,7 +276,7 @@ function trimCommonContext(oldLines: string[], newLines: string[]): HunkVariant
277
276
  }
278
277
 
279
278
  function collapseConsecutiveSharedLines(oldLines: string[], newLines: string[]): HunkVariant | undefined {
280
- const shared = new Set(oldLines.filter((line) => newLines.includes(line)));
279
+ const shared = new Set(oldLines.filter(line => newLines.includes(line)));
281
280
  const collapse = (lines: string[]): string[] => {
282
281
  const out: string[] = [];
283
282
  let i = 0;
@@ -302,7 +301,7 @@ function collapseConsecutiveSharedLines(oldLines: string[], newLines: string[]):
302
301
  }
303
302
 
304
303
  function collapseRepeatedBlocks(oldLines: string[], newLines: string[]): HunkVariant | undefined {
305
- const shared = new Set(oldLines.filter((line) => newLines.includes(line)));
304
+ const shared = new Set(oldLines.filter(line => newLines.includes(line)));
306
305
  const collapse = (lines: string[]): string[] => {
307
306
  const output = [...lines];
308
307
  let changed = false;
@@ -313,7 +312,7 @@ function collapseRepeatedBlocks(oldLines: string[], newLines: string[]): HunkVar
313
312
  const first = output.slice(i, i + size);
314
313
  const second = output.slice(i + size, i + size * 2);
315
314
  if (first.length !== second.length || first.length === 0) continue;
316
- if (!first.every((line) => shared.has(line))) continue;
315
+ if (!first.every(line => shared.has(line))) continue;
317
316
  let same = true;
318
317
  for (let idx = 0; idx < size; idx++) {
319
318
  if (first[idx] !== second[idx]) {
@@ -379,7 +378,7 @@ function buildFallbackVariants(hunk: DiffHunk): HunkVariant[] {
379
378
  if (singleLine) variants.push(singleLine);
380
379
 
381
380
  const seen = new Set<string>();
382
- return variants.filter((variant) => {
381
+ return variants.filter(variant => {
383
382
  if (variant.oldLines.length === 0 && variant.newLines.length === 0) return false;
384
383
  const key = `${variant.oldLines.join("\n")}||${variant.newLines.join("\n")}`;
385
384
  if (seen.has(key)) return false;
@@ -443,8 +442,8 @@ function findHierarchicalContext(
443
442
  if (context.includes("\n")) {
444
443
  const parts = context
445
444
  .split("\n")
446
- .map((p) => p.trim())
447
- .filter((p) => p.length > 0);
445
+ .map(p => p.trim())
446
+ .filter(p => p.length > 0);
448
447
  let currentStart = startFrom;
449
448
 
450
449
  for (let i = 0; i < parts.length; i++) {
@@ -488,7 +487,7 @@ function findHierarchicalContext(
488
487
  }
489
488
 
490
489
  // Try literal context first
491
- const spaceParts = context.split(/\s+/).filter((p) => p.length > 0);
490
+ const spaceParts = context.split(/\s+/).filter(p => p.length > 0);
492
491
  const hasSignatureChars = /[(){}[\]]/.test(context);
493
492
  if (!hasSignatureChars && spaceParts.length > 2) {
494
493
  const outer = spaceParts.slice(0, -1).join(" ");
@@ -899,7 +898,7 @@ function computeReplacements(
899
898
  for (const variant of buildFallbackVariants(hunk)) {
900
899
  if (variant.oldLines.length !== 1 || variant.newLines.length !== 1) continue;
901
900
  const removedLine = variant.oldLines[0];
902
- const hasSharedDuplicate = hunk.newLines.some((line) => line.trim() === removedLine.trim());
901
+ const hasSharedDuplicate = hunk.newLines.some(line => line.trim() === removedLine.trim());
903
902
  const adjacentIndex = findContextRelativeMatch(
904
903
  originalLines,
905
904
  removedLine,
@@ -922,7 +921,7 @@ function computeReplacements(
922
921
  if (line.trim() === trimmed) occurrenceCount++;
923
922
  }
924
923
  if (occurrenceCount > 1) {
925
- const hasSharedDuplicate = hunk.newLines.some((line) => line.trim() === trimmed);
924
+ const hasSharedDuplicate = hunk.newLines.some(line => line.trim() === trimmed);
926
925
  const contextMatch = findContextRelativeMatch(originalLines, pattern[0], contextIndex, hasSharedDuplicate);
927
926
  if (contextMatch !== undefined) {
928
927
  searchResult = { index: contextMatch, confidence: searchResult.confidence ?? 0.95 };
@@ -1113,7 +1112,7 @@ async function applyNormalizedPatch(
1113
1112
  const content = normalizedContent.endsWith("\n") ? normalizedContent : `${normalizedContent}\n`;
1114
1113
 
1115
1114
  if (!dryRun) {
1116
- const parentDir = dirname(absolutePath);
1115
+ const parentDir = path.dirname(absolutePath);
1117
1116
  if (parentDir && parentDir !== ".") {
1118
1117
  await fs.mkdir(parentDir);
1119
1118
  }
@@ -1182,7 +1181,7 @@ async function applyNormalizedPatch(
1182
1181
 
1183
1182
  if (!dryRun) {
1184
1183
  if (isMove) {
1185
- const parentDir = dirname(destPath);
1184
+ const parentDir = path.dirname(destPath);
1186
1185
  if (parentDir && parentDir !== ".") {
1187
1186
  await fs.mkdir(parentDir);
1188
1187
  }
package/src/patch/diff.ts CHANGED
@@ -4,9 +4,8 @@
4
4
  * Provides diff string generation and the replace-mode edit logic
5
5
  * used when not in patch mode.
6
6
  */
7
-
8
- import { resolveToCwd } from "@oh-my-pi/pi-coding-agent/tools/path-utils";
9
7
  import * as Diff from "diff";
8
+ import { resolveToCwd } from "../tools/path-utils";
10
9
  import { previewPatch } from "./applicator";
11
10
  import { DEFAULT_FUZZY_THRESHOLD, findMatch } from "./fuzzy";
12
11
  import { adjustIndentation, normalizeToLF, stripBom } from "./normalize";
@@ -4,7 +4,6 @@
4
4
  * Provides both character-level and line-level fuzzy matching with progressive
5
5
  * fallback strategies for finding text in files.
6
6
  */
7
-
8
7
  import { countLeadingWhitespace, normalizeForFuzzy, normalizeUnicode } from "./normalize";
9
8
  import type { ContextLineResult, FuzzyMatch, MatchOutcome, SequenceSearchResult } from "./types";
10
9
 
@@ -89,7 +88,7 @@ function computeRelativeIndentDepths(lines: string[]): number[] {
89
88
  }
90
89
  }
91
90
  const minIndent = nonEmptyIndents.length > 0 ? Math.min(...nonEmptyIndents) : 0;
92
- const indentSteps = nonEmptyIndents.map((indent) => indent - minIndent).filter((step) => step > 0);
91
+ const indentSteps = nonEmptyIndents.map(indent => indent - minIndent).filter(step => step > 0);
93
92
  const indentUnit = indentSteps.length > 0 ? Math.min(...indentSteps) : 1;
94
93
 
95
94
  return lines.map((line, index) => {