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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (402) hide show
  1. package/CHANGELOG.md +21 -1
  2. package/docs/session.md +111 -46
  3. package/examples/custom-tools/hello/index.ts +1 -1
  4. package/examples/custom-tools/todo/index.ts +3 -4
  5. package/examples/extensions/api-demo.ts +0 -1
  6. package/examples/extensions/chalk-logger.ts +2 -3
  7. package/examples/extensions/hello.ts +0 -1
  8. package/examples/extensions/pirate.ts +0 -1
  9. package/examples/extensions/plan-mode.ts +15 -16
  10. package/examples/extensions/todo.ts +3 -4
  11. package/examples/extensions/tools.ts +1 -2
  12. package/examples/extensions/with-deps/index.ts +0 -1
  13. package/examples/hooks/auto-commit-on-exit.ts +1 -2
  14. package/examples/hooks/confirm-destructive.ts +0 -1
  15. package/examples/hooks/custom-compaction.ts +1 -2
  16. package/examples/hooks/dirty-repo-guard.ts +0 -1
  17. package/examples/hooks/file-trigger.ts +3 -4
  18. package/examples/hooks/git-checkpoint.ts +0 -1
  19. package/examples/hooks/handoff.ts +3 -4
  20. package/examples/hooks/permission-gate.ts +1 -2
  21. package/examples/hooks/protected-paths.ts +1 -2
  22. package/examples/hooks/qna.ts +2 -3
  23. package/examples/hooks/snake.ts +4 -5
  24. package/examples/hooks/status-line.ts +0 -1
  25. package/examples/sdk/01-minimal.ts +2 -3
  26. package/examples/sdk/02-custom-model.ts +2 -3
  27. package/examples/sdk/03-custom-prompt.ts +3 -4
  28. package/examples/sdk/04-skills.ts +2 -3
  29. package/examples/sdk/06-extensions.ts +1 -2
  30. package/examples/sdk/06-hooks.ts +6 -7
  31. package/examples/sdk/07-context-files.ts +0 -1
  32. package/examples/sdk/08-prompt-templates.ts +0 -1
  33. package/examples/sdk/08-slash-commands.ts +0 -1
  34. package/examples/sdk/09-api-keys-and-oauth.ts +0 -1
  35. package/examples/sdk/10-settings.ts +0 -1
  36. package/examples/sdk/11-sessions.ts +0 -1
  37. package/package.json +51 -23
  38. package/scripts/format-prompts.ts +0 -1
  39. package/src/capability/context-file.ts +2 -3
  40. package/src/capability/extension-module.ts +2 -3
  41. package/src/capability/extension.ts +2 -3
  42. package/src/capability/fs.ts +20 -21
  43. package/src/capability/hook.ts +2 -3
  44. package/src/capability/index.ts +15 -16
  45. package/src/capability/instruction.ts +2 -3
  46. package/src/capability/mcp.ts +2 -3
  47. package/src/capability/prompt.ts +2 -3
  48. package/src/capability/rule.ts +2 -3
  49. package/src/capability/settings.ts +1 -2
  50. package/src/capability/skill.ts +2 -3
  51. package/src/capability/slash-command.ts +2 -3
  52. package/src/capability/ssh.ts +2 -3
  53. package/src/capability/system-prompt.ts +2 -3
  54. package/src/capability/tool.ts +2 -3
  55. package/src/cli/args.ts +5 -6
  56. package/src/cli/config-cli.ts +6 -7
  57. package/src/cli/file-processor.ts +19 -17
  58. package/src/cli/jupyter-cli.ts +105 -0
  59. package/src/cli/list-models.ts +10 -11
  60. package/src/cli/plugin-cli.ts +20 -21
  61. package/src/cli/session-picker.ts +2 -3
  62. package/src/cli/setup-cli.ts +2 -3
  63. package/src/cli/stats-cli.ts +2 -3
  64. package/src/cli/update-cli.ts +25 -22
  65. package/src/commit/agentic/agent.ts +21 -23
  66. package/src/commit/agentic/fallback.ts +9 -9
  67. package/src/commit/agentic/index.ts +30 -38
  68. package/src/commit/agentic/state.ts +1 -6
  69. package/src/commit/agentic/tools/analyze-file.ts +15 -15
  70. package/src/commit/agentic/tools/git-file-diff.ts +3 -3
  71. package/src/commit/agentic/tools/git-hunk.ts +7 -7
  72. package/src/commit/agentic/tools/git-overview.ts +5 -5
  73. package/src/commit/agentic/tools/index.ts +14 -14
  74. package/src/commit/agentic/tools/propose-changelog.ts +6 -6
  75. package/src/commit/agentic/tools/propose-commit.ts +8 -8
  76. package/src/commit/agentic/tools/recent-commits.ts +2 -2
  77. package/src/commit/agentic/tools/split-commit.ts +19 -23
  78. package/src/commit/agentic/topo-sort.ts +1 -1
  79. package/src/commit/agentic/trivial.ts +3 -3
  80. package/src/commit/agentic/validation.ts +12 -12
  81. package/src/commit/analysis/conventional.ts +7 -11
  82. package/src/commit/analysis/index.ts +4 -4
  83. package/src/commit/analysis/scope.ts +4 -4
  84. package/src/commit/analysis/summary.ts +7 -9
  85. package/src/commit/analysis/validation.ts +1 -1
  86. package/src/commit/changelog/detect.ts +6 -6
  87. package/src/commit/changelog/generate.ts +7 -9
  88. package/src/commit/changelog/index.ts +13 -13
  89. package/src/commit/changelog/parse.ts +2 -2
  90. package/src/commit/cli.ts +1 -1
  91. package/src/commit/git/diff.ts +3 -3
  92. package/src/commit/git/index.ts +19 -24
  93. package/src/commit/index.ts +1 -1
  94. package/src/commit/map-reduce/index.ts +9 -9
  95. package/src/commit/map-reduce/map-phase.ts +19 -34
  96. package/src/commit/map-reduce/reduce-phase.ts +9 -11
  97. package/src/commit/message.ts +2 -2
  98. package/src/commit/model-selection.ts +3 -7
  99. package/src/commit/pipeline.ts +20 -22
  100. package/src/commit/utils/exclusions.ts +3 -3
  101. package/src/config/file-lock.ts +17 -7
  102. package/src/config/keybindings.ts +6 -8
  103. package/src/config/model-registry.ts +55 -37
  104. package/src/config/model-resolver.ts +18 -19
  105. package/src/config/prompt-templates.ts +11 -11
  106. package/src/config/settings-manager.ts +50 -34
  107. package/src/config.ts +60 -62
  108. package/src/cursor.ts +11 -9
  109. package/src/discovery/agents-md.ts +11 -12
  110. package/src/discovery/builtin.ts +68 -73
  111. package/src/discovery/claude.ts +41 -42
  112. package/src/discovery/cline.ts +11 -12
  113. package/src/discovery/codex.ts +52 -53
  114. package/src/discovery/cursor.ts +9 -10
  115. package/src/discovery/gemini.ts +17 -22
  116. package/src/discovery/github.ts +13 -14
  117. package/src/discovery/helpers.ts +35 -34
  118. package/src/discovery/index.ts +16 -18
  119. package/src/discovery/mcp-json.ts +8 -9
  120. package/src/discovery/ssh.ts +8 -9
  121. package/src/discovery/vscode.ts +4 -5
  122. package/src/discovery/windsurf.ts +6 -7
  123. package/src/exa/company.ts +1 -2
  124. package/src/exa/index.ts +2 -3
  125. package/src/exa/linkedin.ts +1 -2
  126. package/src/exa/mcp-client.ts +14 -16
  127. package/src/exa/render.ts +10 -11
  128. package/src/exa/researcher.ts +1 -2
  129. package/src/exa/search.ts +1 -2
  130. package/src/exa/types.ts +0 -1
  131. package/src/exa/websets.ts +1 -2
  132. package/src/exec/bash-executor.ts +3 -4
  133. package/src/exec/exec.ts +0 -1
  134. package/src/export/custom-share.ts +5 -6
  135. package/src/export/html/index.ts +24 -21
  136. package/src/export/ttsr.ts +2 -3
  137. package/src/extensibility/custom-commands/bundled/review/index.ts +7 -8
  138. package/src/extensibility/custom-commands/loader.ts +17 -14
  139. package/src/extensibility/custom-commands/types.ts +1 -2
  140. package/src/extensibility/custom-tools/loader.ts +10 -11
  141. package/src/extensibility/custom-tools/types.ts +6 -7
  142. package/src/extensibility/custom-tools/wrapper.ts +2 -3
  143. package/src/extensibility/extensions/loader.ts +75 -53
  144. package/src/extensibility/extensions/runner.ts +11 -12
  145. package/src/extensibility/extensions/types.ts +19 -26
  146. package/src/extensibility/extensions/wrapper.ts +3 -4
  147. package/src/extensibility/hooks/index.ts +1 -1
  148. package/src/extensibility/hooks/loader.ts +8 -9
  149. package/src/extensibility/hooks/runner.ts +7 -8
  150. package/src/extensibility/hooks/tool-wrapper.ts +0 -1
  151. package/src/extensibility/hooks/types.ts +10 -17
  152. package/src/extensibility/plugins/doctor.ts +3 -3
  153. package/src/extensibility/plugins/installer.ts +27 -27
  154. package/src/extensibility/plugins/loader.ts +59 -56
  155. package/src/extensibility/plugins/manager.ts +211 -171
  156. package/src/extensibility/plugins/parser.ts +1 -1
  157. package/src/extensibility/plugins/paths.ts +8 -8
  158. package/src/extensibility/skills.ts +63 -60
  159. package/src/extensibility/slash-commands.ts +10 -10
  160. package/src/index.ts +46 -46
  161. package/src/internal-urls/agent-protocol.ts +21 -11
  162. package/src/internal-urls/artifact-protocol.ts +17 -13
  163. package/src/internal-urls/router.ts +1 -2
  164. package/src/internal-urls/rule-protocol.ts +3 -4
  165. package/src/internal-urls/skill-protocol.ts +3 -4
  166. package/src/ipy/executor.ts +14 -10
  167. package/src/ipy/gateway-coordinator.ts +79 -90
  168. package/src/ipy/kernel.ts +32 -30
  169. package/src/ipy/modules.ts +13 -13
  170. package/src/lsp/client.ts +21 -10
  171. package/src/lsp/clients/biome-client.ts +1 -2
  172. package/src/lsp/clients/index.ts +3 -3
  173. package/src/lsp/clients/lsp-linter-client.ts +4 -5
  174. package/src/lsp/config.ts +15 -15
  175. package/src/lsp/edits.ts +4 -5
  176. package/src/lsp/index.ts +43 -44
  177. package/src/lsp/lspmux.ts +8 -8
  178. package/src/lsp/render.ts +10 -16
  179. package/src/lsp/utils.ts +3 -3
  180. package/src/main.ts +55 -34
  181. package/src/mcp/client.ts +2 -3
  182. package/src/mcp/config.ts +5 -6
  183. package/src/mcp/json-rpc.ts +0 -1
  184. package/src/mcp/loader.ts +3 -4
  185. package/src/mcp/manager.ts +17 -18
  186. package/src/mcp/tool-bridge.ts +4 -9
  187. package/src/mcp/tool-cache.ts +2 -3
  188. package/src/mcp/transports/http.ts +2 -4
  189. package/src/mcp/transports/stdio.ts +1 -2
  190. package/src/migrations.ts +60 -49
  191. package/src/modes/components/armin.ts +4 -5
  192. package/src/modes/components/assistant-message.ts +6 -6
  193. package/src/modes/components/bash-execution.ts +7 -8
  194. package/src/modes/components/bordered-loader.ts +3 -3
  195. package/src/modes/components/branch-summary-message.ts +3 -3
  196. package/src/modes/components/compaction-summary-message.ts +3 -3
  197. package/src/modes/components/countdown-timer.ts +0 -1
  198. package/src/modes/components/custom-message.ts +5 -5
  199. package/src/modes/components/diff.ts +1 -1
  200. package/src/modes/components/dynamic-border.ts +2 -2
  201. package/src/modes/components/extensions/extension-dashboard.ts +6 -7
  202. package/src/modes/components/extensions/extension-list.ts +2 -3
  203. package/src/modes/components/extensions/inspector-panel.ts +3 -4
  204. package/src/modes/components/extensions/state-manager.ts +25 -26
  205. package/src/modes/components/extensions/types.ts +1 -2
  206. package/src/modes/components/footer.ts +47 -43
  207. package/src/modes/components/history-search.ts +2 -2
  208. package/src/modes/components/hook-editor.ts +3 -4
  209. package/src/modes/components/hook-input.ts +2 -3
  210. package/src/modes/components/hook-message.ts +5 -5
  211. package/src/modes/components/hook-selector.ts +2 -3
  212. package/src/modes/components/keybinding-hints.ts +2 -3
  213. package/src/modes/components/login-dialog.ts +2 -2
  214. package/src/modes/components/model-selector.ts +12 -12
  215. package/src/modes/components/oauth-selector.ts +2 -2
  216. package/src/modes/components/plugin-settings.ts +20 -20
  217. package/src/modes/components/python-execution.ts +7 -8
  218. package/src/modes/components/queue-mode-selector.ts +3 -3
  219. package/src/modes/components/read-tool-group.ts +2 -2
  220. package/src/modes/components/session-selector.ts +4 -4
  221. package/src/modes/components/settings-defs.ts +77 -69
  222. package/src/modes/components/settings-selector.ts +16 -16
  223. package/src/modes/components/show-images-selector.ts +2 -2
  224. package/src/modes/components/status-line/segments.ts +4 -4
  225. package/src/modes/components/status-line/separators.ts +1 -1
  226. package/src/modes/components/status-line/types.ts +2 -2
  227. package/src/modes/components/status-line-segment-editor.ts +7 -8
  228. package/src/modes/components/status-line.ts +12 -12
  229. package/src/modes/components/theme-selector.ts +8 -7
  230. package/src/modes/components/thinking-selector.ts +4 -4
  231. package/src/modes/components/todo-display.ts +2 -2
  232. package/src/modes/components/todo-reminder.ts +4 -4
  233. package/src/modes/components/tool-execution.ts +11 -16
  234. package/src/modes/components/tree-selector.ts +11 -11
  235. package/src/modes/components/ttsr-notification.ts +5 -5
  236. package/src/modes/components/user-message-selector.ts +1 -1
  237. package/src/modes/components/user-message.ts +1 -1
  238. package/src/modes/components/visual-truncate.ts +0 -1
  239. package/src/modes/components/welcome.ts +4 -4
  240. package/src/modes/controllers/command-controller.ts +46 -47
  241. package/src/modes/controllers/event-controller.ts +16 -20
  242. package/src/modes/controllers/extension-ui-controller.ts +40 -46
  243. package/src/modes/controllers/input-controller.ts +17 -18
  244. package/src/modes/controllers/selector-controller.ts +103 -91
  245. package/src/modes/index.ts +3 -3
  246. package/src/modes/interactive-mode.ts +27 -29
  247. package/src/modes/print-mode.ts +12 -13
  248. package/src/modes/rpc/rpc-client.ts +7 -8
  249. package/src/modes/rpc/rpc-mode.ts +24 -25
  250. package/src/modes/rpc/rpc-types.ts +3 -4
  251. package/src/modes/theme/mermaid-cache.ts +2 -2
  252. package/src/modes/theme/theme.ts +128 -53
  253. package/src/modes/types.ts +10 -10
  254. package/src/modes/utils/ui-helpers.ts +17 -17
  255. package/src/patch/applicator.ts +18 -19
  256. package/src/patch/diff.ts +1 -2
  257. package/src/patch/fuzzy.ts +1 -2
  258. package/src/patch/index.ts +10 -11
  259. package/src/patch/normalize.ts +4 -4
  260. package/src/patch/normative.ts +1 -2
  261. package/src/patch/parser.ts +8 -9
  262. package/src/patch/shared.ts +12 -13
  263. package/src/sdk.ts +60 -63
  264. package/src/session/agent-session.ts +83 -84
  265. package/src/session/agent-storage.ts +11 -11
  266. package/src/session/artifacts.ts +8 -9
  267. package/src/session/auth-storage.ts +25 -29
  268. package/src/session/compaction/branch-summarization.ts +7 -10
  269. package/src/session/compaction/compaction.ts +8 -19
  270. package/src/session/compaction/utils.ts +6 -9
  271. package/src/session/history-storage.ts +10 -10
  272. package/src/session/messages.ts +4 -5
  273. package/src/session/session-manager.ts +76 -65
  274. package/src/session/session-storage.ts +57 -69
  275. package/src/session/storage-migration.ts +2 -3
  276. package/src/session/streaming-output.ts +2 -2
  277. package/src/ssh/connection-manager.ts +43 -50
  278. package/src/ssh/ssh-executor.ts +2 -2
  279. package/src/ssh/sshfs-mount.ts +11 -18
  280. package/src/system-prompt.ts +27 -34
  281. package/src/task/agents.ts +45 -30
  282. package/src/task/commands.ts +6 -7
  283. package/src/task/discovery.ts +39 -76
  284. package/src/task/executor.ts +14 -15
  285. package/src/task/index.ts +33 -36
  286. package/src/task/output-manager.ts +3 -4
  287. package/src/task/parallel.ts +0 -1
  288. package/src/task/render.ts +19 -20
  289. package/src/task/subprocess-tool-registry.ts +1 -2
  290. package/src/task/worker-protocol.ts +3 -3
  291. package/src/task/worker.ts +32 -38
  292. package/src/task/worktree.ts +19 -19
  293. package/src/tools/ask.ts +8 -9
  294. package/src/tools/bash-interceptor.ts +1 -5
  295. package/src/tools/bash.ts +19 -18
  296. package/src/tools/calculator.ts +12 -12
  297. package/src/tools/complete.ts +3 -4
  298. package/src/tools/context.ts +2 -2
  299. package/src/tools/fetch.ts +23 -26
  300. package/src/tools/find.ts +15 -16
  301. package/src/tools/gemini-image.ts +14 -14
  302. package/src/tools/grep.ts +27 -27
  303. package/src/tools/index.ts +78 -56
  304. package/src/tools/list-limit.ts +1 -1
  305. package/src/tools/ls.ts +7 -7
  306. package/src/tools/notebook.ts +5 -5
  307. package/src/tools/output-meta.ts +3 -4
  308. package/src/tools/output-utils.ts +1 -1
  309. package/src/tools/path-utils.ts +5 -5
  310. package/src/tools/python.ts +36 -37
  311. package/src/tools/read.ts +23 -23
  312. package/src/tools/render-utils.ts +8 -9
  313. package/src/tools/renderers.ts +6 -7
  314. package/src/tools/review.ts +8 -11
  315. package/src/tools/ssh.ts +31 -30
  316. package/src/tools/todo-write.ts +13 -13
  317. package/src/tools/tool-errors.ts +3 -3
  318. package/src/tools/tool-result.ts +3 -8
  319. package/src/tools/write.ts +11 -16
  320. package/src/tui/code-cell.ts +3 -9
  321. package/src/tui/file-list.ts +3 -4
  322. package/src/tui/output-block.ts +1 -2
  323. package/src/tui/status-line.ts +2 -3
  324. package/src/tui/tree-list.ts +2 -3
  325. package/src/tui/types.ts +1 -2
  326. package/src/tui/utils.ts +2 -3
  327. package/src/utils/changelog.ts +9 -10
  328. package/src/utils/clipboard.ts +11 -11
  329. package/src/utils/file-mentions.ts +4 -10
  330. package/src/utils/frontmatter.ts +6 -3
  331. package/src/utils/fuzzy.ts +2 -2
  332. package/src/utils/image-convert.ts +1 -1
  333. package/src/utils/image-resize.ts +1 -1
  334. package/src/utils/mime.ts +2 -2
  335. package/src/utils/shell-snapshot.ts +11 -13
  336. package/src/utils/shell.ts +4 -5
  337. package/src/utils/title-generator.ts +8 -9
  338. package/src/utils/tools-manager.ts +23 -23
  339. package/src/vendor/photon/index.js +1099 -1059
  340. package/src/vendor/photon/photon_rs_bg.wasm +0 -0
  341. package/src/web/scrapers/artifacthub.ts +1 -1
  342. package/src/web/scrapers/arxiv.ts +2 -2
  343. package/src/web/scrapers/bluesky.ts +2 -2
  344. package/src/web/scrapers/cheatsh.ts +1 -1
  345. package/src/web/scrapers/chocolatey.ts +2 -2
  346. package/src/web/scrapers/choosealicense.ts +5 -5
  347. package/src/web/scrapers/cisa-kev.ts +1 -1
  348. package/src/web/scrapers/crossref.ts +2 -2
  349. package/src/web/scrapers/devto.ts +3 -3
  350. package/src/web/scrapers/discogs.ts +3 -4
  351. package/src/web/scrapers/discourse.ts +1 -1
  352. package/src/web/scrapers/dockerhub.ts +1 -1
  353. package/src/web/scrapers/fdroid.ts +2 -2
  354. package/src/web/scrapers/firefox-addons.ts +3 -3
  355. package/src/web/scrapers/flathub.ts +1 -1
  356. package/src/web/scrapers/github.ts +3 -3
  357. package/src/web/scrapers/gitlab.ts +4 -4
  358. package/src/web/scrapers/hackernews.ts +2 -2
  359. package/src/web/scrapers/huggingface.ts +1 -1
  360. package/src/web/scrapers/iacr.ts +2 -2
  361. package/src/web/scrapers/index.ts +0 -1
  362. package/src/web/scrapers/jetbrains-marketplace.ts +1 -1
  363. package/src/web/scrapers/lemmy.ts +2 -2
  364. package/src/web/scrapers/maven.ts +2 -2
  365. package/src/web/scrapers/mdn.ts +2 -4
  366. package/src/web/scrapers/metacpan.ts +2 -2
  367. package/src/web/scrapers/musicbrainz.ts +1 -2
  368. package/src/web/scrapers/npm.ts +1 -1
  369. package/src/web/scrapers/nuget.ts +2 -2
  370. package/src/web/scrapers/nvd.ts +3 -3
  371. package/src/web/scrapers/ollama.ts +7 -9
  372. package/src/web/scrapers/opencorporates.ts +2 -2
  373. package/src/web/scrapers/openlibrary.ts +6 -6
  374. package/src/web/scrapers/orcid.ts +0 -1
  375. package/src/web/scrapers/osv.ts +2 -2
  376. package/src/web/scrapers/packagist.ts +1 -1
  377. package/src/web/scrapers/pubmed.ts +1 -2
  378. package/src/web/scrapers/rawg.ts +2 -2
  379. package/src/web/scrapers/readthedocs.ts +1 -2
  380. package/src/web/scrapers/repology.ts +2 -2
  381. package/src/web/scrapers/rfc.ts +1 -1
  382. package/src/web/scrapers/searchcode.ts +2 -2
  383. package/src/web/scrapers/semantic-scholar.ts +1 -1
  384. package/src/web/scrapers/snapcraft.ts +2 -2
  385. package/src/web/scrapers/sourcegraph.ts +1 -1
  386. package/src/web/scrapers/spdx.ts +3 -3
  387. package/src/web/scrapers/spotify.ts +0 -1
  388. package/src/web/scrapers/twitter.ts +1 -1
  389. package/src/web/scrapers/types.ts +1 -2
  390. package/src/web/scrapers/utils.ts +5 -5
  391. package/src/web/scrapers/wikidata.ts +3 -3
  392. package/src/web/scrapers/youtube.ts +9 -14
  393. package/src/web/search/auth.ts +4 -9
  394. package/src/web/search/index.ts +11 -21
  395. package/src/web/search/providers/anthropic.ts +3 -9
  396. package/src/web/search/providers/exa.ts +6 -10
  397. package/src/web/search/providers/perplexity.ts +5 -5
  398. package/src/web/search/render.ts +16 -18
  399. package/scripts/generate-wasm-b64.ts +0 -24
  400. package/src/commit/map-reduce/.map-phase.ts.kate-swp +0 -0
  401. package/src/task/.executor.ts.kate-swp +0 -0
  402. package/src/vendor/photon/photon_rs_bg.wasm.b64.js +0 -1
@@ -1,6 +1,6 @@
1
- import { readdir } from "node:fs/promises";
2
- import { homedir } from "node:os";
3
- import { join, resolve } from "node:path";
1
+ import * as fs from "node:fs/promises";
2
+ import * as os from "node:os";
3
+ import * as path from "node:path";
4
4
 
5
5
  export type PythonModuleSource = "user" | "project";
6
6
 
@@ -38,12 +38,12 @@ interface ModuleCandidate {
38
38
 
39
39
  async function listModuleCandidates(dir: string, source: PythonModuleSource): Promise<ModuleCandidate[]> {
40
40
  try {
41
- const entries = await readdir(dir, { withFileTypes: true });
41
+ const entries = await fs.readdir(dir, { withFileTypes: true });
42
42
  return entries
43
- .filter((entry) => entry.isFile() && entry.name.endsWith(".py"))
44
- .map((entry) => ({
43
+ .filter(entry => entry.isFile() && entry.name.endsWith(".py"))
44
+ .map(entry => ({
45
45
  name: entry.name,
46
- path: resolve(dir, entry.name),
46
+ path: path.resolve(dir, entry.name),
47
47
  source,
48
48
  }));
49
49
  } catch {
@@ -66,13 +66,13 @@ async function readModuleContent(candidate: ModuleCandidate): Promise<PythonModu
66
66
  */
67
67
  export async function discoverPythonModules(options: DiscoverPythonModulesOptions = {}): Promise<PythonModuleEntry[]> {
68
68
  const cwd = options.cwd ?? process.cwd();
69
- const homeDir = options.homeDir ?? homedir();
69
+ const homeDir = options.homeDir ?? os.homedir();
70
70
 
71
- const userDirs = [join(homeDir, ".omp", "agent", "modules"), join(homeDir, ".pi", "agent", "modules")];
72
- const projectDirs = [resolve(cwd, ".omp", "modules"), resolve(cwd, ".pi", "modules")];
71
+ const userDirs = [path.join(homeDir, ".omp", "agent", "modules"), path.join(homeDir, ".pi", "agent", "modules")];
72
+ const projectDirs = [path.resolve(cwd, ".omp", "modules"), path.resolve(cwd, ".pi", "modules")];
73
73
 
74
- const userCandidates = (await Promise.all(userDirs.map((dir) => listModuleCandidates(dir, "user")))).flat();
75
- const projectCandidates = (await Promise.all(projectDirs.map((dir) => listModuleCandidates(dir, "project")))).flat();
74
+ const userCandidates = (await Promise.all(userDirs.map(dir => listModuleCandidates(dir, "user")))).flat();
75
+ const projectCandidates = (await Promise.all(projectDirs.map(dir => listModuleCandidates(dir, "project")))).flat();
76
76
 
77
77
  const byName = new Map<string, ModuleCandidate>();
78
78
  for (const candidate of userCandidates) {
@@ -88,7 +88,7 @@ export async function discoverPythonModules(options: DiscoverPythonModulesOption
88
88
  }
89
89
 
90
90
  const sorted = Array.from(byName.values()).sort((a, b) => a.name.localeCompare(b.name));
91
- return Promise.all(sorted.map((candidate) => readModuleContent(candidate)));
91
+ return Promise.all(sorted.map(candidate => readModuleContent(candidate)));
92
92
  }
93
93
 
94
94
  /**
package/src/lsp/client.ts CHANGED
@@ -1,6 +1,5 @@
1
- import * as fs from "node:fs";
2
- import { ToolAbortError, throwIfAborted } from "@oh-my-pi/pi-coding-agent/tools/tool-errors";
3
- import { logger } from "@oh-my-pi/pi-utils";
1
+ import { isEnoent, logger } from "@oh-my-pi/pi-utils";
2
+ import { ToolAbortError, throwIfAborted } from "../tools/tool-errors";
4
3
  import { applyWorkspaceEdit } from "./edits";
5
4
  import { getLspmuxCommand, isLspmuxSupported } from "./lspmux";
6
5
  import type {
@@ -298,7 +297,7 @@ async function handleConfigurationRequest(client: LspClient, message: LspJsonRpc
298
297
  if (typeof message.id !== "number") return;
299
298
  const params = message.params as { items?: Array<{ section?: string }> };
300
299
  const items = params?.items ?? [];
301
- const result = items.map((item) => {
300
+ const result = items.map(item => {
302
301
  const section = item.section ?? "";
303
302
  return client.config.settings?.[section] ?? {};
304
303
  });
@@ -512,7 +511,13 @@ export async function ensureFileOpen(client: LspClient, filePath: string): Promi
512
511
  return;
513
512
  }
514
513
 
515
- const content = fs.readFileSync(filePath, "utf-8");
514
+ let content: string;
515
+ try {
516
+ content = await Bun.file(filePath).text();
517
+ } catch (err) {
518
+ if (isEnoent(err)) return;
519
+ throw err;
520
+ }
516
521
  const languageId = detectLanguageId(filePath);
517
522
 
518
523
  await sendNotification(client, "textDocument/didOpen", {
@@ -634,7 +639,13 @@ export async function refreshFile(client: LspClient, filePath: string): Promise<
634
639
  return;
635
640
  }
636
641
 
637
- const content = fs.readFileSync(filePath, "utf-8");
642
+ let content: string;
643
+ try {
644
+ content = await Bun.file(filePath).text();
645
+ } catch (err) {
646
+ if (isEnoent(err)) return;
647
+ throw err;
648
+ }
638
649
  const version = ++info.version;
639
650
 
640
651
  await sendNotification(client, "textDocument/didChange", {
@@ -748,12 +759,12 @@ export async function sendRequest(
748
759
 
749
760
  // Register pending request with timeout wrapper
750
761
  client.pendingRequests.set(id, {
751
- resolve: (result) => {
762
+ resolve: result => {
752
763
  if (timeout) clearTimeout(timeout);
753
764
  cleanup();
754
765
  resolve(result);
755
766
  },
756
- reject: (err) => {
767
+ reject: err => {
757
768
  if (timeout) clearTimeout(timeout);
758
769
  cleanup();
759
770
  reject(err);
@@ -762,7 +773,7 @@ export async function sendRequest(
762
773
  });
763
774
 
764
775
  // Write request
765
- writeMessage(client.process.stdin as import("bun").FileSink, request).catch((err) => {
776
+ writeMessage(client.process.stdin as import("bun").FileSink, request).catch(err => {
766
777
  if (timeout) clearTimeout(timeout);
767
778
  client.pendingRequests.delete(id);
768
779
  cleanup();
@@ -816,7 +827,7 @@ export interface LspServerStatus {
816
827
  * Get status of all active LSP clients.
817
828
  */
818
829
  export function getActiveClients(): LspServerStatus[] {
819
- return Array.from(clients.values()).map((client) => ({
830
+ return Array.from(clients.values()).map(client => ({
820
831
  name: client.config.command,
821
832
  status: "ready" as const,
822
833
  fileTypes: client.config.fileTypes,
@@ -2,9 +2,8 @@
2
2
  * Biome CLI-based linter client.
3
3
  * Uses Biome's CLI with JSON output instead of LSP (which has stale diagnostics issues).
4
4
  */
5
-
6
5
  import path from "node:path";
7
- import type { Diagnostic, DiagnosticSeverity, LinterClient, ServerConfig } from "@oh-my-pi/pi-coding-agent/lsp/types";
6
+ import type { Diagnostic, DiagnosticSeverity, LinterClient, ServerConfig } from "../../lsp/types";
8
7
 
9
8
  // =============================================================================
10
9
  // Biome JSON Output Types
@@ -1,3 +1,6 @@
1
+ import type { LinterClient, ServerConfig } from "../../lsp/types";
2
+ import { LspLinterClient } from "./lsp-linter-client";
3
+
1
4
  /**
2
5
  * Linter client implementations.
3
6
  *
@@ -8,9 +11,6 @@
8
11
  export { BiomeClient } from "./biome-client";
9
12
  export { LspLinterClient } from "./lsp-linter-client";
10
13
 
11
- import type { LinterClient, ServerConfig } from "@oh-my-pi/pi-coding-agent/lsp/types";
12
- import { LspLinterClient } from "./lsp-linter-client";
13
-
14
14
  // Cache of linter clients by server name + cwd
15
15
  const clientCache = new Map<string, LinterClient>();
16
16
 
@@ -2,11 +2,10 @@
2
2
  * LSP-based linter client.
3
3
  * Uses the Language Server Protocol for formatting and diagnostics.
4
4
  */
5
-
6
- import { getOrCreateClient, notifySaved, sendRequest, syncContent } from "@oh-my-pi/pi-coding-agent/lsp/client";
7
- import { applyTextEditsToString } from "@oh-my-pi/pi-coding-agent/lsp/edits";
8
- import type { Diagnostic, LinterClient, LspClient, ServerConfig, TextEdit } from "@oh-my-pi/pi-coding-agent/lsp/types";
9
- import { fileToUri } from "@oh-my-pi/pi-coding-agent/lsp/utils";
5
+ import { getOrCreateClient, notifySaved, sendRequest, syncContent } from "../../lsp/client";
6
+ import { applyTextEditsToString } from "../../lsp/edits";
7
+ import type { Diagnostic, LinterClient, LspClient, ServerConfig, TextEdit } from "../../lsp/types";
8
+ import { fileToUri } from "../../lsp/utils";
10
9
 
11
10
  /** Default formatting options for LSP */
12
11
  const DEFAULT_FORMAT_OPTIONS = {
package/src/lsp/config.ts CHANGED
@@ -1,9 +1,9 @@
1
- import { homedir } from "node:os";
2
- import { basename, extname, join } from "node:path";
3
- import { getConfigDirPaths } from "@oh-my-pi/pi-coding-agent/config";
1
+ import * as os from "node:os";
2
+ import * as path from "node:path";
4
3
  import { logger } from "@oh-my-pi/pi-utils";
5
4
  import { YAML } from "bun";
6
5
  import { globSync } from "glob";
6
+ import { getConfigDirPaths } from "../config";
7
7
  import { BiomeClient } from "./clients/biome-client";
8
8
  import DEFAULTS from "./defaults.json" with { type: "json" };
9
9
  import type { ServerConfig } from "./types";
@@ -30,7 +30,7 @@ function isRecord(value: unknown): value is Record<string, unknown> {
30
30
  }
31
31
 
32
32
  function parseConfigContent(content: string, filePath: string): unknown {
33
- const extension = extname(filePath).toLowerCase();
33
+ const extension = path.extname(filePath).toLowerCase();
34
34
  if (extension === ".yaml" || extension === ".yml") {
35
35
  return YAML.parse(content) as unknown;
36
36
  }
@@ -141,7 +141,7 @@ function applyRuntimeDefaults(servers: Record<string, ServerConfig>): Record<str
141
141
  }
142
142
 
143
143
  if (updated.omnisharp?.args) {
144
- const args = updated.omnisharp.args.map((arg) => (arg === PID_TOKEN ? String(process.pid) : arg));
144
+ const args = updated.omnisharp.args.map(arg => (arg === PID_TOKEN ? String(process.pid) : arg));
145
145
  updated.omnisharp = { ...updated.omnisharp, args };
146
146
  }
147
147
 
@@ -160,7 +160,7 @@ export async function hasRootMarkers(cwd: string, markers: string[]): Promise<bo
160
160
  // Handle glob-like patterns (e.g., "*.cabal")
161
161
  if (marker.includes("*")) {
162
162
  try {
163
- const matches = globSync(join(cwd, marker));
163
+ const matches = globSync(path.join(cwd, marker));
164
164
  if (matches.length > 0) {
165
165
  return true;
166
166
  }
@@ -169,7 +169,7 @@ export async function hasRootMarkers(cwd: string, markers: string[]): Promise<bo
169
169
  }
170
170
  continue;
171
171
  }
172
- const filePath = join(cwd, marker);
172
+ const filePath = path.join(cwd, marker);
173
173
  if (await Bun.file(filePath).exists()) {
174
174
  return true;
175
175
  }
@@ -211,7 +211,7 @@ export async function resolveCommand(command: string, cwd: string): Promise<stri
211
211
  // Check local bin directories based on project markers
212
212
  for (const { markers, binDir } of LOCAL_BIN_PATHS) {
213
213
  if (await hasRootMarkers(cwd, markers)) {
214
- const localPath = join(cwd, binDir, command);
214
+ const localPath = path.join(cwd, binDir, command);
215
215
  if (await Bun.file(localPath).exists()) {
216
216
  return localPath;
217
217
  }
@@ -232,14 +232,14 @@ function getConfigPaths(cwd: string): string[] {
232
232
 
233
233
  // Project root files (highest priority)
234
234
  for (const filename of filenames) {
235
- paths.push(join(cwd, filename));
235
+ paths.push(path.join(cwd, filename));
236
236
  }
237
237
 
238
238
  // Project config directories (.omp/, .pi/, .claude/)
239
239
  const projectDirs = getConfigDirPaths("", { user: false, project: true, cwd });
240
240
  for (const dir of projectDirs) {
241
241
  for (const filename of filenames) {
242
- paths.push(join(dir, filename));
242
+ paths.push(path.join(dir, filename));
243
243
  }
244
244
  }
245
245
 
@@ -247,13 +247,13 @@ function getConfigPaths(cwd: string): string[] {
247
247
  const userDirs = getConfigDirPaths("", { user: true, project: false });
248
248
  for (const dir of userDirs) {
249
249
  for (const filename of filenames) {
250
- paths.push(join(dir, filename));
250
+ paths.push(path.join(dir, filename));
251
251
  }
252
252
  }
253
253
 
254
254
  // User home root files (lowest priority fallback)
255
255
  for (const filename of filenames) {
256
- paths.push(join(homedir(), filename));
256
+ paths.push(path.join(os.homedir(), filename));
257
257
  }
258
258
 
259
259
  return paths;
@@ -352,12 +352,12 @@ export async function loadConfig(cwd: string): Promise<LspConfig> {
352
352
  * Returns servers sorted with primary (non-linter) servers first.
353
353
  */
354
354
  export function getServersForFile(config: LspConfig, filePath: string): Array<[string, ServerConfig]> {
355
- const ext = extname(filePath).toLowerCase();
356
- const fileName = basename(filePath).toLowerCase();
355
+ const ext = path.extname(filePath).toLowerCase();
356
+ const fileName = path.basename(filePath).toLowerCase();
357
357
  const matches: Array<[string, ServerConfig]> = [];
358
358
 
359
359
  for (const [name, serverConfig] of Object.entries(config.servers)) {
360
- const supportsFile = serverConfig.fileTypes.some((fileType) => {
360
+ const supportsFile = serverConfig.fileTypes.some(fileType => {
361
361
  const normalized = fileType.toLowerCase();
362
362
  return normalized === ext || normalized === fileName;
363
363
  });
package/src/lsp/edits.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { mkdir, rename, rm } from "node:fs/promises";
1
+ import * as fs from "node:fs/promises";
2
2
  import path from "node:path";
3
3
  import type { CreateFile, DeleteFile, RenameFile, TextDocumentEdit, TextEdit, WorkspaceEdit } from "./types";
4
4
  import { uriToFile } from "./utils";
@@ -86,20 +86,19 @@ export async function applyWorkspaceEdit(edit: WorkspaceEdit, cwd: string): Prom
86
86
  if (change.kind === "create") {
87
87
  const createOp = change as CreateFile;
88
88
  const filePath = uriToFile(createOp.uri);
89
- await mkdir(path.dirname(filePath), { recursive: true });
90
89
  await Bun.write(filePath, "");
91
90
  applied.push(`Created ${path.relative(cwd, filePath)}`);
92
91
  } else if (change.kind === "rename") {
93
92
  const renameOp = change as RenameFile;
94
93
  const oldPath = uriToFile(renameOp.oldUri);
95
94
  const newPath = uriToFile(renameOp.newUri);
96
- await mkdir(path.dirname(newPath), { recursive: true });
97
- await rename(oldPath, newPath);
95
+ await fs.mkdir(path.dirname(newPath), { recursive: true });
96
+ await fs.rename(oldPath, newPath);
98
97
  applied.push(`Renamed ${path.relative(cwd, oldPath)} → ${path.relative(cwd, newPath)}`);
99
98
  } else if (change.kind === "delete") {
100
99
  const deleteOp = change as DeleteFile;
101
100
  const filePath = uriToFile(deleteOp.uri);
102
- await rm(filePath, { recursive: true });
101
+ await fs.rm(filePath, { recursive: true });
103
102
  applied.push(`Deleted ${path.relative(cwd, filePath)}`);
104
103
  }
105
104
  }
package/src/lsp/index.ts CHANGED
@@ -1,15 +1,14 @@
1
- import type { Dirent } from "node:fs";
2
- import { existsSync, statSync } from "node:fs";
1
+ import * as fs from "node:fs";
3
2
  import path from "node:path";
4
3
  import type { AgentTool, AgentToolContext, AgentToolResult, AgentToolUpdateCallback } from "@oh-my-pi/pi-agent-core";
5
- import { renderPromptTemplate } from "@oh-my-pi/pi-coding-agent/config/prompt-templates";
6
- import { type Theme, theme } from "@oh-my-pi/pi-coding-agent/modes/theme/theme";
7
- import lspDescription from "@oh-my-pi/pi-coding-agent/prompts/tools/lsp.md" with { type: "text" };
8
- import type { ToolSession } from "@oh-my-pi/pi-coding-agent/tools";
9
- import { resolveToCwd } from "@oh-my-pi/pi-coding-agent/tools/path-utils";
10
- import { throwIfAborted } from "@oh-my-pi/pi-coding-agent/tools/tool-errors";
11
4
  import { logger, once, untilAborted } from "@oh-my-pi/pi-utils";
12
5
  import type { BunFile } from "bun";
6
+ import { renderPromptTemplate } from "../config/prompt-templates";
7
+ import { type Theme, theme } from "../modes/theme/theme";
8
+ import lspDescription from "../prompts/tools/lsp.md" with { type: "text" };
9
+ import type { ToolSession } from "../tools";
10
+ import { resolveToCwd } from "../tools/path-utils";
11
+ import { throwIfAborted } from "../tools/tool-errors";
13
12
  import {
14
13
  ensureFileOpen,
15
14
  getActiveClients,
@@ -254,21 +253,21 @@ function limitDiagnosticMessages(messages: string[]): string[] {
254
253
  }
255
254
 
256
255
  function findFileByExtensions(baseDir: string, extensions: string[], maxDepth: number): string | null {
257
- const normalized = extensions.map((ext) => ext.toLowerCase());
256
+ const normalized = extensions.map(ext => ext.toLowerCase());
258
257
  const search = (dir: string, depth: number): string | null => {
259
258
  if (depth > maxDepth) return null;
260
- const entries: Dirent[] = [];
259
+ const entries: fs.Dirent[] = [];
261
260
  try {
262
261
  const names = Array.from(new Bun.Glob("*").scanSync({ cwd: dir, onlyFiles: false }));
263
262
  for (const name of names) {
264
263
  const fullPath = path.join(dir, name);
265
264
  let isDir = false;
266
265
  try {
267
- isDir = statSync(fullPath).isDirectory();
266
+ isDir = fs.statSync(fullPath).isDirectory();
268
267
  } catch {
269
268
  continue;
270
269
  }
271
- entries.push({ name, isFile: () => !isDir, isDirectory: () => isDir } as Dirent);
270
+ entries.push({ name, isFile: () => !isDir, isDirectory: () => isDir } as fs.Dirent);
272
271
  }
273
272
  } catch {
274
273
  return null;
@@ -281,7 +280,7 @@ function findFileByExtensions(baseDir: string, extensions: string[], maxDepth: n
281
280
 
282
281
  if (entry.isFile()) {
283
282
  const lowerName = entry.name.toLowerCase();
284
- if (normalized.some((ext) => lowerName.endsWith(ext))) {
283
+ if (normalized.some(ext => lowerName.endsWith(ext))) {
285
284
  return fullPath;
286
285
  }
287
286
  } else if (entry.isDirectory()) {
@@ -362,22 +361,22 @@ interface ProjectType {
362
361
  /** Detect project type from root markers */
363
362
  function detectProjectType(cwd: string): ProjectType {
364
363
  // Check for Rust (Cargo.toml)
365
- if (existsSync(path.join(cwd, "Cargo.toml"))) {
364
+ if (fs.existsSync(path.join(cwd, "Cargo.toml"))) {
366
365
  return { type: "rust", command: ["cargo", "check", "--message-format=short"], description: "Rust (cargo check)" };
367
366
  }
368
367
 
369
368
  // Check for TypeScript (tsconfig.json)
370
- if (existsSync(path.join(cwd, "tsconfig.json"))) {
369
+ if (fs.existsSync(path.join(cwd, "tsconfig.json"))) {
371
370
  return { type: "typescript", command: ["npx", "tsc", "--noEmit"], description: "TypeScript (tsc --noEmit)" };
372
371
  }
373
372
 
374
373
  // Check for Go (go.mod)
375
- if (existsSync(path.join(cwd, "go.mod"))) {
374
+ if (fs.existsSync(path.join(cwd, "go.mod"))) {
376
375
  return { type: "go", command: ["go", "build", "./..."], description: "Go (go build)" };
377
376
  }
378
377
 
379
378
  // Check for Python (pyproject.toml or pyrightconfig.json)
380
- if (existsSync(path.join(cwd, "pyproject.toml")) || existsSync(path.join(cwd, "pyrightconfig.json"))) {
379
+ if (fs.existsSync(path.join(cwd, "pyproject.toml")) || fs.existsSync(path.join(cwd, "pyrightconfig.json"))) {
381
380
  return { type: "python", command: ["pyright"], description: "Python (pyright)" };
382
381
  }
383
382
 
@@ -412,10 +411,10 @@ async function runWorkspaceDiagnostics(
412
411
  return { output: "No issues found", projectType };
413
412
  }
414
413
 
415
- const summary = formatDiagnosticsSummary(collected.map((d) => d.diagnostic));
416
- const formatted = collected.slice(0, 50).map((d) => formatDiagnostic(d.diagnostic, d.filePath));
414
+ const summary = formatDiagnosticsSummary(collected.map(d => d.diagnostic));
415
+ const formatted = collected.slice(0, 50).map(d => formatDiagnostic(d.diagnostic, d.filePath));
417
416
  const more = collected.length > 50 ? `\n ... and ${collected.length - 50} more` : "";
418
- return { output: `${summary}:\n${formatted.map((f) => ` ${f}`).join("\n")}${more}`, projectType };
417
+ return { output: `${summary}:\n${formatted.map(f => ` ${f}`).join("\n")}${more}`, projectType };
419
418
  } catch (err) {
420
419
  logger.debug("LSP diagnostics failed, falling back to shell", { error: String(err) });
421
420
  // Fall through to shell command
@@ -571,10 +570,10 @@ async function getDiagnosticsForFile(
571
570
  }
572
571
  }
573
572
 
574
- const formatted = uniqueDiagnostics.map((d) => formatDiagnostic(d, relPath));
573
+ const formatted = uniqueDiagnostics.map(d => formatDiagnostic(d, relPath));
575
574
  const limited = limitDiagnosticMessages(formatted);
576
575
  const summary = formatDiagnosticsSummary(uniqueDiagnostics);
577
- const hasErrors = uniqueDiagnostics.some((d) => d.severity === 1);
576
+ const hasErrors = uniqueDiagnostics.some(d => d.severity === 1);
578
577
 
579
578
  return {
580
579
  server: serverNames.join(", "),
@@ -1096,8 +1095,8 @@ export class LspTool implements AgentTool<typeof lspSchema, LspToolDetails, Them
1096
1095
  }
1097
1096
 
1098
1097
  const summary = formatDiagnosticsSummary(uniqueDiagnostics);
1099
- const formatted = uniqueDiagnostics.map((d) => formatDiagnostic(d, relPath));
1100
- const output = `${summary}:\n${formatted.map((f) => ` ${f}`).join("\n")}`;
1098
+ const formatted = uniqueDiagnostics.map(d => formatDiagnostic(d, relPath));
1099
+ const output = `${summary}:\n${formatted.map(f => ` ${f}`).join("\n")}`;
1101
1100
  return {
1102
1101
  content: [{ type: "text", text: output }],
1103
1102
  details: { action, serverName: Array.from(allServerNames).join(", "), success: true },
@@ -1187,7 +1186,7 @@ export class LspTool implements AgentTool<typeof lspSchema, LspToolDetails, Them
1187
1186
  output = "No definition found";
1188
1187
  } else {
1189
1188
  const raw = Array.isArray(result) ? result : [result];
1190
- const locations = raw.flatMap((loc) => {
1189
+ const locations = raw.flatMap(loc => {
1191
1190
  if ("uri" in loc) {
1192
1191
  return [loc as Location];
1193
1192
  }
@@ -1203,7 +1202,7 @@ export class LspTool implements AgentTool<typeof lspSchema, LspToolDetails, Them
1203
1202
  output = "No definition found";
1204
1203
  } else {
1205
1204
  output = `Found ${locations.length} definition(s):\n${locations
1206
- .map((loc) => ` ${formatLocation(loc, this.session.cwd)}`)
1205
+ .map(loc => ` ${formatLocation(loc, this.session.cwd)}`)
1207
1206
  .join("\n")}`;
1208
1207
  }
1209
1208
  }
@@ -1220,7 +1219,7 @@ export class LspTool implements AgentTool<typeof lspSchema, LspToolDetails, Them
1220
1219
  if (!result || result.length === 0) {
1221
1220
  output = "No references found";
1222
1221
  } else {
1223
- const lines = result.map((loc) => ` ${formatLocation(loc, this.session.cwd)}`);
1222
+ const lines = result.map(loc => ` ${formatLocation(loc, this.session.cwd)}`);
1224
1223
  output = `Found ${result.length} reference(s):\n${lines.join("\n")}`;
1225
1224
  }
1226
1225
  break;
@@ -1257,11 +1256,11 @@ export class LspTool implements AgentTool<typeof lspSchema, LspToolDetails, Them
1257
1256
  // Check if hierarchical (DocumentSymbol) or flat (SymbolInformation)
1258
1257
  if ("selectionRange" in result[0]) {
1259
1258
  // Hierarchical
1260
- const lines = (result as DocumentSymbol[]).flatMap((s) => formatDocumentSymbol(s));
1259
+ const lines = (result as DocumentSymbol[]).flatMap(s => formatDocumentSymbol(s));
1261
1260
  output = `Symbols in ${relPath}:\n${lines.join("\n")}`;
1262
1261
  } else {
1263
1262
  // Flat
1264
- const lines = (result as SymbolInformation[]).map((s) => {
1263
+ const lines = (result as SymbolInformation[]).map(s => {
1265
1264
  const line = s.location.range.start.line + 1;
1266
1265
  const icon = symbolKindToIcon(s.kind);
1267
1266
  return `${icon} ${s.name} @ line ${line}`;
@@ -1285,8 +1284,8 @@ export class LspTool implements AgentTool<typeof lspSchema, LspToolDetails, Them
1285
1284
  if (!result || result.length === 0) {
1286
1285
  output = `No symbols matching "${query}"`;
1287
1286
  } else {
1288
- const lines = result.map((s) => formatSymbolInformation(s, this.session.cwd));
1289
- output = `Found ${result.length} symbol(s) matching "${query}":\n${lines.map((l) => ` ${l}`).join("\n")}`;
1287
+ const lines = result.map(s => formatSymbolInformation(s, this.session.cwd));
1288
+ output = `Found ${result.length} symbol(s) matching "${query}":\n${lines.map(l => ` ${l}`).join("\n")}`;
1290
1289
  }
1291
1290
  break;
1292
1291
  }
@@ -1311,10 +1310,10 @@ export class LspTool implements AgentTool<typeof lspSchema, LspToolDetails, Them
1311
1310
  const shouldApply = apply !== false;
1312
1311
  if (shouldApply) {
1313
1312
  const applied = await applyWorkspaceEdit(result, this.session.cwd);
1314
- output = `Applied rename:\n${applied.map((a) => ` ${a}`).join("\n")}`;
1313
+ output = `Applied rename:\n${applied.map(a => ` ${a}`).join("\n")}`;
1315
1314
  } else {
1316
1315
  const preview = formatWorkspaceEdit(result, this.session.cwd);
1317
- output = `Rename preview:\n${preview.map((p) => ` ${p}`).join("\n")}`;
1316
+ output = `Rename preview:\n${preview.map(p => ` ${p}`).join("\n")}`;
1318
1317
  }
1319
1318
  }
1320
1319
  break;
@@ -1335,7 +1334,7 @@ export class LspTool implements AgentTool<typeof lspSchema, LspToolDetails, Them
1335
1334
  const endCharacter = (end_character ?? column ?? 1) - 1;
1336
1335
  const range = { start: position, end: { line: endLine, character: endCharacter } };
1337
1336
  const relevantDiagnostics = diagnostics.filter(
1338
- (d) => d.range.start.line <= range.end.line && d.range.end.line >= range.start.line,
1337
+ d => d.range.start.line <= range.end.line && d.range.end.line >= range.start.line,
1339
1338
  );
1340
1339
 
1341
1340
  const codeActionContext: { diagnostics: Diagnostic[]; only?: string[] } = {
@@ -1401,7 +1400,7 @@ export class LspTool implements AgentTool<typeof lspSchema, LspToolDetails, Them
1401
1400
 
1402
1401
  if (isCodeAction(resolvedAction) && resolvedAction.edit) {
1403
1402
  const applied = await applyWorkspaceEdit(resolvedAction.edit, this.session.cwd);
1404
- output = `Applied "${codeAction.title}":\n${applied.map((a) => ` ${a}`).join("\n")}`;
1403
+ output = `Applied "${codeAction.title}":\n${applied.map(a => ` ${a}`).join("\n")}`;
1405
1404
  } else {
1406
1405
  const commandPayload = getCommandPayload(resolvedAction);
1407
1406
  if (commandPayload) {
@@ -1450,7 +1449,7 @@ export class LspTool implements AgentTool<typeof lspSchema, LspToolDetails, Them
1450
1449
  if (!calls || calls.length === 0) {
1451
1450
  output = `No callers found for "${item.name}"`;
1452
1451
  } else {
1453
- const lines = calls.map((call) => {
1452
+ const lines = calls.map(call => {
1454
1453
  const loc = { uri: call.from.uri, range: call.from.selectionRange };
1455
1454
  const detail = call.from.detail ? ` (${call.from.detail})` : "";
1456
1455
  return ` ${call.from.name}${detail} @ ${formatLocation(loc, this.session.cwd)}`;
@@ -1465,7 +1464,7 @@ export class LspTool implements AgentTool<typeof lspSchema, LspToolDetails, Them
1465
1464
  if (!calls || calls.length === 0) {
1466
1465
  output = `"${item.name}" doesn't call any functions`;
1467
1466
  } else {
1468
- const lines = calls.map((call) => {
1467
+ const lines = calls.map(call => {
1469
1468
  const loc = { uri: call.to.uri, range: call.to.selectionRange };
1470
1469
  const detail = call.to.detail ? ` (${call.to.detail})` : "";
1471
1470
  return ` ${call.to.name}${detail} @ ${formatLocation(loc, this.session.cwd)}`;
@@ -1500,10 +1499,10 @@ export class LspTool implements AgentTool<typeof lspSchema, LspToolDetails, Them
1500
1499
  if (collected.length === 0) {
1501
1500
  output = "Flycheck: no issues found";
1502
1501
  } else {
1503
- const summary = formatDiagnosticsSummary(collected.map((d) => d.diagnostic));
1504
- const formatted = collected.slice(0, 20).map((d) => formatDiagnostic(d.diagnostic, d.filePath));
1502
+ const summary = formatDiagnosticsSummary(collected.map(d => d.diagnostic));
1503
+ const formatted = collected.slice(0, 20).map(d => formatDiagnostic(d.diagnostic, d.filePath));
1505
1504
  const more = collected.length > 20 ? `\n ... and ${collected.length - 20} more` : "";
1506
- output = `Flycheck ${summary}:\n${formatted.map((f) => ` ${f}`).join("\n")}${more}`;
1505
+ output = `Flycheck ${summary}:\n${formatted.map(f => ` ${f}`).join("\n")}${more}`;
1507
1506
  }
1508
1507
  break;
1509
1508
  }
@@ -1561,13 +1560,13 @@ export class LspTool implements AgentTool<typeof lspSchema, LspToolDetails, Them
1561
1560
  const applied = await applyWorkspaceEdit(result, this.session.cwd);
1562
1561
  output =
1563
1562
  applied.length > 0
1564
- ? `Applied SSR:\n${applied.map((a) => ` ${a}`).join("\n")}`
1563
+ ? `Applied SSR:\n${applied.map(a => ` ${a}`).join("\n")}`
1565
1564
  : "SSR: no matches found";
1566
1565
  } else {
1567
1566
  const preview = formatWorkspaceEdit(result, this.session.cwd);
1568
1567
  output =
1569
1568
  preview.length > 0
1570
- ? `SSR preview:\n${preview.map((p) => ` ${p}`).join("\n")}`
1569
+ ? `SSR preview:\n${preview.map(p => ` ${p}`).join("\n")}`
1571
1570
  : "SSR: no matches found";
1572
1571
  }
1573
1572
  break;
@@ -1592,7 +1591,7 @@ export class LspTool implements AgentTool<typeof lspSchema, LspToolDetails, Them
1592
1591
  if (result.length === 0) {
1593
1592
  output = "No runnables found";
1594
1593
  } else {
1595
- const lines = result.map((r) => {
1594
+ const lines = result.map(r => {
1596
1595
  const args = r.args?.cargoArgs?.join(" ") || "";
1597
1596
  return ` [${r.kind}] ${r.label}${args ? ` (cargo ${args})` : ""}`;
1598
1597
  });
@@ -1620,7 +1619,7 @@ export class LspTool implements AgentTool<typeof lspSchema, LspToolDetails, Them
1620
1619
  if (result.length === 0) {
1621
1620
  output = "No related tests found";
1622
1621
  } else {
1623
- output = `Found ${result.length} related test(s):\n${result.map((t) => ` ${t}`).join("\n")}`;
1622
+ output = `Found ${result.length} related test(s):\n${result.map(t => ` ${t}`).join("\n")}`;
1624
1623
  }
1625
1624
  break;
1626
1625
  }
package/src/lsp/lspmux.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { homedir, platform } from "node:os";
2
- import { join } from "node:path";
1
+ import * as os from "node:os";
2
+ import * as path from "node:path";
3
3
  import { logger } from "@oh-my-pi/pi-utils";
4
4
  import { TOML } from "bun";
5
5
 
@@ -63,14 +63,14 @@ const STATE_CACHE_TTL_MS = 5 * 60 * 1000;
63
63
  * Matches Rust's `dirs::config_dir()` behavior.
64
64
  */
65
65
  function getConfigPath(): string {
66
- const home = homedir();
67
- switch (platform()) {
66
+ const home = os.homedir();
67
+ switch (os.platform()) {
68
68
  case "win32":
69
- return join(process.env.APPDATA ?? join(home, "AppData", "Roaming"), "lspmux", "config.toml");
69
+ return path.join(process.env.APPDATA ?? path.join(home, "AppData", "Roaming"), "lspmux", "config.toml");
70
70
  case "darwin":
71
- return join(home, "Library", "Application Support", "lspmux", "config.toml");
71
+ return path.join(home, "Library", "Application Support", "lspmux", "config.toml");
72
72
  default:
73
- return join(process.env.XDG_CONFIG_HOME ?? join(home, ".config"), "lspmux", "config.toml");
73
+ return path.join(process.env.XDG_CONFIG_HOME ?? path.join(home, ".config"), "lspmux", "config.toml");
74
74
  }
75
75
  }
76
76
 
@@ -108,7 +108,7 @@ async function checkServerRunning(binaryPath: string): Promise<boolean> {
108
108
 
109
109
  const exited = await Promise.race([
110
110
  proc.exited,
111
- new Promise<null>((resolve) => setTimeout(() => resolve(null), LIVENESS_TIMEOUT_MS)),
111
+ new Promise<null>(resolve => setTimeout(() => resolve(null), LIVENESS_TIMEOUT_MS)),
112
112
  ]);
113
113
 
114
114
  if (exited === null) {