@steipete/summarize 0.10.0 → 0.11.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 (374) hide show
  1. package/CHANGELOG.md +80 -28
  2. package/README.md +115 -30
  3. package/dist/cli.js +1 -1
  4. package/dist/esm/cache.js +67 -65
  5. package/dist/esm/cache.js.map +1 -1
  6. package/dist/esm/cli-main.js +27 -27
  7. package/dist/esm/cli-main.js.map +1 -1
  8. package/dist/esm/cli.js +2 -2
  9. package/dist/esm/cli.js.map +1 -1
  10. package/dist/esm/config.js +310 -166
  11. package/dist/esm/config.js.map +1 -1
  12. package/dist/esm/content/asset.js +53 -50
  13. package/dist/esm/content/asset.js.map +1 -1
  14. package/dist/esm/content/index.js +1 -1
  15. package/dist/esm/content/index.js.map +1 -1
  16. package/dist/esm/costs.js +1 -1
  17. package/dist/esm/costs.js.map +1 -1
  18. package/dist/esm/daemon/agent.js +165 -164
  19. package/dist/esm/daemon/agent.js.map +1 -1
  20. package/dist/esm/daemon/auto-mode.js +3 -3
  21. package/dist/esm/daemon/auto-mode.js.map +1 -1
  22. package/dist/esm/daemon/chat.js +16 -14
  23. package/dist/esm/daemon/chat.js.map +1 -1
  24. package/dist/esm/daemon/cli-entrypoint.js +72 -0
  25. package/dist/esm/daemon/cli-entrypoint.js.map +1 -0
  26. package/dist/esm/daemon/cli.js +63 -87
  27. package/dist/esm/daemon/cli.js.map +1 -1
  28. package/dist/esm/daemon/config.js +15 -15
  29. package/dist/esm/daemon/config.js.map +1 -1
  30. package/dist/esm/daemon/constants.js +6 -6
  31. package/dist/esm/daemon/constants.js.map +1 -1
  32. package/dist/esm/daemon/env-merge.js.map +1 -1
  33. package/dist/esm/daemon/env-snapshot.js +36 -31
  34. package/dist/esm/daemon/env-snapshot.js.map +1 -1
  35. package/dist/esm/daemon/flow-context.js +59 -28
  36. package/dist/esm/daemon/flow-context.js.map +1 -1
  37. package/dist/esm/daemon/launchd.js +100 -55
  38. package/dist/esm/daemon/launchd.js.map +1 -1
  39. package/dist/esm/daemon/meta.js +5 -5
  40. package/dist/esm/daemon/meta.js.map +1 -1
  41. package/dist/esm/daemon/models.js +54 -31
  42. package/dist/esm/daemon/models.js.map +1 -1
  43. package/dist/esm/daemon/process-registry.js +15 -15
  44. package/dist/esm/daemon/process-registry.js.map +1 -1
  45. package/dist/esm/daemon/schtasks.js +42 -42
  46. package/dist/esm/daemon/schtasks.js.map +1 -1
  47. package/dist/esm/daemon/server.js +248 -244
  48. package/dist/esm/daemon/server.js.map +1 -1
  49. package/dist/esm/daemon/summarize-progress.js +11 -11
  50. package/dist/esm/daemon/summarize-progress.js.map +1 -1
  51. package/dist/esm/daemon/summarize.js +29 -29
  52. package/dist/esm/daemon/summarize.js.map +1 -1
  53. package/dist/esm/daemon/systemd.js +47 -47
  54. package/dist/esm/daemon/systemd.js.map +1 -1
  55. package/dist/esm/firecrawl.js +12 -12
  56. package/dist/esm/firecrawl.js.map +1 -1
  57. package/dist/esm/flags.js +32 -32
  58. package/dist/esm/flags.js.map +1 -1
  59. package/dist/esm/index.js +3 -3
  60. package/dist/esm/index.js.map +1 -1
  61. package/dist/esm/language.js +1 -1
  62. package/dist/esm/language.js.map +1 -1
  63. package/dist/esm/llm/cli.js +128 -64
  64. package/dist/esm/llm/cli.js.map +1 -1
  65. package/dist/esm/llm/errors.js +1 -1
  66. package/dist/esm/llm/errors.js.map +1 -1
  67. package/dist/esm/llm/generate-text.js +107 -98
  68. package/dist/esm/llm/generate-text.js.map +1 -1
  69. package/dist/esm/llm/google-models.js +17 -17
  70. package/dist/esm/llm/google-models.js.map +1 -1
  71. package/dist/esm/llm/html-to-markdown.js +3 -3
  72. package/dist/esm/llm/html-to-markdown.js.map +1 -1
  73. package/dist/esm/llm/model-id.js +38 -16
  74. package/dist/esm/llm/model-id.js.map +1 -1
  75. package/dist/esm/llm/prompt.js +5 -5
  76. package/dist/esm/llm/prompt.js.map +1 -1
  77. package/dist/esm/llm/providers/anthropic.js +33 -33
  78. package/dist/esm/llm/providers/anthropic.js.map +1 -1
  79. package/dist/esm/llm/providers/google.js +19 -19
  80. package/dist/esm/llm/providers/google.js.map +1 -1
  81. package/dist/esm/llm/providers/models.js +30 -30
  82. package/dist/esm/llm/providers/models.js.map +1 -1
  83. package/dist/esm/llm/providers/openai.js +35 -34
  84. package/dist/esm/llm/providers/openai.js.map +1 -1
  85. package/dist/esm/llm/providers/shared.js +8 -8
  86. package/dist/esm/llm/providers/shared.js.map +1 -1
  87. package/dist/esm/llm/transcript-to-markdown.js +9 -5
  88. package/dist/esm/llm/transcript-to-markdown.js.map +1 -1
  89. package/dist/esm/llm/usage.js +18 -18
  90. package/dist/esm/llm/usage.js.map +1 -1
  91. package/dist/esm/logging/daemon.js +21 -21
  92. package/dist/esm/logging/daemon.js.map +1 -1
  93. package/dist/esm/logging/ring-file.js +5 -5
  94. package/dist/esm/logging/ring-file.js.map +1 -1
  95. package/dist/esm/markitdown.js +21 -19
  96. package/dist/esm/markitdown.js.map +1 -1
  97. package/dist/esm/media-cache.js +39 -39
  98. package/dist/esm/media-cache.js.map +1 -1
  99. package/dist/esm/model-auto.js +175 -106
  100. package/dist/esm/model-auto.js.map +1 -1
  101. package/dist/esm/model-spec.js +52 -42
  102. package/dist/esm/model-spec.js.map +1 -1
  103. package/dist/esm/pricing/litellm.js +4 -4
  104. package/dist/esm/pricing/litellm.js.map +1 -1
  105. package/dist/esm/processes.js +1 -1
  106. package/dist/esm/processes.js.map +1 -1
  107. package/dist/esm/prompts/index.js +1 -1
  108. package/dist/esm/prompts/index.js.map +1 -1
  109. package/dist/esm/refresh-free.js +81 -81
  110. package/dist/esm/refresh-free.js.map +1 -1
  111. package/dist/esm/run/attachments.js +47 -44
  112. package/dist/esm/run/attachments.js.map +1 -1
  113. package/dist/esm/run/bird.js +26 -26
  114. package/dist/esm/run/bird.js.map +1 -1
  115. package/dist/esm/run/cache-state.js +7 -7
  116. package/dist/esm/run/cache-state.js.map +1 -1
  117. package/dist/esm/run/cli-fallback-state.js +45 -0
  118. package/dist/esm/run/cli-fallback-state.js.map +1 -0
  119. package/dist/esm/run/cli-preflight.js +24 -24
  120. package/dist/esm/run/cli-preflight.js.map +1 -1
  121. package/dist/esm/run/constants.js +12 -12
  122. package/dist/esm/run/constants.js.map +1 -1
  123. package/dist/esm/run/cookies/twitter.js +47 -47
  124. package/dist/esm/run/cookies/twitter.js.map +1 -1
  125. package/dist/esm/run/env.js +21 -15
  126. package/dist/esm/run/env.js.map +1 -1
  127. package/dist/esm/run/fetch-with-timeout.js +4 -4
  128. package/dist/esm/run/fetch-with-timeout.js.map +1 -1
  129. package/dist/esm/run/finish-line.js +68 -68
  130. package/dist/esm/run/finish-line.js.map +1 -1
  131. package/dist/esm/run/flows/asset/extract.js +15 -15
  132. package/dist/esm/run/flows/asset/extract.js.map +1 -1
  133. package/dist/esm/run/flows/asset/input.js +47 -66
  134. package/dist/esm/run/flows/asset/input.js.map +1 -1
  135. package/dist/esm/run/flows/asset/media-policy.js +1 -1
  136. package/dist/esm/run/flows/asset/media-policy.js.map +1 -1
  137. package/dist/esm/run/flows/asset/media.js +49 -40
  138. package/dist/esm/run/flows/asset/media.js.map +1 -1
  139. package/dist/esm/run/flows/asset/output.js +12 -12
  140. package/dist/esm/run/flows/asset/output.js.map +1 -1
  141. package/dist/esm/run/flows/asset/preprocess.js +79 -44
  142. package/dist/esm/run/flows/asset/preprocess.js.map +1 -1
  143. package/dist/esm/run/flows/asset/summary.js +173 -106
  144. package/dist/esm/run/flows/asset/summary.js.map +1 -1
  145. package/dist/esm/run/flows/url/extract.js +26 -26
  146. package/dist/esm/run/flows/url/extract.js.map +1 -1
  147. package/dist/esm/run/flows/url/flow.js +104 -98
  148. package/dist/esm/run/flows/url/flow.js.map +1 -1
  149. package/dist/esm/run/flows/url/markdown.js +57 -57
  150. package/dist/esm/run/flows/url/markdown.js.map +1 -1
  151. package/dist/esm/run/flows/url/slides-output.js +61 -59
  152. package/dist/esm/run/flows/url/slides-output.js.map +1 -1
  153. package/dist/esm/run/flows/url/slides-text.js +85 -85
  154. package/dist/esm/run/flows/url/slides-text.js.map +1 -1
  155. package/dist/esm/run/flows/url/summary.js +174 -107
  156. package/dist/esm/run/flows/url/summary.js.map +1 -1
  157. package/dist/esm/run/format.js +10 -10
  158. package/dist/esm/run/format.js.map +1 -1
  159. package/dist/esm/run/help.js +141 -135
  160. package/dist/esm/run/help.js.map +1 -1
  161. package/dist/esm/run/logging.js +10 -10
  162. package/dist/esm/run/logging.js.map +1 -1
  163. package/dist/esm/run/markdown.js +12 -12
  164. package/dist/esm/run/markdown.js.map +1 -1
  165. package/dist/esm/run/media-cache-state.js +5 -5
  166. package/dist/esm/run/media-cache-state.js.map +1 -1
  167. package/dist/esm/run/model-attempts.js.map +1 -1
  168. package/dist/esm/run/openrouter.js +11 -11
  169. package/dist/esm/run/openrouter.js.map +1 -1
  170. package/dist/esm/run/progress.js +1 -1
  171. package/dist/esm/run/progress.js.map +1 -1
  172. package/dist/esm/run/run-config.js +16 -16
  173. package/dist/esm/run/run-config.js.map +1 -1
  174. package/dist/esm/run/run-context.js +2 -2
  175. package/dist/esm/run/run-context.js.map +1 -1
  176. package/dist/esm/run/run-env.js +55 -54
  177. package/dist/esm/run/run-env.js.map +1 -1
  178. package/dist/esm/run/run-input.js +3 -3
  179. package/dist/esm/run/run-input.js.map +1 -1
  180. package/dist/esm/run/run-metrics.js +16 -16
  181. package/dist/esm/run/run-metrics.js.map +1 -1
  182. package/dist/esm/run/run-models.js +28 -23
  183. package/dist/esm/run/run-models.js.map +1 -1
  184. package/dist/esm/run/run-output.js +3 -3
  185. package/dist/esm/run/run-output.js.map +1 -1
  186. package/dist/esm/run/run-settings.js +83 -34
  187. package/dist/esm/run/run-settings.js.map +1 -1
  188. package/dist/esm/run/run-stream.js +4 -4
  189. package/dist/esm/run/run-stream.js.map +1 -1
  190. package/dist/esm/run/runner.js +166 -127
  191. package/dist/esm/run/runner.js.map +1 -1
  192. package/dist/esm/run/slides-cli.js +43 -42
  193. package/dist/esm/run/slides-cli.js.map +1 -1
  194. package/dist/esm/run/slides-render.js +36 -36
  195. package/dist/esm/run/slides-render.js.map +1 -1
  196. package/dist/esm/run/stdin-temp-file.js +77 -0
  197. package/dist/esm/run/stdin-temp-file.js.map +1 -0
  198. package/dist/esm/run/stream-output.js +7 -7
  199. package/dist/esm/run/stream-output.js.map +1 -1
  200. package/dist/esm/run/streaming.js +16 -16
  201. package/dist/esm/run/streaming.js.map +1 -1
  202. package/dist/esm/run/summary-engine.js +57 -51
  203. package/dist/esm/run/summary-engine.js.map +1 -1
  204. package/dist/esm/run/summary-llm.js +3 -3
  205. package/dist/esm/run/summary-llm.js.map +1 -1
  206. package/dist/esm/run/terminal.js +4 -4
  207. package/dist/esm/run/terminal.js.map +1 -1
  208. package/dist/esm/run/tips.js +2 -2
  209. package/dist/esm/run/tips.js.map +1 -1
  210. package/dist/esm/run/transcriber-cli.js +49 -49
  211. package/dist/esm/run/transcriber-cli.js.map +1 -1
  212. package/dist/esm/run.js +1 -1
  213. package/dist/esm/run.js.map +1 -1
  214. package/dist/esm/shared/contracts.js +1 -1
  215. package/dist/esm/shared/contracts.js.map +1 -1
  216. package/dist/esm/shared/sse-events.js +16 -16
  217. package/dist/esm/shared/sse-events.js.map +1 -1
  218. package/dist/esm/shared/streaming-merge.js +3 -3
  219. package/dist/esm/shared/streaming-merge.js.map +1 -1
  220. package/dist/esm/slides/extract.js +258 -249
  221. package/dist/esm/slides/extract.js.map +1 -1
  222. package/dist/esm/slides/index.js +3 -3
  223. package/dist/esm/slides/index.js.map +1 -1
  224. package/dist/esm/slides/settings.js +14 -14
  225. package/dist/esm/slides/settings.js.map +1 -1
  226. package/dist/esm/slides/store.js +9 -9
  227. package/dist/esm/slides/store.js.map +1 -1
  228. package/dist/esm/tty/format.js +13 -13
  229. package/dist/esm/tty/format.js.map +1 -1
  230. package/dist/esm/tty/osc-progress.js +1 -1
  231. package/dist/esm/tty/osc-progress.js.map +1 -1
  232. package/dist/esm/tty/progress/fetch-html.js +14 -14
  233. package/dist/esm/tty/progress/fetch-html.js.map +1 -1
  234. package/dist/esm/tty/progress/transcript.js +70 -62
  235. package/dist/esm/tty/progress/transcript.js.map +1 -1
  236. package/dist/esm/tty/spinner.js +20 -9
  237. package/dist/esm/tty/spinner.js.map +1 -1
  238. package/dist/esm/tty/theme.js +92 -92
  239. package/dist/esm/tty/theme.js.map +1 -1
  240. package/dist/esm/tty/website-progress.js +32 -32
  241. package/dist/esm/tty/website-progress.js.map +1 -1
  242. package/dist/esm/version.js +29 -29
  243. package/dist/esm/version.js.map +1 -1
  244. package/dist/types/cache.d.ts +6 -6
  245. package/dist/types/config.d.ts +49 -7
  246. package/dist/types/content/asset.d.ts +8 -6
  247. package/dist/types/content/index.d.ts +1 -1
  248. package/dist/types/costs.d.ts +3 -3
  249. package/dist/types/daemon/agent.d.ts +1 -1
  250. package/dist/types/daemon/auto-mode.d.ts +3 -3
  251. package/dist/types/daemon/chat.d.ts +2 -2
  252. package/dist/types/daemon/cli-entrypoint.d.ts +2 -0
  253. package/dist/types/daemon/config.d.ts +2 -2
  254. package/dist/types/daemon/env-merge.d.ts +1 -1
  255. package/dist/types/daemon/env-snapshot.d.ts +1 -1
  256. package/dist/types/daemon/flow-context.d.ts +7 -7
  257. package/dist/types/daemon/launchd.d.ts +8 -0
  258. package/dist/types/daemon/models.d.ts +6 -2
  259. package/dist/types/daemon/process-registry.d.ts +5 -5
  260. package/dist/types/daemon/server.d.ts +2 -2
  261. package/dist/types/daemon/summarize-progress.d.ts +1 -1
  262. package/dist/types/daemon/summarize.d.ts +7 -7
  263. package/dist/types/firecrawl.d.ts +1 -1
  264. package/dist/types/flags.d.ts +11 -11
  265. package/dist/types/index.d.ts +4 -4
  266. package/dist/types/language.d.ts +1 -1
  267. package/dist/types/llm/attachments.d.ts +1 -1
  268. package/dist/types/llm/cli.d.ts +3 -3
  269. package/dist/types/llm/generate-text.d.ts +7 -7
  270. package/dist/types/llm/html-to-markdown.d.ts +3 -3
  271. package/dist/types/llm/model-id.d.ts +1 -1
  272. package/dist/types/llm/prompt.d.ts +2 -2
  273. package/dist/types/llm/providers/anthropic.d.ts +3 -3
  274. package/dist/types/llm/providers/google.d.ts +3 -3
  275. package/dist/types/llm/providers/models.d.ts +2 -2
  276. package/dist/types/llm/providers/openai.d.ts +4 -4
  277. package/dist/types/llm/providers/shared.d.ts +2 -2
  278. package/dist/types/llm/transcript-to-markdown.d.ts +4 -2
  279. package/dist/types/llm/usage.d.ts +1 -1
  280. package/dist/types/logging/daemon.d.ts +4 -4
  281. package/dist/types/markitdown.d.ts +1 -1
  282. package/dist/types/media-cache.d.ts +2 -2
  283. package/dist/types/model-auto.d.ts +14 -4
  284. package/dist/types/model-spec.d.ts +10 -10
  285. package/dist/types/pricing/litellm.d.ts +1 -1
  286. package/dist/types/processes.d.ts +1 -1
  287. package/dist/types/prompts/index.d.ts +1 -1
  288. package/dist/types/run/attachments.d.ts +7 -7
  289. package/dist/types/run/bird.d.ts +2 -2
  290. package/dist/types/run/cache-state.d.ts +2 -2
  291. package/dist/types/run/cli-fallback-state.d.ts +6 -0
  292. package/dist/types/run/constants.d.ts +1 -1
  293. package/dist/types/run/cookies/twitter.d.ts +1 -1
  294. package/dist/types/run/env.d.ts +1 -1
  295. package/dist/types/run/finish-line.d.ts +5 -5
  296. package/dist/types/run/flows/asset/extract.d.ts +4 -4
  297. package/dist/types/run/flows/asset/input.d.ts +9 -3
  298. package/dist/types/run/flows/asset/media.d.ts +1 -1
  299. package/dist/types/run/flows/asset/output.d.ts +5 -5
  300. package/dist/types/run/flows/asset/preprocess.d.ts +23 -17
  301. package/dist/types/run/flows/asset/summary.d.ts +19 -17
  302. package/dist/types/run/flows/url/extract.d.ts +1 -1
  303. package/dist/types/run/flows/url/flow.d.ts +1 -1
  304. package/dist/types/run/flows/url/markdown.d.ts +6 -6
  305. package/dist/types/run/flows/url/slides-output.d.ts +7 -7
  306. package/dist/types/run/flows/url/slides-text.d.ts +9 -9
  307. package/dist/types/run/flows/url/summary.d.ts +11 -11
  308. package/dist/types/run/flows/url/types.d.ts +26 -22
  309. package/dist/types/run/format.d.ts +3 -3
  310. package/dist/types/run/help.d.ts +1 -1
  311. package/dist/types/run/media-cache-state.d.ts +2 -2
  312. package/dist/types/run/model-attempts.d.ts +1 -1
  313. package/dist/types/run/run-config.d.ts +4 -4
  314. package/dist/types/run/run-context.d.ts +3 -1
  315. package/dist/types/run/run-env.d.ts +3 -1
  316. package/dist/types/run/run-input.d.ts +2 -2
  317. package/dist/types/run/run-metrics.d.ts +3 -3
  318. package/dist/types/run/run-models.d.ts +3 -2
  319. package/dist/types/run/run-output.d.ts +1 -1
  320. package/dist/types/run/run-settings.d.ts +15 -6
  321. package/dist/types/run/run-stream.d.ts +2 -2
  322. package/dist/types/run/runner.d.ts +3 -2
  323. package/dist/types/run/slides-render.d.ts +4 -4
  324. package/dist/types/run/stdin-temp-file.d.ts +9 -0
  325. package/dist/types/run/stream-output.d.ts +1 -1
  326. package/dist/types/run/streaming.d.ts +4 -4
  327. package/dist/types/run/summary-engine.d.ts +11 -11
  328. package/dist/types/run/summary-llm.d.ts +5 -5
  329. package/dist/types/run/types.d.ts +4 -4
  330. package/dist/types/run.d.ts +1 -1
  331. package/dist/types/shared/contracts.d.ts +2 -2
  332. package/dist/types/shared/sse-events.d.ts +9 -9
  333. package/dist/types/slides/extract.d.ts +5 -4
  334. package/dist/types/slides/index.d.ts +5 -5
  335. package/dist/types/slides/store.d.ts +2 -2
  336. package/dist/types/slides/types.d.ts +2 -2
  337. package/dist/types/tty/osc-progress.d.ts +5 -5
  338. package/dist/types/tty/progress/fetch-html.d.ts +3 -3
  339. package/dist/types/tty/progress/transcript.d.ts +3 -3
  340. package/dist/types/tty/spinner.d.ts +2 -2
  341. package/dist/types/tty/theme.d.ts +2 -2
  342. package/dist/types/tty/website-progress.d.ts +3 -3
  343. package/dist/types/version.d.ts +1 -1
  344. package/docs/agent.md +38 -4
  345. package/docs/assets/site.js +46 -46
  346. package/docs/chrome-extension.md +11 -5
  347. package/docs/cli.md +59 -13
  348. package/docs/config.md +59 -10
  349. package/docs/extract-only.md +2 -0
  350. package/docs/index.html +33 -14
  351. package/docs/llm.md +7 -4
  352. package/docs/media.md +5 -4
  353. package/docs/model-auto.md +3 -2
  354. package/docs/nvidia-onnx-transcription.md +3 -3
  355. package/docs/openai.md +1 -1
  356. package/docs/releasing.md +3 -0
  357. package/docs/site/404.html +4 -1
  358. package/docs/site/assets/site.js +46 -46
  359. package/docs/site/docs/chrome-extension.html +18 -6
  360. package/docs/site/docs/config.html +29 -8
  361. package/docs/site/docs/extract-only.html +16 -4
  362. package/docs/site/docs/firecrawl.html +12 -3
  363. package/docs/site/docs/index.html +35 -6
  364. package/docs/site/docs/llm.html +19 -5
  365. package/docs/site/docs/openai.html +18 -5
  366. package/docs/site/docs/website.html +29 -9
  367. package/docs/site/docs/youtube.html +12 -3
  368. package/docs/site/index.html +33 -14
  369. package/docs/slides.md +13 -5
  370. package/docs/smoketest.md +29 -20
  371. package/docs/timestamps.md +21 -0
  372. package/docs/website.md +2 -1
  373. package/docs/youtube.md +4 -0
  374. package/package.json +36 -35
@@ -1,70 +1,80 @@
1
- import { normalizeGatewayStyleModelId, parseGatewayStyleModelId } from './llm/model-id.js';
1
+ import { normalizeGatewayStyleModelId, parseGatewayStyleModelId } from "./llm/model-id.js";
2
2
  const DEFAULT_CLI_MODELS = {
3
- claude: 'sonnet',
4
- codex: 'gpt-5.2',
5
- gemini: 'gemini-3-flash-preview',
3
+ claude: "sonnet",
4
+ codex: "gpt-5.2",
5
+ gemini: "gemini-3-flash-preview",
6
+ agent: "gpt-5.2",
6
7
  };
7
8
  export function parseRequestedModelId(raw) {
8
9
  const trimmed = raw.trim();
9
10
  if (trimmed.length === 0)
10
- throw new Error('Missing model id');
11
+ throw new Error("Missing model id");
11
12
  const lower = trimmed.toLowerCase();
12
- if (lower === 'auto')
13
- return { kind: 'auto' };
14
- if (lower.startsWith('openrouter/')) {
15
- const openrouterModelId = trimmed.slice('openrouter/'.length).trim();
13
+ if (lower === "auto")
14
+ return { kind: "auto" };
15
+ if (lower.startsWith("openrouter/")) {
16
+ const openrouterModelId = trimmed.slice("openrouter/".length).trim();
16
17
  if (openrouterModelId.length === 0) {
17
- throw new Error('Invalid model id: openrouter/… is missing the OpenRouter model id');
18
+ throw new Error("Invalid model id: openrouter/… is missing the OpenRouter model id");
18
19
  }
19
- if (!openrouterModelId.includes('/')) {
20
+ if (!openrouterModelId.includes("/")) {
20
21
  throw new Error(`Invalid OpenRouter model id "${openrouterModelId}". Expected "author/slug" (e.g. "openai/gpt-5-mini").`);
21
22
  }
22
23
  return {
23
- kind: 'fixed',
24
- transport: 'openrouter',
24
+ kind: "fixed",
25
+ transport: "openrouter",
25
26
  userModelId: `openrouter/${openrouterModelId}`,
26
27
  openrouterModelId,
27
28
  llmModelId: `openai/${openrouterModelId}`,
28
29
  openrouterProviders: null,
29
30
  forceOpenRouter: true,
30
- requiredEnv: 'OPENROUTER_API_KEY',
31
+ requiredEnv: "OPENROUTER_API_KEY",
31
32
  };
32
33
  }
33
- if (lower.startsWith('zai/')) {
34
- const model = trimmed.slice('zai/'.length).trim();
34
+ if (lower.startsWith("zai/")) {
35
+ const model = trimmed.slice("zai/".length).trim();
35
36
  if (model.length === 0) {
36
- throw new Error('Invalid model id: zai/… is missing the model id');
37
+ throw new Error("Invalid model id: zai/… is missing the model id");
37
38
  }
38
39
  return {
39
- kind: 'fixed',
40
- transport: 'native',
40
+ kind: "fixed",
41
+ transport: "native",
41
42
  userModelId: `zai/${model}`,
42
43
  llmModelId: `zai/${model}`,
43
- provider: 'zai',
44
+ provider: "zai",
44
45
  openrouterProviders: null,
45
46
  forceOpenRouter: false,
46
- requiredEnv: 'Z_AI_API_KEY',
47
- openaiBaseUrlOverride: 'https://api.z.ai/api/paas/v4',
47
+ requiredEnv: "Z_AI_API_KEY",
48
+ openaiBaseUrlOverride: "https://api.z.ai/api/paas/v4",
48
49
  forceChatCompletions: true,
49
50
  };
50
51
  }
51
- if (lower.startsWith('cli/')) {
52
+ if (lower.startsWith("cli/")) {
52
53
  const parts = trimmed
53
- .split('/')
54
+ .split("/")
54
55
  .map((part) => part.trim())
55
56
  .filter((part) => part.length > 0);
56
- const providerRaw = parts[1]?.toLowerCase() ?? '';
57
- if (providerRaw !== 'claude' && providerRaw !== 'codex' && providerRaw !== 'gemini') {
57
+ const providerRaw = parts[1]?.toLowerCase() ?? "";
58
+ if (providerRaw !== "claude" &&
59
+ providerRaw !== "codex" &&
60
+ providerRaw !== "gemini" &&
61
+ providerRaw !== "agent") {
58
62
  throw new Error(`Invalid CLI model id "${trimmed}". Expected cli/<provider>/<model>.`);
59
63
  }
60
64
  const cliProvider = providerRaw;
61
- const requestedModel = parts.slice(2).join('/').trim();
65
+ const requestedModel = parts.slice(2).join("/").trim();
62
66
  const cliModel = requestedModel.length > 0 ? requestedModel : DEFAULT_CLI_MODELS[cliProvider];
63
- const requiredEnv = cliProvider === 'claude' ? 'CLI_CLAUDE' : cliProvider === 'codex' ? 'CLI_CODEX' : 'CLI_GEMINI';
67
+ const requiredEnv = cliProvider === "claude"
68
+ ? "CLI_CLAUDE"
69
+ : cliProvider === "codex"
70
+ ? "CLI_CODEX"
71
+ : cliProvider === "gemini"
72
+ ? "CLI_GEMINI"
73
+ : "CLI_AGENT";
64
74
  const userModelId = `cli/${cliProvider}/${cliModel}`;
65
75
  return {
66
- kind: 'fixed',
67
- transport: 'cli',
76
+ kind: "fixed",
77
+ transport: "cli",
68
78
  userModelId,
69
79
  llmModelId: null,
70
80
  openrouterProviders: null,
@@ -74,23 +84,23 @@ export function parseRequestedModelId(raw) {
74
84
  cliModel,
75
85
  };
76
86
  }
77
- if (!trimmed.includes('/')) {
87
+ if (!trimmed.includes("/")) {
78
88
  throw new Error(`Unknown model "${trimmed}". Expected "auto" or a provider-prefixed id like openai/..., google/..., anthropic/..., xai/..., zai/..., openrouter/... or cli/....`);
79
89
  }
80
90
  const userModelId = normalizeGatewayStyleModelId(trimmed);
81
91
  const parsed = parseGatewayStyleModelId(userModelId);
82
- const requiredEnv = parsed.provider === 'xai'
83
- ? 'XAI_API_KEY'
84
- : parsed.provider === 'google'
85
- ? 'GEMINI_API_KEY'
86
- : parsed.provider === 'anthropic'
87
- ? 'ANTHROPIC_API_KEY'
88
- : parsed.provider === 'zai'
89
- ? 'Z_AI_API_KEY'
90
- : 'OPENAI_API_KEY';
92
+ const requiredEnv = parsed.provider === "xai"
93
+ ? "XAI_API_KEY"
94
+ : parsed.provider === "google"
95
+ ? "GEMINI_API_KEY"
96
+ : parsed.provider === "anthropic"
97
+ ? "ANTHROPIC_API_KEY"
98
+ : parsed.provider === "zai"
99
+ ? "Z_AI_API_KEY"
100
+ : "OPENAI_API_KEY";
91
101
  return {
92
- kind: 'fixed',
93
- transport: 'native',
102
+ kind: "fixed",
103
+ transport: "native",
94
104
  userModelId,
95
105
  llmModelId: userModelId,
96
106
  provider: parsed.provider,
@@ -1 +1 @@
1
- {"version":3,"file":"model-spec.js","sourceRoot":"","sources":["../../src/model-spec.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"model-spec.js","sourceRoot":"","sources":["../../src/model-spec.ts"],"names":[],"mappings":"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"}
@@ -1,13 +1,13 @@
1
- import path from 'node:path';
2
- import { loadLiteLlmCatalog as loadLiteLlmCatalogTokentally, resolveLiteLlmMaxInputTokens as resolveLiteLlmMaxInputTokensTokentally, resolveLiteLlmMaxOutputTokens as resolveLiteLlmMaxOutputTokensTokentally, resolveLiteLlmPricing as resolveLiteLlmPricingTokentally, } from 'tokentally/node';
1
+ import path from "node:path";
2
+ import { loadLiteLlmCatalog as loadLiteLlmCatalogTokentally, resolveLiteLlmMaxInputTokens as resolveLiteLlmMaxInputTokensTokentally, resolveLiteLlmMaxOutputTokens as resolveLiteLlmMaxOutputTokensTokentally, resolveLiteLlmPricing as resolveLiteLlmPricingTokentally, } from "tokentally/node";
3
3
  function withDefaultCacheDir(env) {
4
- if (typeof env.TOKENTALLY_CACHE_DIR === 'string' && env.TOKENTALLY_CACHE_DIR.trim().length > 0) {
4
+ if (typeof env.TOKENTALLY_CACHE_DIR === "string" && env.TOKENTALLY_CACHE_DIR.trim().length > 0) {
5
5
  return env;
6
6
  }
7
7
  const home = env.HOME?.trim();
8
8
  if (!home)
9
9
  return env;
10
- return { ...env, TOKENTALLY_CACHE_DIR: path.join(home, '.summarize', 'cache') };
10
+ return { ...env, TOKENTALLY_CACHE_DIR: path.join(home, ".summarize", "cache") };
11
11
  }
12
12
  export async function loadLiteLlmCatalog({ env, fetchImpl, nowMs = Date.now(), }) {
13
13
  return loadLiteLlmCatalogTokentally({
@@ -1 +1 @@
1
- {"version":3,"file":"litellm.js","sourceRoot":"","sources":["../../../src/pricing/litellm.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAA;AAE5B,OAAO,EAGL,kBAAkB,IAAI,4BAA4B,EAClD,4BAA4B,IAAI,sCAAsC,EACtE,6BAA6B,IAAI,uCAAuC,EACxE,qBAAqB,IAAI,+BAA+B,GACzD,MAAM,iBAAiB,CAAA;AAExB,SAAS,mBAAmB,CAC1B,GAAuC;IAEvC,IAAI,OAAO,GAAG,CAAC,oBAAoB,KAAK,QAAQ,IAAI,GAAG,CAAC,oBAAoB,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC/F,OAAO,GAAG,CAAA;IACZ,CAAC;IACD,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,CAAA;IAC7B,IAAI,CAAC,IAAI;QAAE,OAAO,GAAG,CAAA;IACrB,OAAO,EAAE,GAAG,GAAG,EAAE,oBAAoB,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,YAAY,EAAE,OAAO,CAAC,EAAE,CAAA;AACjF,CAAC;AAID,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,EACvC,GAAG,EACH,SAAS,EACT,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,GAKnB;IACC,OAAO,4BAA4B,CAAC;QAClC,GAAG,EAAE,mBAAmB,CAAC,GAAG,CAAC;QAC7B,SAAS;QACT,KAAK;KACN,CAAC,CAAA;AACJ,CAAC;AAID,MAAM,UAAU,+BAA+B,CAC7C,OAAuB,EACvB,OAAe;IAEf,OAAO,+BAA+B,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;AAC1D,CAAC;AAED,MAAM,UAAU,uCAAuC,CACrD,OAAuB,EACvB,OAAe;IAEf,OAAO,uCAAuC,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;AAClE,CAAC;AAED,MAAM,UAAU,sCAAsC,CACpD,OAAuB,EACvB,OAAe;IAEf,OAAO,sCAAsC,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;AACjE,CAAC"}
1
+ {"version":3,"file":"litellm.js","sourceRoot":"","sources":["../../../src/pricing/litellm.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAGL,kBAAkB,IAAI,4BAA4B,EAClD,4BAA4B,IAAI,sCAAsC,EACtE,6BAA6B,IAAI,uCAAuC,EACxE,qBAAqB,IAAI,+BAA+B,GACzD,MAAM,iBAAiB,CAAC;AAEzB,SAAS,mBAAmB,CAC1B,GAAuC;IAEvC,IAAI,OAAO,GAAG,CAAC,oBAAoB,KAAK,QAAQ,IAAI,GAAG,CAAC,oBAAoB,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC/F,OAAO,GAAG,CAAC;IACb,CAAC;IACD,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC;IAC9B,IAAI,CAAC,IAAI;QAAE,OAAO,GAAG,CAAC;IACtB,OAAO,EAAE,GAAG,GAAG,EAAE,oBAAoB,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,YAAY,EAAE,OAAO,CAAC,EAAE,CAAC;AAClF,CAAC;AAID,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,EACvC,GAAG,EACH,SAAS,EACT,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,GAKnB;IACC,OAAO,4BAA4B,CAAC;QAClC,GAAG,EAAE,mBAAmB,CAAC,GAAG,CAAC;QAC7B,SAAS;QACT,KAAK;KACN,CAAC,CAAC;AACL,CAAC;AAID,MAAM,UAAU,+BAA+B,CAC7C,OAAuB,EACvB,OAAe;IAEf,OAAO,+BAA+B,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;AAC3D,CAAC;AAED,MAAM,UAAU,uCAAuC,CACrD,OAAuB,EACvB,OAAe;IAEf,OAAO,uCAAuC,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;AACnE,CAAC;AAED,MAAM,UAAU,sCAAsC,CACpD,OAAuB,EACvB,OAAe;IAEf,OAAO,sCAAsC,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;AAClE,CAAC"}
@@ -1,2 +1,2 @@
1
- export * from '@steipete/summarize-core/processes';
1
+ export * from "@steipete/summarize-core/processes";
2
2
  //# sourceMappingURL=processes.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"processes.js","sourceRoot":"","sources":["../../src/processes.ts"],"names":[],"mappings":"AAAA,cAAc,oCAAoC,CAAA"}
1
+ {"version":3,"file":"processes.js","sourceRoot":"","sources":["../../src/processes.ts"],"names":[],"mappings":"AAAA,cAAc,oCAAoC,CAAC"}
@@ -1,2 +1,2 @@
1
- export * from '@steipete/summarize-core/prompts';
1
+ export * from "@steipete/summarize-core/prompts";
2
2
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/prompts/index.ts"],"names":[],"mappings":"AAAA,cAAc,kCAAkC,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/prompts/index.ts"],"names":[],"mappings":"AAAA,cAAc,kCAAkC,CAAC"}
@@ -1,17 +1,17 @@
1
- import { mkdir, readFile, rename, writeFile } from 'node:fs/promises';
2
- import { homedir } from 'node:os';
3
- import { dirname, join } from 'node:path';
4
- import JSON5 from 'json5';
5
- import { generateTextWithModelId } from './llm/generate-text.js';
1
+ import JSON5 from "json5";
2
+ import { mkdir, readFile, rename, writeFile } from "node:fs/promises";
3
+ import { homedir } from "node:os";
4
+ import { dirname, join } from "node:path";
5
+ import { generateTextWithModelId } from "./llm/generate-text.js";
6
6
  function supportsColor(stream, env) {
7
7
  if (env.NO_COLOR)
8
8
  return false;
9
- if (env.FORCE_COLOR && env.FORCE_COLOR !== '0')
9
+ if (env.FORCE_COLOR && env.FORCE_COLOR !== "0")
10
10
  return true;
11
11
  if (!stream.isTTY)
12
12
  return false;
13
13
  const term = env.TERM?.toLowerCase();
14
- if (!term || term === 'dumb')
14
+ if (!term || term === "dumb")
15
15
  return false;
16
16
  return true;
17
17
  }
@@ -57,16 +57,16 @@ function inferParamBFromIdOrName(text) {
57
57
  }
58
58
  function classifyOpenRouterRateLimit(message) {
59
59
  const m = message.toLowerCase();
60
- if (!m.includes('rate limit exceeded'))
60
+ if (!m.includes("rate limit exceeded"))
61
61
  return null;
62
- if (m.includes('per-day') || m.includes('per day') || m.includes('free-models-per-day')) {
63
- return 'perDay';
62
+ if (m.includes("per-day") || m.includes("per day") || m.includes("free-models-per-day")) {
63
+ return "perDay";
64
64
  }
65
- if (m.includes('per-min') || m.includes('per min') || m.includes('free-models-per-min')) {
66
- return 'perMin';
65
+ if (m.includes("per-min") || m.includes("per min") || m.includes("free-models-per-min")) {
66
+ return "perMin";
67
67
  }
68
68
  // Default: assume per-minute (most common for free models).
69
- return 'perMin';
69
+ return "perMin";
70
70
  }
71
71
  function assertNoComments(raw, path) {
72
72
  let inString = null;
@@ -74,15 +74,15 @@ function assertNoComments(raw, path) {
74
74
  let line = 1;
75
75
  let col = 1;
76
76
  for (let i = 0; i < raw.length; i += 1) {
77
- const ch = raw[i] ?? '';
78
- const next = raw[i + 1] ?? '';
77
+ const ch = raw[i] ?? "";
78
+ const next = raw[i + 1] ?? "";
79
79
  if (inString) {
80
80
  if (escaped) {
81
81
  escaped = false;
82
82
  col += 1;
83
83
  continue;
84
84
  }
85
- if (ch === '\\') {
85
+ if (ch === "\\") {
86
86
  escaped = true;
87
87
  col += 1;
88
88
  continue;
@@ -90,7 +90,7 @@ function assertNoComments(raw, path) {
90
90
  if (ch === inString) {
91
91
  inString = null;
92
92
  }
93
- if (ch === '\n') {
93
+ if (ch === "\n") {
94
94
  line += 1;
95
95
  col = 1;
96
96
  }
@@ -105,13 +105,13 @@ function assertNoComments(raw, path) {
105
105
  col += 1;
106
106
  continue;
107
107
  }
108
- if (ch === '/' && next === '/') {
108
+ if (ch === "/" && next === "/") {
109
109
  throw new Error(`Invalid config file ${path}: comments are not allowed (found // at ${line}:${col}).`);
110
110
  }
111
- if (ch === '/' && next === '*') {
111
+ if (ch === "/" && next === "*") {
112
112
  throw new Error(`Invalid config file ${path}: comments are not allowed (found /* at ${line}:${col}).`);
113
113
  }
114
- if (ch === '\n') {
114
+ if (ch === "\n") {
115
115
  line += 1;
116
116
  col = 1;
117
117
  }
@@ -123,11 +123,11 @@ function assertNoComments(raw, path) {
123
123
  function resolveConfigPath(env) {
124
124
  const home = env.HOME?.trim() || homedir();
125
125
  if (!home)
126
- throw new Error('Missing HOME');
127
- return join(home, '.summarize', 'config.json');
126
+ throw new Error("Missing HOME");
127
+ return join(home, ".summarize", "config.json");
128
128
  }
129
129
  function isRecord(value) {
130
- return typeof value === 'object' && value !== null && !Array.isArray(value);
130
+ return typeof value === "object" && value !== null && !Array.isArray(value);
131
131
  }
132
132
  async function mapWithConcurrency(items, concurrency, fn) {
133
133
  const limit = Math.max(1, Math.floor(concurrency));
@@ -147,16 +147,16 @@ async function mapWithConcurrency(items, concurrency, fn) {
147
147
  }
148
148
  export async function refreshFree({ env, fetchImpl, stdout, stderr, verbose = false, options = {}, }) {
149
149
  const color = supportsColor(stderr, env);
150
- const okLabel = (text) => ansi('1;32', text, color);
151
- const failLabel = (text) => ansi('1;31', text, color);
152
- const dim = (text) => ansi('2', text, color);
153
- const heading = (text) => ansi('1;36', text, color);
154
- const cmdName = heading('Refresh Free');
155
- const openrouterKey = typeof env.OPENROUTER_API_KEY === 'string' && env.OPENROUTER_API_KEY.trim().length > 0
150
+ const okLabel = (text) => ansi("1;32", text, color);
151
+ const failLabel = (text) => ansi("1;31", text, color);
152
+ const dim = (text) => ansi("2", text, color);
153
+ const heading = (text) => ansi("1;36", text, color);
154
+ const cmdName = heading("Refresh Free");
155
+ const openrouterKey = typeof env.OPENROUTER_API_KEY === "string" && env.OPENROUTER_API_KEY.trim().length > 0
156
156
  ? env.OPENROUTER_API_KEY.trim()
157
157
  : null;
158
158
  if (!openrouterKey) {
159
- throw new Error('Missing OPENROUTER_API_KEY (required for refresh-free)');
159
+ throw new Error("Missing OPENROUTER_API_KEY (required for refresh-free)");
160
160
  }
161
161
  const resolved = {
162
162
  runs: 2,
@@ -179,8 +179,8 @@ export async function refreshFree({ env, fetchImpl, stdout, stderr, verbose = fa
179
179
  const MAX_AGE_DAYS = Math.max(0, Math.floor(resolved.maxAgeDays));
180
180
  const applyMaxAgeFilter = MAX_AGE_DAYS > 0;
181
181
  stderr.write(`${cmdName}: fetching OpenRouter models…\n`);
182
- const response = await fetchImpl('https://openrouter.ai/api/v1/models', {
183
- headers: { Accept: 'application/json' },
182
+ const response = await fetchImpl("https://openrouter.ai/api/v1/models", {
183
+ headers: { Accept: "application/json" },
184
184
  });
185
185
  if (!response.ok) {
186
186
  throw new Error(`OpenRouter /models failed: HTTP ${response.status}`);
@@ -189,20 +189,20 @@ export async function refreshFree({ env, fetchImpl, stdout, stderr, verbose = fa
189
189
  const entries = (Array.isArray(payload.data) ? payload.data : []);
190
190
  const catalogModels = entries
191
191
  .map((entry) => {
192
- if (!entry || typeof entry !== 'object')
192
+ if (!entry || typeof entry !== "object")
193
193
  return null;
194
194
  const obj = entry;
195
- const id = typeof obj.id === 'string' ? obj.id.trim() : '';
195
+ const id = typeof obj.id === "string" ? obj.id.trim() : "";
196
196
  if (!id)
197
197
  return null;
198
- const name = typeof obj.name === 'string' ? obj.name.trim() : '';
199
- const contextLength = typeof obj.context_length === 'number' && Number.isFinite(obj.context_length)
198
+ const name = typeof obj.name === "string" ? obj.name.trim() : "";
199
+ const contextLength = typeof obj.context_length === "number" && Number.isFinite(obj.context_length)
200
200
  ? obj.context_length
201
201
  : null;
202
- const topProvider = obj.top_provider && typeof obj.top_provider === 'object'
202
+ const topProvider = obj.top_provider && typeof obj.top_provider === "object"
203
203
  ? obj.top_provider
204
204
  : null;
205
- const maxCompletionTokens = typeof topProvider?.max_completion_tokens === 'number' &&
205
+ const maxCompletionTokens = typeof topProvider?.max_completion_tokens === "number" &&
206
206
  Number.isFinite(topProvider.max_completion_tokens)
207
207
  ? topProvider.max_completion_tokens
208
208
  : null;
@@ -210,18 +210,18 @@ export async function refreshFree({ env, fetchImpl, stdout, stderr, verbose = fa
210
210
  const sp = obj.supported_parameters;
211
211
  if (!Array.isArray(sp))
212
212
  return 0;
213
- return sp.filter((v) => typeof v === 'string' && v.trim().length > 0).length;
213
+ return sp.filter((v) => typeof v === "string" && v.trim().length > 0).length;
214
214
  })();
215
215
  const modality = (() => {
216
- const arch = obj.architecture && typeof obj.architecture === 'object'
216
+ const arch = obj.architecture && typeof obj.architecture === "object"
217
217
  ? obj.architecture
218
218
  : null;
219
- const raw = typeof arch?.modality === 'string' ? arch.modality.trim() : '';
219
+ const raw = typeof arch?.modality === "string" ? arch.modality.trim() : "";
220
220
  return raw.length > 0 ? raw : null;
221
221
  })();
222
222
  const createdAtMs = (() => {
223
223
  const created = obj.created;
224
- if (typeof created !== 'number' || !Number.isFinite(created) || created <= 0)
224
+ if (typeof created !== "number" || !Number.isFinite(created) || created <= 0)
225
225
  return null;
226
226
  // OpenRouter uses unix timestamp seconds.
227
227
  return Math.round(created * 1000);
@@ -237,7 +237,7 @@ export async function refreshFree({ env, fetchImpl, stdout, stderr, verbose = fa
237
237
  };
238
238
  })
239
239
  .filter((v) => Boolean(v));
240
- const freeModelsAll = catalogModels.filter((m) => m.id.endsWith(':free'));
240
+ const freeModelsAll = catalogModels.filter((m) => m.id.endsWith(":free"));
241
241
  const freeModelsAgeFiltered = freeModelsAll.filter((m) => {
242
242
  if (!applyMaxAgeFilter)
243
243
  return true;
@@ -255,7 +255,7 @@ export async function refreshFree({ env, fetchImpl, stdout, stderr, verbose = fa
255
255
  if (applyMaxAgeFilter) {
256
256
  throw new Error(`OpenRouter /models returned no :free models from the last ${MAX_AGE_DAYS} days`);
257
257
  }
258
- throw new Error('OpenRouter /models returned no :free models');
258
+ throw new Error("OpenRouter /models returned no :free models");
259
259
  }
260
260
  const ageFilteredCount = freeModelsAll.length - freeModelsAgeFiltered.length;
261
261
  if (ageFilteredCount > 0) {
@@ -376,20 +376,20 @@ export async function refreshFree({ env, fetchImpl, stdout, stderr, verbose = fa
376
376
  };
377
377
  const classifyFailure = (message) => {
378
378
  const m = message.toLowerCase();
379
- if (m.includes('empty summary'))
380
- return 'empty';
379
+ if (m.includes("empty summary"))
380
+ return "empty";
381
381
  const rl = classifyOpenRouterRateLimit(message);
382
- if (rl === 'perMin')
383
- return 'rateLimitMin';
384
- if (rl === 'perDay')
385
- return 'rateLimitDay';
386
- if (m.includes('no allowed providers are available'))
387
- return 'noProviders';
388
- if (m.includes('timed out') || m.includes('timeout') || m.includes('aborted'))
389
- return 'timeout';
390
- if (m.includes('provider returned error') || m.includes('provider error'))
391
- return 'providerError';
392
- return 'other';
382
+ if (rl === "perMin")
383
+ return "rateLimitMin";
384
+ if (rl === "perDay")
385
+ return "rateLimitDay";
386
+ if (m.includes("no allowed providers are available"))
387
+ return "noProviders";
388
+ if (m.includes("timed out") || m.includes("timeout") || m.includes("aborted"))
389
+ return "timeout";
390
+ if (m.includes("provider returned error") || m.includes("provider error"))
391
+ return "providerError";
392
+ return "other";
393
393
  };
394
394
  // Pass 1: test all free models once.
395
395
  {
@@ -400,7 +400,7 @@ export async function refreshFree({ env, fetchImpl, stdout, stderr, verbose = fa
400
400
  await generateTextWithModelId({
401
401
  modelId: `openai/${openrouterModelId}`,
402
402
  apiKeys,
403
- prompt: { userText: 'Reply with a single word: OK' },
403
+ prompt: { userText: "Reply with a single word: OK" },
404
404
  temperature: 0,
405
405
  maxOutputTokens: 16,
406
406
  timeoutMs: TIMEOUT_MS,
@@ -411,9 +411,9 @@ export async function refreshFree({ env, fetchImpl, stdout, stderr, verbose = fa
411
411
  const latencyMs = Date.now() - runStartedAt;
412
412
  done += 1;
413
413
  okCount += 1;
414
- progress('tested');
414
+ progress("tested");
415
415
  const meta = idToMeta.get(openrouterModelId) ?? null;
416
- note(`${okLabel('ok')} ${openrouterModelId} ${dim(`(${formatMs(latencyMs)})`)}`);
416
+ note(`${okLabel("ok")} ${openrouterModelId} ${dim(`(${formatMs(latencyMs)})`)}`);
417
417
  return {
418
418
  ok: true,
419
419
  value: {
@@ -434,7 +434,7 @@ export async function refreshFree({ env, fetchImpl, stdout, stderr, verbose = fa
434
434
  const message = error instanceof Error ? error.message : String(error);
435
435
  const kind = classifyFailure(message);
436
436
  failureCounts[kind] += 1;
437
- if (kind === 'rateLimitMin') {
437
+ if (kind === "rateLimitMin") {
438
438
  // Back off globally and retry once.
439
439
  setCooldown(COOLDOWN_MS);
440
440
  await waitForCooldown();
@@ -443,7 +443,7 @@ export async function refreshFree({ env, fetchImpl, stdout, stderr, verbose = fa
443
443
  await generateTextWithModelId({
444
444
  modelId: `openai/${openrouterModelId}`,
445
445
  apiKeys,
446
- prompt: { userText: 'Reply with a single word: OK' },
446
+ prompt: { userText: "Reply with a single word: OK" },
447
447
  temperature: 0,
448
448
  maxOutputTokens: 16,
449
449
  timeoutMs: TIMEOUT_MS,
@@ -454,9 +454,9 @@ export async function refreshFree({ env, fetchImpl, stdout, stderr, verbose = fa
454
454
  const retryLatencyMs = Date.now() - retryStartedAt;
455
455
  done += 1;
456
456
  okCount += 1;
457
- progress('tested');
457
+ progress("tested");
458
458
  const meta = idToMeta.get(openrouterModelId) ?? null;
459
- note(`${okLabel('ok')} ${openrouterModelId} ${dim(`(${formatMs(retryLatencyMs)})`)}`);
459
+ note(`${okLabel("ok")} ${openrouterModelId} ${dim(`(${formatMs(retryLatencyMs)})`)}`);
460
460
  return {
461
461
  ok: true,
462
462
  value: {
@@ -478,9 +478,9 @@ export async function refreshFree({ env, fetchImpl, stdout, stderr, verbose = fa
478
478
  }
479
479
  }
480
480
  done += 1;
481
- progress('tested');
481
+ progress("tested");
482
482
  if (verbose) {
483
- note(`${failLabel('fail')} ${openrouterModelId} ${dim(`(${kind})`)}: ${message}`);
483
+ note(`${failLabel("fail")} ${openrouterModelId} ${dim(`(${kind})`)}: ${message}`);
484
484
  }
485
485
  return { ok: false, openrouterModelId, error: message };
486
486
  }
@@ -489,7 +489,7 @@ export async function refreshFree({ env, fetchImpl, stdout, stderr, verbose = fa
489
489
  results.push(r);
490
490
  }
491
491
  if (isTty)
492
- stderr.write('\n');
492
+ stderr.write("\n");
493
493
  const ok = results
494
494
  .filter((r) => r.ok)
495
495
  .map((r) => r.value)
@@ -506,12 +506,12 @@ export async function refreshFree({ env, fetchImpl, stdout, stderr, verbose = fa
506
506
  .filter(([, v]) => v > 0)
507
507
  .map(([k, v]) => `${k}=${v}`),
508
508
  ];
509
- stderr.write(`${cmdName}: results ${parts.join(' ')}\n`);
509
+ stderr.write(`${cmdName}: results ${parts.join(" ")}\n`);
510
510
  if (failureCounts.rateLimitMin > 0) {
511
- stderr.write(`${dim('Note: OpenRouter free-model rate limits were hit; retrying later may find more working models.')}\n`);
511
+ stderr.write(`${dim("Note: OpenRouter free-model rate limits were hit; retrying later may find more working models.")}\n`);
512
512
  }
513
513
  if (failureCounts.rateLimitDay > 0) {
514
- stderr.write(`${dim('Note: OpenRouter per-day free-model quota was hit.')}\n`);
514
+ stderr.write(`${dim("Note: OpenRouter per-day free-model quota was hit.")}\n`);
515
515
  }
516
516
  }
517
517
  const buildSelection = (working) => {
@@ -579,7 +579,7 @@ export async function refreshFree({ env, fetchImpl, stdout, stderr, verbose = fa
579
579
  await generateTextWithModelId({
580
580
  modelId: `openai/${openrouterModelId}`,
581
581
  apiKeys,
582
- prompt: { userText: 'Reply with a single word: OK' },
582
+ prompt: { userText: "Reply with a single word: OK" },
583
583
  temperature: 0,
584
584
  maxOutputTokens: 16,
585
585
  timeoutMs: TIMEOUT_MS,
@@ -614,7 +614,7 @@ export async function refreshFree({ env, fetchImpl, stdout, stderr, verbose = fa
614
614
  const configPath = resolveConfigPath(env);
615
615
  let root = {};
616
616
  try {
617
- const raw = await readFile(configPath, 'utf8');
617
+ const raw = await readFile(configPath, "utf8");
618
618
  assertNoComments(raw, configPath);
619
619
  const parsed = JSON5.parse(raw);
620
620
  if (!isRecord(parsed)) {
@@ -624,12 +624,12 @@ export async function refreshFree({ env, fetchImpl, stdout, stderr, verbose = fa
624
624
  }
625
625
  catch (error) {
626
626
  const code = error?.code;
627
- if (code !== 'ENOENT')
627
+ if (code !== "ENOENT")
628
628
  throw error;
629
629
  }
630
630
  const configModelsRaw = root.models;
631
631
  const configModels = (() => {
632
- if (typeof configModelsRaw === 'undefined')
632
+ if (typeof configModelsRaw === "undefined")
633
633
  return {};
634
634
  if (!isRecord(configModelsRaw)) {
635
635
  throw new Error(`Invalid config file ${configPath}: "models" must be an object.`);
@@ -639,28 +639,28 @@ export async function refreshFree({ env, fetchImpl, stdout, stderr, verbose = fa
639
639
  configModels.free = { rules: [{ candidates: selected }] };
640
640
  root.models = configModels;
641
641
  if (resolved.setDefault) {
642
- root.model = 'free';
642
+ root.model = "free";
643
643
  }
644
644
  await mkdir(dirname(configPath), { recursive: true });
645
645
  const next = `${JSON.stringify(root, null, 2)}\n`;
646
646
  const tmp = `${configPath}.tmp-${process.pid}-${Date.now()}`;
647
- await writeFile(tmp, next, 'utf8');
647
+ await writeFile(tmp, next, "utf8");
648
648
  await rename(tmp, configPath);
649
649
  stdout.write(`Wrote ${configPath} (models.free)\n`);
650
650
  const refinedById = new Map(refined.map((m) => [m.openrouterModelId, m]));
651
- stderr.write(`\n${heading('Selected')} (sorted, Δ latency)\n`);
651
+ stderr.write(`\n${heading("Selected")} (sorted, Δ latency)\n`);
652
652
  for (const modelId of selectedIds) {
653
653
  const r = refinedById.get(modelId);
654
654
  if (!r)
655
655
  continue;
656
656
  const avg = r.successCount > 0 ? r.totalLatencyMs / r.successCount : r.medianLatencyMs;
657
- const ctx = typeof r.contextLength === 'number' ? `ctx=${formatTokenK(r.contextLength)}` : null;
658
- const out = typeof r.maxCompletionTokens === 'number'
657
+ const ctx = typeof r.contextLength === "number" ? `ctx=${formatTokenK(r.contextLength)}` : null;
658
+ const out = typeof r.maxCompletionTokens === "number"
659
659
  ? `out=${formatTokenK(r.maxCompletionTokens)}`
660
660
  : null;
661
661
  const modality = r.modality ? r.modality : null;
662
- const params = typeof r.inferredParamB === 'number' ? `~${r.inferredParamB}B` : null;
663
- const meta = [params, ctx, out, modality].filter(Boolean).join(' ');
662
+ const params = typeof r.inferredParamB === "number" ? `~${r.inferredParamB}B` : null;
663
+ const meta = [params, ctx, out, modality].filter(Boolean).join(" ");
664
664
  stderr.write(`- ${modelId} ${dim(`Δ ${formatMs(avg)} (n=${r.successCount})`)} ${dim(meta)}\n`);
665
665
  }
666
666
  }