tenbrains 2.1.0 → 2.3.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 (89) hide show
  1. package/AGENTS.md +19 -2
  2. package/README.md +93 -9
  3. package/dist/ai/analyzer.d.ts +7 -2
  4. package/dist/ai/analyzer.d.ts.map +1 -1
  5. package/dist/ai/analyzer.js +19 -5
  6. package/dist/ai/analyzer.js.map +1 -1
  7. package/dist/ai/mock.d.ts +2 -1
  8. package/dist/ai/mock.d.ts.map +1 -1
  9. package/dist/ai/mock.js +12 -0
  10. package/dist/ai/mock.js.map +1 -1
  11. package/dist/ai/prompts.d.ts +3 -1
  12. package/dist/ai/prompts.d.ts.map +1 -1
  13. package/dist/ai/prompts.js +17 -2
  14. package/dist/ai/prompts.js.map +1 -1
  15. package/dist/bin/tenbrains.js +0 -0
  16. package/dist/cli.d.ts.map +1 -1
  17. package/dist/cli.js +115 -8
  18. package/dist/cli.js.map +1 -1
  19. package/dist/commands/analyze.d.ts.map +1 -1
  20. package/dist/commands/analyze.js +100 -11
  21. package/dist/commands/analyze.js.map +1 -1
  22. package/dist/commands/bookmark.d.ts.map +1 -1
  23. package/dist/commands/bookmark.js +10 -1
  24. package/dist/commands/bookmark.js.map +1 -1
  25. package/dist/commands/digest.d.ts +6 -1
  26. package/dist/commands/digest.d.ts.map +1 -1
  27. package/dist/commands/digest.js +15 -5
  28. package/dist/commands/digest.js.map +1 -1
  29. package/dist/commands/learn.d.ts.map +1 -1
  30. package/dist/commands/learn.js +14 -2
  31. package/dist/commands/learn.js.map +1 -1
  32. package/dist/commands/manifest.d.ts.map +1 -1
  33. package/dist/commands/manifest.js +6 -0
  34. package/dist/commands/manifest.js.map +1 -1
  35. package/dist/commands/objective-tags.d.ts +27 -0
  36. package/dist/commands/objective-tags.d.ts.map +1 -0
  37. package/dist/commands/objective-tags.js +105 -0
  38. package/dist/commands/objective-tags.js.map +1 -0
  39. package/dist/commands/objective.d.ts +11 -0
  40. package/dist/commands/objective.d.ts.map +1 -0
  41. package/dist/commands/objective.js +208 -0
  42. package/dist/commands/objective.js.map +1 -0
  43. package/dist/commands/record.d.ts +1 -1
  44. package/dist/commands/record.d.ts.map +1 -1
  45. package/dist/commands/record.js +10 -2
  46. package/dist/commands/record.js.map +1 -1
  47. package/dist/commands/search.d.ts.map +1 -1
  48. package/dist/commands/search.js +16 -2
  49. package/dist/commands/search.js.map +1 -1
  50. package/dist/commands/takeaway.d.ts.map +1 -1
  51. package/dist/commands/takeaway.js +4 -1
  52. package/dist/commands/takeaway.js.map +1 -1
  53. package/dist/core/text.d.ts +2 -0
  54. package/dist/core/text.d.ts.map +1 -1
  55. package/dist/core/text.js +10 -0
  56. package/dist/core/text.js.map +1 -1
  57. package/dist/db/database.d.ts +2 -1
  58. package/dist/db/database.d.ts.map +1 -1
  59. package/dist/db/database.js +3 -0
  60. package/dist/db/database.js.map +1 -1
  61. package/dist/db/migrations.d.ts.map +1 -1
  62. package/dist/db/migrations.js +25 -0
  63. package/dist/db/migrations.js.map +1 -1
  64. package/dist/db/repositories.d.ts +21 -1
  65. package/dist/db/repositories.d.ts.map +1 -1
  66. package/dist/db/repositories.js +209 -0
  67. package/dist/db/repositories.js.map +1 -1
  68. package/dist/domain/learn.d.ts +5 -4
  69. package/dist/domain/learn.d.ts.map +1 -1
  70. package/dist/domain/learn.js +39 -15
  71. package/dist/domain/learn.js.map +1 -1
  72. package/dist/domain/schemas.d.ts +14 -0
  73. package/dist/domain/schemas.d.ts.map +1 -1
  74. package/dist/domain/schemas.js +5 -0
  75. package/dist/domain/schemas.js.map +1 -1
  76. package/dist/domain/search.d.ts +2 -0
  77. package/dist/domain/search.d.ts.map +1 -1
  78. package/dist/domain/search.js +20 -1
  79. package/dist/domain/search.js.map +1 -1
  80. package/dist/domain/suggest.d.ts.map +1 -1
  81. package/dist/domain/suggest.js +34 -14
  82. package/dist/domain/suggest.js.map +1 -1
  83. package/dist/domain/types.d.ts +22 -0
  84. package/dist/domain/types.d.ts.map +1 -1
  85. package/dist/youtube/client.d.ts +31 -0
  86. package/dist/youtube/client.d.ts.map +1 -0
  87. package/dist/youtube/client.js +334 -0
  88. package/dist/youtube/client.js.map +1 -0
  89. package/package.json +5 -3
@@ -0,0 +1,334 @@
1
+ import { CliError } from "../core/errors.js";
2
+ const REQUEST_TIMEOUT_MS = 15_000;
3
+ const WATCH_BASE = "https://www.youtube.com/watch?v=";
4
+ const VIDEO_ID = /^[A-Za-z0-9_-]{11}$/;
5
+ function asRecord(value) {
6
+ return typeof value === "object" && value !== null ? value : {};
7
+ }
8
+ export function parseVideoRef(input) {
9
+ const trimmed = input.trim();
10
+ if (VIDEO_ID.test(trimmed)) {
11
+ return { id: trimmed, url: `${WATCH_BASE}${trimmed}` };
12
+ }
13
+ let url;
14
+ try {
15
+ url = new URL(trimmed);
16
+ }
17
+ catch {
18
+ throw new CliError("USAGE", `Could not parse a YouTube video URL or id from "${input}".`, {
19
+ details: { input },
20
+ });
21
+ }
22
+ const host = url.hostname.toLowerCase().replace(/^www\./, "");
23
+ let id = null;
24
+ if (host === "youtu.be") {
25
+ id = url.pathname.split("/").filter(Boolean)[0] ?? null;
26
+ }
27
+ else if (host === "youtube.com" || host === "m.youtube.com") {
28
+ id =
29
+ url.pathname === "/watch"
30
+ ? url.searchParams.get("v")
31
+ : (url.pathname.match(/^\/(?:shorts|embed)\/([^/?#]+)/)?.[1] ?? null);
32
+ }
33
+ if (!id || !VIDEO_ID.test(id)) {
34
+ throw new CliError("USAGE", `Could not parse a YouTube video URL or id from "${input}".`, {
35
+ details: { input },
36
+ });
37
+ }
38
+ return { id, url: `${WATCH_BASE}${id}` };
39
+ }
40
+ export function isYouTubeUrl(input) {
41
+ try {
42
+ const host = new URL(input).hostname.toLowerCase().replace(/^www\./, "");
43
+ return host === "youtu.be" || host === "youtube.com" || host === "m.youtube.com";
44
+ }
45
+ catch {
46
+ return false;
47
+ }
48
+ }
49
+ function extractJsonAfter(html, marker) {
50
+ const markerIndex = html.indexOf(marker);
51
+ if (markerIndex < 0) {
52
+ throw new CliError("PROVIDER_BAD_OUTPUT", "YouTube watch page did not contain a player response.");
53
+ }
54
+ const start = html.indexOf("{", markerIndex + marker.length);
55
+ if (start < 0) {
56
+ throw new CliError("PROVIDER_BAD_OUTPUT", "YouTube player response was not valid JSON.");
57
+ }
58
+ let depth = 0;
59
+ let quoted = false;
60
+ let escaped = false;
61
+ for (let index = start; index < html.length; index += 1) {
62
+ const char = html[index];
63
+ if (quoted) {
64
+ if (escaped) {
65
+ escaped = false;
66
+ }
67
+ else if (char === "\\") {
68
+ escaped = true;
69
+ }
70
+ else if (char === '"') {
71
+ quoted = false;
72
+ }
73
+ continue;
74
+ }
75
+ if (char === '"') {
76
+ quoted = true;
77
+ }
78
+ else if (char === "{") {
79
+ depth += 1;
80
+ }
81
+ else if (char === "}") {
82
+ depth -= 1;
83
+ if (depth === 0) {
84
+ try {
85
+ return JSON.parse(html.slice(start, index + 1));
86
+ }
87
+ catch (error) {
88
+ throw new CliError("PROVIDER_BAD_OUTPUT", "YouTube player response was not valid JSON.", {
89
+ cause: error,
90
+ });
91
+ }
92
+ }
93
+ }
94
+ }
95
+ throw new CliError("PROVIDER_BAD_OUTPUT", "YouTube player response JSON was incomplete.");
96
+ }
97
+ function parsePlayerObject(value) {
98
+ const player = asRecord(value);
99
+ const details = asRecord(player.videoDetails);
100
+ const microformat = asRecord(asRecord(player.microformat).playerMicroformatRenderer);
101
+ const renderer = asRecord(asRecord(asRecord(player.captions).playerCaptionsTracklistRenderer));
102
+ const rawTracks = renderer.captionTracks;
103
+ const captionTracks = Array.isArray(rawTracks)
104
+ ? rawTracks.flatMap((entry) => {
105
+ const track = asRecord(entry);
106
+ const baseUrl = typeof track.baseUrl === "string" ? track.baseUrl : "";
107
+ const lang = typeof track.languageCode === "string" ? track.languageCode : "";
108
+ if (!baseUrl || !lang) {
109
+ return [];
110
+ }
111
+ return [{ baseUrl, lang, kind: track.kind === "asr" ? "asr" : "manual" }];
112
+ })
113
+ : [];
114
+ const duration = Number(details.lengthSeconds);
115
+ return {
116
+ videoId: typeof details.videoId === "string" ? details.videoId : "",
117
+ title: typeof details.title === "string" ? details.title : "",
118
+ author: typeof details.author === "string" ? details.author : "",
119
+ uploadDate: typeof microformat.uploadDate === "string" ? microformat.uploadDate : undefined,
120
+ durationSeconds: Number.isFinite(duration) ? duration : undefined,
121
+ captionTracks,
122
+ };
123
+ }
124
+ export function parsePlayerResponse(html) {
125
+ return parsePlayerObject(extractJsonAfter(html, "ytInitialPlayerResponse"));
126
+ }
127
+ const NAMED_ENTITIES = {
128
+ amp: "&",
129
+ apos: "'",
130
+ gt: ">",
131
+ lt: "<",
132
+ nbsp: " ",
133
+ quot: '"',
134
+ };
135
+ function decodeEntities(text) {
136
+ return text.replace(/&(#x?[0-9a-f]+|[a-z]+);/gi, (match, code) => {
137
+ if (code.startsWith("#")) {
138
+ const value = code[1]?.toLowerCase() === "x"
139
+ ? Number.parseInt(code.slice(2), 16)
140
+ : Number.parseInt(code.slice(1), 10);
141
+ return Number.isFinite(value) ? String.fromCodePoint(value) : match;
142
+ }
143
+ return NAMED_ENTITIES[code.toLowerCase()] ?? match;
144
+ });
145
+ }
146
+ function cleanSegment(text) {
147
+ return decodeEntities(text.replace(/<[^>]+>/g, ""))
148
+ .replace(/\s+/g, " ")
149
+ .trim();
150
+ }
151
+ export function parseTimedText(input) {
152
+ const trimmed = input.trim();
153
+ let segments;
154
+ if (trimmed.startsWith("{")) {
155
+ let payload;
156
+ try {
157
+ payload = JSON.parse(trimmed);
158
+ }
159
+ catch (error) {
160
+ throw new CliError("PROVIDER_BAD_OUTPUT", "YouTube caption JSON was not parseable.", {
161
+ cause: error,
162
+ });
163
+ }
164
+ const events = asRecord(payload).events;
165
+ segments = Array.isArray(events)
166
+ ? events.flatMap((event) => {
167
+ const segs = asRecord(event).segs;
168
+ if (!Array.isArray(segs)) {
169
+ return [];
170
+ }
171
+ return [
172
+ segs
173
+ .map((segment) => asRecord(segment).utf8)
174
+ .filter((value) => typeof value === "string")
175
+ .join(""),
176
+ ];
177
+ })
178
+ : [];
179
+ }
180
+ else {
181
+ segments = [...trimmed.matchAll(/<(?:text|p)\b[^>]*>([\s\S]*?)<\/(?:text|p)>/gi)].map((match) => match[1] ?? "");
182
+ }
183
+ const text = segments.map(cleanSegment).filter(Boolean).join(" ").replace(/\s+/g, " ").trim();
184
+ if (!text) {
185
+ throw new CliError("PROVIDER_BAD_OUTPUT", "YouTube caption track contained no readable text.");
186
+ }
187
+ return text;
188
+ }
189
+ function manualFallback(message) {
190
+ return `${message} Supply a transcript manually with \`tenbrains analyze --transcript @file\` (or -).`;
191
+ }
192
+ function assertPlayable(player, ref) {
193
+ const playability = asRecord(asRecord(player).playabilityStatus);
194
+ const status = typeof playability.status === "string" ? playability.status : "";
195
+ const reason = typeof playability.reason === "string" ? playability.reason : "";
196
+ const combined = `${status} ${reason}`.toLowerCase();
197
+ if (/(private|login_required|confirm your age|age.?restricted|members.?only|not available in your country|region)/.test(combined)) {
198
+ throw new CliError("PROVIDER_UNAUTHORIZED", `YouTube video is not publicly accessible: ${reason}`, {
199
+ details: { videoId: ref.id, reason },
200
+ });
201
+ }
202
+ if (status && status !== "OK") {
203
+ throw new CliError("NOT_FOUND", manualFallback(`YouTube video was unavailable: ${reason}`), {
204
+ details: { videoId: ref.id, reason },
205
+ });
206
+ }
207
+ }
208
+ function selectTrack(tracks, lang) {
209
+ const preferred = lang?.toLowerCase();
210
+ const languageRank = (track) => {
211
+ const code = track.lang.toLowerCase();
212
+ if (preferred && (code === preferred || code.startsWith(`${preferred}-`)))
213
+ return 0;
214
+ if (code === "en" || code.startsWith("en-"))
215
+ return 1;
216
+ return 2;
217
+ };
218
+ return [...tracks].sort((a, b) => Number(a.kind === "asr") - Number(b.kind === "asr") || languageRank(a) - languageRank(b))[0];
219
+ }
220
+ export async function fetchTranscript(input, options = {}) {
221
+ const ref = typeof input === "string" ? parseVideoRef(input) : input;
222
+ const pageResponse = await safeFetch(ref.url, "watch page");
223
+ if (pageResponse.status === 404) {
224
+ throw new CliError("NOT_FOUND", manualFallback("YouTube video was not found."), {
225
+ details: { videoId: ref.id },
226
+ });
227
+ }
228
+ if (!pageResponse.ok) {
229
+ throw mapStatus(pageResponse.status, "watch page");
230
+ }
231
+ const html = await pageResponse.text();
232
+ const rawPlayer = extractJsonAfter(html, "ytInitialPlayerResponse");
233
+ assertPlayable(rawPlayer, ref);
234
+ const player = parsePlayerResponse(html);
235
+ if (!player.videoId || !player.title) {
236
+ throw new CliError("PROVIDER_BAD_OUTPUT", "YouTube player response omitted video metadata.");
237
+ }
238
+ if (player.captionTracks.length === 0) {
239
+ throw new CliError("NOT_FOUND", manualFallback("YouTube video has no caption tracks."), {
240
+ details: { videoId: ref.id },
241
+ });
242
+ }
243
+ let track = selectTrack(player.captionTracks, options.lang);
244
+ let captionResponse = await safeFetch(track.baseUrl, "caption track");
245
+ if (!captionResponse.ok) {
246
+ throw mapStatus(captionResponse.status, "caption track");
247
+ }
248
+ let captionBody = await captionResponse.text();
249
+ if (!captionBody.trim()) {
250
+ // WEB caption URLs increasingly require a proof-of-origin token and may
251
+ // return 200 with an empty body. The key embedded in the same watch page
252
+ // can request an equivalent, usable track for YouTube's Android client.
253
+ // Maintenance: update the Android client version if this player request stops returning tracks.
254
+ const apiKey = html.match(/"INNERTUBE_API_KEY":"([^"]+)"/)?.[1];
255
+ if (apiKey) {
256
+ const apiResponse = await safeFetch(`https://www.youtube.com/youtubei/v1/player?key=${encodeURIComponent(apiKey)}`, "player api", {
257
+ method: "POST",
258
+ headers: { "content-type": "application/json" },
259
+ body: JSON.stringify({
260
+ context: {
261
+ client: {
262
+ clientName: "ANDROID",
263
+ clientVersion: "20.10.38",
264
+ androidSdkVersion: 35,
265
+ hl: options.lang ?? "en",
266
+ gl: "US",
267
+ },
268
+ },
269
+ videoId: ref.id,
270
+ }),
271
+ });
272
+ if (!apiResponse.ok) {
273
+ throw mapStatus(apiResponse.status, "player api");
274
+ }
275
+ const apiPlayer = parsePlayerObject(await apiResponse.json());
276
+ if (apiPlayer.captionTracks.length > 0) {
277
+ track = selectTrack(apiPlayer.captionTracks, options.lang);
278
+ captionResponse = await safeFetch(track.baseUrl, "caption track");
279
+ if (!captionResponse.ok) {
280
+ throw mapStatus(captionResponse.status, "caption track");
281
+ }
282
+ captionBody = await captionResponse.text();
283
+ }
284
+ }
285
+ }
286
+ return {
287
+ ...player,
288
+ text: parseTimedText(captionBody),
289
+ captionLang: track.lang,
290
+ captionKind: track.kind,
291
+ url: ref.url,
292
+ };
293
+ }
294
+ async function safeFetch(url, label, init = {}) {
295
+ const controller = new AbortController();
296
+ const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
297
+ try {
298
+ return await fetch(url, {
299
+ ...init,
300
+ headers: {
301
+ "user-agent": "Mozilla/5.0 (compatible; tenbrains/2.2)",
302
+ ...init.headers,
303
+ },
304
+ signal: controller.signal,
305
+ });
306
+ }
307
+ catch (error) {
308
+ throw new CliError("PROVIDER_NETWORK", controller.signal.aborted
309
+ ? `youtube ${label}: request timed out after ${REQUEST_TIMEOUT_MS}ms`
310
+ : `youtube ${label}: ${error instanceof Error ? error.message : "network error"}`, { retryable: true, cause: error });
311
+ }
312
+ finally {
313
+ clearTimeout(timeout);
314
+ }
315
+ }
316
+ function mapStatus(status, label) {
317
+ if (status === 401 || status === 403) {
318
+ return new CliError("PROVIDER_UNAUTHORIZED", `youtube ${label}: video is private, restricted, or unavailable in this region (${status}).`, { details: { status } });
319
+ }
320
+ if (status === 429) {
321
+ return new CliError("PROVIDER_RATE_LIMITED", `youtube ${label}: rate limited (429).`, {
322
+ details: { status },
323
+ retryable: true,
324
+ });
325
+ }
326
+ if (status === 404) {
327
+ return new CliError("NOT_FOUND", manualFallback(`youtube ${label}: not found (404).`));
328
+ }
329
+ return new CliError("PROVIDER_UPSTREAM", `youtube ${label}: request failed (${status}).`, {
330
+ details: { status },
331
+ retryable: status >= 500,
332
+ });
333
+ }
334
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/youtube/client.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "tenbrains",
3
- "version": "2.1.0",
4
- "description": "Agent-first CLI for X research: analyze posts, track accounts, surface suggestions, and persist every outcome to a local database.",
3
+ "version": "2.3.0",
4
+ "description": "Agent-first CLI for X and YouTube research: analyze content, track accounts, surface suggestions, and persist every outcome locally.",
5
5
  "type": "module",
6
6
  "license": "MIT",
7
7
  "repository": {
@@ -15,6 +15,8 @@
15
15
  "agent",
16
16
  "x",
17
17
  "twitter",
18
+ "youtube",
19
+ "transcript",
18
20
  "research",
19
21
  "sqlite",
20
22
  "claude"
@@ -35,7 +37,7 @@
35
37
  ],
36
38
  "scripts": {
37
39
  "clean": "rm -rf dist",
38
- "build": "tsc -p tsconfig.build.json",
40
+ "build": "tsc -p tsconfig.build.json && chmod +x dist/bin/tenbrains.js",
39
41
  "dev": "tsx src/bin/tenbrains.ts",
40
42
  "tenbrains": "tsx src/bin/tenbrains.ts",
41
43
  "typecheck": "tsc -p tsconfig.json --noEmit",