@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
@@ -0,0 +1,58 @@
1
+ # Smoke Test Plan (20 combos)
2
+
3
+ Goal: exercise URL + file inputs, extraction + LLM summary paths, multiple models.
4
+
5
+ ## Preconditions
6
+ - API keys set for at least: `OPENAI_API_KEY`, `GEMINI_API_KEY`.
7
+ - Optional: `FIRECRAWL_API_KEY` to test fallback (if available).
8
+
9
+ ## Models (cheap/fast)
10
+ - `openai/gpt-5-mini`
11
+ - `google/gemini-3-flash-preview`
12
+
13
+ ## Matrix (20 cases)
14
+
15
+ ### Websites (LLM summary, 10)
16
+ 1) Static HTML: `https://example.com` (model: gemini-3-flash)
17
+ 2) Wikipedia article: `https://en.wikipedia.org/wiki/Swift_(programming_language)` (model: gpt-5-mini)
18
+ 3) MDN doc: `https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/200` (model: gemini-3-flash)
19
+ 4) Reuters article: `https://www.reuters.com/world/` (model: gpt-5-mini)
20
+ 5) BBC article: `https://www.bbc.com/news` (model: gemini-3-flash)
21
+ 6) GitHub README: `https://github.com/vitejs/vite` (model: gpt-5-mini)
22
+ 7) Substack post: pick any public post (model: gemini-3-flash)
23
+ 8) Medium post: pick any public post (model: gpt-5-mini)
24
+ 9) JS-heavy page: `https://vercel.com` (model: gemini-3-flash)
25
+ 10) 404 page: `https://example.com/does-not-exist` (model: gpt-5-mini)
26
+
27
+ ### YouTube (LLM summary, 2)
28
+ 11) Captions available: pick a popular talk/interview (model: gemini-3-flash, `--youtube auto`)
29
+ 12) No captions: pick a random channel upload w/o captions (model: gpt-5-mini, `--youtube auto`)
30
+
31
+ ### Remote files (LLM summary, 4)
32
+ 13) PDF URL: any public PDF report (model: gemini-3-flash)
33
+ 14) PNG URL: `https://upload.wikimedia.org/wikipedia/commons/7/70/Example.png` (model: gpt-5-mini)
34
+ 15) MP3 URL: any public MP3 sample (model: gemini-3-flash)
35
+ 16) CSV URL: any public CSV sample (model: gpt-5-mini)
36
+
37
+ ### Local files (LLM summary, 4)
38
+ 17) `tests/fixtures/sample.txt` (create if missing) (model: gemini-3-flash)
39
+ 18) `tests/fixtures/sample.md` (create if missing) (model: gpt-5-mini)
40
+ 19) `tests/fixtures/sample.json` (create if missing) (model: gemini-3-flash)
41
+ 20) `tests/fixtures/sample.png` (create if missing; use a real PNG, not 1x1) (model: gpt-5-mini)
42
+
43
+ ## Commands (template)
44
+ - Website: `pnpm summarize -- "<url>" --model <model> --length short`
45
+ - YouTube: `pnpm summarize -- "<url>" --model <model> --youtube auto`
46
+ - File URL: `pnpm summarize -- "<url>" --model <model>`
47
+ - Local file: `pnpm summarize -- "<path>" --model <model>`
48
+
49
+ ## Capture
50
+ - Log: stdout + stderr, exit code, and timing line.
51
+ - Note extraction path (HTML vs Firecrawl vs YouTube transcript).
52
+ - File errors: media type rejection, size limits, token preflight.
53
+
54
+ ## Bug bar
55
+ - Crash, hang, or non-zero exit.
56
+ - Empty summary with non-empty input.
57
+ - Incorrect mode selection (e.g., YouTube treated as normal URL).
58
+ - Wrong fallback behavior or misleading error text.
package/docs/website.md CHANGED
@@ -7,6 +7,7 @@ Use this for non-YouTube URLs.
7
7
  - Fetches the page HTML.
8
8
  - Extracts “article-ish” content and normalizes it into clean text.
9
9
  - If extraction looks blocked or too thin, it can retry via Firecrawl (Markdown).
10
+ - If a page is effectively “video-only”, it may treat it as a video input (see `--video-mode`).
10
11
  - With `--format md`, the CLI prefers Firecrawl Markdown by default when `FIRECRAWL_API_KEY` is configured.
11
12
  - With `--format md`, `--markdown-mode auto|llm` can also convert HTML → Markdown via an LLM using the configured `--model` (no provider fallback).
12
13
  - With `--format md`, `--markdown-mode auto` may fall back to `uvx markitdown` when available (disable with `--preprocess off`).
@@ -17,12 +18,13 @@ Use this for non-YouTube URLs.
17
18
  - `--format md|text` (default: `text`)
18
19
  - `--markdown-mode off|auto|llm` (default: `auto`; only affects `--format md` for non-YouTube URLs)
19
20
  - `--preprocess off|auto|always` (default: `auto`; controls markitdown usage; `always` only affects file inputs)
21
+ - `--video-mode auto|transcript|understand` (only affects video inputs / video-only pages)
20
22
  - Plain-text mode: use `--format text`.
21
23
  - `--timeout 30s|30|2m|5000ms` (default: `2m`)
22
24
  - `--extract` (print extracted content; no summary LLM call)
23
25
  - `--json` (emit a single JSON object)
24
26
  - `--verbose` (progress + which extractor was used)
25
- - `--metrics off|on|detailed` (default: `on`; `detailed` prints a breakdown to stderr)
27
+ - `--metrics off|on|detailed` (default: `on`; `detailed` adds a compact 2nd-line breakdown on stderr)
26
28
 
27
29
  ## API keys
28
30
 
package/package.json CHANGED
@@ -1,10 +1,11 @@
1
1
  {
2
2
  "name": "@steipete/summarize",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "Link → clean text → summary.",
5
5
  "type": "module",
6
6
  "bin": {
7
- "summarize": "./dist/cli.cjs"
7
+ "summarize": "./dist/cli.cjs",
8
+ "summarizer": "./dist/cli.cjs"
8
9
  },
9
10
  "main": "./dist/esm/index.js",
10
11
  "module": "./dist/esm/index.js",
@@ -38,6 +39,7 @@
38
39
  "cheerio": "^1.1.2",
39
40
  "es-toolkit": "^1.43.0",
40
41
  "gpt-tokenizer": "^3.4.0",
42
+ "json5": "^2.2.3",
41
43
  "sanitize-html": "^2.17.0"
42
44
  },
43
45
  "devDependencies": {
@@ -57,6 +59,8 @@
57
59
  "mime": "^4.1.0",
58
60
  "ora": "^9.0.0",
59
61
  "osc-progress": "^0.1.0",
62
+ "oxlint": "^1.35.0",
63
+ "oxlint-tsgolint": "^0.10.0",
60
64
  "tokentally": "github:steipete/tokentally#v0.1.0",
61
65
  "tsx": "^4.21.0",
62
66
  "typescript": "^5.9.3",
@@ -71,8 +75,8 @@
71
75
  "typecheck": "tsc -p tsconfig.build.json --noEmit",
72
76
  "summarize": "tsx src/cli.ts",
73
77
  "format": "biome format --write .",
74
- "lint": "biome check .",
75
- "lint:fix": "biome check --write .",
78
+ "lint": "biome check . && oxlint --type-aware --tsconfig tsconfig.build.json --config .oxlintrc.json .",
79
+ "lint:fix": "biome check --write . && oxlint --type-aware --tsconfig tsconfig.build.json --config .oxlintrc.json --fix .",
76
80
  "check": "pnpm lint && pnpm test:coverage",
77
81
  "test": "pnpm build && vitest run",
78
82
  "test:coverage": "pnpm build && vitest run --coverage",
@@ -1,12 +0,0 @@
1
- const TWITTER_URL_PATTERN = /twitter\.com|x\.com/i;
2
- export const canHandle = ({ url }) => TWITTER_URL_PATTERN.test(url);
3
- export const fetchTranscript = async (_context, _options) => {
4
- await Promise.resolve();
5
- return {
6
- text: null,
7
- source: null,
8
- attemptedProviders: [],
9
- metadata: { provider: 'twitter', reason: 'not_implemented' },
10
- };
11
- };
12
- //# sourceMappingURL=twitter.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"twitter.js","sourceRoot":"","sources":["../../../../../../src/content/link-preview/transcript/providers/twitter.ts"],"names":[],"mappings":"AAEA,MAAM,mBAAmB,GAAG,sBAAsB,CAAA;AAElD,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,EAAE,GAAG,EAAmB,EAAW,EAAE,CAAC,mBAAmB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;AAE7F,MAAM,CAAC,MAAM,eAAe,GAAG,KAAK,EAClC,QAAyB,EACzB,QAA8B,EACL,EAAE;IAC3B,MAAM,OAAO,CAAC,OAAO,EAAE,CAAA;IACvB,OAAO;QACL,IAAI,EAAE,IAAI;QACV,MAAM,EAAE,IAAI;QACZ,kBAAkB,EAAE,EAAE;QACtB,QAAQ,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,iBAAiB,EAAE;KAC7D,CAAA;AACH,CAAC,CAAA"}
@@ -1,114 +0,0 @@
1
- import { execFile } from 'node:child_process';
2
- import { promisify } from 'node:util';
3
- import { fetchWithTimeout } from '../../../fetch-with-timeout.js';
4
- import { sanitizeYoutubeJsonResponse } from '../../utils.js';
5
- const execFileAsync = promisify(execFile);
6
- const isRecord = (value) => typeof value === 'object' && value !== null && !Array.isArray(value);
7
- const parseJson3Transcript = (raw) => {
8
- try {
9
- const parsed = JSON.parse(raw);
10
- if (!isRecord(parsed)) {
11
- return null;
12
- }
13
- const eventsUnknown = parsed.events;
14
- if (!Array.isArray(eventsUnknown)) {
15
- return null;
16
- }
17
- const lines = [];
18
- for (const event of eventsUnknown) {
19
- if (!isRecord(event)) {
20
- continue;
21
- }
22
- const eventRecord = event;
23
- const segs = Array.isArray(eventRecord.segs) ? eventRecord.segs : null;
24
- if (!segs) {
25
- continue;
26
- }
27
- const text = segs
28
- .map((seg) => {
29
- if (!isRecord(seg)) {
30
- return '';
31
- }
32
- const segRecord = seg;
33
- return typeof segRecord.utf8 === 'string' ? segRecord.utf8 : '';
34
- })
35
- .join('')
36
- .trim();
37
- if (text.length > 0) {
38
- lines.push(text);
39
- }
40
- }
41
- const transcript = lines.join('\n').trim();
42
- return transcript.length > 0 ? transcript : null;
43
- }
44
- catch {
45
- return null;
46
- }
47
- };
48
- function pickCaptionUrl(info) {
49
- const sources = [info.subtitles, info.automatic_captions];
50
- const candidates = [];
51
- for (const source of sources) {
52
- if (!isRecord(source))
53
- continue;
54
- for (const [lang, entries] of Object.entries(source)) {
55
- candidates.push([lang, entries]);
56
- }
57
- }
58
- const languagePreference = (lang) => {
59
- const lower = lang.toLowerCase();
60
- if (lower === 'en')
61
- return 0;
62
- if (lower.startsWith('en-'))
63
- return 1;
64
- if (lower.startsWith('en'))
65
- return 2;
66
- return 10;
67
- };
68
- const sorted = candidates.toSorted(([a], [b]) => languagePreference(a) - languagePreference(b));
69
- for (const [, entries] of sorted) {
70
- if (!Array.isArray(entries))
71
- continue;
72
- const normalized = entries.filter((entry) => isRecord(entry));
73
- const json3 = normalized.find((entry) => entry.ext === 'json3' && typeof entry.url === 'string');
74
- if (json3?.url && typeof json3.url === 'string') {
75
- return json3.url;
76
- }
77
- const vtt = normalized.find((entry) => entry.ext === 'vtt' && typeof entry.url === 'string');
78
- if (vtt?.url && typeof vtt.url === 'string') {
79
- return vtt.url;
80
- }
81
- }
82
- return null;
83
- }
84
- export async function fetchTranscriptWithYtDlp(fetchImpl, url, { timeoutMs } = {}) {
85
- try {
86
- const { stdout } = await execFileAsync('yt-dlp', ['--dump-single-json', '--no-playlist', '--no-warnings', url], { timeout: typeof timeoutMs === 'number' && Number.isFinite(timeoutMs) ? timeoutMs : 60_000 });
87
- const parsed = JSON.parse(stdout);
88
- if (!isRecord(parsed)) {
89
- return null;
90
- }
91
- const info = parsed;
92
- const captionUrl = pickCaptionUrl(info);
93
- if (!captionUrl) {
94
- return null;
95
- }
96
- const response = await fetchWithTimeout(fetchImpl, captionUrl, undefined, 60_000);
97
- if (!response.ok) {
98
- return null;
99
- }
100
- const raw = await response.text();
101
- const sanitized = sanitizeYoutubeJsonResponse(raw);
102
- return parseJson3Transcript(sanitized);
103
- }
104
- catch (error) {
105
- const code = error && typeof error === 'object' && 'code' in error
106
- ? error.code
107
- : null;
108
- if (code === 'ENOENT') {
109
- return null;
110
- }
111
- return null;
112
- }
113
- }
114
- //# sourceMappingURL=ytdlp.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ytdlp.js","sourceRoot":"","sources":["../../../../../../../src/content/link-preview/transcript/providers/youtube/ytdlp.ts"],"names":[],"mappings":"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"}
@@ -1,20 +0,0 @@
1
- import { homedir } from 'node:os';
2
- import { join } from 'node:path';
3
- let summarizeHomeDirOverride = null;
4
- /**
5
- * Test-only hook: avoid mutating process.env (shared across Vitest worker threads).
6
- * This override is scoped to the current Node worker.
7
- */
8
- export function setSummarizeHomeDirOverrideForTest(dir) {
9
- summarizeHomeDirOverride = dir;
10
- }
11
- export function getSummarizeHomeDir(env) {
12
- if (summarizeHomeDirOverride)
13
- return summarizeHomeDirOverride;
14
- const fromEnv = env.SUMMARIZE_HOME_DIR?.trim();
15
- if (fromEnv)
16
- return fromEnv;
17
- const home = env.HOME?.trim() || homedir();
18
- return join(home, '.summarize');
19
- }
20
- //# sourceMappingURL=summarizeHome.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"summarizeHome.js","sourceRoot":"","sources":["../../src/summarizeHome.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAEhC,IAAI,wBAAwB,GAAkB,IAAI,CAAA;AAElD;;;GAGG;AACH,MAAM,UAAU,kCAAkC,CAAC,GAAkB;IACnE,wBAAwB,GAAG,GAAG,CAAA;AAChC,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,GAAuC;IACzE,IAAI,wBAAwB;QAAE,OAAO,wBAAwB,CAAA;IAC7D,MAAM,OAAO,GAAG,GAAG,CAAC,kBAAkB,EAAE,IAAI,EAAE,CAAA;IAC9C,IAAI,OAAO;QAAE,OAAO,OAAO,CAAA;IAC3B,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,OAAO,EAAE,CAAA;IAC1C,OAAO,IAAI,CAAC,IAAI,EAAE,YAAY,CAAC,CAAA;AACjC,CAAC"}
@@ -1,52 +0,0 @@
1
- import { render as renderMarkdownAnsi } from 'markdansi';
2
- const BSU = '\u001b[?2026h';
3
- const ESU = '\u001b[?2026l';
4
- const HIDE_CURSOR = '\u001b[?25l';
5
- const SHOW_CURSOR = '\u001b[?25h';
6
- const CLEAR_LINE = '\u001b[2K';
7
- function cursorUp(lines) {
8
- if (lines <= 0)
9
- return '';
10
- return `\u001b[${lines}A`;
11
- }
12
- export function createLiveMarkdownRenderer({ stdout, width, color, }) {
13
- let previousLines = 0;
14
- let cursorHidden = false;
15
- const render = (markdown) => {
16
- const renderedRaw = renderMarkdownAnsi(markdown, { width, wrap: true, color });
17
- const rendered = renderedRaw.endsWith('\n') ? renderedRaw : `${renderedRaw}\n`;
18
- const lines = rendered.split('\n');
19
- if (lines.length > 0 && lines.at(-1) === '')
20
- lines.pop();
21
- const newLines = lines.length;
22
- const maxLines = Math.max(previousLines, newLines);
23
- let frame = '';
24
- if (!cursorHidden) {
25
- frame += HIDE_CURSOR;
26
- cursorHidden = true;
27
- }
28
- frame += BSU;
29
- if (previousLines > 0) {
30
- frame += `${cursorUp(previousLines)}\r`;
31
- }
32
- else {
33
- frame += '\r';
34
- }
35
- for (let i = 0; i < maxLines; i += 1) {
36
- frame += CLEAR_LINE;
37
- frame += lines[i] ?? '';
38
- frame += '\n';
39
- }
40
- frame += ESU;
41
- stdout.write(frame);
42
- previousLines = newLines;
43
- };
44
- const finish = () => {
45
- if (!cursorHidden)
46
- return;
47
- stdout.write(SHOW_CURSOR);
48
- cursorHidden = false;
49
- };
50
- return { render, finish };
51
- }
52
- //# sourceMappingURL=live-markdown.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"live-markdown.js","sourceRoot":"","sources":["../../../src/tty/live-markdown.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,kBAAkB,EAAE,MAAM,WAAW,CAAA;AAOxD,MAAM,GAAG,GAAG,eAAe,CAAA;AAC3B,MAAM,GAAG,GAAG,eAAe,CAAA;AAC3B,MAAM,WAAW,GAAG,aAAa,CAAA;AACjC,MAAM,WAAW,GAAG,aAAa,CAAA;AACjC,MAAM,UAAU,GAAG,WAAW,CAAA;AAE9B,SAAS,QAAQ,CAAC,KAAa;IAC7B,IAAI,KAAK,IAAI,CAAC;QAAE,OAAO,EAAE,CAAA;IACzB,OAAO,UAAU,KAAK,GAAG,CAAA;AAC3B,CAAC;AAED,MAAM,UAAU,0BAA0B,CAAC,EACzC,MAAM,EACN,KAAK,EACL,KAAK,GAKN;IACC,IAAI,aAAa,GAAG,CAAC,CAAA;IACrB,IAAI,YAAY,GAAG,KAAK,CAAA;IAExB,MAAM,MAAM,GAAG,CAAC,QAAgB,EAAE,EAAE;QAClC,MAAM,WAAW,GAAG,kBAAkB,CAAC,QAAQ,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAA;QAC9E,MAAM,QAAQ,GAAG,WAAW,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,GAAG,WAAW,IAAI,CAAA;QAE9E,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QAClC,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE;YAAE,KAAK,CAAC,GAAG,EAAE,CAAA;QAExD,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,CAAA;QAC7B,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,aAAa,EAAE,QAAQ,CAAC,CAAA;QAElD,IAAI,KAAK,GAAG,EAAE,CAAA;QACd,IAAI,CAAC,YAAY,EAAE,CAAC;YAClB,KAAK,IAAI,WAAW,CAAA;YACpB,YAAY,GAAG,IAAI,CAAA;QACrB,CAAC;QAED,KAAK,IAAI,GAAG,CAAA;QACZ,IAAI,aAAa,GAAG,CAAC,EAAE,CAAC;YACtB,KAAK,IAAI,GAAG,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAA;QACzC,CAAC;aAAM,CAAC;YACN,KAAK,IAAI,IAAI,CAAA;QACf,CAAC;QAED,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;YACrC,KAAK,IAAI,UAAU,CAAA;YACnB,KAAK,IAAI,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAA;YACvB,KAAK,IAAI,IAAI,CAAA;QACf,CAAC;QAED,KAAK,IAAI,GAAG,CAAA;QACZ,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;QAEnB,aAAa,GAAG,QAAQ,CAAA;IAC1B,CAAC,CAAA;IAED,MAAM,MAAM,GAAG,GAAG,EAAE;QAClB,IAAI,CAAC,YAAY;YAAE,OAAM;QACzB,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,CAAA;QACzB,YAAY,GAAG,KAAK,CAAA;IACtB,CAAC,CAAA;IAED,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,CAAA;AAC3B,CAAC"}
@@ -1,3 +0,0 @@
1
- import type { ProviderContext, ProviderFetchOptions, ProviderResult } from '../types.js';
2
- export declare const canHandle: ({ url }: ProviderContext) => boolean;
3
- export declare const fetchTranscript: (_context: ProviderContext, _options: ProviderFetchOptions) => Promise<ProviderResult>;
@@ -1,3 +0,0 @@
1
- export declare function fetchTranscriptWithYtDlp(fetchImpl: typeof fetch, url: string, { timeoutMs }?: {
2
- timeoutMs?: number;
3
- }): Promise<string | null>;
@@ -1,6 +0,0 @@
1
- /**
2
- * Test-only hook: avoid mutating process.env (shared across Vitest worker threads).
3
- * This override is scoped to the current Node worker.
4
- */
5
- export declare function setSummarizeHomeDirOverrideForTest(dir: string | null): void;
6
- export declare function getSummarizeHomeDir(env: Record<string, string | undefined>): string;
@@ -1,10 +0,0 @@
1
- type LiveMarkdownRenderer = {
2
- render: (markdown: string) => void;
3
- finish: () => void;
4
- };
5
- export declare function createLiveMarkdownRenderer({ stdout, width, color, }: {
6
- stdout: NodeJS.WritableStream;
7
- width: number;
8
- color: boolean;
9
- }): LiveMarkdownRenderer;
10
- export {};