@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,10 +1,10 @@
1
- import { lstatSync, symlinkSync, unlinkSync } from "node:fs";
2
- import { mkdir } from "node:fs/promises";
3
- import { join, resolve } from "node:path";
4
- import { getAgentDir } from "@oh-my-pi/pi-coding-agent/config";
1
+ import * as fs from "node:fs/promises";
2
+ import * as path from "node:path";
3
+ import { isEnoent } from "@oh-my-pi/pi-utils";
4
+ import { getAgentDir } from "../../config";
5
5
  import type { InstalledPlugin } from "./types";
6
6
 
7
- const PLUGINS_DIR = join(getAgentDir(), "plugins");
7
+ const PLUGINS_DIR = path.join(getAgentDir(), "plugins");
8
8
 
9
9
  // Valid npm package name pattern (scoped and unscoped)
10
10
  const VALID_PACKAGE_NAME = /^(@[a-z0-9-~][a-z0-9-._~]*\/)?[a-z0-9-~][a-z0-9-._~]*(@[a-z0-9-._^~>=<]+)?$/i;
@@ -26,8 +26,8 @@ function validatePackageName(name: string): void {
26
26
  * Ensure the plugins directory exists
27
27
  */
28
28
  async function ensurePluginsDir(): Promise<void> {
29
- await mkdir(PLUGINS_DIR, { recursive: true });
30
- await mkdir(join(PLUGINS_DIR, "node_modules"), { recursive: true });
29
+ await fs.mkdir(PLUGINS_DIR, { recursive: true });
30
+ await fs.mkdir(path.join(PLUGINS_DIR, "node_modules"), { recursive: true });
31
31
  }
32
32
 
33
33
  export async function installPlugin(packageName: string): Promise<InstalledPlugin> {
@@ -38,7 +38,7 @@ export async function installPlugin(packageName: string): Promise<InstalledPlugi
38
38
  await ensurePluginsDir();
39
39
 
40
40
  // Initialize package.json if it doesn't exist
41
- const pkgJsonPath = join(PLUGINS_DIR, "package.json");
41
+ const pkgJsonPath = path.join(PLUGINS_DIR, "package.json");
42
42
  const pkgJson = Bun.file(pkgJsonPath);
43
43
  if (!(await pkgJson.exists())) {
44
44
  await pkgJson.write(JSON.stringify({ name: "omp-plugins", private: true, dependencies: {} }, null, 2));
@@ -62,7 +62,7 @@ export async function installPlugin(packageName: string): Promise<InstalledPlugi
62
62
  const actualName = packageName.replace(/@[^/]+$/, "").replace(/^(@[^/]+\/[^@]+).*$/, "$1");
63
63
 
64
64
  // Read the installed package's package.json
65
- const pkgPath = join(PLUGINS_DIR, "node_modules", actualName, "package.json");
65
+ const pkgPath = path.join(PLUGINS_DIR, "node_modules", actualName, "package.json");
66
66
  const pkgFile = Bun.file(pkgPath);
67
67
  if (!(await pkgFile.exists())) {
68
68
  throw new Error(`Package installed but package.json not found at ${pkgPath}`);
@@ -73,7 +73,7 @@ export async function installPlugin(packageName: string): Promise<InstalledPlugi
73
73
  return {
74
74
  name: pkg.name,
75
75
  version: pkg.version,
76
- path: join(PLUGINS_DIR, "node_modules", actualName),
76
+ path: path.join(PLUGINS_DIR, "node_modules", actualName),
77
77
  manifest: pkg.omp || pkg.pi || { version: pkg.version },
78
78
  enabledFeatures: null,
79
79
  enabled: true,
@@ -100,7 +100,7 @@ export async function uninstallPlugin(name: string): Promise<void> {
100
100
  }
101
101
 
102
102
  export async function listPlugins(): Promise<InstalledPlugin[]> {
103
- const pkgJsonPath = Bun.file(join(PLUGINS_DIR, "package.json"));
103
+ const pkgJsonPath = Bun.file(path.join(PLUGINS_DIR, "package.json"));
104
104
  if (!(await pkgJsonPath.exists())) {
105
105
  return [];
106
106
  }
@@ -110,14 +110,14 @@ export async function listPlugins(): Promise<InstalledPlugin[]> {
110
110
 
111
111
  const plugins: InstalledPlugin[] = [];
112
112
  for (const [name, _version] of Object.entries(deps)) {
113
- const path = join(PLUGINS_DIR, "node_modules", name);
114
- const fpkg = Bun.file(join(path, "package.json"));
113
+ const pluginPath = path.join(PLUGINS_DIR, "node_modules", name);
114
+ const fpkg = Bun.file(path.join(pluginPath, "package.json"));
115
115
  if (await fpkg.exists()) {
116
116
  const pkg = await fpkg.json();
117
117
  plugins.push({
118
118
  name,
119
119
  version: pkg.version,
120
- path,
120
+ path: pluginPath,
121
121
  manifest: pkg.omp || pkg.pi || { version: pkg.version },
122
122
  enabledFeatures: null,
123
123
  enabled: true,
@@ -130,17 +130,17 @@ export async function listPlugins(): Promise<InstalledPlugin[]> {
130
130
 
131
131
  export async function linkPlugin(localPath: string): Promise<void> {
132
132
  const cwd = process.cwd();
133
- const absolutePath = resolve(cwd, localPath);
133
+ const absolutePath = path.resolve(cwd, localPath);
134
134
 
135
135
  // Validate that resolved path is within cwd to prevent path traversal
136
- const normalizedCwd = resolve(cwd);
137
- const normalizedPath = resolve(absolutePath);
136
+ const normalizedCwd = path.resolve(cwd);
137
+ const normalizedPath = path.resolve(absolutePath);
138
138
  if (!normalizedPath.startsWith(`${normalizedCwd}/`) && normalizedPath !== normalizedCwd) {
139
139
  throw new Error(`Invalid path: ${localPath} resolves outside working directory`);
140
140
  }
141
141
 
142
142
  // Validate package.json exists
143
- const pkgFile = Bun.file(join(absolutePath, "package.json"));
143
+ const pkgFile = Bun.file(path.join(absolutePath, "package.json"));
144
144
  if (!(await pkgFile.exists())) {
145
145
  throw new Error(`package.json not found at ${absolutePath}`);
146
146
  }
@@ -167,24 +167,24 @@ export async function linkPlugin(localPath: string): Promise<void> {
167
167
  await ensurePluginsDir();
168
168
 
169
169
  // Create symlink in plugins/node_modules
170
- const linkPath = join(PLUGINS_DIR, "node_modules", pkg.name);
170
+ const linkPath = path.join(PLUGINS_DIR, "node_modules", pkg.name);
171
171
 
172
172
  // For scoped packages, ensure the scope directory exists
173
173
  if (pkg.name.startsWith("@")) {
174
- const scopeDir = join(PLUGINS_DIR, "node_modules", pkg.name.split("/")[0]);
175
- await mkdir(scopeDir, { recursive: true });
174
+ const scopeDir = path.join(PLUGINS_DIR, "node_modules", pkg.name.split("/")[0]);
175
+ await fs.mkdir(scopeDir, { recursive: true });
176
176
  }
177
177
 
178
178
  // Remove existing if present
179
179
  try {
180
- const stat = lstatSync(linkPath);
181
- if (stat.isSymbolicLink() || stat.isDirectory()) {
182
- unlinkSync(linkPath);
180
+ const stats = await fs.lstat(linkPath);
181
+ if (stats.isSymbolicLink() || stats.isDirectory()) {
182
+ await fs.unlink(linkPath);
183
183
  }
184
- } catch {
185
- // Doesn't exist, that's fine
184
+ } catch (err) {
185
+ if (!isEnoent(err)) throw err;
186
186
  }
187
187
 
188
188
  // Create symlink using fs instead of shell command
189
- symlinkSync(absolutePath, linkPath);
189
+ await fs.symlink(absolutePath, linkPath);
190
190
  }
@@ -4,9 +4,9 @@
4
4
  * Reads enabled plugins from the runtime config and loads their tools/hooks
5
5
  * based on manifest entries and enabled features.
6
6
  */
7
-
8
- import { existsSync, readFileSync } from "node:fs";
9
- import { join } from "node:path";
7
+ import * as fs from "node:fs";
8
+ import * as path from "node:path";
9
+ import { isEnoent } from "@oh-my-pi/pi-utils";
10
10
  import {
11
11
  getAllProjectPluginOverridePaths,
12
12
  getPluginsLockfile,
@@ -22,29 +22,26 @@ import type { InstalledPlugin, PluginManifest, PluginRuntimeConfig, ProjectPlugi
22
22
  /**
23
23
  * Load plugin runtime config from lock file.
24
24
  */
25
- function loadRuntimeConfig(): PluginRuntimeConfig {
25
+ async function loadRuntimeConfig(): Promise<PluginRuntimeConfig> {
26
26
  const lockPath = getPluginsLockfile();
27
- if (!existsSync(lockPath)) {
28
- return { plugins: {}, settings: {} };
29
- }
30
27
  try {
31
- return JSON.parse(readFileSync(lockPath, "utf-8"));
32
- } catch {
33
- return { plugins: {}, settings: {} };
28
+ return await Bun.file(lockPath).json();
29
+ } catch (err) {
30
+ if (isEnoent(err)) return { plugins: {}, settings: {} };
31
+ throw err;
34
32
  }
35
33
  }
36
34
 
37
35
  /**
38
36
  * Load project-local plugin overrides (checks .omp and .pi directories).
39
37
  */
40
- function loadProjectOverrides(cwd: string): ProjectPluginOverrides {
38
+ async function loadProjectOverrides(cwd: string): Promise<ProjectPluginOverrides> {
41
39
  for (const overridesPath of getAllProjectPluginOverridePaths(cwd)) {
42
- if (existsSync(overridesPath)) {
43
- try {
44
- return JSON.parse(readFileSync(overridesPath, "utf-8"));
45
- } catch {
46
- // Continue to next path
47
- }
40
+ try {
41
+ return await Bun.file(overridesPath).json();
42
+ } catch (err) {
43
+ if (isEnoent(err)) continue;
44
+ // JSON parse error - continue to next path
48
45
  }
49
46
  }
50
47
  return {};
@@ -58,30 +55,36 @@ function loadProjectOverrides(cwd: string): ProjectPluginOverrides {
58
55
  * Get list of enabled plugins with their resolved configurations.
59
56
  * Respects both global runtime config and project overrides.
60
57
  */
61
- export function getEnabledPlugins(cwd: string): InstalledPlugin[] {
58
+ export async function getEnabledPlugins(cwd: string): Promise<InstalledPlugin[]> {
62
59
  const pkgJsonPath = getPluginsPackageJson();
63
- if (!existsSync(pkgJsonPath)) {
64
- return [];
60
+ let pkg: { dependencies?: Record<string, string> };
61
+ try {
62
+ pkg = await Bun.file(pkgJsonPath).json();
63
+ } catch (err) {
64
+ if (isEnoent(err)) return [];
65
+ throw err;
65
66
  }
66
67
 
67
68
  const nodeModulesPath = getPluginsNodeModules();
68
- if (!existsSync(nodeModulesPath)) {
69
+ if (!fs.existsSync(nodeModulesPath)) {
69
70
  return [];
70
71
  }
71
72
 
72
- const pkg = JSON.parse(readFileSync(pkgJsonPath, "utf-8"));
73
73
  const deps = pkg.dependencies || {};
74
- const runtimeConfig = loadRuntimeConfig();
75
- const projectOverrides = loadProjectOverrides(cwd);
74
+ const runtimeConfig = await loadRuntimeConfig();
75
+ const projectOverrides = await loadProjectOverrides(cwd);
76
76
  const plugins: InstalledPlugin[] = [];
77
77
 
78
78
  for (const [name] of Object.entries(deps)) {
79
- const pluginPkgPath = join(nodeModulesPath, name, "package.json");
80
- if (!existsSync(pluginPkgPath)) {
81
- continue;
79
+ const pluginPkgPath = path.join(nodeModulesPath, name, "package.json");
80
+ let pluginPkg: { version: string; omp?: PluginManifest; pi?: PluginManifest };
81
+ try {
82
+ pluginPkg = await Bun.file(pluginPkgPath).json();
83
+ } catch (err) {
84
+ if (isEnoent(err)) continue;
85
+ throw err;
82
86
  }
83
87
 
84
- const pluginPkg = JSON.parse(readFileSync(pluginPkgPath, "utf-8"));
85
88
  const manifest: PluginManifest | undefined = pluginPkg.omp || pluginPkg.pi;
86
89
 
87
90
  if (!manifest) {
@@ -109,7 +112,7 @@ export function getEnabledPlugins(cwd: string): InstalledPlugin[] {
109
112
  plugins.push({
110
113
  name,
111
114
  version: pluginPkg.version,
112
- path: join(nodeModulesPath, name),
115
+ path: path.join(nodeModulesPath, name),
113
116
  manifest,
114
117
  enabledFeatures,
115
118
  enabled: true,
@@ -133,8 +136,8 @@ export function resolvePluginToolPaths(plugin: InstalledPlugin): string[] {
133
136
 
134
137
  // Base tools entry (always included if exists)
135
138
  if (manifest.tools) {
136
- const toolPath = join(plugin.path, manifest.tools);
137
- if (existsSync(toolPath)) {
139
+ const toolPath = path.join(plugin.path, manifest.tools);
140
+ if (fs.existsSync(toolPath)) {
138
141
  paths.push(toolPath);
139
142
  }
140
143
  }
@@ -148,8 +151,8 @@ export function resolvePluginToolPaths(plugin: InstalledPlugin): string[] {
148
151
 
149
152
  if (feat.tools) {
150
153
  for (const toolEntry of feat.tools) {
151
- const toolPath = join(plugin.path, toolEntry);
152
- if (existsSync(toolPath)) {
154
+ const toolPath = path.join(plugin.path, toolEntry);
155
+ if (fs.existsSync(toolPath)) {
153
156
  paths.push(toolPath);
154
157
  }
155
158
  }
@@ -162,8 +165,8 @@ export function resolvePluginToolPaths(plugin: InstalledPlugin): string[] {
162
165
 
163
166
  if (feat.tools) {
164
167
  for (const toolEntry of feat.tools) {
165
- const toolPath = join(plugin.path, toolEntry);
166
- if (existsSync(toolPath)) {
168
+ const toolPath = path.join(plugin.path, toolEntry);
169
+ if (fs.existsSync(toolPath)) {
167
170
  paths.push(toolPath);
168
171
  }
169
172
  }
@@ -184,8 +187,8 @@ export function resolvePluginHookPaths(plugin: InstalledPlugin): string[] {
184
187
 
185
188
  // Base hooks entry (always included if exists)
186
189
  if (manifest.hooks) {
187
- const hookPath = join(plugin.path, manifest.hooks);
188
- if (existsSync(hookPath)) {
190
+ const hookPath = path.join(plugin.path, manifest.hooks);
191
+ if (fs.existsSync(hookPath)) {
189
192
  paths.push(hookPath);
190
193
  }
191
194
  }
@@ -199,8 +202,8 @@ export function resolvePluginHookPaths(plugin: InstalledPlugin): string[] {
199
202
 
200
203
  if (feat.hooks) {
201
204
  for (const hookEntry of feat.hooks) {
202
- const hookPath = join(plugin.path, hookEntry);
203
- if (existsSync(hookPath)) {
205
+ const hookPath = path.join(plugin.path, hookEntry);
206
+ if (fs.existsSync(hookPath)) {
204
207
  paths.push(hookPath);
205
208
  }
206
209
  }
@@ -213,8 +216,8 @@ export function resolvePluginHookPaths(plugin: InstalledPlugin): string[] {
213
216
 
214
217
  if (feat.hooks) {
215
218
  for (const hookEntry of feat.hooks) {
216
- const hookPath = join(plugin.path, hookEntry);
217
- if (existsSync(hookPath)) {
219
+ const hookPath = path.join(plugin.path, hookEntry);
220
+ if (fs.existsSync(hookPath)) {
218
221
  paths.push(hookPath);
219
222
  }
220
223
  }
@@ -236,8 +239,8 @@ export function resolvePluginCommandPaths(plugin: InstalledPlugin): string[] {
236
239
  // Base commands (always included if exists)
237
240
  if (manifest.commands) {
238
241
  for (const cmdEntry of manifest.commands) {
239
- const cmdPath = join(plugin.path, cmdEntry);
240
- if (existsSync(cmdPath)) {
242
+ const cmdPath = path.join(plugin.path, cmdEntry);
243
+ if (fs.existsSync(cmdPath)) {
241
244
  paths.push(cmdPath);
242
245
  }
243
246
  }
@@ -252,8 +255,8 @@ export function resolvePluginCommandPaths(plugin: InstalledPlugin): string[] {
252
255
 
253
256
  if (feat.commands) {
254
257
  for (const cmdEntry of feat.commands) {
255
- const cmdPath = join(plugin.path, cmdEntry);
256
- if (existsSync(cmdPath)) {
258
+ const cmdPath = path.join(plugin.path, cmdEntry);
259
+ if (fs.existsSync(cmdPath)) {
257
260
  paths.push(cmdPath);
258
261
  }
259
262
  }
@@ -266,8 +269,8 @@ export function resolvePluginCommandPaths(plugin: InstalledPlugin): string[] {
266
269
 
267
270
  if (feat.commands) {
268
271
  for (const cmdEntry of feat.commands) {
269
- const cmdPath = join(plugin.path, cmdEntry);
270
- if (existsSync(cmdPath)) {
272
+ const cmdPath = path.join(plugin.path, cmdEntry);
273
+ if (fs.existsSync(cmdPath)) {
271
274
  paths.push(cmdPath);
272
275
  }
273
276
  }
@@ -285,8 +288,8 @@ export function resolvePluginCommandPaths(plugin: InstalledPlugin): string[] {
285
288
  /**
286
289
  * Get all tool paths from all enabled plugins.
287
290
  */
288
- export function getAllPluginToolPaths(cwd: string): string[] {
289
- const plugins = getEnabledPlugins(cwd);
291
+ export async function getAllPluginToolPaths(cwd: string): Promise<string[]> {
292
+ const plugins = await getEnabledPlugins(cwd);
290
293
  const paths: string[] = [];
291
294
 
292
295
  for (const plugin of plugins) {
@@ -299,8 +302,8 @@ export function getAllPluginToolPaths(cwd: string): string[] {
299
302
  /**
300
303
  * Get all hook paths from all enabled plugins.
301
304
  */
302
- export function getAllPluginHookPaths(cwd: string): string[] {
303
- const plugins = getEnabledPlugins(cwd);
305
+ export async function getAllPluginHookPaths(cwd: string): Promise<string[]> {
306
+ const plugins = await getEnabledPlugins(cwd);
304
307
  const paths: string[] = [];
305
308
 
306
309
  for (const plugin of plugins) {
@@ -313,8 +316,8 @@ export function getAllPluginHookPaths(cwd: string): string[] {
313
316
  /**
314
317
  * Get all command paths from all enabled plugins.
315
318
  */
316
- export function getAllPluginCommandPaths(cwd: string): string[] {
317
- const plugins = getEnabledPlugins(cwd);
319
+ export async function getAllPluginCommandPaths(cwd: string): Promise<string[]> {
320
+ const plugins = await getEnabledPlugins(cwd);
318
321
  const paths: string[] = [];
319
322
 
320
323
  for (const plugin of plugins) {
@@ -328,9 +331,9 @@ export function getAllPluginCommandPaths(cwd: string): string[] {
328
331
  * Get plugin settings for use in tool/hook contexts.
329
332
  * Merges global settings with project overrides.
330
333
  */
331
- export function getPluginSettings(pluginName: string, cwd: string): Record<string, unknown> {
332
- const runtimeConfig = loadRuntimeConfig();
333
- const projectOverrides = loadProjectOverrides(cwd);
334
+ export async function getPluginSettings(pluginName: string, cwd: string): Promise<Record<string, unknown>> {
335
+ const runtimeConfig = await loadRuntimeConfig();
336
+ const projectOverrides = await loadProjectOverrides(cwd);
334
337
 
335
338
  const global = runtimeConfig.settings[pluginName] || {};
336
339
  const project = projectOverrides.settings?.[pluginName] || {};