@timmeck/brain-core 2.15.0 → 2.16.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/dist/api/server.js +10 -0
- package/dist/api/server.js.map +1 -1
- package/dist/consciousness/consciousness-server.js +10 -0
- package/dist/consciousness/consciousness-server.js.map +1 -1
- package/dist/index.d.ts +6 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/mcp/http-server.js +10 -0
- package/dist/mcp/http-server.js.map +1 -1
- package/dist/prediction/types.d.ts +1 -1
- package/dist/research/research-orchestrator.d.ts +4 -0
- package/dist/research/research-orchestrator.js +37 -0
- package/dist/research/research-orchestrator.js.map +1 -1
- package/dist/scanner/crypto-collector.d.ts +17 -0
- package/dist/scanner/crypto-collector.js +89 -0
- package/dist/scanner/crypto-collector.js.map +1 -0
- package/dist/scanner/github-collector.d.ts +22 -0
- package/dist/scanner/github-collector.js +104 -0
- package/dist/scanner/github-collector.js.map +1 -0
- package/dist/scanner/hn-collector.d.ts +17 -0
- package/dist/scanner/hn-collector.js +58 -0
- package/dist/scanner/hn-collector.js.map +1 -0
- package/dist/scanner/index.d.ts +6 -0
- package/dist/scanner/index.js +6 -0
- package/dist/scanner/index.js.map +1 -0
- package/dist/scanner/signal-scanner.d.ts +83 -0
- package/dist/scanner/signal-scanner.js +859 -0
- package/dist/scanner/signal-scanner.js.map +1 -0
- package/dist/scanner/signal-scorer.d.ts +31 -0
- package/dist/scanner/signal-scorer.js +205 -0
- package/dist/scanner/signal-scorer.js.map +1 -0
- package/dist/scanner/types.d.ts +170 -0
- package/dist/scanner/types.js +3 -0
- package/dist/scanner/types.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { getLogger } from '../utils/logger.js';
|
|
2
|
+
const log = getLogger();
|
|
3
|
+
const TRENDING_LANGUAGES = [
|
|
4
|
+
'TypeScript', 'Python', 'Rust', 'Go', 'JavaScript',
|
|
5
|
+
'C++', 'Java', 'Kotlin', 'Swift', 'Zig',
|
|
6
|
+
'C#', 'Ruby', 'Elixir',
|
|
7
|
+
];
|
|
8
|
+
/**
|
|
9
|
+
* Collect emerging and trending repos from GitHub Search API.
|
|
10
|
+
* Respects rate limits (30 req/min for authenticated, 10 for unauthed).
|
|
11
|
+
*/
|
|
12
|
+
export class GitHubCollector {
|
|
13
|
+
token;
|
|
14
|
+
minStarsEmerging;
|
|
15
|
+
minStarsTrending;
|
|
16
|
+
aborted = false;
|
|
17
|
+
constructor(config) {
|
|
18
|
+
this.token = config.githubToken;
|
|
19
|
+
this.minStarsEmerging = config.minStarsEmerging;
|
|
20
|
+
this.minStarsTrending = config.minStarsTrending;
|
|
21
|
+
}
|
|
22
|
+
abort() { this.aborted = true; }
|
|
23
|
+
reset() { this.aborted = false; }
|
|
24
|
+
/** Fetch emerging repos: created in last 7 days with stars > threshold. */
|
|
25
|
+
async collectEmerging() {
|
|
26
|
+
const sevenDaysAgo = new Date(Date.now() - 7 * 86_400_000).toISOString().split('T')[0];
|
|
27
|
+
const query = `created:>${sevenDaysAgo} stars:>${this.minStarsEmerging}`;
|
|
28
|
+
return this.searchAll(query, 300);
|
|
29
|
+
}
|
|
30
|
+
/** Fetch trending repos: pushed in last 3 days with stars > threshold, per language. */
|
|
31
|
+
async collectTrending() {
|
|
32
|
+
const threeDaysAgo = new Date(Date.now() - 3 * 86_400_000).toISOString().split('T')[0];
|
|
33
|
+
const all = [];
|
|
34
|
+
const seen = new Set();
|
|
35
|
+
for (const lang of TRENDING_LANGUAGES) {
|
|
36
|
+
if (this.aborted)
|
|
37
|
+
break;
|
|
38
|
+
const query = `pushed:>${threeDaysAgo} stars:>${this.minStarsTrending} language:${lang}`;
|
|
39
|
+
const repos = await this.search(query, 1, 30);
|
|
40
|
+
for (const r of repos) {
|
|
41
|
+
if (!seen.has(r.id)) {
|
|
42
|
+
seen.add(r.id);
|
|
43
|
+
all.push(r);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
// Delay between language searches to respect rate limits
|
|
47
|
+
await sleep(1200);
|
|
48
|
+
}
|
|
49
|
+
return all;
|
|
50
|
+
}
|
|
51
|
+
/** Search with pagination up to maxResults. */
|
|
52
|
+
async searchAll(query, maxResults) {
|
|
53
|
+
const all = [];
|
|
54
|
+
const perPage = 100;
|
|
55
|
+
const maxPages = Math.ceil(maxResults / perPage);
|
|
56
|
+
for (let page = 1; page <= maxPages; page++) {
|
|
57
|
+
if (this.aborted)
|
|
58
|
+
break;
|
|
59
|
+
const repos = await this.search(query, page, perPage);
|
|
60
|
+
all.push(...repos);
|
|
61
|
+
if (repos.length < perPage)
|
|
62
|
+
break;
|
|
63
|
+
await sleep(1500);
|
|
64
|
+
}
|
|
65
|
+
return all;
|
|
66
|
+
}
|
|
67
|
+
/** Single search API call. */
|
|
68
|
+
async search(query, page, perPage) {
|
|
69
|
+
const url = `https://api.github.com/search/repositories?q=${encodeURIComponent(query)}&sort=stars&order=desc&per_page=${perPage}&page=${page}`;
|
|
70
|
+
const headers = {
|
|
71
|
+
'Accept': 'application/vnd.github+json',
|
|
72
|
+
'User-Agent': 'brain-ecosystem-scanner',
|
|
73
|
+
};
|
|
74
|
+
if (this.token) {
|
|
75
|
+
headers['Authorization'] = `Bearer ${this.token}`;
|
|
76
|
+
}
|
|
77
|
+
try {
|
|
78
|
+
const res = await fetch(url, { headers, signal: this.aborted ? AbortSignal.abort() : undefined });
|
|
79
|
+
if (res.status === 403 || res.status === 429) {
|
|
80
|
+
const reset = res.headers.get('x-ratelimit-reset');
|
|
81
|
+
const waitMs = reset ? (Number(reset) * 1000 - Date.now()) : 60_000;
|
|
82
|
+
log.warn(`[github-collector] Rate limited, waiting ${Math.ceil(waitMs / 1000)}s`);
|
|
83
|
+
await sleep(Math.min(waitMs, 120_000));
|
|
84
|
+
return this.search(query, page, perPage);
|
|
85
|
+
}
|
|
86
|
+
if (!res.ok) {
|
|
87
|
+
log.error(`[github-collector] Search failed: ${res.status} ${res.statusText}`);
|
|
88
|
+
return [];
|
|
89
|
+
}
|
|
90
|
+
const data = await res.json();
|
|
91
|
+
return data.items ?? [];
|
|
92
|
+
}
|
|
93
|
+
catch (err) {
|
|
94
|
+
if (this.aborted)
|
|
95
|
+
return [];
|
|
96
|
+
log.error(`[github-collector] Error: ${err.message}`);
|
|
97
|
+
return [];
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
function sleep(ms) {
|
|
102
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=github-collector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"github-collector.js","sourceRoot":"","sources":["../../src/scanner/github-collector.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { HnHit } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Collect GitHub-related posts from HackerNews via Algolia API.
|
|
4
|
+
* Free, no auth required, generous rate limits.
|
|
5
|
+
*/
|
|
6
|
+
export declare class HnCollector {
|
|
7
|
+
private aborted;
|
|
8
|
+
abort(): void;
|
|
9
|
+
reset(): void;
|
|
10
|
+
/** Search HN for GitHub repos on frontpage (last 24h). */
|
|
11
|
+
collectFrontpage(): Promise<HnHit[]>;
|
|
12
|
+
/** Cross-reference: search HN for a specific repo name. */
|
|
13
|
+
searchRepo(repoFullName: string): Promise<HnHit[]>;
|
|
14
|
+
/** Batch cross-reference: search HN for multiple repos. */
|
|
15
|
+
crossReference(repoNames: string[]): Promise<Map<string, HnHit[]>>;
|
|
16
|
+
private fetch;
|
|
17
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { getLogger } from '../utils/logger.js';
|
|
2
|
+
const log = getLogger();
|
|
3
|
+
/**
|
|
4
|
+
* Collect GitHub-related posts from HackerNews via Algolia API.
|
|
5
|
+
* Free, no auth required, generous rate limits.
|
|
6
|
+
*/
|
|
7
|
+
export class HnCollector {
|
|
8
|
+
aborted = false;
|
|
9
|
+
abort() { this.aborted = true; }
|
|
10
|
+
reset() { this.aborted = false; }
|
|
11
|
+
/** Search HN for GitHub repos on frontpage (last 24h). */
|
|
12
|
+
async collectFrontpage() {
|
|
13
|
+
const oneDayAgo = Math.floor((Date.now() - 86_400_000) / 1000);
|
|
14
|
+
const url = `https://hn.algolia.com/api/v1/search?query=github.com&tags=story&numericFilters=created_at_i>${oneDayAgo}&hitsPerPage=100`;
|
|
15
|
+
return this.fetch(url);
|
|
16
|
+
}
|
|
17
|
+
/** Cross-reference: search HN for a specific repo name. */
|
|
18
|
+
async searchRepo(repoFullName) {
|
|
19
|
+
const url = `https://hn.algolia.com/api/v1/search?query=${encodeURIComponent(repoFullName)}&tags=story&hitsPerPage=20`;
|
|
20
|
+
return this.fetch(url);
|
|
21
|
+
}
|
|
22
|
+
/** Batch cross-reference: search HN for multiple repos. */
|
|
23
|
+
async crossReference(repoNames) {
|
|
24
|
+
const results = new Map();
|
|
25
|
+
for (const name of repoNames) {
|
|
26
|
+
if (this.aborted)
|
|
27
|
+
break;
|
|
28
|
+
const hits = await this.searchRepo(name);
|
|
29
|
+
if (hits.length > 0) {
|
|
30
|
+
results.set(name, hits);
|
|
31
|
+
}
|
|
32
|
+
// Be polite to Algolia API
|
|
33
|
+
await new Promise(r => setTimeout(r, 200));
|
|
34
|
+
}
|
|
35
|
+
return results;
|
|
36
|
+
}
|
|
37
|
+
async fetch(url) {
|
|
38
|
+
try {
|
|
39
|
+
const res = await globalThis.fetch(url, {
|
|
40
|
+
headers: { 'User-Agent': 'brain-ecosystem-scanner' },
|
|
41
|
+
signal: this.aborted ? AbortSignal.abort() : undefined,
|
|
42
|
+
});
|
|
43
|
+
if (!res.ok) {
|
|
44
|
+
log.error(`[hn-collector] Fetch failed: ${res.status} ${res.statusText}`);
|
|
45
|
+
return [];
|
|
46
|
+
}
|
|
47
|
+
const data = await res.json();
|
|
48
|
+
return data.hits ?? [];
|
|
49
|
+
}
|
|
50
|
+
catch (err) {
|
|
51
|
+
if (this.aborted)
|
|
52
|
+
return [];
|
|
53
|
+
log.error(`[hn-collector] Error: ${err.message}`);
|
|
54
|
+
return [];
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=hn-collector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hn-collector.js","sourceRoot":"","sources":["../../src/scanner/hn-collector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAG/C,MAAM,GAAG,GAAG,SAAS,EAAE,CAAC;AAExB;;;GAGG;AACH,MAAM,OAAO,WAAW;IACd,OAAO,GAAG,KAAK,CAAC;IAExB,KAAK,KAAW,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC;IACtC,KAAK,KAAW,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC;IAEvC,0DAA0D;IAC1D,KAAK,CAAC,gBAAgB;QACpB,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,UAAU,CAAC,GAAG,IAAI,CAAC,CAAC;QAC/D,MAAM,GAAG,GAAG,gGAAgG,SAAS,kBAAkB,CAAC;QACxI,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACzB,CAAC;IAED,2DAA2D;IAC3D,KAAK,CAAC,UAAU,CAAC,YAAoB;QACnC,MAAM,GAAG,GAAG,8CAA8C,kBAAkB,CAAC,YAAY,CAAC,4BAA4B,CAAC;QACvH,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACzB,CAAC;IAED,2DAA2D;IAC3D,KAAK,CAAC,cAAc,CAAC,SAAmB;QACtC,MAAM,OAAO,GAAG,IAAI,GAAG,EAAmB,CAAC;QAC3C,KAAK,MAAM,IAAI,IAAI,SAAS,EAAE,CAAC;YAC7B,IAAI,IAAI,CAAC,OAAO;gBAAE,MAAM;YACxB,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;YACzC,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACpB,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;YAC1B,CAAC;YACD,2BAA2B;YAC3B,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;QAC7C,CAAC;QACD,OAAO,OAAO,CAAC;IACjB,CAAC;IAEO,KAAK,CAAC,KAAK,CAAC,GAAW;QAC7B,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,UAAU,CAAC,KAAK,CAAC,GAAG,EAAE;gBACtC,OAAO,EAAE,EAAE,YAAY,EAAE,yBAAyB,EAAE;gBACpD,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,WAAW,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS;aACvD,CAAC,CAAC;YAEH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;gBACZ,GAAG,CAAC,KAAK,CAAC,gCAAgC,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,UAAU,EAAE,CAAC,CAAC;gBAC1E,OAAO,EAAE,CAAC;YACZ,CAAC;YAED,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAoB,CAAC;YAChD,OAAO,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC;QACzB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,IAAI,CAAC,OAAO;gBAAE,OAAO,EAAE,CAAC;YAC5B,GAAG,CAAC,KAAK,CAAC,yBAA0B,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;YAC7D,OAAO,EAAE,CAAC;QACZ,CAAC;IACH,CAAC;CACF"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { SignalScanner, runScannerMigration } from './signal-scanner.js';
|
|
2
|
+
export { GitHubCollector } from './github-collector.js';
|
|
3
|
+
export { HnCollector } from './hn-collector.js';
|
|
4
|
+
export { CryptoCollector } from './crypto-collector.js';
|
|
5
|
+
export { scoreRepo, classifyLevel, classifyWithHysteresis, classifyPhase, scoreCrypto } from './signal-scorer.js';
|
|
6
|
+
export type { ScannerConfig, ScannedRepo, DailyStats, HnMention, CryptoToken, ScanResult, ScannerStatus, SignalLevel, RepoPhase, ScoreBreakdown, GitHubSearchResult, GitHubRepo, HnSearchResult, HnHit, CoinGeckoMarket, CoinGeckoTrending, } from './types.js';
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { SignalScanner, runScannerMigration } from './signal-scanner.js';
|
|
2
|
+
export { GitHubCollector } from './github-collector.js';
|
|
3
|
+
export { HnCollector } from './hn-collector.js';
|
|
4
|
+
export { CryptoCollector } from './crypto-collector.js';
|
|
5
|
+
export { scoreRepo, classifyLevel, classifyWithHysteresis, classifyPhase, scoreCrypto } from './signal-scorer.js';
|
|
6
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/scanner/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AACzE,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,sBAAsB,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import Database from 'better-sqlite3';
|
|
2
|
+
import type { ScannerConfig, ScanResult, ScannerStatus, ScannedRepo, SignalLevel, HnMention, CryptoToken, DailyStats } from './types.js';
|
|
3
|
+
export declare function runScannerMigration(db: Database.Database): void;
|
|
4
|
+
export declare class SignalScanner {
|
|
5
|
+
private db;
|
|
6
|
+
private config;
|
|
7
|
+
private github;
|
|
8
|
+
private hn;
|
|
9
|
+
private crypto;
|
|
10
|
+
private timer;
|
|
11
|
+
private scanning;
|
|
12
|
+
private lastResult;
|
|
13
|
+
constructor(db: Database.Database, config: Partial<ScannerConfig> & {
|
|
14
|
+
githubToken?: string;
|
|
15
|
+
});
|
|
16
|
+
/** Start periodic scanning. */
|
|
17
|
+
start(): void;
|
|
18
|
+
/** Stop periodic scanning. */
|
|
19
|
+
stop(): void;
|
|
20
|
+
/** Abort currently running scan. */
|
|
21
|
+
abortScan(): void;
|
|
22
|
+
/** Run a full scan pipeline. */
|
|
23
|
+
scan(): Promise<ScanResult>;
|
|
24
|
+
getStatus(): ScannerStatus;
|
|
25
|
+
getSignals(level: SignalLevel, limit?: number): ScannedRepo[];
|
|
26
|
+
getTrending(limit?: number): ScannedRepo[];
|
|
27
|
+
searchRepos(query: string, language?: string, limit?: number): ScannedRepo[];
|
|
28
|
+
getRepo(githubId: number): (ScannedRepo & {
|
|
29
|
+
daily_stats: DailyStats[];
|
|
30
|
+
}) | null;
|
|
31
|
+
getHnMentions(limit?: number): HnMention[];
|
|
32
|
+
getCryptoTokens(limit?: number): CryptoToken[];
|
|
33
|
+
getCryptoTrending(): CryptoToken[];
|
|
34
|
+
getStats(): Record<string, unknown>;
|
|
35
|
+
getConfig(): ScannerConfig;
|
|
36
|
+
updateConfig(updates: Partial<ScannerConfig>): ScannerConfig;
|
|
37
|
+
/** Upsert a GitHub repo. Returns true if new. */
|
|
38
|
+
private upsertRepo;
|
|
39
|
+
/** Record daily stats (UPSERT). */
|
|
40
|
+
private recordDailyStats;
|
|
41
|
+
/** Calculate velocity for all active repos from daily_stats. */
|
|
42
|
+
private calculateVelocities;
|
|
43
|
+
/** Process HN mentions and link to repos. */
|
|
44
|
+
private processHnMentions;
|
|
45
|
+
/** Score all active repos. */
|
|
46
|
+
private scoreAllRepos;
|
|
47
|
+
/** Classify all repos with hysteresis. Returns new breakout/signal counts. */
|
|
48
|
+
private classifyAll;
|
|
49
|
+
private getPhase;
|
|
50
|
+
/** Scan crypto tokens. */
|
|
51
|
+
private scanCrypto;
|
|
52
|
+
private upsertCrypto;
|
|
53
|
+
/**
|
|
54
|
+
* Import repos from the reposignal.dev API into scanned_repos.
|
|
55
|
+
* Fetches all signals from the live API and upserts them.
|
|
56
|
+
*/
|
|
57
|
+
importFromApi(apiUrl?: string, options?: {
|
|
58
|
+
limit?: number;
|
|
59
|
+
level?: string;
|
|
60
|
+
adminKey?: string;
|
|
61
|
+
}): Promise<{
|
|
62
|
+
repos: number;
|
|
63
|
+
skipped: number;
|
|
64
|
+
duration_ms: number;
|
|
65
|
+
}>;
|
|
66
|
+
/**
|
|
67
|
+
* Import repos from a reposignal/aisurvival SQLite database directly into scanned_repos.
|
|
68
|
+
* Copies: repositories → scanned_repos, repo_daily_stats → repo_daily_stats,
|
|
69
|
+
* hn_mentions → hn_mentions, crypto_tokens → crypto_tokens.
|
|
70
|
+
*/
|
|
71
|
+
importFromReposignal(dbPath: string, options?: {
|
|
72
|
+
minLevel?: string;
|
|
73
|
+
}): {
|
|
74
|
+
repos: number;
|
|
75
|
+
dailyStats: number;
|
|
76
|
+
hnMentions: number;
|
|
77
|
+
crypto: number;
|
|
78
|
+
skipped: number;
|
|
79
|
+
duration_ms: number;
|
|
80
|
+
};
|
|
81
|
+
private saveState;
|
|
82
|
+
private loadLastResult;
|
|
83
|
+
}
|