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.
- package/AGENTS.md +19 -2
- package/README.md +93 -9
- package/dist/ai/analyzer.d.ts +7 -2
- package/dist/ai/analyzer.d.ts.map +1 -1
- package/dist/ai/analyzer.js +19 -5
- package/dist/ai/analyzer.js.map +1 -1
- package/dist/ai/mock.d.ts +2 -1
- package/dist/ai/mock.d.ts.map +1 -1
- package/dist/ai/mock.js +12 -0
- package/dist/ai/mock.js.map +1 -1
- package/dist/ai/prompts.d.ts +3 -1
- package/dist/ai/prompts.d.ts.map +1 -1
- package/dist/ai/prompts.js +17 -2
- package/dist/ai/prompts.js.map +1 -1
- package/dist/bin/tenbrains.js +0 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +115 -8
- package/dist/cli.js.map +1 -1
- package/dist/commands/analyze.d.ts.map +1 -1
- package/dist/commands/analyze.js +100 -11
- package/dist/commands/analyze.js.map +1 -1
- package/dist/commands/bookmark.d.ts.map +1 -1
- package/dist/commands/bookmark.js +10 -1
- package/dist/commands/bookmark.js.map +1 -1
- package/dist/commands/digest.d.ts +6 -1
- package/dist/commands/digest.d.ts.map +1 -1
- package/dist/commands/digest.js +15 -5
- package/dist/commands/digest.js.map +1 -1
- package/dist/commands/learn.d.ts.map +1 -1
- package/dist/commands/learn.js +14 -2
- package/dist/commands/learn.js.map +1 -1
- package/dist/commands/manifest.d.ts.map +1 -1
- package/dist/commands/manifest.js +6 -0
- package/dist/commands/manifest.js.map +1 -1
- package/dist/commands/objective-tags.d.ts +27 -0
- package/dist/commands/objective-tags.d.ts.map +1 -0
- package/dist/commands/objective-tags.js +105 -0
- package/dist/commands/objective-tags.js.map +1 -0
- package/dist/commands/objective.d.ts +11 -0
- package/dist/commands/objective.d.ts.map +1 -0
- package/dist/commands/objective.js +208 -0
- package/dist/commands/objective.js.map +1 -0
- package/dist/commands/record.d.ts +1 -1
- package/dist/commands/record.d.ts.map +1 -1
- package/dist/commands/record.js +10 -2
- package/dist/commands/record.js.map +1 -1
- package/dist/commands/search.d.ts.map +1 -1
- package/dist/commands/search.js +16 -2
- package/dist/commands/search.js.map +1 -1
- package/dist/commands/takeaway.d.ts.map +1 -1
- package/dist/commands/takeaway.js +4 -1
- package/dist/commands/takeaway.js.map +1 -1
- package/dist/core/text.d.ts +2 -0
- package/dist/core/text.d.ts.map +1 -1
- package/dist/core/text.js +10 -0
- package/dist/core/text.js.map +1 -1
- package/dist/db/database.d.ts +2 -1
- package/dist/db/database.d.ts.map +1 -1
- package/dist/db/database.js +3 -0
- package/dist/db/database.js.map +1 -1
- package/dist/db/migrations.d.ts.map +1 -1
- package/dist/db/migrations.js +25 -0
- package/dist/db/migrations.js.map +1 -1
- package/dist/db/repositories.d.ts +21 -1
- package/dist/db/repositories.d.ts.map +1 -1
- package/dist/db/repositories.js +209 -0
- package/dist/db/repositories.js.map +1 -1
- package/dist/domain/learn.d.ts +5 -4
- package/dist/domain/learn.d.ts.map +1 -1
- package/dist/domain/learn.js +39 -15
- package/dist/domain/learn.js.map +1 -1
- package/dist/domain/schemas.d.ts +14 -0
- package/dist/domain/schemas.d.ts.map +1 -1
- package/dist/domain/schemas.js +5 -0
- package/dist/domain/schemas.js.map +1 -1
- package/dist/domain/search.d.ts +2 -0
- package/dist/domain/search.d.ts.map +1 -1
- package/dist/domain/search.js +20 -1
- package/dist/domain/search.js.map +1 -1
- package/dist/domain/suggest.d.ts.map +1 -1
- package/dist/domain/suggest.js +34 -14
- package/dist/domain/suggest.js.map +1 -1
- package/dist/domain/types.d.ts +22 -0
- package/dist/domain/types.d.ts.map +1 -1
- package/dist/youtube/client.d.ts +31 -0
- package/dist/youtube/client.d.ts.map +1 -0
- package/dist/youtube/client.js +334 -0
- package/dist/youtube/client.js.map +1 -0
- package/package.json +5 -3
package/AGENTS.md
CHANGED
|
@@ -46,10 +46,12 @@ Error envelope:
|
|
|
46
46
|
inline strings, `@path` (read file), or `-` (read stdin). JSON inputs (`--posts`, `--ratings`) take
|
|
47
47
|
the same forms. `takeaway refresh` fetches a timeline when `--posts` is omitted (needs an X token,
|
|
48
48
|
usually a paid tier).
|
|
49
|
-
- **Ids are prefixed and stable**: `post_`, `ana_`, `acc_`, `snap_`, `bm_`, `sug_`, `trk_`. Any id
|
|
49
|
+
- **Ids are prefixed and stable**: `post_`, `ana_`, `acc_`, `snap_`, `bm_`, `sug_`, `trk_`, `obj_`. Any id
|
|
50
50
|
resolves via `tenbrains record get <id>`.
|
|
51
51
|
- **Dedup is automatic.** Re-ingesting a post with the same `--id` (external X id) reuses the stored
|
|
52
52
|
post (`meta.deduped: true`).
|
|
53
|
+
- **Objective tagging is explicit.** Repeat `--objective <slug>` on supported creation commands, or
|
|
54
|
+
use `objective link`; objectives must already exist. The current focus never adds tags.
|
|
53
55
|
- **Isolate state with `--db <path>`** if you want a per-task workspace.
|
|
54
56
|
- **No environment variables.** Configure once with `tenbrains setup --provider <p> --api-key <k>`
|
|
55
57
|
(add `--x-bearer <token>` for X timeline fetches; `-` pipes a secret without echo). Or test offline
|
|
@@ -73,6 +75,21 @@ echo '[{"concept":"Agentic","familiarity":2,"interest":5}]' \
|
|
|
73
75
|
| tenbrains analyze --provider mock --text "..." --learn --minutes 10 --ratings -
|
|
74
76
|
```
|
|
75
77
|
|
|
78
|
+
Create and apply learning objectives (repeat `--objective` for multiple goals):
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
tenbrains objective add "Agentic systems" --focus
|
|
82
|
+
tenbrains analyze --provider mock --text "..." --objective agentic-systems
|
|
83
|
+
tenbrains objective link bm_... --objective agentic-systems
|
|
84
|
+
tenbrains objective show agentic-systems
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Objective descriptions lens learning-track concept order through deterministic token overlap. For
|
|
88
|
+
multiple described objectives, use the maximum overlap against any one description. Read
|
|
89
|
+
`objective show`'s raw progress counts; do not derive or present a made-up completion percentage.
|
|
90
|
+
The current focus also biases `suggest generate` when it has a description, but never tags.
|
|
91
|
+
Use `search --objective <slug>` or `digest --objective <slug>` for explicit scoped output.
|
|
92
|
+
|
|
76
93
|
Account takeaways (supply recent posts, or fetch from X with a token):
|
|
77
94
|
|
|
78
95
|
```bash
|
|
@@ -85,7 +102,7 @@ tenbrains takeaway show levelsio --history
|
|
|
85
102
|
Suggestion feedback loop:
|
|
86
103
|
|
|
87
104
|
```bash
|
|
88
|
-
tenbrains suggest generate #
|
|
105
|
+
tenbrains suggest generate # saved-signal ranking + described current-focus bias
|
|
89
106
|
tenbrains suggest save sug_... # -> creates a bookmark (meta.bookmarkId)
|
|
90
107
|
tenbrains suggest dismiss sug_... # -> suppressed in future ranking
|
|
91
108
|
```
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# tenbrains
|
|
2
2
|
|
|
3
|
-
An **agent-first** CLI for X research. It analyzes posts, tracks followed accounts, surfaces
|
|
3
|
+
An **agent-first** CLI for X and YouTube research. It analyzes posts and video transcripts, tracks followed accounts, surfaces
|
|
4
4
|
suggestions, and **persists every outcome to a local SQLite database** — all from the command line,
|
|
5
5
|
with no `.env` files and no hosted backend.
|
|
6
6
|
|
|
@@ -21,8 +21,8 @@ machine-readable code and a deterministic exit status, and the entire surface is
|
|
|
21
21
|
error codes, and exit codes as JSON — an agent can discover the whole tool in one call.
|
|
22
22
|
- **Non-interactive.** No blocking prompts. Content comes in via flags, `@file`, or `-` (stdin);
|
|
23
23
|
credentials are collected through commands, never by hand-editing a dotfile.
|
|
24
|
-
- **Everything persisted.** Posts, analyses, takeaways, bookmarks, suggestions,
|
|
25
|
-
all land in one local SQLite file you can point anywhere with `--db`.
|
|
24
|
+
- **Everything persisted.** Posts, analyses, takeaways, bookmarks, suggestions, learning tracks,
|
|
25
|
+
and learning objectives all land in one local SQLite file you can point anywhere with `--db`.
|
|
26
26
|
- **Offline-capable.** The built-in `mock` provider produces deterministic analysis with no network,
|
|
27
27
|
so agents and CI can exercise the full pipeline without API keys.
|
|
28
28
|
|
|
@@ -32,6 +32,13 @@ machine-readable code and a deterministic exit status, and the entire surface is
|
|
|
32
32
|
|
|
33
33
|
## Install
|
|
34
34
|
|
|
35
|
+
```bash
|
|
36
|
+
npm install -g tenbrains # from npm — puts `tenbrains` (and `tb`) on PATH
|
|
37
|
+
tenbrains --help
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Or from a clone:
|
|
41
|
+
|
|
35
42
|
```bash
|
|
36
43
|
npm install
|
|
37
44
|
npm run build
|
|
@@ -58,6 +65,9 @@ tenbrains analyze --author levelsio --id 1790000000000000000 \
|
|
|
58
65
|
# 2b. Or analyze a tweet by URL — fetched free via X's oEmbed endpoint, no key needed.
|
|
59
66
|
tenbrains analyze --url "https://x.com/jack/status/20"
|
|
60
67
|
|
|
68
|
+
# 2c. Or fetch and analyze public YouTube captions, then add a narrative digest and study plan.
|
|
69
|
+
tenbrains analyze --url "https://www.youtube.com/watch?v=M7lc1UVf-VE" --summarize --learn
|
|
70
|
+
|
|
61
71
|
# 3. Read it back / explore.
|
|
62
72
|
tenbrains analyze list --limit 5
|
|
63
73
|
tenbrains search "agent cli"
|
|
@@ -101,15 +111,16 @@ Exit codes: `0` success · `2` usage · `3` not found · `4` missing credentials
|
|
|
101
111
|
|
|
102
112
|
| Command | Purpose |
|
|
103
113
|
| --- | --- |
|
|
104
|
-
| `analyze` | Analyze a post (`--text`, or `--url
|
|
114
|
+
| `analyze` | Analyze a post or YouTube transcript (`--text`, `--transcript`, or `--url` to fetch) into topic, summary, intent, and concepts. `--summarize` adds a narrative digest; `--learn` builds a track. |
|
|
105
115
|
| `analyze list` / `analyze get <id>` | Read stored analyses. |
|
|
116
|
+
| `objective add\|list\|show\|focus\|archive\|link\|unlink` | Manage first-class learning goals, one optional current focus, and explicit record tags. |
|
|
106
117
|
| `takeaway follow\|unfollow\|list\|refresh\|show` | Track accounts; summarize recent posts (supplied via `--posts` or fetched from X) into snapshots. |
|
|
107
|
-
| `suggest generate\|list\|save\|dismiss\|add` | Rank un-saved posts against your saved signal; save/dismiss feedback. |
|
|
118
|
+
| `suggest generate\|list\|save\|dismiss\|add` | Rank un-saved posts against your saved signal, biased toward a described current objective focus; save/dismiss feedback. |
|
|
108
119
|
| `bookmark add\|list\|show\|tag\|remove` | Save posts with tags (auto-suggested from analysis) and notes. |
|
|
109
120
|
| `learn generate\|today\|done\|show\|list` | Build 7-day Feynman learning tracks, get today's task, and check off progress. |
|
|
110
|
-
| `search <query>` | Full-text search (SQLite FTS5, BM25-ranked, stemmed) across analyses, takeaways, and bookmarks. |
|
|
121
|
+
| `search <query>` | Full-text search (SQLite FTS5, BM25-ranked, stemmed) across analyses, takeaways, and bookmarks; optionally filter by objective. |
|
|
111
122
|
| `import x-archive <path>` | Bulk-import your extracted official X archive: likes become bookmarked posts, your tweets become posts. Free, idempotent. |
|
|
112
|
-
| `digest [--days N]` | Markdown recap of analyses, takeaways, and bookmarks saved in the window (default 7 days). |
|
|
123
|
+
| `digest [--days N]` | Markdown recap of analyses, takeaways, and bookmarks saved in the window (default 7 days), optionally filtered by objective. |
|
|
113
124
|
| `setup` / `config set\|get\|list\|unset\|path` | Collect and manage provider credentials and defaults. |
|
|
114
125
|
| `record get <id>` | Resolve any record by its prefixed id (`post_`, `ana_`, `acc_`, ...). |
|
|
115
126
|
| `db stats\|migrate\|vacuum\|reindex\|reset` | Inspect and maintain the database. |
|
|
@@ -125,6 +136,78 @@ echo "long post text..." | tenbrains analyze --provider mock --text -
|
|
|
125
136
|
tenbrains takeaway refresh levelsio --provider mock --posts @recent.json
|
|
126
137
|
```
|
|
127
138
|
|
|
139
|
+
## Learning objectives
|
|
140
|
+
|
|
141
|
+
Objectives are persistent learning goals, separate from loose bookmark tags. Each objective has a
|
|
142
|
+
name, derived slug, optional description, active/archived lifecycle, and tagged-record counts.
|
|
143
|
+
You can keep several active objectives while marking at most one as the current focus:
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
tenbrains objective add "Stablecoins" \
|
|
147
|
+
--description "Understand reserve models, settlement, and failure modes." --focus
|
|
148
|
+
tenbrains objective add "AI agents"
|
|
149
|
+
tenbrains objective list
|
|
150
|
+
tenbrains objective show # defaults to the current focus
|
|
151
|
+
tenbrains objective focus ai-agents
|
|
152
|
+
tenbrains objective focus --clear
|
|
153
|
+
tenbrains objective link post_... --objective stablecoins
|
|
154
|
+
tenbrains objective unlink post_... --objective stablecoins
|
|
155
|
+
tenbrains objective archive stablecoins
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Tag at creation time with a repeatable `--objective` flag:
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
tenbrains analyze --provider mock --text "..." \
|
|
162
|
+
--objective stablecoins --objective ai-agents
|
|
163
|
+
tenbrains takeaway follow levelsio --objective ai-agents
|
|
164
|
+
tenbrains bookmark add --post-id post_... --objective stablecoins
|
|
165
|
+
tenbrains learn generate --analysis ana_... --objective stablecoins
|
|
166
|
+
tenbrains search "reserve risk" --objective stablecoins
|
|
167
|
+
tenbrains digest --objective stablecoins
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
`bookmark add` tags the bookmark's post. Without an explicit `--objective`, `learn generate` inherits
|
|
171
|
+
the objective tags on its source analysis' post; supplying the flag overrides that inheritance.
|
|
172
|
+
Every referenced objective must already exist or the command returns `NOT_FOUND` without silently
|
|
173
|
+
creating one. Focus never tags records automatically. `objective show` groups tagged posts,
|
|
174
|
+
accounts, bookmarks, and tracks; `record get` includes an `objectives` array for linkable records.
|
|
175
|
+
|
|
176
|
+
When a selected or inherited objective has a description, learning tracks rank concepts first by
|
|
177
|
+
deterministic token overlap with that description, then by the existing interest and familiarity
|
|
178
|
+
ratings. With multiple described objectives, a concept uses its highest overlap with any one
|
|
179
|
+
description; matches are not summed across objectives. `objective show` also returns descriptive
|
|
180
|
+
progress counts under `data.progress`:
|
|
181
|
+
accounts followed, posts and transcripts analyzed, bookmarks saved, tracks completed, and learning
|
|
182
|
+
days completed/total. It never fabricates a completion percentage.
|
|
183
|
+
|
|
184
|
+
`suggest generate` adds deterministic token-overlap relevance from the current focus description to
|
|
185
|
+
its existing saved-interest scores. With no focus or no usable focus description, its scores,
|
|
186
|
+
reasons, and ordering are unchanged. This bias never creates objective links. `search` and `digest`
|
|
187
|
+
accept one `--objective <slug>` filter and return only analyses whose posts, takeaways whose
|
|
188
|
+
accounts, and bookmarks (directly or through their posts) are tagged to that objective. Unknown
|
|
189
|
+
objectives return `NOT_FOUND`.
|
|
190
|
+
|
|
191
|
+
## YouTube transcripts
|
|
192
|
+
|
|
193
|
+
Pass a public YouTube watch, `youtu.be`, Shorts, or embed URL to `analyze`. tenbrains selects a
|
|
194
|
+
caption track without an API key (manual before auto-generated; `--lang`, then English, then the
|
|
195
|
+
first available), stores the transcript and video metadata with the post, and runs the normal
|
|
196
|
+
analysis pipeline:
|
|
197
|
+
|
|
198
|
+
```bash
|
|
199
|
+
tenbrains analyze --url "https://youtu.be/M7lc1UVf-VE" --lang en
|
|
200
|
+
tenbrains analyze --url "https://youtu.be/M7lc1UVf-VE" --summarize --learn
|
|
201
|
+
tenbrains analyze --url "https://youtu.be/M7lc1UVf-VE" --transcript @captions.txt
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
`--summarize` returns `{ summary, keyPoints[] }` under `data.summary`, persists it in the post's
|
|
205
|
+
`raw` metadata, and uses that digest as the condensed input for concept extraction. It composes
|
|
206
|
+
with `--learn`. If a video is unavailable or has no captions, supply an existing transcript with
|
|
207
|
+
`--transcript <text|@file|->`. v1 is caption-only: it does not download audio or invoke Whisper.
|
|
208
|
+
YouTube's WEB caption URLs can return empty bodies, so the client retries through the embedded
|
|
209
|
+
Android player API; that undocumented client version is the primary maintenance surface.
|
|
210
|
+
|
|
128
211
|
## Configuration & credentials
|
|
129
212
|
|
|
130
213
|
There is **no `.env`**. The CLI owns credential collection:
|
|
@@ -172,8 +255,9 @@ If your tier can't read a tweet/timeline, the CLI returns a structured `PROVIDER
|
|
|
172
255
|
|
|
173
256
|
A single SQLite file (default `~/.local/share/tenbrains/tenbrains.db`, override with `--db`). Schema
|
|
174
257
|
is versioned and migrated automatically on open. Tables: `posts`, `analyses`, `accounts`,
|
|
175
|
-
`takeaway_snapshots`, `bookmarks`, `suggestions`, `learning_tracks`,
|
|
176
|
-
FTS5 index (`search_fts`) behind `search` — rebuild
|
|
258
|
+
`takeaway_snapshots`, `bookmarks`, `suggestions`, `learning_tracks`, `track_progress`, `objectives`,
|
|
259
|
+
and `objective_links`, plus a trigger-maintained FTS5 index (`search_fts`) behind `search` — rebuild
|
|
260
|
+
it anytime with `tenbrains db reindex`.
|
|
177
261
|
|
|
178
262
|
```bash
|
|
179
263
|
tenbrains --db ./research.db analyze --provider mock --text "..." # isolate a workspace
|
package/dist/ai/analyzer.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type AnalysisResult, type TakeawayResult } from "../domain/schemas.js";
|
|
1
|
+
import { type AnalysisResult, type SummaryResult, type TakeawayResult } from "../domain/schemas.js";
|
|
2
2
|
import type { ResolvedProvider } from "./resolve.js";
|
|
3
3
|
export interface AnalysisOutcome {
|
|
4
4
|
result: AnalysisResult;
|
|
@@ -10,7 +10,12 @@ export interface PostForAnalysis {
|
|
|
10
10
|
authorName?: string | undefined;
|
|
11
11
|
url?: string | undefined;
|
|
12
12
|
}
|
|
13
|
-
export declare function analyzePost(resolved: ResolvedProvider, post: PostForAnalysis): Promise<AnalysisOutcome>;
|
|
13
|
+
export declare function analyzePost(resolved: ResolvedProvider, post: PostForAnalysis, kind?: "tweet" | "transcript"): Promise<AnalysisOutcome>;
|
|
14
|
+
export interface SummaryOutcome {
|
|
15
|
+
result: SummaryResult;
|
|
16
|
+
mock: boolean;
|
|
17
|
+
}
|
|
18
|
+
export declare function summarizeContent(resolved: ResolvedProvider, content: string): Promise<SummaryOutcome>;
|
|
14
19
|
export interface TakeawayOutcome {
|
|
15
20
|
result: TakeawayResult;
|
|
16
21
|
mock: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"analyzer.d.ts","sourceRoot":"","sources":["../../src/ai/analyzer.ts"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,cAAc,EAEnB,KAAK,cAAc,EAEpB,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"analyzer.d.ts","sourceRoot":"","sources":["../../src/ai/analyzer.ts"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,cAAc,EAEnB,KAAK,aAAa,EAElB,KAAK,cAAc,EAEpB,MAAM,sBAAsB,CAAC;AAY9B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAErD,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,cAAc,CAAC;IACvB,IAAI,EAAE,OAAO,CAAC;CACf;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC1B;AAED,wBAAsB,WAAW,CAC/B,QAAQ,EAAE,gBAAgB,EAC1B,IAAI,EAAE,eAAe,EACrB,IAAI,GAAE,OAAO,GAAG,YAAsB,GACrC,OAAO,CAAC,eAAe,CAAC,CAkB1B;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,aAAa,CAAC;IACtB,IAAI,EAAE,OAAO,CAAC;CACf;AAED,wBAAsB,gBAAgB,CACpC,QAAQ,EAAE,gBAAgB,EAC1B,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,cAAc,CAAC,CAkBzB;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,cAAc,CAAC;IACvB,IAAI,EAAE,OAAO,CAAC;CACf;AAED,wBAAsB,gBAAgB,CACpC,QAAQ,EAAE,gBAAgB,EAC1B,KAAK,EAAE;IACL,OAAO,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;KAAE,CAAC;IACzD,KAAK,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;KAAE,CAAC,CAAC;CAC/D,GACA,OAAO,CAAC,eAAe,CAAC,CAkB1B"}
|
package/dist/ai/analyzer.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { parseOrThrow } from "../core/validate.js";
|
|
2
|
-
import { AnalysisResultSchema, TakeawayResultSchema, } from "../domain/schemas.js";
|
|
2
|
+
import { AnalysisResultSchema, SummaryResultSchema, TakeawayResultSchema, } from "../domain/schemas.js";
|
|
3
3
|
import { complete } from "./client.js";
|
|
4
4
|
import { extractJsonObject } from "./json.js";
|
|
5
|
-
import { mockAnalysis, mockTakeaway } from "./mock.js";
|
|
6
|
-
import { accountTakeawaySystemPrompt, accountTakeawayUserPrompt, tweetAnalysisSystemPrompt, tweetAnalysisUserPrompt, } from "./prompts.js";
|
|
7
|
-
export async function analyzePost(resolved, post) {
|
|
5
|
+
import { mockAnalysis, mockSummary, mockTakeaway } from "./mock.js";
|
|
6
|
+
import { accountTakeawaySystemPrompt, accountTakeawayUserPrompt, contentSummarySystemPrompt, contentSummaryUserPrompt, tweetAnalysisSystemPrompt, tweetAnalysisUserPrompt, } from "./prompts.js";
|
|
7
|
+
export async function analyzePost(resolved, post, kind = "tweet") {
|
|
8
8
|
if (resolved.provider === "mock") {
|
|
9
9
|
return { result: mockAnalysis(post.text), mock: true };
|
|
10
10
|
}
|
|
@@ -12,12 +12,26 @@ export async function analyzePost(resolved, post) {
|
|
|
12
12
|
provider: resolved.provider,
|
|
13
13
|
model: resolved.model,
|
|
14
14
|
apiKey: resolved.apiKey,
|
|
15
|
-
system: tweetAnalysisSystemPrompt(),
|
|
15
|
+
system: tweetAnalysisSystemPrompt(kind),
|
|
16
16
|
user: tweetAnalysisUserPrompt(post),
|
|
17
17
|
});
|
|
18
18
|
const result = parseOrThrow(AnalysisResultSchema, extractJsonObject(text), "Provider response did not match the expected analysis shape.", "PROVIDER_BAD_OUTPUT");
|
|
19
19
|
return { result, mock: false };
|
|
20
20
|
}
|
|
21
|
+
export async function summarizeContent(resolved, content) {
|
|
22
|
+
if (resolved.provider === "mock") {
|
|
23
|
+
return { result: mockSummary(content), mock: true };
|
|
24
|
+
}
|
|
25
|
+
const text = await complete({
|
|
26
|
+
provider: resolved.provider,
|
|
27
|
+
model: resolved.model,
|
|
28
|
+
apiKey: resolved.apiKey,
|
|
29
|
+
system: contentSummarySystemPrompt(),
|
|
30
|
+
user: contentSummaryUserPrompt(content),
|
|
31
|
+
});
|
|
32
|
+
const result = parseOrThrow(SummaryResultSchema, extractJsonObject(text), "Provider response did not match the expected summary shape.", "PROVIDER_BAD_OUTPUT");
|
|
33
|
+
return { result, mock: false };
|
|
34
|
+
}
|
|
21
35
|
export async function summarizeAccount(resolved, input) {
|
|
22
36
|
if (resolved.provider === "mock") {
|
|
23
37
|
return { result: mockTakeaway(input.posts), mock: true };
|
package/dist/ai/analyzer.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"analyzer.js","sourceRoot":"","sources":["../../src/ai/analyzer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAEL,oBAAoB,EAEpB,oBAAoB,GACrB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"analyzer.js","sourceRoot":"","sources":["../../src/ai/analyzer.ts"],"names":[],"mappings":"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"}
|
package/dist/ai/mock.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import type { AnalysisResult, TakeawayResult } from "../domain/schemas.js";
|
|
1
|
+
import type { AnalysisResult, SummaryResult, TakeawayResult } from "../domain/schemas.js";
|
|
2
2
|
export declare function mockAnalysis(text: string): AnalysisResult;
|
|
3
|
+
export declare function mockSummary(text: string): SummaryResult;
|
|
3
4
|
export declare function mockTakeaway(posts: Array<{
|
|
4
5
|
text: string;
|
|
5
6
|
}>): TakeawayResult;
|
package/dist/ai/mock.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mock.d.ts","sourceRoot":"","sources":["../../src/ai/mock.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"mock.d.ts","sourceRoot":"","sources":["../../src/ai/mock.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAsC1F,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,CAsBzD;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,CAWvD;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,GAAG,cAAc,CAgB3E"}
|
package/dist/ai/mock.js
CHANGED
|
@@ -49,6 +49,18 @@ export function mockAnalysis(text) {
|
|
|
49
49
|
});
|
|
50
50
|
return { topic, summary, intent, novelConcepts };
|
|
51
51
|
}
|
|
52
|
+
export function mockSummary(text) {
|
|
53
|
+
const sentences = text
|
|
54
|
+
.trim()
|
|
55
|
+
.split(/(?<=[.!?])\s+/)
|
|
56
|
+
.filter(Boolean);
|
|
57
|
+
const summary = (sentences.slice(0, 4).join(" ") || firstSentence(text)).slice(0, 1200);
|
|
58
|
+
const terms = significantTerms(text, 5);
|
|
59
|
+
const keyPoints = terms.length
|
|
60
|
+
? terms.map((term) => `${titleCase(term)} is a recurring theme in the content.`)
|
|
61
|
+
: ["The supplied content does not contain enough detail for additional key points."];
|
|
62
|
+
return { summary, keyPoints };
|
|
63
|
+
}
|
|
52
64
|
export function mockTakeaway(posts) {
|
|
53
65
|
const combined = posts.map((p) => p.text).join("\n");
|
|
54
66
|
const terms = significantTerms(combined, 6);
|
package/dist/ai/mock.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mock.js","sourceRoot":"","sources":["../../src/ai/mock.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAGnD;;;;;GAKG;AAEH,SAAS,SAAS,CAAC,IAAY;IAC7B,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IACrC,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACxD,CAAC;AAED,SAAS,aAAa,CAAC,IAAY;IACjC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;IAC5B,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC;IAC/C,MAAM,QAAQ,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;IACrD,OAAO,QAAQ,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC;AAC3E,CAAC;AAED,SAAS,YAAY,CAAC,IAAY;IAChC,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;IACjC,IACE,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC;QAC1B,wDAAwD,CAAC,IAAI,CAAC,KAAK,CAAC,EACpE,CAAC;QACD,OAAO,+CAA+C,CAAC;IACzD,CAAC;IACD,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,kCAAkC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QACzE,OAAO,sCAAsC,CAAC;IAChD,CAAC;IACD,IAAI,4CAA4C,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QAC7D,OAAO,4BAA4B,CAAC;IACtC,CAAC;IACD,OAAO,iCAAiC,CAAC;AAC3C,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,MAAM,KAAK,GAAG,gBAAgB,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IACxC,MAAM,KAAK,GACT,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,oBAAoB,CAAC;IACzF,MAAM,OAAO,GAAG,aAAa,CAAC,IAAI,CAAC,IAAI,sBAAsB,KAAK,CAAC,WAAW,EAAE,GAAG,CAAC;IACpF,MAAM,MAAM,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IAElC,MAAM,aAAa,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QACvD,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QACtB,IAAI,IAAI,EAAE,CAAC;YACT,OAAO;gBACL,IAAI,EAAE,SAAS,CAAC,IAAI,CAAC;gBACrB,mBAAmB,EAAE,IAAI,SAAS,CAAC,IAAI,CAAC,sDAAsD,KAAK,CAAC,WAAW,EAAE,SAAS;aAC3H,CAAC;QACJ,CAAC;QACD,OAAO;YACL,IAAI,EAAE,mBAAmB,CAAC,GAAG,CAAC,EAAE;YAChC,mBAAmB,EAAE,6DAA6D,KAAK,CAAC,WAAW,EAAE,GAAG;SACzG,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,CAAC;AACnD,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,KAA8B;IACzD,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACrD,MAAM,KAAK,GAAG,gBAAgB,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;IAC5C,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,eAAe,CAAC;IAC7E,MAAM,OAAO,GAAG,UAAU,KAAK,CAAC,MAAM,eAAe,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,2CAA2C,KAAK,GAAG,CAAC;IAEtI,MAAM,SAAS,GAAa,EAAE,CAAC;IAC/B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QACnE,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QACtB,SAAS,CAAC,IAAI,CACZ,IAAI;YACF,CAAC,CAAC,sBAAsB,SAAS,CAAC,IAAI,CAAC,GAAG;YAC1C,CAAC,CAAC,2CAA2C,KAAK,CAAC,MAAM,iBAAiB,CAC7E,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC;AAChC,CAAC"}
|
|
1
|
+
{"version":3,"file":"mock.js","sourceRoot":"","sources":["../../src/ai/mock.ts"],"names":[],"mappings":"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"}
|
package/dist/ai/prompts.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
export declare function tweetAnalysisSystemPrompt(): string;
|
|
1
|
+
export declare function tweetAnalysisSystemPrompt(kind?: "tweet" | "transcript"): string;
|
|
2
|
+
export declare function contentSummarySystemPrompt(): string;
|
|
3
|
+
export declare function contentSummaryUserPrompt(content: string): string;
|
|
2
4
|
export declare function tweetAnalysisUserPrompt(post: {
|
|
3
5
|
text: string;
|
|
4
6
|
authorUsername?: string | undefined;
|
package/dist/ai/prompts.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../../src/ai/prompts.ts"],"names":[],"mappings":"AAWA,wBAAgB,yBAAyB,IAAI,MAAM,
|
|
1
|
+
{"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../../src/ai/prompts.ts"],"names":[],"mappings":"AAWA,wBAAgB,yBAAyB,CAAC,IAAI,GAAE,OAAO,GAAG,YAAsB,GAAG,MAAM,CAYxF;AAED,wBAAgB,0BAA0B,IAAI,MAAM,CASnD;AAED,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEhE;AAED,wBAAgB,uBAAuB,CAAC,IAAI,EAAE;IAC5C,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC1B,GAAG,MAAM,CAET;AAED,wBAAgB,2BAA2B,IAAI,MAAM,CAUpD;AAED,wBAAgB,yBAAyB,CAAC,KAAK,EAAE;IAC/C,OAAO,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;KAAE,CAAC;IACzD,KAAK,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;KAAE,CAAC,CAAC;CAC/D,GAAG,MAAM,CAST"}
|
package/dist/ai/prompts.js
CHANGED
|
@@ -6,9 +6,11 @@ function compactPost(post) {
|
|
|
6
6
|
url: post.url ?? null,
|
|
7
7
|
};
|
|
8
8
|
}
|
|
9
|
-
export function tweetAnalysisSystemPrompt() {
|
|
9
|
+
export function tweetAnalysisSystemPrompt(kind = "tweet") {
|
|
10
10
|
return [
|
|
11
|
-
|
|
11
|
+
kind === "transcript"
|
|
12
|
+
? "You are analyzing a video transcript."
|
|
13
|
+
: "You are analyzing a post on X.",
|
|
12
14
|
"Return only a valid JSON object with exactly these keys: topic, summary, intent, novelConcepts.",
|
|
13
15
|
"novelConcepts must be an array with exactly 5 objects.",
|
|
14
16
|
"Each concept object must have keys: name and whyItMattersInTweet.",
|
|
@@ -17,6 +19,19 @@ export function tweetAnalysisSystemPrompt() {
|
|
|
17
19
|
"Keep it factual and avoid speculation when evidence is missing.",
|
|
18
20
|
].join(" ");
|
|
19
21
|
}
|
|
22
|
+
export function contentSummarySystemPrompt() {
|
|
23
|
+
return [
|
|
24
|
+
"You are summarizing long-form content.",
|
|
25
|
+
"Return only a valid JSON object with exactly these keys: summary, keyPoints.",
|
|
26
|
+
"summary must be a substantive, readable multi-paragraph string.",
|
|
27
|
+
"keyPoints must be an array of non-empty strings.",
|
|
28
|
+
"Stay factual and grounded in the supplied content.",
|
|
29
|
+
"Do not include markdown fences, comments, or extra keys.",
|
|
30
|
+
].join(" ");
|
|
31
|
+
}
|
|
32
|
+
export function contentSummaryUserPrompt(content) {
|
|
33
|
+
return JSON.stringify({ content }, null, 2);
|
|
34
|
+
}
|
|
20
35
|
export function tweetAnalysisUserPrompt(post) {
|
|
21
36
|
return JSON.stringify({ post: compactPost(post) }, null, 2);
|
|
22
37
|
}
|
package/dist/ai/prompts.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prompts.js","sourceRoot":"","sources":["../../src/ai/prompts.ts"],"names":[],"mappings":"AAEA,SAAS,WAAW,CAAC,IAAqE;IACxF,OAAO;QACL,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,cAAc,EAAE,IAAI,CAAC,cAAc,IAAI,IAAI;QAC3C,UAAU,EAAE,IAAI,CAAC,UAAU,IAAI,IAAI;QACnC,GAAG,EAAE,IAAI,CAAC,GAAG,IAAI,IAAI;KACtB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,yBAAyB;
|
|
1
|
+
{"version":3,"file":"prompts.js","sourceRoot":"","sources":["../../src/ai/prompts.ts"],"names":[],"mappings":"AAEA,SAAS,WAAW,CAAC,IAAqE;IACxF,OAAO;QACL,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,cAAc,EAAE,IAAI,CAAC,cAAc,IAAI,IAAI;QAC3C,UAAU,EAAE,IAAI,CAAC,UAAU,IAAI,IAAI;QACnC,GAAG,EAAE,IAAI,CAAC,GAAG,IAAI,IAAI;KACtB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,yBAAyB,CAAC,OAA+B,OAAO;IAC9E,OAAO;QACL,IAAI,KAAK,YAAY;YACnB,CAAC,CAAC,uCAAuC;YACzC,CAAC,CAAC,gCAAgC;QACpC,iGAAiG;QACjG,wDAAwD;QACxD,mEAAmE;QACnE,kFAAkF;QAClF,0DAA0D;QAC1D,iEAAiE;KAClE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACd,CAAC;AAED,MAAM,UAAU,0BAA0B;IACxC,OAAO;QACL,wCAAwC;QACxC,8EAA8E;QAC9E,iEAAiE;QACjE,kDAAkD;QAClD,oDAAoD;QACpD,0DAA0D;KAC3D,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACd,CAAC;AAED,MAAM,UAAU,wBAAwB,CAAC,OAAe;IACtD,OAAO,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;AAC9C,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,IAKvC;IACC,OAAO,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,WAAW,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;AAC9D,CAAC;AAED,MAAM,UAAU,2BAA2B;IACzC,OAAO;QACL,mEAAmE;QACnE,8EAA8E;QAC9E,qCAAqC;QACrC,2DAA2D;QAC3D,yEAAyE;QACzE,oDAAoD;QACpD,0DAA0D;KAC3D,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACd,CAAC;AAED,MAAM,UAAU,yBAAyB,CAAC,KAGzC;IACC,OAAO,IAAI,CAAC,SAAS,CACnB;QACE,OAAO,EAAE,EAAE,QAAQ,EAAE,KAAK,CAAC,OAAO,CAAC,QAAQ,EAAE,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,IAAI,IAAI,IAAI,EAAE;QAC/E,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,IAAI,IAAI,EAAE,CAAC,CAAC;KAChF,EACD,IAAI,EACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
|
package/dist/bin/tenbrains.js
CHANGED
|
File without changes
|
package/dist/cli.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAkB,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAkB,MAAM,WAAW,CAAC;AA6LpD,wBAAgB,YAAY,IAAI,OAAO,CAinBtC;AAED,wBAAsB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAwBvD"}
|
package/dist/cli.js
CHANGED
|
@@ -8,6 +8,7 @@ import { digestCommand } from "./commands/digest.js";
|
|
|
8
8
|
import { importXArchiveCommand } from "./commands/import.js";
|
|
9
9
|
import { learnDoneCommand, learnGenerateCommand, learnListCommand, learnShowCommand, learnTodayCommand, } from "./commands/learn.js";
|
|
10
10
|
import { manifestCommand } from "./commands/manifest.js";
|
|
11
|
+
import { objectiveAddCommand, objectiveArchiveCommand, objectiveFocusCommand, objectiveLinkCommand, objectiveListCommand, objectiveShowCommand, objectiveUnlinkCommand, } from "./commands/objective.js";
|
|
11
12
|
import { recordGetCommand } from "./commands/record.js";
|
|
12
13
|
import { searchCommand } from "./commands/search.js";
|
|
13
14
|
import { suggestAddCommand, suggestDismissCommand, suggestGenerateCommand, suggestListCommand, suggestSaveCommand, } from "./commands/suggest.js";
|
|
@@ -92,7 +93,12 @@ function makeCommand(reg) {
|
|
|
92
93
|
cmd.argument(arg.spec, arg.description ?? "");
|
|
93
94
|
}
|
|
94
95
|
for (const option of reg.options ?? []) {
|
|
95
|
-
|
|
96
|
+
if (option.repeatable) {
|
|
97
|
+
cmd.option(option.flags, option.description, (value, previous) => [...previous, value], []);
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
cmd.option(option.flags, option.description);
|
|
101
|
+
}
|
|
96
102
|
}
|
|
97
103
|
for (const negation of reg.negations ?? []) {
|
|
98
104
|
cmd.option(negation.flags, negation.description);
|
|
@@ -117,7 +123,7 @@ export function buildProgram() {
|
|
|
117
123
|
const program = new Command();
|
|
118
124
|
program
|
|
119
125
|
.name("tenbrains")
|
|
120
|
-
.description("Agent-first CLI for X research: analyze
|
|
126
|
+
.description("Agent-first CLI for X and YouTube research: analyze content and persist every outcome to a local SQLite database.")
|
|
121
127
|
.version(readVersion(), "-v, --version")
|
|
122
128
|
.exitOverride()
|
|
123
129
|
.configureOutput({ writeErr: () => { } });
|
|
@@ -125,13 +131,25 @@ export function buildProgram() {
|
|
|
125
131
|
// --- analyze --------------------------------------------------------------
|
|
126
132
|
const analyze = makeCommand({
|
|
127
133
|
name: "analyze",
|
|
128
|
-
description: "Analyze a post into topic, summary, intent, and
|
|
134
|
+
description: "Analyze a post or YouTube transcript into topic, summary, intent, and concepts.",
|
|
129
135
|
options: [
|
|
130
136
|
...POST_INPUT_OPTIONS,
|
|
131
137
|
{
|
|
132
138
|
flags: "--thread [json]",
|
|
133
139
|
description: "Analyze a whole thread as one document: pass parts as JSON (@file/- ok), or bare with --url/--id to fetch the author's self-thread via the X API",
|
|
134
140
|
},
|
|
141
|
+
{
|
|
142
|
+
flags: "--transcript <text>",
|
|
143
|
+
description: "Video transcript; @file reads a file, - reads stdin",
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
flags: "--lang <code>",
|
|
147
|
+
description: "Preferred YouTube caption language (then English, then first available)",
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
flags: "--summarize",
|
|
151
|
+
description: "Also generate and persist a fuller narrative summary with key points",
|
|
152
|
+
},
|
|
135
153
|
{
|
|
136
154
|
flags: "--fetch <mode>",
|
|
137
155
|
description: "With --url/--id and no --text: auto|oembed|api (default auto, free-first)",
|
|
@@ -141,6 +159,11 @@ export function buildProgram() {
|
|
|
141
159
|
description: "X API Bearer token for --fetch api/fallback; - reads stdin",
|
|
142
160
|
},
|
|
143
161
|
...PROVIDER_OPTIONS,
|
|
162
|
+
{
|
|
163
|
+
flags: "--objective <slug>",
|
|
164
|
+
description: "Tag the resulting post; repeat for multiple existing objectives",
|
|
165
|
+
repeatable: true,
|
|
166
|
+
},
|
|
144
167
|
{ flags: "--learn", description: "Also generate a 7-day Feynman learning track" },
|
|
145
168
|
{ flags: "--ratings <json>", description: "Concept ratings JSON for --learn (@file/- ok)" },
|
|
146
169
|
{ flags: "--minutes <n>", description: "Minutes per day for --learn (default 10)" },
|
|
@@ -176,7 +199,14 @@ export function buildProgram() {
|
|
|
176
199
|
name: "follow",
|
|
177
200
|
description: "Follow an account for takeaway tracking.",
|
|
178
201
|
args: [{ spec: "<username>", description: "X username (with or without @)" }],
|
|
179
|
-
options: [
|
|
202
|
+
options: [
|
|
203
|
+
{ flags: "--name <name>", description: "Display name" },
|
|
204
|
+
{
|
|
205
|
+
flags: "--objective <slug>",
|
|
206
|
+
description: "Tag the followed account; repeat for multiple existing objectives",
|
|
207
|
+
repeatable: true,
|
|
208
|
+
},
|
|
209
|
+
],
|
|
180
210
|
handler: takeawayFollowCommand,
|
|
181
211
|
}));
|
|
182
212
|
takeaway.addCommand(makeCommand({
|
|
@@ -232,7 +262,7 @@ export function buildProgram() {
|
|
|
232
262
|
});
|
|
233
263
|
suggest.addCommand(makeCommand({
|
|
234
264
|
name: "generate",
|
|
235
|
-
description: "Regenerate
|
|
265
|
+
description: "Regenerate suggestions, biased by the described current objective focus.",
|
|
236
266
|
options: [{ flags: "--limit <n>", description: "Max suggestions returned (default 10)" }],
|
|
237
267
|
handler: suggestGenerateCommand,
|
|
238
268
|
}));
|
|
@@ -289,6 +319,11 @@ export function buildProgram() {
|
|
|
289
319
|
{ flags: "--tags <list>", description: "Comma-separated tags" },
|
|
290
320
|
{ flags: "--note <note>", description: "Freeform note" },
|
|
291
321
|
{ flags: "--source <source>", description: "Source label (default cli)" },
|
|
322
|
+
{
|
|
323
|
+
flags: "--objective <slug>",
|
|
324
|
+
description: "Tag the bookmarked post; repeat for multiple existing objectives",
|
|
325
|
+
repeatable: true,
|
|
326
|
+
},
|
|
292
327
|
],
|
|
293
328
|
negations: [{ flags: "--no-auto-tags", description: "Disable automatic tag suggestion" }],
|
|
294
329
|
handler: bookmarkAddCommand,
|
|
@@ -337,11 +372,16 @@ export function buildProgram() {
|
|
|
337
372
|
});
|
|
338
373
|
learn.addCommand(makeCommand({
|
|
339
374
|
name: "generate",
|
|
340
|
-
description: "Build a learning track
|
|
375
|
+
description: "Build a learning track, lensed by any selected objective descriptions.",
|
|
341
376
|
options: [
|
|
342
377
|
{ flags: "--analysis <id>", description: "Analysis id to build from" },
|
|
343
378
|
{ flags: "--ratings <json>", description: "Concept ratings JSON (@file/- ok)" },
|
|
344
379
|
{ flags: "--minutes <n>", description: "Minutes per day (default 10)" },
|
|
380
|
+
{
|
|
381
|
+
flags: "--objective <slug>",
|
|
382
|
+
description: "Tag the track; repeat to override inherited objectives",
|
|
383
|
+
repeatable: true,
|
|
384
|
+
},
|
|
345
385
|
],
|
|
346
386
|
handler: learnGenerateCommand,
|
|
347
387
|
}));
|
|
@@ -377,6 +417,69 @@ export function buildProgram() {
|
|
|
377
417
|
handler: learnListCommand,
|
|
378
418
|
}));
|
|
379
419
|
program.addCommand(learn);
|
|
420
|
+
// --- objective ------------------------------------------------------------
|
|
421
|
+
const objective = makeCommand({
|
|
422
|
+
name: "objective",
|
|
423
|
+
description: "Manage first-class learning objectives and the current focus.",
|
|
424
|
+
handler: () => {
|
|
425
|
+
throw new CliError("USAGE", "Specify a subcommand: add|list|show|focus|archive|link|unlink.");
|
|
426
|
+
},
|
|
427
|
+
});
|
|
428
|
+
objective.addCommand(makeCommand({
|
|
429
|
+
name: "add",
|
|
430
|
+
description: "Create a learning objective; its kebab-case slug is derived from the name.",
|
|
431
|
+
args: [{ spec: "<name>", description: "Objective name" }],
|
|
432
|
+
options: [
|
|
433
|
+
{ flags: "--description <text>", description: "Fuller statement of the learning goal" },
|
|
434
|
+
{ flags: "--focus", description: "Make this objective the current focus" },
|
|
435
|
+
],
|
|
436
|
+
handler: objectiveAddCommand,
|
|
437
|
+
}));
|
|
438
|
+
objective.addCommand(makeCommand({
|
|
439
|
+
name: "list",
|
|
440
|
+
description: "List objectives with tagged counts and the current-focus marker.",
|
|
441
|
+
options: [
|
|
442
|
+
{
|
|
443
|
+
flags: "--status <status>",
|
|
444
|
+
description: "Filter active|archived|all (default active)",
|
|
445
|
+
},
|
|
446
|
+
],
|
|
447
|
+
handler: objectiveListCommand,
|
|
448
|
+
}));
|
|
449
|
+
objective.addCommand(makeCommand({
|
|
450
|
+
name: "show",
|
|
451
|
+
description: "Show an objective, tagged records, and descriptive progress (defaults to the current focus).",
|
|
452
|
+
args: [{ spec: "[slug]", description: "Objective slug or obj_ id" }],
|
|
453
|
+
handler: objectiveShowCommand,
|
|
454
|
+
}));
|
|
455
|
+
objective.addCommand(makeCommand({
|
|
456
|
+
name: "focus",
|
|
457
|
+
description: "Set or clear the one current objective focus.",
|
|
458
|
+
args: [{ spec: "[slug]", description: "Active objective slug or obj_ id" }],
|
|
459
|
+
options: [{ flags: "--clear", description: "Clear the current focus" }],
|
|
460
|
+
handler: objectiveFocusCommand,
|
|
461
|
+
}));
|
|
462
|
+
objective.addCommand(makeCommand({
|
|
463
|
+
name: "archive",
|
|
464
|
+
description: "Archive an objective while preserving its record links.",
|
|
465
|
+
args: [{ spec: "<slug>", description: "Objective slug or obj_ id" }],
|
|
466
|
+
handler: objectiveArchiveCommand,
|
|
467
|
+
}));
|
|
468
|
+
objective.addCommand(makeCommand({
|
|
469
|
+
name: "link",
|
|
470
|
+
description: "Tag an existing post, account, bookmark, or track with an objective.",
|
|
471
|
+
args: [{ spec: "<recordId>", description: "Existing post_, acc_, bm_, or trk_ id" }],
|
|
472
|
+
options: [{ flags: "--objective <slug>", description: "Existing objective slug or obj_ id" }],
|
|
473
|
+
handler: objectiveLinkCommand,
|
|
474
|
+
}));
|
|
475
|
+
objective.addCommand(makeCommand({
|
|
476
|
+
name: "unlink",
|
|
477
|
+
description: "Remove an objective tag from an existing record.",
|
|
478
|
+
args: [{ spec: "<recordId>", description: "Existing post_, acc_, bm_, or trk_ id" }],
|
|
479
|
+
options: [{ flags: "--objective <slug>", description: "Existing objective slug or obj_ id" }],
|
|
480
|
+
handler: objectiveUnlinkCommand,
|
|
481
|
+
}));
|
|
482
|
+
program.addCommand(objective);
|
|
380
483
|
// --- search ---------------------------------------------------------------
|
|
381
484
|
program.addCommand(makeCommand({
|
|
382
485
|
name: "search",
|
|
@@ -385,6 +488,7 @@ export function buildProgram() {
|
|
|
385
488
|
options: [
|
|
386
489
|
{ flags: "--type <list>", description: "Limit types: analysis,takeaway,bookmark (or all)" },
|
|
387
490
|
{ flags: "--limit <n>", description: "Max hits per type (default 10)" },
|
|
491
|
+
{ flags: "--objective <slug>", description: "Only records tagged with this objective" },
|
|
388
492
|
],
|
|
389
493
|
handler: searchCommand,
|
|
390
494
|
}));
|
|
@@ -392,7 +496,10 @@ export function buildProgram() {
|
|
|
392
496
|
program.addCommand(makeCommand({
|
|
393
497
|
name: "digest",
|
|
394
498
|
description: "Markdown recap of analyses, takeaways, and bookmarks saved recently.",
|
|
395
|
-
options: [
|
|
499
|
+
options: [
|
|
500
|
+
{ flags: "--days <n>", description: "Window in days (default 7)" },
|
|
501
|
+
{ flags: "--objective <slug>", description: "Only records tagged with this objective" },
|
|
502
|
+
],
|
|
396
503
|
handler: digestCommand,
|
|
397
504
|
}));
|
|
398
505
|
// --- import ---------------------------------------------------------------
|
|
@@ -479,7 +586,7 @@ export function buildProgram() {
|
|
|
479
586
|
});
|
|
480
587
|
record.addCommand(makeCommand({
|
|
481
588
|
name: "get",
|
|
482
|
-
description: "Fetch any record by id
|
|
589
|
+
description: "Fetch any record by id, including obj_, with its objective tags.",
|
|
483
590
|
args: [{ spec: "<id>" }],
|
|
484
591
|
handler: recordGetCommand,
|
|
485
592
|
}));
|