@steipete/summarize 0.4.0 → 0.5.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 (82) hide show
  1. package/CHANGELOG.md +73 -5
  2. package/README.md +116 -18
  3. package/dist/cli.cjs +8136 -4368
  4. package/dist/cli.cjs.map +4 -4
  5. package/dist/esm/cli-main.js +47 -2
  6. package/dist/esm/cli-main.js.map +1 -1
  7. package/dist/esm/config.js +368 -3
  8. package/dist/esm/config.js.map +1 -1
  9. package/dist/esm/content/link-preview/content/index.js +13 -0
  10. package/dist/esm/content/link-preview/content/index.js.map +1 -1
  11. package/dist/esm/content/link-preview/content/utils.js +3 -1
  12. package/dist/esm/content/link-preview/content/utils.js.map +1 -1
  13. package/dist/esm/content/link-preview/content/video.js +96 -0
  14. package/dist/esm/content/link-preview/content/video.js.map +1 -0
  15. package/dist/esm/content/link-preview/transcript/providers/youtube/captions.js +21 -21
  16. package/dist/esm/content/link-preview/transcript/providers/youtube/captions.js.map +1 -1
  17. package/dist/esm/costs.js.map +1 -1
  18. package/dist/esm/flags.js +23 -0
  19. package/dist/esm/flags.js.map +1 -1
  20. package/dist/esm/generate-free.js +616 -0
  21. package/dist/esm/generate-free.js.map +1 -0
  22. package/dist/esm/llm/cli.js +290 -0
  23. package/dist/esm/llm/cli.js.map +1 -0
  24. package/dist/esm/llm/generate-text.js +159 -105
  25. package/dist/esm/llm/generate-text.js.map +1 -1
  26. package/dist/esm/llm/html-to-markdown.js +4 -2
  27. package/dist/esm/llm/html-to-markdown.js.map +1 -1
  28. package/dist/esm/model-auto.js +353 -0
  29. package/dist/esm/model-auto.js.map +1 -0
  30. package/dist/esm/model-spec.js +82 -0
  31. package/dist/esm/model-spec.js.map +1 -0
  32. package/dist/esm/prompts/cli.js +18 -0
  33. package/dist/esm/prompts/cli.js.map +1 -0
  34. package/dist/esm/prompts/file.js +4 -4
  35. package/dist/esm/prompts/file.js.map +1 -1
  36. package/dist/esm/prompts/index.js +1 -0
  37. package/dist/esm/prompts/index.js.map +1 -1
  38. package/dist/esm/prompts/link-summary.js +3 -8
  39. package/dist/esm/prompts/link-summary.js.map +1 -1
  40. package/dist/esm/refresh-free.js +667 -0
  41. package/dist/esm/refresh-free.js.map +1 -0
  42. package/dist/esm/run.js +1384 -532
  43. package/dist/esm/run.js.map +1 -1
  44. package/dist/esm/version.js +1 -1
  45. package/dist/types/config.d.ts +58 -5
  46. package/dist/types/content/link-preview/content/types.d.ts +10 -0
  47. package/dist/types/content/link-preview/content/utils.d.ts +1 -1
  48. package/dist/types/content/link-preview/content/video.d.ts +5 -0
  49. package/dist/types/costs.d.ts +2 -1
  50. package/dist/types/flags.d.ts +3 -0
  51. package/dist/types/generate-free.d.ts +17 -0
  52. package/dist/types/llm/cli.d.ts +24 -0
  53. package/dist/types/llm/generate-text.d.ts +13 -4
  54. package/dist/types/llm/html-to-markdown.d.ts +9 -3
  55. package/dist/types/model-auto.d.ts +23 -0
  56. package/dist/types/model-spec.d.ts +33 -0
  57. package/dist/types/prompts/cli.d.ts +8 -0
  58. package/dist/types/prompts/index.d.ts +1 -0
  59. package/dist/types/refresh-free.d.ts +19 -0
  60. package/dist/types/version.d.ts +1 -1
  61. package/docs/README.md +3 -0
  62. package/docs/cli.md +95 -0
  63. package/docs/config.md +123 -1
  64. package/docs/llm.md +24 -4
  65. package/docs/manual-tests.md +40 -0
  66. package/docs/model-auto.md +92 -0
  67. package/docs/site/assets/site.js +20 -17
  68. package/docs/smoketest.md +58 -0
  69. package/docs/website.md +3 -1
  70. package/package.json +8 -4
  71. package/dist/esm/content/link-preview/transcript/providers/twitter.js +0 -12
  72. package/dist/esm/content/link-preview/transcript/providers/twitter.js.map +0 -1
  73. package/dist/esm/content/link-preview/transcript/providers/youtube/ytdlp.js +0 -114
  74. package/dist/esm/content/link-preview/transcript/providers/youtube/ytdlp.js.map +0 -1
  75. package/dist/esm/summarizeHome.js +0 -20
  76. package/dist/esm/summarizeHome.js.map +0 -1
  77. package/dist/esm/tty/live-markdown.js +0 -52
  78. package/dist/esm/tty/live-markdown.js.map +0 -1
  79. package/dist/types/content/link-preview/transcript/providers/twitter.d.ts +0 -3
  80. package/dist/types/content/link-preview/transcript/providers/youtube/ytdlp.d.ts +0 -3
  81. package/dist/types/summarizeHome.d.ts +0 -6
  82. package/dist/types/tty/live-markdown.d.ts +0 -10
package/CHANGELOG.md CHANGED
@@ -1,11 +1,80 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.5.0 - 2025-12-24
4
+
5
+ ### Features
6
+
7
+ - **Model selection & presets**
8
+ - Automatic model selection (`--model auto`, now the default):
9
+ - Chooses models based on input kind (website/YouTube/file/image/video/text) and prompt size.
10
+ - Skips candidates without API keys; retries next model on request errors.
11
+ - Adds OpenRouter fallback attempts when `OPENROUTER_API_KEY` is present.
12
+ - Shows the chosen model in the progress UI.
13
+ - Named model presets via config (`~/.summarize/config.json` → `models`), selectable as `--model <preset>`.
14
+ - Built-in preset: `--model free` (OpenRouter `:free` candidates; override via `models.free`).
15
+ - **OpenRouter free preset maintenance**
16
+ - `summarize refresh-free` regenerates `models.free` by scanning OpenRouter `:free` models and testing availability + latency.
17
+ - `summarize refresh-free --set-default` also sets `"model": "free"` in `~/.summarize/config.json` (so free becomes your default).
18
+ - **CLI models**
19
+ - Add `--cli <provider>` flag (equivalent to `--model cli/<provider>`).
20
+ - `--cli` accepts case-insensitive providers and can be used without a provider to enable CLI auto selection.
21
+ - **Content extraction**
22
+ - Website extraction detects video-only pages:
23
+ - YouTube embeds switch to transcript extraction automatically.
24
+ - Direct video URLs can be downloaded + summarized when `--video-mode auto|understand` and a Gemini key is available.
25
+ - **Env**
26
+ - `.env` in the current directory is loaded automatically (so API keys work without exporting env vars).
27
+
28
+ ### Changes
29
+
30
+ - **CLI config**
31
+ - Auto mode uses CLI models only when `cli.enabled` is set; order follows the list.
32
+ - `cli.enabled` is an allowlist for CLI usage.
33
+ - **OpenRouter**
34
+ - Stop sending extra routing headers.
35
+ - `--model free`: when OpenRouter rejects routing with “No allowed providers”, print the exact provider names to allow and suggest running `summarize refresh-free`.
36
+ - `--max-output-tokens`: when explicitly set, it is also forwarded to OpenRouter calls.
37
+ - **Refresh Free**
38
+ - Default extra runs reduced to 2 (total runs = 1 + runs) to reduce rate-limit pressure.
39
+ - Filter `:free` candidates by recency (default: last 180 days; configurable via `--max-age-days`).
40
+ - Print `ctx`/`out` in `k` units for readability.
41
+ - **Defaults**
42
+ - Default summary length is now `xl`.
43
+
44
+ ### Fixes
45
+
46
+ - **LLM / OpenRouter**
47
+ - LLM request retries (`--retries`) and clearer timeout errors.
48
+ - `summarize refresh-free`: detect OpenRouter free-model rate limits and back off + retry.
49
+ - **Streaming**
50
+ - Normalize + de-dupe overlapping chunks to prevent repeated sections in live Markdown output.
51
+ - **YouTube**
52
+ - Prefer manual captions over auto-generated when both exist. Thanks @dougvk.
53
+ - Always summarize YouTube transcripts in auto mode (instead of printing the transcript).
54
+ - **Prompting & metrics**
55
+ - Don’t “pad” beyond input length when asking for longer summaries.
56
+ - `--metrics detailed`: fold metrics into finish line and make labels less cryptic.
57
+
58
+ ### Docs
59
+
60
+ - Add documentation for presets and Refresh Free.
61
+ - Add a “make free the default” quick start for `summarize refresh-free --set-default`.
62
+ - Add a manual end-to-end checklist (`docs/manual-tests.md`).
63
+ - Add a quick CLI smoke checklist (`docs/smoketest.md`).
64
+ - Document CLI ordering and model selection behavior.
65
+
66
+ ### Tests
67
+
68
+ - Add coverage for presets and Refresh Free regeneration.
69
+ - Add live coverage for the `free` preset.
70
+ - Add regression coverage for YouTube transcript handling and metrics formatting.
71
+
3
72
  ## 0.4.0 - 2025-12-21
4
73
 
5
74
  ### Changes
6
75
 
7
- - Add URL extraction mode via `--extract` (deprecated alias: `--extract-only`) with `--format md|text`.
8
- - Rename HTML→Markdown conversion flag to `--markdown-mode` (deprecated alias: `--markdown`).
76
+ - Add URL extraction mode via `--extract` with `--format md|text`.
77
+ - Rename HTML→Markdown conversion flag to `--markdown-mode`.
9
78
  - Add `--preprocess off|auto|always` and a `uvx markitdown` fallback for Markdown extraction and unsupported file attachments (when `--format md` is used).
10
79
 
11
80
  ## 0.3.0 - 2025-12-20
@@ -16,7 +85,6 @@
16
85
  - Run yt-dlp after web + Apify in `--youtube auto`, and error early for missing keys in `--youtube yt-dlp`.
17
86
  - Require Node 22+.
18
87
  - Respect `OPENAI_BASE_URL` when set, even with OpenRouter keys.
19
- - Apply OpenRouter provider ordering headers to HTML→Markdown conversion.
20
88
  - Add OpenRouter configuration tests. Thanks @dougvk for the initial OpenRouter support.
21
89
  - Build and ship a Bun bytecode arm64 binary for Homebrew.
22
90
 
@@ -33,7 +101,7 @@
33
101
 
34
102
  ### Changes
35
103
 
36
- - Add native OpenRouter support via `OPENROUTER_API_KEY` with optional provider ordering (`OPENROUTER_PROVIDERS`).
104
+ - Add native OpenRouter support via `OPENROUTER_API_KEY`.
37
105
  - Remove map-reduce summarization; reject inputs that exceed the model's context window.
38
106
  - Preflight text prompts with the GPT tokenizer and the model’s max input tokens.
39
107
  - Reject text files over 10 MB before tokenization.
@@ -101,7 +169,7 @@ First public release.
101
169
  - `--max-output-tokens <count>` (optional hard cap)
102
170
  - `--timeout <duration>` (default `2m`)
103
171
  - `--stream auto|on|off`, `--render auto|md-live|md|plain`
104
- - `--extract` (URLs only; no summary; deprecated alias: `--extract-only`)
172
+ - `--extract` (URLs only; no summary)
105
173
  - `--json` (structured output incl. input config, prompt, extracted content, LLM metadata, and metrics)
106
174
  - `--metrics off|on|detailed` (default `on`)
107
175
  - `--verbose`
package/README.md CHANGED
@@ -16,7 +16,13 @@ Requires Node 22+.
16
16
  - npx (no install):
17
17
 
18
18
  ```bash
19
- npx -y @steipete/summarize "https://example.com" --model google/gemini-3-flash-preview
19
+ npx -y @steipete/summarize "https://example.com"
20
+ ```
21
+
22
+ - npm (global install):
23
+
24
+ ```bash
25
+ npm i -g @steipete/summarize
20
26
  ```
21
27
 
22
28
  - Homebrew (custom tap):
@@ -30,7 +36,7 @@ Apple Silicon only (arm64).
30
36
  ## Quickstart
31
37
 
32
38
  ```bash
33
- summarize "https://example.com" --model google/gemini-3-flash-preview
39
+ summarize "https://example.com"
34
40
  ```
35
41
 
36
42
  Input can be a URL or a local file path:
@@ -73,10 +79,11 @@ Use “gateway-style” ids: `<provider>/<model>`.
73
79
 
74
80
  Examples:
75
81
 
76
- - `openai/gpt-5.2`
77
- - `anthropic/claude-opus-4-5`
82
+ - `openai/gpt-5-mini`
83
+ - `anthropic/claude-sonnet-4-5`
78
84
  - `xai/grok-4-fast-non-reasoning`
79
85
  - `google/gemini-3-flash-preview`
86
+ - `openrouter/openai/gpt-5-mini` (force OpenRouter)
80
87
 
81
88
  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).
82
89
 
@@ -93,6 +100,8 @@ npx -y @steipete/summarize "https://example.com" --length 20k
93
100
  - Character targets: `1500`, `20k`, `20000`
94
101
  - Optional hard cap: `--max-output-tokens <count>` (e.g. `2000`, `2k`)
95
102
  - Provider/model APIs still enforce their own maximum output limits.
103
+ - If omitted, no max token parameter is sent (provider default).
104
+ - Prefer `--length` unless you need a hard cap (some providers count “reasoning” into the cap).
96
105
  - Minimums: `--length` numeric values must be ≥ 50 chars; `--max-output-tokens` must be ≥ 16.
97
106
 
98
107
  ## Limits
@@ -106,19 +115,53 @@ npx -y @steipete/summarize "https://example.com" --length 20k
106
115
  npx -y @steipete/summarize <input> [flags]
107
116
  ```
108
117
 
109
- - `--model <provider/model>`: which model to use (defaults to `google/gemini-3-flash-preview`)
118
+ - `--model <provider/model>`: which model to use (defaults to `auto`)
119
+ - `--model auto`: automatic model selection + fallback (default)
120
+ - `--model <name>`: use a config-defined model (see “Configuration”)
110
121
  - `--timeout <duration>`: `30s`, `2m`, `5000ms` (default `2m`)
122
+ - `--retries <count>`: LLM retry attempts on timeout (default `1`)
111
123
  - `--length short|medium|long|xl|xxl|<chars>`
112
- - `--max-output-tokens <count>`: hard cap for LLM output tokens (optional)
124
+ - `--max-output-tokens <count>`: hard cap for LLM output tokens (optional; only sent when set)
125
+ - `--cli [provider]`: use a CLI provider (case-insensitive; equivalent to `--model cli/<provider>`). If omitted, uses auto selection with CLI enabled.
113
126
  - `--stream auto|on|off`: stream LLM output (`auto` = TTY only; disabled in `--json` mode)
114
127
  - `--render auto|md-live|md|plain`: Markdown rendering (`auto` = best default for TTY)
115
128
  - `--format md|text`: website/file content format (default `text`)
116
- - `--preprocess off|auto|always`: preprocess files (only with `--format md`) for model compatibility (default `auto`)
129
+ - `--preprocess off|auto|always`: controls `uvx markitdown` usage (default `auto`; `always` forces file preprocessing)
130
+ - Install `uvx`: `brew install uv` (or https://astral.sh/uv/)
117
131
  - `--extract`: print extracted content and exit (no summary) — only for URLs
118
132
  - Deprecated alias: `--extract-only`
119
133
  - `--json`: machine-readable output with diagnostics, prompt, `metrics`, and optional summary
120
134
  - `--verbose`: debug/diagnostics on stderr
121
- - `--metrics off|on|detailed`: metrics output (default `on`; `detailed` prints a breakdown to stderr)
135
+ - `--metrics off|on|detailed`: metrics output (default `on`; `detailed` adds a compact 2nd-line breakdown on stderr)
136
+
137
+ ## Auto model ordering
138
+
139
+ `--model auto` builds candidate attempts from built-in rules (or your `model.rules` overrides).
140
+ CLI tools are **not** used in auto mode unless you explicitly enable them via `cli.enabled` in config.
141
+ Why: CLI adds ~4s latency per attempt and higher variance.
142
+ Shortcut: `--cli` (with no provider) uses auto selection with CLI enabled.
143
+
144
+ When enabled, auto prepends CLI attempts in the order listed in `cli.enabled`
145
+ (recommended: `["gemini"]`), then tries the native provider candidates
146
+ (with OpenRouter fallbacks when configured).
147
+
148
+ Enable CLI attempts:
149
+
150
+ ```json
151
+ {
152
+ "cli": { "enabled": ["gemini"] }
153
+ }
154
+ ```
155
+
156
+ Disable CLI attempts:
157
+
158
+ ```json
159
+ {
160
+ "cli": { "enabled": [] }
161
+ }
162
+ ```
163
+
164
+ Note: when `cli.enabled` is set, it’s also an allowlist for explicit `--cli` / `--model cli/...`.
122
165
 
123
166
  ## Website extraction (Firecrawl + Markdown)
124
167
 
@@ -127,6 +170,9 @@ Non-YouTube URLs go through a “fetch → extract” pipeline. When the direct
127
170
  - `--firecrawl off|auto|always` (default `auto`)
128
171
  - `--extract --format md|text` (default `text`)
129
172
  - `--markdown-mode off|auto|llm` (default `auto`; only affects `--format md` for non-YouTube URLs)
173
+ - `auto`: use an LLM converter when configured; may fall back to `uvx markitdown`
174
+ - `llm`: force LLM conversion (requires a configured model key)
175
+ - `off`: disable LLM conversion (still may return Firecrawl Markdown when configured)
130
176
  - Plain-text mode: use `--format text`.
131
177
 
132
178
  ## YouTube transcripts
@@ -153,16 +199,34 @@ Supported keys today:
153
199
 
154
200
  ```json
155
201
  {
156
- "model": "openai/gpt-5.2"
202
+ "model": { "id": "openai/gpt-5-mini" }
157
203
  }
158
204
  ```
159
205
 
206
+ Shorthand (equivalent):
207
+
208
+ ```json
209
+ {
210
+ "model": "openai/gpt-5-mini"
211
+ }
212
+ ```
213
+
214
+ Also supported:
215
+
216
+ - `model: { "mode": "auto" }` (automatic model selection + fallback; see `docs/model-auto.md`)
217
+ - `model.rules` (customize candidates / ordering)
218
+ - `models` (define presets selectable via `--model <preset>`)
219
+ - `media.videoMode: "auto"|"transcript"|"understand"`
220
+
221
+ Note: the config is parsed leniently (JSON5), but **comments are not allowed**.
222
+ Unknown keys are ignored.
223
+
160
224
  Precedence:
161
225
 
162
226
  1) `--model`
163
227
  2) `SUMMARIZE_MODEL`
164
228
  3) `~/.summarize/config.json`
165
- 4) default
229
+ 4) default (`auto`)
166
230
 
167
231
  ## Environment variables
168
232
 
@@ -176,23 +240,57 @@ Set the key matching your chosen `--model`:
176
240
 
177
241
  OpenRouter (OpenAI-compatible):
178
242
 
179
- - Set `OPENROUTER_API_KEY=...` to route `openai/...` models through OpenRouter
180
- - Use OpenRouter models via the `openai/...` prefix, e.g. `--model openai/openai/gpt-oss-20b`
181
- - Optional: `OPENROUTER_PROVIDERS=...` to specify provider fallback order (e.g. `groq,google-vertex`)
243
+ - Set `OPENROUTER_API_KEY=...`
244
+ - Prefer forcing OpenRouter per model id: `--model openrouter/<author>/<slug>` (e.g. `openrouter/meta-llama/llama-3.1-8b-instruct:free`)
245
+ - Built-in preset: `--model free` (uses a default set of OpenRouter `:free` models).
182
246
 
183
- Example:
247
+ ### `summarize refresh-free`
248
+
249
+ Quick start: make free the default (keep `auto` available)
184
250
 
185
251
  ```bash
186
- OPENROUTER_API_KEY=sk-or-... summarize "https://example.com" --model openai/openai/gpt-oss-20b
252
+ # writes ~/.summarize/config.json (models.free) and sets model="free"
253
+ summarize refresh-free --set-default
254
+
255
+ # now this defaults to free models
256
+ summarize "https://example.com"
257
+
258
+ # whenever you want best quality instead
259
+ summarize "https://example.com" --model auto
187
260
  ```
188
261
 
189
- With provider ordering (falls back through providers in order):
262
+ Regenerates the `free` preset (writes `models.free` into `~/.summarize/config.json`) by:
263
+
264
+ - Fetching OpenRouter `/models`, filtering `:free`
265
+ - Skipping models that look very small (<27B by default) based on the model id/name (best-effort heuristic)
266
+ - Testing which ones return non-empty text (concurrency 4, timeout 10s)
267
+ - Picking a mix of “smart-ish” (bigger `context_length` / output cap) and fast models
268
+ - Refining timings for the final selection and writing the sorted list back
269
+
270
+ If `--model free` stops working (rate limits, allowed-provider restrictions, models removed), run:
271
+
272
+ ```bash
273
+ summarize refresh-free
274
+ ```
275
+
276
+ Flags:
277
+
278
+ - `--runs 2` (default): extra timing runs per selected model (total runs = 1 + runs)
279
+ - `--smart 3` (default): how many “smart-first” picks (rest filled by fastest)
280
+ - `--min-params 27b` (default): ignore models with inferred size smaller than N billion parameters
281
+ - `--max-age-days 180` (default): ignore models older than N days (set 0 to disable)
282
+ - `--set-default`: also sets `"model": "free"` in `~/.summarize/config.json`
283
+
284
+ Example:
190
285
 
191
286
  ```bash
192
- OPENROUTER_API_KEY=sk-or-... OPENROUTER_PROVIDERS="groq,google-vertex" summarize "https://example.com"
287
+ OPENROUTER_API_KEY=sk-or-... summarize "https://example.com" --model openrouter/meta-llama/llama-3.1-8b-instruct:free
193
288
  ```
194
289
 
195
- Legacy: `OPENAI_BASE_URL=https://openrouter.ai/api/v1` with `OPENAI_API_KEY` also works.
290
+ If your OpenRouter account enforces an allowed-provider list, make sure at least one provider
291
+ is allowed for the selected model. (When routing fails, `summarize` prints the exact providers to allow.)
292
+
293
+ Legacy: `OPENAI_BASE_URL=https://openrouter.ai/api/v1` (and either `OPENAI_API_KEY` or `OPENROUTER_API_KEY`) also works.
196
294
 
197
295
  Optional services:
198
296