@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,15 @@
1
1
  import { spawn } from "node:child_process";
2
- import type { FileHandle } from "node:fs/promises";
3
- import { open, rm } from "node:fs/promises";
2
+ import * as fs from "node:fs/promises";
4
3
  import * as os from "node:os";
5
4
  import * as path from "node:path";
6
5
  import type { AgentMessage } from "@oh-my-pi/pi-agent-core";
7
- import { theme } from "@oh-my-pi/pi-coding-agent/modes/theme/theme";
8
- import type { InteractiveModeContext } from "@oh-my-pi/pi-coding-agent/modes/types";
9
- import type { AgentSessionEvent } from "@oh-my-pi/pi-coding-agent/session/agent-session";
10
- import { readImageFromClipboard } from "@oh-my-pi/pi-coding-agent/utils/clipboard";
11
- import { resizeImage } from "@oh-my-pi/pi-coding-agent/utils/image-resize";
12
- import { generateSessionTitle, setTerminalTitle } from "@oh-my-pi/pi-coding-agent/utils/title-generator";
13
6
  import { nanoid } from "nanoid";
7
+ import { theme } from "../../modes/theme/theme";
8
+ import type { InteractiveModeContext } from "../../modes/types";
9
+ import type { AgentSessionEvent } from "../../session/agent-session";
10
+ import { readImageFromClipboard } from "../../utils/clipboard";
11
+ import { resizeImage } from "../../utils/image-resize";
12
+ import { generateSessionTitle, setTerminalTitle } from "../../utils/title-generator";
14
13
 
15
14
  interface Expandable {
16
15
  setExpanded(expanded: boolean): void;
@@ -207,7 +206,7 @@ export class InputController {
207
206
  return;
208
207
  }
209
208
  if (text === "/session") {
210
- this.ctx.handleSessionCommand();
209
+ await this.ctx.handleSessionCommand();
211
210
  this.ctx.editor.setText("");
212
211
  return;
213
212
  }
@@ -217,7 +216,7 @@ export class InputController {
217
216
  return;
218
217
  }
219
218
  if (text === "/changelog") {
220
- this.ctx.handleChangelogCommand();
219
+ await this.ctx.handleChangelogCommand();
221
220
  this.ctx.editor.setText("");
222
221
  return;
223
222
  }
@@ -386,7 +385,7 @@ export class InputController {
386
385
  const registry = this.ctx.session.modelRegistry;
387
386
  const smolModel = this.ctx.settingsManager.getModelRole("smol");
388
387
  generateSessionTitle(text, registry, smolModel, this.ctx.session.sessionId)
389
- .then(async (title) => {
388
+ .then(async title => {
390
389
  if (title) {
391
390
  await this.ctx.sessionManager.setSessionTitle(title);
392
391
  setTerminalTitle(`π: ${title}`);
@@ -455,7 +454,7 @@ export class InputController {
455
454
  }
456
455
  const queuedText = allQueued.join("\n\n");
457
456
  const currentText = options?.currentText ?? this.ctx.editor.getText();
458
- const combinedText = [queuedText, currentText].filter((t) => t.trim()).join("\n\n");
457
+ const combinedText = [queuedText, currentText].filter(t => t.trim()).join("\n\n");
459
458
  this.ctx.editor.setText(combinedText);
460
459
  this.ctx.updatePendingMessagesDisplay();
461
460
  if (options?.abort) {
@@ -586,7 +585,7 @@ export class InputController {
586
585
  const tempLabel = options?.temporary ? " (temporary)" : "";
587
586
  const cycleSeparator = theme.fg("dim", " > ");
588
587
  const cycleLabel = roleOrder
589
- .map((role) => {
588
+ .map(role => {
590
589
  if (role === result.role) {
591
590
  return theme.bold(theme.fg("accent", role));
592
591
  }
@@ -638,13 +637,13 @@ export class InputController {
638
637
  return "/dev/tty";
639
638
  }
640
639
 
641
- private async openEditorTerminalHandle(): Promise<FileHandle | null> {
640
+ private async openEditorTerminalHandle(): Promise<fs.FileHandle | null> {
642
641
  const terminalPath = this.getEditorTerminalPath();
643
642
  if (!terminalPath) {
644
643
  return null;
645
644
  }
646
645
  try {
647
- return await open(terminalPath, "r+");
646
+ return await fs.open(terminalPath, "r+");
648
647
  } catch {
649
648
  return null;
650
649
  }
@@ -661,7 +660,7 @@ export class InputController {
661
660
  const currentText = this.ctx.editor.getText();
662
661
  const tmpFile = path.join(os.tmpdir(), `omp-editor-${nanoid()}.omp.md`);
663
662
 
664
- let ttyHandle: FileHandle | null = null;
663
+ let ttyHandle: fs.FileHandle | null = null;
665
664
  try {
666
665
  // Write current content to temp file
667
666
  await Bun.write(tmpFile, currentText);
@@ -680,7 +679,7 @@ export class InputController {
680
679
  const child = spawn(editor, [...editorArgs, tmpFile], { stdio });
681
680
  const exitCode = await new Promise<number>((resolve, reject) => {
682
681
  child.once("exit", (code, signal) => resolve(code ?? (signal ? -1 : 0)));
683
- child.once("error", (error) => reject(error));
682
+ child.once("error", error => reject(error));
684
683
  });
685
684
 
686
685
  // On successful exit (exitCode 0), replace editor content
@@ -696,7 +695,7 @@ export class InputController {
696
695
  } finally {
697
696
  // Clean up temp file
698
697
  try {
699
- await rm(tmpFile, { force: true });
698
+ await fs.rm(tmpFile, { force: true });
700
699
  } catch {
701
700
  // Ignore cleanup errors
702
701
  }
@@ -1,29 +1,30 @@
1
1
  import type { ThinkingLevel } from "@oh-my-pi/pi-agent-core";
2
2
  import type { OAuthProvider } from "@oh-my-pi/pi-ai";
3
- import { getAgentDbPath } from "@oh-my-pi/pi-coding-agent/config";
4
- import { disableProvider, enableProvider } from "@oh-my-pi/pi-coding-agent/discovery";
5
- import { AssistantMessageComponent } from "@oh-my-pi/pi-coding-agent/modes/components/assistant-message";
6
- import { ExtensionDashboard } from "@oh-my-pi/pi-coding-agent/modes/components/extensions";
7
- import { HistorySearchComponent } from "@oh-my-pi/pi-coding-agent/modes/components/history-search";
8
- import { ModelSelectorComponent } from "@oh-my-pi/pi-coding-agent/modes/components/model-selector";
9
- import { OAuthSelectorComponent } from "@oh-my-pi/pi-coding-agent/modes/components/oauth-selector";
10
- import { SessionSelectorComponent } from "@oh-my-pi/pi-coding-agent/modes/components/session-selector";
11
- import { SettingsSelectorComponent } from "@oh-my-pi/pi-coding-agent/modes/components/settings-selector";
12
- import { ToolExecutionComponent } from "@oh-my-pi/pi-coding-agent/modes/components/tool-execution";
13
- import { TreeSelectorComponent } from "@oh-my-pi/pi-coding-agent/modes/components/tree-selector";
14
- import { UserMessageSelectorComponent } from "@oh-my-pi/pi-coding-agent/modes/components/user-message-selector";
3
+ import type { Component } from "@oh-my-pi/pi-tui";
4
+ import { Input, Loader, Spacer, Text } from "@oh-my-pi/pi-tui";
5
+ import { getAgentDbPath } from "../../config";
6
+ import { disableProvider, enableProvider } from "../../discovery";
7
+ import { AssistantMessageComponent } from "../../modes/components/assistant-message";
8
+ import { ExtensionDashboard } from "../../modes/components/extensions";
9
+ import { HistorySearchComponent } from "../../modes/components/history-search";
10
+ import { ModelSelectorComponent } from "../../modes/components/model-selector";
11
+ import { OAuthSelectorComponent } from "../../modes/components/oauth-selector";
12
+ import { SessionSelectorComponent } from "../../modes/components/session-selector";
13
+ import { SettingsSelectorComponent } from "../../modes/components/settings-selector";
14
+ import { ToolExecutionComponent } from "../../modes/components/tool-execution";
15
+ import { TreeSelectorComponent } from "../../modes/components/tree-selector";
16
+ import { UserMessageSelectorComponent } from "../../modes/components/user-message-selector";
15
17
  import {
16
18
  getAvailableThemes,
17
19
  getSymbolTheme,
20
+ setColorBlindMode,
18
21
  setSymbolPreset,
19
22
  setTheme,
20
23
  theme,
21
- } from "@oh-my-pi/pi-coding-agent/modes/theme/theme";
22
- import type { InteractiveModeContext } from "@oh-my-pi/pi-coding-agent/modes/types";
23
- import { SessionManager } from "@oh-my-pi/pi-coding-agent/session/session-manager";
24
- import { setPreferredImageProvider, setPreferredWebSearchProvider } from "@oh-my-pi/pi-coding-agent/tools/index";
25
- import type { Component } from "@oh-my-pi/pi-tui";
26
- import { Input, Loader, Spacer, Text } from "@oh-my-pi/pi-tui";
24
+ } from "../../modes/theme/theme";
25
+ import type { InteractiveModeContext } from "../../modes/types";
26
+ import { SessionManager } from "../../session/session-manager";
27
+ import { setPreferredImageProvider, setPreferredWebSearchProvider } from "../../tools";
27
28
 
28
29
  export class SelectorController {
29
30
  constructor(private ctx: InteractiveModeContext) {}
@@ -46,49 +47,52 @@ export class SelectorController {
46
47
  }
47
48
 
48
49
  showSettingsSelector(): void {
49
- this.showSelector((done) => {
50
- const selector = new SettingsSelectorComponent(
51
- this.ctx.settingsManager,
52
- {
53
- availableThinkingLevels: this.ctx.session.getAvailableThinkingLevels(),
54
- thinkingLevel: this.ctx.session.thinkingLevel,
55
- availableThemes: getAvailableThemes(),
56
- cwd: process.cwd(),
57
- },
58
- {
59
- onChange: (id, value) => this.handleSettingChange(id, value),
60
- onThemePreview: (themeName) => {
61
- const result = setTheme(themeName, true);
62
- if (result.success) {
63
- this.ctx.ui.invalidate();
64
- this.ctx.ui.requestRender();
65
- }
50
+ getAvailableThemes().then(availableThemes => {
51
+ this.showSelector(done => {
52
+ const selector = new SettingsSelectorComponent(
53
+ this.ctx.settingsManager,
54
+ {
55
+ availableThinkingLevels: this.ctx.session.getAvailableThinkingLevels(),
56
+ thinkingLevel: this.ctx.session.thinkingLevel,
57
+ availableThemes,
58
+ cwd: process.cwd(),
66
59
  },
67
- onStatusLinePreview: (settings) => {
68
- // Update status line with preview settings
69
- const currentSettings = this.ctx.settingsManager.getStatusLineSettings();
70
- this.ctx.statusLine.updateSettings({ ...currentSettings, ...settings });
71
- this.ctx.updateEditorTopBorder();
72
- this.ctx.ui.requestRender();
73
- },
74
- getStatusLinePreview: () => {
75
- // Return the rendered status line for inline preview
76
- const width = this.ctx.ui.getWidth();
77
- return this.ctx.statusLine.getTopBorder(width).content;
78
- },
79
- onPluginsChanged: () => {
80
- this.ctx.ui.requestRender();
81
- },
82
- onCancel: () => {
83
- done();
84
- // Restore status line to saved settings
85
- this.ctx.statusLine.updateSettings(this.ctx.settingsManager.getStatusLineSettings());
86
- this.ctx.updateEditorTopBorder();
87
- this.ctx.ui.requestRender();
60
+ {
61
+ onChange: (id, value) => this.handleSettingChange(id, value),
62
+ onThemePreview: themeName => {
63
+ setTheme(themeName, true).then(result => {
64
+ if (result.success) {
65
+ this.ctx.ui.invalidate();
66
+ this.ctx.ui.requestRender();
67
+ }
68
+ });
69
+ },
70
+ onStatusLinePreview: settings => {
71
+ // Update status line with preview settings
72
+ const currentSettings = this.ctx.settingsManager.getStatusLineSettings();
73
+ this.ctx.statusLine.updateSettings({ ...currentSettings, ...settings });
74
+ this.ctx.updateEditorTopBorder();
75
+ this.ctx.ui.requestRender();
76
+ },
77
+ getStatusLinePreview: () => {
78
+ // Return the rendered status line for inline preview
79
+ const width = this.ctx.ui.getWidth();
80
+ return this.ctx.statusLine.getTopBorder(width).content;
81
+ },
82
+ onPluginsChanged: () => {
83
+ this.ctx.ui.requestRender();
84
+ },
85
+ onCancel: () => {
86
+ done();
87
+ // Restore status line to saved settings
88
+ this.ctx.statusLine.updateSettings(this.ctx.settingsManager.getStatusLineSettings());
89
+ this.ctx.updateEditorTopBorder();
90
+ this.ctx.ui.requestRender();
91
+ },
88
92
  },
89
- },
90
- );
91
- return { component: selector, focus: selector };
93
+ );
94
+ return { component: selector, focus: selector };
95
+ });
92
96
  });
93
97
  }
94
98
 
@@ -96,10 +100,10 @@ export class SelectorController {
96
100
  const historyStorage = this.ctx.historyStorage;
97
101
  if (!historyStorage) return;
98
102
 
99
- this.showSelector((done) => {
103
+ this.showSelector(done => {
100
104
  const component = new HistorySearchComponent(
101
105
  historyStorage,
102
- (prompt) => {
106
+ prompt => {
103
107
  done();
104
108
  this.ctx.editor.setText(prompt);
105
109
  this.ctx.ui.requestRender();
@@ -123,7 +127,7 @@ export class SelectorController {
123
127
  this.ctx.settingsManager,
124
128
  this.ctx.ui.terminal.rows,
125
129
  );
126
- this.showSelector((done) => {
130
+ this.showSelector(done => {
127
131
  dashboard.onClose = () => {
128
132
  done();
129
133
  this.ctx.ui.requestRender();
@@ -189,20 +193,28 @@ export class SelectorController {
189
193
  this.ctx.rebuildChatFromMessages();
190
194
  break;
191
195
  case "theme": {
192
- const result = setTheme(value as string, true);
193
- this.ctx.statusLine.invalidate();
194
- this.ctx.updateEditorTopBorder();
195
- this.ctx.ui.invalidate();
196
- if (!result.success) {
197
- this.ctx.showError(`Failed to load theme "${value}": ${result.error}\nFell back to dark theme.`);
198
- }
196
+ setTheme(value as string, true).then(result => {
197
+ this.ctx.statusLine.invalidate();
198
+ this.ctx.updateEditorTopBorder();
199
+ this.ctx.ui.invalidate();
200
+ if (!result.success) {
201
+ this.ctx.showError(`Failed to load theme "${value}": ${result.error}\nFell back to dark theme.`);
202
+ }
203
+ });
199
204
  break;
200
205
  }
201
206
  case "symbolPreset": {
202
- setSymbolPreset(value as "unicode" | "nerd" | "ascii");
203
- this.ctx.statusLine.invalidate();
204
- this.ctx.updateEditorTopBorder();
205
- this.ctx.ui.invalidate();
207
+ setSymbolPreset(value as "unicode" | "nerd" | "ascii").then(() => {
208
+ this.ctx.statusLine.invalidate();
209
+ this.ctx.updateEditorTopBorder();
210
+ this.ctx.ui.invalidate();
211
+ });
212
+ break;
213
+ }
214
+ case "colorBlindMode": {
215
+ setColorBlindMode(value === "true" || value === true).then(() => {
216
+ this.ctx.ui.invalidate();
217
+ });
206
218
  break;
207
219
  }
208
220
  case "statusLinePreset":
@@ -239,7 +251,7 @@ export class SelectorController {
239
251
  }
240
252
 
241
253
  showModelSelector(options?: { temporaryOnly?: boolean }): void {
242
- this.showSelector((done) => {
254
+ this.showSelector(done => {
243
255
  const selector = new ModelSelectorComponent(
244
256
  this.ctx.ui,
245
257
  this.ctx.session.model,
@@ -291,10 +303,10 @@ export class SelectorController {
291
303
  return;
292
304
  }
293
305
 
294
- this.showSelector((done) => {
306
+ this.showSelector(done => {
295
307
  const selector = new UserMessageSelectorComponent(
296
- userMessages.map((m) => ({ id: m.entryId, text: m.text })),
297
- async (entryId) => {
308
+ userMessages.map(m => ({ id: m.entryId, text: m.text })),
309
+ async entryId => {
298
310
  const result = await this.ctx.session.branch(entryId);
299
311
  if (result.cancelled) {
300
312
  // Hook cancelled the branch
@@ -336,12 +348,12 @@ export class SelectorController {
336
348
  return;
337
349
  }
338
350
 
339
- this.showSelector((done) => {
351
+ this.showSelector(done => {
340
352
  const selector = new TreeSelectorComponent(
341
353
  tree,
342
354
  visibleLeafId,
343
355
  this.ctx.ui.terminal.rows,
344
- async (entryId) => {
356
+ async entryId => {
345
357
  // Selecting the visible leaf is a no-op (already there)
346
358
  if (entryId === visibleLeafId) {
347
359
  done();
@@ -396,8 +408,8 @@ export class SelectorController {
396
408
  this.ctx.chatContainer.addChild(new Spacer(1));
397
409
  summaryLoader = new Loader(
398
410
  this.ctx.ui,
399
- (spinner) => theme.fg("accent", spinner),
400
- (text) => theme.fg("muted", text),
411
+ spinner => theme.fg("accent", spinner),
412
+ text => theme.fg("muted", text),
401
413
  "Summarizing branch... (esc to cancel)",
402
414
  getSymbolTheme().spinnerFrames,
403
415
  );
@@ -453,15 +465,15 @@ export class SelectorController {
453
465
  });
454
466
  }
455
467
 
456
- showSessionSelector(): void {
457
- this.showSelector((done) => {
458
- const sessions = SessionManager.list(
459
- this.ctx.sessionManager.getCwd(),
460
- this.ctx.sessionManager.getSessionDir(),
461
- );
468
+ async showSessionSelector(): Promise<void> {
469
+ const sessions = await SessionManager.list(
470
+ this.ctx.sessionManager.getCwd(),
471
+ this.ctx.sessionManager.getSessionDir(),
472
+ );
473
+ this.showSelector(done => {
462
474
  const selector = new SessionSelectorComponent(
463
475
  sessions,
464
- async (sessionPath) => {
476
+ async sessionPath => {
465
477
  done();
466
478
  await this.handleResumeSession(sessionPath);
467
479
  },
@@ -505,14 +517,14 @@ export class SelectorController {
505
517
  async showOAuthSelector(mode: "login" | "logout"): Promise<void> {
506
518
  if (mode === "logout") {
507
519
  const providers = this.ctx.session.modelRegistry.authStorage.list();
508
- const loggedInProviders = providers.filter((p) => this.ctx.session.modelRegistry.authStorage.hasOAuth(p));
520
+ const loggedInProviders = providers.filter(p => this.ctx.session.modelRegistry.authStorage.hasOAuth(p));
509
521
  if (loggedInProviders.length === 0) {
510
522
  this.ctx.showStatus("No OAuth providers logged in. Use /login first.");
511
523
  return;
512
524
  }
513
525
  }
514
526
 
515
- this.showSelector((done) => {
527
+ this.showSelector(done => {
516
528
  const selector = new OAuthSelectorComponent(
517
529
  mode,
518
530
  this.ctx.session.modelRegistry.authStorage,
@@ -546,7 +558,7 @@ export class SelectorController {
546
558
  }
547
559
  this.ctx.ui.requestRender();
548
560
 
549
- return new Promise<string>((resolve) => {
561
+ return new Promise<string>(resolve => {
550
562
  const codeInput = new Input();
551
563
  codeInput.onSubmit = () => {
552
564
  const code = codeInput.getValue();
@@ -1,3 +1,6 @@
1
+ import { emergencyTerminalRestore } from "@oh-my-pi/pi-tui";
2
+ import { postmortem } from "@oh-my-pi/pi-utils";
3
+
1
4
  /**
2
5
  * Run modes for the coding agent.
3
6
  */
@@ -7,9 +10,6 @@ export { type ModelInfo, RpcClient, type RpcClientOptions, type RpcEventListener
7
10
  export { runRpcMode } from "./rpc/rpc-mode";
8
11
  export type { RpcCommand, RpcResponse, RpcSessionState } from "./rpc/rpc-types";
9
12
 
10
- import { emergencyTerminalRestore } from "@oh-my-pi/pi-tui";
11
- import { postmortem } from "@oh-my-pi/pi-utils";
12
-
13
13
  postmortem.register("terminal-restore", () => {
14
14
  emergencyTerminalRestore();
15
15
  });
@@ -2,20 +2,9 @@
2
2
  * Interactive mode for the coding agent.
3
3
  * Handles TUI rendering and user interaction, delegating business logic to AgentSession.
4
4
  */
5
-
6
5
  import * as path from "node:path";
7
6
  import type { AgentMessage } from "@oh-my-pi/pi-agent-core";
8
7
  import type { AssistantMessage, ImageContent, Message, UsageReport } from "@oh-my-pi/pi-ai";
9
- import { KeybindingsManager } from "@oh-my-pi/pi-coding-agent/config/keybindings";
10
- import type { SettingsManager } from "@oh-my-pi/pi-coding-agent/config/settings-manager";
11
- import type { ExtensionUIContext } from "@oh-my-pi/pi-coding-agent/extensibility/extensions/index";
12
- import type { CompactOptions } from "@oh-my-pi/pi-coding-agent/extensibility/extensions/types";
13
- import { loadSlashCommands } from "@oh-my-pi/pi-coding-agent/extensibility/slash-commands";
14
- import type { AgentSession, AgentSessionEvent } from "@oh-my-pi/pi-coding-agent/session/agent-session";
15
- import { HistoryStorage } from "@oh-my-pi/pi-coding-agent/session/history-storage";
16
- import type { SessionContext, SessionManager } from "@oh-my-pi/pi-coding-agent/session/session-manager";
17
- import { getRecentSessions } from "@oh-my-pi/pi-coding-agent/session/session-manager";
18
- import { setTerminalTitle } from "@oh-my-pi/pi-coding-agent/utils/title-generator";
19
8
  import type { Component, Loader, SlashCommand } from "@oh-my-pi/pi-tui";
20
9
  import {
21
10
  CombinedAutocompleteProvider,
@@ -26,8 +15,18 @@ import {
26
15
  Text,
27
16
  TUI,
28
17
  } from "@oh-my-pi/pi-tui";
29
- import { logger, postmortem } from "@oh-my-pi/pi-utils";
18
+ import { isEnoent, logger, postmortem } from "@oh-my-pi/pi-utils";
30
19
  import chalk from "chalk";
20
+ import { KeybindingsManager } from "../config/keybindings";
21
+ import type { SettingsManager } from "../config/settings-manager";
22
+ import type { ExtensionUIContext } from "../extensibility/extensions";
23
+ import type { CompactOptions } from "../extensibility/extensions/types";
24
+ import { loadSlashCommands } from "../extensibility/slash-commands";
25
+ import type { AgentSession, AgentSessionEvent } from "../session/agent-session";
26
+ import { HistoryStorage } from "../session/history-storage";
27
+ import type { SessionContext, SessionManager } from "../session/session-manager";
28
+ import { getRecentSessions } from "../session/session-manager";
29
+ import { setTerminalTitle } from "../utils/title-generator";
31
30
  import type { AssistantMessageComponent } from "./components/assistant-message";
32
31
  import type { BashExecutionComponent } from "./components/bash-execution";
33
32
  import { CustomEditor } from "./components/custom-editor";
@@ -44,6 +43,7 @@ import { EventController } from "./controllers/event-controller";
44
43
  import { ExtensionUiController } from "./controllers/extension-ui-controller";
45
44
  import { InputController } from "./controllers/input-controller";
46
45
  import { SelectorController } from "./controllers/selector-controller";
46
+ import { setMermaidRenderCallback } from "./theme/mermaid-cache";
47
47
  import type { Theme } from "./theme/theme";
48
48
  import { getEditorTheme, getMarkdownTheme, onThemeChange, theme } from "./theme/theme";
49
49
  import type { CompactionQueuedMessage, InteractiveModeContext, TodoItem } from "./types";
@@ -124,7 +124,7 @@ export class InteractiveMode implements InteractiveModeContext {
124
124
  private readonly changelogMarkdown: string | undefined;
125
125
  public readonly lspServers: Array<{ name: string; status: "ready" | "error"; fileTypes: string[] }> | undefined =
126
126
  undefined;
127
- public mcpManager?: import("@oh-my-pi/pi-coding-agent/mcp/index").MCPManager;
127
+ public mcpManager?: import("@oh-my-pi/pi-coding-agent/mcp").MCPManager;
128
128
  private readonly toolUiContextSetter: (uiContext: ExtensionUIContext, hasUI: boolean) => void;
129
129
 
130
130
  private readonly commandController: CommandController;
@@ -140,7 +140,7 @@ export class InteractiveMode implements InteractiveModeContext {
140
140
  changelogMarkdown: string | undefined = undefined,
141
141
  setToolUIContext: (uiContext: ExtensionUIContext, hasUI: boolean) => void = () => {},
142
142
  lspServers: Array<{ name: string; status: "ready" | "error"; fileTypes: string[] }> | undefined = undefined,
143
- mcpManager?: import("@oh-my-pi/pi-coding-agent/mcp/index").MCPManager,
143
+ mcpManager?: import("@oh-my-pi/pi-coding-agent/mcp").MCPManager,
144
144
  ) {
145
145
  this.session = session;
146
146
  this.sessionManager = session.sessionManager;
@@ -154,6 +154,7 @@ export class InteractiveMode implements InteractiveModeContext {
154
154
  this.mcpManager = mcpManager;
155
155
 
156
156
  this.ui = new TUI(new ProcessTerminal(), this.settingsManager.getShowHardwareCursor());
157
+ setMermaidRenderCallback(() => this.ui.requestRender());
157
158
  this.chatContainer = new Container();
158
159
  this.pendingMessagesContainer = new Container();
159
160
  this.statusContainer = new Container();
@@ -205,14 +206,14 @@ export class InteractiveMode implements InteractiveModeContext {
205
206
  ];
206
207
 
207
208
  // Convert hook commands to SlashCommand format
208
- const hookCommands: SlashCommand[] = (this.session.extensionRunner?.getRegisteredCommands() ?? []).map((cmd) => ({
209
+ const hookCommands: SlashCommand[] = (this.session.extensionRunner?.getRegisteredCommands() ?? []).map(cmd => ({
209
210
  name: cmd.name,
210
211
  description: cmd.description ?? "(hook command)",
211
212
  getArgumentCompletions: cmd.getArgumentCompletions,
212
213
  }));
213
214
 
214
215
  // Convert custom commands (TypeScript) to SlashCommand format
215
- const customCommands: SlashCommand[] = this.session.customCommands.map((loaded) => ({
216
+ const customCommands: SlashCommand[] = this.session.customCommands.map(loaded => ({
216
217
  name: loaded.command.name,
217
218
  description: `${loaded.command.description} (${loaded.source})`,
218
219
  }));
@@ -248,8 +249,8 @@ export class InteractiveMode implements InteractiveModeContext {
248
249
 
249
250
  // Load and convert file commands to SlashCommand format (async)
250
251
  const fileCommands = await loadSlashCommands({ cwd: process.cwd() });
251
- this.fileSlashCommands = new Set(fileCommands.map((cmd) => cmd.name));
252
- const fileSlashCommands: SlashCommand[] = fileCommands.map((cmd) => ({
252
+ this.fileSlashCommands = new Set(fileCommands.map(cmd => cmd.name));
253
+ const fileSlashCommands: SlashCommand[] = fileCommands.map(cmd => ({
253
254
  name: cmd.name,
254
255
  description: cmd.description,
255
256
  }));
@@ -266,14 +267,14 @@ export class InteractiveMode implements InteractiveModeContext {
266
267
  const providerName = this.session.model?.provider ?? "Unknown";
267
268
 
268
269
  // Get recent sessions
269
- const recentSessions = getRecentSessions(this.sessionManager.getSessionDir()).map((s) => ({
270
+ const recentSessions = (await getRecentSessions(this.sessionManager.getSessionDir())).map(s => ({
270
271
  name: s.name,
271
272
  timeAgo: s.timeAgo,
272
273
  }));
273
274
 
274
275
  // Convert LSP servers to welcome format
275
276
  const lspServerInfo =
276
- this.lspServers?.map((s) => ({
277
+ this.lspServers?.map(s => ({
277
278
  name: s.name,
278
279
  status: s.status as "ready" | "error" | "connecting",
279
280
  fileTypes: s.fileTypes,
@@ -362,7 +363,7 @@ export class InteractiveMode implements InteractiveModeContext {
362
363
 
363
364
  async getUserInput(): Promise<{ text: string; images?: ImageContent[] }> {
364
365
  const { promise, resolve } = Promise.withResolvers<{ text: string; images?: ImageContent[] }>();
365
- this.onInputCallback = (input) => {
366
+ this.onInputCallback = input => {
366
367
  this.onInputCallback = undefined;
367
368
  resolve(input);
368
369
  };
@@ -450,17 +451,16 @@ export class InteractiveMode implements InteractiveModeContext {
450
451
  }
451
452
  const artifactsDir = sessionFile.slice(0, -6);
452
453
  const todoPath = path.join(artifactsDir, TODO_FILE_NAME);
453
- const file = Bun.file(todoPath);
454
- if (!(await file.exists())) {
455
- this.renderTodoList();
456
- return;
457
- }
458
454
  try {
459
- const data = (await file.json()) as { todos?: TodoItem[] };
455
+ const data = (await Bun.file(todoPath).json()) as { todos?: TodoItem[] };
460
456
  if (data?.todos && Array.isArray(data.todos)) {
461
457
  this.todoItems = data.todos;
462
458
  }
463
459
  } catch (error) {
460
+ if (isEnoent(error)) {
461
+ this.renderTodoList();
462
+ return;
463
+ }
464
464
  logger.warn("Failed to load todos", { path: todoPath, error: String(error) });
465
465
  }
466
466
  this.renderTodoList();
@@ -610,16 +610,16 @@ export class InteractiveMode implements InteractiveModeContext {
610
610
  return this.commandController.handleCopyCommand();
611
611
  }
612
612
 
613
- handleSessionCommand(): void {
614
- this.commandController.handleSessionCommand();
613
+ handleSessionCommand(): Promise<void> {
614
+ return this.commandController.handleSessionCommand();
615
615
  }
616
616
 
617
617
  handleUsageCommand(reports?: UsageReport[] | null): Promise<void> {
618
618
  return this.commandController.handleUsageCommand(reports);
619
619
  }
620
620
 
621
- handleChangelogCommand(): void {
622
- this.commandController.handleChangelogCommand();
621
+ async handleChangelogCommand(): Promise<void> {
622
+ await this.commandController.handleChangelogCommand();
623
623
  }
624
624
 
625
625
  handleHotkeysCommand(): void {