@imdigitalashish/zpi 0.1.1

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 (604) hide show
  1. package/CHANGELOG.md +2801 -0
  2. package/README.md +95 -0
  3. package/dist/cli/args.d.ts +47 -0
  4. package/dist/cli/args.d.ts.map +1 -0
  5. package/dist/cli/args.js +293 -0
  6. package/dist/cli/args.js.map +1 -0
  7. package/dist/cli/config-selector.d.ts +14 -0
  8. package/dist/cli/config-selector.d.ts.map +1 -0
  9. package/dist/cli/config-selector.js +31 -0
  10. package/dist/cli/config-selector.js.map +1 -0
  11. package/dist/cli/file-processor.d.ts +15 -0
  12. package/dist/cli/file-processor.d.ts.map +1 -0
  13. package/dist/cli/file-processor.js +79 -0
  14. package/dist/cli/file-processor.js.map +1 -0
  15. package/dist/cli/list-models.d.ts +9 -0
  16. package/dist/cli/list-models.d.ts.map +1 -0
  17. package/dist/cli/list-models.js +92 -0
  18. package/dist/cli/list-models.js.map +1 -0
  19. package/dist/cli/session-picker.d.ts +9 -0
  20. package/dist/cli/session-picker.d.ts.map +1 -0
  21. package/dist/cli/session-picker.js +34 -0
  22. package/dist/cli/session-picker.js.map +1 -0
  23. package/dist/cli.d.ts +3 -0
  24. package/dist/cli.d.ts.map +1 -0
  25. package/dist/cli.js +11 -0
  26. package/dist/cli.js.map +1 -0
  27. package/dist/config.d.ts +68 -0
  28. package/dist/config.d.ts.map +1 -0
  29. package/dist/config.js +203 -0
  30. package/dist/config.js.map +1 -0
  31. package/dist/core/agent-session.d.ts +571 -0
  32. package/dist/core/agent-session.d.ts.map +1 -0
  33. package/dist/core/agent-session.js +2353 -0
  34. package/dist/core/agent-session.js.map +1 -0
  35. package/dist/core/auth-storage.d.ts +129 -0
  36. package/dist/core/auth-storage.d.ts.map +1 -0
  37. package/dist/core/auth-storage.js +394 -0
  38. package/dist/core/auth-storage.js.map +1 -0
  39. package/dist/core/bash-executor.d.ts +47 -0
  40. package/dist/core/bash-executor.d.ts.map +1 -0
  41. package/dist/core/bash-executor.js +212 -0
  42. package/dist/core/bash-executor.js.map +1 -0
  43. package/dist/core/compaction/branch-summarization.d.ts +86 -0
  44. package/dist/core/compaction/branch-summarization.d.ts.map +1 -0
  45. package/dist/core/compaction/branch-summarization.js +242 -0
  46. package/dist/core/compaction/branch-summarization.js.map +1 -0
  47. package/dist/core/compaction/compaction.d.ts +121 -0
  48. package/dist/core/compaction/compaction.d.ts.map +1 -0
  49. package/dist/core/compaction/compaction.js +607 -0
  50. package/dist/core/compaction/compaction.js.map +1 -0
  51. package/dist/core/compaction/index.d.ts +7 -0
  52. package/dist/core/compaction/index.d.ts.map +1 -0
  53. package/dist/core/compaction/index.js +7 -0
  54. package/dist/core/compaction/index.js.map +1 -0
  55. package/dist/core/compaction/utils.d.ts +35 -0
  56. package/dist/core/compaction/utils.d.ts.map +1 -0
  57. package/dist/core/compaction/utils.js +138 -0
  58. package/dist/core/compaction/utils.js.map +1 -0
  59. package/dist/core/defaults.d.ts +3 -0
  60. package/dist/core/defaults.d.ts.map +1 -0
  61. package/dist/core/defaults.js +2 -0
  62. package/dist/core/defaults.js.map +1 -0
  63. package/dist/core/diagnostics.d.ts +15 -0
  64. package/dist/core/diagnostics.d.ts.map +1 -0
  65. package/dist/core/diagnostics.js +2 -0
  66. package/dist/core/diagnostics.js.map +1 -0
  67. package/dist/core/event-bus.d.ts +9 -0
  68. package/dist/core/event-bus.d.ts.map +1 -0
  69. package/dist/core/event-bus.js +25 -0
  70. package/dist/core/event-bus.js.map +1 -0
  71. package/dist/core/exec.d.ts +29 -0
  72. package/dist/core/exec.d.ts.map +1 -0
  73. package/dist/core/exec.js +71 -0
  74. package/dist/core/exec.js.map +1 -0
  75. package/dist/core/export-html/ansi-to-html.d.ts +22 -0
  76. package/dist/core/export-html/ansi-to-html.d.ts.map +1 -0
  77. package/dist/core/export-html/ansi-to-html.js +249 -0
  78. package/dist/core/export-html/ansi-to-html.js.map +1 -0
  79. package/dist/core/export-html/index.d.ts +34 -0
  80. package/dist/core/export-html/index.d.ts.map +1 -0
  81. package/dist/core/export-html/index.js +222 -0
  82. package/dist/core/export-html/index.js.map +1 -0
  83. package/dist/core/export-html/template.css +971 -0
  84. package/dist/core/export-html/template.html +54 -0
  85. package/dist/core/export-html/template.js +1586 -0
  86. package/dist/core/export-html/tool-renderer.d.ts +35 -0
  87. package/dist/core/export-html/tool-renderer.d.ts.map +1 -0
  88. package/dist/core/export-html/tool-renderer.js +57 -0
  89. package/dist/core/export-html/tool-renderer.js.map +1 -0
  90. package/dist/core/export-html/vendor/highlight.min.js +1213 -0
  91. package/dist/core/export-html/vendor/marked.min.js +6 -0
  92. package/dist/core/extensions/index.d.ts +11 -0
  93. package/dist/core/extensions/index.d.ts.map +1 -0
  94. package/dist/core/extensions/index.js +9 -0
  95. package/dist/core/extensions/index.js.map +1 -0
  96. package/dist/core/extensions/loader.d.ts +25 -0
  97. package/dist/core/extensions/loader.d.ts.map +1 -0
  98. package/dist/core/extensions/loader.js +402 -0
  99. package/dist/core/extensions/loader.js.map +1 -0
  100. package/dist/core/extensions/runner.d.ts +146 -0
  101. package/dist/core/extensions/runner.d.ts.map +1 -0
  102. package/dist/core/extensions/runner.js +626 -0
  103. package/dist/core/extensions/runner.js.map +1 -0
  104. package/dist/core/extensions/types.d.ts +984 -0
  105. package/dist/core/extensions/types.d.ts.map +1 -0
  106. package/dist/core/extensions/types.js +35 -0
  107. package/dist/core/extensions/types.js.map +1 -0
  108. package/dist/core/extensions/wrapper.d.ts +27 -0
  109. package/dist/core/extensions/wrapper.d.ts.map +1 -0
  110. package/dist/core/extensions/wrapper.js +102 -0
  111. package/dist/core/extensions/wrapper.js.map +1 -0
  112. package/dist/core/footer-data-provider.d.ts +32 -0
  113. package/dist/core/footer-data-provider.d.ts.map +1 -0
  114. package/dist/core/footer-data-provider.js +134 -0
  115. package/dist/core/footer-data-provider.js.map +1 -0
  116. package/dist/core/index.d.ts +9 -0
  117. package/dist/core/index.d.ts.map +1 -0
  118. package/dist/core/index.js +9 -0
  119. package/dist/core/index.js.map +1 -0
  120. package/dist/core/keybindings.d.ts +55 -0
  121. package/dist/core/keybindings.d.ts.map +1 -0
  122. package/dist/core/keybindings.js +153 -0
  123. package/dist/core/keybindings.js.map +1 -0
  124. package/dist/core/memory.d.ts +64 -0
  125. package/dist/core/memory.d.ts.map +1 -0
  126. package/dist/core/memory.js +247 -0
  127. package/dist/core/memory.js.map +1 -0
  128. package/dist/core/messages.d.ts +77 -0
  129. package/dist/core/messages.d.ts.map +1 -0
  130. package/dist/core/messages.js +149 -0
  131. package/dist/core/messages.js.map +1 -0
  132. package/dist/core/model-registry.d.ts +102 -0
  133. package/dist/core/model-registry.d.ts.map +1 -0
  134. package/dist/core/model-registry.js +515 -0
  135. package/dist/core/model-registry.js.map +1 -0
  136. package/dist/core/model-resolver.d.ts +104 -0
  137. package/dist/core/model-resolver.d.ts.map +1 -0
  138. package/dist/core/model-resolver.js +403 -0
  139. package/dist/core/model-resolver.js.map +1 -0
  140. package/dist/core/package-manager.d.ts +151 -0
  141. package/dist/core/package-manager.d.ts.map +1 -0
  142. package/dist/core/package-manager.js +1426 -0
  143. package/dist/core/package-manager.js.map +1 -0
  144. package/dist/core/prompt-templates.d.ts +50 -0
  145. package/dist/core/prompt-templates.d.ts.map +1 -0
  146. package/dist/core/prompt-templates.js +251 -0
  147. package/dist/core/prompt-templates.js.map +1 -0
  148. package/dist/core/resolve-config-value.d.ts +17 -0
  149. package/dist/core/resolve-config-value.d.ts.map +1 -0
  150. package/dist/core/resolve-config-value.js +59 -0
  151. package/dist/core/resolve-config-value.js.map +1 -0
  152. package/dist/core/resource-loader.d.ts +184 -0
  153. package/dist/core/resource-loader.d.ts.map +1 -0
  154. package/dist/core/resource-loader.js +673 -0
  155. package/dist/core/resource-loader.js.map +1 -0
  156. package/dist/core/sdk.d.ts +90 -0
  157. package/dist/core/sdk.d.ts.map +1 -0
  158. package/dist/core/sdk.js +238 -0
  159. package/dist/core/sdk.js.map +1 -0
  160. package/dist/core/session-manager.d.ts +323 -0
  161. package/dist/core/session-manager.d.ts.map +1 -0
  162. package/dist/core/session-manager.js +1091 -0
  163. package/dist/core/session-manager.js.map +1 -0
  164. package/dist/core/settings-manager.d.ts +230 -0
  165. package/dist/core/settings-manager.d.ts.map +1 -0
  166. package/dist/core/settings-manager.js +656 -0
  167. package/dist/core/settings-manager.js.map +1 -0
  168. package/dist/core/skills.d.ts +58 -0
  169. package/dist/core/skills.d.ts.map +1 -0
  170. package/dist/core/skills.js +364 -0
  171. package/dist/core/skills.js.map +1 -0
  172. package/dist/core/slash-commands.d.ts +15 -0
  173. package/dist/core/slash-commands.d.ts.map +1 -0
  174. package/dist/core/slash-commands.js +23 -0
  175. package/dist/core/slash-commands.js.map +1 -0
  176. package/dist/core/system-prompt.d.ts +26 -0
  177. package/dist/core/system-prompt.d.ts.map +1 -0
  178. package/dist/core/system-prompt.js +150 -0
  179. package/dist/core/system-prompt.js.map +1 -0
  180. package/dist/core/timings.d.ts +7 -0
  181. package/dist/core/timings.d.ts.map +1 -0
  182. package/dist/core/timings.js +25 -0
  183. package/dist/core/timings.js.map +1 -0
  184. package/dist/core/tools/bash.d.ts +55 -0
  185. package/dist/core/tools/bash.d.ts.map +1 -0
  186. package/dist/core/tools/bash.js +242 -0
  187. package/dist/core/tools/bash.js.map +1 -0
  188. package/dist/core/tools/edit-diff.d.ts +63 -0
  189. package/dist/core/tools/edit-diff.d.ts.map +1 -0
  190. package/dist/core/tools/edit-diff.js +243 -0
  191. package/dist/core/tools/edit-diff.js.map +1 -0
  192. package/dist/core/tools/edit.d.ts +39 -0
  193. package/dist/core/tools/edit.d.ts.map +1 -0
  194. package/dist/core/tools/edit.js +146 -0
  195. package/dist/core/tools/edit.js.map +1 -0
  196. package/dist/core/tools/find.d.ts +39 -0
  197. package/dist/core/tools/find.d.ts.map +1 -0
  198. package/dist/core/tools/find.js +206 -0
  199. package/dist/core/tools/find.js.map +1 -0
  200. package/dist/core/tools/grep.d.ts +45 -0
  201. package/dist/core/tools/grep.d.ts.map +1 -0
  202. package/dist/core/tools/grep.js +239 -0
  203. package/dist/core/tools/grep.js.map +1 -0
  204. package/dist/core/tools/index.d.ts +102 -0
  205. package/dist/core/tools/index.d.ts.map +1 -0
  206. package/dist/core/tools/index.js +71 -0
  207. package/dist/core/tools/index.js.map +1 -0
  208. package/dist/core/tools/ls.d.ts +40 -0
  209. package/dist/core/tools/ls.d.ts.map +1 -0
  210. package/dist/core/tools/ls.js +118 -0
  211. package/dist/core/tools/ls.js.map +1 -0
  212. package/dist/core/tools/memory.d.ts +45 -0
  213. package/dist/core/tools/memory.d.ts.map +1 -0
  214. package/dist/core/tools/memory.js +346 -0
  215. package/dist/core/tools/memory.js.map +1 -0
  216. package/dist/core/tools/path-utils.d.ts +8 -0
  217. package/dist/core/tools/path-utils.d.ts.map +1 -0
  218. package/dist/core/tools/path-utils.js +81 -0
  219. package/dist/core/tools/path-utils.js.map +1 -0
  220. package/dist/core/tools/read.d.ts +39 -0
  221. package/dist/core/tools/read.d.ts.map +1 -0
  222. package/dist/core/tools/read.js +166 -0
  223. package/dist/core/tools/read.js.map +1 -0
  224. package/dist/core/tools/truncate.d.ts +70 -0
  225. package/dist/core/tools/truncate.d.ts.map +1 -0
  226. package/dist/core/tools/truncate.js +205 -0
  227. package/dist/core/tools/truncate.js.map +1 -0
  228. package/dist/core/tools/write.d.ts +29 -0
  229. package/dist/core/tools/write.d.ts.map +1 -0
  230. package/dist/core/tools/write.js +78 -0
  231. package/dist/core/tools/write.js.map +1 -0
  232. package/dist/index.d.ts +28 -0
  233. package/dist/index.d.ts.map +1 -0
  234. package/dist/index.js +43 -0
  235. package/dist/index.js.map +1 -0
  236. package/dist/main.d.ts +8 -0
  237. package/dist/main.d.ts.map +1 -0
  238. package/dist/main.js +651 -0
  239. package/dist/main.js.map +1 -0
  240. package/dist/migrations.d.ts +33 -0
  241. package/dist/migrations.d.ts.map +1 -0
  242. package/dist/migrations.js +261 -0
  243. package/dist/migrations.js.map +1 -0
  244. package/dist/modes/index.d.ts +9 -0
  245. package/dist/modes/index.d.ts.map +1 -0
  246. package/dist/modes/index.js +8 -0
  247. package/dist/modes/index.js.map +1 -0
  248. package/dist/modes/interactive/components/armin.d.ts +34 -0
  249. package/dist/modes/interactive/components/armin.d.ts.map +1 -0
  250. package/dist/modes/interactive/components/armin.js +333 -0
  251. package/dist/modes/interactive/components/armin.js.map +1 -0
  252. package/dist/modes/interactive/components/assistant-message.d.ts +16 -0
  253. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -0
  254. package/dist/modes/interactive/components/assistant-message.js +96 -0
  255. package/dist/modes/interactive/components/assistant-message.js.map +1 -0
  256. package/dist/modes/interactive/components/bash-execution.d.ts +35 -0
  257. package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -0
  258. package/dist/modes/interactive/components/bash-execution.js +162 -0
  259. package/dist/modes/interactive/components/bash-execution.js.map +1 -0
  260. package/dist/modes/interactive/components/bordered-loader.d.ts +16 -0
  261. package/dist/modes/interactive/components/bordered-loader.d.ts.map +1 -0
  262. package/dist/modes/interactive/components/bordered-loader.js +51 -0
  263. package/dist/modes/interactive/components/bordered-loader.js.map +1 -0
  264. package/dist/modes/interactive/components/branch-summary-message.d.ts +16 -0
  265. package/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -0
  266. package/dist/modes/interactive/components/branch-summary-message.js +44 -0
  267. package/dist/modes/interactive/components/branch-summary-message.js.map +1 -0
  268. package/dist/modes/interactive/components/compaction-summary-message.d.ts +16 -0
  269. package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -0
  270. package/dist/modes/interactive/components/compaction-summary-message.js +45 -0
  271. package/dist/modes/interactive/components/compaction-summary-message.js.map +1 -0
  272. package/dist/modes/interactive/components/config-selector.d.ts +71 -0
  273. package/dist/modes/interactive/components/config-selector.d.ts.map +1 -0
  274. package/dist/modes/interactive/components/config-selector.js +479 -0
  275. package/dist/modes/interactive/components/config-selector.js.map +1 -0
  276. package/dist/modes/interactive/components/countdown-timer.d.ts +14 -0
  277. package/dist/modes/interactive/components/countdown-timer.d.ts.map +1 -0
  278. package/dist/modes/interactive/components/countdown-timer.js +33 -0
  279. package/dist/modes/interactive/components/countdown-timer.js.map +1 -0
  280. package/dist/modes/interactive/components/custom-editor.d.ts +21 -0
  281. package/dist/modes/interactive/components/custom-editor.d.ts.map +1 -0
  282. package/dist/modes/interactive/components/custom-editor.js +70 -0
  283. package/dist/modes/interactive/components/custom-editor.js.map +1 -0
  284. package/dist/modes/interactive/components/custom-message.d.ts +20 -0
  285. package/dist/modes/interactive/components/custom-message.d.ts.map +1 -0
  286. package/dist/modes/interactive/components/custom-message.js +79 -0
  287. package/dist/modes/interactive/components/custom-message.js.map +1 -0
  288. package/dist/modes/interactive/components/daxnuts.d.ts +23 -0
  289. package/dist/modes/interactive/components/daxnuts.d.ts.map +1 -0
  290. package/dist/modes/interactive/components/daxnuts.js +140 -0
  291. package/dist/modes/interactive/components/daxnuts.js.map +1 -0
  292. package/dist/modes/interactive/components/diff.d.ts +12 -0
  293. package/dist/modes/interactive/components/diff.d.ts.map +1 -0
  294. package/dist/modes/interactive/components/diff.js +133 -0
  295. package/dist/modes/interactive/components/diff.js.map +1 -0
  296. package/dist/modes/interactive/components/dynamic-border.d.ts +15 -0
  297. package/dist/modes/interactive/components/dynamic-border.d.ts.map +1 -0
  298. package/dist/modes/interactive/components/dynamic-border.js +21 -0
  299. package/dist/modes/interactive/components/dynamic-border.js.map +1 -0
  300. package/dist/modes/interactive/components/extension-editor.d.ts +17 -0
  301. package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -0
  302. package/dist/modes/interactive/components/extension-editor.js +102 -0
  303. package/dist/modes/interactive/components/extension-editor.js.map +1 -0
  304. package/dist/modes/interactive/components/extension-input.d.ts +23 -0
  305. package/dist/modes/interactive/components/extension-input.d.ts.map +1 -0
  306. package/dist/modes/interactive/components/extension-input.js +61 -0
  307. package/dist/modes/interactive/components/extension-input.js.map +1 -0
  308. package/dist/modes/interactive/components/extension-selector.d.ts +24 -0
  309. package/dist/modes/interactive/components/extension-selector.d.ts.map +1 -0
  310. package/dist/modes/interactive/components/extension-selector.js +78 -0
  311. package/dist/modes/interactive/components/extension-selector.js.map +1 -0
  312. package/dist/modes/interactive/components/footer.d.ts +26 -0
  313. package/dist/modes/interactive/components/footer.d.ts.map +1 -0
  314. package/dist/modes/interactive/components/footer.js +213 -0
  315. package/dist/modes/interactive/components/footer.js.map +1 -0
  316. package/dist/modes/interactive/components/index.d.ts +32 -0
  317. package/dist/modes/interactive/components/index.d.ts.map +1 -0
  318. package/dist/modes/interactive/components/index.js +33 -0
  319. package/dist/modes/interactive/components/index.js.map +1 -0
  320. package/dist/modes/interactive/components/keybinding-hints.d.ts +41 -0
  321. package/dist/modes/interactive/components/keybinding-hints.d.ts.map +1 -0
  322. package/dist/modes/interactive/components/keybinding-hints.js +61 -0
  323. package/dist/modes/interactive/components/keybinding-hints.js.map +1 -0
  324. package/dist/modes/interactive/components/login-dialog.d.ts +42 -0
  325. package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -0
  326. package/dist/modes/interactive/components/login-dialog.js +145 -0
  327. package/dist/modes/interactive/components/login-dialog.js.map +1 -0
  328. package/dist/modes/interactive/components/model-selector.d.ts +47 -0
  329. package/dist/modes/interactive/components/model-selector.d.ts.map +1 -0
  330. package/dist/modes/interactive/components/model-selector.js +271 -0
  331. package/dist/modes/interactive/components/model-selector.js.map +1 -0
  332. package/dist/modes/interactive/components/oauth-selector.d.ts +19 -0
  333. package/dist/modes/interactive/components/oauth-selector.d.ts.map +1 -0
  334. package/dist/modes/interactive/components/oauth-selector.js +97 -0
  335. package/dist/modes/interactive/components/oauth-selector.js.map +1 -0
  336. package/dist/modes/interactive/components/scoped-models-selector.d.ts +49 -0
  337. package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -0
  338. package/dist/modes/interactive/components/scoped-models-selector.js +275 -0
  339. package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -0
  340. package/dist/modes/interactive/components/session-selector-search.d.ts +23 -0
  341. package/dist/modes/interactive/components/session-selector-search.d.ts.map +1 -0
  342. package/dist/modes/interactive/components/session-selector-search.js +155 -0
  343. package/dist/modes/interactive/components/session-selector-search.js.map +1 -0
  344. package/dist/modes/interactive/components/session-selector.d.ts +95 -0
  345. package/dist/modes/interactive/components/session-selector.d.ts.map +1 -0
  346. package/dist/modes/interactive/components/session-selector.js +851 -0
  347. package/dist/modes/interactive/components/session-selector.js.map +1 -0
  348. package/dist/modes/interactive/components/settings-selector.d.ts +58 -0
  349. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -0
  350. package/dist/modes/interactive/components/settings-selector.js +299 -0
  351. package/dist/modes/interactive/components/settings-selector.js.map +1 -0
  352. package/dist/modes/interactive/components/show-images-selector.d.ts +10 -0
  353. package/dist/modes/interactive/components/show-images-selector.d.ts.map +1 -0
  354. package/dist/modes/interactive/components/show-images-selector.js +35 -0
  355. package/dist/modes/interactive/components/show-images-selector.js.map +1 -0
  356. package/dist/modes/interactive/components/skill-invocation-message.d.ts +17 -0
  357. package/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -0
  358. package/dist/modes/interactive/components/skill-invocation-message.js +47 -0
  359. package/dist/modes/interactive/components/skill-invocation-message.js.map +1 -0
  360. package/dist/modes/interactive/components/theme-selector.d.ts +11 -0
  361. package/dist/modes/interactive/components/theme-selector.d.ts.map +1 -0
  362. package/dist/modes/interactive/components/theme-selector.js +46 -0
  363. package/dist/modes/interactive/components/theme-selector.js.map +1 -0
  364. package/dist/modes/interactive/components/thinking-selector.d.ts +11 -0
  365. package/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -0
  366. package/dist/modes/interactive/components/thinking-selector.js +47 -0
  367. package/dist/modes/interactive/components/thinking-selector.js.map +1 -0
  368. package/dist/modes/interactive/components/tool-execution.d.ts +70 -0
  369. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -0
  370. package/dist/modes/interactive/components/tool-execution.js +636 -0
  371. package/dist/modes/interactive/components/tool-execution.js.map +1 -0
  372. package/dist/modes/interactive/components/tree-selector.d.ts +68 -0
  373. package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -0
  374. package/dist/modes/interactive/components/tree-selector.js +934 -0
  375. package/dist/modes/interactive/components/tree-selector.js.map +1 -0
  376. package/dist/modes/interactive/components/user-message-selector.d.ts +30 -0
  377. package/dist/modes/interactive/components/user-message-selector.d.ts.map +1 -0
  378. package/dist/modes/interactive/components/user-message-selector.js +113 -0
  379. package/dist/modes/interactive/components/user-message-selector.js.map +1 -0
  380. package/dist/modes/interactive/components/user-message.d.ts +8 -0
  381. package/dist/modes/interactive/components/user-message.d.ts.map +1 -0
  382. package/dist/modes/interactive/components/user-message.js +16 -0
  383. package/dist/modes/interactive/components/user-message.js.map +1 -0
  384. package/dist/modes/interactive/components/visual-truncate.d.ts +24 -0
  385. package/dist/modes/interactive/components/visual-truncate.d.ts.map +1 -0
  386. package/dist/modes/interactive/components/visual-truncate.js +33 -0
  387. package/dist/modes/interactive/components/visual-truncate.js.map +1 -0
  388. package/dist/modes/interactive/interactive-mode.d.ts +316 -0
  389. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -0
  390. package/dist/modes/interactive/interactive-mode.js +3848 -0
  391. package/dist/modes/interactive/interactive-mode.js.map +1 -0
  392. package/dist/modes/interactive/theme/dark.json +85 -0
  393. package/dist/modes/interactive/theme/light.json +84 -0
  394. package/dist/modes/interactive/theme/theme-schema.json +335 -0
  395. package/dist/modes/interactive/theme/theme.d.ts +78 -0
  396. package/dist/modes/interactive/theme/theme.d.ts.map +1 -0
  397. package/dist/modes/interactive/theme/theme.js +944 -0
  398. package/dist/modes/interactive/theme/theme.js.map +1 -0
  399. package/dist/modes/print-mode.d.ts +28 -0
  400. package/dist/modes/print-mode.d.ts.map +1 -0
  401. package/dist/modes/print-mode.js +101 -0
  402. package/dist/modes/print-mode.js.map +1 -0
  403. package/dist/modes/rpc/rpc-client.d.ts +217 -0
  404. package/dist/modes/rpc/rpc-client.d.ts.map +1 -0
  405. package/dist/modes/rpc/rpc-client.js +405 -0
  406. package/dist/modes/rpc/rpc-client.js.map +1 -0
  407. package/dist/modes/rpc/rpc-mode.d.ts +20 -0
  408. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -0
  409. package/dist/modes/rpc/rpc-mode.js +511 -0
  410. package/dist/modes/rpc/rpc-mode.js.map +1 -0
  411. package/dist/modes/rpc/rpc-types.d.ts +409 -0
  412. package/dist/modes/rpc/rpc-types.d.ts.map +1 -0
  413. package/dist/modes/rpc/rpc-types.js +8 -0
  414. package/dist/modes/rpc/rpc-types.js.map +1 -0
  415. package/dist/utils/changelog.d.ts +21 -0
  416. package/dist/utils/changelog.d.ts.map +1 -0
  417. package/dist/utils/changelog.js +87 -0
  418. package/dist/utils/changelog.js.map +1 -0
  419. package/dist/utils/clipboard-image.d.ts +11 -0
  420. package/dist/utils/clipboard-image.d.ts.map +1 -0
  421. package/dist/utils/clipboard-image.js +162 -0
  422. package/dist/utils/clipboard-image.js.map +1 -0
  423. package/dist/utils/clipboard-native.d.ts +7 -0
  424. package/dist/utils/clipboard-native.d.ts.map +1 -0
  425. package/dist/utils/clipboard-native.js +14 -0
  426. package/dist/utils/clipboard-native.js.map +1 -0
  427. package/dist/utils/clipboard.d.ts +2 -0
  428. package/dist/utils/clipboard.d.ts.map +1 -0
  429. package/dist/utils/clipboard.js +67 -0
  430. package/dist/utils/clipboard.js.map +1 -0
  431. package/dist/utils/frontmatter.d.ts +8 -0
  432. package/dist/utils/frontmatter.d.ts.map +1 -0
  433. package/dist/utils/frontmatter.js +26 -0
  434. package/dist/utils/frontmatter.js.map +1 -0
  435. package/dist/utils/git.d.ts +26 -0
  436. package/dist/utils/git.d.ts.map +1 -0
  437. package/dist/utils/git.js +163 -0
  438. package/dist/utils/git.js.map +1 -0
  439. package/dist/utils/image-convert.d.ts +9 -0
  440. package/dist/utils/image-convert.d.ts.map +1 -0
  441. package/dist/utils/image-convert.js +35 -0
  442. package/dist/utils/image-convert.js.map +1 -0
  443. package/dist/utils/image-resize.d.ts +36 -0
  444. package/dist/utils/image-resize.d.ts.map +1 -0
  445. package/dist/utils/image-resize.js +181 -0
  446. package/dist/utils/image-resize.js.map +1 -0
  447. package/dist/utils/mime.d.ts +2 -0
  448. package/dist/utils/mime.d.ts.map +1 -0
  449. package/dist/utils/mime.js +26 -0
  450. package/dist/utils/mime.js.map +1 -0
  451. package/dist/utils/photon.d.ts +21 -0
  452. package/dist/utils/photon.d.ts.map +1 -0
  453. package/dist/utils/photon.js +121 -0
  454. package/dist/utils/photon.js.map +1 -0
  455. package/dist/utils/shell.d.ts +26 -0
  456. package/dist/utils/shell.d.ts.map +1 -0
  457. package/dist/utils/shell.js +186 -0
  458. package/dist/utils/shell.js.map +1 -0
  459. package/dist/utils/sleep.d.ts +5 -0
  460. package/dist/utils/sleep.d.ts.map +1 -0
  461. package/dist/utils/sleep.js +17 -0
  462. package/dist/utils/sleep.js.map +1 -0
  463. package/dist/utils/tools-manager.d.ts +3 -0
  464. package/dist/utils/tools-manager.d.ts.map +1 -0
  465. package/dist/utils/tools-manager.js +207 -0
  466. package/dist/utils/tools-manager.js.map +1 -0
  467. package/docs/compaction.md +390 -0
  468. package/docs/custom-provider.md +548 -0
  469. package/docs/development.md +69 -0
  470. package/docs/extensions.md +1935 -0
  471. package/docs/images/doom-extension.png +0 -0
  472. package/docs/images/exy.png +0 -0
  473. package/docs/images/interactive-mode.png +0 -0
  474. package/docs/images/tree-view.png +0 -0
  475. package/docs/json.md +79 -0
  476. package/docs/keybindings.md +174 -0
  477. package/docs/models.md +293 -0
  478. package/docs/packages.md +209 -0
  479. package/docs/prompt-templates.md +67 -0
  480. package/docs/providers.md +186 -0
  481. package/docs/rpc.md +1317 -0
  482. package/docs/sdk.md +968 -0
  483. package/docs/session.md +412 -0
  484. package/docs/settings.md +223 -0
  485. package/docs/shell-aliases.md +13 -0
  486. package/docs/skills.md +231 -0
  487. package/docs/terminal-setup.md +70 -0
  488. package/docs/termux.md +127 -0
  489. package/docs/themes.md +295 -0
  490. package/docs/tree.md +219 -0
  491. package/docs/tui.md +887 -0
  492. package/docs/windows.md +17 -0
  493. package/examples/README.md +25 -0
  494. package/examples/extensions/README.md +203 -0
  495. package/examples/extensions/antigravity-image-gen.ts +413 -0
  496. package/examples/extensions/auto-commit-on-exit.ts +49 -0
  497. package/examples/extensions/bash-spawn-hook.ts +30 -0
  498. package/examples/extensions/bookmark.ts +50 -0
  499. package/examples/extensions/claude-rules.ts +86 -0
  500. package/examples/extensions/commands.ts +72 -0
  501. package/examples/extensions/confirm-destructive.ts +59 -0
  502. package/examples/extensions/custom-compaction.ts +114 -0
  503. package/examples/extensions/custom-footer.ts +64 -0
  504. package/examples/extensions/custom-header.ts +73 -0
  505. package/examples/extensions/custom-provider-anthropic/index.ts +604 -0
  506. package/examples/extensions/custom-provider-anthropic/package-lock.json +24 -0
  507. package/examples/extensions/custom-provider-anthropic/package.json +19 -0
  508. package/examples/extensions/custom-provider-gitlab-duo/index.ts +349 -0
  509. package/examples/extensions/custom-provider-gitlab-duo/package.json +16 -0
  510. package/examples/extensions/custom-provider-gitlab-duo/test.ts +82 -0
  511. package/examples/extensions/custom-provider-qwen-cli/index.ts +345 -0
  512. package/examples/extensions/custom-provider-qwen-cli/package.json +16 -0
  513. package/examples/extensions/dirty-repo-guard.ts +56 -0
  514. package/examples/extensions/doom-overlay/README.md +46 -0
  515. package/examples/extensions/doom-overlay/doom/build/doom.js +21 -0
  516. package/examples/extensions/doom-overlay/doom/build/doom.wasm +0 -0
  517. package/examples/extensions/doom-overlay/doom/build.sh +152 -0
  518. package/examples/extensions/doom-overlay/doom/doomgeneric_pi.c +72 -0
  519. package/examples/extensions/doom-overlay/doom-component.ts +132 -0
  520. package/examples/extensions/doom-overlay/doom-engine.ts +173 -0
  521. package/examples/extensions/doom-overlay/doom-keys.ts +104 -0
  522. package/examples/extensions/doom-overlay/index.ts +74 -0
  523. package/examples/extensions/doom-overlay/wad-finder.ts +51 -0
  524. package/examples/extensions/dynamic-resources/SKILL.md +8 -0
  525. package/examples/extensions/dynamic-resources/dynamic.json +79 -0
  526. package/examples/extensions/dynamic-resources/dynamic.md +5 -0
  527. package/examples/extensions/dynamic-resources/index.ts +15 -0
  528. package/examples/extensions/event-bus.ts +43 -0
  529. package/examples/extensions/file-trigger.ts +41 -0
  530. package/examples/extensions/git-checkpoint.ts +53 -0
  531. package/examples/extensions/handoff.ts +150 -0
  532. package/examples/extensions/hello.ts +25 -0
  533. package/examples/extensions/inline-bash.ts +94 -0
  534. package/examples/extensions/input-transform.ts +43 -0
  535. package/examples/extensions/interactive-shell.ts +196 -0
  536. package/examples/extensions/mac-system-theme.ts +47 -0
  537. package/examples/extensions/message-renderer.ts +59 -0
  538. package/examples/extensions/minimal-mode.ts +426 -0
  539. package/examples/extensions/modal-editor.ts +85 -0
  540. package/examples/extensions/model-status.ts +31 -0
  541. package/examples/extensions/notify.ts +55 -0
  542. package/examples/extensions/overlay-qa-tests.ts +881 -0
  543. package/examples/extensions/overlay-test.ts +150 -0
  544. package/examples/extensions/permission-gate.ts +34 -0
  545. package/examples/extensions/pirate.ts +47 -0
  546. package/examples/extensions/plan-mode/README.md +65 -0
  547. package/examples/extensions/plan-mode/index.ts +340 -0
  548. package/examples/extensions/plan-mode/utils.ts +168 -0
  549. package/examples/extensions/preset.ts +398 -0
  550. package/examples/extensions/protected-paths.ts +30 -0
  551. package/examples/extensions/qna.ts +119 -0
  552. package/examples/extensions/question.ts +264 -0
  553. package/examples/extensions/questionnaire.ts +427 -0
  554. package/examples/extensions/rainbow-editor.ts +88 -0
  555. package/examples/extensions/reload-runtime.ts +37 -0
  556. package/examples/extensions/rpc-demo.ts +124 -0
  557. package/examples/extensions/sandbox/index.ts +318 -0
  558. package/examples/extensions/sandbox/package-lock.json +92 -0
  559. package/examples/extensions/sandbox/package.json +19 -0
  560. package/examples/extensions/send-user-message.ts +97 -0
  561. package/examples/extensions/session-name.ts +27 -0
  562. package/examples/extensions/shutdown-command.ts +63 -0
  563. package/examples/extensions/snake.ts +343 -0
  564. package/examples/extensions/space-invaders.ts +560 -0
  565. package/examples/extensions/ssh.ts +220 -0
  566. package/examples/extensions/status-line.ts +40 -0
  567. package/examples/extensions/subagent/README.md +172 -0
  568. package/examples/extensions/subagent/agents/planner.md +37 -0
  569. package/examples/extensions/subagent/agents/reviewer.md +35 -0
  570. package/examples/extensions/subagent/agents/scout.md +50 -0
  571. package/examples/extensions/subagent/agents/worker.md +24 -0
  572. package/examples/extensions/subagent/agents.ts +127 -0
  573. package/examples/extensions/subagent/index.ts +964 -0
  574. package/examples/extensions/subagent/prompts/implement-and-review.md +10 -0
  575. package/examples/extensions/subagent/prompts/implement.md +10 -0
  576. package/examples/extensions/subagent/prompts/scout-and-plan.md +9 -0
  577. package/examples/extensions/summarize.ts +195 -0
  578. package/examples/extensions/system-prompt-header.ts +17 -0
  579. package/examples/extensions/timed-confirm.ts +70 -0
  580. package/examples/extensions/titlebar-spinner.ts +58 -0
  581. package/examples/extensions/todo.ts +299 -0
  582. package/examples/extensions/tool-override.ts +143 -0
  583. package/examples/extensions/tools.ts +146 -0
  584. package/examples/extensions/trigger-compact.ts +40 -0
  585. package/examples/extensions/truncated-tool.ts +192 -0
  586. package/examples/extensions/widget-placement.ts +17 -0
  587. package/examples/extensions/with-deps/index.ts +36 -0
  588. package/examples/extensions/with-deps/package-lock.json +31 -0
  589. package/examples/extensions/with-deps/package.json +22 -0
  590. package/examples/rpc-extension-ui.ts +632 -0
  591. package/examples/sdk/01-minimal.ts +22 -0
  592. package/examples/sdk/02-custom-model.ts +49 -0
  593. package/examples/sdk/03-custom-prompt.ts +55 -0
  594. package/examples/sdk/04-skills.ts +46 -0
  595. package/examples/sdk/05-tools.ts +56 -0
  596. package/examples/sdk/06-extensions.ts +88 -0
  597. package/examples/sdk/07-context-files.ts +40 -0
  598. package/examples/sdk/08-prompt-templates.ts +47 -0
  599. package/examples/sdk/09-api-keys-and-oauth.ts +48 -0
  600. package/examples/sdk/10-settings.ts +51 -0
  601. package/examples/sdk/11-sessions.ts +48 -0
  602. package/examples/sdk/12-full-control.ts +82 -0
  603. package/examples/sdk/README.md +144 -0
  604. package/package.json +96 -0
@@ -0,0 +1,104 @@
1
+ /**
2
+ * Model resolution, scoping, and initial selection
3
+ */
4
+ import type { ThinkingLevel } from "@mariozechner/pi-agent-core";
5
+ import { type Api, type KnownProvider, type Model } from "@mariozechner/pi-ai";
6
+ import type { ModelRegistry } from "./model-registry.js";
7
+ /** Default model IDs for each known provider */
8
+ export declare const defaultModelPerProvider: Record<KnownProvider, string>;
9
+ export interface ScopedModel {
10
+ model: Model<Api>;
11
+ /** Thinking level if explicitly specified in pattern (e.g., "model:high"), undefined otherwise */
12
+ thinkingLevel?: ThinkingLevel;
13
+ }
14
+ export interface ParsedModelResult {
15
+ model: Model<Api> | undefined;
16
+ /** Thinking level if explicitly specified in pattern, undefined otherwise */
17
+ thinkingLevel?: ThinkingLevel;
18
+ warning: string | undefined;
19
+ }
20
+ /**
21
+ * Parse a pattern to extract model and thinking level.
22
+ * Handles models with colons in their IDs (e.g., OpenRouter's :exacto suffix).
23
+ *
24
+ * Algorithm:
25
+ * 1. Try to match full pattern as a model
26
+ * 2. If found, return it with "off" thinking level
27
+ * 3. If not found and has colons, split on last colon:
28
+ * - If suffix is valid thinking level, use it and recurse on prefix
29
+ * - If suffix is invalid, warn and recurse on prefix with "off"
30
+ *
31
+ * @internal Exported for testing
32
+ */
33
+ export declare function parseModelPattern(pattern: string, availableModels: Model<Api>[], options?: {
34
+ allowInvalidThinkingLevelFallback?: boolean;
35
+ }): ParsedModelResult;
36
+ /**
37
+ * Resolve model patterns to actual Model objects with optional thinking levels
38
+ * Format: "pattern:level" where :level is optional
39
+ * For each pattern, finds all matching models and picks the best version:
40
+ * 1. Prefer alias (e.g., claude-sonnet-4-5) over dated versions (claude-sonnet-4-5-20250929)
41
+ * 2. If no alias, pick the latest dated version
42
+ *
43
+ * Supports models with colons in their IDs (e.g., OpenRouter's model:exacto).
44
+ * The algorithm tries to match the full pattern first, then progressively
45
+ * strips colon-suffixes to find a match.
46
+ */
47
+ export declare function resolveModelScope(patterns: string[], modelRegistry: ModelRegistry): Promise<ScopedModel[]>;
48
+ export interface ResolveCliModelResult {
49
+ model: Model<Api> | undefined;
50
+ thinkingLevel?: ThinkingLevel;
51
+ warning: string | undefined;
52
+ /**
53
+ * Error message suitable for CLI display.
54
+ * When set, model will be undefined.
55
+ */
56
+ error: string | undefined;
57
+ }
58
+ /**
59
+ * Resolve a single model from CLI flags.
60
+ *
61
+ * Supports:
62
+ * - --provider <provider> --model <pattern>
63
+ * - --model <provider>/<pattern>
64
+ * - Fuzzy matching (same rules as model scoping: exact id, then partial id/name)
65
+ *
66
+ * Note: This does not apply the thinking level by itself, but it may *parse* and
67
+ * return a thinking level from "<pattern>:<thinking>" so the caller can apply it.
68
+ */
69
+ export declare function resolveCliModel(options: {
70
+ cliProvider?: string;
71
+ cliModel?: string;
72
+ modelRegistry: ModelRegistry;
73
+ }): ResolveCliModelResult;
74
+ export interface InitialModelResult {
75
+ model: Model<Api> | undefined;
76
+ thinkingLevel: ThinkingLevel;
77
+ fallbackMessage: string | undefined;
78
+ }
79
+ /**
80
+ * Find the initial model to use based on priority:
81
+ * 1. CLI args (provider + model)
82
+ * 2. First model from scoped models (if not continuing/resuming)
83
+ * 3. Restored from session (if continuing/resuming)
84
+ * 4. Saved default from settings
85
+ * 5. First available model with valid API key
86
+ */
87
+ export declare function findInitialModel(options: {
88
+ cliProvider?: string;
89
+ cliModel?: string;
90
+ scopedModels: ScopedModel[];
91
+ isContinuing: boolean;
92
+ defaultProvider?: string;
93
+ defaultModelId?: string;
94
+ defaultThinkingLevel?: ThinkingLevel;
95
+ modelRegistry: ModelRegistry;
96
+ }): Promise<InitialModelResult>;
97
+ /**
98
+ * Restore model from session, with fallback to available models
99
+ */
100
+ export declare function restoreModelFromSession(savedProvider: string, savedModelId: string, currentModel: Model<Api> | undefined, shouldPrintMessages: boolean, modelRegistry: ModelRegistry): Promise<{
101
+ model: Model<Api> | undefined;
102
+ fallbackMessage: string | undefined;
103
+ }>;
104
+ //# sourceMappingURL=model-resolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model-resolver.d.ts","sourceRoot":"","sources":["../../src/core/model-resolver.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AACjE,OAAO,EAAE,KAAK,GAAG,EAAE,KAAK,aAAa,EAAE,KAAK,KAAK,EAAkB,MAAM,qBAAqB,CAAC;AAK/F,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEzD,gDAAgD;AAChD,eAAO,MAAM,uBAAuB,EAAE,MAAM,CAAC,aAAa,EAAE,MAAM,CAuBjE,CAAC;AAEF,MAAM,WAAW,WAAW;IAC3B,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;IAClB,kGAAkG;IAClG,aAAa,CAAC,EAAE,aAAa,CAAC;CAC9B;AAkED,MAAM,WAAW,iBAAiB;IACjC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC;IAC9B,6EAA6E;IAC7E,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;CAC5B;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAChC,OAAO,EAAE,MAAM,EACf,eAAe,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE,EAC7B,OAAO,CAAC,EAAE;IAAE,iCAAiC,CAAC,EAAE,OAAO,CAAA;CAAE,GACvD,iBAAiB,CAiDnB;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE,aAAa,EAAE,aAAa,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CA0DhH;AAED,MAAM,WAAW,qBAAqB;IACrC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC;IAC9B,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B;;;OAGG;IACH,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;CAC1B;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE;IACxC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,aAAa,CAAC;CAC7B,GAAG,qBAAqB,CAkFxB;AAED,MAAM,WAAW,kBAAkB;IAClC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC;IAC9B,aAAa,EAAE,aAAa,CAAC;IAC7B,eAAe,EAAE,MAAM,GAAG,SAAS,CAAC;CACpC;AAED;;;;;;;GAOG;AACH,wBAAsB,gBAAgB,CAAC,OAAO,EAAE;IAC/C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,WAAW,EAAE,CAAC;IAC5B,YAAY,EAAE,OAAO,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,oBAAoB,CAAC,EAAE,aAAa,CAAC;IACrC,aAAa,EAAE,aAAa,CAAC;CAC7B,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAiE9B;AAED;;GAEG;AACH,wBAAsB,uBAAuB,CAC5C,aAAa,EAAE,MAAM,EACrB,YAAY,EAAE,MAAM,EACpB,YAAY,EAAE,KAAK,CAAC,GAAG,CAAC,GAAG,SAAS,EACpC,mBAAmB,EAAE,OAAO,EAC5B,aAAa,EAAE,aAAa,GAC1B,OAAO,CAAC;IAAE,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC;IAAC,eAAe,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,CAAC,CA+DjF","sourcesContent":["/**\r\n * Model resolution, scoping, and initial selection\r\n */\r\n\r\nimport type { ThinkingLevel } from \"@mariozechner/pi-agent-core\";\r\nimport { type Api, type KnownProvider, type Model, modelsAreEqual } from \"@mariozechner/pi-ai\";\r\nimport chalk from \"chalk\";\r\nimport { minimatch } from \"minimatch\";\r\nimport { isValidThinkingLevel } from \"../cli/args.js\";\r\nimport { DEFAULT_THINKING_LEVEL } from \"./defaults.js\";\r\nimport type { ModelRegistry } from \"./model-registry.js\";\r\n\r\n/** Default model IDs for each known provider */\r\nexport const defaultModelPerProvider: Record<KnownProvider, string> = {\r\n\t\"amazon-bedrock\": \"us.anthropic.claude-opus-4-6-v1\",\r\n\tanthropic: \"claude-opus-4-6\",\r\n\topenai: \"gpt-5.1-codex\",\r\n\t\"azure-openai-responses\": \"gpt-5.2\",\r\n\t\"openai-codex\": \"gpt-5.3-codex\",\r\n\tgoogle: \"gemini-2.5-pro\",\r\n\t\"google-gemini-cli\": \"gemini-2.5-pro\",\r\n\t\"google-antigravity\": \"gemini-3-pro-high\",\r\n\t\"google-vertex\": \"gemini-3-pro-preview\",\r\n\t\"github-copilot\": \"gpt-4o\",\r\n\topenrouter: \"openai/gpt-5.1-codex\",\r\n\t\"vercel-ai-gateway\": \"anthropic/claude-opus-4-6\",\r\n\txai: \"grok-4-fast-non-reasoning\",\r\n\tgroq: \"openai/gpt-oss-120b\",\r\n\tcerebras: \"zai-glm-4.6\",\r\n\tzai: \"glm-4.6\",\r\n\tmistral: \"devstral-medium-latest\",\r\n\tminimax: \"MiniMax-M2.1\",\r\n\t\"minimax-cn\": \"MiniMax-M2.1\",\r\n\thuggingface: \"moonshotai/Kimi-K2.5\",\r\n\topencode: \"claude-opus-4-6\",\r\n\t\"kimi-coding\": \"kimi-k2-thinking\",\r\n};\r\n\r\nexport interface ScopedModel {\r\n\tmodel: Model<Api>;\r\n\t/** Thinking level if explicitly specified in pattern (e.g., \"model:high\"), undefined otherwise */\r\n\tthinkingLevel?: ThinkingLevel;\r\n}\r\n\r\n/**\r\n * Helper to check if a model ID looks like an alias (no date suffix)\r\n * Dates are typically in format: -20241022 or -20250929\r\n */\r\nfunction isAlias(id: string): boolean {\r\n\t// Check if ID ends with -latest\r\n\tif (id.endsWith(\"-latest\")) return true;\r\n\r\n\t// Check if ID ends with a date pattern (-YYYYMMDD)\r\n\tconst datePattern = /-\\d{8}$/;\r\n\treturn !datePattern.test(id);\r\n}\r\n\r\n/**\r\n * Try to match a pattern to a model from the available models list.\r\n * Returns the matched model or undefined if no match found.\r\n */\r\nfunction tryMatchModel(modelPattern: string, availableModels: Model<Api>[]): Model<Api> | undefined {\r\n\t// Check for provider/modelId format (provider is everything before the first /)\r\n\tconst slashIndex = modelPattern.indexOf(\"/\");\r\n\tif (slashIndex !== -1) {\r\n\t\tconst provider = modelPattern.substring(0, slashIndex);\r\n\t\tconst modelId = modelPattern.substring(slashIndex + 1);\r\n\t\tconst providerMatch = availableModels.find(\r\n\t\t\t(m) => m.provider.toLowerCase() === provider.toLowerCase() && m.id.toLowerCase() === modelId.toLowerCase(),\r\n\t\t);\r\n\t\tif (providerMatch) {\r\n\t\t\treturn providerMatch;\r\n\t\t}\r\n\t\t// No exact provider/model match - fall through to other matching\r\n\t}\r\n\r\n\t// Check for exact ID match (case-insensitive)\r\n\tconst exactMatch = availableModels.find((m) => m.id.toLowerCase() === modelPattern.toLowerCase());\r\n\tif (exactMatch) {\r\n\t\treturn exactMatch;\r\n\t}\r\n\r\n\t// No exact match - fall back to partial matching\r\n\tconst matches = availableModels.filter(\r\n\t\t(m) =>\r\n\t\t\tm.id.toLowerCase().includes(modelPattern.toLowerCase()) ||\r\n\t\t\tm.name?.toLowerCase().includes(modelPattern.toLowerCase()),\r\n\t);\r\n\r\n\tif (matches.length === 0) {\r\n\t\treturn undefined;\r\n\t}\r\n\r\n\t// Separate into aliases and dated versions\r\n\tconst aliases = matches.filter((m) => isAlias(m.id));\r\n\tconst datedVersions = matches.filter((m) => !isAlias(m.id));\r\n\r\n\tif (aliases.length > 0) {\r\n\t\t// Prefer alias - if multiple aliases, pick the one that sorts highest\r\n\t\taliases.sort((a, b) => b.id.localeCompare(a.id));\r\n\t\treturn aliases[0];\r\n\t} else {\r\n\t\t// No alias found, pick latest dated version\r\n\t\tdatedVersions.sort((a, b) => b.id.localeCompare(a.id));\r\n\t\treturn datedVersions[0];\r\n\t}\r\n}\r\n\r\nexport interface ParsedModelResult {\r\n\tmodel: Model<Api> | undefined;\r\n\t/** Thinking level if explicitly specified in pattern, undefined otherwise */\r\n\tthinkingLevel?: ThinkingLevel;\r\n\twarning: string | undefined;\r\n}\r\n\r\n/**\r\n * Parse a pattern to extract model and thinking level.\r\n * Handles models with colons in their IDs (e.g., OpenRouter's :exacto suffix).\r\n *\r\n * Algorithm:\r\n * 1. Try to match full pattern as a model\r\n * 2. If found, return it with \"off\" thinking level\r\n * 3. If not found and has colons, split on last colon:\r\n * - If suffix is valid thinking level, use it and recurse on prefix\r\n * - If suffix is invalid, warn and recurse on prefix with \"off\"\r\n *\r\n * @internal Exported for testing\r\n */\r\nexport function parseModelPattern(\r\n\tpattern: string,\r\n\tavailableModels: Model<Api>[],\r\n\toptions?: { allowInvalidThinkingLevelFallback?: boolean },\r\n): ParsedModelResult {\r\n\t// Try exact match first\r\n\tconst exactMatch = tryMatchModel(pattern, availableModels);\r\n\tif (exactMatch) {\r\n\t\treturn { model: exactMatch, thinkingLevel: undefined, warning: undefined };\r\n\t}\r\n\r\n\t// No match - try splitting on last colon if present\r\n\tconst lastColonIndex = pattern.lastIndexOf(\":\");\r\n\tif (lastColonIndex === -1) {\r\n\t\t// No colons, pattern simply doesn't match any model\r\n\t\treturn { model: undefined, thinkingLevel: undefined, warning: undefined };\r\n\t}\r\n\r\n\tconst prefix = pattern.substring(0, lastColonIndex);\r\n\tconst suffix = pattern.substring(lastColonIndex + 1);\r\n\r\n\tif (isValidThinkingLevel(suffix)) {\r\n\t\t// Valid thinking level - recurse on prefix and use this level\r\n\t\tconst result = parseModelPattern(prefix, availableModels, options);\r\n\t\tif (result.model) {\r\n\t\t\t// Only use this thinking level if no warning from inner recursion\r\n\t\t\treturn {\r\n\t\t\t\tmodel: result.model,\r\n\t\t\t\tthinkingLevel: result.warning ? undefined : suffix,\r\n\t\t\t\twarning: result.warning,\r\n\t\t\t};\r\n\t\t}\r\n\t\treturn result;\r\n\t} else {\r\n\t\t// Invalid suffix\r\n\t\tconst allowFallback = options?.allowInvalidThinkingLevelFallback ?? true;\r\n\t\tif (!allowFallback) {\r\n\t\t\t// In strict mode (CLI --model parsing), treat it as part of the model id and fail.\r\n\t\t\t// This avoids accidentally resolving to a different model.\r\n\t\t\treturn { model: undefined, thinkingLevel: undefined, warning: undefined };\r\n\t\t}\r\n\r\n\t\t// Scope mode: recurse on prefix and warn\r\n\t\tconst result = parseModelPattern(prefix, availableModels, options);\r\n\t\tif (result.model) {\r\n\t\t\treturn {\r\n\t\t\t\tmodel: result.model,\r\n\t\t\t\tthinkingLevel: undefined,\r\n\t\t\t\twarning: `Invalid thinking level \"${suffix}\" in pattern \"${pattern}\". Using default instead.`,\r\n\t\t\t};\r\n\t\t}\r\n\t\treturn result;\r\n\t}\r\n}\r\n\r\n/**\r\n * Resolve model patterns to actual Model objects with optional thinking levels\r\n * Format: \"pattern:level\" where :level is optional\r\n * For each pattern, finds all matching models and picks the best version:\r\n * 1. Prefer alias (e.g., claude-sonnet-4-5) over dated versions (claude-sonnet-4-5-20250929)\r\n * 2. If no alias, pick the latest dated version\r\n *\r\n * Supports models with colons in their IDs (e.g., OpenRouter's model:exacto).\r\n * The algorithm tries to match the full pattern first, then progressively\r\n * strips colon-suffixes to find a match.\r\n */\r\nexport async function resolveModelScope(patterns: string[], modelRegistry: ModelRegistry): Promise<ScopedModel[]> {\r\n\tconst availableModels = await modelRegistry.getAvailable();\r\n\tconst scopedModels: ScopedModel[] = [];\r\n\r\n\tfor (const pattern of patterns) {\r\n\t\t// Check if pattern contains glob characters\r\n\t\tif (pattern.includes(\"*\") || pattern.includes(\"?\") || pattern.includes(\"[\")) {\r\n\t\t\t// Extract optional thinking level suffix (e.g., \"provider/*:high\")\r\n\t\t\tconst colonIdx = pattern.lastIndexOf(\":\");\r\n\t\t\tlet globPattern = pattern;\r\n\t\t\tlet thinkingLevel: ThinkingLevel | undefined;\r\n\r\n\t\t\tif (colonIdx !== -1) {\r\n\t\t\t\tconst suffix = pattern.substring(colonIdx + 1);\r\n\t\t\t\tif (isValidThinkingLevel(suffix)) {\r\n\t\t\t\t\tthinkingLevel = suffix;\r\n\t\t\t\t\tglobPattern = pattern.substring(0, colonIdx);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\t// Match against \"provider/modelId\" format OR just model ID\r\n\t\t\t// This allows \"*sonnet*\" to match without requiring \"anthropic/*sonnet*\"\r\n\t\t\tconst matchingModels = availableModels.filter((m) => {\r\n\t\t\t\tconst fullId = `${m.provider}/${m.id}`;\r\n\t\t\t\treturn minimatch(fullId, globPattern, { nocase: true }) || minimatch(m.id, globPattern, { nocase: true });\r\n\t\t\t});\r\n\r\n\t\t\tif (matchingModels.length === 0) {\r\n\t\t\t\tconsole.warn(chalk.yellow(`Warning: No models match pattern \"${pattern}\"`));\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\tfor (const model of matchingModels) {\r\n\t\t\t\tif (!scopedModels.find((sm) => modelsAreEqual(sm.model, model))) {\r\n\t\t\t\t\tscopedModels.push({ model, thinkingLevel });\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tcontinue;\r\n\t\t}\r\n\r\n\t\tconst { model, thinkingLevel, warning } = parseModelPattern(pattern, availableModels);\r\n\r\n\t\tif (warning) {\r\n\t\t\tconsole.warn(chalk.yellow(`Warning: ${warning}`));\r\n\t\t}\r\n\r\n\t\tif (!model) {\r\n\t\t\tconsole.warn(chalk.yellow(`Warning: No models match pattern \"${pattern}\"`));\r\n\t\t\tcontinue;\r\n\t\t}\r\n\r\n\t\t// Avoid duplicates\r\n\t\tif (!scopedModels.find((sm) => modelsAreEqual(sm.model, model))) {\r\n\t\t\tscopedModels.push({ model, thinkingLevel });\r\n\t\t}\r\n\t}\r\n\r\n\treturn scopedModels;\r\n}\r\n\r\nexport interface ResolveCliModelResult {\r\n\tmodel: Model<Api> | undefined;\r\n\tthinkingLevel?: ThinkingLevel;\r\n\twarning: string | undefined;\r\n\t/**\r\n\t * Error message suitable for CLI display.\r\n\t * When set, model will be undefined.\r\n\t */\r\n\terror: string | undefined;\r\n}\r\n\r\n/**\r\n * Resolve a single model from CLI flags.\r\n *\r\n * Supports:\r\n * - --provider <provider> --model <pattern>\r\n * - --model <provider>/<pattern>\r\n * - Fuzzy matching (same rules as model scoping: exact id, then partial id/name)\r\n *\r\n * Note: This does not apply the thinking level by itself, but it may *parse* and\r\n * return a thinking level from \"<pattern>:<thinking>\" so the caller can apply it.\r\n */\r\nexport function resolveCliModel(options: {\r\n\tcliProvider?: string;\r\n\tcliModel?: string;\r\n\tmodelRegistry: ModelRegistry;\r\n}): ResolveCliModelResult {\r\n\tconst { cliProvider, cliModel, modelRegistry } = options;\r\n\r\n\tif (!cliModel) {\r\n\t\treturn { model: undefined, warning: undefined, error: undefined };\r\n\t}\r\n\r\n\t// Important: use *all* models here, not just models with pre-configured auth.\r\n\t// This allows \"--api-key\" to be used for first-time setup.\r\n\tconst availableModels = modelRegistry.getAll();\r\n\tif (availableModels.length === 0) {\r\n\t\treturn {\r\n\t\t\tmodel: undefined,\r\n\t\t\twarning: undefined,\r\n\t\t\terror: \"No models available. Check your installation or add models to models.json.\",\r\n\t\t};\r\n\t}\r\n\r\n\t// Build canonical provider lookup (case-insensitive)\r\n\tconst providerMap = new Map<string, string>();\r\n\tfor (const m of availableModels) {\r\n\t\tproviderMap.set(m.provider.toLowerCase(), m.provider);\r\n\t}\r\n\r\n\tlet provider = cliProvider ? providerMap.get(cliProvider.toLowerCase()) : undefined;\r\n\tif (cliProvider && !provider) {\r\n\t\treturn {\r\n\t\t\tmodel: undefined,\r\n\t\t\twarning: undefined,\r\n\t\t\terror: `Unknown provider \"${cliProvider}\". Use --list-models to see available providers/models.`,\r\n\t\t};\r\n\t}\r\n\r\n\t// If no explicit --provider, first try exact matches without any provider inference.\r\n\t// This avoids misinterpreting model IDs that themselves contain slashes (e.g. OpenRouter-style IDs).\r\n\tif (!provider) {\r\n\t\tconst lower = cliModel.toLowerCase();\r\n\t\tconst exact = availableModels.find(\r\n\t\t\t(m) => m.id.toLowerCase() === lower || `${m.provider}/${m.id}`.toLowerCase() === lower,\r\n\t\t);\r\n\t\tif (exact) {\r\n\t\t\treturn { model: exact, warning: undefined, thinkingLevel: undefined, error: undefined };\r\n\t\t}\r\n\t}\r\n\r\n\tlet pattern = cliModel;\r\n\r\n\t// If no explicit --provider, allow --model provider/<pattern>\r\n\tif (!provider) {\r\n\t\tconst slashIndex = cliModel.indexOf(\"/\");\r\n\t\tif (slashIndex !== -1) {\r\n\t\t\tconst maybeProvider = cliModel.substring(0, slashIndex);\r\n\t\t\tconst canonical = providerMap.get(maybeProvider.toLowerCase());\r\n\t\t\tif (canonical) {\r\n\t\t\t\tprovider = canonical;\r\n\t\t\t\tpattern = cliModel.substring(slashIndex + 1);\r\n\t\t\t}\r\n\t\t}\r\n\t} else {\r\n\t\t// If both were provided, tolerate --model <provider>/<pattern> by stripping the provider prefix\r\n\t\tconst prefix = `${provider}/`;\r\n\t\tif (cliModel.toLowerCase().startsWith(prefix.toLowerCase())) {\r\n\t\t\tpattern = cliModel.substring(prefix.length);\r\n\t\t}\r\n\t}\r\n\r\n\tconst candidates = provider ? availableModels.filter((m) => m.provider === provider) : availableModels;\r\n\tconst { model, thinkingLevel, warning } = parseModelPattern(pattern, candidates, {\r\n\t\tallowInvalidThinkingLevelFallback: false,\r\n\t});\r\n\r\n\tif (!model) {\r\n\t\tconst display = provider ? `${provider}/${pattern}` : cliModel;\r\n\t\treturn {\r\n\t\t\tmodel: undefined,\r\n\t\t\tthinkingLevel: undefined,\r\n\t\t\twarning,\r\n\t\t\terror: `Model \"${display}\" not found. Use --list-models to see available models.`,\r\n\t\t};\r\n\t}\r\n\r\n\treturn { model, thinkingLevel, warning, error: undefined };\r\n}\r\n\r\nexport interface InitialModelResult {\r\n\tmodel: Model<Api> | undefined;\r\n\tthinkingLevel: ThinkingLevel;\r\n\tfallbackMessage: string | undefined;\r\n}\r\n\r\n/**\r\n * Find the initial model to use based on priority:\r\n * 1. CLI args (provider + model)\r\n * 2. First model from scoped models (if not continuing/resuming)\r\n * 3. Restored from session (if continuing/resuming)\r\n * 4. Saved default from settings\r\n * 5. First available model with valid API key\r\n */\r\nexport async function findInitialModel(options: {\r\n\tcliProvider?: string;\r\n\tcliModel?: string;\r\n\tscopedModels: ScopedModel[];\r\n\tisContinuing: boolean;\r\n\tdefaultProvider?: string;\r\n\tdefaultModelId?: string;\r\n\tdefaultThinkingLevel?: ThinkingLevel;\r\n\tmodelRegistry: ModelRegistry;\r\n}): Promise<InitialModelResult> {\r\n\tconst {\r\n\t\tcliProvider,\r\n\t\tcliModel,\r\n\t\tscopedModels,\r\n\t\tisContinuing,\r\n\t\tdefaultProvider,\r\n\t\tdefaultModelId,\r\n\t\tdefaultThinkingLevel,\r\n\t\tmodelRegistry,\r\n\t} = options;\r\n\r\n\tlet model: Model<Api> | undefined;\r\n\tlet thinkingLevel: ThinkingLevel = DEFAULT_THINKING_LEVEL;\r\n\r\n\t// 1. CLI args take priority\r\n\tif (cliProvider && cliModel) {\r\n\t\tconst found = modelRegistry.find(cliProvider, cliModel);\r\n\t\tif (!found) {\r\n\t\t\tconsole.error(chalk.red(`Model ${cliProvider}/${cliModel} not found`));\r\n\t\t\tprocess.exit(1);\r\n\t\t}\r\n\t\treturn { model: found, thinkingLevel: DEFAULT_THINKING_LEVEL, fallbackMessage: undefined };\r\n\t}\r\n\r\n\t// 2. Use first model from scoped models (skip if continuing/resuming)\r\n\tif (scopedModels.length > 0 && !isContinuing) {\r\n\t\treturn {\r\n\t\t\tmodel: scopedModels[0].model,\r\n\t\t\tthinkingLevel: scopedModels[0].thinkingLevel ?? defaultThinkingLevel ?? DEFAULT_THINKING_LEVEL,\r\n\t\t\tfallbackMessage: undefined,\r\n\t\t};\r\n\t}\r\n\r\n\t// 3. Try saved default from settings\r\n\tif (defaultProvider && defaultModelId) {\r\n\t\tconst found = modelRegistry.find(defaultProvider, defaultModelId);\r\n\t\tif (found) {\r\n\t\t\tmodel = found;\r\n\t\t\tif (defaultThinkingLevel) {\r\n\t\t\t\tthinkingLevel = defaultThinkingLevel;\r\n\t\t\t}\r\n\t\t\treturn { model, thinkingLevel, fallbackMessage: undefined };\r\n\t\t}\r\n\t}\r\n\r\n\t// 4. Try first available model with valid API key\r\n\tconst availableModels = await modelRegistry.getAvailable();\r\n\r\n\tif (availableModels.length > 0) {\r\n\t\t// Try to find a default model from known providers\r\n\t\tfor (const provider of Object.keys(defaultModelPerProvider) as KnownProvider[]) {\r\n\t\t\tconst defaultId = defaultModelPerProvider[provider];\r\n\t\t\tconst match = availableModels.find((m) => m.provider === provider && m.id === defaultId);\r\n\t\t\tif (match) {\r\n\t\t\t\treturn { model: match, thinkingLevel: DEFAULT_THINKING_LEVEL, fallbackMessage: undefined };\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// If no default found, use first available\r\n\t\treturn { model: availableModels[0], thinkingLevel: DEFAULT_THINKING_LEVEL, fallbackMessage: undefined };\r\n\t}\r\n\r\n\t// 5. No model found\r\n\treturn { model: undefined, thinkingLevel: DEFAULT_THINKING_LEVEL, fallbackMessage: undefined };\r\n}\r\n\r\n/**\r\n * Restore model from session, with fallback to available models\r\n */\r\nexport async function restoreModelFromSession(\r\n\tsavedProvider: string,\r\n\tsavedModelId: string,\r\n\tcurrentModel: Model<Api> | undefined,\r\n\tshouldPrintMessages: boolean,\r\n\tmodelRegistry: ModelRegistry,\r\n): Promise<{ model: Model<Api> | undefined; fallbackMessage: string | undefined }> {\r\n\tconst restoredModel = modelRegistry.find(savedProvider, savedModelId);\r\n\r\n\t// Check if restored model exists and has a valid API key\r\n\tconst hasApiKey = restoredModel ? !!(await modelRegistry.getApiKey(restoredModel)) : false;\r\n\r\n\tif (restoredModel && hasApiKey) {\r\n\t\tif (shouldPrintMessages) {\r\n\t\t\tconsole.log(chalk.dim(`Restored model: ${savedProvider}/${savedModelId}`));\r\n\t\t}\r\n\t\treturn { model: restoredModel, fallbackMessage: undefined };\r\n\t}\r\n\r\n\t// Model not found or no API key - fall back\r\n\tconst reason = !restoredModel ? \"model no longer exists\" : \"no API key available\";\r\n\r\n\tif (shouldPrintMessages) {\r\n\t\tconsole.error(chalk.yellow(`Warning: Could not restore model ${savedProvider}/${savedModelId} (${reason}).`));\r\n\t}\r\n\r\n\t// If we already have a model, use it as fallback\r\n\tif (currentModel) {\r\n\t\tif (shouldPrintMessages) {\r\n\t\t\tconsole.log(chalk.dim(`Falling back to: ${currentModel.provider}/${currentModel.id}`));\r\n\t\t}\r\n\t\treturn {\r\n\t\t\tmodel: currentModel,\r\n\t\t\tfallbackMessage: `Could not restore model ${savedProvider}/${savedModelId} (${reason}). Using ${currentModel.provider}/${currentModel.id}.`,\r\n\t\t};\r\n\t}\r\n\r\n\t// Try to find any available model\r\n\tconst availableModels = await modelRegistry.getAvailable();\r\n\r\n\tif (availableModels.length > 0) {\r\n\t\t// Try to find a default model from known providers\r\n\t\tlet fallbackModel: Model<Api> | undefined;\r\n\t\tfor (const provider of Object.keys(defaultModelPerProvider) as KnownProvider[]) {\r\n\t\t\tconst defaultId = defaultModelPerProvider[provider];\r\n\t\t\tconst match = availableModels.find((m) => m.provider === provider && m.id === defaultId);\r\n\t\t\tif (match) {\r\n\t\t\t\tfallbackModel = match;\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// If no default found, use first available\r\n\t\tif (!fallbackModel) {\r\n\t\t\tfallbackModel = availableModels[0];\r\n\t\t}\r\n\r\n\t\tif (shouldPrintMessages) {\r\n\t\t\tconsole.log(chalk.dim(`Falling back to: ${fallbackModel.provider}/${fallbackModel.id}`));\r\n\t\t}\r\n\r\n\t\treturn {\r\n\t\t\tmodel: fallbackModel,\r\n\t\t\tfallbackMessage: `Could not restore model ${savedProvider}/${savedModelId} (${reason}). Using ${fallbackModel.provider}/${fallbackModel.id}.`,\r\n\t\t};\r\n\t}\r\n\r\n\t// No models available\r\n\treturn { model: undefined, fallbackMessage: undefined };\r\n}\r\n"]}
@@ -0,0 +1,403 @@
1
+ /**
2
+ * Model resolution, scoping, and initial selection
3
+ */
4
+ import { modelsAreEqual } from "@mariozechner/pi-ai";
5
+ import chalk from "chalk";
6
+ import { minimatch } from "minimatch";
7
+ import { isValidThinkingLevel } from "../cli/args.js";
8
+ import { DEFAULT_THINKING_LEVEL } from "./defaults.js";
9
+ /** Default model IDs for each known provider */
10
+ export const defaultModelPerProvider = {
11
+ "amazon-bedrock": "us.anthropic.claude-opus-4-6-v1",
12
+ anthropic: "claude-opus-4-6",
13
+ openai: "gpt-5.1-codex",
14
+ "azure-openai-responses": "gpt-5.2",
15
+ "openai-codex": "gpt-5.3-codex",
16
+ google: "gemini-2.5-pro",
17
+ "google-gemini-cli": "gemini-2.5-pro",
18
+ "google-antigravity": "gemini-3-pro-high",
19
+ "google-vertex": "gemini-3-pro-preview",
20
+ "github-copilot": "gpt-4o",
21
+ openrouter: "openai/gpt-5.1-codex",
22
+ "vercel-ai-gateway": "anthropic/claude-opus-4-6",
23
+ xai: "grok-4-fast-non-reasoning",
24
+ groq: "openai/gpt-oss-120b",
25
+ cerebras: "zai-glm-4.6",
26
+ zai: "glm-4.6",
27
+ mistral: "devstral-medium-latest",
28
+ minimax: "MiniMax-M2.1",
29
+ "minimax-cn": "MiniMax-M2.1",
30
+ huggingface: "moonshotai/Kimi-K2.5",
31
+ opencode: "claude-opus-4-6",
32
+ "kimi-coding": "kimi-k2-thinking",
33
+ };
34
+ /**
35
+ * Helper to check if a model ID looks like an alias (no date suffix)
36
+ * Dates are typically in format: -20241022 or -20250929
37
+ */
38
+ function isAlias(id) {
39
+ // Check if ID ends with -latest
40
+ if (id.endsWith("-latest"))
41
+ return true;
42
+ // Check if ID ends with a date pattern (-YYYYMMDD)
43
+ const datePattern = /-\d{8}$/;
44
+ return !datePattern.test(id);
45
+ }
46
+ /**
47
+ * Try to match a pattern to a model from the available models list.
48
+ * Returns the matched model or undefined if no match found.
49
+ */
50
+ function tryMatchModel(modelPattern, availableModels) {
51
+ // Check for provider/modelId format (provider is everything before the first /)
52
+ const slashIndex = modelPattern.indexOf("/");
53
+ if (slashIndex !== -1) {
54
+ const provider = modelPattern.substring(0, slashIndex);
55
+ const modelId = modelPattern.substring(slashIndex + 1);
56
+ const providerMatch = availableModels.find((m) => m.provider.toLowerCase() === provider.toLowerCase() && m.id.toLowerCase() === modelId.toLowerCase());
57
+ if (providerMatch) {
58
+ return providerMatch;
59
+ }
60
+ // No exact provider/model match - fall through to other matching
61
+ }
62
+ // Check for exact ID match (case-insensitive)
63
+ const exactMatch = availableModels.find((m) => m.id.toLowerCase() === modelPattern.toLowerCase());
64
+ if (exactMatch) {
65
+ return exactMatch;
66
+ }
67
+ // No exact match - fall back to partial matching
68
+ const matches = availableModels.filter((m) => m.id.toLowerCase().includes(modelPattern.toLowerCase()) ||
69
+ m.name?.toLowerCase().includes(modelPattern.toLowerCase()));
70
+ if (matches.length === 0) {
71
+ return undefined;
72
+ }
73
+ // Separate into aliases and dated versions
74
+ const aliases = matches.filter((m) => isAlias(m.id));
75
+ const datedVersions = matches.filter((m) => !isAlias(m.id));
76
+ if (aliases.length > 0) {
77
+ // Prefer alias - if multiple aliases, pick the one that sorts highest
78
+ aliases.sort((a, b) => b.id.localeCompare(a.id));
79
+ return aliases[0];
80
+ }
81
+ else {
82
+ // No alias found, pick latest dated version
83
+ datedVersions.sort((a, b) => b.id.localeCompare(a.id));
84
+ return datedVersions[0];
85
+ }
86
+ }
87
+ /**
88
+ * Parse a pattern to extract model and thinking level.
89
+ * Handles models with colons in their IDs (e.g., OpenRouter's :exacto suffix).
90
+ *
91
+ * Algorithm:
92
+ * 1. Try to match full pattern as a model
93
+ * 2. If found, return it with "off" thinking level
94
+ * 3. If not found and has colons, split on last colon:
95
+ * - If suffix is valid thinking level, use it and recurse on prefix
96
+ * - If suffix is invalid, warn and recurse on prefix with "off"
97
+ *
98
+ * @internal Exported for testing
99
+ */
100
+ export function parseModelPattern(pattern, availableModels, options) {
101
+ // Try exact match first
102
+ const exactMatch = tryMatchModel(pattern, availableModels);
103
+ if (exactMatch) {
104
+ return { model: exactMatch, thinkingLevel: undefined, warning: undefined };
105
+ }
106
+ // No match - try splitting on last colon if present
107
+ const lastColonIndex = pattern.lastIndexOf(":");
108
+ if (lastColonIndex === -1) {
109
+ // No colons, pattern simply doesn't match any model
110
+ return { model: undefined, thinkingLevel: undefined, warning: undefined };
111
+ }
112
+ const prefix = pattern.substring(0, lastColonIndex);
113
+ const suffix = pattern.substring(lastColonIndex + 1);
114
+ if (isValidThinkingLevel(suffix)) {
115
+ // Valid thinking level - recurse on prefix and use this level
116
+ const result = parseModelPattern(prefix, availableModels, options);
117
+ if (result.model) {
118
+ // Only use this thinking level if no warning from inner recursion
119
+ return {
120
+ model: result.model,
121
+ thinkingLevel: result.warning ? undefined : suffix,
122
+ warning: result.warning,
123
+ };
124
+ }
125
+ return result;
126
+ }
127
+ else {
128
+ // Invalid suffix
129
+ const allowFallback = options?.allowInvalidThinkingLevelFallback ?? true;
130
+ if (!allowFallback) {
131
+ // In strict mode (CLI --model parsing), treat it as part of the model id and fail.
132
+ // This avoids accidentally resolving to a different model.
133
+ return { model: undefined, thinkingLevel: undefined, warning: undefined };
134
+ }
135
+ // Scope mode: recurse on prefix and warn
136
+ const result = parseModelPattern(prefix, availableModels, options);
137
+ if (result.model) {
138
+ return {
139
+ model: result.model,
140
+ thinkingLevel: undefined,
141
+ warning: `Invalid thinking level "${suffix}" in pattern "${pattern}". Using default instead.`,
142
+ };
143
+ }
144
+ return result;
145
+ }
146
+ }
147
+ /**
148
+ * Resolve model patterns to actual Model objects with optional thinking levels
149
+ * Format: "pattern:level" where :level is optional
150
+ * For each pattern, finds all matching models and picks the best version:
151
+ * 1. Prefer alias (e.g., claude-sonnet-4-5) over dated versions (claude-sonnet-4-5-20250929)
152
+ * 2. If no alias, pick the latest dated version
153
+ *
154
+ * Supports models with colons in their IDs (e.g., OpenRouter's model:exacto).
155
+ * The algorithm tries to match the full pattern first, then progressively
156
+ * strips colon-suffixes to find a match.
157
+ */
158
+ export async function resolveModelScope(patterns, modelRegistry) {
159
+ const availableModels = await modelRegistry.getAvailable();
160
+ const scopedModels = [];
161
+ for (const pattern of patterns) {
162
+ // Check if pattern contains glob characters
163
+ if (pattern.includes("*") || pattern.includes("?") || pattern.includes("[")) {
164
+ // Extract optional thinking level suffix (e.g., "provider/*:high")
165
+ const colonIdx = pattern.lastIndexOf(":");
166
+ let globPattern = pattern;
167
+ let thinkingLevel;
168
+ if (colonIdx !== -1) {
169
+ const suffix = pattern.substring(colonIdx + 1);
170
+ if (isValidThinkingLevel(suffix)) {
171
+ thinkingLevel = suffix;
172
+ globPattern = pattern.substring(0, colonIdx);
173
+ }
174
+ }
175
+ // Match against "provider/modelId" format OR just model ID
176
+ // This allows "*sonnet*" to match without requiring "anthropic/*sonnet*"
177
+ const matchingModels = availableModels.filter((m) => {
178
+ const fullId = `${m.provider}/${m.id}`;
179
+ return minimatch(fullId, globPattern, { nocase: true }) || minimatch(m.id, globPattern, { nocase: true });
180
+ });
181
+ if (matchingModels.length === 0) {
182
+ console.warn(chalk.yellow(`Warning: No models match pattern "${pattern}"`));
183
+ continue;
184
+ }
185
+ for (const model of matchingModels) {
186
+ if (!scopedModels.find((sm) => modelsAreEqual(sm.model, model))) {
187
+ scopedModels.push({ model, thinkingLevel });
188
+ }
189
+ }
190
+ continue;
191
+ }
192
+ const { model, thinkingLevel, warning } = parseModelPattern(pattern, availableModels);
193
+ if (warning) {
194
+ console.warn(chalk.yellow(`Warning: ${warning}`));
195
+ }
196
+ if (!model) {
197
+ console.warn(chalk.yellow(`Warning: No models match pattern "${pattern}"`));
198
+ continue;
199
+ }
200
+ // Avoid duplicates
201
+ if (!scopedModels.find((sm) => modelsAreEqual(sm.model, model))) {
202
+ scopedModels.push({ model, thinkingLevel });
203
+ }
204
+ }
205
+ return scopedModels;
206
+ }
207
+ /**
208
+ * Resolve a single model from CLI flags.
209
+ *
210
+ * Supports:
211
+ * - --provider <provider> --model <pattern>
212
+ * - --model <provider>/<pattern>
213
+ * - Fuzzy matching (same rules as model scoping: exact id, then partial id/name)
214
+ *
215
+ * Note: This does not apply the thinking level by itself, but it may *parse* and
216
+ * return a thinking level from "<pattern>:<thinking>" so the caller can apply it.
217
+ */
218
+ export function resolveCliModel(options) {
219
+ const { cliProvider, cliModel, modelRegistry } = options;
220
+ if (!cliModel) {
221
+ return { model: undefined, warning: undefined, error: undefined };
222
+ }
223
+ // Important: use *all* models here, not just models with pre-configured auth.
224
+ // This allows "--api-key" to be used for first-time setup.
225
+ const availableModels = modelRegistry.getAll();
226
+ if (availableModels.length === 0) {
227
+ return {
228
+ model: undefined,
229
+ warning: undefined,
230
+ error: "No models available. Check your installation or add models to models.json.",
231
+ };
232
+ }
233
+ // Build canonical provider lookup (case-insensitive)
234
+ const providerMap = new Map();
235
+ for (const m of availableModels) {
236
+ providerMap.set(m.provider.toLowerCase(), m.provider);
237
+ }
238
+ let provider = cliProvider ? providerMap.get(cliProvider.toLowerCase()) : undefined;
239
+ if (cliProvider && !provider) {
240
+ return {
241
+ model: undefined,
242
+ warning: undefined,
243
+ error: `Unknown provider "${cliProvider}". Use --list-models to see available providers/models.`,
244
+ };
245
+ }
246
+ // If no explicit --provider, first try exact matches without any provider inference.
247
+ // This avoids misinterpreting model IDs that themselves contain slashes (e.g. OpenRouter-style IDs).
248
+ if (!provider) {
249
+ const lower = cliModel.toLowerCase();
250
+ const exact = availableModels.find((m) => m.id.toLowerCase() === lower || `${m.provider}/${m.id}`.toLowerCase() === lower);
251
+ if (exact) {
252
+ return { model: exact, warning: undefined, thinkingLevel: undefined, error: undefined };
253
+ }
254
+ }
255
+ let pattern = cliModel;
256
+ // If no explicit --provider, allow --model provider/<pattern>
257
+ if (!provider) {
258
+ const slashIndex = cliModel.indexOf("/");
259
+ if (slashIndex !== -1) {
260
+ const maybeProvider = cliModel.substring(0, slashIndex);
261
+ const canonical = providerMap.get(maybeProvider.toLowerCase());
262
+ if (canonical) {
263
+ provider = canonical;
264
+ pattern = cliModel.substring(slashIndex + 1);
265
+ }
266
+ }
267
+ }
268
+ else {
269
+ // If both were provided, tolerate --model <provider>/<pattern> by stripping the provider prefix
270
+ const prefix = `${provider}/`;
271
+ if (cliModel.toLowerCase().startsWith(prefix.toLowerCase())) {
272
+ pattern = cliModel.substring(prefix.length);
273
+ }
274
+ }
275
+ const candidates = provider ? availableModels.filter((m) => m.provider === provider) : availableModels;
276
+ const { model, thinkingLevel, warning } = parseModelPattern(pattern, candidates, {
277
+ allowInvalidThinkingLevelFallback: false,
278
+ });
279
+ if (!model) {
280
+ const display = provider ? `${provider}/${pattern}` : cliModel;
281
+ return {
282
+ model: undefined,
283
+ thinkingLevel: undefined,
284
+ warning,
285
+ error: `Model "${display}" not found. Use --list-models to see available models.`,
286
+ };
287
+ }
288
+ return { model, thinkingLevel, warning, error: undefined };
289
+ }
290
+ /**
291
+ * Find the initial model to use based on priority:
292
+ * 1. CLI args (provider + model)
293
+ * 2. First model from scoped models (if not continuing/resuming)
294
+ * 3. Restored from session (if continuing/resuming)
295
+ * 4. Saved default from settings
296
+ * 5. First available model with valid API key
297
+ */
298
+ export async function findInitialModel(options) {
299
+ const { cliProvider, cliModel, scopedModels, isContinuing, defaultProvider, defaultModelId, defaultThinkingLevel, modelRegistry, } = options;
300
+ let model;
301
+ let thinkingLevel = DEFAULT_THINKING_LEVEL;
302
+ // 1. CLI args take priority
303
+ if (cliProvider && cliModel) {
304
+ const found = modelRegistry.find(cliProvider, cliModel);
305
+ if (!found) {
306
+ console.error(chalk.red(`Model ${cliProvider}/${cliModel} not found`));
307
+ process.exit(1);
308
+ }
309
+ return { model: found, thinkingLevel: DEFAULT_THINKING_LEVEL, fallbackMessage: undefined };
310
+ }
311
+ // 2. Use first model from scoped models (skip if continuing/resuming)
312
+ if (scopedModels.length > 0 && !isContinuing) {
313
+ return {
314
+ model: scopedModels[0].model,
315
+ thinkingLevel: scopedModels[0].thinkingLevel ?? defaultThinkingLevel ?? DEFAULT_THINKING_LEVEL,
316
+ fallbackMessage: undefined,
317
+ };
318
+ }
319
+ // 3. Try saved default from settings
320
+ if (defaultProvider && defaultModelId) {
321
+ const found = modelRegistry.find(defaultProvider, defaultModelId);
322
+ if (found) {
323
+ model = found;
324
+ if (defaultThinkingLevel) {
325
+ thinkingLevel = defaultThinkingLevel;
326
+ }
327
+ return { model, thinkingLevel, fallbackMessage: undefined };
328
+ }
329
+ }
330
+ // 4. Try first available model with valid API key
331
+ const availableModels = await modelRegistry.getAvailable();
332
+ if (availableModels.length > 0) {
333
+ // Try to find a default model from known providers
334
+ for (const provider of Object.keys(defaultModelPerProvider)) {
335
+ const defaultId = defaultModelPerProvider[provider];
336
+ const match = availableModels.find((m) => m.provider === provider && m.id === defaultId);
337
+ if (match) {
338
+ return { model: match, thinkingLevel: DEFAULT_THINKING_LEVEL, fallbackMessage: undefined };
339
+ }
340
+ }
341
+ // If no default found, use first available
342
+ return { model: availableModels[0], thinkingLevel: DEFAULT_THINKING_LEVEL, fallbackMessage: undefined };
343
+ }
344
+ // 5. No model found
345
+ return { model: undefined, thinkingLevel: DEFAULT_THINKING_LEVEL, fallbackMessage: undefined };
346
+ }
347
+ /**
348
+ * Restore model from session, with fallback to available models
349
+ */
350
+ export async function restoreModelFromSession(savedProvider, savedModelId, currentModel, shouldPrintMessages, modelRegistry) {
351
+ const restoredModel = modelRegistry.find(savedProvider, savedModelId);
352
+ // Check if restored model exists and has a valid API key
353
+ const hasApiKey = restoredModel ? !!(await modelRegistry.getApiKey(restoredModel)) : false;
354
+ if (restoredModel && hasApiKey) {
355
+ if (shouldPrintMessages) {
356
+ console.log(chalk.dim(`Restored model: ${savedProvider}/${savedModelId}`));
357
+ }
358
+ return { model: restoredModel, fallbackMessage: undefined };
359
+ }
360
+ // Model not found or no API key - fall back
361
+ const reason = !restoredModel ? "model no longer exists" : "no API key available";
362
+ if (shouldPrintMessages) {
363
+ console.error(chalk.yellow(`Warning: Could not restore model ${savedProvider}/${savedModelId} (${reason}).`));
364
+ }
365
+ // If we already have a model, use it as fallback
366
+ if (currentModel) {
367
+ if (shouldPrintMessages) {
368
+ console.log(chalk.dim(`Falling back to: ${currentModel.provider}/${currentModel.id}`));
369
+ }
370
+ return {
371
+ model: currentModel,
372
+ fallbackMessage: `Could not restore model ${savedProvider}/${savedModelId} (${reason}). Using ${currentModel.provider}/${currentModel.id}.`,
373
+ };
374
+ }
375
+ // Try to find any available model
376
+ const availableModels = await modelRegistry.getAvailable();
377
+ if (availableModels.length > 0) {
378
+ // Try to find a default model from known providers
379
+ let fallbackModel;
380
+ for (const provider of Object.keys(defaultModelPerProvider)) {
381
+ const defaultId = defaultModelPerProvider[provider];
382
+ const match = availableModels.find((m) => m.provider === provider && m.id === defaultId);
383
+ if (match) {
384
+ fallbackModel = match;
385
+ break;
386
+ }
387
+ }
388
+ // If no default found, use first available
389
+ if (!fallbackModel) {
390
+ fallbackModel = availableModels[0];
391
+ }
392
+ if (shouldPrintMessages) {
393
+ console.log(chalk.dim(`Falling back to: ${fallbackModel.provider}/${fallbackModel.id}`));
394
+ }
395
+ return {
396
+ model: fallbackModel,
397
+ fallbackMessage: `Could not restore model ${savedProvider}/${savedModelId} (${reason}). Using ${fallbackModel.provider}/${fallbackModel.id}.`,
398
+ };
399
+ }
400
+ // No models available
401
+ return { model: undefined, fallbackMessage: undefined };
402
+ }
403
+ //# sourceMappingURL=model-resolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model-resolver.js","sourceRoot":"","sources":["../../src/core/model-resolver.ts"],"names":[],"mappings":"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","sourcesContent":["/**\r\n * Model resolution, scoping, and initial selection\r\n */\r\n\r\nimport type { ThinkingLevel } from \"@mariozechner/pi-agent-core\";\r\nimport { type Api, type KnownProvider, type Model, modelsAreEqual } from \"@mariozechner/pi-ai\";\r\nimport chalk from \"chalk\";\r\nimport { minimatch } from \"minimatch\";\r\nimport { isValidThinkingLevel } from \"../cli/args.js\";\r\nimport { DEFAULT_THINKING_LEVEL } from \"./defaults.js\";\r\nimport type { ModelRegistry } from \"./model-registry.js\";\r\n\r\n/** Default model IDs for each known provider */\r\nexport const defaultModelPerProvider: Record<KnownProvider, string> = {\r\n\t\"amazon-bedrock\": \"us.anthropic.claude-opus-4-6-v1\",\r\n\tanthropic: \"claude-opus-4-6\",\r\n\topenai: \"gpt-5.1-codex\",\r\n\t\"azure-openai-responses\": \"gpt-5.2\",\r\n\t\"openai-codex\": \"gpt-5.3-codex\",\r\n\tgoogle: \"gemini-2.5-pro\",\r\n\t\"google-gemini-cli\": \"gemini-2.5-pro\",\r\n\t\"google-antigravity\": \"gemini-3-pro-high\",\r\n\t\"google-vertex\": \"gemini-3-pro-preview\",\r\n\t\"github-copilot\": \"gpt-4o\",\r\n\topenrouter: \"openai/gpt-5.1-codex\",\r\n\t\"vercel-ai-gateway\": \"anthropic/claude-opus-4-6\",\r\n\txai: \"grok-4-fast-non-reasoning\",\r\n\tgroq: \"openai/gpt-oss-120b\",\r\n\tcerebras: \"zai-glm-4.6\",\r\n\tzai: \"glm-4.6\",\r\n\tmistral: \"devstral-medium-latest\",\r\n\tminimax: \"MiniMax-M2.1\",\r\n\t\"minimax-cn\": \"MiniMax-M2.1\",\r\n\thuggingface: \"moonshotai/Kimi-K2.5\",\r\n\topencode: \"claude-opus-4-6\",\r\n\t\"kimi-coding\": \"kimi-k2-thinking\",\r\n};\r\n\r\nexport interface ScopedModel {\r\n\tmodel: Model<Api>;\r\n\t/** Thinking level if explicitly specified in pattern (e.g., \"model:high\"), undefined otherwise */\r\n\tthinkingLevel?: ThinkingLevel;\r\n}\r\n\r\n/**\r\n * Helper to check if a model ID looks like an alias (no date suffix)\r\n * Dates are typically in format: -20241022 or -20250929\r\n */\r\nfunction isAlias(id: string): boolean {\r\n\t// Check if ID ends with -latest\r\n\tif (id.endsWith(\"-latest\")) return true;\r\n\r\n\t// Check if ID ends with a date pattern (-YYYYMMDD)\r\n\tconst datePattern = /-\\d{8}$/;\r\n\treturn !datePattern.test(id);\r\n}\r\n\r\n/**\r\n * Try to match a pattern to a model from the available models list.\r\n * Returns the matched model or undefined if no match found.\r\n */\r\nfunction tryMatchModel(modelPattern: string, availableModels: Model<Api>[]): Model<Api> | undefined {\r\n\t// Check for provider/modelId format (provider is everything before the first /)\r\n\tconst slashIndex = modelPattern.indexOf(\"/\");\r\n\tif (slashIndex !== -1) {\r\n\t\tconst provider = modelPattern.substring(0, slashIndex);\r\n\t\tconst modelId = modelPattern.substring(slashIndex + 1);\r\n\t\tconst providerMatch = availableModels.find(\r\n\t\t\t(m) => m.provider.toLowerCase() === provider.toLowerCase() && m.id.toLowerCase() === modelId.toLowerCase(),\r\n\t\t);\r\n\t\tif (providerMatch) {\r\n\t\t\treturn providerMatch;\r\n\t\t}\r\n\t\t// No exact provider/model match - fall through to other matching\r\n\t}\r\n\r\n\t// Check for exact ID match (case-insensitive)\r\n\tconst exactMatch = availableModels.find((m) => m.id.toLowerCase() === modelPattern.toLowerCase());\r\n\tif (exactMatch) {\r\n\t\treturn exactMatch;\r\n\t}\r\n\r\n\t// No exact match - fall back to partial matching\r\n\tconst matches = availableModels.filter(\r\n\t\t(m) =>\r\n\t\t\tm.id.toLowerCase().includes(modelPattern.toLowerCase()) ||\r\n\t\t\tm.name?.toLowerCase().includes(modelPattern.toLowerCase()),\r\n\t);\r\n\r\n\tif (matches.length === 0) {\r\n\t\treturn undefined;\r\n\t}\r\n\r\n\t// Separate into aliases and dated versions\r\n\tconst aliases = matches.filter((m) => isAlias(m.id));\r\n\tconst datedVersions = matches.filter((m) => !isAlias(m.id));\r\n\r\n\tif (aliases.length > 0) {\r\n\t\t// Prefer alias - if multiple aliases, pick the one that sorts highest\r\n\t\taliases.sort((a, b) => b.id.localeCompare(a.id));\r\n\t\treturn aliases[0];\r\n\t} else {\r\n\t\t// No alias found, pick latest dated version\r\n\t\tdatedVersions.sort((a, b) => b.id.localeCompare(a.id));\r\n\t\treturn datedVersions[0];\r\n\t}\r\n}\r\n\r\nexport interface ParsedModelResult {\r\n\tmodel: Model<Api> | undefined;\r\n\t/** Thinking level if explicitly specified in pattern, undefined otherwise */\r\n\tthinkingLevel?: ThinkingLevel;\r\n\twarning: string | undefined;\r\n}\r\n\r\n/**\r\n * Parse a pattern to extract model and thinking level.\r\n * Handles models with colons in their IDs (e.g., OpenRouter's :exacto suffix).\r\n *\r\n * Algorithm:\r\n * 1. Try to match full pattern as a model\r\n * 2. If found, return it with \"off\" thinking level\r\n * 3. If not found and has colons, split on last colon:\r\n * - If suffix is valid thinking level, use it and recurse on prefix\r\n * - If suffix is invalid, warn and recurse on prefix with \"off\"\r\n *\r\n * @internal Exported for testing\r\n */\r\nexport function parseModelPattern(\r\n\tpattern: string,\r\n\tavailableModels: Model<Api>[],\r\n\toptions?: { allowInvalidThinkingLevelFallback?: boolean },\r\n): ParsedModelResult {\r\n\t// Try exact match first\r\n\tconst exactMatch = tryMatchModel(pattern, availableModels);\r\n\tif (exactMatch) {\r\n\t\treturn { model: exactMatch, thinkingLevel: undefined, warning: undefined };\r\n\t}\r\n\r\n\t// No match - try splitting on last colon if present\r\n\tconst lastColonIndex = pattern.lastIndexOf(\":\");\r\n\tif (lastColonIndex === -1) {\r\n\t\t// No colons, pattern simply doesn't match any model\r\n\t\treturn { model: undefined, thinkingLevel: undefined, warning: undefined };\r\n\t}\r\n\r\n\tconst prefix = pattern.substring(0, lastColonIndex);\r\n\tconst suffix = pattern.substring(lastColonIndex + 1);\r\n\r\n\tif (isValidThinkingLevel(suffix)) {\r\n\t\t// Valid thinking level - recurse on prefix and use this level\r\n\t\tconst result = parseModelPattern(prefix, availableModels, options);\r\n\t\tif (result.model) {\r\n\t\t\t// Only use this thinking level if no warning from inner recursion\r\n\t\t\treturn {\r\n\t\t\t\tmodel: result.model,\r\n\t\t\t\tthinkingLevel: result.warning ? undefined : suffix,\r\n\t\t\t\twarning: result.warning,\r\n\t\t\t};\r\n\t\t}\r\n\t\treturn result;\r\n\t} else {\r\n\t\t// Invalid suffix\r\n\t\tconst allowFallback = options?.allowInvalidThinkingLevelFallback ?? true;\r\n\t\tif (!allowFallback) {\r\n\t\t\t// In strict mode (CLI --model parsing), treat it as part of the model id and fail.\r\n\t\t\t// This avoids accidentally resolving to a different model.\r\n\t\t\treturn { model: undefined, thinkingLevel: undefined, warning: undefined };\r\n\t\t}\r\n\r\n\t\t// Scope mode: recurse on prefix and warn\r\n\t\tconst result = parseModelPattern(prefix, availableModels, options);\r\n\t\tif (result.model) {\r\n\t\t\treturn {\r\n\t\t\t\tmodel: result.model,\r\n\t\t\t\tthinkingLevel: undefined,\r\n\t\t\t\twarning: `Invalid thinking level \"${suffix}\" in pattern \"${pattern}\". Using default instead.`,\r\n\t\t\t};\r\n\t\t}\r\n\t\treturn result;\r\n\t}\r\n}\r\n\r\n/**\r\n * Resolve model patterns to actual Model objects with optional thinking levels\r\n * Format: \"pattern:level\" where :level is optional\r\n * For each pattern, finds all matching models and picks the best version:\r\n * 1. Prefer alias (e.g., claude-sonnet-4-5) over dated versions (claude-sonnet-4-5-20250929)\r\n * 2. If no alias, pick the latest dated version\r\n *\r\n * Supports models with colons in their IDs (e.g., OpenRouter's model:exacto).\r\n * The algorithm tries to match the full pattern first, then progressively\r\n * strips colon-suffixes to find a match.\r\n */\r\nexport async function resolveModelScope(patterns: string[], modelRegistry: ModelRegistry): Promise<ScopedModel[]> {\r\n\tconst availableModels = await modelRegistry.getAvailable();\r\n\tconst scopedModels: ScopedModel[] = [];\r\n\r\n\tfor (const pattern of patterns) {\r\n\t\t// Check if pattern contains glob characters\r\n\t\tif (pattern.includes(\"*\") || pattern.includes(\"?\") || pattern.includes(\"[\")) {\r\n\t\t\t// Extract optional thinking level suffix (e.g., \"provider/*:high\")\r\n\t\t\tconst colonIdx = pattern.lastIndexOf(\":\");\r\n\t\t\tlet globPattern = pattern;\r\n\t\t\tlet thinkingLevel: ThinkingLevel | undefined;\r\n\r\n\t\t\tif (colonIdx !== -1) {\r\n\t\t\t\tconst suffix = pattern.substring(colonIdx + 1);\r\n\t\t\t\tif (isValidThinkingLevel(suffix)) {\r\n\t\t\t\t\tthinkingLevel = suffix;\r\n\t\t\t\t\tglobPattern = pattern.substring(0, colonIdx);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\t// Match against \"provider/modelId\" format OR just model ID\r\n\t\t\t// This allows \"*sonnet*\" to match without requiring \"anthropic/*sonnet*\"\r\n\t\t\tconst matchingModels = availableModels.filter((m) => {\r\n\t\t\t\tconst fullId = `${m.provider}/${m.id}`;\r\n\t\t\t\treturn minimatch(fullId, globPattern, { nocase: true }) || minimatch(m.id, globPattern, { nocase: true });\r\n\t\t\t});\r\n\r\n\t\t\tif (matchingModels.length === 0) {\r\n\t\t\t\tconsole.warn(chalk.yellow(`Warning: No models match pattern \"${pattern}\"`));\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\tfor (const model of matchingModels) {\r\n\t\t\t\tif (!scopedModels.find((sm) => modelsAreEqual(sm.model, model))) {\r\n\t\t\t\t\tscopedModels.push({ model, thinkingLevel });\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tcontinue;\r\n\t\t}\r\n\r\n\t\tconst { model, thinkingLevel, warning } = parseModelPattern(pattern, availableModels);\r\n\r\n\t\tif (warning) {\r\n\t\t\tconsole.warn(chalk.yellow(`Warning: ${warning}`));\r\n\t\t}\r\n\r\n\t\tif (!model) {\r\n\t\t\tconsole.warn(chalk.yellow(`Warning: No models match pattern \"${pattern}\"`));\r\n\t\t\tcontinue;\r\n\t\t}\r\n\r\n\t\t// Avoid duplicates\r\n\t\tif (!scopedModels.find((sm) => modelsAreEqual(sm.model, model))) {\r\n\t\t\tscopedModels.push({ model, thinkingLevel });\r\n\t\t}\r\n\t}\r\n\r\n\treturn scopedModels;\r\n}\r\n\r\nexport interface ResolveCliModelResult {\r\n\tmodel: Model<Api> | undefined;\r\n\tthinkingLevel?: ThinkingLevel;\r\n\twarning: string | undefined;\r\n\t/**\r\n\t * Error message suitable for CLI display.\r\n\t * When set, model will be undefined.\r\n\t */\r\n\terror: string | undefined;\r\n}\r\n\r\n/**\r\n * Resolve a single model from CLI flags.\r\n *\r\n * Supports:\r\n * - --provider <provider> --model <pattern>\r\n * - --model <provider>/<pattern>\r\n * - Fuzzy matching (same rules as model scoping: exact id, then partial id/name)\r\n *\r\n * Note: This does not apply the thinking level by itself, but it may *parse* and\r\n * return a thinking level from \"<pattern>:<thinking>\" so the caller can apply it.\r\n */\r\nexport function resolveCliModel(options: {\r\n\tcliProvider?: string;\r\n\tcliModel?: string;\r\n\tmodelRegistry: ModelRegistry;\r\n}): ResolveCliModelResult {\r\n\tconst { cliProvider, cliModel, modelRegistry } = options;\r\n\r\n\tif (!cliModel) {\r\n\t\treturn { model: undefined, warning: undefined, error: undefined };\r\n\t}\r\n\r\n\t// Important: use *all* models here, not just models with pre-configured auth.\r\n\t// This allows \"--api-key\" to be used for first-time setup.\r\n\tconst availableModels = modelRegistry.getAll();\r\n\tif (availableModels.length === 0) {\r\n\t\treturn {\r\n\t\t\tmodel: undefined,\r\n\t\t\twarning: undefined,\r\n\t\t\terror: \"No models available. Check your installation or add models to models.json.\",\r\n\t\t};\r\n\t}\r\n\r\n\t// Build canonical provider lookup (case-insensitive)\r\n\tconst providerMap = new Map<string, string>();\r\n\tfor (const m of availableModels) {\r\n\t\tproviderMap.set(m.provider.toLowerCase(), m.provider);\r\n\t}\r\n\r\n\tlet provider = cliProvider ? providerMap.get(cliProvider.toLowerCase()) : undefined;\r\n\tif (cliProvider && !provider) {\r\n\t\treturn {\r\n\t\t\tmodel: undefined,\r\n\t\t\twarning: undefined,\r\n\t\t\terror: `Unknown provider \"${cliProvider}\". Use --list-models to see available providers/models.`,\r\n\t\t};\r\n\t}\r\n\r\n\t// If no explicit --provider, first try exact matches without any provider inference.\r\n\t// This avoids misinterpreting model IDs that themselves contain slashes (e.g. OpenRouter-style IDs).\r\n\tif (!provider) {\r\n\t\tconst lower = cliModel.toLowerCase();\r\n\t\tconst exact = availableModels.find(\r\n\t\t\t(m) => m.id.toLowerCase() === lower || `${m.provider}/${m.id}`.toLowerCase() === lower,\r\n\t\t);\r\n\t\tif (exact) {\r\n\t\t\treturn { model: exact, warning: undefined, thinkingLevel: undefined, error: undefined };\r\n\t\t}\r\n\t}\r\n\r\n\tlet pattern = cliModel;\r\n\r\n\t// If no explicit --provider, allow --model provider/<pattern>\r\n\tif (!provider) {\r\n\t\tconst slashIndex = cliModel.indexOf(\"/\");\r\n\t\tif (slashIndex !== -1) {\r\n\t\t\tconst maybeProvider = cliModel.substring(0, slashIndex);\r\n\t\t\tconst canonical = providerMap.get(maybeProvider.toLowerCase());\r\n\t\t\tif (canonical) {\r\n\t\t\t\tprovider = canonical;\r\n\t\t\t\tpattern = cliModel.substring(slashIndex + 1);\r\n\t\t\t}\r\n\t\t}\r\n\t} else {\r\n\t\t// If both were provided, tolerate --model <provider>/<pattern> by stripping the provider prefix\r\n\t\tconst prefix = `${provider}/`;\r\n\t\tif (cliModel.toLowerCase().startsWith(prefix.toLowerCase())) {\r\n\t\t\tpattern = cliModel.substring(prefix.length);\r\n\t\t}\r\n\t}\r\n\r\n\tconst candidates = provider ? availableModels.filter((m) => m.provider === provider) : availableModels;\r\n\tconst { model, thinkingLevel, warning } = parseModelPattern(pattern, candidates, {\r\n\t\tallowInvalidThinkingLevelFallback: false,\r\n\t});\r\n\r\n\tif (!model) {\r\n\t\tconst display = provider ? `${provider}/${pattern}` : cliModel;\r\n\t\treturn {\r\n\t\t\tmodel: undefined,\r\n\t\t\tthinkingLevel: undefined,\r\n\t\t\twarning,\r\n\t\t\terror: `Model \"${display}\" not found. Use --list-models to see available models.`,\r\n\t\t};\r\n\t}\r\n\r\n\treturn { model, thinkingLevel, warning, error: undefined };\r\n}\r\n\r\nexport interface InitialModelResult {\r\n\tmodel: Model<Api> | undefined;\r\n\tthinkingLevel: ThinkingLevel;\r\n\tfallbackMessage: string | undefined;\r\n}\r\n\r\n/**\r\n * Find the initial model to use based on priority:\r\n * 1. CLI args (provider + model)\r\n * 2. First model from scoped models (if not continuing/resuming)\r\n * 3. Restored from session (if continuing/resuming)\r\n * 4. Saved default from settings\r\n * 5. First available model with valid API key\r\n */\r\nexport async function findInitialModel(options: {\r\n\tcliProvider?: string;\r\n\tcliModel?: string;\r\n\tscopedModels: ScopedModel[];\r\n\tisContinuing: boolean;\r\n\tdefaultProvider?: string;\r\n\tdefaultModelId?: string;\r\n\tdefaultThinkingLevel?: ThinkingLevel;\r\n\tmodelRegistry: ModelRegistry;\r\n}): Promise<InitialModelResult> {\r\n\tconst {\r\n\t\tcliProvider,\r\n\t\tcliModel,\r\n\t\tscopedModels,\r\n\t\tisContinuing,\r\n\t\tdefaultProvider,\r\n\t\tdefaultModelId,\r\n\t\tdefaultThinkingLevel,\r\n\t\tmodelRegistry,\r\n\t} = options;\r\n\r\n\tlet model: Model<Api> | undefined;\r\n\tlet thinkingLevel: ThinkingLevel = DEFAULT_THINKING_LEVEL;\r\n\r\n\t// 1. CLI args take priority\r\n\tif (cliProvider && cliModel) {\r\n\t\tconst found = modelRegistry.find(cliProvider, cliModel);\r\n\t\tif (!found) {\r\n\t\t\tconsole.error(chalk.red(`Model ${cliProvider}/${cliModel} not found`));\r\n\t\t\tprocess.exit(1);\r\n\t\t}\r\n\t\treturn { model: found, thinkingLevel: DEFAULT_THINKING_LEVEL, fallbackMessage: undefined };\r\n\t}\r\n\r\n\t// 2. Use first model from scoped models (skip if continuing/resuming)\r\n\tif (scopedModels.length > 0 && !isContinuing) {\r\n\t\treturn {\r\n\t\t\tmodel: scopedModels[0].model,\r\n\t\t\tthinkingLevel: scopedModels[0].thinkingLevel ?? defaultThinkingLevel ?? DEFAULT_THINKING_LEVEL,\r\n\t\t\tfallbackMessage: undefined,\r\n\t\t};\r\n\t}\r\n\r\n\t// 3. Try saved default from settings\r\n\tif (defaultProvider && defaultModelId) {\r\n\t\tconst found = modelRegistry.find(defaultProvider, defaultModelId);\r\n\t\tif (found) {\r\n\t\t\tmodel = found;\r\n\t\t\tif (defaultThinkingLevel) {\r\n\t\t\t\tthinkingLevel = defaultThinkingLevel;\r\n\t\t\t}\r\n\t\t\treturn { model, thinkingLevel, fallbackMessage: undefined };\r\n\t\t}\r\n\t}\r\n\r\n\t// 4. Try first available model with valid API key\r\n\tconst availableModels = await modelRegistry.getAvailable();\r\n\r\n\tif (availableModels.length > 0) {\r\n\t\t// Try to find a default model from known providers\r\n\t\tfor (const provider of Object.keys(defaultModelPerProvider) as KnownProvider[]) {\r\n\t\t\tconst defaultId = defaultModelPerProvider[provider];\r\n\t\t\tconst match = availableModels.find((m) => m.provider === provider && m.id === defaultId);\r\n\t\t\tif (match) {\r\n\t\t\t\treturn { model: match, thinkingLevel: DEFAULT_THINKING_LEVEL, fallbackMessage: undefined };\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// If no default found, use first available\r\n\t\treturn { model: availableModels[0], thinkingLevel: DEFAULT_THINKING_LEVEL, fallbackMessage: undefined };\r\n\t}\r\n\r\n\t// 5. No model found\r\n\treturn { model: undefined, thinkingLevel: DEFAULT_THINKING_LEVEL, fallbackMessage: undefined };\r\n}\r\n\r\n/**\r\n * Restore model from session, with fallback to available models\r\n */\r\nexport async function restoreModelFromSession(\r\n\tsavedProvider: string,\r\n\tsavedModelId: string,\r\n\tcurrentModel: Model<Api> | undefined,\r\n\tshouldPrintMessages: boolean,\r\n\tmodelRegistry: ModelRegistry,\r\n): Promise<{ model: Model<Api> | undefined; fallbackMessage: string | undefined }> {\r\n\tconst restoredModel = modelRegistry.find(savedProvider, savedModelId);\r\n\r\n\t// Check if restored model exists and has a valid API key\r\n\tconst hasApiKey = restoredModel ? !!(await modelRegistry.getApiKey(restoredModel)) : false;\r\n\r\n\tif (restoredModel && hasApiKey) {\r\n\t\tif (shouldPrintMessages) {\r\n\t\t\tconsole.log(chalk.dim(`Restored model: ${savedProvider}/${savedModelId}`));\r\n\t\t}\r\n\t\treturn { model: restoredModel, fallbackMessage: undefined };\r\n\t}\r\n\r\n\t// Model not found or no API key - fall back\r\n\tconst reason = !restoredModel ? \"model no longer exists\" : \"no API key available\";\r\n\r\n\tif (shouldPrintMessages) {\r\n\t\tconsole.error(chalk.yellow(`Warning: Could not restore model ${savedProvider}/${savedModelId} (${reason}).`));\r\n\t}\r\n\r\n\t// If we already have a model, use it as fallback\r\n\tif (currentModel) {\r\n\t\tif (shouldPrintMessages) {\r\n\t\t\tconsole.log(chalk.dim(`Falling back to: ${currentModel.provider}/${currentModel.id}`));\r\n\t\t}\r\n\t\treturn {\r\n\t\t\tmodel: currentModel,\r\n\t\t\tfallbackMessage: `Could not restore model ${savedProvider}/${savedModelId} (${reason}). Using ${currentModel.provider}/${currentModel.id}.`,\r\n\t\t};\r\n\t}\r\n\r\n\t// Try to find any available model\r\n\tconst availableModels = await modelRegistry.getAvailable();\r\n\r\n\tif (availableModels.length > 0) {\r\n\t\t// Try to find a default model from known providers\r\n\t\tlet fallbackModel: Model<Api> | undefined;\r\n\t\tfor (const provider of Object.keys(defaultModelPerProvider) as KnownProvider[]) {\r\n\t\t\tconst defaultId = defaultModelPerProvider[provider];\r\n\t\t\tconst match = availableModels.find((m) => m.provider === provider && m.id === defaultId);\r\n\t\t\tif (match) {\r\n\t\t\t\tfallbackModel = match;\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// If no default found, use first available\r\n\t\tif (!fallbackModel) {\r\n\t\t\tfallbackModel = availableModels[0];\r\n\t\t}\r\n\r\n\t\tif (shouldPrintMessages) {\r\n\t\t\tconsole.log(chalk.dim(`Falling back to: ${fallbackModel.provider}/${fallbackModel.id}`));\r\n\t\t}\r\n\r\n\t\treturn {\r\n\t\t\tmodel: fallbackModel,\r\n\t\t\tfallbackMessage: `Could not restore model ${savedProvider}/${savedModelId} (${reason}). Using ${fallbackModel.provider}/${fallbackModel.id}.`,\r\n\t\t};\r\n\t}\r\n\r\n\t// No models available\r\n\treturn { model: undefined, fallbackMessage: undefined };\r\n}\r\n"]}