@steipete/summarize 0.9.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (398) hide show
  1. package/CHANGELOG.md +121 -0
  2. package/LICENSE +1 -1
  3. package/README.md +391 -183
  4. package/dist/cli.js +1 -1
  5. package/dist/esm/cache.js +134 -64
  6. package/dist/esm/cache.js.map +1 -1
  7. package/dist/esm/cli-main.js +27 -27
  8. package/dist/esm/cli-main.js.map +1 -1
  9. package/dist/esm/cli.js +2 -2
  10. package/dist/esm/cli.js.map +1 -1
  11. package/dist/esm/config.js +396 -126
  12. package/dist/esm/config.js.map +1 -1
  13. package/dist/esm/content/asset.js +53 -50
  14. package/dist/esm/content/asset.js.map +1 -1
  15. package/dist/esm/content/index.js +1 -1
  16. package/dist/esm/content/index.js.map +1 -1
  17. package/dist/esm/costs.js +1 -1
  18. package/dist/esm/costs.js.map +1 -1
  19. package/dist/esm/daemon/agent.js +548 -0
  20. package/dist/esm/daemon/agent.js.map +1 -0
  21. package/dist/esm/daemon/auto-mode.js +3 -3
  22. package/dist/esm/daemon/auto-mode.js.map +1 -1
  23. package/dist/esm/daemon/chat.js +88 -178
  24. package/dist/esm/daemon/chat.js.map +1 -1
  25. package/dist/esm/daemon/cli-entrypoint.js +72 -0
  26. package/dist/esm/daemon/cli-entrypoint.js.map +1 -0
  27. package/dist/esm/daemon/cli.js +91 -83
  28. package/dist/esm/daemon/cli.js.map +1 -1
  29. package/dist/esm/daemon/config.js +15 -15
  30. package/dist/esm/daemon/config.js.map +1 -1
  31. package/dist/esm/daemon/constants.js +6 -6
  32. package/dist/esm/daemon/constants.js.map +1 -1
  33. package/dist/esm/daemon/env-merge.js.map +1 -1
  34. package/dist/esm/daemon/env-snapshot.js +36 -28
  35. package/dist/esm/daemon/env-snapshot.js.map +1 -1
  36. package/dist/esm/daemon/flow-context.js +86 -32
  37. package/dist/esm/daemon/flow-context.js.map +1 -1
  38. package/dist/esm/daemon/launchd.js +119 -47
  39. package/dist/esm/daemon/launchd.js.map +1 -1
  40. package/dist/esm/daemon/meta.js +5 -5
  41. package/dist/esm/daemon/meta.js.map +1 -1
  42. package/dist/esm/daemon/models.js +54 -31
  43. package/dist/esm/daemon/models.js.map +1 -1
  44. package/dist/esm/daemon/process-registry.js +206 -0
  45. package/dist/esm/daemon/process-registry.js.map +1 -0
  46. package/dist/esm/daemon/schtasks.js +96 -32
  47. package/dist/esm/daemon/schtasks.js.map +1 -1
  48. package/dist/esm/daemon/server.js +832 -158
  49. package/dist/esm/daemon/server.js.map +1 -1
  50. package/dist/esm/daemon/summarize-progress.js +11 -11
  51. package/dist/esm/daemon/summarize-progress.js.map +1 -1
  52. package/dist/esm/daemon/summarize.js +61 -32
  53. package/dist/esm/daemon/summarize.js.map +1 -1
  54. package/dist/esm/daemon/systemd.js +96 -35
  55. package/dist/esm/daemon/systemd.js.map +1 -1
  56. package/dist/esm/firecrawl.js +12 -12
  57. package/dist/esm/firecrawl.js.map +1 -1
  58. package/dist/esm/flags.js +55 -31
  59. package/dist/esm/flags.js.map +1 -1
  60. package/dist/esm/index.js +3 -3
  61. package/dist/esm/index.js.map +1 -1
  62. package/dist/esm/language.js +1 -1
  63. package/dist/esm/language.js.map +1 -1
  64. package/dist/esm/llm/cli.js +128 -64
  65. package/dist/esm/llm/cli.js.map +1 -1
  66. package/dist/esm/llm/errors.js +1 -1
  67. package/dist/esm/llm/errors.js.map +1 -1
  68. package/dist/esm/llm/generate-text.js +107 -98
  69. package/dist/esm/llm/generate-text.js.map +1 -1
  70. package/dist/esm/llm/google-models.js +17 -17
  71. package/dist/esm/llm/google-models.js.map +1 -1
  72. package/dist/esm/llm/html-to-markdown.js +3 -3
  73. package/dist/esm/llm/html-to-markdown.js.map +1 -1
  74. package/dist/esm/llm/model-id.js +38 -16
  75. package/dist/esm/llm/model-id.js.map +1 -1
  76. package/dist/esm/llm/prompt.js +5 -5
  77. package/dist/esm/llm/prompt.js.map +1 -1
  78. package/dist/esm/llm/providers/anthropic.js +33 -33
  79. package/dist/esm/llm/providers/anthropic.js.map +1 -1
  80. package/dist/esm/llm/providers/google.js +19 -19
  81. package/dist/esm/llm/providers/google.js.map +1 -1
  82. package/dist/esm/llm/providers/models.js +30 -30
  83. package/dist/esm/llm/providers/models.js.map +1 -1
  84. package/dist/esm/llm/providers/openai.js +36 -35
  85. package/dist/esm/llm/providers/openai.js.map +1 -1
  86. package/dist/esm/llm/providers/shared.js +8 -8
  87. package/dist/esm/llm/providers/shared.js.map +1 -1
  88. package/dist/esm/llm/transcript-to-markdown.js +9 -5
  89. package/dist/esm/llm/transcript-to-markdown.js.map +1 -1
  90. package/dist/esm/llm/usage.js +18 -18
  91. package/dist/esm/llm/usage.js.map +1 -1
  92. package/dist/esm/logging/daemon.js +21 -21
  93. package/dist/esm/logging/daemon.js.map +1 -1
  94. package/dist/esm/logging/ring-file.js +5 -5
  95. package/dist/esm/logging/ring-file.js.map +1 -1
  96. package/dist/esm/markitdown.js +21 -19
  97. package/dist/esm/markitdown.js.map +1 -1
  98. package/dist/esm/media-cache.js +251 -0
  99. package/dist/esm/media-cache.js.map +1 -0
  100. package/dist/esm/model-auto.js +175 -106
  101. package/dist/esm/model-auto.js.map +1 -1
  102. package/dist/esm/model-spec.js +52 -42
  103. package/dist/esm/model-spec.js.map +1 -1
  104. package/dist/esm/pricing/litellm.js +4 -4
  105. package/dist/esm/pricing/litellm.js.map +1 -1
  106. package/dist/esm/processes.js +2 -0
  107. package/dist/esm/processes.js.map +1 -0
  108. package/dist/esm/prompts/index.js +1 -1
  109. package/dist/esm/prompts/index.js.map +1 -1
  110. package/dist/esm/refresh-free.js +81 -81
  111. package/dist/esm/refresh-free.js.map +1 -1
  112. package/dist/esm/run/attachments.js +47 -44
  113. package/dist/esm/run/attachments.js.map +1 -1
  114. package/dist/esm/run/bird.js +125 -12
  115. package/dist/esm/run/bird.js.map +1 -1
  116. package/dist/esm/run/cache-state.js +7 -7
  117. package/dist/esm/run/cache-state.js.map +1 -1
  118. package/dist/esm/run/cli-fallback-state.js +45 -0
  119. package/dist/esm/run/cli-fallback-state.js.map +1 -0
  120. package/dist/esm/run/cli-preflight.js +40 -22
  121. package/dist/esm/run/cli-preflight.js.map +1 -1
  122. package/dist/esm/run/constants.js +12 -12
  123. package/dist/esm/run/constants.js.map +1 -1
  124. package/dist/esm/run/cookies/twitter.js +47 -47
  125. package/dist/esm/run/cookies/twitter.js.map +1 -1
  126. package/dist/esm/run/env.js +21 -15
  127. package/dist/esm/run/env.js.map +1 -1
  128. package/dist/esm/run/fetch-with-timeout.js +4 -4
  129. package/dist/esm/run/fetch-with-timeout.js.map +1 -1
  130. package/dist/esm/run/finish-line.js +78 -71
  131. package/dist/esm/run/finish-line.js.map +1 -1
  132. package/dist/esm/run/flows/asset/extract.js +70 -0
  133. package/dist/esm/run/flows/asset/extract.js.map +1 -0
  134. package/dist/esm/run/flows/asset/input.js +202 -37
  135. package/dist/esm/run/flows/asset/input.js.map +1 -1
  136. package/dist/esm/run/flows/asset/media-policy.js +3 -0
  137. package/dist/esm/run/flows/asset/media-policy.js.map +1 -0
  138. package/dist/esm/run/flows/asset/media.js +233 -0
  139. package/dist/esm/run/flows/asset/media.js.map +1 -0
  140. package/dist/esm/run/flows/asset/output.js +98 -0
  141. package/dist/esm/run/flows/asset/output.js.map +1 -0
  142. package/dist/esm/run/flows/asset/preprocess.js +79 -44
  143. package/dist/esm/run/flows/asset/preprocess.js.map +1 -1
  144. package/dist/esm/run/flows/asset/summary.js +306 -89
  145. package/dist/esm/run/flows/asset/summary.js.map +1 -1
  146. package/dist/esm/run/flows/url/extract.js +31 -31
  147. package/dist/esm/run/flows/url/extract.js.map +1 -1
  148. package/dist/esm/run/flows/url/flow.js +388 -82
  149. package/dist/esm/run/flows/url/flow.js.map +1 -1
  150. package/dist/esm/run/flows/url/markdown.js +61 -56
  151. package/dist/esm/run/flows/url/markdown.js.map +1 -1
  152. package/dist/esm/run/flows/url/slides-output.js +487 -0
  153. package/dist/esm/run/flows/url/slides-output.js.map +1 -0
  154. package/dist/esm/run/flows/url/slides-text.js +628 -0
  155. package/dist/esm/run/flows/url/slides-text.js.map +1 -0
  156. package/dist/esm/run/flows/url/summary.js +493 -152
  157. package/dist/esm/run/flows/url/summary.js.map +1 -1
  158. package/dist/esm/run/format.js +10 -10
  159. package/dist/esm/run/format.js.map +1 -1
  160. package/dist/esm/run/help.js +179 -84
  161. package/dist/esm/run/help.js.map +1 -1
  162. package/dist/esm/run/logging.js +20 -12
  163. package/dist/esm/run/logging.js.map +1 -1
  164. package/dist/esm/run/markdown.js +12 -12
  165. package/dist/esm/run/markdown.js.map +1 -1
  166. package/dist/esm/run/media-cache-state.js +33 -0
  167. package/dist/esm/run/media-cache-state.js.map +1 -0
  168. package/dist/esm/run/model-attempts.js.map +1 -1
  169. package/dist/esm/run/openrouter.js +11 -11
  170. package/dist/esm/run/openrouter.js.map +1 -1
  171. package/dist/esm/run/progress.js +19 -1
  172. package/dist/esm/run/progress.js.map +1 -1
  173. package/dist/esm/run/run-config.js +16 -16
  174. package/dist/esm/run/run-config.js.map +1 -1
  175. package/dist/esm/run/run-context.js +2 -2
  176. package/dist/esm/run/run-context.js.map +1 -1
  177. package/dist/esm/run/run-env.js +55 -54
  178. package/dist/esm/run/run-env.js.map +1 -1
  179. package/dist/esm/run/run-input.js +3 -3
  180. package/dist/esm/run/run-input.js.map +1 -1
  181. package/dist/esm/run/run-metrics.js +16 -16
  182. package/dist/esm/run/run-metrics.js.map +1 -1
  183. package/dist/esm/run/run-models.js +28 -23
  184. package/dist/esm/run/run-models.js.map +1 -1
  185. package/dist/esm/run/run-output.js +3 -3
  186. package/dist/esm/run/run-output.js.map +1 -1
  187. package/dist/esm/run/run-settings.js +108 -21
  188. package/dist/esm/run/run-settings.js.map +1 -1
  189. package/dist/esm/run/run-stream.js +4 -4
  190. package/dist/esm/run/run-stream.js.map +1 -1
  191. package/dist/esm/run/runner.js +327 -100
  192. package/dist/esm/run/runner.js.map +1 -1
  193. package/dist/esm/run/slides-cli.js +226 -0
  194. package/dist/esm/run/slides-cli.js.map +1 -0
  195. package/dist/esm/run/slides-render.js +163 -0
  196. package/dist/esm/run/slides-render.js.map +1 -0
  197. package/dist/esm/run/stdin-temp-file.js +77 -0
  198. package/dist/esm/run/stdin-temp-file.js.map +1 -0
  199. package/dist/esm/run/stream-output.js +17 -10
  200. package/dist/esm/run/stream-output.js.map +1 -1
  201. package/dist/esm/run/streaming.js +16 -16
  202. package/dist/esm/run/streaming.js.map +1 -1
  203. package/dist/esm/run/summary-engine.js +89 -57
  204. package/dist/esm/run/summary-engine.js.map +1 -1
  205. package/dist/esm/run/summary-llm.js +3 -3
  206. package/dist/esm/run/summary-llm.js.map +1 -1
  207. package/dist/esm/run/terminal.js +4 -4
  208. package/dist/esm/run/terminal.js.map +1 -1
  209. package/dist/esm/run/tips.js +2 -2
  210. package/dist/esm/run/tips.js.map +1 -1
  211. package/dist/esm/run/transcriber-cli.js +148 -0
  212. package/dist/esm/run/transcriber-cli.js.map +1 -0
  213. package/dist/esm/run.js +1 -1
  214. package/dist/esm/run.js.map +1 -1
  215. package/dist/esm/shared/contracts.js +1 -1
  216. package/dist/esm/shared/contracts.js.map +1 -1
  217. package/dist/esm/shared/sse-events.js +16 -12
  218. package/dist/esm/shared/sse-events.js.map +1 -1
  219. package/dist/esm/shared/streaming-merge.js +3 -3
  220. package/dist/esm/shared/streaming-merge.js.map +1 -1
  221. package/dist/esm/slides/extract.js +1951 -0
  222. package/dist/esm/slides/extract.js.map +1 -0
  223. package/dist/esm/slides/index.js +4 -0
  224. package/dist/esm/slides/index.js.map +1 -0
  225. package/dist/esm/slides/settings.js +73 -0
  226. package/dist/esm/slides/settings.js.map +1 -0
  227. package/dist/esm/slides/store.js +111 -0
  228. package/dist/esm/slides/store.js.map +1 -0
  229. package/dist/esm/slides/types.js +2 -0
  230. package/dist/esm/slides/types.js.map +1 -0
  231. package/dist/esm/tty/format.js +13 -13
  232. package/dist/esm/tty/format.js.map +1 -1
  233. package/dist/esm/tty/osc-progress.js +22 -2
  234. package/dist/esm/tty/osc-progress.js.map +1 -1
  235. package/dist/esm/tty/progress/fetch-html.js +20 -16
  236. package/dist/esm/tty/progress/fetch-html.js.map +1 -1
  237. package/dist/esm/tty/progress/transcript.js +127 -68
  238. package/dist/esm/tty/progress/transcript.js.map +1 -1
  239. package/dist/esm/tty/spinner.js +21 -10
  240. package/dist/esm/tty/spinner.js.map +1 -1
  241. package/dist/esm/tty/theme.js +189 -0
  242. package/dist/esm/tty/theme.js.map +1 -0
  243. package/dist/esm/tty/website-progress.js +38 -34
  244. package/dist/esm/tty/website-progress.js.map +1 -1
  245. package/dist/esm/version.js +29 -29
  246. package/dist/esm/version.js.map +1 -1
  247. package/dist/types/cache.d.ts +19 -7
  248. package/dist/types/config.d.ts +71 -6
  249. package/dist/types/content/asset.d.ts +8 -6
  250. package/dist/types/content/index.d.ts +1 -1
  251. package/dist/types/costs.d.ts +3 -3
  252. package/dist/types/daemon/agent.d.ts +25 -0
  253. package/dist/types/daemon/auto-mode.d.ts +3 -3
  254. package/dist/types/daemon/chat.d.ts +10 -18
  255. package/dist/types/daemon/cli-entrypoint.d.ts +2 -0
  256. package/dist/types/daemon/config.d.ts +2 -2
  257. package/dist/types/daemon/env-merge.d.ts +1 -1
  258. package/dist/types/daemon/env-snapshot.d.ts +1 -1
  259. package/dist/types/daemon/flow-context.d.ts +24 -4
  260. package/dist/types/daemon/launchd.d.ts +12 -0
  261. package/dist/types/daemon/models.d.ts +6 -2
  262. package/dist/types/daemon/process-registry.d.ts +73 -0
  263. package/dist/types/daemon/schtasks.d.ts +4 -0
  264. package/dist/types/daemon/server.d.ts +2 -2
  265. package/dist/types/daemon/summarize-progress.d.ts +1 -1
  266. package/dist/types/daemon/summarize.d.ts +38 -7
  267. package/dist/types/daemon/systemd.d.ts +4 -0
  268. package/dist/types/firecrawl.d.ts +1 -1
  269. package/dist/types/flags.d.ts +12 -11
  270. package/dist/types/index.d.ts +4 -4
  271. package/dist/types/language.d.ts +1 -1
  272. package/dist/types/llm/attachments.d.ts +1 -1
  273. package/dist/types/llm/cli.d.ts +3 -3
  274. package/dist/types/llm/generate-text.d.ts +7 -7
  275. package/dist/types/llm/html-to-markdown.d.ts +3 -3
  276. package/dist/types/llm/model-id.d.ts +1 -1
  277. package/dist/types/llm/prompt.d.ts +2 -2
  278. package/dist/types/llm/providers/anthropic.d.ts +3 -3
  279. package/dist/types/llm/providers/google.d.ts +3 -3
  280. package/dist/types/llm/providers/models.d.ts +2 -2
  281. package/dist/types/llm/providers/openai.d.ts +4 -4
  282. package/dist/types/llm/providers/shared.d.ts +2 -2
  283. package/dist/types/llm/transcript-to-markdown.d.ts +4 -2
  284. package/dist/types/llm/usage.d.ts +1 -1
  285. package/dist/types/logging/daemon.d.ts +4 -4
  286. package/dist/types/markitdown.d.ts +1 -1
  287. package/dist/types/media-cache.d.ts +22 -0
  288. package/dist/types/model-auto.d.ts +14 -4
  289. package/dist/types/model-spec.d.ts +10 -10
  290. package/dist/types/pricing/litellm.d.ts +1 -1
  291. package/dist/types/processes.d.ts +1 -0
  292. package/dist/types/prompts/index.d.ts +1 -1
  293. package/dist/types/run/attachments.d.ts +7 -7
  294. package/dist/types/run/bird.d.ts +7 -0
  295. package/dist/types/run/cache-state.d.ts +2 -2
  296. package/dist/types/run/cli-fallback-state.d.ts +6 -0
  297. package/dist/types/run/constants.d.ts +1 -1
  298. package/dist/types/run/cookies/twitter.d.ts +1 -1
  299. package/dist/types/run/env.d.ts +1 -1
  300. package/dist/types/run/finish-line.d.ts +7 -6
  301. package/dist/types/run/flows/asset/extract.d.ts +18 -0
  302. package/dist/types/run/flows/asset/input.d.ts +19 -3
  303. package/dist/types/run/flows/asset/media-policy.d.ts +2 -0
  304. package/dist/types/run/flows/asset/media.d.ts +21 -0
  305. package/dist/types/run/flows/asset/output.d.ts +42 -0
  306. package/dist/types/run/flows/asset/preprocess.d.ts +23 -17
  307. package/dist/types/run/flows/asset/summary.d.ts +24 -16
  308. package/dist/types/run/flows/url/extract.d.ts +3 -2
  309. package/dist/types/run/flows/url/flow.d.ts +1 -1
  310. package/dist/types/run/flows/url/markdown.d.ts +6 -6
  311. package/dist/types/run/flows/url/slides-output.d.ts +66 -0
  312. package/dist/types/run/flows/url/slides-text.d.ts +87 -0
  313. package/dist/types/run/flows/url/summary.d.ts +18 -10
  314. package/dist/types/run/flows/url/types.d.ts +52 -21
  315. package/dist/types/run/format.d.ts +3 -3
  316. package/dist/types/run/help.d.ts +4 -1
  317. package/dist/types/run/logging.d.ts +3 -2
  318. package/dist/types/run/media-cache-state.d.ts +7 -0
  319. package/dist/types/run/model-attempts.d.ts +1 -1
  320. package/dist/types/run/progress.d.ts +2 -1
  321. package/dist/types/run/run-config.d.ts +4 -4
  322. package/dist/types/run/run-context.d.ts +3 -1
  323. package/dist/types/run/run-env.d.ts +3 -1
  324. package/dist/types/run/run-input.d.ts +2 -2
  325. package/dist/types/run/run-metrics.d.ts +3 -3
  326. package/dist/types/run/run-models.d.ts +3 -2
  327. package/dist/types/run/run-output.d.ts +1 -1
  328. package/dist/types/run/run-settings.d.ts +20 -5
  329. package/dist/types/run/run-stream.d.ts +2 -2
  330. package/dist/types/run/runner.d.ts +3 -2
  331. package/dist/types/run/slides-cli.d.ts +9 -0
  332. package/dist/types/run/slides-render.d.ts +30 -0
  333. package/dist/types/run/stdin-temp-file.d.ts +9 -0
  334. package/dist/types/run/stream-output.d.ts +3 -2
  335. package/dist/types/run/streaming.d.ts +4 -4
  336. package/dist/types/run/summary-engine.d.ts +22 -12
  337. package/dist/types/run/summary-llm.d.ts +5 -5
  338. package/dist/types/run/transcriber-cli.d.ts +8 -0
  339. package/dist/types/run/types.d.ts +4 -4
  340. package/dist/types/run.d.ts +1 -1
  341. package/dist/types/shared/contracts.d.ts +2 -2
  342. package/dist/types/shared/sse-events.d.ts +26 -6
  343. package/dist/types/slides/extract.d.ts +43 -0
  344. package/dist/types/slides/index.d.ts +5 -0
  345. package/dist/types/slides/settings.d.ts +20 -0
  346. package/dist/types/slides/store.d.ts +15 -0
  347. package/dist/types/slides/types.d.ts +40 -0
  348. package/dist/types/tty/osc-progress.d.ts +5 -5
  349. package/dist/types/tty/progress/fetch-html.d.ts +5 -3
  350. package/dist/types/tty/progress/transcript.d.ts +5 -3
  351. package/dist/types/tty/spinner.d.ts +3 -1
  352. package/dist/types/tty/theme.d.ts +44 -0
  353. package/dist/types/tty/website-progress.d.ts +5 -3
  354. package/dist/types/version.d.ts +1 -1
  355. package/docs/README.md +1 -1
  356. package/docs/_config.yml +26 -0
  357. package/docs/_layouts/default.html +60 -0
  358. package/docs/agent.md +367 -0
  359. package/docs/assets/site.css +748 -0
  360. package/docs/assets/site.js +72 -0
  361. package/docs/assets/summarize-cli.png +0 -0
  362. package/docs/assets/summarize-extension.png +0 -0
  363. package/docs/assets/youtube-slides.png +0 -0
  364. package/docs/cache.md +29 -3
  365. package/docs/chrome-extension.md +72 -16
  366. package/docs/cli.md +59 -13
  367. package/docs/config.md +109 -12
  368. package/docs/extract-only.md +10 -0
  369. package/docs/index.html +224 -0
  370. package/docs/index.md +25 -0
  371. package/docs/llm.md +18 -5
  372. package/docs/manual-tests.md +2 -0
  373. package/docs/media.md +6 -2
  374. package/docs/model-auto.md +3 -2
  375. package/docs/nvidia-onnx-transcription.md +55 -0
  376. package/docs/openai.md +1 -1
  377. package/docs/releasing.md +3 -0
  378. package/docs/site/404.html +4 -1
  379. package/docs/site/assets/site.css +399 -228
  380. package/docs/site/assets/site.js +46 -46
  381. package/docs/site/assets/summarize-cli.png +0 -0
  382. package/docs/site/assets/summarize-extension.png +0 -0
  383. package/docs/site/docs/chrome-extension.html +101 -0
  384. package/docs/site/docs/config.html +30 -8
  385. package/docs/site/docs/extract-only.html +17 -4
  386. package/docs/site/docs/firecrawl.html +13 -3
  387. package/docs/site/docs/index.html +40 -6
  388. package/docs/site/docs/llm.html +20 -5
  389. package/docs/site/docs/openai.html +19 -5
  390. package/docs/site/docs/website.html +30 -9
  391. package/docs/site/docs/youtube.html +13 -3
  392. package/docs/site/index.html +168 -85
  393. package/docs/slides.md +82 -0
  394. package/docs/smoketest.md +29 -20
  395. package/docs/timestamps.md +124 -0
  396. package/docs/website.md +13 -0
  397. package/docs/youtube.md +20 -0
  398. package/package.json +57 -48
@@ -1,31 +1,164 @@
1
- import path from 'node:path';
2
- import { countTokens } from 'gpt-tokenizer';
3
- import { render as renderMarkdownAnsi } from 'markdansi';
4
- import { buildLanguageKey, buildLengthKey, buildPromptHash, buildSummaryCacheKey, extractTaggedBlock, hashString, normalizeContentForHash, } from '../../../cache.js';
5
- import { formatOutputLanguageForJson } from '../../../language.js';
6
- import { parseGatewayStyleModelId } from '../../../llm/model-id.js';
7
- import { buildAutoModelAttempts } from '../../../model-auto.js';
8
- import { buildPathSummaryPrompt } from '../../../prompts/index.js';
9
- import { ensureCliAttachmentPath, isUnsupportedAttachmentError, } from '../../attachments.js';
10
- import { parseCliUserModelId } from '../../env.js';
11
- import { writeFinishLine } from '../../finish-line.js';
12
- import { writeVerbose } from '../../logging.js';
13
- import { prepareMarkdownForTerminal } from '../../markdown.js';
14
- import { runModelAttempts } from '../../model-attempts.js';
15
- import { buildOpenRouterNoAllowedProvidersMessage } from '../../openrouter.js';
16
- import { isRichTty, markdownRenderWidth, supportsColor } from '../../terminal.js';
17
- import { prepareAssetPrompt } from './preprocess.js';
1
+ import { countTokens } from "gpt-tokenizer";
2
+ import { render as renderMarkdownAnsi } from "markdansi";
3
+ import path from "node:path";
4
+ import { buildLanguageKey, buildLengthKey, buildPromptHash, buildSummaryCacheKey, extractTaggedBlock, hashString, normalizeContentForHash, } from "../../../cache.js";
5
+ import { formatOutputLanguageForJson } from "../../../language.js";
6
+ import { parseGatewayStyleModelId } from "../../../llm/model-id.js";
7
+ import { buildAutoModelAttempts } from "../../../model-auto.js";
8
+ import { buildPathSummaryPrompt, SUMMARY_LENGTH_TARGET_CHARACTERS, SUMMARY_SYSTEM_PROMPT, } from "../../../prompts/index.js";
9
+ import { ensureCliAttachmentPath, isUnsupportedAttachmentError, } from "../../attachments.js";
10
+ import { readLastSuccessfulCliProvider, writeLastSuccessfulCliProvider, } from "../../cli-fallback-state.js";
11
+ import { parseCliUserModelId } from "../../env.js";
12
+ import { writeFinishLine } from "../../finish-line.js";
13
+ import { resolveTargetCharacters } from "../../format.js";
14
+ import { writeVerbose } from "../../logging.js";
15
+ import { prepareMarkdownForTerminal } from "../../markdown.js";
16
+ import { runModelAttempts } from "../../model-attempts.js";
17
+ import { buildOpenRouterNoAllowedProvidersMessage } from "../../openrouter.js";
18
+ import { isRichTty, markdownRenderWidth, supportsColor } from "../../terminal.js";
19
+ import { prepareAssetPrompt } from "./preprocess.js";
18
20
  const buildModelMetaFromAttempt = (attempt) => {
19
- if (attempt.transport === 'cli') {
20
- return { provider: 'cli', canonical: attempt.userModelId };
21
+ if (attempt.transport === "cli") {
22
+ return { provider: "cli", canonical: attempt.userModelId };
21
23
  }
22
24
  const parsed = parseGatewayStyleModelId(attempt.llmModelId ?? attempt.userModelId);
23
- const canonical = attempt.userModelId.toLowerCase().startsWith('openrouter/')
25
+ const canonical = attempt.userModelId.toLowerCase().startsWith("openrouter/")
24
26
  ? attempt.userModelId
25
27
  : parsed.canonical;
26
28
  return { provider: parsed.provider, canonical };
27
29
  };
30
+ function shouldBypassShortContentSummary({ ctx, textContent, }) {
31
+ if (ctx.forceSummary)
32
+ return false;
33
+ if (!textContent?.content)
34
+ return false;
35
+ const targetCharacters = resolveTargetCharacters(ctx.lengthArg, SUMMARY_LENGTH_TARGET_CHARACTERS);
36
+ if (!Number.isFinite(targetCharacters) || targetCharacters <= 0)
37
+ return false;
38
+ if (textContent.content.length > targetCharacters)
39
+ return false;
40
+ if (!ctx.json && typeof ctx.maxOutputTokensArg === "number") {
41
+ const tokenCount = countTokens(textContent.content);
42
+ if (tokenCount > ctx.maxOutputTokensArg)
43
+ return false;
44
+ }
45
+ return true;
46
+ }
47
+ async function outputBypassedAssetSummary({ ctx, args, promptText, summaryText, assetFooterParts, footerLabel, }) {
48
+ const summary = summaryText.trimEnd();
49
+ const extracted = {
50
+ kind: "asset",
51
+ source: args.sourceLabel,
52
+ mediaType: args.attachment.mediaType,
53
+ filename: args.attachment.filename,
54
+ };
55
+ if (ctx.json) {
56
+ ctx.clearProgressForStdout();
57
+ const finishReport = ctx.shouldComputeReport ? await ctx.buildReport() : null;
58
+ const input = args.sourceKind === "file"
59
+ ? {
60
+ kind: "file",
61
+ filePath: args.sourceLabel,
62
+ timeoutMs: ctx.timeoutMs,
63
+ length: ctx.lengthArg.kind === "preset"
64
+ ? { kind: "preset", preset: ctx.lengthArg.preset }
65
+ : { kind: "chars", maxCharacters: ctx.lengthArg.maxCharacters },
66
+ maxOutputTokens: ctx.maxOutputTokensArg,
67
+ model: ctx.requestedModelLabel,
68
+ language: formatOutputLanguageForJson(ctx.outputLanguage),
69
+ }
70
+ : {
71
+ kind: "asset-url",
72
+ url: args.sourceLabel,
73
+ timeoutMs: ctx.timeoutMs,
74
+ length: ctx.lengthArg.kind === "preset"
75
+ ? { kind: "preset", preset: ctx.lengthArg.preset }
76
+ : { kind: "chars", maxCharacters: ctx.lengthArg.maxCharacters },
77
+ maxOutputTokens: ctx.maxOutputTokensArg,
78
+ model: ctx.requestedModelLabel,
79
+ language: formatOutputLanguageForJson(ctx.outputLanguage),
80
+ };
81
+ const payload = {
82
+ input,
83
+ env: {
84
+ hasXaiKey: Boolean(ctx.apiStatus.xaiApiKey),
85
+ hasOpenAIKey: Boolean(ctx.apiStatus.apiKey),
86
+ hasOpenRouterKey: Boolean(ctx.apiStatus.openrouterApiKey),
87
+ hasApifyToken: Boolean(ctx.apiStatus.apifyToken),
88
+ hasFirecrawlKey: ctx.apiStatus.firecrawlConfigured,
89
+ hasGoogleKey: ctx.apiStatus.googleConfigured,
90
+ hasAnthropicKey: ctx.apiStatus.anthropicConfigured,
91
+ },
92
+ extracted,
93
+ prompt: promptText,
94
+ llm: null,
95
+ metrics: ctx.metricsEnabled ? finishReport : null,
96
+ summary,
97
+ };
98
+ ctx.stdout.write(`${JSON.stringify(payload, null, 2)}\n`);
99
+ ctx.restoreProgressAfterStdout?.();
100
+ if (ctx.metricsEnabled && finishReport) {
101
+ const costUsd = await ctx.estimateCostUsd();
102
+ writeFinishLine({
103
+ stderr: ctx.stderr,
104
+ env: ctx.envForRun,
105
+ elapsedMs: Date.now() - ctx.runStartedAtMs,
106
+ elapsedLabel: null,
107
+ model: null,
108
+ report: finishReport,
109
+ costUsd,
110
+ detailed: ctx.metricsDetailed,
111
+ extraParts: null,
112
+ color: ctx.verboseColor,
113
+ });
114
+ }
115
+ return;
116
+ }
117
+ ctx.clearProgressForStdout();
118
+ const rendered = !ctx.plain && isRichTty(ctx.stdout)
119
+ ? renderMarkdownAnsi(prepareMarkdownForTerminal(summary), {
120
+ width: markdownRenderWidth(ctx.stdout, ctx.env),
121
+ wrap: true,
122
+ color: supportsColor(ctx.stdout, ctx.envForRun),
123
+ hyperlinks: true,
124
+ })
125
+ : summary;
126
+ if (!ctx.plain && isRichTty(ctx.stdout)) {
127
+ ctx.stdout.write(`\n${rendered.replace(/^\n+/, "")}`);
128
+ }
129
+ else {
130
+ if (isRichTty(ctx.stdout))
131
+ ctx.stdout.write("\n");
132
+ ctx.stdout.write(rendered.replace(/^\n+/, ""));
133
+ }
134
+ if (!rendered.endsWith("\n")) {
135
+ ctx.stdout.write("\n");
136
+ }
137
+ ctx.restoreProgressAfterStdout?.();
138
+ if (assetFooterParts.length > 0) {
139
+ ctx.writeViaFooter([...assetFooterParts, footerLabel]);
140
+ }
141
+ const report = ctx.shouldComputeReport ? await ctx.buildReport() : null;
142
+ if (ctx.metricsEnabled && report) {
143
+ const costUsd = await ctx.estimateCostUsd();
144
+ writeFinishLine({
145
+ stderr: ctx.stderr,
146
+ env: ctx.envForRun,
147
+ elapsedMs: Date.now() - ctx.runStartedAtMs,
148
+ elapsedLabel: null,
149
+ model: null,
150
+ report,
151
+ costUsd,
152
+ detailed: ctx.metricsDetailed,
153
+ extraParts: null,
154
+ color: ctx.verboseColor,
155
+ });
156
+ }
157
+ }
28
158
  export async function summarizeAsset(ctx, args) {
159
+ const lastSuccessfulCliProvider = ctx.isFallbackModel
160
+ ? await readLastSuccessfulCliProvider(ctx.envForRun)
161
+ : null;
29
162
  const { promptText, attachments, assetFooterParts, textContent } = await prepareAssetPrompt({
30
163
  ctx: {
31
164
  env: ctx.env,
@@ -44,32 +177,48 @@ export async function summarizeAsset(ctx, args) {
44
177
  attachment: args.attachment,
45
178
  });
46
179
  const prompt = {
180
+ system: SUMMARY_SYSTEM_PROMPT,
47
181
  userText: promptText,
48
182
  ...(attachments.length > 0 ? { attachments } : {}),
49
183
  };
50
- const summaryLengthTarget = ctx.lengthArg.kind === 'preset'
184
+ const summaryLengthTarget = ctx.lengthArg.kind === "preset"
51
185
  ? ctx.lengthArg.preset
52
186
  : { maxCharacters: ctx.lengthArg.maxCharacters };
53
187
  const promptTokensForAuto = attachments.length === 0 ? countTokens(prompt.userText) : null;
54
188
  const lowerMediaType = args.attachment.mediaType.toLowerCase();
55
- const kind = lowerMediaType.startsWith('video/')
56
- ? 'video'
57
- : lowerMediaType.startsWith('image/')
58
- ? 'image'
189
+ const kind = lowerMediaType.startsWith("video/")
190
+ ? "video"
191
+ : lowerMediaType.startsWith("image/")
192
+ ? "image"
59
193
  : textContent
60
- ? 'text'
61
- : 'file';
62
- const requiresVideoUnderstanding = kind === 'video' && ctx.videoMode !== 'transcript';
63
- if (ctx.requestedModel.kind === 'auto' &&
194
+ ? "text"
195
+ : "file";
196
+ const requiresVideoUnderstanding = kind === "video" && ctx.videoMode !== "transcript";
197
+ if (ctx.isFallbackModel &&
198
+ !ctx.isNamedModelSelection &&
199
+ shouldBypassShortContentSummary({ ctx, textContent })) {
200
+ await outputBypassedAssetSummary({
201
+ ctx,
202
+ args,
203
+ promptText,
204
+ summaryText: textContent?.content ?? "",
205
+ assetFooterParts,
206
+ footerLabel: "short content",
207
+ });
208
+ return;
209
+ }
210
+ if (ctx.requestedModel.kind === "auto" &&
64
211
  !ctx.isNamedModelSelection &&
212
+ !ctx.forceSummary &&
65
213
  !ctx.json &&
66
- typeof ctx.maxOutputTokensArg === 'number' &&
214
+ typeof ctx.maxOutputTokensArg === "number" &&
67
215
  textContent &&
68
216
  countTokens(textContent.content) <= ctx.maxOutputTokensArg) {
69
217
  ctx.clearProgressForStdout();
70
218
  ctx.stdout.write(`${textContent.content.trim()}\n`);
219
+ ctx.restoreProgressAfterStdout?.();
71
220
  if (assetFooterParts.length > 0) {
72
- ctx.writeViaFooter([...assetFooterParts, 'no model']);
221
+ ctx.writeViaFooter([...assetFooterParts, "no model"]);
73
222
  }
74
223
  return;
75
224
  }
@@ -86,9 +235,12 @@ export async function summarizeAsset(ctx, args) {
86
235
  catalog,
87
236
  openrouterProvidersFromEnv: null,
88
237
  cliAvailability: ctx.cliAvailability,
238
+ isImplicitAutoSelection: ctx.isImplicitAutoSelection,
239
+ allowAutoCliFallback: ctx.allowAutoCliFallback,
240
+ lastSuccessfulCliProvider,
89
241
  });
90
242
  const mapped = all.map((attempt) => {
91
- if (attempt.transport !== 'cli')
243
+ if (attempt.transport !== "cli")
92
244
  return ctx.summaryEngine.applyZaiOverrides(attempt);
93
245
  const parsed = parseCliUserModelId(attempt.userModelId);
94
246
  return { ...attempt, cliProvider: parsed.provider, cliModel: parsed.model };
@@ -97,12 +249,12 @@ export async function summarizeAsset(ctx, args) {
97
249
  }
98
250
  /* v8 ignore next */
99
251
  if (!ctx.fixedModelSpec) {
100
- throw new Error('Internal error: missing fixed model spec');
252
+ throw new Error("Internal error: missing fixed model spec");
101
253
  }
102
- if (ctx.fixedModelSpec.transport === 'cli') {
254
+ if (ctx.fixedModelSpec.transport === "cli") {
103
255
  return [
104
256
  {
105
- transport: 'cli',
257
+ transport: "cli",
106
258
  userModelId: ctx.fixedModelSpec.userModelId,
107
259
  llmModelId: null,
108
260
  cliProvider: ctx.fixedModelSpec.cliProvider,
@@ -113,7 +265,7 @@ export async function summarizeAsset(ctx, args) {
113
265
  },
114
266
  ];
115
267
  }
116
- const openaiOverrides = ctx.fixedModelSpec.requiredEnv === 'Z_AI_API_KEY'
268
+ const openaiOverrides = ctx.fixedModelSpec.requiredEnv === "Z_AI_API_KEY"
117
269
  ? {
118
270
  openaiApiKeyOverride: ctx.apiStatus.zaiApiKey,
119
271
  openaiBaseUrlOverride: ctx.apiStatus.zaiBaseUrl,
@@ -122,7 +274,7 @@ export async function summarizeAsset(ctx, args) {
122
274
  : {};
123
275
  return [
124
276
  {
125
- transport: ctx.fixedModelSpec.transport === 'openrouter' ? 'openrouter' : 'native',
277
+ transport: ctx.fixedModelSpec.transport === "openrouter" ? "openrouter" : "native",
126
278
  userModelId: ctx.fixedModelSpec.userModelId,
127
279
  llmModelId: ctx.fixedModelSpec.llmModelId,
128
280
  openrouterProviders: ctx.fixedModelSpec.openrouterProviders,
@@ -133,11 +285,11 @@ export async function summarizeAsset(ctx, args) {
133
285
  ];
134
286
  })();
135
287
  const cliContext = await (async () => {
136
- if (!attempts.some((a) => a.transport === 'cli'))
288
+ if (!attempts.some((a) => a.transport === "cli"))
137
289
  return null;
138
290
  if (attachments.length === 0)
139
291
  return null;
140
- const needsPathPrompt = args.attachment.kind === 'image' || args.attachment.kind === 'file';
292
+ const needsPathPrompt = args.attachment.kind === "image" || args.attachment.kind === "file";
141
293
  if (!needsPathPrompt)
142
294
  return null;
143
295
  const filePath = await ensureCliAttachmentPath({
@@ -147,12 +299,12 @@ export async function summarizeAsset(ctx, args) {
147
299
  });
148
300
  const dir = path.dirname(filePath);
149
301
  const extraArgsByProvider = {
150
- gemini: ['--include-directories', dir],
151
- codex: args.attachment.kind === 'image' ? ['-i', filePath] : undefined,
302
+ gemini: ["--include-directories", dir],
303
+ codex: args.attachment.kind === "image" ? ["-i", filePath] : undefined,
152
304
  };
153
305
  return {
154
306
  promptOverride: buildPathSummaryPrompt({
155
- kindLabel: args.attachment.kind === 'image' ? 'image' : 'file',
307
+ kindLabel: args.attachment.kind === "image" ? "image" : "file",
156
308
  filePath,
157
309
  filename: args.attachment.filename,
158
310
  mediaType: args.attachment.mediaType,
@@ -167,48 +319,88 @@ export async function summarizeAsset(ctx, args) {
167
319
  extraArgsByProvider,
168
320
  };
169
321
  })();
170
- const cacheStore = ctx.cache.mode === 'default' ? ctx.cache.store : null;
171
- const contentBlock = extractTaggedBlock(promptText, 'content');
322
+ const cacheStore = ctx.cache.mode === "default" && !ctx.summaryCacheBypass ? ctx.cache.store : null;
323
+ const contentBlock = extractTaggedBlock(promptText, "content");
172
324
  const contentHash = cacheStore && contentBlock && contentBlock.trim().length > 0
173
325
  ? hashString(normalizeContentForHash(contentBlock))
174
326
  : null;
175
327
  const promptHash = cacheStore ? buildPromptHash(promptText) : null;
176
328
  const lengthKey = buildLengthKey(ctx.lengthArg);
177
329
  const languageKey = buildLanguageKey(ctx.outputLanguage);
330
+ const autoSelectionCacheModel = ctx.isFallbackModel
331
+ ? `selection:${ctx.requestedModelInput.toLowerCase()}`
332
+ : null;
178
333
  let summaryResult = null;
179
334
  let usedAttempt = null;
180
335
  let summaryFromCache = false;
181
336
  let cacheChecked = false;
182
337
  if (cacheStore && contentHash && promptHash) {
183
338
  cacheChecked = true;
184
- for (const attempt of attempts) {
185
- if (!ctx.summaryEngine.envHasKeyFor(attempt.requiredEnv))
186
- continue;
339
+ if (autoSelectionCacheModel) {
187
340
  const key = buildSummaryCacheKey({
188
341
  contentHash,
189
342
  promptHash,
190
- model: attempt.userModelId,
343
+ model: autoSelectionCacheModel,
191
344
  lengthKey,
192
345
  languageKey,
193
346
  });
194
- const cached = cacheStore.getText('summary', key);
195
- if (!cached)
196
- continue;
197
- writeVerbose(ctx.stderr, ctx.verbose, 'cache hit summary', ctx.verboseColor);
198
- args.onModelChosen?.(attempt.userModelId);
199
- summaryResult = {
200
- summary: cached,
201
- summaryAlreadyPrinted: false,
202
- modelMeta: buildModelMetaFromAttempt(attempt),
203
- maxOutputTokensForCall: null,
204
- };
205
- usedAttempt = attempt;
206
- summaryFromCache = true;
207
- break;
347
+ const cached = cacheStore.getJson("summary", key);
348
+ const cachedSummary = cached && typeof cached.summary === "string" ? cached.summary.trim() : null;
349
+ const cachedModelId = cached && typeof cached.model === "string" ? cached.model.trim() : null;
350
+ if (cachedSummary) {
351
+ const cachedAttempt = cachedModelId
352
+ ? (attempts.find((attempt) => attempt.userModelId === cachedModelId) ?? null)
353
+ : null;
354
+ const fallbackAttempt = attempts.find((attempt) => ctx.summaryEngine.envHasKeyFor(attempt.requiredEnv)) ??
355
+ attempts[0] ??
356
+ null;
357
+ const matchedAttempt = cachedAttempt && ctx.summaryEngine.envHasKeyFor(cachedAttempt.requiredEnv)
358
+ ? cachedAttempt
359
+ : fallbackAttempt;
360
+ if (matchedAttempt) {
361
+ writeVerbose(ctx.stderr, ctx.verbose, "cache hit summary (auto selection)", ctx.verboseColor, ctx.envForRun);
362
+ args.onModelChosen?.(cachedModelId || matchedAttempt.userModelId);
363
+ summaryResult = {
364
+ summary: cachedSummary,
365
+ summaryAlreadyPrinted: false,
366
+ modelMeta: buildModelMetaFromAttempt(matchedAttempt),
367
+ maxOutputTokensForCall: null,
368
+ };
369
+ usedAttempt = matchedAttempt;
370
+ summaryFromCache = true;
371
+ }
372
+ }
373
+ }
374
+ if (!summaryFromCache) {
375
+ for (const attempt of attempts) {
376
+ if (!ctx.summaryEngine.envHasKeyFor(attempt.requiredEnv))
377
+ continue;
378
+ const key = buildSummaryCacheKey({
379
+ contentHash,
380
+ promptHash,
381
+ model: attempt.userModelId,
382
+ lengthKey,
383
+ languageKey,
384
+ });
385
+ const cached = cacheStore.getText("summary", key);
386
+ if (!cached)
387
+ continue;
388
+ writeVerbose(ctx.stderr, ctx.verbose, "cache hit summary", ctx.verboseColor, ctx.envForRun);
389
+ args.onModelChosen?.(attempt.userModelId);
390
+ summaryResult = {
391
+ summary: cached,
392
+ summaryAlreadyPrinted: false,
393
+ modelMeta: buildModelMetaFromAttempt(attempt),
394
+ maxOutputTokensForCall: null,
395
+ };
396
+ usedAttempt = attempt;
397
+ summaryFromCache = true;
398
+ break;
399
+ }
208
400
  }
209
401
  }
210
402
  if (cacheChecked && !summaryFromCache) {
211
- writeVerbose(ctx.stderr, ctx.verbose, 'cache miss summary', ctx.verboseColor);
403
+ writeVerbose(ctx.stderr, ctx.verbose, "cache miss summary", ctx.verboseColor, ctx.envForRun);
212
404
  }
213
405
  let lastError = null;
214
406
  let missingRequiredEnvs = new Set();
@@ -221,10 +413,10 @@ export async function summarizeAsset(ctx, args) {
221
413
  envHasKeyFor: ctx.summaryEngine.envHasKeyFor,
222
414
  formatMissingModelError: ctx.summaryEngine.formatMissingModelError,
223
415
  onAutoSkip: (attempt) => {
224
- writeVerbose(ctx.stderr, ctx.verbose, `auto skip ${attempt.userModelId}: missing ${attempt.requiredEnv}`, ctx.verboseColor);
416
+ writeVerbose(ctx.stderr, ctx.verbose, `auto skip ${attempt.userModelId}: missing ${attempt.requiredEnv}`, ctx.verboseColor, ctx.envForRun);
225
417
  },
226
418
  onAutoFailure: (attempt, error) => {
227
- writeVerbose(ctx.stderr, ctx.verbose, `auto failed ${attempt.userModelId}: ${error instanceof Error ? error.message : String(error)}`, ctx.verboseColor);
419
+ writeVerbose(ctx.stderr, ctx.verbose, `auto failed ${attempt.userModelId}: ${error instanceof Error ? error.message : String(error)}`, ctx.verboseColor, ctx.envForRun);
228
420
  },
229
421
  onFixedModelError: (attempt, error) => {
230
422
  if (isUnsupportedAttachmentError(error)) {
@@ -255,7 +447,7 @@ export async function summarizeAsset(ctx, args) {
255
447
  };
256
448
  if (ctx.isNamedModelSelection) {
257
449
  if (lastError === null && missingRequiredEnvs.size > 0) {
258
- throw new Error(withFreeTip(`Missing ${Array.from(missingRequiredEnvs).sort().join(', ')} for --model ${ctx.requestedModelInput}.`));
450
+ throw new Error(withFreeTip(`Missing ${Array.from(missingRequiredEnvs).sort().join(", ")} for --model ${ctx.requestedModelInput}.`));
259
451
  }
260
452
  if (lastError instanceof Error) {
261
453
  if (sawOpenRouterNoAllowedProviders) {
@@ -273,29 +465,50 @@ export async function summarizeAsset(ctx, args) {
273
465
  if (textContent) {
274
466
  ctx.clearProgressForStdout();
275
467
  ctx.stdout.write(`${textContent.content.trim()}\n`);
468
+ ctx.restoreProgressAfterStdout?.();
276
469
  if (assetFooterParts.length > 0) {
277
- ctx.writeViaFooter([...assetFooterParts, 'no model']);
470
+ ctx.writeViaFooter([...assetFooterParts, "no model"]);
278
471
  }
279
472
  return;
280
473
  }
281
474
  if (lastError instanceof Error)
282
475
  throw lastError;
283
- throw new Error('No model available for this input');
476
+ throw new Error("No model available for this input");
284
477
  }
285
478
  if (!summaryFromCache && cacheStore && contentHash && promptHash) {
286
- const key = buildSummaryCacheKey({
479
+ const perModelKey = buildSummaryCacheKey({
287
480
  contentHash,
288
481
  promptHash,
289
482
  model: usedAttempt.userModelId,
290
483
  lengthKey,
291
484
  languageKey,
292
485
  });
293
- cacheStore.setText('summary', key, summaryResult.summary, ctx.cache.ttlMs);
294
- writeVerbose(ctx.stderr, ctx.verbose, 'cache write summary', ctx.verboseColor);
486
+ cacheStore.setText("summary", perModelKey, summaryResult.summary, ctx.cache.ttlMs);
487
+ writeVerbose(ctx.stderr, ctx.verbose, "cache write summary", ctx.verboseColor, ctx.envForRun);
488
+ if (autoSelectionCacheModel) {
489
+ const selectionKey = buildSummaryCacheKey({
490
+ contentHash,
491
+ promptHash,
492
+ model: autoSelectionCacheModel,
493
+ lengthKey,
494
+ languageKey,
495
+ });
496
+ cacheStore.setJson("summary", selectionKey, { summary: summaryResult.summary, model: usedAttempt.userModelId }, ctx.cache.ttlMs);
497
+ writeVerbose(ctx.stderr, ctx.verbose, "cache write summary (auto selection)", ctx.verboseColor, ctx.envForRun);
498
+ }
499
+ }
500
+ if (!summaryFromCache &&
501
+ ctx.isFallbackModel &&
502
+ usedAttempt.transport === "cli" &&
503
+ usedAttempt.cliProvider) {
504
+ await writeLastSuccessfulCliProvider({
505
+ env: ctx.envForRun,
506
+ provider: usedAttempt.cliProvider,
507
+ });
295
508
  }
296
509
  const { summary, summaryAlreadyPrinted, modelMeta, maxOutputTokensForCall } = summaryResult;
297
510
  const extracted = {
298
- kind: 'asset',
511
+ kind: "asset",
299
512
  source: args.sourceLabel,
300
513
  mediaType: args.attachment.mediaType,
301
514
  filename: args.attachment.filename,
@@ -303,25 +516,25 @@ export async function summarizeAsset(ctx, args) {
303
516
  if (ctx.json) {
304
517
  ctx.clearProgressForStdout();
305
518
  const finishReport = ctx.shouldComputeReport ? await ctx.buildReport() : null;
306
- const input = args.sourceKind === 'file'
519
+ const input = args.sourceKind === "file"
307
520
  ? {
308
- kind: 'file',
521
+ kind: "file",
309
522
  filePath: args.sourceLabel,
310
523
  timeoutMs: ctx.timeoutMs,
311
- length: ctx.lengthArg.kind === 'preset'
312
- ? { kind: 'preset', preset: ctx.lengthArg.preset }
313
- : { kind: 'chars', maxCharacters: ctx.lengthArg.maxCharacters },
524
+ length: ctx.lengthArg.kind === "preset"
525
+ ? { kind: "preset", preset: ctx.lengthArg.preset }
526
+ : { kind: "chars", maxCharacters: ctx.lengthArg.maxCharacters },
314
527
  maxOutputTokens: ctx.maxOutputTokensArg,
315
528
  model: ctx.requestedModelLabel,
316
529
  language: formatOutputLanguageForJson(ctx.outputLanguage),
317
530
  }
318
531
  : {
319
- kind: 'asset-url',
532
+ kind: "asset-url",
320
533
  url: args.sourceLabel,
321
534
  timeoutMs: ctx.timeoutMs,
322
- length: ctx.lengthArg.kind === 'preset'
323
- ? { kind: 'preset', preset: ctx.lengthArg.preset }
324
- : { kind: 'chars', maxCharacters: ctx.lengthArg.maxCharacters },
535
+ length: ctx.lengthArg.kind === "preset"
536
+ ? { kind: "preset", preset: ctx.lengthArg.preset }
537
+ : { kind: "chars", maxCharacters: ctx.lengthArg.maxCharacters },
325
538
  maxOutputTokens: ctx.maxOutputTokensArg,
326
539
  model: ctx.requestedModelLabel,
327
540
  language: formatOutputLanguageForJson(ctx.outputLanguage),
@@ -343,18 +556,20 @@ export async function summarizeAsset(ctx, args) {
343
556
  provider: modelMeta.provider,
344
557
  model: usedAttempt.userModelId,
345
558
  maxCompletionTokens: maxOutputTokensForCall,
346
- strategy: 'single',
559
+ strategy: "single",
347
560
  },
348
561
  metrics: ctx.metricsEnabled ? finishReport : null,
349
562
  summary,
350
563
  };
351
564
  ctx.stdout.write(`${JSON.stringify(payload, null, 2)}\n`);
565
+ ctx.restoreProgressAfterStdout?.();
352
566
  if (ctx.metricsEnabled && finishReport) {
353
567
  const costUsd = await ctx.estimateCostUsd();
354
568
  writeFinishLine({
355
569
  stderr: ctx.stderr,
570
+ env: ctx.envForRun,
356
571
  elapsedMs: Date.now() - ctx.runStartedAtMs,
357
- elapsedLabel: summaryFromCache ? 'Cached' : null,
572
+ elapsedLabel: summaryFromCache ? "Cached" : null,
358
573
  model: usedAttempt.userModelId,
359
574
  report: finishReport,
360
575
  costUsd,
@@ -376,16 +591,17 @@ export async function summarizeAsset(ctx, args) {
376
591
  })
377
592
  : summary;
378
593
  if (!ctx.plain && isRichTty(ctx.stdout)) {
379
- ctx.stdout.write(`\n${rendered.replace(/^\n+/, '')}`);
594
+ ctx.stdout.write(`\n${rendered.replace(/^\n+/, "")}`);
380
595
  }
381
596
  else {
382
597
  if (isRichTty(ctx.stdout))
383
- ctx.stdout.write('\n');
384
- ctx.stdout.write(rendered.replace(/^\n+/, ''));
598
+ ctx.stdout.write("\n");
599
+ ctx.stdout.write(rendered.replace(/^\n+/, ""));
385
600
  }
386
- if (!rendered.endsWith('\n')) {
387
- ctx.stdout.write('\n');
601
+ if (!rendered.endsWith("\n")) {
602
+ ctx.stdout.write("\n");
388
603
  }
604
+ ctx.restoreProgressAfterStdout?.();
389
605
  }
390
606
  ctx.writeViaFooter([...assetFooterParts, `model ${usedAttempt.userModelId}`]);
391
607
  const report = ctx.shouldComputeReport ? await ctx.buildReport() : null;
@@ -393,8 +609,9 @@ export async function summarizeAsset(ctx, args) {
393
609
  const costUsd = await ctx.estimateCostUsd();
394
610
  writeFinishLine({
395
611
  stderr: ctx.stderr,
612
+ env: ctx.envForRun,
396
613
  elapsedMs: Date.now() - ctx.runStartedAtMs,
397
- elapsedLabel: summaryFromCache ? 'Cached' : null,
614
+ elapsedLabel: summaryFromCache ? "Cached" : null,
398
615
  model: usedAttempt.userModelId,
399
616
  report,
400
617
  costUsd,