@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
@@ -0,0 +1,17 @@
1
+ {{#if types_description}}
2
+ <type_definitions>
3
+ {{ types_description }}
4
+ </type_definitions>
5
+ {{/if}}
6
+
7
+ <observations>
8
+ {{ observations }}
9
+ </observations>
10
+
11
+ <diff_statistics>
12
+ {{ stat }}
13
+ </diff_statistics>
14
+
15
+ <scope_candidates>
16
+ {{ scope_candidates }}
17
+ </scope_candidates>
@@ -0,0 +1,4 @@
1
+ {{#if base_context}}
2
+ {{ base_context }}
3
+
4
+ {{/if}}Previous summary failed validation: {{ errors }}
@@ -0,0 +1,52 @@
1
+ You are a commit message specialist generating precise, informative descriptions.
2
+
3
+ <context>
4
+ Output: ONLY the description after "{{ commit_type }}{{ scope_prefix }}:".
5
+ Constraint: {{ chars }} characters max, no trailing period, no type prefix in output.
6
+ </context>
7
+
8
+ <instructions>
9
+ 1. Start with lowercase past-tense verb (must differ from "{{ commit_type }}")
10
+ 2. Name the specific subsystem/component affected
11
+ 3. Include WHY when it clarifies intent
12
+ 4. One focused concept per message
13
+
14
+ Get this right.
15
+ </instructions>
16
+
17
+ <verb_reference>
18
+ | Type | Use instead |
19
+ |----------|-------------------------------------------------|
20
+ | feat | added, introduced, implemented, enabled |
21
+ | fix | corrected, resolved, patched, addressed |
22
+ | refactor | restructured, reorganized, migrated, simplified |
23
+ | perf | optimized, reduced, eliminated, accelerated |
24
+ | docs | documented, clarified, expanded |
25
+ | build | upgraded, pinned, configured |
26
+ | chore | cleaned, removed, renamed, organized |
27
+ </verb_reference>
28
+
29
+ <examples>
30
+ feat | TLS encryption added to HTTP client for MITM prevention
31
+ -> added TLS support to prevent man-in-the-middle attacks
32
+
33
+ refactor | Consolidated HTTP transport into unified builder pattern
34
+ -> migrated HTTP transport to unified builder API
35
+
36
+ fix | Race condition in connection pool causing exhaustion under load
37
+ -> corrected race condition causing connection pool exhaustion
38
+
39
+ perf | Batch processing optimized to reduce memory allocations
40
+ -> eliminated allocation overhead in batch processing
41
+
42
+ build | Updated serde to fix CVE-2024-1234
43
+ -> upgraded serde to 1.0.200 for CVE-2024-1234
44
+ </examples>
45
+
46
+ <banned_words>
47
+ comprehensive, various, several, improved, enhanced, quickly, simply, basically, this change, this commit, now
48
+ </banned_words>
49
+
50
+ <output_format>
51
+ Output the description text only. Include motivation, name specifics, stay focused.
52
+ </output_format>
@@ -0,0 +1,13 @@
1
+ {{#if user_context}}
2
+ <user_context>
3
+ {{ user_context }}
4
+ </user_context>
5
+ {{/if}}
6
+
7
+ <detail_points>
8
+ {{ details }}
9
+ </detail_points>
10
+
11
+ <diff_stat>
12
+ {{ stat }}
13
+ </diff_stat>
@@ -0,0 +1,2 @@
1
+ Types: feat, fix, refactor, perf, docs, test, build, ci, chore, style, revert.
2
+ Format: <type>(<scope>): <summary> with past-tense summary.
@@ -0,0 +1,109 @@
1
+ /**
2
+ * Types for the omp commit pipeline.
3
+ */
4
+
5
+ export type CommitType =
6
+ | "feat"
7
+ | "fix"
8
+ | "refactor"
9
+ | "perf"
10
+ | "docs"
11
+ | "test"
12
+ | "build"
13
+ | "ci"
14
+ | "chore"
15
+ | "style"
16
+ | "revert";
17
+
18
+ export type ChangelogCategory =
19
+ | "Breaking Changes"
20
+ | "Added"
21
+ | "Changed"
22
+ | "Deprecated"
23
+ | "Removed"
24
+ | "Fixed"
25
+ | "Security";
26
+
27
+ export interface CommitCommandArgs {
28
+ /** Push after commit */
29
+ push: boolean;
30
+ /** Preview without committing */
31
+ dryRun: boolean;
32
+ /** Skip changelog updates */
33
+ noChangelog: boolean;
34
+ /** Use legacy deterministic pipeline */
35
+ legacy?: boolean;
36
+ /** Additional user context for the model */
37
+ context?: string;
38
+ /** Override the model selection */
39
+ model?: string;
40
+ }
41
+
42
+ export interface NumstatEntry {
43
+ path: string;
44
+ additions: number;
45
+ deletions: number;
46
+ }
47
+
48
+ export interface ConventionalDetail {
49
+ text: string;
50
+ changelogCategory?: ChangelogCategory;
51
+ userVisible: boolean;
52
+ }
53
+
54
+ export interface ConventionalAnalysis {
55
+ type: CommitType;
56
+ scope: string | null;
57
+ details: ConventionalDetail[];
58
+ issueRefs: string[];
59
+ }
60
+
61
+ export interface CommitSummary {
62
+ summary: string;
63
+ }
64
+
65
+ export interface FileObservation {
66
+ file: string;
67
+ observations: string[];
68
+ additions: number;
69
+ deletions: number;
70
+ }
71
+
72
+ export interface FileDiff {
73
+ filename: string;
74
+ content: string;
75
+ additions: number;
76
+ deletions: number;
77
+ isBinary: boolean;
78
+ }
79
+
80
+ export interface DiffHunk {
81
+ index: number;
82
+ header: string;
83
+ oldStart: number;
84
+ oldLines: number;
85
+ newStart: number;
86
+ newLines: number;
87
+ content: string;
88
+ }
89
+
90
+ export interface FileHunks {
91
+ filename: string;
92
+ isBinary: boolean;
93
+ hunks: DiffHunk[];
94
+ }
95
+
96
+ export interface ChangelogBoundary {
97
+ changelogPath: string;
98
+ files: string[];
99
+ }
100
+
101
+ export interface UnreleasedSection {
102
+ startLine: number;
103
+ endLine: number;
104
+ entries: Record<string, string[]>;
105
+ }
106
+
107
+ export interface ChangelogGenerationResult {
108
+ entries: Record<string, string[]>;
109
+ }
@@ -0,0 +1,42 @@
1
+ const EXCLUDED_FILES = [
2
+ "Cargo.lock",
3
+ "package-lock.json",
4
+ "npm-shrinkwrap.json",
5
+ "yarn.lock",
6
+ "pnpm-lock.yaml",
7
+ "shrinkwrap.yaml",
8
+ "bun.lock",
9
+ "bun.lockb",
10
+ "deno.lock",
11
+ "composer.lock",
12
+ "Gemfile.lock",
13
+ "poetry.lock",
14
+ "Pipfile.lock",
15
+ "pdm.lock",
16
+ "uv.lock",
17
+ "go.sum",
18
+ "flake.lock",
19
+ "pubspec.lock",
20
+ "Podfile.lock",
21
+ "Packages.resolved",
22
+ "mix.lock",
23
+ "packages.lock.json",
24
+ "config.yml.lock",
25
+ "config.yaml.lock",
26
+ "settings.yml.lock",
27
+ "settings.yaml.lock",
28
+ ];
29
+
30
+ const EXCLUDED_SUFFIXES = [".lock.yml", ".lock.yaml", "-lock.yml", "-lock.yaml"];
31
+
32
+ export function isExcludedFile(path: string): boolean {
33
+ const lower = path.toLowerCase();
34
+ if (EXCLUDED_FILES.some(name => lower.endsWith(name.toLowerCase()))) {
35
+ return true;
36
+ }
37
+ return EXCLUDED_SUFFIXES.some(suffix => lower.endsWith(suffix));
38
+ }
39
+
40
+ export function filterExcludedFiles<T extends { filename: string }>(files: T[]): T[] {
41
+ return files.filter(file => !isExcludedFile(file.filename));
42
+ }
@@ -0,0 +1,121 @@
1
+ import * as fs from "node:fs/promises";
2
+ import { isEnoent } from "@oh-my-pi/pi-utils";
3
+
4
+ export interface FileLockOptions {
5
+ staleMs?: number;
6
+ retries?: number;
7
+ retryDelayMs?: number;
8
+ }
9
+
10
+ const DEFAULT_OPTIONS: Required<FileLockOptions> = {
11
+ staleMs: 10_000,
12
+ retries: 50,
13
+ retryDelayMs: 100,
14
+ };
15
+
16
+ interface LockInfo {
17
+ pid: number;
18
+ timestamp: number;
19
+ }
20
+
21
+ function getLockPath(filePath: string): string {
22
+ return `${filePath}.lock`;
23
+ }
24
+
25
+ async function writeLockInfo(lockPath: string): Promise<void> {
26
+ const info: LockInfo = { pid: process.pid, timestamp: Date.now() };
27
+ await Bun.write(`${lockPath}/info`, JSON.stringify(info));
28
+ }
29
+
30
+ async function readLockInfo(lockPath: string): Promise<LockInfo | null> {
31
+ try {
32
+ const content = await fs.readFile(`${lockPath}/info`, "utf-8");
33
+ return JSON.parse(content) as LockInfo;
34
+ } catch {
35
+ return null;
36
+ }
37
+ }
38
+
39
+ function isProcessAlive(pid: number): boolean {
40
+ try {
41
+ process.kill(pid, 0);
42
+ return true;
43
+ } catch {
44
+ return false;
45
+ }
46
+ }
47
+
48
+ async function isLockStale(lockPath: string, staleMs: number): Promise<boolean> {
49
+ const info = await readLockInfo(lockPath);
50
+ if (!info) return true;
51
+
52
+ if (!isProcessAlive(info.pid)) return true;
53
+
54
+ if (Date.now() - info.timestamp > staleMs) return true;
55
+
56
+ return false;
57
+ }
58
+
59
+ async function tryAcquireLock(lockPath: string): Promise<boolean> {
60
+ try {
61
+ await fs.mkdir(lockPath);
62
+ await writeLockInfo(lockPath);
63
+ return true;
64
+ } catch (error) {
65
+ if ((error as NodeJS.ErrnoException).code === "EEXIST") {
66
+ return false;
67
+ }
68
+ throw error;
69
+ }
70
+ }
71
+
72
+ async function releaseLock(lockPath: string): Promise<void> {
73
+ try {
74
+ await fs.rm(lockPath, { recursive: true });
75
+ } catch {
76
+ // Ignore errors on release
77
+ }
78
+ }
79
+
80
+ async function lockExists(lockPath: string): Promise<boolean> {
81
+ try {
82
+ await fs.stat(lockPath);
83
+ return true;
84
+ } catch (err) {
85
+ if (isEnoent(err)) return false;
86
+ throw err;
87
+ }
88
+ }
89
+
90
+ async function acquireLock(filePath: string, options: FileLockOptions = {}): Promise<() => Promise<void>> {
91
+ const opts = { ...DEFAULT_OPTIONS, ...options };
92
+ const lockPath = getLockPath(filePath);
93
+
94
+ for (let attempt = 0; attempt < opts.retries; attempt++) {
95
+ if (await tryAcquireLock(lockPath)) {
96
+ return () => releaseLock(lockPath);
97
+ }
98
+
99
+ if ((await lockExists(lockPath)) && (await isLockStale(lockPath, opts.staleMs))) {
100
+ await releaseLock(lockPath);
101
+ continue;
102
+ }
103
+
104
+ await new Promise(resolve => setTimeout(resolve, opts.retryDelayMs));
105
+ }
106
+
107
+ throw new Error(`Failed to acquire lock for ${filePath} after ${opts.retries} attempts`);
108
+ }
109
+
110
+ export async function withFileLock<T>(
111
+ filePath: string,
112
+ fn: () => Promise<T>,
113
+ options: FileLockOptions = {},
114
+ ): Promise<T> {
115
+ const release = await acquireLock(filePath, options);
116
+ try {
117
+ return await fn();
118
+ } finally {
119
+ await release();
120
+ }
121
+ }
@@ -1,6 +1,4 @@
1
- import { existsSync, readFileSync } from "node:fs";
2
- import { join } from "node:path";
3
- import { getAgentDir } from "@oh-my-pi/pi-coding-agent/config";
1
+ import * as path from "node:path";
4
2
  import {
5
3
  DEFAULT_EDITOR_KEYBINDINGS,
6
4
  type EditorAction,
@@ -11,6 +9,7 @@ import {
11
9
  setEditorKeybindings,
12
10
  } from "@oh-my-pi/pi-tui";
13
11
  import { logger } from "@oh-my-pi/pi-utils";
12
+ import { getAgentDir } from "../config";
14
13
 
15
14
  /**
16
15
  * Application-level actions (coding agent specific).
@@ -162,7 +161,7 @@ export class KeybindingsManager {
162
161
  * Create from config file and set up editor keybindings.
163
162
  */
164
163
  static async create(agentDir: string = getAgentDir()): Promise<KeybindingsManager> {
165
- const configPath = join(agentDir, "keybindings.json");
164
+ const configPath = path.join(agentDir, "keybindings.json");
166
165
  const config = await KeybindingsManager.loadFromFile(configPath);
167
166
  const manager = new KeybindingsManager(config);
168
167
 
@@ -186,9 +185,8 @@ export class KeybindingsManager {
186
185
  }
187
186
 
188
187
  private static async loadFromFile(path: string): Promise<KeybindingsConfig> {
189
- if (!existsSync(path)) return {};
190
188
  try {
191
- return JSON.parse(readFileSync(path, "utf-8"));
189
+ return await Bun.file(path).json();
192
190
  } catch (error) {
193
191
  logger.warn("Failed to parse keybindings config", { path, error: String(error) });
194
192
  return {};
@@ -203,7 +201,7 @@ export class KeybindingsManager {
203
201
  const keyArray = Array.isArray(keys) ? keys : [keys];
204
202
  this.appActionToKeys.set(
205
203
  action as AppAction,
206
- keyArray.map((key) => normalizeKeyId(key as KeyId)),
204
+ keyArray.map(key => normalizeKeyId(key as KeyId)),
207
205
  );
208
206
  }
209
207
 
@@ -213,7 +211,7 @@ export class KeybindingsManager {
213
211
  const keyArray = Array.isArray(keys) ? keys : [keys];
214
212
  this.appActionToKeys.set(
215
213
  action,
216
- keyArray.map((key) => normalizeKeyId(key as KeyId)),
214
+ keyArray.map(key => normalizeKeyId(key as KeyId)),
217
215
  );
218
216
  }
219
217
  }
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * Model registry - manages built-in and custom models, provides API key resolution.
3
3
  */
4
-
5
- import { existsSync, readFileSync } from "node:fs";
4
+ import * as fs from "node:fs";
5
+ import * as path from "node:path";
6
6
  import {
7
7
  type Api,
8
8
  getGitHubCopilotBaseUrl,
@@ -11,10 +11,11 @@ import {
11
11
  type Model,
12
12
  normalizeDomain,
13
13
  } from "@oh-my-pi/pi-ai";
14
- import type { AuthStorage } from "@oh-my-pi/pi-coding-agent/session/auth-storage";
15
- import { logger } from "@oh-my-pi/pi-utils";
14
+ import { isEnoent, logger } from "@oh-my-pi/pi-utils";
16
15
  import { type Static, Type } from "@sinclair/typebox";
17
16
  import AjvModule from "ajv";
17
+ import { YAML } from "bun";
18
+ import type { AuthStorage } from "../session/auth-storage";
18
19
 
19
20
  const Ajv = (AjvModule as any).default || AjvModule;
20
21
 
@@ -102,10 +103,12 @@ interface CustomModelsResult {
102
103
  /** Providers with only baseUrl/headers override (no custom models) */
103
104
  overrides: Map<string, ProviderOverride>;
104
105
  error: string | undefined;
106
+ /** Whether the file was found (true) or didn't exist (false) */
107
+ found: boolean;
105
108
  }
106
109
 
107
110
  function emptyCustomModelsResult(error?: string): CustomModelsResult {
108
- return { models: [], replacedProviders: new Set(), overrides: new Map(), error };
111
+ return { models: [], replacedProviders: new Set(), overrides: new Map(), error, found: false };
109
112
  }
110
113
 
111
114
  /**
@@ -137,7 +140,7 @@ export class ModelRegistry {
137
140
  private fallbackPaths: string[] = [],
138
141
  ) {
139
142
  // Set up fallback resolver for custom provider API keys
140
- this.authStorage.setFallbackResolver((provider) => {
143
+ this.authStorage.setFallbackResolver(provider => {
141
144
  const keyConfig = this.customProviderApiKeys.get(provider);
142
145
  if (keyConfig) {
143
146
  return resolveApiKeyConfig(keyConfig);
@@ -159,7 +162,7 @@ export class ModelRegistry {
159
162
  instance.customProviderApiKeys = new Map(Object.entries(data.customProviderApiKeys ?? {}));
160
163
  instance.loadError = data.loadError;
161
164
 
162
- authStorage.setFallbackResolver((provider) => {
165
+ authStorage.setFallbackResolver(provider => {
163
166
  const keyConfig = instance.customProviderApiKeys.get(provider);
164
167
  if (keyConfig) {
165
168
  return resolveApiKeyConfig(keyConfig);
@@ -201,7 +204,7 @@ export class ModelRegistry {
201
204
  return this.loadError;
202
205
  }
203
206
 
204
- private loadModels(): void {
207
+ private loadModels() {
205
208
  // Load custom models from models.json first (to know which providers to skip/override)
206
209
  let customModels: Model<Api>[] = [];
207
210
  let replacedProviders: Set<string> = new Set();
@@ -213,19 +216,20 @@ export class ModelRegistry {
213
216
  }
214
217
 
215
218
  for (const modelsPath of pathsToCheck) {
216
- if (existsSync(modelsPath)) {
217
- logger.debug("ModelRegistry.loadModels loading", { path: modelsPath });
218
- const result = this.loadCustomModels(modelsPath);
219
- if (result.error) {
220
- this.loadError = result.error;
221
- // Keep built-in models even if custom models failed to load
222
- } else {
223
- customModels = result.models;
224
- replacedProviders = result.replacedProviders;
225
- overrides = result.overrides;
226
- }
227
- break; // Use first existing file
219
+ const result = this.loadCustomModels(modelsPath);
220
+ if (!result.found) {
221
+ continue; // File doesn't exist, try next path
228
222
  }
223
+ logger.debug("ModelRegistry.loadModels loading", { path: modelsPath });
224
+ if (result.error) {
225
+ this.loadError = result.error;
226
+ // Keep built-in models even if custom models failed to load
227
+ } else {
228
+ customModels = result.models;
229
+ replacedProviders = result.replacedProviders;
230
+ overrides = result.overrides;
231
+ }
232
+ break; // Use first existing file
229
233
  }
230
234
 
231
235
  const builtInModels = this.loadBuiltInModels(replacedProviders, overrides);
@@ -238,7 +242,7 @@ export class ModelRegistry {
238
242
  ? (normalizeDomain(copilotCred.enterpriseUrl) ?? undefined)
239
243
  : undefined;
240
244
  const baseUrl = getGitHubCopilotBaseUrl(copilotCred.access, domain);
241
- this.models = combined.map((m) => (m.provider === "github-copilot" ? { ...m, baseUrl } : m));
245
+ this.models = combined.map(m => (m.provider === "github-copilot" ? { ...m, baseUrl } : m));
242
246
  } else {
243
247
  this.models = combined;
244
248
  }
@@ -247,14 +251,14 @@ export class ModelRegistry {
247
251
  /** Load built-in models, skipping replaced providers and applying overrides */
248
252
  private loadBuiltInModels(replacedProviders: Set<string>, overrides: Map<string, ProviderOverride>): Model<Api>[] {
249
253
  return getProviders()
250
- .filter((provider) => !replacedProviders.has(provider))
251
- .flatMap((provider) => {
254
+ .filter(provider => !replacedProviders.has(provider))
255
+ .flatMap(provider => {
252
256
  const models = getModels(provider as any) as Model<Api>[];
253
257
  const override = overrides.get(provider);
254
258
  if (!override) return models;
255
259
 
256
260
  // Apply baseUrl/headers override to all models of this provider
257
- return models.map((m) => ({
261
+ return models.map(m => ({
258
262
  ...m,
259
263
  baseUrl: override.baseUrl ?? m.baseUrl,
260
264
  headers: override.headers ? { ...m.headers, ...override.headers } : m.headers,
@@ -262,14 +266,31 @@ export class ModelRegistry {
262
266
  });
263
267
  }
264
268
 
265
- private loadCustomModels(modelsJsonPath: string): CustomModelsResult {
266
- if (!existsSync(modelsJsonPath)) {
267
- return emptyCustomModelsResult();
269
+ private loadCustomModels(modelsPath: string): CustomModelsResult {
270
+ let content: string;
271
+ try {
272
+ content = fs.readFileSync(modelsPath, "utf-8");
273
+ } catch (error) {
274
+ if (isEnoent(error)) {
275
+ return emptyCustomModelsResult();
276
+ }
277
+ return {
278
+ ...emptyCustomModelsResult(
279
+ `Failed to load models config: ${error instanceof Error ? error.message : error}\n\nFile: ${modelsPath}`,
280
+ ),
281
+ found: true,
282
+ };
268
283
  }
269
284
 
270
285
  try {
271
- const content = readFileSync(modelsJsonPath, "utf-8");
272
- const config: ModelsConfig = JSON.parse(content);
286
+ const ext = path.extname(modelsPath).toLowerCase();
287
+ let config: ModelsConfig;
288
+
289
+ if (ext === ".yaml" || ext === ".yml") {
290
+ config = YAML.parse(content) as ModelsConfig;
291
+ } else {
292
+ config = JSON.parse(content) as ModelsConfig;
293
+ }
273
294
 
274
295
  // Validate schema
275
296
  const ajv = new Ajv();
@@ -278,7 +299,7 @@ export class ModelRegistry {
278
299
  const errors =
279
300
  validate.errors?.map((e: any) => ` - ${e.instancePath || "root"}: ${e.message}`).join("\n") ||
280
301
  "Unknown schema error";
281
- return emptyCustomModelsResult(`Invalid models.json schema:\n${errors}\n\nFile: ${modelsJsonPath}`);
302
+ return emptyCustomModelsResult(`Invalid models config schema:\n${errors}\n\nFile: ${modelsPath}`);
282
303
  }
283
304
 
284
305
  // Additional validation
@@ -306,14 +327,20 @@ export class ModelRegistry {
306
327
  }
307
328
  }
308
329
 
309
- return { models: this.parseModels(config), replacedProviders, overrides, error: undefined };
330
+ return { models: this.parseModels(config), replacedProviders, overrides, error: undefined, found: true };
310
331
  } catch (error) {
311
332
  if (error instanceof SyntaxError) {
312
- return emptyCustomModelsResult(`Failed to parse models.json: ${error.message}\n\nFile: ${modelsJsonPath}`);
333
+ return {
334
+ ...emptyCustomModelsResult(`Failed to parse models config: ${error.message}\n\nFile: ${modelsPath}`),
335
+ found: true,
336
+ };
313
337
  }
314
- return emptyCustomModelsResult(
315
- `Failed to load models.json: ${error instanceof Error ? error.message : error}\n\nFile: ${modelsJsonPath}`,
316
- );
338
+ return {
339
+ ...emptyCustomModelsResult(
340
+ `Failed to load models config: ${error instanceof Error ? error.message : error}\n\nFile: ${modelsPath}`,
341
+ ),
342
+ found: true,
343
+ };
317
344
  }
318
345
  }
319
346
 
@@ -422,21 +449,21 @@ export class ModelRegistry {
422
449
  * This is a fast check that doesn't refresh OAuth tokens.
423
450
  */
424
451
  getAvailable(): Model<Api>[] {
425
- return this.models.filter((m) => this.authStorage.hasAuth(m.provider));
452
+ return this.models.filter(m => this.authStorage.hasAuth(m.provider));
426
453
  }
427
454
 
428
455
  /**
429
456
  * Find a model by provider and ID.
430
457
  */
431
458
  find(provider: string, modelId: string): Model<Api> | undefined {
432
- return this.models.find((m) => m.provider === provider && m.id === modelId);
459
+ return this.models.find(m => m.provider === provider && m.id === modelId);
433
460
  }
434
461
 
435
462
  /**
436
463
  * Get the base URL associated with a provider, if any model defines one.
437
464
  */
438
465
  getProviderBaseUrl(provider: string): string | undefined {
439
- return this.models.find((m) => m.provider === provider && m.baseUrl)?.baseUrl;
466
+ return this.models.find(m => m.provider === provider && m.baseUrl)?.baseUrl;
440
467
  }
441
468
 
442
469
  /**