@timmeck/brain 3.15.0 → 3.17.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.
@@ -0,0 +1,68 @@
1
+ import Database from 'better-sqlite3';
2
+ export interface ReposignalRepo {
3
+ id: number;
4
+ full_name: string;
5
+ name: string;
6
+ owner: string;
7
+ description: string | null;
8
+ language: string | null;
9
+ topics: string | null;
10
+ current_stars: number;
11
+ current_forks: number;
12
+ signal_score: number;
13
+ signal_level: string;
14
+ phase: string;
15
+ first_seen_at: string;
16
+ last_scanned_at: string | null;
17
+ }
18
+ export interface ReposignalHnMention {
19
+ title: string;
20
+ url: string;
21
+ score: number;
22
+ comment_count: number;
23
+ repo_id: number | null;
24
+ }
25
+ export interface ReposignalImportOptions {
26
+ /** Minimum signal level: 'noise' | 'watch' | 'signal' | 'breakout'. Default: 'watch' */
27
+ minSignalLevel?: string;
28
+ /** Maximum repos to import per run. Default: 5000 */
29
+ batchSize?: number;
30
+ /** Import HN mentions too. Default: true */
31
+ includeHnMentions?: boolean;
32
+ /** Record metrics for PredictionEngine. Default: true */
33
+ recordMetrics?: boolean;
34
+ }
35
+ export interface ReposignalImportResult {
36
+ dbPath: string;
37
+ totalReposInDb: number;
38
+ reposImported: number;
39
+ discoveriesCreated: number;
40
+ journalEntriesCreated: number;
41
+ hnMentionsImported: number;
42
+ metricsRecorded: number;
43
+ skippedDuplicates: number;
44
+ languageBreakdown: Record<string, number>;
45
+ signalBreakdown: Record<string, number>;
46
+ duration_ms: number;
47
+ }
48
+ export declare class ReposignalImporter {
49
+ private brainDb;
50
+ private log;
51
+ private lastResult;
52
+ constructor(brainDb: Database.Database);
53
+ private ensureStateTable;
54
+ /** Import repos from a reposignal/aisurvival SQLite database. */
55
+ import(dbPath: string, options?: ReposignalImportOptions): ReposignalImportResult;
56
+ /** Import top HN mentions as journal entries. */
57
+ private importHnMentions;
58
+ /** Record aggregated metrics into prediction_metrics table. */
59
+ private recordImportMetrics;
60
+ private parseTopics;
61
+ getLastResult(): ReposignalImportResult | null;
62
+ /** Get import stats from state table. */
63
+ getStats(): {
64
+ totalImported: number;
65
+ byLevel: Record<string, number>;
66
+ lastImport: string | null;
67
+ };
68
+ }
@@ -0,0 +1,242 @@
1
+ import Database from 'better-sqlite3';
2
+ import fs from 'node:fs';
3
+ import { getLogger } from '@timmeck/brain-core/utils/logger';
4
+ // ── Constants ───────────────────────────────────────
5
+ const SIGNAL_LEVELS = ['noise', 'watch', 'signal', 'breakout'];
6
+ function signalLevelIndex(level) {
7
+ return SIGNAL_LEVELS.indexOf(level);
8
+ }
9
+ // ── Importer ────────────────────────────────────────
10
+ export class ReposignalImporter {
11
+ brainDb;
12
+ log = getLogger();
13
+ lastResult = null;
14
+ constructor(brainDb) {
15
+ this.brainDb = brainDb;
16
+ this.ensureStateTable();
17
+ }
18
+ ensureStateTable() {
19
+ this.brainDb.exec(`
20
+ CREATE TABLE IF NOT EXISTS reposignal_import_state (
21
+ repo_full_name TEXT PRIMARY KEY,
22
+ signal_score REAL NOT NULL,
23
+ signal_level TEXT NOT NULL,
24
+ imported_at TEXT DEFAULT (datetime('now'))
25
+ )
26
+ `);
27
+ }
28
+ /** Import repos from a reposignal/aisurvival SQLite database. */
29
+ import(dbPath, options = {}) {
30
+ const start = Date.now();
31
+ const minLevel = options.minSignalLevel ?? 'watch';
32
+ const batchSize = options.batchSize ?? 5000;
33
+ const includeHn = options.includeHnMentions !== false;
34
+ const recordMetrics = options.recordMetrics !== false;
35
+ if (!fs.existsSync(dbPath)) {
36
+ throw new Error(`Reposignal DB not found: ${dbPath}`);
37
+ }
38
+ const extDb = new Database(dbPath, { readonly: true });
39
+ const result = {
40
+ dbPath,
41
+ totalReposInDb: 0,
42
+ reposImported: 0,
43
+ discoveriesCreated: 0,
44
+ journalEntriesCreated: 0,
45
+ hnMentionsImported: 0,
46
+ metricsRecorded: 0,
47
+ skippedDuplicates: 0,
48
+ languageBreakdown: {},
49
+ signalBreakdown: {},
50
+ duration_ms: 0,
51
+ };
52
+ try {
53
+ // Count total repos
54
+ result.totalReposInDb = extDb.prepare('SELECT COUNT(*) as c FROM repositories').get().c;
55
+ // Fetch repos at or above minimum signal level
56
+ const minLevelIdx = signalLevelIndex(minLevel);
57
+ const allowedLevels = SIGNAL_LEVELS.filter((_, i) => i >= minLevelIdx);
58
+ const placeholders = allowedLevels.map(() => '?').join(',');
59
+ const repos = extDb.prepare(`
60
+ SELECT id, full_name, name, owner, description, language, topics,
61
+ current_stars, current_forks, signal_score, signal_level, phase,
62
+ first_seen_at, last_scanned_at
63
+ FROM repositories
64
+ WHERE signal_level IN (${placeholders}) AND is_active = 1
65
+ ORDER BY signal_score DESC
66
+ LIMIT ?
67
+ `).all(...allowedLevels, batchSize);
68
+ this.log.info(`[reposignal] Found ${repos.length} repos at ${minLevel}+ level (${result.totalReposInDb} total in DB)`);
69
+ // Check which repos we already imported
70
+ const alreadyImported = new Set();
71
+ const existing = this.brainDb.prepare('SELECT repo_full_name FROM reposignal_import_state').all();
72
+ for (const e of existing)
73
+ alreadyImported.add(e.repo_full_name);
74
+ // Prepare statements
75
+ const insertDiscovery = this.brainDb.prepare(`
76
+ INSERT INTO research_discoveries (type, title, description, confidence, impact, source, data)
77
+ VALUES (?, ?, ?, ?, ?, ?, ?)
78
+ `);
79
+ const insertJournal = this.brainDb.prepare(`
80
+ INSERT INTO research_journal (timestamp, type, title, content, tags, ref_ids, significance, data)
81
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)
82
+ `);
83
+ const insertState = this.brainDb.prepare(`
84
+ INSERT OR REPLACE INTO reposignal_import_state (repo_full_name, signal_score, signal_level)
85
+ VALUES (?, ?, ?)
86
+ `);
87
+ // Batch import repos
88
+ const importBatch = this.brainDb.transaction(() => {
89
+ for (const repo of repos) {
90
+ // Track breakdown
91
+ const lang = repo.language || 'unknown';
92
+ result.languageBreakdown[lang] = (result.languageBreakdown[lang] || 0) + 1;
93
+ result.signalBreakdown[repo.signal_level] = (result.signalBreakdown[repo.signal_level] || 0) + 1;
94
+ // Skip duplicates
95
+ if (alreadyImported.has(repo.full_name)) {
96
+ result.skippedDuplicates++;
97
+ continue;
98
+ }
99
+ // Create research discovery for signal+ repos
100
+ const confidence = Math.min(repo.signal_score / 100, 1.0);
101
+ const impact = repo.signal_level === 'breakout' ? 0.9 : repo.signal_level === 'signal' ? 0.7 : 0.4;
102
+ const topics = this.parseTopics(repo.topics);
103
+ const description = [
104
+ repo.description || 'No description',
105
+ `Language: ${lang}`,
106
+ `Stars: ${repo.current_stars}, Forks: ${repo.current_forks}`,
107
+ `Phase: ${repo.phase}`,
108
+ topics.length > 0 ? `Topics: ${topics.join(', ')}` : '',
109
+ ].filter(Boolean).join('\n');
110
+ insertDiscovery.run('reposignal_import', `[${repo.signal_level.toUpperCase()}] ${repo.full_name} — ${(repo.description || 'GitHub project').slice(0, 120)}`, description, confidence, impact, 'reposignal', JSON.stringify({
111
+ repo: repo.full_name,
112
+ language: lang,
113
+ stars: repo.current_stars,
114
+ forks: repo.current_forks,
115
+ signal_score: repo.signal_score,
116
+ signal_level: repo.signal_level,
117
+ phase: repo.phase,
118
+ topics,
119
+ }));
120
+ result.discoveriesCreated++;
121
+ // Mark as imported
122
+ insertState.run(repo.full_name, repo.signal_score, repo.signal_level);
123
+ result.reposImported++;
124
+ }
125
+ // Create journal entries summarizing the import by language
126
+ const langGroups = Object.entries(result.languageBreakdown)
127
+ .sort(([, a], [, b]) => b - a)
128
+ .slice(0, 10);
129
+ if (result.reposImported > 0) {
130
+ const langSummary = langGroups.map(([lang, count]) => `${lang}: ${count}`).join(', ');
131
+ insertJournal.run(Date.now(), 'discovery', `Reposignal Import: ${result.reposImported} repos imported`, `Imported ${result.reposImported} trending repos from reposignal DB (${result.totalReposInDb} total tracked).\n` +
132
+ `Signal breakdown: ${Object.entries(result.signalBreakdown).map(([k, v]) => `${k}: ${v}`).join(', ')}\n` +
133
+ `Top languages: ${langSummary}`, JSON.stringify(['reposignal', 'import', 'tech-trends']), '[]', 'notable', JSON.stringify({ reposImported: result.reposImported, languageBreakdown: result.languageBreakdown }));
134
+ result.journalEntriesCreated++;
135
+ }
136
+ // Create journal entries for top signal repos (breakout/signal)
137
+ const topRepos = repos
138
+ .filter(r => !alreadyImported.has(r.full_name) && (r.signal_level === 'breakout' || r.signal_level === 'signal'))
139
+ .slice(0, 20);
140
+ for (const repo of topRepos) {
141
+ const topics = this.parseTopics(repo.topics);
142
+ insertJournal.run(Date.now(), 'discovery', `Trending: ${repo.full_name} (${repo.signal_level}, ${repo.signal_score.toFixed(1)} score)`, `${repo.description || 'No description'}\n` +
143
+ `Language: ${repo.language || 'unknown'}, Stars: ${repo.current_stars}, Phase: ${repo.phase}`, JSON.stringify(['reposignal', repo.signal_level, repo.language || 'unknown', ...topics.slice(0, 3)]), '[]', repo.signal_level === 'breakout' ? 'breakthrough' : 'notable', JSON.stringify({ repo: repo.full_name, signal_score: repo.signal_score }));
144
+ result.journalEntriesCreated++;
145
+ }
146
+ });
147
+ importBatch();
148
+ // Import HN mentions
149
+ if (includeHn) {
150
+ result.hnMentionsImported = this.importHnMentions(extDb, insertJournal);
151
+ result.journalEntriesCreated += result.hnMentionsImported;
152
+ }
153
+ // Record metrics for PredictionEngine
154
+ if (recordMetrics) {
155
+ result.metricsRecorded = this.recordImportMetrics(result);
156
+ }
157
+ }
158
+ finally {
159
+ extDb.close();
160
+ }
161
+ result.duration_ms = Date.now() - start;
162
+ this.lastResult = result;
163
+ this.log.info(`[reposignal] Import complete: ${result.reposImported} repos, ${result.discoveriesCreated} discoveries, ${result.journalEntriesCreated} journal entries in ${result.duration_ms}ms`);
164
+ return result;
165
+ }
166
+ /** Import top HN mentions as journal entries. */
167
+ importHnMentions(extDb, insertJournal) {
168
+ let count = 0;
169
+ try {
170
+ const mentions = extDb.prepare(`
171
+ SELECT DISTINCT title, url, score, comment_count
172
+ FROM hn_mentions
173
+ WHERE score > 50
174
+ ORDER BY score DESC
175
+ LIMIT 100
176
+ `).all();
177
+ for (const m of mentions) {
178
+ insertJournal.run(Date.now(), 'discovery', `HN: ${m.title} (${m.score} pts, ${m.comment_count} comments)`, `High-engagement HN/Reddit post: ${m.title}\nScore: ${m.score}, Comments: ${m.comment_count}`, JSON.stringify(['reposignal', 'hn', 'social-signal']), '[]', m.score > 500 ? 'notable' : 'routine', JSON.stringify({ source: 'hn', score: m.score, comments: m.comment_count }));
179
+ count++;
180
+ }
181
+ }
182
+ catch {
183
+ this.log.debug('[reposignal] No HN mentions table or error reading it');
184
+ }
185
+ return count;
186
+ }
187
+ /** Record aggregated metrics into prediction_metrics table. */
188
+ recordImportMetrics(result) {
189
+ let count = 0;
190
+ try {
191
+ const insertMetric = this.brainDb.prepare(`
192
+ INSERT INTO prediction_metrics (metric, value, timestamp, domain)
193
+ VALUES (?, ?, ?, ?)
194
+ `);
195
+ const now = Date.now();
196
+ insertMetric.run('reposignal_total_repos', result.totalReposInDb, now, 'metric');
197
+ count++;
198
+ insertMetric.run('reposignal_repos_imported', result.reposImported, now, 'metric');
199
+ count++;
200
+ // Record per-language counts
201
+ for (const [lang, langCount] of Object.entries(result.languageBreakdown)) {
202
+ if (langCount >= 10) {
203
+ insertMetric.run(`reposignal_lang_${lang.toLowerCase()}`, langCount, now, 'metric');
204
+ count++;
205
+ }
206
+ }
207
+ // Record signal level counts
208
+ for (const [level, levelCount] of Object.entries(result.signalBreakdown)) {
209
+ insertMetric.run(`reposignal_${level}_count`, levelCount, now, 'metric');
210
+ count++;
211
+ }
212
+ }
213
+ catch (err) {
214
+ this.log.debug('[reposignal] Error recording metrics:', err);
215
+ }
216
+ return count;
217
+ }
218
+ parseTopics(topics) {
219
+ if (!topics)
220
+ return [];
221
+ try {
222
+ return JSON.parse(topics);
223
+ }
224
+ catch {
225
+ return [];
226
+ }
227
+ }
228
+ getLastResult() {
229
+ return this.lastResult;
230
+ }
231
+ /** Get import stats from state table. */
232
+ getStats() {
233
+ const total = this.brainDb.prepare('SELECT COUNT(*) as c FROM reposignal_import_state').get().c;
234
+ const levels = this.brainDb.prepare('SELECT signal_level, COUNT(*) as c FROM reposignal_import_state GROUP BY signal_level').all();
235
+ const last = this.brainDb.prepare('SELECT MAX(imported_at) as t FROM reposignal_import_state').get();
236
+ const byLevel = {};
237
+ for (const l of levels)
238
+ byLevel[l.signal_level] = l.c;
239
+ return { totalImported: total, byLevel, lastImport: last.t };
240
+ }
241
+ }
242
+ //# sourceMappingURL=reposignal-importer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reposignal-importer.js","sourceRoot":"","sources":["../../src/services/reposignal-importer.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AACtC,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,SAAS,EAAE,MAAM,kCAAkC,CAAC;AAsD7D,uDAAuD;AAEvD,MAAM,aAAa,GAAG,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,UAAU,CAAU,CAAC;AAExE,SAAS,gBAAgB,CAAC,KAAa;IACrC,OAAO,aAAa,CAAC,OAAO,CAAC,KAAqC,CAAC,CAAC;AACtE,CAAC;AAED,uDAAuD;AAEvD,MAAM,OAAO,kBAAkB;IACrB,OAAO,CAAoB;IAC3B,GAAG,GAAG,SAAS,EAAE,CAAC;IAClB,UAAU,GAAkC,IAAI,CAAC;IAEzD,YAAY,OAA0B;QACpC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,gBAAgB,EAAE,CAAC;IAC1B,CAAC;IAEO,gBAAgB;QACtB,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;;;;;;;KAOjB,CAAC,CAAC;IACL,CAAC;IAED,iEAAiE;IACjE,MAAM,CAAC,MAAc,EAAE,UAAmC,EAAE;QAC1D,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACzB,MAAM,QAAQ,GAAG,OAAO,CAAC,cAAc,IAAI,OAAO,CAAC;QACnD,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,IAAI,CAAC;QAC5C,MAAM,SAAS,GAAG,OAAO,CAAC,iBAAiB,KAAK,KAAK,CAAC;QACtD,MAAM,aAAa,GAAG,OAAO,CAAC,aAAa,KAAK,KAAK,CAAC;QAEtD,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;YAC3B,MAAM,IAAI,KAAK,CAAC,4BAA4B,MAAM,EAAE,CAAC,CAAC;QACxD,CAAC;QAED,MAAM,KAAK,GAAG,IAAI,QAAQ,CAAC,MAAM,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;QAEvD,MAAM,MAAM,GAA2B;YACrC,MAAM;YACN,cAAc,EAAE,CAAC;YACjB,aAAa,EAAE,CAAC;YAChB,kBAAkB,EAAE,CAAC;YACrB,qBAAqB,EAAE,CAAC;YACxB,kBAAkB,EAAE,CAAC;YACrB,eAAe,EAAE,CAAC;YAClB,iBAAiB,EAAE,CAAC;YACpB,iBAAiB,EAAE,EAAE;YACrB,eAAe,EAAE,EAAE;YACnB,WAAW,EAAE,CAAC;SACf,CAAC;QAEF,IAAI,CAAC;YACH,oBAAoB;YACpB,MAAM,CAAC,cAAc,GAAI,KAAK,CAAC,OAAO,CAAC,wCAAwC,CAAC,CAAC,GAAG,EAAoB,CAAC,CAAC,CAAC;YAE3G,+CAA+C;YAC/C,MAAM,WAAW,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAC;YAC/C,MAAM,aAAa,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,WAAW,CAAC,CAAC;YACvE,MAAM,YAAY,GAAG,aAAa,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAE5D,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC;;;;;iCAKD,YAAY;;;OAGtC,CAAC,CAAC,GAAG,CAAC,GAAG,aAAa,EAAE,SAAS,CAAqB,CAAC;YAExD,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,sBAAsB,KAAK,CAAC,MAAM,aAAa,QAAQ,YAAY,MAAM,CAAC,cAAc,eAAe,CAAC,CAAC;YAEvH,wCAAwC;YACxC,MAAM,eAAe,GAAG,IAAI,GAAG,EAAU,CAAC;YAC1C,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,oDAAoD,CAAC,CAAC,GAAG,EAAuC,CAAC;YACvI,KAAK,MAAM,CAAC,IAAI,QAAQ;gBAAE,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC;YAEhE,qBAAqB;YACrB,MAAM,eAAe,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC;;;OAG5C,CAAC,CAAC;YACH,MAAM,aAAa,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC;;;OAG1C,CAAC,CAAC;YACH,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC;;;OAGxC,CAAC,CAAC;YAEH,qBAAqB;YACrB,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,GAAG,EAAE;gBAChD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;oBACzB,kBAAkB;oBAClB,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,IAAI,SAAS,CAAC;oBACxC,MAAM,CAAC,iBAAiB,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;oBAC3E,MAAM,CAAC,eAAe,CAAC,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,eAAe,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;oBAEjG,kBAAkB;oBAClB,IAAI,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;wBACxC,MAAM,CAAC,iBAAiB,EAAE,CAAC;wBAC3B,SAAS;oBACX,CAAC;oBAED,8CAA8C;oBAC9C,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,YAAY,GAAG,GAAG,EAAE,GAAG,CAAC,CAAC;oBAC1D,MAAM,MAAM,GAAG,IAAI,CAAC,YAAY,KAAK,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;oBAEnG,MAAM,MAAM,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;oBAC7C,MAAM,WAAW,GAAG;wBAClB,IAAI,CAAC,WAAW,IAAI,gBAAgB;wBACpC,aAAa,IAAI,EAAE;wBACnB,UAAU,IAAI,CAAC,aAAa,YAAY,IAAI,CAAC,aAAa,EAAE;wBAC5D,UAAU,IAAI,CAAC,KAAK,EAAE;wBACtB,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,WAAW,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE;qBACxD,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;oBAE7B,eAAe,CAAC,GAAG,CACjB,mBAAmB,EACnB,IAAI,IAAI,CAAC,YAAY,CAAC,WAAW,EAAE,KAAK,IAAI,CAAC,SAAS,MAAM,CAAC,IAAI,CAAC,WAAW,IAAI,gBAAgB,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,EAClH,WAAW,EACX,UAAU,EACV,MAAM,EACN,YAAY,EACZ,IAAI,CAAC,SAAS,CAAC;wBACb,IAAI,EAAE,IAAI,CAAC,SAAS;wBACpB,QAAQ,EAAE,IAAI;wBACd,KAAK,EAAE,IAAI,CAAC,aAAa;wBACzB,KAAK,EAAE,IAAI,CAAC,aAAa;wBACzB,YAAY,EAAE,IAAI,CAAC,YAAY;wBAC/B,YAAY,EAAE,IAAI,CAAC,YAAY;wBAC/B,KAAK,EAAE,IAAI,CAAC,KAAK;wBACjB,MAAM;qBACP,CAAC,CACH,CAAC;oBACF,MAAM,CAAC,kBAAkB,EAAE,CAAC;oBAE5B,mBAAmB;oBACnB,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;oBACtE,MAAM,CAAC,aAAa,EAAE,CAAC;gBACzB,CAAC;gBAED,4DAA4D;gBAC5D,MAAM,UAAU,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,iBAAiB,CAAC;qBACxD,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC;qBAC7B,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;gBAEhB,IAAI,MAAM,CAAC,aAAa,GAAG,CAAC,EAAE,CAAC;oBAC7B,MAAM,WAAW,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,GAAG,IAAI,KAAK,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;oBACtF,aAAa,CAAC,GAAG,CACf,IAAI,CAAC,GAAG,EAAE,EACV,WAAW,EACX,sBAAsB,MAAM,CAAC,aAAa,iBAAiB,EAC3D,YAAY,MAAM,CAAC,aAAa,uCAAuC,MAAM,CAAC,cAAc,oBAAoB;wBAChH,qBAAqB,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI;wBACxG,kBAAkB,WAAW,EAAE,EAC/B,IAAI,CAAC,SAAS,CAAC,CAAC,YAAY,EAAE,QAAQ,EAAE,aAAa,CAAC,CAAC,EACvD,IAAI,EACJ,SAAS,EACT,IAAI,CAAC,SAAS,CAAC,EAAE,aAAa,EAAE,MAAM,CAAC,aAAa,EAAE,iBAAiB,EAAE,MAAM,CAAC,iBAAiB,EAAE,CAAC,CACrG,CAAC;oBACF,MAAM,CAAC,qBAAqB,EAAE,CAAC;gBACjC,CAAC;gBAED,gEAAgE;gBAChE,MAAM,QAAQ,GAAG,KAAK;qBACnB,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,YAAY,KAAK,UAAU,IAAI,CAAC,CAAC,YAAY,KAAK,QAAQ,CAAC,CAAC;qBAChH,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;gBAEhB,KAAK,MAAM,IAAI,IAAI,QAAQ,EAAE,CAAC;oBAC5B,MAAM,MAAM,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;oBAC7C,aAAa,CAAC,GAAG,CACf,IAAI,CAAC,GAAG,EAAE,EACV,WAAW,EACX,aAAa,IAAI,CAAC,SAAS,KAAK,IAAI,CAAC,YAAY,KAAK,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,EAC3F,GAAG,IAAI,CAAC,WAAW,IAAI,gBAAgB,IAAI;wBAC3C,aAAa,IAAI,CAAC,QAAQ,IAAI,SAAS,YAAY,IAAI,CAAC,aAAa,YAAY,IAAI,CAAC,KAAK,EAAE,EAC7F,IAAI,CAAC,SAAS,CAAC,CAAC,YAAY,EAAE,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,QAAQ,IAAI,SAAS,EAAE,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EACpG,IAAI,EACJ,IAAI,CAAC,YAAY,KAAK,UAAU,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,SAAS,EAC7D,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,EAAE,YAAY,EAAE,IAAI,CAAC,YAAY,EAAE,CAAC,CAC1E,CAAC;oBACF,MAAM,CAAC,qBAAqB,EAAE,CAAC;gBACjC,CAAC;YACH,CAAC,CAAC,CAAC;YAEH,WAAW,EAAE,CAAC;YAEd,qBAAqB;YACrB,IAAI,SAAS,EAAE,CAAC;gBACd,MAAM,CAAC,kBAAkB,GAAG,IAAI,CAAC,gBAAgB,CAAC,KAAK,EAAE,aAAa,CAAC,CAAC;gBACxE,MAAM,CAAC,qBAAqB,IAAI,MAAM,CAAC,kBAAkB,CAAC;YAC5D,CAAC;YAED,sCAAsC;YACtC,IAAI,aAAa,EAAE,CAAC;gBAClB,MAAM,CAAC,eAAe,GAAG,IAAI,CAAC,mBAAmB,CAAC,MAAM,CAAC,CAAC;YAC5D,CAAC;QAEH,CAAC;gBAAS,CAAC;YACT,KAAK,CAAC,KAAK,EAAE,CAAC;QAChB,CAAC;QAED,MAAM,CAAC,WAAW,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC;QACxC,IAAI,CAAC,UAAU,GAAG,MAAM,CAAC;QACzB,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,iCAAiC,MAAM,CAAC,aAAa,WAAW,MAAM,CAAC,kBAAkB,iBAAiB,MAAM,CAAC,qBAAqB,uBAAuB,MAAM,CAAC,WAAW,IAAI,CAAC,CAAC;QAEnM,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,iDAAiD;IACzC,gBAAgB,CAAC,KAAwB,EAAE,aAAiC;QAClF,IAAI,KAAK,GAAG,CAAC,CAAC;QACd,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC;;;;;;OAM9B,CAAC,CAAC,GAAG,EAA2B,CAAC;YAElC,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;gBACzB,aAAa,CAAC,GAAG,CACf,IAAI,CAAC,GAAG,EAAE,EACV,WAAW,EACX,OAAO,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC,aAAa,YAAY,EAC9D,mCAAmC,CAAC,CAAC,KAAK,YAAY,CAAC,CAAC,KAAK,eAAe,CAAC,CAAC,aAAa,EAAE,EAC7F,IAAI,CAAC,SAAS,CAAC,CAAC,YAAY,EAAE,IAAI,EAAE,eAAe,CAAC,CAAC,EACrD,IAAI,EACJ,CAAC,CAAC,KAAK,GAAG,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,EACrC,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC,aAAa,EAAE,CAAC,CAC5E,CAAC;gBACF,KAAK,EAAE,CAAC;YACV,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,uDAAuD,CAAC,CAAC;QAC1E,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,+DAA+D;IACvD,mBAAmB,CAAC,MAA8B;QACxD,IAAI,KAAK,GAAG,CAAC,CAAC;QACd,IAAI,CAAC;YACH,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC;;;OAGzC,CAAC,CAAC;YACH,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YAEvB,YAAY,CAAC,GAAG,CAAC,wBAAwB,EAAE,MAAM,CAAC,cAAc,EAAE,GAAG,EAAE,QAAQ,CAAC,CAAC;YACjF,KAAK,EAAE,CAAC;YACR,YAAY,CAAC,GAAG,CAAC,2BAA2B,EAAE,MAAM,CAAC,aAAa,EAAE,GAAG,EAAE,QAAQ,CAAC,CAAC;YACnF,KAAK,EAAE,CAAC;YAER,6BAA6B;YAC7B,KAAK,MAAM,CAAC,IAAI,EAAE,SAAS,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,iBAAiB,CAAC,EAAE,CAAC;gBACzE,IAAI,SAAS,IAAI,EAAE,EAAE,CAAC;oBACpB,YAAY,CAAC,GAAG,CAAC,mBAAmB,IAAI,CAAC,WAAW,EAAE,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE,QAAQ,CAAC,CAAC;oBACpF,KAAK,EAAE,CAAC;gBACV,CAAC;YACH,CAAC;YAED,6BAA6B;YAC7B,KAAK,MAAM,CAAC,KAAK,EAAE,UAAU,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,eAAe,CAAC,EAAE,CAAC;gBACzE,YAAY,CAAC,GAAG,CAAC,cAAc,KAAK,QAAQ,EAAE,UAAU,EAAE,GAAG,EAAE,QAAQ,CAAC,CAAC;gBACzE,KAAK,EAAE,CAAC;YACV,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,uCAAuC,EAAE,GAAG,CAAC,CAAC;QAC/D,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAEO,WAAW,CAAC,MAAqB;QACvC,IAAI,CAAC,MAAM;YAAE,OAAO,EAAE,CAAC;QACvB,IAAI,CAAC;YAAC,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC;YAAC,OAAO,EAAE,CAAC;QAAC,CAAC;IACzD,CAAC;IAED,aAAa;QACX,OAAO,IAAI,CAAC,UAAU,CAAC;IACzB,CAAC;IAED,yCAAyC;IACzC,QAAQ;QACN,MAAM,KAAK,GAAI,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,mDAAmD,CAAC,CAAC,GAAG,EAAoB,CAAC,CAAC,CAAC;QACnH,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,uFAAuF,CAAC,CAAC,GAAG,EAAgD,CAAC;QACjL,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,2DAA2D,CAAC,CAAC,GAAG,EAA0B,CAAC;QAE7H,MAAM,OAAO,GAA2B,EAAE,CAAC;QAC3C,KAAK,MAAM,CAAC,IAAI,MAAM;YAAE,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QAEtD,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,IAAI,CAAC,CAAC,EAAE,CAAC;IAC/D,CAAC;CACF"}
@@ -73,6 +73,16 @@ export interface EmbeddingsConfig {
73
73
  sweepIntervalMs: number;
74
74
  batchSize: number;
75
75
  }
76
+ export interface ScannerBrainConfig {
77
+ enabled: boolean;
78
+ githubToken: string;
79
+ scanIntervalMs: number;
80
+ minStarsEmerging: number;
81
+ minStarsTrending: number;
82
+ maxReposPerScan: number;
83
+ cryptoEnabled: boolean;
84
+ hnEnabled: boolean;
85
+ }
76
86
  export interface BrainConfig {
77
87
  dataDir: string;
78
88
  dbPath: string;
@@ -88,4 +98,5 @@ export interface BrainConfig {
88
98
  research: ResearchConfig;
89
99
  log: LogConfig;
90
100
  retention: RetentionConfig;
101
+ scanner: ScannerBrainConfig;
91
102
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@timmeck/brain",
3
- "version": "3.15.0",
3
+ "version": "3.17.0",
4
4
  "description": "Adaptive error memory and code intelligence system with Hebbian synapse network, hybrid search, and REST API",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -43,7 +43,7 @@
43
43
  "dependencies": {
44
44
  "@huggingface/transformers": "^3.8.1",
45
45
  "@modelcontextprotocol/sdk": "^1.0.0",
46
- "@timmeck/brain-core": "2.11.0",
46
+ "@timmeck/brain-core": "^2.16.0",
47
47
  "better-sqlite3": "^11.7.0",
48
48
  "chalk": "^5.6.2",
49
49
  "commander": "^13.0.0",