@steipete/summarize 0.9.0 → 0.10.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 (203) hide show
  1. package/CHANGELOG.md +75 -0
  2. package/LICENSE +1 -1
  3. package/README.md +307 -184
  4. package/dist/cli.js +1 -1
  5. package/dist/esm/cache.js +72 -4
  6. package/dist/esm/cache.js.map +1 -1
  7. package/dist/esm/config.js +127 -1
  8. package/dist/esm/config.js.map +1 -1
  9. package/dist/esm/daemon/agent.js +547 -0
  10. package/dist/esm/daemon/agent.js.map +1 -0
  11. package/dist/esm/daemon/chat.js +83 -175
  12. package/dist/esm/daemon/chat.js.map +1 -1
  13. package/dist/esm/daemon/cli.js +35 -3
  14. package/dist/esm/daemon/cli.js.map +1 -1
  15. package/dist/esm/daemon/env-snapshot.js +3 -0
  16. package/dist/esm/daemon/env-snapshot.js.map +1 -1
  17. package/dist/esm/daemon/flow-context.js +31 -8
  18. package/dist/esm/daemon/flow-context.js.map +1 -1
  19. package/dist/esm/daemon/launchd.js +27 -0
  20. package/dist/esm/daemon/launchd.js.map +1 -1
  21. package/dist/esm/daemon/process-registry.js +206 -0
  22. package/dist/esm/daemon/process-registry.js.map +1 -0
  23. package/dist/esm/daemon/schtasks.js +64 -0
  24. package/dist/esm/daemon/schtasks.js.map +1 -1
  25. package/dist/esm/daemon/server.js +712 -42
  26. package/dist/esm/daemon/server.js.map +1 -1
  27. package/dist/esm/daemon/summarize.js +33 -4
  28. package/dist/esm/daemon/summarize.js.map +1 -1
  29. package/dist/esm/daemon/systemd.js +61 -0
  30. package/dist/esm/daemon/systemd.js.map +1 -1
  31. package/dist/esm/flags.js +24 -0
  32. package/dist/esm/flags.js.map +1 -1
  33. package/dist/esm/llm/providers/openai.js +1 -1
  34. package/dist/esm/llm/providers/openai.js.map +1 -1
  35. package/dist/esm/media-cache.js +251 -0
  36. package/dist/esm/media-cache.js.map +1 -0
  37. package/dist/esm/processes.js +2 -0
  38. package/dist/esm/processes.js.map +1 -0
  39. package/dist/esm/run/bird.js +118 -5
  40. package/dist/esm/run/bird.js.map +1 -1
  41. package/dist/esm/run/cli-preflight.js +19 -1
  42. package/dist/esm/run/cli-preflight.js.map +1 -1
  43. package/dist/esm/run/finish-line.js +11 -4
  44. package/dist/esm/run/finish-line.js.map +1 -1
  45. package/dist/esm/run/flows/asset/extract.js +70 -0
  46. package/dist/esm/run/flows/asset/extract.js.map +1 -0
  47. package/dist/esm/run/flows/asset/input.js +208 -24
  48. package/dist/esm/run/flows/asset/input.js.map +1 -1
  49. package/dist/esm/run/flows/asset/media-policy.js +3 -0
  50. package/dist/esm/run/flows/asset/media-policy.js.map +1 -0
  51. package/dist/esm/run/flows/asset/media.js +224 -0
  52. package/dist/esm/run/flows/asset/media.js.map +1 -0
  53. package/dist/esm/run/flows/asset/output.js +98 -0
  54. package/dist/esm/run/flows/asset/output.js.map +1 -0
  55. package/dist/esm/run/flows/asset/summary.js +157 -7
  56. package/dist/esm/run/flows/asset/summary.js.map +1 -1
  57. package/dist/esm/run/flows/url/extract.js +6 -6
  58. package/dist/esm/run/flows/url/extract.js.map +1 -1
  59. package/dist/esm/run/flows/url/flow.js +336 -36
  60. package/dist/esm/run/flows/url/flow.js.map +1 -1
  61. package/dist/esm/run/flows/url/markdown.js +6 -1
  62. package/dist/esm/run/flows/url/markdown.js.map +1 -1
  63. package/dist/esm/run/flows/url/slides-output.js +485 -0
  64. package/dist/esm/run/flows/url/slides-output.js.map +1 -0
  65. package/dist/esm/run/flows/url/slides-text.js +628 -0
  66. package/dist/esm/run/flows/url/slides-text.js.map +1 -0
  67. package/dist/esm/run/flows/url/summary.js +356 -82
  68. package/dist/esm/run/flows/url/summary.js.map +1 -1
  69. package/dist/esm/run/help.js +94 -5
  70. package/dist/esm/run/help.js.map +1 -1
  71. package/dist/esm/run/logging.js +12 -4
  72. package/dist/esm/run/logging.js.map +1 -1
  73. package/dist/esm/run/media-cache-state.js +33 -0
  74. package/dist/esm/run/media-cache-state.js.map +1 -0
  75. package/dist/esm/run/progress.js +19 -1
  76. package/dist/esm/run/progress.js.map +1 -1
  77. package/dist/esm/run/run-settings.js +39 -1
  78. package/dist/esm/run/run-settings.js.map +1 -1
  79. package/dist/esm/run/runner.js +196 -8
  80. package/dist/esm/run/runner.js.map +1 -1
  81. package/dist/esm/run/slides-cli.js +225 -0
  82. package/dist/esm/run/slides-cli.js.map +1 -0
  83. package/dist/esm/run/slides-render.js +163 -0
  84. package/dist/esm/run/slides-render.js.map +1 -0
  85. package/dist/esm/run/stream-output.js +10 -3
  86. package/dist/esm/run/stream-output.js.map +1 -1
  87. package/dist/esm/run/summary-engine.js +33 -7
  88. package/dist/esm/run/summary-engine.js.map +1 -1
  89. package/dist/esm/run/transcriber-cli.js +148 -0
  90. package/dist/esm/run/transcriber-cli.js.map +1 -0
  91. package/dist/esm/shared/sse-events.js +4 -0
  92. package/dist/esm/shared/sse-events.js.map +1 -1
  93. package/dist/esm/slides/extract.js +1942 -0
  94. package/dist/esm/slides/extract.js.map +1 -0
  95. package/dist/esm/slides/index.js +4 -0
  96. package/dist/esm/slides/index.js.map +1 -0
  97. package/dist/esm/slides/settings.js +73 -0
  98. package/dist/esm/slides/settings.js.map +1 -0
  99. package/dist/esm/slides/store.js +111 -0
  100. package/dist/esm/slides/store.js.map +1 -0
  101. package/dist/esm/slides/types.js +2 -0
  102. package/dist/esm/slides/types.js.map +1 -0
  103. package/dist/esm/tty/osc-progress.js +21 -1
  104. package/dist/esm/tty/osc-progress.js.map +1 -1
  105. package/dist/esm/tty/progress/fetch-html.js +8 -4
  106. package/dist/esm/tty/progress/fetch-html.js.map +1 -1
  107. package/dist/esm/tty/progress/transcript.js +82 -31
  108. package/dist/esm/tty/progress/transcript.js.map +1 -1
  109. package/dist/esm/tty/spinner.js +2 -2
  110. package/dist/esm/tty/spinner.js.map +1 -1
  111. package/dist/esm/tty/theme.js +189 -0
  112. package/dist/esm/tty/theme.js.map +1 -0
  113. package/dist/esm/tty/website-progress.js +17 -13
  114. package/dist/esm/tty/website-progress.js.map +1 -1
  115. package/dist/esm/version.js +1 -1
  116. package/dist/esm/version.js.map +1 -1
  117. package/dist/types/cache.d.ts +14 -2
  118. package/dist/types/config.d.ts +23 -0
  119. package/dist/types/daemon/agent.d.ts +25 -0
  120. package/dist/types/daemon/chat.d.ts +10 -18
  121. package/dist/types/daemon/env-snapshot.d.ts +1 -1
  122. package/dist/types/daemon/flow-context.d.ts +21 -1
  123. package/dist/types/daemon/launchd.d.ts +4 -0
  124. package/dist/types/daemon/process-registry.d.ts +73 -0
  125. package/dist/types/daemon/schtasks.d.ts +4 -0
  126. package/dist/types/daemon/summarize.d.ts +36 -5
  127. package/dist/types/daemon/systemd.d.ts +4 -0
  128. package/dist/types/flags.d.ts +1 -0
  129. package/dist/types/media-cache.d.ts +22 -0
  130. package/dist/types/processes.d.ts +1 -0
  131. package/dist/types/run/bird.d.ts +7 -0
  132. package/dist/types/run/finish-line.d.ts +2 -1
  133. package/dist/types/run/flows/asset/extract.d.ts +18 -0
  134. package/dist/types/run/flows/asset/input.d.ts +12 -2
  135. package/dist/types/run/flows/asset/media-policy.d.ts +2 -0
  136. package/dist/types/run/flows/asset/media.d.ts +21 -0
  137. package/dist/types/run/flows/asset/output.d.ts +42 -0
  138. package/dist/types/run/flows/asset/summary.d.ts +6 -0
  139. package/dist/types/run/flows/url/extract.d.ts +2 -1
  140. package/dist/types/run/flows/url/slides-output.d.ts +66 -0
  141. package/dist/types/run/flows/url/slides-text.d.ts +87 -0
  142. package/dist/types/run/flows/url/summary.d.ts +11 -3
  143. package/dist/types/run/flows/url/types.d.ts +29 -2
  144. package/dist/types/run/help.d.ts +3 -0
  145. package/dist/types/run/logging.d.ts +3 -2
  146. package/dist/types/run/media-cache-state.d.ts +7 -0
  147. package/dist/types/run/progress.d.ts +2 -1
  148. package/dist/types/run/run-settings.d.ts +7 -1
  149. package/dist/types/run/slides-cli.d.ts +9 -0
  150. package/dist/types/run/slides-render.d.ts +30 -0
  151. package/dist/types/run/stream-output.d.ts +2 -1
  152. package/dist/types/run/summary-engine.d.ts +11 -1
  153. package/dist/types/run/transcriber-cli.d.ts +8 -0
  154. package/dist/types/shared/sse-events.d.ts +20 -0
  155. package/dist/types/slides/extract.d.ts +42 -0
  156. package/dist/types/slides/index.d.ts +5 -0
  157. package/dist/types/slides/settings.d.ts +20 -0
  158. package/dist/types/slides/store.d.ts +15 -0
  159. package/dist/types/slides/types.d.ts +40 -0
  160. package/dist/types/tty/osc-progress.d.ts +2 -2
  161. package/dist/types/tty/progress/fetch-html.d.ts +3 -1
  162. package/dist/types/tty/progress/transcript.d.ts +3 -1
  163. package/dist/types/tty/spinner.d.ts +3 -1
  164. package/dist/types/tty/theme.d.ts +44 -0
  165. package/dist/types/tty/website-progress.d.ts +3 -1
  166. package/dist/types/version.d.ts +1 -1
  167. package/docs/README.md +1 -1
  168. package/docs/_config.yml +26 -0
  169. package/docs/_layouts/default.html +60 -0
  170. package/docs/agent.md +333 -0
  171. package/docs/assets/site.css +748 -0
  172. package/docs/assets/site.js +72 -0
  173. package/docs/assets/summarize-cli.png +0 -0
  174. package/docs/assets/summarize-extension.png +0 -0
  175. package/docs/assets/youtube-slides.png +0 -0
  176. package/docs/cache.md +29 -3
  177. package/docs/chrome-extension.md +61 -11
  178. package/docs/config.md +50 -2
  179. package/docs/extract-only.md +8 -0
  180. package/docs/index.html +205 -0
  181. package/docs/index.md +25 -0
  182. package/docs/llm.md +11 -1
  183. package/docs/manual-tests.md +2 -0
  184. package/docs/media.md +3 -0
  185. package/docs/nvidia-onnx-transcription.md +55 -0
  186. package/docs/site/assets/site.css +399 -228
  187. package/docs/site/assets/summarize-cli.png +0 -0
  188. package/docs/site/assets/summarize-extension.png +0 -0
  189. package/docs/site/docs/chrome-extension.html +89 -0
  190. package/docs/site/docs/config.html +1 -0
  191. package/docs/site/docs/extract-only.html +1 -0
  192. package/docs/site/docs/firecrawl.html +1 -0
  193. package/docs/site/docs/index.html +5 -0
  194. package/docs/site/docs/llm.html +1 -0
  195. package/docs/site/docs/openai.html +1 -0
  196. package/docs/site/docs/website.html +1 -0
  197. package/docs/site/docs/youtube.html +1 -0
  198. package/docs/site/index.html +148 -84
  199. package/docs/slides.md +74 -0
  200. package/docs/timestamps.md +103 -0
  201. package/docs/website.md +12 -0
  202. package/docs/youtube.md +16 -0
  203. package/package.json +16 -15
package/README.md CHANGED
@@ -1,17 +1,93 @@
1
- # Summarize 👉 Point at any URL or file. Get the gist.
1
+ # Summarize Chrome Side Panel + CLI
2
2
 
3
- Fast CLI for summarizing *anything you can point at*:
3
+ Fast summaries from URLs, files, and media. Works in the terminal, a Chrome Side Panel and Firefox Sidebar.
4
4
 
5
- - Web pages (article extraction; Firecrawl fallback if sites block agents)
6
- - YouTube links (best-effort transcripts; can fall back to audio transcription)
7
- - Podcasts (Apple Podcasts / Spotify / RSS; prefers published transcripts when available; otherwise transcribes full episodes)
8
- - Any audio/video (local files or direct media URLs; transcribe via Whisper, then summarize)
9
- - Remote files (PDFs/images/audio/video via URL — downloaded and forwarded to the model)
10
- - Local files (PDFs/images/audio/video/text — forwarded or inlined; support depends on provider/model)
5
+ **0.10.0 preview (unreleased):** this README reflects the upcoming release.
11
6
 
12
- It streams output by default on TTY and renders Markdown to ANSI (via `markdansi`) using scrollback-safe hybrid streaming (line-by-line, but buffers fenced code blocks and tables as blocks). At the end it prints a single “Finished in …” line with timing, token usage, and a best-effort cost estimate (when pricing is available).
7
+ ## 0.10.0 preview highlights (most interesting first)
13
8
 
14
- ## Install
9
+ - Chrome Side Panel **chat** (streaming agent + history) inside the sidebar.
10
+ - **YouTube slides**: screenshots + OCR + transcript cards, timestamped seek, OCR/Transcript toggle.
11
+ - Media-aware summaries: auto‑detect video/audio vs page content.
12
+ - Streaming Markdown + metrics + cache‑aware status.
13
+ - CLI supports URLs, files, podcasts, YouTube, audio/video, PDFs.
14
+
15
+ ## Feature overview
16
+
17
+ - URLs, files, and media: web pages, PDFs, images, audio/video, YouTube, podcasts, RSS.
18
+ - Slide extraction for video sources (YouTube/direct media) with OCR + timestamped cards.
19
+ - Transcript-first media flow: published transcripts when available, Whisper fallback when not.
20
+ - Streaming output with Markdown rendering, metrics, and cache-aware status.
21
+ - Local, paid, and free models: OpenAI‑compatible local endpoints, paid providers, plus an OpenRouter free preset.
22
+ - Output modes: Markdown/text, JSON diagnostics, extract-only, metrics, timing, and cost estimates.
23
+ - Smart default: if content is shorter than the requested length, we return it as-is (use `--force-summary` to override).
24
+
25
+ ## Get the extension (recommended)
26
+
27
+ ![Summarize extension screenshot](docs/assets/summarize-extension.png)
28
+
29
+ One‑click summarizer for the current tab. Chrome Side Panel + Firefox Sidebar + local daemon for streaming Markdown.
30
+
31
+ **Chrome Web Store:** [Summarize Side Panel](https://chromewebstore.google.com/detail/summarize/cejgnmmhbbpdmjnfppjdfkocebngehfg)
32
+
33
+ YouTube slide screenshots (from the browser):
34
+
35
+ ![Summarize YouTube slide screenshots](docs/assets/youtube-slides.png)
36
+
37
+ ### Beginner quickstart (extension)
38
+
39
+ 1) Install the CLI (choose one):
40
+ - **npm** (cross‑platform): `npm i -g @steipete/summarize`
41
+ - **Homebrew** (macOS arm64): `brew install steipete/tap/summarize`
42
+ 2) Install the extension (Chrome Web Store link above) and open the Side Panel.
43
+ 3) The panel shows a token + install command. Run it in Terminal:
44
+ - `summarize daemon install --token <TOKEN>`
45
+
46
+ Why a daemon/service?
47
+ - The extension can’t run heavy extraction inside the browser. It talks to a local background service on `127.0.0.1` for fast streaming and media tools (yt‑dlp, ffmpeg, OCR, transcription).
48
+ - The service autostarts (launchd/systemd/Scheduled Task) so the Side Panel is always ready.
49
+
50
+ If you only want the **CLI**, you can skip the daemon install entirely.
51
+
52
+ Notes:
53
+
54
+ - Summarization only runs when the Side Panel is open.
55
+ - Auto mode summarizes on navigation (incl. SPAs); otherwise use the button.
56
+ - Daemon is localhost-only and requires a shared token.
57
+ - Autostart: macOS (launchd), Linux (systemd user), Windows (Scheduled Task).
58
+ - Tip: configure `free` via `summarize refresh-free` (needs `OPENROUTER_API_KEY`). Add `--set-default` to set model=`free`.
59
+
60
+ More:
61
+
62
+ - Step-by-step install: [apps/chrome-extension/README.md](apps/chrome-extension/README.md)
63
+ - Architecture + troubleshooting: [docs/chrome-extension.md](docs/chrome-extension.md)
64
+ - Firefox compatibility notes: [apps/chrome-extension/docs/firefox.md](apps/chrome-extension/docs/firefox.md)
65
+
66
+ ### Slides (extension)
67
+
68
+ - Select **Video + Slides** in the Summarize picker.
69
+ - Slides render at the top; expand to full‑width cards with timestamps.
70
+ - Click a slide to seek the video; toggle **Transcript/OCR** when OCR is significant.
71
+ - Requirements: `yt-dlp` + `ffmpeg` for extraction; `tesseract` for OCR. Missing tools show an in‑panel notice.
72
+
73
+ ### Advanced (unpacked / dev)
74
+
75
+ 1) Build + load the extension (unpacked):
76
+ - Chrome: `pnpm -C apps/chrome-extension build`
77
+ - `chrome://extensions` → Developer mode → Load unpacked
78
+ - Pick: `apps/chrome-extension/.output/chrome-mv3`
79
+ - Firefox: `pnpm -C apps/chrome-extension build:firefox`
80
+ - `about:debugging#/runtime/this-firefox` → Load Temporary Add-on
81
+ - Pick: `apps/chrome-extension/.output/firefox-mv3/manifest.json`
82
+ 2) Open Side Panel/Sidebar → copy token.
83
+ 3) Install daemon in dev mode:
84
+ - `pnpm summarize daemon install --token <TOKEN> --dev`
85
+
86
+ ## CLI
87
+
88
+ ![Summarize CLI screenshot](docs/assets/summarize-cli.png)
89
+
90
+ ### Install
15
91
 
16
92
  Requires Node 22+.
17
93
 
@@ -21,7 +97,7 @@ Requires Node 22+.
21
97
  npx -y @steipete/summarize "https://example.com"
22
98
  ```
23
99
 
24
- - npm (global install):
100
+ - npm (global):
25
101
 
26
102
  ```bash
27
103
  npm i -g @steipete/summarize
@@ -45,110 +121,95 @@ brew install steipete/tap/summarize
45
121
 
46
122
  Apple Silicon only (arm64).
47
123
 
48
- ## Quickstart
124
+ ### CLI vs extension
125
+
126
+ - **CLI only:** just install via npm/Homebrew and run `summarize ...` (no daemon needed).
127
+ - **Chrome/Firefox extension:** install the CLI **and** run `summarize daemon install --token <TOKEN>` so the Side Panel can stream results and use local tools.
128
+
129
+ ### Quickstart
49
130
 
50
131
  ```bash
51
132
  summarize "https://example.com"
52
133
  ```
53
134
 
54
- ## Chrome Extension (Side Panel)
55
-
56
- Want a one-click “always-on” summarizer in Chrome (real Side Panel, not injected UI)?
57
-
58
- This is a **Chrome extension** + a tiny local **daemon** (autostart service) that streams Markdown summaries for the **currently visible tab** into the Side Panel.
59
-
60
- - Step-by-step install (Chrome + daemon): `apps/chrome-extension/README.md`
61
- - Architecture + troubleshooting: `docs/chrome-extension.md`
62
-
63
- Quickstart (local daemon):
64
-
65
- 1) Install summarize (choose one):
66
- - `npm i -g @steipete/summarize`
67
- - `brew install steipete/tap/summarize` (macOS arm64)
68
- 2) Build + load the extension (unpacked):
69
- - `pnpm -C apps/chrome-extension build`
70
- - Chrome → `chrome://extensions` → Developer mode → “Load unpacked”
71
- - Pick: `apps/chrome-extension/.output/chrome-mv3`
72
- 3) Open the Side Panel → it shows a token + install command.
73
- 4) Run the install command in Terminal:
74
- - Installed binary: `summarize daemon install --token <TOKEN>`
75
- - Repo/dev checkout: `pnpm summarize daemon install --token <TOKEN> --dev`
76
- 5) Verify / debug:
77
- - `summarize daemon status`
78
- - `summarize daemon restart`
79
-
80
- Notes:
81
-
82
- - Summarization only runs when the Side Panel is open.
83
- - “Auto” mode summarizes on navigation (incl. SPAs); otherwise use the button.
84
- - The daemon is localhost-only and requires a shared token.
85
- - Daemon autostart: macOS (launchd), Linux (systemd user), Windows (Scheduled Task).
86
- - Tip: configure `free` via `summarize refresh-free` (requires `OPENROUTER_API_KEY`). Add `--set-default` to also set model=`free`, then set Model to `free` in extension settings.
87
-
88
- Troubleshooting:
89
-
90
- - **“Receiving end does not exist”**: Chrome didn’t inject the content script yet.
91
- - Extension details → “Site access” → set to “On all sites” (or allow this domain)
92
- - Reload the tab once.
93
- - **“Failed to fetch” / daemon unreachable**:
94
- - Run `summarize daemon status`
95
- - Check logs: `~/.summarize/logs/daemon.err.log`
135
+ ### Inputs
96
136
 
97
- Input can be a URL or a local file path:
137
+ URLs or local paths:
98
138
 
99
139
  ```bash
100
- npx -y @steipete/summarize "/path/to/file.pdf" --model google/gemini-3-flash-preview
101
- npx -y @steipete/summarize "/path/to/image.jpeg" --model google/gemini-3-flash-preview
140
+ summarize "/path/to/file.pdf" --model google/gemini-3-flash-preview
141
+ summarize "https://example.com/report.pdf" --model google/gemini-3-flash-preview
142
+ summarize "/path/to/audio.mp3"
143
+ summarize "/path/to/video.mp4"
102
144
  ```
103
145
 
104
- Remote file URLs work the same (best-effort; the file is downloaded and passed to the model):
146
+ YouTube (supports `youtube.com` and `youtu.be`):
105
147
 
106
148
  ```bash
107
- npx -y @steipete/summarize "https://example.com/report.pdf" --model google/gemini-3-flash-preview
149
+ summarize "https://youtu.be/dQw4w9WgXcQ" --youtube auto
108
150
  ```
109
151
 
110
- YouTube (supports `youtube.com` and `youtu.be`):
152
+ Podcast RSS (transcribes latest enclosure):
111
153
 
112
154
  ```bash
113
- npx -y @steipete/summarize "https://youtu.be/dQw4w9WgXcQ" --youtube auto
155
+ summarize "https://feeds.npr.org/500005/podcast.xml"
114
156
  ```
115
157
 
116
- Podcast RSS feed (transcribes latest episode enclosure):
158
+ Apple Podcasts episode page:
117
159
 
118
160
  ```bash
119
- npx -y @steipete/summarize "https://feeds.npr.org/500005/podcast.xml"
161
+ summarize "https://podcasts.apple.com/us/podcast/2424-jelly-roll/id360084272?i=1000740717432"
120
162
  ```
121
163
 
122
- Apple Podcasts episode page (extracts stream URL, transcribes via Whisper):
164
+ Spotify episode page (best-effort; may fail for exclusives):
123
165
 
124
166
  ```bash
125
- npx -y @steipete/summarize "https://podcasts.apple.com/us/podcast/2424-jelly-roll/id360084272?i=1000740717432"
167
+ summarize "https://open.spotify.com/episode/5auotqWAXhhKyb9ymCuBJY"
126
168
  ```
127
169
 
128
- Spotify episode page (best-effort; resolves to full episode via iTunes/RSS enclosure when available — not preview clips; may fail for Spotify-exclusive shows):
170
+ ### Output length
171
+
172
+ `--length` controls how much output we ask for (guideline), not a hard cap.
129
173
 
130
174
  ```bash
131
- npx -y @steipete/summarize "https://open.spotify.com/episode/5auotqWAXhhKyb9ymCuBJY"
175
+ summarize "https://example.com" --length long
176
+ summarize "https://example.com" --length 20k
132
177
  ```
133
178
 
134
- ## What file types work?
179
+ - Presets: `short|medium|long|xl|xxl`
180
+ - Character targets: `1500`, `20k`, `20000`
181
+ - Optional hard cap: `--max-output-tokens <count>` (e.g. `2000`, `2k`)
182
+ - Provider/model APIs still enforce their own maximum output limits.
183
+ - If omitted, no max token parameter is sent (provider default).
184
+ - Prefer `--length` unless you need a hard cap.
185
+ - Short content: when extracted content is shorter than the requested length, the CLI returns the content as-is.
186
+ - Override with `--force-summary` to always run the LLM.
187
+ - Minimums: `--length` numeric values must be >= 50 chars; `--max-output-tokens` must be >= 16.
188
+ - Preset targets (source of truth: `packages/core/src/prompts/summary-lengths.ts`):
189
+ - short: target ~900 chars (range 600-1,200)
190
+ - medium: target ~1,800 chars (range 1,200-2,500)
191
+ - long: target ~4,200 chars (range 2,500-6,000)
192
+ - xl: target ~9,000 chars (range 6,000-14,000)
193
+ - xxl: target ~17,000 chars (range 14,000-22,000)
135
194
 
136
- This is “best effort” and depends on what your selected model/provider accepts. In practice these usually work well:
195
+ ### What file types work?
137
196
 
138
- - `text/*` and common structured text (`.txt`, `.md`, `.json`, `.yaml`, `.xml`, …)
139
- - text-like files are **inlined into the prompt** (instead of attached as a file part) for better provider compatibility
140
- - PDFs: `application/pdf` (provider support varies; Google is the most reliable in this CLI right now)
197
+ Best effort and provider-dependent. These usually work well:
198
+
199
+ - `text/*` and common structured text (`.txt`, `.md`, `.json`, `.yaml`, `.xml`, ...)
200
+ - Text-like files are inlined into the prompt for better provider compatibility.
201
+ - PDFs: `application/pdf` (provider support varies; Google is the most reliable here)
141
202
  - Images: `image/jpeg`, `image/png`, `image/webp`, `image/gif`
142
- - Audio/Video: `audio/*`, `video/*` (when supported by the model)
203
+ - Audio/Video: `audio/*`, `video/*` (local audio/video files MP3/WAV/M4A/OGG/FLAC/MP4/MOV/WEBM automatically transcribed, when supported by the model)
143
204
 
144
205
  Notes:
145
206
 
146
- - If a provider rejects a media type, the CLI fails fast with a friendly message (no “mystery stack traces”).
147
- - xAI models currently don’t support attaching generic files (like PDFs) via the AI SDK; use a Google/OpenAI/Anthropic model for those.
207
+ - If a provider rejects a media type, the CLI fails fast with a friendly message.
208
+ - xAI models do not support attaching generic files (like PDFs) via the AI SDK; use Google/OpenAI/Anthropic for those.
148
209
 
149
- ## Model ids
210
+ ### Model ids
150
211
 
151
- Use gateway-style ids: `<provider>/<model>`.
212
+ Use gateway-style ids: `<provider>/<model>`.
152
213
 
153
214
  Examples:
154
215
 
@@ -159,104 +220,54 @@ Examples:
159
220
  - `zai/glm-4.7`
160
221
  - `openrouter/openai/gpt-5-mini` (force OpenRouter)
161
222
 
162
- Note: some models/providers don’t support streaming or certain file media types. When that happens, the CLI prints a friendly error (or auto-disables streaming for that model when supported by the provider).
163
-
164
- ## Output length
165
-
166
- `--length` controls *how much output we ask for* (guideline), not a hard truncation.
167
-
168
- ```bash
169
- npx -y @steipete/summarize "https://example.com" --length long
170
- npx -y @steipete/summarize "https://example.com" --length 20k
171
- ```
223
+ Note: some models/providers do not support streaming or certain file media types. When that happens, the CLI prints a friendly error (or auto-disables streaming for that model when supported by the provider).
172
224
 
173
- - Presets: `short|medium|long|xl|xxl`
174
- - Character targets: `1500`, `20k`, `20000`
175
- - Optional hard cap: `--max-output-tokens <count>` (e.g. `2000`, `2k`)
176
- - Provider/model APIs still enforce their own maximum output limits.
177
- - If omitted, no max token parameter is sent (provider default).
178
- - Prefer `--length` unless you need a hard cap (some providers count “reasoning” into the cap).
179
- - Minimums: `--length` numeric values must be ≥ 50 chars; `--max-output-tokens` must be ≥ 16.
180
- - Preset targets (source of truth: `packages/core/src/prompts/summary-lengths.ts`):
181
- - short: target ~900 chars (range 600-1,200)
182
- - medium: target ~1,800 chars (range 1,200-2,500)
183
- - long: target ~4,200 chars (range 2,500-6,000)
184
- - xl: target ~9,000 chars (range 6,000-14,000)
185
- - xxl: target ~17,000 chars (range 14,000-22,000)
186
-
187
- ## Limits
225
+ ### Limits
188
226
 
189
227
  - Text inputs over 10 MB are rejected before tokenization.
190
- - Text prompts are preflighted against the model’s input limit (LiteLLM catalog), using a GPT tokenizer.
228
+ - Text prompts are preflighted against the model input limit (LiteLLM catalog), using a GPT tokenizer.
191
229
 
192
- ## Common flags
230
+ ### Common flags
193
231
 
194
232
  ```bash
195
- npx -y @steipete/summarize <input> [flags]
233
+ summarize <input> [flags]
196
234
  ```
197
235
 
198
236
  Use `summarize --help` or `summarize help` for the full help text.
199
237
 
200
238
  - `--model <provider/model>`: which model to use (defaults to `auto`)
201
239
  - `--model auto`: automatic model selection + fallback (default)
202
- - `--model <name>`: use a config-defined model (see Configuration)
240
+ - `--model <name>`: use a config-defined model (see Configuration)
203
241
  - `--timeout <duration>`: `30s`, `2m`, `5000ms` (default `2m`)
204
242
  - `--retries <count>`: LLM retry attempts on timeout (default `1`)
205
243
  - `--length short|medium|long|xl|xxl|s|m|l|<chars>`
206
- - `--language, --lang <language>`: output language (`auto` = match source; or `en`, `de`, `english`, `german`, ...)
207
- - `--max-output-tokens <count>`: hard cap for LLM output tokens (optional; only sent when set)
208
- - `--cli [provider]`: use a CLI provider (case-insensitive; equivalent to `--model cli/<provider>`). If omitted, uses auto selection with CLI enabled.
244
+ - `--language, --lang <language>`: output language (`auto` = match source)
245
+ - `--max-output-tokens <count>`: hard cap for LLM output tokens
246
+ - `--cli [provider]`: use a CLI provider (`--model cli/<provider>`). If omitted, uses auto selection with CLI enabled.
209
247
  - `--stream auto|on|off`: stream LLM output (`auto` = TTY only; disabled in `--json` mode)
210
- - `--plain`: Keep raw output (no ANSI/OSC Markdown rendering)
248
+ - `--plain`: keep raw output (no ANSI/OSC Markdown rendering)
211
249
  - `--no-color`: disable ANSI colors
250
+ - `--theme <name>`: CLI theme (`aurora`, `ember`, `moss`, `mono`)
212
251
  - `--format md|text`: website/file content format (default `text`)
213
- - `--markdown-mode off|auto|llm|readability`: Markdown conversion mode (default `readability`). For websites: HTML→Markdown conversion. For YouTube transcripts: `llm` formats the raw transcript into clean Markdown (headings/paragraphs).
214
- - `--preprocess off|auto|always`: controls `uvx markitdown` usage (default `auto`; `always` forces file preprocessing)
252
+ - `--markdown-mode off|auto|llm|readability`: HTML -> Markdown mode (default `readability`)
253
+ - `--preprocess off|auto|always`: controls `uvx markitdown` usage (default `auto`)
215
254
  - Install `uvx`: `brew install uv` (or https://astral.sh/uv/)
216
- - `--extract`: print extracted content and exit (no summary) — only for URLs
255
+ - `--extract`: print extracted content and exit (URLs only)
217
256
  - Deprecated alias: `--extract-only`
257
+ - `--slides`: extract slides for YouTube/direct video URLs and render them inline in the summary narrative (auto-renders inline in supported terminals)
258
+ - `--slides-ocr`: run OCR on extracted slides (requires `tesseract`)
259
+ - `--slides-dir <dir>`: base output dir for slide images (default `./slides`)
260
+ - `--slides-scene-threshold <value>`: scene detection threshold (0.1-1.0)
261
+ - `--slides-max <count>`: maximum slides to extract (default `6`)
262
+ - `--slides-min-duration <seconds>`: minimum seconds between slides
218
263
  - `--json`: machine-readable output with diagnostics, prompt, `metrics`, and optional summary
219
264
  - `--verbose`: debug/diagnostics on stderr
220
- - `--metrics off|on|detailed`: metrics output (default `on`; `detailed` adds a compact 2nd-line breakdown on stderr)
265
+ - `--metrics off|on|detailed`: metrics output (default `on`)
221
266
 
222
- ## Verified podcast services (2025-12-25)
223
-
224
- Run: `summarize <url>`
225
-
226
- - Apple Podcasts
227
- - Spotify
228
- - Amazon Music / Audible podcast pages
229
- - Podbean
230
- - Podchaser
231
- - RSS feeds (Podcasting 2.0 transcripts when available)
232
- - Embedded YouTube podcast pages (e.g. JREPodcast)
233
-
234
- Transcription: prefers local `whisper.cpp` when installed; otherwise uses OpenAI Whisper or FAL when keys are set.
235
-
236
- ## Translation paths
237
-
238
- `--language/--lang` controls the *output language* of the summary (and other LLM-generated text). Default is `auto` (match source language).
239
-
240
- When the input is audio/video, the CLI needs a transcript first. The transcript comes from one of these paths:
241
-
242
- 1. **Existing transcript (preferred)**
243
- - YouTube: uses `youtubei` / `captionTracks` when available.
244
- - Podcasts: uses Podcasting 2.0 RSS `<podcast:transcript>` (JSON/VTT) when the feed publishes it.
245
- 2. **Whisper transcription (fallback)**
246
- - YouTube: falls back to `yt-dlp` (audio download) + Whisper transcription when configured; Apify is a last-last resort (requires `APIFY_API_TOKEN`).
247
- - Prefers local `whisper.cpp` when installed + model available.
248
- - Otherwise uses cloud Whisper (OpenAI `OPENAI_API_KEY`) or FAL (`FAL_KEY`) depending on configuration.
249
-
250
- For “any video/audio file” (local path or direct media URL), use `--video-mode transcript` to force “transcribe → summarize”:
251
-
252
- ```bash
253
- summarize /path/to/file.mp4 --video-mode transcript --lang en
254
- ```
255
-
256
- ## Auto model ordering
267
+ ### Auto model ordering
257
268
 
258
269
  `--model auto` builds candidate attempts from built-in rules (or your `model.rules` overrides).
259
- CLI tools are **not** used in auto mode unless you explicitly enable them via `cli.enabled` in config.
270
+ CLI tools are not used in auto mode unless you enable them via `cli.enabled` in config.
260
271
  Why: CLI adds ~4s latency per attempt and higher variance.
261
272
  Shortcut: `--cli` (with no provider) uses auto selection with CLI enabled.
262
273
 
@@ -280,28 +291,31 @@ Disable CLI attempts:
280
291
  }
281
292
  ```
282
293
 
283
- Note: when `cli.enabled` is set, it’s also an allowlist for explicit `--cli` / `--model cli/...`.
294
+ Note: when `cli.enabled` is set, it is also an allowlist for explicit `--cli` / `--model cli/...`.
284
295
 
285
- ## Website extraction (Firecrawl + Markdown)
296
+ ### Website extraction (Firecrawl + Markdown)
286
297
 
287
- Non-YouTube URLs go through a fetch extract pipeline. When the direct fetch/extraction is blocked or too thin, `--firecrawl auto` can fall back to Firecrawl (if configured).
298
+ Non-YouTube URLs go through a fetch -> extract pipeline. When direct fetch/extraction is blocked or too thin,
299
+ `--firecrawl auto` can fall back to Firecrawl (if configured).
288
300
 
289
301
  - `--firecrawl off|auto|always` (default `auto`)
290
302
  - `--extract --format md|text` (default `text`; if `--format` is omitted, `--extract` defaults to `md` for non-YouTube URLs)
291
- - `--markdown-mode off|auto|llm|readability` (default `readability`; for non-YouTube URLs this controls HTML→Markdown conversion)
303
+ - `--markdown-mode off|auto|llm|readability` (default `readability`)
292
304
  - `auto`: use an LLM converter when configured; may fall back to `uvx markitdown`
293
305
  - `llm`: force LLM conversion (requires a configured model key)
294
306
  - `off`: disable LLM conversion (still may return Firecrawl Markdown when configured)
295
307
  - Plain-text mode: use `--format text`.
296
308
 
297
- ## YouTube transcripts
309
+ ### YouTube transcripts
298
310
 
299
- `--youtube auto` tries best-effort web transcript endpoints first. When captions aren't available, it falls back to:
311
+ `--youtube auto` tries best-effort web transcript endpoints first. When captions are not available, it falls back to:
300
312
 
301
- 1. **Apify** (if `APIFY_API_TOKEN` is set): Uses a scraping actor (`faVsWy9VTSNVIhWpR`)
302
- 2. **yt-dlp + Whisper** (if `yt-dlp` is available): Downloads audio via yt-dlp, transcribes with local `whisper.cpp` when installed (preferred), otherwise falls back to OpenAI (`OPENAI_API_KEY`) or FAL (`FAL_KEY`)
313
+ 1. Apify (if `APIFY_API_TOKEN` is set): uses a scraping actor (`faVsWy9VTSNVIhWpR`)
314
+ 2. yt-dlp + Whisper (if `yt-dlp` is available): downloads audio, then transcribes with local `whisper.cpp` when installed
315
+ (preferred), otherwise falls back to OpenAI (`OPENAI_API_KEY`) or FAL (`FAL_KEY`)
303
316
 
304
317
  Environment variables for yt-dlp mode:
318
+
305
319
  - `YT_DLP_PATH` - optional path to yt-dlp binary (otherwise `yt-dlp` is resolved via `PATH`)
306
320
  - `SUMMARIZE_WHISPER_CPP_MODEL_PATH` - optional override for the local `whisper.cpp` model file
307
321
  - `SUMMARIZE_WHISPER_CPP_BINARY` - optional override for the local binary (default: `whisper-cli`)
@@ -311,17 +325,82 @@ Environment variables for yt-dlp mode:
311
325
 
312
326
  Apify costs money but tends to be more reliable when captions exist.
313
327
 
328
+ ### Slide extraction (YouTube + direct video URLs)
329
+
330
+ Extract slide screenshots (scene detection via `ffmpeg`) and optional OCR:
331
+
332
+ ```bash
333
+ summarize "https://www.youtube.com/watch?v=..." --slides
334
+ summarize "https://www.youtube.com/watch?v=..." --slides --slides-ocr
335
+ ```
336
+
337
+ Outputs are written under `./slides/<sourceId>/` (or `--slides-dir`). OCR results are included in JSON output
338
+ (`--json`) and stored in `slides.json` inside the slide directory. When scene detection is too sparse, the
339
+ extractor also samples at a fixed interval to improve coverage.
340
+ When using `--slides`, supported terminals (kitty/iTerm/Konsole) render inline thumbnails automatically inside the
341
+ summary narrative (the model inserts `[slide:N]` markers). Timestamp links are clickable when the terminal supports
342
+ OSC-8 (YouTube/Vimeo/Loom/Dropbox). If inline images are unsupported, Summarize prints a note with the on-disk
343
+ slide directory.
344
+
345
+ Use `--slides --extract` to print the full timed transcript and insert slide images inline at matching timestamps.
346
+
314
347
  Format the extracted transcript as Markdown (headings + paragraphs) via an LLM:
315
348
 
316
349
  ```bash
317
350
  summarize "https://www.youtube.com/watch?v=..." --extract --format md --markdown-mode llm
318
351
  ```
319
352
 
320
- ## Media transcription (Whisper)
353
+ ### Media transcription (Whisper)
354
+
355
+ Local audio/video files are transcribed first, then summarized. `--video-mode transcript` forces
356
+ direct media URLs (and embedded media) through Whisper first. Prefers local `whisper.cpp` when available; otherwise requires
357
+ `OPENAI_API_KEY` or `FAL_KEY`.
321
358
 
322
- `--video-mode transcript` forces audio/video inputs (local files or direct media URLs) through Whisper first, then summarizes the transcript text. Prefers local `whisper.cpp` when available; otherwise requires `OPENAI_API_KEY` or `FAL_KEY`.
359
+ ### Local ONNX transcription (Parakeet/Canary)
323
360
 
324
- ## Configuration
361
+ Summarize can use NVIDIA Parakeet/Canary ONNX models via a local CLI you provide. Auto selection (default) prefers ONNX when configured.
362
+
363
+ - Setup helper: `summarize transcriber setup`
364
+ - Install `sherpa-onnx` from upstream binaries/build (Homebrew may not have a formula)
365
+ - Auto selection: set `SUMMARIZE_ONNX_PARAKEET_CMD` or `SUMMARIZE_ONNX_CANARY_CMD` (no flag needed)
366
+ - Force a model: `--transcriber parakeet|canary|whisper|auto`
367
+ - Docs: `docs/nvidia-onnx-transcription.md`
368
+
369
+ ### Verified podcast services (2025-12-25)
370
+
371
+ Run: `summarize <url>`
372
+
373
+ - Apple Podcasts
374
+ - Spotify
375
+ - Amazon Music / Audible podcast pages
376
+ - Podbean
377
+ - Podchaser
378
+ - RSS feeds (Podcasting 2.0 transcripts when available)
379
+ - Embedded YouTube podcast pages (e.g. JREPodcast)
380
+
381
+ Transcription: prefers local `whisper.cpp` when installed; otherwise uses OpenAI Whisper or FAL when keys are set.
382
+
383
+ ### Translation paths
384
+
385
+ `--language/--lang` controls the output language of the summary (and other LLM-generated text). Default is `auto`.
386
+
387
+ When the input is audio/video, the CLI needs a transcript first. The transcript comes from one of these paths:
388
+
389
+ 1. Existing transcript (preferred)
390
+ - YouTube: uses `youtubei` / `captionTracks` when available.
391
+ - Podcasts: uses Podcasting 2.0 RSS `<podcast:transcript>` (JSON/VTT) when the feed publishes it.
392
+ 2. Whisper transcription (fallback)
393
+ - YouTube: falls back to yt-dlp (audio download) + Whisper transcription when configured; Apify is a last resort.
394
+ - Prefers local `whisper.cpp` when installed + model available.
395
+ - Otherwise uses cloud Whisper (OpenAI `OPENAI_API_KEY`) or FAL (`FAL_KEY`).
396
+
397
+ For direct media URLs, use `--video-mode transcript` to force transcribe -> summarize:
398
+
399
+ ```bash
400
+ summarize https://example.com/file.mp4 --video-mode transcript --lang en
401
+ ```
402
+
403
+ ### Configuration
325
404
 
326
405
  Single config location:
327
406
 
@@ -331,7 +410,8 @@ Supported keys today:
331
410
 
332
411
  ```json
333
412
  {
334
- "model": { "id": "openai/gpt-5-mini" }
413
+ "model": { "id": "openai/gpt-5-mini" },
414
+ "ui": { "theme": "ember" }
335
415
  }
336
416
  ```
337
417
 
@@ -345,14 +425,28 @@ Shorthand (equivalent):
345
425
 
346
426
  Also supported:
347
427
 
348
- - `model: { "mode": "auto" }` (automatic model selection + fallback; see `docs/model-auto.md`)
428
+ - `model: { "mode": "auto" }` (automatic model selection + fallback; see [docs/model-auto.md](docs/model-auto.md))
349
429
  - `model.rules` (customize candidates / ordering)
350
430
  - `models` (define presets selectable via `--model <preset>`)
431
+ - `cache.media` (media download cache: TTL 7 days, 2048 MB cap by default; `--no-media-cache` disables)
351
432
  - `media.videoMode: "auto"|"transcript"|"understand"`
433
+ - `slides.enabled` / `slides.max` / `slides.ocr` / `slides.dir` (defaults for `--slides`)
434
+ - `ui.theme: "aurora"|"ember"|"moss"|"mono"`
352
435
  - `openai.useChatCompletions: true` (force OpenAI-compatible chat completions)
353
436
 
354
- Note: the config is parsed leniently (JSON5), but **comments are not allowed**.
355
- Unknown keys are ignored.
437
+ Note: the config is parsed leniently (JSON5), but comments are not allowed. Unknown keys are ignored.
438
+
439
+ Media cache defaults:
440
+
441
+ ```json
442
+ {
443
+ "cache": {
444
+ "media": { "enabled": true, "ttlDays": 7, "maxMb": 2048, "verify": "size" }
445
+ }
446
+ }
447
+ ```
448
+
449
+ Note: `--no-cache` bypasses summary caching only (LLM output). Extract/transcript caches still apply. Use `--no-media-cache` to skip media files.
356
450
 
357
451
  Precedence:
358
452
 
@@ -361,7 +455,14 @@ Precedence:
361
455
  3) `~/.summarize/config.json`
362
456
  4) default (`auto`)
363
457
 
364
- ## Environment variables
458
+ Theme precedence:
459
+
460
+ 1) `--theme`
461
+ 2) `SUMMARIZE_THEME`
462
+ 3) `~/.summarize/config.json` (`ui.theme`)
463
+ 4) default (`aurora`)
464
+
465
+ ### Environment variables
365
466
 
366
467
  Set the key matching your chosen `--model`:
367
468
 
@@ -369,43 +470,44 @@ Set the key matching your chosen `--model`:
369
470
  - `ANTHROPIC_API_KEY` (for `anthropic/...`)
370
471
  - `XAI_API_KEY` (for `xai/...`)
371
472
  - `Z_AI_API_KEY` (for `zai/...`; supports `ZAI_API_KEY` alias)
372
- - `GEMINI_API_KEY` (for `google/...`)
473
+ - `GEMINI_API_KEY` (for `google/...`)
373
474
  - also accepts `GOOGLE_GENERATIVE_AI_API_KEY` and `GOOGLE_API_KEY` as aliases
374
475
 
375
476
  OpenAI-compatible chat completions toggle:
376
477
 
377
478
  - `OPENAI_USE_CHAT_COMPLETIONS=1` (or set `openai.useChatCompletions` in config)
378
479
 
480
+ UI theme:
481
+
482
+ - `SUMMARIZE_THEME=aurora|ember|moss|mono`
483
+ - `SUMMARIZE_TRUECOLOR=1` (force 24-bit ANSI)
484
+ - `SUMMARIZE_NO_TRUECOLOR=1` (disable 24-bit ANSI)
485
+
379
486
  OpenRouter (OpenAI-compatible):
380
487
 
381
488
  - Set `OPENROUTER_API_KEY=...`
382
- - Prefer forcing OpenRouter per model id: `--model openrouter/<author>/<slug>` (e.g. `openrouter/meta-llama/llama-3.1-8b-instruct:free`)
383
- - Built-in preset: `--model free` (uses a default set of OpenRouter `:free` models).
489
+ - Prefer forcing OpenRouter per model id: `--model openrouter/<author>/<slug>`
490
+ - Built-in preset: `--model free` (uses a default set of OpenRouter `:free` models)
384
491
 
385
492
  ### `summarize refresh-free`
386
493
 
387
494
  Quick start: make free the default (keep `auto` available)
388
495
 
389
496
  ```bash
390
- # writes ~/.summarize/config.json (models.free) and sets model="free"
391
497
  summarize refresh-free --set-default
392
-
393
- # now this defaults to free models
394
498
  summarize "https://example.com"
395
-
396
- # whenever you want best quality instead
397
499
  summarize "https://example.com" --model auto
398
500
  ```
399
501
 
400
- Regenerates the `free` preset (writes `models.free` into `~/.summarize/config.json`) by:
502
+ Regenerates the `free` preset (`models.free` in `~/.summarize/config.json`) by:
401
503
 
402
504
  - Fetching OpenRouter `/models`, filtering `:free`
403
- - Skipping models that look very small (<27B by default) based on the model id/name (best-effort heuristic)
505
+ - Skipping models that look very small (<27B by default) based on the model id/name
404
506
  - Testing which ones return non-empty text (concurrency 4, timeout 10s)
405
- - Picking a mix of smart-ish (bigger `context_length` / output cap) and fast models
406
- - Refining timings for the final selection and writing the sorted list back
507
+ - Picking a mix of smart-ish (bigger `context_length` / output cap) and fast models
508
+ - Refining timings and writing the sorted list back
407
509
 
408
- If `--model free` stops working (rate limits, allowed-provider restrictions, models removed), run:
510
+ If `--model free` stops working, run:
409
511
 
410
512
  ```bash
411
513
  summarize refresh-free
@@ -414,7 +516,7 @@ summarize refresh-free
414
516
  Flags:
415
517
 
416
518
  - `--runs 2` (default): extra timing runs per selected model (total runs = 1 + runs)
417
- - `--smart 3` (default): how many smart-first picks (rest filled by fastest)
519
+ - `--smart 3` (default): how many smart-first picks (rest filled by fastest)
418
520
  - `--min-params 27b` (default): ignore models with inferred size smaller than N billion parameters
419
521
  - `--max-age-days 180` (default): ignore models older than N days (set 0 to disable)
420
522
  - `--set-default`: also sets `"model": "free"` in `~/.summarize/config.json`
@@ -426,7 +528,7 @@ OPENROUTER_API_KEY=sk-or-... summarize "https://example.com" --model openrouter/
426
528
  ```
427
529
 
428
530
  If your OpenRouter account enforces an allowed-provider list, make sure at least one provider
429
- is allowed for the selected model. (When routing fails, `summarize` prints the exact providers to allow.)
531
+ is allowed for the selected model. When routing fails, `summarize` prints the exact providers to allow.
430
532
 
431
533
  Legacy: `OPENAI_BASE_URL=https://openrouter.ai/api/v1` (and either `OPENAI_API_KEY` or `OPENROUTER_API_KEY`) also works.
432
534
 
@@ -442,14 +544,14 @@ Optional services:
442
544
  - `FAL_KEY` (FAL AI API key for audio transcription via Whisper)
443
545
  - `APIFY_API_TOKEN` (YouTube transcript fallback)
444
546
 
445
- ## Model limits
547
+ ### Model limits
446
548
 
447
549
  The CLI uses the LiteLLM model catalog for model limits (like max output tokens):
448
550
 
449
551
  - Downloaded from: `https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json`
450
552
  - Cached at: `~/.summarize/cache/`
451
553
 
452
- ## Library usage (optional)
554
+ ### Library usage (optional)
453
555
 
454
556
  Recommended (minimal deps):
455
557
 
@@ -461,9 +563,30 @@ Compatibility (pulls in CLI deps):
461
563
  - `@steipete/summarize/content`
462
564
  - `@steipete/summarize/prompts`
463
565
 
464
- ## Development
566
+ ### Development
465
567
 
466
568
  ```bash
467
569
  pnpm install
468
570
  pnpm check
469
571
  ```
572
+
573
+ ## More
574
+
575
+ - Docs index: [docs/README.md](docs/README.md)
576
+ - CLI providers and config: [docs/cli.md](docs/cli.md)
577
+ - Auto model rules: [docs/model-auto.md](docs/model-auto.md)
578
+ - Website extraction: [docs/website.md](docs/website.md)
579
+ - YouTube handling: [docs/youtube.md](docs/youtube.md)
580
+ - Media pipeline: [docs/media.md](docs/media.md)
581
+ - Config schema and precedence: [docs/config.md](docs/config.md)
582
+
583
+ ## Troubleshooting
584
+
585
+ - "Receiving end does not exist": Chrome did not inject the content script yet.
586
+ - Extension details -> Site access -> On all sites (or allow this domain)
587
+ - Reload the tab once.
588
+ - "Failed to fetch" / daemon unreachable:
589
+ - `summarize daemon status`
590
+ - Logs: `~/.summarize/logs/daemon.err.log`
591
+
592
+ License: MIT