@timmeck/brain-core 2.36.28 → 2.36.29
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/command-center.html +43 -2
- package/dist/codegen/index.d.ts +2 -0
- package/dist/codegen/index.js +1 -0
- package/dist/codegen/index.js.map +1 -1
- package/dist/codegen/repo-absorber.d.ts +83 -0
- package/dist/codegen/repo-absorber.js +389 -0
- package/dist/codegen/repo-absorber.js.map +1 -0
- package/dist/dashboard/command-center-server.d.ts +2 -0
- package/dist/dashboard/command-center-server.js +19 -1
- package/dist/dashboard/command-center-server.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/research/research-orchestrator.d.ts +4 -0
- package/dist/research/research-orchestrator.js +52 -7
- package/dist/research/research-orchestrator.js.map +1 -1
- package/package.json +1 -1
package/command-center.html
CHANGED
|
@@ -536,6 +536,18 @@ canvas{display:block;width:100%;height:100%}
|
|
|
536
536
|
</div>
|
|
537
537
|
<div id="missionList" style="margin-top:12px"><div class="empty">Keine aktiven Missionen</div></div>
|
|
538
538
|
</div>
|
|
539
|
+
|
|
540
|
+
<!-- Repo Absorber -->
|
|
541
|
+
<div class="section">
|
|
542
|
+
<div class="section-title"><span class="icon">🧬</span> <span data-t="Code-Assimilierung">Code-Assimilierung</span></div>
|
|
543
|
+
<p style="font-size:12px;color:var(--text-dim);margin-bottom:12px" data-t="Brain klont Open-Source-Repos, extrahiert Patterns und Wissen, indexiert alles in RAG + Knowledge Graph, und löscht den Clone wieder.">Brain klont Open-Source-Repos, extrahiert Patterns und Wissen, indexiert alles in RAG + Knowledge Graph, und löscht den Clone wieder.</p>
|
|
544
|
+
<div class="grid grid-3" id="absorberStats">
|
|
545
|
+
<div class="card" style="text-align:center"><div class="card-value" id="ra-total" style="color:var(--cyan)">0</div><div class="card-sub" data-t="Repos assimiliert">Repos assimiliert</div></div>
|
|
546
|
+
<div class="card" style="text-align:center"><div class="card-value" id="ra-queue" style="color:var(--yellow)">0</div><div class="card-sub" data-t="In der Warteschlange">In der Warteschlange</div></div>
|
|
547
|
+
<div class="card" style="text-align:center"><div class="card-value" id="ra-last" style="color:var(--green);font-size:14px">—</div><div class="card-sub" data-t="Zuletzt assimiliert">Zuletzt assimiliert</div></div>
|
|
548
|
+
</div>
|
|
549
|
+
<div id="absorberHistory" style="margin-top:12px"><div class="empty" data-t="Noch keine Repos assimiliert">Noch keine Repos assimiliert</div></div>
|
|
550
|
+
</div>
|
|
539
551
|
</div>
|
|
540
552
|
|
|
541
553
|
<!-- ════ Page 7: Debates & Challenges ═════════════════ -->
|
|
@@ -644,6 +656,10 @@ const translations = { en: {
|
|
|
644
656
|
'Aktive Recherche-Missionen':'Active Research Missions',
|
|
645
657
|
'Brain forscht eigenständig zu Themen. Jede Mission durchläuft 5 Phasen: Aufteilen, Sammeln, Hypothesen bilden, Analysieren, Zusammenfassen.':'Brain researches topics autonomously. Each mission goes through 5 phases: decompose, gather, hypothesize, analyze, synthesize.',
|
|
646
658
|
'Aktive Missionen':'Active Missions','Abgeschlossen':'Completed','Quellen gesammelt':'Sources Gathered',
|
|
659
|
+
'Code-Assimilierung':'Code Assimilation',
|
|
660
|
+
'Brain klont Open-Source-Repos, extrahiert Patterns und Wissen, indexiert alles in RAG + Knowledge Graph, und löscht den Clone wieder.':'Brain clones open-source repos, extracts patterns and knowledge, indexes everything into RAG + Knowledge Graph, then deletes the clone.',
|
|
661
|
+
'Repos assimiliert':'Repos Assimilated','In der Warteschlange':'In Queue','Zuletzt assimiliert':'Last Assimilated',
|
|
662
|
+
'Noch keine Repos assimiliert':'No repos assimilated yet','Dateien':'Files',
|
|
647
663
|
'Multi-Perspektiven-Debatten zu Schlüsselfragen. Jeder Brain liefert seine Sichtweise basierend auf Prinzipien, Hypothesen und Vorhersagen.':'Multi-perspective debates on key questions. Each brain provides its viewpoint based on principles, hypotheses, and predictions.',
|
|
648
664
|
'Debatten gesamt':'Total Debates','Offen':'Open','Synthesiert':'Synthesized','Letzte Debatten':'Recent Debates',
|
|
649
665
|
'Advocatus Diaboli — Prinzip-Challenges':'Advocatus Diaboli — Principle Challenges',
|
|
@@ -748,6 +764,7 @@ function connectSSE() {
|
|
|
748
764
|
es.addEventListener('errors', e => { state.errors = JSON.parse(e.data); renderErrors(); });
|
|
749
765
|
es.addEventListener('selfmod', e => { state.selfmod = JSON.parse(e.data); renderSelfMod(); });
|
|
750
766
|
es.addEventListener('missions', e => { state.missions = JSON.parse(e.data); renderMissions(); });
|
|
767
|
+
es.addEventListener('repoAbsorber', e => { state.repoAbsorber = JSON.parse(e.data); renderRepoAbsorber(); });
|
|
751
768
|
es.addEventListener('knowledge', e => { state.knowledge = JSON.parse(e.data); renderKnowledge(); });
|
|
752
769
|
es.addEventListener('debates', e => { state.debates = JSON.parse(e.data); renderDebates(); });
|
|
753
770
|
es.onerror = () => { state.connected = false; updateConnection(); };
|
|
@@ -767,12 +784,12 @@ async function loadInitial() {
|
|
|
767
784
|
state.watchdog = data.watchdog || []; state.plugins = data.plugins || [];
|
|
768
785
|
state.borg = data.borg; state.analytics = data.analytics; state.llm = data.llm;
|
|
769
786
|
state.errors = data.errors; state.selfmod = data.selfmod;
|
|
770
|
-
state.missions = data.missions; state.knowledge = data.knowledge;
|
|
787
|
+
state.missions = data.missions; state.knowledge = data.knowledge; state.repoAbsorber = data.repoAbsorber;
|
|
771
788
|
state.debates = data.debates;
|
|
772
789
|
if (data.thoughts) { state.thoughts = data.thoughts; renderThoughts(); }
|
|
773
790
|
renderEcosystem(); renderEngines(); renderWatchdog(); renderPlugins();
|
|
774
791
|
renderBorg(); renderAnalytics(); renderLLM(); renderErrors();
|
|
775
|
-
renderSelfMod(); renderMissions(); renderKnowledge(); renderDebates();
|
|
792
|
+
renderSelfMod(); renderMissions(); renderRepoAbsorber(); renderKnowledge(); renderDebates();
|
|
776
793
|
} catch {}
|
|
777
794
|
}
|
|
778
795
|
|
|
@@ -955,6 +972,30 @@ function renderMissions() {
|
|
|
955
972
|
}).join('');
|
|
956
973
|
}
|
|
957
974
|
|
|
975
|
+
// ── Repo Absorber ────────────────────────────────────────
|
|
976
|
+
function renderRepoAbsorber() {
|
|
977
|
+
const d = state.repoAbsorber;
|
|
978
|
+
if (!d || !d.status) {
|
|
979
|
+
setText('ra-total', 0); setText('ra-queue', 0); setText('ra-last', '—');
|
|
980
|
+
document.getElementById('absorberHistory').innerHTML = `<div class="empty">${t('Noch keine Repos assimiliert')}</div>`;
|
|
981
|
+
return;
|
|
982
|
+
}
|
|
983
|
+
setText('ra-total', d.status.totalAbsorbed || 0);
|
|
984
|
+
setText('ra-queue', d.status.queueSize || 0);
|
|
985
|
+
setText('ra-last', d.status.lastAbsorbed || '—');
|
|
986
|
+
|
|
987
|
+
const list = d.history || [];
|
|
988
|
+
const el = document.getElementById('absorberHistory');
|
|
989
|
+
if (!list.length) { el.innerHTML = `<div class="empty">${t('Noch keine Repos assimiliert')}</div>`; return; }
|
|
990
|
+
el.innerHTML = list.map(r => `<div class="card" style="padding:8px 12px;margin-bottom:6px;display:flex;justify-content:space-between;align-items:center">
|
|
991
|
+
<div>
|
|
992
|
+
<div style="font-weight:600;color:var(--cyan)">${escHtml(r.name)}</div>
|
|
993
|
+
<div style="font-size:11px;color:var(--text-dim)">${r.filesScanned} ${t('Dateien')} · ${r.ragVectors} RAG · ${r.factsExtracted} Facts · ${(r.durationMs/1000).toFixed(1)}s</div>
|
|
994
|
+
</div>
|
|
995
|
+
<div style="font-size:11px;color:var(--text-dim)">${r.absorbedAt ? new Date(r.absorbedAt).toLocaleString(getLocale(), {day:'2-digit',month:'2-digit',hour:'2-digit',minute:'2-digit'}) : ''}</div>
|
|
996
|
+
</div>`).join('');
|
|
997
|
+
}
|
|
998
|
+
|
|
958
999
|
// ── Knowledge Growth ──────────────────────────────────────
|
|
959
1000
|
function renderKnowledge() {
|
|
960
1001
|
const d = state.knowledge;
|
package/dist/codegen/index.d.ts
CHANGED
|
@@ -5,4 +5,6 @@ export { CodeGenerator, runCodeGeneratorMigration } from './code-generator.js';
|
|
|
5
5
|
export type { SelfImprovementProposal } from './code-generator.js';
|
|
6
6
|
export { CodegenServer } from './codegen-server.js';
|
|
7
7
|
export type { CodegenServerOptions } from './codegen-server.js';
|
|
8
|
+
export { RepoAbsorber } from './repo-absorber.js';
|
|
9
|
+
export type { AbsorbResult, RepoAbsorberStatus } from './repo-absorber.js';
|
|
8
10
|
export type { CodeMinerConfig, RepoContent, CodeMinerSummary, ExtractedPattern, DependencyPattern, TechStack, ProjectStructure, ReadmePattern, ContextBuilderConfig, BuiltContext, CodeGeneratorConfig, GenerationTrigger, GenerationStatus, GenerationRequest, GenerationResult, GenerationRecord, CodeGeneratorSummary, } from './types.js';
|
package/dist/codegen/index.js
CHANGED
|
@@ -3,4 +3,5 @@ export { PatternExtractor, runPatternExtractorMigration } from './pattern-extrac
|
|
|
3
3
|
export { ContextBuilder } from './context-builder.js';
|
|
4
4
|
export { CodeGenerator, runCodeGeneratorMigration } from './code-generator.js';
|
|
5
5
|
export { CodegenServer } from './codegen-server.js';
|
|
6
|
+
export { RepoAbsorber } from './repo-absorber.js';
|
|
6
7
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/codegen/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AACnE,OAAO,EAAE,gBAAgB,EAAE,4BAA4B,EAAE,MAAM,wBAAwB,CAAC;AACxF,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,yBAAyB,EAAE,MAAM,qBAAqB,CAAC;AAE/E,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/codegen/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AACnE,OAAO,EAAE,gBAAgB,EAAE,4BAA4B,EAAE,MAAM,wBAAwB,CAAC;AACxF,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,yBAAyB,EAAE,MAAM,qBAAqB,CAAC;AAE/E,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEpD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import type Database from 'better-sqlite3';
|
|
2
|
+
import type { ThoughtStream } from '../consciousness/thought-stream.js';
|
|
3
|
+
import type { RAGEngine } from '../rag/rag-engine.js';
|
|
4
|
+
import type { KnowledgeGraphEngine } from '../knowledge-graph/graph-engine.js';
|
|
5
|
+
export interface AbsorbResult {
|
|
6
|
+
repo: string;
|
|
7
|
+
filesScanned: number;
|
|
8
|
+
patternsFound: number;
|
|
9
|
+
factsExtracted: number;
|
|
10
|
+
ragVectorsAdded: number;
|
|
11
|
+
durationMs: number;
|
|
12
|
+
}
|
|
13
|
+
export interface RepoAbsorberStatus {
|
|
14
|
+
totalAbsorbed: number;
|
|
15
|
+
lastAbsorbed: string | null;
|
|
16
|
+
queueSize: number;
|
|
17
|
+
}
|
|
18
|
+
interface RepoCandidate {
|
|
19
|
+
name: string;
|
|
20
|
+
url: string;
|
|
21
|
+
source: string;
|
|
22
|
+
relevance: number;
|
|
23
|
+
}
|
|
24
|
+
export declare class RepoAbsorber {
|
|
25
|
+
private readonly db;
|
|
26
|
+
private readonly log;
|
|
27
|
+
private thoughtStream;
|
|
28
|
+
private ragEngine;
|
|
29
|
+
private knowledgeGraph;
|
|
30
|
+
private totalAbsorbed;
|
|
31
|
+
private lastAbsorbed;
|
|
32
|
+
constructor(db: Database.Database);
|
|
33
|
+
setThoughtStream(ts: ThoughtStream): void;
|
|
34
|
+
setRAGEngine(rag: RAGEngine): void;
|
|
35
|
+
setKnowledgeGraph(kg: KnowledgeGraphEngine): void;
|
|
36
|
+
private ensureTable;
|
|
37
|
+
/**
|
|
38
|
+
* Pick the next repo to absorb from TechRadar + DataScout discoveries.
|
|
39
|
+
* Skips repos already absorbed.
|
|
40
|
+
*/
|
|
41
|
+
getNextCandidate(): RepoCandidate | null;
|
|
42
|
+
/**
|
|
43
|
+
* Absorb one repo: clone → scan → index → delete.
|
|
44
|
+
* Returns null if no candidate available.
|
|
45
|
+
*/
|
|
46
|
+
absorbNext(): Promise<AbsorbResult | null>;
|
|
47
|
+
/**
|
|
48
|
+
* Recursively scan for code files, respecting limits.
|
|
49
|
+
*/
|
|
50
|
+
private scanFiles;
|
|
51
|
+
/**
|
|
52
|
+
* Extract structured patterns from a code file for the Knowledge Graph.
|
|
53
|
+
*/
|
|
54
|
+
private extractCodePatterns;
|
|
55
|
+
/**
|
|
56
|
+
* Count interesting patterns in a file (for stats).
|
|
57
|
+
*/
|
|
58
|
+
private countPatterns;
|
|
59
|
+
/**
|
|
60
|
+
* Detect test framework from package.json.
|
|
61
|
+
*/
|
|
62
|
+
private detectTestFramework;
|
|
63
|
+
/**
|
|
64
|
+
* Normalize various GitHub URL formats to a clonable URL.
|
|
65
|
+
*/
|
|
66
|
+
private normalizeGitUrl;
|
|
67
|
+
getStatus(): RepoAbsorberStatus;
|
|
68
|
+
/**
|
|
69
|
+
* Get recently absorbed repos from DB.
|
|
70
|
+
*/
|
|
71
|
+
getHistory(limit?: number): Array<{
|
|
72
|
+
name: string;
|
|
73
|
+
url: string;
|
|
74
|
+
source: string;
|
|
75
|
+
filesScanned: number;
|
|
76
|
+
patternsFound: number;
|
|
77
|
+
factsExtracted: number;
|
|
78
|
+
ragVectors: number;
|
|
79
|
+
durationMs: number;
|
|
80
|
+
absorbedAt: string;
|
|
81
|
+
}>;
|
|
82
|
+
}
|
|
83
|
+
export {};
|
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
import { execSync } from 'node:child_process';
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import os from 'node:os';
|
|
5
|
+
import { getLogger } from '../utils/logger.js';
|
|
6
|
+
// ── File patterns to scan ─────────────────────────────────
|
|
7
|
+
const CODE_EXTENSIONS = new Set([
|
|
8
|
+
'.ts', '.js', '.py', '.go', '.rs', '.java', '.c', '.cpp', '.h',
|
|
9
|
+
'.tsx', '.jsx', '.vue', '.svelte', '.rb', '.php', '.cs', '.swift', '.kt',
|
|
10
|
+
]);
|
|
11
|
+
const CONFIG_FILES = new Set([
|
|
12
|
+
'package.json', 'tsconfig.json', 'Cargo.toml', 'go.mod', 'pyproject.toml',
|
|
13
|
+
'setup.py', 'requirements.txt', 'Gemfile', 'pom.xml', 'build.gradle',
|
|
14
|
+
'Dockerfile', 'docker-compose.yml', '.github/workflows/ci.yml',
|
|
15
|
+
]);
|
|
16
|
+
const SKIP_DIRS = new Set([
|
|
17
|
+
'node_modules', '.git', 'dist', 'build', 'target', '__pycache__',
|
|
18
|
+
'.next', '.nuxt', 'vendor', 'venv', '.venv', 'coverage',
|
|
19
|
+
]);
|
|
20
|
+
const MAX_FILE_SIZE = 50_000; // 50KB per file
|
|
21
|
+
const MAX_FILES_PER_REPO = 100;
|
|
22
|
+
const MAX_TOTAL_BYTES = 2_000_000; // 2MB total text
|
|
23
|
+
// ── RepoAbsorber ──────────────────────────────────────────
|
|
24
|
+
export class RepoAbsorber {
|
|
25
|
+
db;
|
|
26
|
+
log = getLogger();
|
|
27
|
+
thoughtStream = null;
|
|
28
|
+
ragEngine = null;
|
|
29
|
+
knowledgeGraph = null;
|
|
30
|
+
totalAbsorbed = 0;
|
|
31
|
+
lastAbsorbed = null;
|
|
32
|
+
constructor(db) {
|
|
33
|
+
this.db = db;
|
|
34
|
+
this.ensureTable();
|
|
35
|
+
}
|
|
36
|
+
setThoughtStream(ts) { this.thoughtStream = ts; }
|
|
37
|
+
setRAGEngine(rag) { this.ragEngine = rag; }
|
|
38
|
+
setKnowledgeGraph(kg) { this.knowledgeGraph = kg; }
|
|
39
|
+
ensureTable() {
|
|
40
|
+
this.db.exec(`
|
|
41
|
+
CREATE TABLE IF NOT EXISTS absorbed_repos (
|
|
42
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
43
|
+
name TEXT UNIQUE NOT NULL,
|
|
44
|
+
url TEXT NOT NULL DEFAULT '',
|
|
45
|
+
source TEXT NOT NULL DEFAULT '',
|
|
46
|
+
files_scanned INTEGER DEFAULT 0,
|
|
47
|
+
patterns_found INTEGER DEFAULT 0,
|
|
48
|
+
facts_extracted INTEGER DEFAULT 0,
|
|
49
|
+
rag_vectors INTEGER DEFAULT 0,
|
|
50
|
+
duration_ms INTEGER DEFAULT 0,
|
|
51
|
+
absorbed_at TEXT DEFAULT (datetime('now'))
|
|
52
|
+
);
|
|
53
|
+
CREATE INDEX IF NOT EXISTS idx_absorbed_name ON absorbed_repos(name);
|
|
54
|
+
`);
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Pick the next repo to absorb from TechRadar + DataScout discoveries.
|
|
58
|
+
* Skips repos already absorbed.
|
|
59
|
+
*/
|
|
60
|
+
getNextCandidate() {
|
|
61
|
+
// 1. Try TechRadar watched repos
|
|
62
|
+
try {
|
|
63
|
+
const watched = this.db.prepare(`
|
|
64
|
+
SELECT full_name, url FROM techradar_watched_repos
|
|
65
|
+
WHERE is_active = 1
|
|
66
|
+
AND full_name NOT IN (SELECT name FROM absorbed_repos)
|
|
67
|
+
ORDER BY RANDOM() LIMIT 1
|
|
68
|
+
`).get();
|
|
69
|
+
if (watched) {
|
|
70
|
+
return {
|
|
71
|
+
name: watched.full_name,
|
|
72
|
+
url: watched.url || `https://github.com/${watched.full_name}`,
|
|
73
|
+
source: 'techradar_watched',
|
|
74
|
+
relevance: 1.0,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
catch { /* table may not exist */ }
|
|
79
|
+
// 2. Try TechRadar entries (high relevance first)
|
|
80
|
+
try {
|
|
81
|
+
const entry = this.db.prepare(`
|
|
82
|
+
SELECT name, source_url FROM techradar_entries
|
|
83
|
+
WHERE source IN ('github_trending', 'github_release')
|
|
84
|
+
AND source_url LIKE '%github.com%'
|
|
85
|
+
AND name NOT IN (SELECT name FROM absorbed_repos)
|
|
86
|
+
ORDER BY relevance_score DESC LIMIT 1
|
|
87
|
+
`).get();
|
|
88
|
+
if (entry) {
|
|
89
|
+
return {
|
|
90
|
+
name: entry.name,
|
|
91
|
+
url: entry.source_url,
|
|
92
|
+
source: 'techradar_entry',
|
|
93
|
+
relevance: 0.8,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
catch { /* table may not exist */ }
|
|
98
|
+
// 3. Try DataScout discoveries (GitHub sources)
|
|
99
|
+
try {
|
|
100
|
+
const discovery = this.db.prepare(`
|
|
101
|
+
SELECT title, url FROM scout_discoveries
|
|
102
|
+
WHERE source = 'github-trending'
|
|
103
|
+
AND url LIKE '%github.com%'
|
|
104
|
+
AND title NOT IN (SELECT name FROM absorbed_repos)
|
|
105
|
+
ORDER BY relevance_score DESC LIMIT 1
|
|
106
|
+
`).get();
|
|
107
|
+
if (discovery) {
|
|
108
|
+
return {
|
|
109
|
+
name: discovery.title,
|
|
110
|
+
url: discovery.url,
|
|
111
|
+
source: 'datascout',
|
|
112
|
+
relevance: 0.6,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
catch { /* table may not exist */ }
|
|
117
|
+
return null;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Absorb one repo: clone → scan → index → delete.
|
|
121
|
+
* Returns null if no candidate available.
|
|
122
|
+
*/
|
|
123
|
+
async absorbNext() {
|
|
124
|
+
const candidate = this.getNextCandidate();
|
|
125
|
+
if (!candidate)
|
|
126
|
+
return null;
|
|
127
|
+
const start = Date.now();
|
|
128
|
+
this.thoughtStream?.emit('repo_absorber', 'perceiving', `Absorbing repo: ${candidate.name}...`, 'notable');
|
|
129
|
+
const tmpDir = path.join(os.tmpdir(), `brain-absorb-${Date.now()}`);
|
|
130
|
+
let result = {
|
|
131
|
+
repo: candidate.name,
|
|
132
|
+
filesScanned: 0,
|
|
133
|
+
patternsFound: 0,
|
|
134
|
+
factsExtracted: 0,
|
|
135
|
+
ragVectorsAdded: 0,
|
|
136
|
+
durationMs: 0,
|
|
137
|
+
};
|
|
138
|
+
try {
|
|
139
|
+
// 1. Clone (shallow, no history)
|
|
140
|
+
const cloneUrl = this.normalizeGitUrl(candidate.url);
|
|
141
|
+
this.log.info(`[RepoAbsorber] Cloning ${cloneUrl} → ${tmpDir}`);
|
|
142
|
+
execSync(`git clone --depth 1 --single-branch "${cloneUrl}" "${tmpDir}"`, {
|
|
143
|
+
timeout: 60_000,
|
|
144
|
+
stdio: 'pipe',
|
|
145
|
+
});
|
|
146
|
+
// 2. Scan code files
|
|
147
|
+
const files = this.scanFiles(tmpDir);
|
|
148
|
+
result.filesScanned = files.length;
|
|
149
|
+
this.log.info(`[RepoAbsorber] Scanned ${files.length} files from ${candidate.name}`);
|
|
150
|
+
// 3. Extract patterns & index into RAG
|
|
151
|
+
let totalBytes = 0;
|
|
152
|
+
for (const file of files) {
|
|
153
|
+
if (totalBytes > MAX_TOTAL_BYTES)
|
|
154
|
+
break;
|
|
155
|
+
try {
|
|
156
|
+
const content = fs.readFileSync(file.fullPath, 'utf8');
|
|
157
|
+
if (content.length > MAX_FILE_SIZE)
|
|
158
|
+
continue;
|
|
159
|
+
totalBytes += content.length;
|
|
160
|
+
// Index into RAG
|
|
161
|
+
if (this.ragEngine) {
|
|
162
|
+
try {
|
|
163
|
+
// sourceId: use a hash of the file path as numeric ID
|
|
164
|
+
const sourceId = Math.abs(file.relativePath.split('').reduce((a, c) => ((a << 5) - a + c.charCodeAt(0)) | 0, 0));
|
|
165
|
+
await this.ragEngine.index('absorbed_code', sourceId, content, {
|
|
166
|
+
repo: candidate.name, ext: file.ext, source: candidate.source, path: file.relativePath,
|
|
167
|
+
});
|
|
168
|
+
result.ragVectorsAdded++;
|
|
169
|
+
}
|
|
170
|
+
catch { /* embedding may fail */ }
|
|
171
|
+
}
|
|
172
|
+
// Extract patterns for Knowledge Graph
|
|
173
|
+
if (this.knowledgeGraph) {
|
|
174
|
+
const patterns = this.extractCodePatterns(content, file.relativePath, candidate.name);
|
|
175
|
+
for (const p of patterns) {
|
|
176
|
+
this.knowledgeGraph.addFact(p.subject, p.predicate, p.object, p.context, p.confidence, 'repo', candidate.name);
|
|
177
|
+
result.factsExtracted++;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
result.patternsFound += this.countPatterns(content, file.ext);
|
|
181
|
+
}
|
|
182
|
+
catch { /* read error, skip */ }
|
|
183
|
+
}
|
|
184
|
+
// 4. Extract project-level patterns
|
|
185
|
+
const pkgJsonPath = path.join(tmpDir, 'package.json');
|
|
186
|
+
if (fs.existsSync(pkgJsonPath)) {
|
|
187
|
+
try {
|
|
188
|
+
const pkg = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf8'));
|
|
189
|
+
if (this.knowledgeGraph && pkg.name) {
|
|
190
|
+
const deps = Object.keys(pkg.dependencies ?? {});
|
|
191
|
+
const devDeps = Object.keys(pkg.devDependencies ?? {});
|
|
192
|
+
for (const dep of deps.slice(0, 10)) {
|
|
193
|
+
this.knowledgeGraph.addFact(pkg.name, 'depends_on', dep, `repo:${candidate.name}`, 0.9, 'repo', candidate.name);
|
|
194
|
+
result.factsExtracted++;
|
|
195
|
+
}
|
|
196
|
+
if (pkg.scripts?.test) {
|
|
197
|
+
this.knowledgeGraph.addFact(candidate.name, 'uses_test_framework', this.detectTestFramework(pkg), `repo:${candidate.name}`, 0.8, 'repo', candidate.name);
|
|
198
|
+
result.factsExtracted++;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
catch { /* invalid json */ }
|
|
203
|
+
}
|
|
204
|
+
this.thoughtStream?.emit('repo_absorber', 'discovering', `Absorbed ${candidate.name}: ${result.filesScanned} files, ${result.ragVectorsAdded} vectors, ${result.factsExtracted} facts`, 'notable');
|
|
205
|
+
}
|
|
206
|
+
catch (err) {
|
|
207
|
+
this.log.warn(`[RepoAbsorber] Failed to absorb ${candidate.name}: ${err.message}`);
|
|
208
|
+
this.thoughtStream?.emit('repo_absorber', 'analyzing', `Failed to absorb ${candidate.name}: ${err.message}`, 'routine');
|
|
209
|
+
}
|
|
210
|
+
finally {
|
|
211
|
+
// 5. Always clean up
|
|
212
|
+
try {
|
|
213
|
+
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
214
|
+
this.log.debug(`[RepoAbsorber] Cleaned up ${tmpDir}`);
|
|
215
|
+
}
|
|
216
|
+
catch { /* cleanup failed, not critical */ }
|
|
217
|
+
}
|
|
218
|
+
result.durationMs = Date.now() - start;
|
|
219
|
+
// Record in DB
|
|
220
|
+
try {
|
|
221
|
+
this.db.prepare(`
|
|
222
|
+
INSERT OR REPLACE INTO absorbed_repos (name, url, source, files_scanned, patterns_found, facts_extracted, rag_vectors, duration_ms)
|
|
223
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
224
|
+
`).run(candidate.name, candidate.url, candidate.source, result.filesScanned, result.patternsFound, result.factsExtracted, result.ragVectorsAdded, result.durationMs);
|
|
225
|
+
}
|
|
226
|
+
catch { /* DB error */ }
|
|
227
|
+
this.totalAbsorbed++;
|
|
228
|
+
this.lastAbsorbed = candidate.name;
|
|
229
|
+
return result;
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Recursively scan for code files, respecting limits.
|
|
233
|
+
*/
|
|
234
|
+
scanFiles(dir, base) {
|
|
235
|
+
const root = base ?? dir;
|
|
236
|
+
const results = [];
|
|
237
|
+
try {
|
|
238
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
239
|
+
for (const entry of entries) {
|
|
240
|
+
if (results.length >= MAX_FILES_PER_REPO)
|
|
241
|
+
break;
|
|
242
|
+
if (entry.isDirectory()) {
|
|
243
|
+
if (SKIP_DIRS.has(entry.name))
|
|
244
|
+
continue;
|
|
245
|
+
results.push(...this.scanFiles(path.join(dir, entry.name), root));
|
|
246
|
+
}
|
|
247
|
+
else if (entry.isFile()) {
|
|
248
|
+
const ext = path.extname(entry.name).toLowerCase();
|
|
249
|
+
const relativePath = path.relative(root, path.join(dir, entry.name)).replace(/\\/g, '/');
|
|
250
|
+
if (CODE_EXTENSIONS.has(ext) || CONFIG_FILES.has(entry.name)) {
|
|
251
|
+
results.push({ fullPath: path.join(dir, entry.name), relativePath, ext });
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
catch { /* permission error */ }
|
|
257
|
+
return results;
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Extract structured patterns from a code file for the Knowledge Graph.
|
|
261
|
+
*/
|
|
262
|
+
extractCodePatterns(content, filePath, repo) {
|
|
263
|
+
const facts = [];
|
|
264
|
+
// Detect imports/dependencies
|
|
265
|
+
const importMatches = content.matchAll(/(?:import|require)\s*\(?['"]([^'"]+)['"]\)?/g);
|
|
266
|
+
const seenImports = new Set();
|
|
267
|
+
for (const m of importMatches) {
|
|
268
|
+
const dep = m[1];
|
|
269
|
+
if (dep.startsWith('.') || dep.startsWith('/'))
|
|
270
|
+
continue; // skip relative
|
|
271
|
+
const pkg = dep.startsWith('@') ? dep.split('/').slice(0, 2).join('/') : dep.split('/')[0];
|
|
272
|
+
if (!seenImports.has(pkg)) {
|
|
273
|
+
seenImports.add(pkg);
|
|
274
|
+
facts.push({
|
|
275
|
+
subject: filePath, predicate: 'imports', object: pkg,
|
|
276
|
+
context: `repo:${repo}`, confidence: 0.9,
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
// Detect design patterns
|
|
281
|
+
if (/class\s+\w+\s+extends/.test(content)) {
|
|
282
|
+
facts.push({ subject: repo, predicate: 'uses_pattern', object: 'inheritance', context: filePath, confidence: 0.7 });
|
|
283
|
+
}
|
|
284
|
+
if (/implements\s+\w+/.test(content)) {
|
|
285
|
+
facts.push({ subject: repo, predicate: 'uses_pattern', object: 'interface_impl', context: filePath, confidence: 0.7 });
|
|
286
|
+
}
|
|
287
|
+
if (/(?:export\s+)?(?:async\s+)?function\s+\w+Factory/i.test(content)) {
|
|
288
|
+
facts.push({ subject: repo, predicate: 'uses_pattern', object: 'factory', context: filePath, confidence: 0.8 });
|
|
289
|
+
}
|
|
290
|
+
if (/\.subscribe\(|\.on\(|EventEmitter|addEventListener/i.test(content)) {
|
|
291
|
+
facts.push({ subject: repo, predicate: 'uses_pattern', object: 'observer', context: filePath, confidence: 0.6 });
|
|
292
|
+
}
|
|
293
|
+
if (/Singleton|getInstance/i.test(content)) {
|
|
294
|
+
facts.push({ subject: repo, predicate: 'uses_pattern', object: 'singleton', context: filePath, confidence: 0.8 });
|
|
295
|
+
}
|
|
296
|
+
return facts;
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* Count interesting patterns in a file (for stats).
|
|
300
|
+
*/
|
|
301
|
+
countPatterns(content, ext) {
|
|
302
|
+
let count = 0;
|
|
303
|
+
if (/export\s+(class|function|const|interface)/.test(content))
|
|
304
|
+
count++;
|
|
305
|
+
if (/async\s+function|await\s/.test(content))
|
|
306
|
+
count++;
|
|
307
|
+
if (/(?:try|catch|throw)\s/.test(content))
|
|
308
|
+
count++;
|
|
309
|
+
if (ext === '.ts' && /interface\s+\w+/.test(content))
|
|
310
|
+
count++;
|
|
311
|
+
return count;
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* Detect test framework from package.json.
|
|
315
|
+
*/
|
|
316
|
+
detectTestFramework(pkg) {
|
|
317
|
+
const all = { ...(pkg.dependencies ?? {}), ...(pkg.devDependencies ?? {}) };
|
|
318
|
+
if ('vitest' in all)
|
|
319
|
+
return 'vitest';
|
|
320
|
+
if ('jest' in all)
|
|
321
|
+
return 'jest';
|
|
322
|
+
if ('mocha' in all)
|
|
323
|
+
return 'mocha';
|
|
324
|
+
if ('ava' in all)
|
|
325
|
+
return 'ava';
|
|
326
|
+
if ('pytest' in all)
|
|
327
|
+
return 'pytest';
|
|
328
|
+
return 'unknown';
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* Normalize various GitHub URL formats to a clonable URL.
|
|
332
|
+
*/
|
|
333
|
+
normalizeGitUrl(url) {
|
|
334
|
+
// Already a .git URL
|
|
335
|
+
if (url.endsWith('.git'))
|
|
336
|
+
return url;
|
|
337
|
+
// GitHub URL like https://github.com/owner/repo
|
|
338
|
+
const match = url.match(/github\.com\/([^/]+\/[^/]+)/);
|
|
339
|
+
if (match)
|
|
340
|
+
return `https://github.com/${match[1]}.git`;
|
|
341
|
+
// Fallback: assume it's a GitHub "owner/repo" string
|
|
342
|
+
if (url.includes('/') && !url.includes('://'))
|
|
343
|
+
return `https://github.com/${url}.git`;
|
|
344
|
+
return url;
|
|
345
|
+
}
|
|
346
|
+
getStatus() {
|
|
347
|
+
let queueSize = 0;
|
|
348
|
+
try {
|
|
349
|
+
const count = this.db.prepare(`
|
|
350
|
+
SELECT COUNT(*) as c FROM techradar_watched_repos
|
|
351
|
+
WHERE is_active = 1 AND full_name NOT IN (SELECT name FROM absorbed_repos)
|
|
352
|
+
`).get();
|
|
353
|
+
queueSize += count?.c ?? 0;
|
|
354
|
+
}
|
|
355
|
+
catch { /* table may not exist */ }
|
|
356
|
+
try {
|
|
357
|
+
const count = this.db.prepare(`
|
|
358
|
+
SELECT COUNT(*) as c FROM techradar_entries
|
|
359
|
+
WHERE source IN ('github_trending', 'github_release')
|
|
360
|
+
AND source_url LIKE '%github.com%'
|
|
361
|
+
AND name NOT IN (SELECT name FROM absorbed_repos)
|
|
362
|
+
`).get();
|
|
363
|
+
queueSize += count?.c ?? 0;
|
|
364
|
+
}
|
|
365
|
+
catch { /* table may not exist */ }
|
|
366
|
+
return {
|
|
367
|
+
totalAbsorbed: this.totalAbsorbed,
|
|
368
|
+
lastAbsorbed: this.lastAbsorbed,
|
|
369
|
+
queueSize,
|
|
370
|
+
};
|
|
371
|
+
}
|
|
372
|
+
/**
|
|
373
|
+
* Get recently absorbed repos from DB.
|
|
374
|
+
*/
|
|
375
|
+
getHistory(limit = 10) {
|
|
376
|
+
try {
|
|
377
|
+
return this.db.prepare(`
|
|
378
|
+
SELECT name, url, source, files_scanned as filesScanned, patterns_found as patternsFound,
|
|
379
|
+
facts_extracted as factsExtracted, rag_vectors as ragVectors, duration_ms as durationMs,
|
|
380
|
+
absorbed_at as absorbedAt
|
|
381
|
+
FROM absorbed_repos ORDER BY absorbed_at DESC LIMIT ?
|
|
382
|
+
`).all(limit);
|
|
383
|
+
}
|
|
384
|
+
catch {
|
|
385
|
+
return [];
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
//# sourceMappingURL=repo-absorber.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repo-absorber.js","sourceRoot":"","sources":["../../src/codegen/repo-absorber.ts"],"names":[],"mappings":"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"}
|
|
@@ -30,6 +30,8 @@ export interface CommandCenterOptions {
|
|
|
30
30
|
getDebateList?: (limit?: number) => unknown;
|
|
31
31
|
getChallengeHistory?: (limit?: number) => unknown;
|
|
32
32
|
getChallengeVulnerable?: (limit?: number) => unknown;
|
|
33
|
+
getRepoAbsorberStatus?: () => unknown;
|
|
34
|
+
getRepoAbsorberHistory?: (limit?: number) => unknown;
|
|
33
35
|
triggerAction?: (action: string, params?: unknown) => Promise<unknown>;
|
|
34
36
|
}
|
|
35
37
|
export declare class CommandCenterServer {
|
|
@@ -255,6 +255,20 @@ export class CommandCenterServer {
|
|
|
255
255
|
}
|
|
256
256
|
catch { /* ignore */ }
|
|
257
257
|
}, 30_000));
|
|
258
|
+
// Repo Absorber (30s)
|
|
259
|
+
this.timers.push(setInterval(() => {
|
|
260
|
+
if (this.clients.size === 0)
|
|
261
|
+
return;
|
|
262
|
+
if (!this.options.getRepoAbsorberStatus)
|
|
263
|
+
return;
|
|
264
|
+
try {
|
|
265
|
+
this.broadcast('repoAbsorber', {
|
|
266
|
+
status: this.options.getRepoAbsorberStatus(),
|
|
267
|
+
history: this.options.getRepoAbsorberHistory?.(10) ?? [],
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
catch { /* ignore */ }
|
|
271
|
+
}, 30_000));
|
|
258
272
|
// Heartbeat (30s)
|
|
259
273
|
this.timers.push(setInterval(() => {
|
|
260
274
|
if (this.clients.size > 0) {
|
|
@@ -347,7 +361,11 @@ export class CommandCenterServer {
|
|
|
347
361
|
challenges: this.options.getChallengeHistory?.(10) ?? [],
|
|
348
362
|
vulnerable: this.options.getChallengeVulnerable?.(5) ?? [],
|
|
349
363
|
} : null;
|
|
350
|
-
|
|
364
|
+
const repoAbsorber = this.options.getRepoAbsorberStatus ? {
|
|
365
|
+
status: this.options.getRepoAbsorberStatus(),
|
|
366
|
+
history: this.options.getRepoAbsorberHistory?.(10) ?? [],
|
|
367
|
+
} : null;
|
|
368
|
+
this.json(res, { ecosystem, engines: engineResults, watchdog, plugins, borg, analytics, llm, thoughts, errors, selfmod, missions, knowledge, debates, repoAbsorber });
|
|
351
369
|
}
|
|
352
370
|
catch (err) {
|
|
353
371
|
this.json(res, { error: err.message }, 500);
|