tenbrains 2.1.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 +112 -0
- package/README.md +218 -0
- package/dist/ai/analyzer.d.ts +28 -0
- package/dist/ai/analyzer.d.ts.map +1 -0
- package/dist/ai/analyzer.js +35 -0
- package/dist/ai/analyzer.js.map +1 -0
- package/dist/ai/client.d.ts +12 -0
- package/dist/ai/client.d.ts.map +1 -0
- package/dist/ai/client.js +152 -0
- package/dist/ai/client.js.map +1 -0
- package/dist/ai/json.d.ts +7 -0
- package/dist/ai/json.d.ts.map +1 -0
- package/dist/ai/json.js +57 -0
- package/dist/ai/json.js.map +1 -0
- package/dist/ai/mock.d.ts +6 -0
- package/dist/ai/mock.d.ts.map +1 -0
- package/dist/ai/mock.js +66 -0
- package/dist/ai/mock.js.map +1 -0
- package/dist/ai/prompts.d.ts +19 -0
- package/dist/ai/prompts.d.ts.map +1 -0
- package/dist/ai/prompts.js +40 -0
- package/dist/ai/prompts.js.map +1 -0
- package/dist/ai/providers.d.ts +22 -0
- package/dist/ai/providers.d.ts.map +1 -0
- package/dist/ai/providers.js +56 -0
- package/dist/ai/providers.js.map +1 -0
- package/dist/ai/resolve.d.ts +24 -0
- package/dist/ai/resolve.d.ts.map +1 -0
- package/dist/ai/resolve.js +33 -0
- package/dist/ai/resolve.js.map +1 -0
- package/dist/bin/preflight.d.ts +2 -0
- package/dist/bin/preflight.d.ts.map +1 -0
- package/dist/bin/preflight.js +11 -0
- package/dist/bin/preflight.js.map +1 -0
- package/dist/bin/tenbrains.d.ts +3 -0
- package/dist/bin/tenbrains.d.ts.map +1 -0
- package/dist/bin/tenbrains.js +9 -0
- package/dist/bin/tenbrains.js.map +1 -0
- package/dist/cli.d.ts +4 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +554 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/analyze.d.ts +7 -0
- package/dist/commands/analyze.d.ts.map +1 -0
- package/dist/commands/analyze.js +204 -0
- package/dist/commands/analyze.js.map +1 -0
- package/dist/commands/bookmark.d.ts +9 -0
- package/dist/commands/bookmark.d.ts.map +1 -0
- package/dist/commands/bookmark.js +120 -0
- package/dist/commands/bookmark.js.map +1 -0
- package/dist/commands/config.d.ts +15 -0
- package/dist/commands/config.d.ts.map +1 -0
- package/dist/commands/config.js +142 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/db.d.ts +9 -0
- package/dist/commands/db.d.ts.map +1 -0
- package/dist/commands/db.js +64 -0
- package/dist/commands/db.js.map +1 -0
- package/dist/commands/digest.d.ts +19 -0
- package/dist/commands/digest.d.ts.map +1 -0
- package/dist/commands/digest.js +71 -0
- package/dist/commands/digest.js.map +1 -0
- package/dist/commands/import.d.ts +11 -0
- package/dist/commands/import.d.ts.map +1 -0
- package/dist/commands/import.js +78 -0
- package/dist/commands/import.js.map +1 -0
- package/dist/commands/learn.d.ts +9 -0
- package/dist/commands/learn.d.ts.map +1 -0
- package/dist/commands/learn.js +149 -0
- package/dist/commands/learn.js.map +1 -0
- package/dist/commands/manifest.d.ts +13 -0
- package/dist/commands/manifest.d.ts.map +1 -0
- package/dist/commands/manifest.js +62 -0
- package/dist/commands/manifest.js.map +1 -0
- package/dist/commands/record.d.ts +10 -0
- package/dist/commands/record.d.ts.map +1 -0
- package/dist/commands/record.js +37 -0
- package/dist/commands/record.js.map +1 -0
- package/dist/commands/search.d.ts +5 -0
- package/dist/commands/search.d.ts.map +1 -0
- package/dist/commands/search.js +33 -0
- package/dist/commands/search.js.map +1 -0
- package/dist/commands/shared.d.ts +9 -0
- package/dist/commands/shared.d.ts.map +1 -0
- package/dist/commands/shared.js +13 -0
- package/dist/commands/shared.js.map +1 -0
- package/dist/commands/suggest.d.ts +9 -0
- package/dist/commands/suggest.d.ts.map +1 -0
- package/dist/commands/suggest.js +102 -0
- package/dist/commands/suggest.js.map +1 -0
- package/dist/commands/takeaway.d.ts +9 -0
- package/dist/commands/takeaway.d.ts.map +1 -0
- package/dist/commands/takeaway.js +167 -0
- package/dist/commands/takeaway.js.map +1 -0
- package/dist/core/config.d.ts +52 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/config.js +180 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/context.d.ts +28 -0
- package/dist/core/context.d.ts.map +1 -0
- package/dist/core/context.js +40 -0
- package/dist/core/context.js.map +1 -0
- package/dist/core/errors.d.ts +33 -0
- package/dist/core/errors.d.ts.map +1 -0
- package/dist/core/errors.js +82 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/input.d.ts +9 -0
- package/dist/core/input.d.ts.map +1 -0
- package/dist/core/input.js +47 -0
- package/dist/core/input.js.map +1 -0
- package/dist/core/opts.d.ts +8 -0
- package/dist/core/opts.d.ts.map +1 -0
- package/dist/core/opts.js +38 -0
- package/dist/core/opts.js.map +1 -0
- package/dist/core/output.d.ts +58 -0
- package/dist/core/output.d.ts.map +1 -0
- package/dist/core/output.js +76 -0
- package/dist/core/output.js.map +1 -0
- package/dist/core/paths.d.ts +20 -0
- package/dist/core/paths.d.ts.map +1 -0
- package/dist/core/paths.js +31 -0
- package/dist/core/paths.js.map +1 -0
- package/dist/core/text.d.ts +10 -0
- package/dist/core/text.d.ts.map +1 -0
- package/dist/core/text.js +132 -0
- package/dist/core/text.js.map +1 -0
- package/dist/core/validate.d.ts +5 -0
- package/dist/core/validate.d.ts.map +1 -0
- package/dist/core/validate.js +17 -0
- package/dist/core/validate.js.map +1 -0
- package/dist/db/database.d.ts +27 -0
- package/dist/db/database.d.ts.map +1 -0
- package/dist/db/database.js +90 -0
- package/dist/db/database.js.map +1 -0
- package/dist/db/fts.d.ts +12 -0
- package/dist/db/fts.d.ts.map +1 -0
- package/dist/db/fts.js +42 -0
- package/dist/db/fts.js.map +1 -0
- package/dist/db/migrations.d.ts +20 -0
- package/dist/db/migrations.d.ts.map +1 -0
- package/dist/db/migrations.js +243 -0
- package/dist/db/migrations.js.map +1 -0
- package/dist/db/repositories.d.ts +130 -0
- package/dist/db/repositories.d.ts.map +1 -0
- package/dist/db/repositories.js +418 -0
- package/dist/db/repositories.js.map +1 -0
- package/dist/domain/learn.d.ts +25 -0
- package/dist/domain/learn.d.ts.map +1 -0
- package/dist/domain/learn.js +85 -0
- package/dist/domain/learn.js.map +1 -0
- package/dist/domain/schemas.d.ts +169 -0
- package/dist/domain/schemas.d.ts.map +1 -0
- package/dist/domain/schemas.js +54 -0
- package/dist/domain/schemas.js.map +1 -0
- package/dist/domain/search.d.ts +32 -0
- package/dist/domain/search.d.ts.map +1 -0
- package/dist/domain/search.js +77 -0
- package/dist/domain/search.js.map +1 -0
- package/dist/domain/suggest.d.ts +17 -0
- package/dist/domain/suggest.d.ts.map +1 -0
- package/dist/domain/suggest.js +114 -0
- package/dist/domain/suggest.js.map +1 -0
- package/dist/domain/tags.d.ts +9 -0
- package/dist/domain/tags.d.ts.map +1 -0
- package/dist/domain/tags.js +40 -0
- package/dist/domain/tags.js.map +1 -0
- package/dist/domain/types.d.ts +84 -0
- package/dist/domain/types.d.ts.map +1 -0
- package/dist/domain/types.js +2 -0
- package/dist/domain/types.js.map +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/dist/x/archive.d.ts +32 -0
- package/dist/x/archive.d.ts.map +1 -0
- package/dist/x/archive.js +108 -0
- package/dist/x/archive.js.map +1 -0
- package/dist/x/client.d.ts +61 -0
- package/dist/x/client.d.ts.map +1 -0
- package/dist/x/client.js +321 -0
- package/dist/x/client.js.map +1 -0
- package/package.json +58 -0
|
@@ -0,0 +1,418 @@
|
|
|
1
|
+
import { newId, nowIso } from "./database.js";
|
|
2
|
+
/** Coerce undefined to null; SQLite bindings reject undefined. */
|
|
3
|
+
function nn(value) {
|
|
4
|
+
return value === undefined ? null : value;
|
|
5
|
+
}
|
|
6
|
+
function parseJsonArray(raw) {
|
|
7
|
+
if (typeof raw !== "string") {
|
|
8
|
+
return [];
|
|
9
|
+
}
|
|
10
|
+
try {
|
|
11
|
+
const parsed = JSON.parse(raw);
|
|
12
|
+
return Array.isArray(parsed) ? parsed : [];
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
return [];
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
// --- mappers -----------------------------------------------------------------
|
|
19
|
+
function mapPost(row) {
|
|
20
|
+
return {
|
|
21
|
+
id: row.id,
|
|
22
|
+
externalId: row.external_id,
|
|
23
|
+
url: row.url,
|
|
24
|
+
authorUsername: row.author_username,
|
|
25
|
+
authorName: row.author_name,
|
|
26
|
+
text: row.text,
|
|
27
|
+
postedAt: row.posted_at,
|
|
28
|
+
createdAt: row.created_at,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
function mapAnalysis(row) {
|
|
32
|
+
return {
|
|
33
|
+
id: row.id,
|
|
34
|
+
postId: row.post_id,
|
|
35
|
+
provider: row.provider,
|
|
36
|
+
model: row.model,
|
|
37
|
+
topic: row.topic,
|
|
38
|
+
summary: row.summary,
|
|
39
|
+
intent: row.intent,
|
|
40
|
+
concepts: parseJsonArray(row.concepts_json),
|
|
41
|
+
mock: row.mock === 1,
|
|
42
|
+
createdAt: row.created_at,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
function mapAccount(row) {
|
|
46
|
+
return {
|
|
47
|
+
id: row.id,
|
|
48
|
+
username: row.username,
|
|
49
|
+
name: row.name,
|
|
50
|
+
followedAt: row.followed_at,
|
|
51
|
+
lastRefreshedAt: row.last_refreshed_at,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
function mapSnapshot(row) {
|
|
55
|
+
return {
|
|
56
|
+
id: row.id,
|
|
57
|
+
accountId: row.account_id,
|
|
58
|
+
provider: row.provider,
|
|
59
|
+
model: row.model,
|
|
60
|
+
summary: row.summary,
|
|
61
|
+
takeaways: parseJsonArray(row.takeaways_json),
|
|
62
|
+
sourcePostIds: parseJsonArray(row.source_post_ids_json),
|
|
63
|
+
postCount: row.post_count,
|
|
64
|
+
mock: row.mock === 1,
|
|
65
|
+
createdAt: row.created_at,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
function mapBookmark(row) {
|
|
69
|
+
return {
|
|
70
|
+
id: row.id,
|
|
71
|
+
postId: row.post_id,
|
|
72
|
+
tags: parseJsonArray(row.tags_json),
|
|
73
|
+
note: row.note,
|
|
74
|
+
source: row.source,
|
|
75
|
+
createdAt: row.created_at,
|
|
76
|
+
updatedAt: row.updated_at,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
function mapSuggestion(row) {
|
|
80
|
+
return {
|
|
81
|
+
id: row.id,
|
|
82
|
+
postId: row.post_id,
|
|
83
|
+
reason: row.reason,
|
|
84
|
+
score: row.score,
|
|
85
|
+
status: row.status,
|
|
86
|
+
createdAt: row.created_at,
|
|
87
|
+
updatedAt: row.updated_at,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
function mapTrack(row, progress) {
|
|
91
|
+
return {
|
|
92
|
+
id: row.id,
|
|
93
|
+
analysisId: row.analysis_id,
|
|
94
|
+
minutesPerDay: row.minutes_per_day,
|
|
95
|
+
ratings: parseJsonArray(row.ratings_json),
|
|
96
|
+
days: parseJsonArray(row.days_json),
|
|
97
|
+
progress,
|
|
98
|
+
createdAt: row.created_at,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
// --- repositories ------------------------------------------------------------
|
|
102
|
+
export class PostsRepo {
|
|
103
|
+
db;
|
|
104
|
+
constructor(db) {
|
|
105
|
+
this.db = db;
|
|
106
|
+
}
|
|
107
|
+
create(data) {
|
|
108
|
+
const id = newId("post");
|
|
109
|
+
const createdAt = nowIso();
|
|
110
|
+
this.db
|
|
111
|
+
.prepare(`INSERT INTO posts (id, external_id, url, author_username, author_name, text, posted_at, raw_json, created_at)
|
|
112
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`)
|
|
113
|
+
.run(id, nn(data.externalId), nn(data.url), nn(data.authorUsername), nn(data.authorName), data.text, nn(data.postedAt), data.raw === undefined ? null : JSON.stringify(data.raw), createdAt);
|
|
114
|
+
return this.findById(id);
|
|
115
|
+
}
|
|
116
|
+
/** Insert, or return the existing post when externalId already present. */
|
|
117
|
+
ingest(data) {
|
|
118
|
+
if (data.externalId) {
|
|
119
|
+
const existing = this.findByExternalId(data.externalId);
|
|
120
|
+
if (existing) {
|
|
121
|
+
return { post: existing, deduped: true };
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return { post: this.create(data), deduped: false };
|
|
125
|
+
}
|
|
126
|
+
findById(id) {
|
|
127
|
+
const row = this.db.prepare("SELECT * FROM posts WHERE id = ?").get(id);
|
|
128
|
+
return row ? mapPost(row) : null;
|
|
129
|
+
}
|
|
130
|
+
findByExternalId(externalId) {
|
|
131
|
+
const row = this.db.prepare("SELECT * FROM posts WHERE external_id = ?").get(externalId);
|
|
132
|
+
return row ? mapPost(row) : null;
|
|
133
|
+
}
|
|
134
|
+
list(limit, offset) {
|
|
135
|
+
const rows = this.db
|
|
136
|
+
.prepare("SELECT * FROM posts ORDER BY created_at DESC, id DESC LIMIT ? OFFSET ?")
|
|
137
|
+
.all(limit, offset);
|
|
138
|
+
return rows.map(mapPost);
|
|
139
|
+
}
|
|
140
|
+
all() {
|
|
141
|
+
const rows = this.db.prepare("SELECT * FROM posts").all();
|
|
142
|
+
return rows.map(mapPost);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
export class AnalysesRepo {
|
|
146
|
+
db;
|
|
147
|
+
constructor(db) {
|
|
148
|
+
this.db = db;
|
|
149
|
+
}
|
|
150
|
+
create(data) {
|
|
151
|
+
const id = newId("ana");
|
|
152
|
+
const createdAt = nowIso();
|
|
153
|
+
this.db
|
|
154
|
+
.prepare(`INSERT INTO analyses (id, post_id, provider, model, topic, summary, intent, concepts_json, mock, created_at)
|
|
155
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
|
|
156
|
+
.run(id, data.postId, data.provider, data.model, data.topic, data.summary, data.intent, JSON.stringify(data.concepts), data.mock ? 1 : 0, createdAt);
|
|
157
|
+
return this.findById(id);
|
|
158
|
+
}
|
|
159
|
+
findById(id) {
|
|
160
|
+
const row = this.db.prepare("SELECT * FROM analyses WHERE id = ?").get(id);
|
|
161
|
+
return row ? mapAnalysis(row) : null;
|
|
162
|
+
}
|
|
163
|
+
latestForPost(postId) {
|
|
164
|
+
const row = this.db
|
|
165
|
+
.prepare("SELECT * FROM analyses WHERE post_id = ? ORDER BY created_at DESC LIMIT 1")
|
|
166
|
+
.get(postId);
|
|
167
|
+
return row ? mapAnalysis(row) : null;
|
|
168
|
+
}
|
|
169
|
+
list(limit, offset, author) {
|
|
170
|
+
if (author) {
|
|
171
|
+
const rows = this.db
|
|
172
|
+
.prepare(`SELECT a.* FROM analyses a JOIN posts p ON p.id = a.post_id
|
|
173
|
+
WHERE p.author_username = ? ORDER BY a.created_at DESC LIMIT ? OFFSET ?`)
|
|
174
|
+
.all(author, limit, offset);
|
|
175
|
+
return rows.map(mapAnalysis);
|
|
176
|
+
}
|
|
177
|
+
const rows = this.db
|
|
178
|
+
.prepare("SELECT * FROM analyses ORDER BY created_at DESC LIMIT ? OFFSET ?")
|
|
179
|
+
.all(limit, offset);
|
|
180
|
+
return rows.map(mapAnalysis);
|
|
181
|
+
}
|
|
182
|
+
all() {
|
|
183
|
+
const rows = this.db.prepare("SELECT * FROM analyses").all();
|
|
184
|
+
return rows.map(mapAnalysis);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
export class AccountsRepo {
|
|
188
|
+
db;
|
|
189
|
+
constructor(db) {
|
|
190
|
+
this.db = db;
|
|
191
|
+
}
|
|
192
|
+
create(username, name) {
|
|
193
|
+
const id = newId("acc");
|
|
194
|
+
this.db
|
|
195
|
+
.prepare("INSERT INTO accounts (id, username, name, followed_at) VALUES (?, ?, ?, ?)")
|
|
196
|
+
.run(id, username, nn(name), nowIso());
|
|
197
|
+
return this.findById(id);
|
|
198
|
+
}
|
|
199
|
+
findById(id) {
|
|
200
|
+
const row = this.db.prepare("SELECT * FROM accounts WHERE id = ?").get(id);
|
|
201
|
+
return row ? mapAccount(row) : null;
|
|
202
|
+
}
|
|
203
|
+
findByUsername(username) {
|
|
204
|
+
const row = this.db.prepare("SELECT * FROM accounts WHERE username = ?").get(username);
|
|
205
|
+
return row ? mapAccount(row) : null;
|
|
206
|
+
}
|
|
207
|
+
list() {
|
|
208
|
+
const rows = this.db
|
|
209
|
+
.prepare("SELECT * FROM accounts ORDER BY username ASC")
|
|
210
|
+
.all();
|
|
211
|
+
return rows.map(mapAccount);
|
|
212
|
+
}
|
|
213
|
+
touch(id) {
|
|
214
|
+
this.db.prepare("UPDATE accounts SET last_refreshed_at = ? WHERE id = ?").run(nowIso(), id);
|
|
215
|
+
}
|
|
216
|
+
delete(id) {
|
|
217
|
+
this.db.prepare("DELETE FROM accounts WHERE id = ?").run(id);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
export class SnapshotsRepo {
|
|
221
|
+
db;
|
|
222
|
+
constructor(db) {
|
|
223
|
+
this.db = db;
|
|
224
|
+
}
|
|
225
|
+
create(data) {
|
|
226
|
+
const id = newId("snap");
|
|
227
|
+
this.db
|
|
228
|
+
.prepare(`INSERT INTO takeaway_snapshots
|
|
229
|
+
(id, account_id, provider, model, summary, takeaways_json, source_post_ids_json, post_count, mock, created_at)
|
|
230
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
|
|
231
|
+
.run(id, data.accountId, data.provider, data.model, data.summary, JSON.stringify(data.takeaways), JSON.stringify(data.sourcePostIds), data.sourcePostIds.length, data.mock ? 1 : 0, nowIso());
|
|
232
|
+
return this.findById(id);
|
|
233
|
+
}
|
|
234
|
+
findById(id) {
|
|
235
|
+
const row = this.db.prepare("SELECT * FROM takeaway_snapshots WHERE id = ?").get(id);
|
|
236
|
+
return row ? mapSnapshot(row) : null;
|
|
237
|
+
}
|
|
238
|
+
latestByAccount(accountId) {
|
|
239
|
+
const row = this.db
|
|
240
|
+
.prepare("SELECT * FROM takeaway_snapshots WHERE account_id = ? ORDER BY created_at DESC LIMIT 1")
|
|
241
|
+
.get(accountId);
|
|
242
|
+
return row ? mapSnapshot(row) : null;
|
|
243
|
+
}
|
|
244
|
+
listByAccount(accountId, limit) {
|
|
245
|
+
const rows = this.db
|
|
246
|
+
.prepare("SELECT * FROM takeaway_snapshots WHERE account_id = ? ORDER BY created_at DESC LIMIT ?")
|
|
247
|
+
.all(accountId, limit);
|
|
248
|
+
return rows.map(mapSnapshot);
|
|
249
|
+
}
|
|
250
|
+
all() {
|
|
251
|
+
const rows = this.db
|
|
252
|
+
.prepare("SELECT * FROM takeaway_snapshots")
|
|
253
|
+
.all();
|
|
254
|
+
return rows.map(mapSnapshot);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
export class BookmarksRepo {
|
|
258
|
+
db;
|
|
259
|
+
constructor(db) {
|
|
260
|
+
this.db = db;
|
|
261
|
+
}
|
|
262
|
+
create(data) {
|
|
263
|
+
const id = newId("bm");
|
|
264
|
+
const ts = nowIso();
|
|
265
|
+
this.db
|
|
266
|
+
.prepare(`INSERT INTO bookmarks (id, post_id, tags_json, note, source, created_at, updated_at)
|
|
267
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)`)
|
|
268
|
+
.run(id, data.postId, JSON.stringify(data.tags), nn(data.note), data.source, ts, ts);
|
|
269
|
+
return this.findById(id);
|
|
270
|
+
}
|
|
271
|
+
findById(id) {
|
|
272
|
+
const row = this.db.prepare("SELECT * FROM bookmarks WHERE id = ?").get(id);
|
|
273
|
+
return row ? mapBookmark(row) : null;
|
|
274
|
+
}
|
|
275
|
+
findByPostId(postId) {
|
|
276
|
+
const row = this.db.prepare("SELECT * FROM bookmarks WHERE post_id = ?").get(postId);
|
|
277
|
+
return row ? mapBookmark(row) : null;
|
|
278
|
+
}
|
|
279
|
+
list(limit, offset) {
|
|
280
|
+
const rows = this.db
|
|
281
|
+
.prepare("SELECT * FROM bookmarks ORDER BY created_at DESC LIMIT ? OFFSET ?")
|
|
282
|
+
.all(limit, offset);
|
|
283
|
+
return rows.map(mapBookmark);
|
|
284
|
+
}
|
|
285
|
+
all() {
|
|
286
|
+
const rows = this.db.prepare("SELECT * FROM bookmarks").all();
|
|
287
|
+
return rows.map(mapBookmark);
|
|
288
|
+
}
|
|
289
|
+
updateTags(id, tags) {
|
|
290
|
+
this.db
|
|
291
|
+
.prepare("UPDATE bookmarks SET tags_json = ?, updated_at = ? WHERE id = ?")
|
|
292
|
+
.run(JSON.stringify(tags), nowIso(), id);
|
|
293
|
+
return this.findById(id);
|
|
294
|
+
}
|
|
295
|
+
delete(id) {
|
|
296
|
+
this.db.prepare("DELETE FROM bookmarks WHERE id = ?").run(id);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
export class SuggestionsRepo {
|
|
300
|
+
db;
|
|
301
|
+
constructor(db) {
|
|
302
|
+
this.db = db;
|
|
303
|
+
}
|
|
304
|
+
/** Insert a pending suggestion or refresh score/reason if one exists for the post. */
|
|
305
|
+
upsert(data) {
|
|
306
|
+
const existing = this.findByPostId(data.postId);
|
|
307
|
+
const ts = nowIso();
|
|
308
|
+
if (existing) {
|
|
309
|
+
if (existing.status === "pending") {
|
|
310
|
+
this.db
|
|
311
|
+
.prepare("UPDATE suggestions SET reason = ?, score = ?, updated_at = ? WHERE id = ?")
|
|
312
|
+
.run(data.reason, data.score, ts, existing.id);
|
|
313
|
+
}
|
|
314
|
+
return this.findById(existing.id);
|
|
315
|
+
}
|
|
316
|
+
const id = newId("sug");
|
|
317
|
+
this.db
|
|
318
|
+
.prepare(`INSERT INTO suggestions (id, post_id, reason, score, status, created_at, updated_at)
|
|
319
|
+
VALUES (?, ?, ?, ?, 'pending', ?, ?)`)
|
|
320
|
+
.run(id, data.postId, data.reason, data.score, ts, ts);
|
|
321
|
+
return this.findById(id);
|
|
322
|
+
}
|
|
323
|
+
findById(id) {
|
|
324
|
+
const row = this.db.prepare("SELECT * FROM suggestions WHERE id = ?").get(id);
|
|
325
|
+
return row ? mapSuggestion(row) : null;
|
|
326
|
+
}
|
|
327
|
+
findByPostId(postId) {
|
|
328
|
+
const row = this.db.prepare("SELECT * FROM suggestions WHERE post_id = ?").get(postId);
|
|
329
|
+
return row ? mapSuggestion(row) : null;
|
|
330
|
+
}
|
|
331
|
+
list(status, limit) {
|
|
332
|
+
if (status === "all") {
|
|
333
|
+
const rows = this.db
|
|
334
|
+
.prepare("SELECT * FROM suggestions ORDER BY score DESC, created_at DESC LIMIT ?")
|
|
335
|
+
.all(limit);
|
|
336
|
+
return rows.map(mapSuggestion);
|
|
337
|
+
}
|
|
338
|
+
const rows = this.db
|
|
339
|
+
.prepare("SELECT * FROM suggestions WHERE status = ? ORDER BY score DESC, created_at DESC LIMIT ?")
|
|
340
|
+
.all(status, limit);
|
|
341
|
+
return rows.map(mapSuggestion);
|
|
342
|
+
}
|
|
343
|
+
setStatus(id, status) {
|
|
344
|
+
this.db
|
|
345
|
+
.prepare("UPDATE suggestions SET status = ?, updated_at = ? WHERE id = ?")
|
|
346
|
+
.run(status, nowIso(), id);
|
|
347
|
+
return this.findById(id);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
export class TracksRepo {
|
|
351
|
+
db;
|
|
352
|
+
constructor(db) {
|
|
353
|
+
this.db = db;
|
|
354
|
+
}
|
|
355
|
+
create(data) {
|
|
356
|
+
const id = newId("trk");
|
|
357
|
+
this.db
|
|
358
|
+
.prepare(`INSERT INTO learning_tracks (id, analysis_id, minutes_per_day, ratings_json, days_json, created_at)
|
|
359
|
+
VALUES (?, ?, ?, ?, ?, ?)`)
|
|
360
|
+
.run(id, data.analysisId, data.minutesPerDay, JSON.stringify(data.ratings), JSON.stringify(data.days), nowIso());
|
|
361
|
+
return this.findById(id);
|
|
362
|
+
}
|
|
363
|
+
findById(id) {
|
|
364
|
+
const row = this.db.prepare("SELECT * FROM learning_tracks WHERE id = ?").get(id);
|
|
365
|
+
return row ? mapTrack(row, this.progressFor(row.id)) : null;
|
|
366
|
+
}
|
|
367
|
+
list(limit, analysisId) {
|
|
368
|
+
if (analysisId) {
|
|
369
|
+
const rows = this.db
|
|
370
|
+
.prepare("SELECT * FROM learning_tracks WHERE analysis_id = ? ORDER BY created_at DESC LIMIT ?")
|
|
371
|
+
.all(analysisId, limit);
|
|
372
|
+
return rows.map((row) => mapTrack(row, this.progressFor(row.id)));
|
|
373
|
+
}
|
|
374
|
+
const rows = this.db
|
|
375
|
+
.prepare("SELECT * FROM learning_tracks ORDER BY created_at DESC LIMIT ?")
|
|
376
|
+
.all(limit);
|
|
377
|
+
return rows.map((row) => mapTrack(row, this.progressFor(row.id)));
|
|
378
|
+
}
|
|
379
|
+
progressFor(trackId) {
|
|
380
|
+
const rows = this.db
|
|
381
|
+
.prepare("SELECT day, notes, completed_at FROM track_progress WHERE track_id = ? ORDER BY day")
|
|
382
|
+
.all(trackId);
|
|
383
|
+
return rows.map((row) => ({ day: row.day, notes: row.notes, completedAt: row.completed_at }));
|
|
384
|
+
}
|
|
385
|
+
/** Record a day as done. Caller guards against duplicates (PK would throw). */
|
|
386
|
+
markDone(trackId, day, notes) {
|
|
387
|
+
this.db
|
|
388
|
+
.prepare("INSERT INTO track_progress (track_id, day, notes, completed_at) VALUES (?, ?, ?, ?)")
|
|
389
|
+
.run(trackId, day, nn(notes), nowIso());
|
|
390
|
+
return this.findById(trackId);
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
/** Facade exposing every repository over a single Database. */
|
|
394
|
+
export class Store {
|
|
395
|
+
database;
|
|
396
|
+
posts;
|
|
397
|
+
analyses;
|
|
398
|
+
accounts;
|
|
399
|
+
snapshots;
|
|
400
|
+
bookmarks;
|
|
401
|
+
suggestions;
|
|
402
|
+
tracks;
|
|
403
|
+
constructor(database) {
|
|
404
|
+
this.database = database;
|
|
405
|
+
const handle = database.handle;
|
|
406
|
+
this.posts = new PostsRepo(handle);
|
|
407
|
+
this.analyses = new AnalysesRepo(handle);
|
|
408
|
+
this.accounts = new AccountsRepo(handle);
|
|
409
|
+
this.snapshots = new SnapshotsRepo(handle);
|
|
410
|
+
this.bookmarks = new BookmarksRepo(handle);
|
|
411
|
+
this.suggestions = new SuggestionsRepo(handle);
|
|
412
|
+
this.tracks = new TracksRepo(handle);
|
|
413
|
+
}
|
|
414
|
+
transaction(fn) {
|
|
415
|
+
return this.database.transaction(fn);
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
//# sourceMappingURL=repositories.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repositories.js","sourceRoot":"","sources":["../../src/db/repositories.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { Concept, ConceptRating, LearningDay, TrackDayProgress } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Order concepts for study: highest interest first, then most novel (lowest
|
|
4
|
+
* familiarity), preserving original order as a stable tiebreaker.
|
|
5
|
+
*/
|
|
6
|
+
export declare function prioritizeConcepts(concepts: Concept[], ratings: ConceptRating[]): Concept[];
|
|
7
|
+
/**
|
|
8
|
+
* Build a 7-day Feynman track. Each day pairs a prioritized concept with
|
|
9
|
+
* Learn / Explain / Check steps. With fewer than 7 concepts, the top concepts
|
|
10
|
+
* recur on later days for spaced repetition.
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* The next day to study: the first day without a progress entry. Progress is
|
|
14
|
+
* session-based, not calendar-based, so missing a calendar day never skips
|
|
15
|
+
* content. Returns null when every day is done.
|
|
16
|
+
*/
|
|
17
|
+
export declare function nextPendingDay(days: LearningDay[], progress: TrackDayProgress[]): number | null;
|
|
18
|
+
/**
|
|
19
|
+
* Where the calendar says you should be: day 1 on the creation date, clamped
|
|
20
|
+
* to the track length. Reported alongside the pending day so callers can see
|
|
21
|
+
* whether the learner is behind schedule.
|
|
22
|
+
*/
|
|
23
|
+
export declare function scheduledDay(createdAt: string, now: Date, totalDays: number): number;
|
|
24
|
+
export declare function buildFeynmanTrack(concepts: Concept[], minutesPerDay: number, ratings: ConceptRating[]): LearningDay[];
|
|
25
|
+
//# sourceMappingURL=learn.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"learn.d.ts","sourceRoot":"","sources":["../../src/domain/learn.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAiBxF;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,OAAO,EAAE,aAAa,EAAE,GAAG,OAAO,EAAE,CAe3F;AASD;;;;GAIG;AACH;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,WAAW,EAAE,EAAE,QAAQ,EAAE,gBAAgB,EAAE,GAAG,MAAM,GAAG,IAAI,CAQ/F;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAGpF;AAED,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,OAAO,EAAE,EACnB,aAAa,EAAE,MAAM,EACrB,OAAO,EAAE,aAAa,EAAE,GACvB,WAAW,EAAE,CAmBf"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
const TRACK_DAYS = 7;
|
|
2
|
+
const DEFAULT_FAMILIARITY = 1; // assume novel when unrated
|
|
3
|
+
const DEFAULT_INTEREST = 3; // assume neutral interest when unrated
|
|
4
|
+
function ratingFor(concept, ratings) {
|
|
5
|
+
const match = ratings.find((r) => r.concept.toLowerCase() === concept.name.toLowerCase());
|
|
6
|
+
return {
|
|
7
|
+
familiarity: match?.familiarity ?? DEFAULT_FAMILIARITY,
|
|
8
|
+
interest: match?.interest ?? DEFAULT_INTEREST,
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Order concepts for study: highest interest first, then most novel (lowest
|
|
13
|
+
* familiarity), preserving original order as a stable tiebreaker.
|
|
14
|
+
*/
|
|
15
|
+
export function prioritizeConcepts(concepts, ratings) {
|
|
16
|
+
return concepts
|
|
17
|
+
.map((concept, index) => ({ concept, index, ...ratingFor(concept, ratings) }))
|
|
18
|
+
.sort((a, b) => {
|
|
19
|
+
if (b.interest !== a.interest) {
|
|
20
|
+
return b.interest - a.interest;
|
|
21
|
+
}
|
|
22
|
+
const noveltyA = 6 - a.familiarity;
|
|
23
|
+
const noveltyB = 6 - b.familiarity;
|
|
24
|
+
if (noveltyB !== noveltyA) {
|
|
25
|
+
return noveltyB - noveltyA;
|
|
26
|
+
}
|
|
27
|
+
return a.index - b.index;
|
|
28
|
+
})
|
|
29
|
+
.map((entry) => entry.concept);
|
|
30
|
+
}
|
|
31
|
+
function splitMinutes(total) {
|
|
32
|
+
const learn = Math.max(1, Math.round(total * 0.4));
|
|
33
|
+
const explain = Math.max(1, Math.round(total * 0.4));
|
|
34
|
+
const check = Math.max(1, total - learn - explain);
|
|
35
|
+
return { learn, explain, check };
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Build a 7-day Feynman track. Each day pairs a prioritized concept with
|
|
39
|
+
* Learn / Explain / Check steps. With fewer than 7 concepts, the top concepts
|
|
40
|
+
* recur on later days for spaced repetition.
|
|
41
|
+
*/
|
|
42
|
+
/**
|
|
43
|
+
* The next day to study: the first day without a progress entry. Progress is
|
|
44
|
+
* session-based, not calendar-based, so missing a calendar day never skips
|
|
45
|
+
* content. Returns null when every day is done.
|
|
46
|
+
*/
|
|
47
|
+
export function nextPendingDay(days, progress) {
|
|
48
|
+
const done = new Set(progress.map((p) => p.day));
|
|
49
|
+
for (const day of days) {
|
|
50
|
+
if (!done.has(day.day)) {
|
|
51
|
+
return day.day;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Where the calendar says you should be: day 1 on the creation date, clamped
|
|
58
|
+
* to the track length. Reported alongside the pending day so callers can see
|
|
59
|
+
* whether the learner is behind schedule.
|
|
60
|
+
*/
|
|
61
|
+
export function scheduledDay(createdAt, now, totalDays) {
|
|
62
|
+
const elapsed = Math.floor((now.getTime() - new Date(createdAt).getTime()) / 86_400_000);
|
|
63
|
+
return Math.min(Math.max(elapsed + 1, 1), Math.max(totalDays, 1));
|
|
64
|
+
}
|
|
65
|
+
export function buildFeynmanTrack(concepts, minutesPerDay, ratings) {
|
|
66
|
+
const ordered = prioritizeConcepts(concepts, ratings);
|
|
67
|
+
if (ordered.length === 0) {
|
|
68
|
+
return [];
|
|
69
|
+
}
|
|
70
|
+
const minutes = splitMinutes(minutesPerDay);
|
|
71
|
+
const days = [];
|
|
72
|
+
for (let day = 1; day <= TRACK_DAYS; day += 1) {
|
|
73
|
+
const concept = ordered[(day - 1) % ordered.length];
|
|
74
|
+
const revisiting = day > ordered.length;
|
|
75
|
+
days.push({
|
|
76
|
+
day,
|
|
77
|
+
concept: concept.name,
|
|
78
|
+
learn: `${minutes.learn} min: ${revisiting ? "Revisit" : "Read or watch a primer on"} "${concept.name}". ${concept.whyItMattersInTweet}`,
|
|
79
|
+
explain: `${minutes.explain} min: Write a plain-language explanation of "${concept.name}" as if teaching a beginner, no jargon.`,
|
|
80
|
+
check: `${minutes.check} min: List what still feels fuzzy about "${concept.name}" and note one question to resolve tomorrow.`,
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
return days;
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=learn.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"learn.js","sourceRoot":"","sources":["../../src/domain/learn.ts"],"names":[],"mappings":"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"}
|