@timmeck/brain-core 2.36.12 → 2.36.14

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.
Files changed (125) hide show
  1. package/dist/cross-brain/__tests__/borg-sync-engine.test.d.ts +1 -0
  2. package/dist/cross-brain/__tests__/borg-sync-engine.test.js +240 -0
  3. package/dist/cross-brain/__tests__/borg-sync-engine.test.js.map +1 -0
  4. package/dist/cross-brain/borg-sync-engine.d.ts +62 -0
  5. package/dist/cross-brain/borg-sync-engine.js +215 -0
  6. package/dist/cross-brain/borg-sync-engine.js.map +1 -0
  7. package/dist/cross-brain/borg-types.d.ts +37 -0
  8. package/dist/cross-brain/borg-types.js +9 -0
  9. package/dist/cross-brain/borg-types.js.map +1 -0
  10. package/dist/embeddings/engine.js +2 -1
  11. package/dist/embeddings/engine.js.map +1 -1
  12. package/dist/index.d.ts +18 -1
  13. package/dist/index.js +14 -0
  14. package/dist/index.js.map +1 -1
  15. package/dist/llm/__tests__/anthropic-provider.test.d.ts +1 -0
  16. package/dist/llm/__tests__/anthropic-provider.test.js +121 -0
  17. package/dist/llm/__tests__/anthropic-provider.test.js.map +1 -0
  18. package/dist/llm/__tests__/llm-service.test.js +181 -40
  19. package/dist/llm/__tests__/llm-service.test.js.map +1 -1
  20. package/dist/llm/__tests__/ollama-embedding.test.d.ts +1 -0
  21. package/dist/llm/__tests__/ollama-embedding.test.js +128 -0
  22. package/dist/llm/__tests__/ollama-embedding.test.js.map +1 -0
  23. package/dist/llm/__tests__/ollama-provider.test.d.ts +1 -0
  24. package/dist/llm/__tests__/ollama-provider.test.js +213 -0
  25. package/dist/llm/__tests__/ollama-provider.test.js.map +1 -0
  26. package/dist/llm/__tests__/provider.test.d.ts +1 -0
  27. package/dist/llm/__tests__/provider.test.js +126 -0
  28. package/dist/llm/__tests__/provider.test.js.map +1 -0
  29. package/dist/llm/anthropic-provider.d.ts +41 -0
  30. package/dist/llm/anthropic-provider.js +86 -0
  31. package/dist/llm/anthropic-provider.js.map +1 -0
  32. package/dist/llm/index.d.ts +9 -1
  33. package/dist/llm/index.js +4 -0
  34. package/dist/llm/index.js.map +1 -1
  35. package/dist/llm/llm-service.d.ts +55 -7
  36. package/dist/llm/llm-service.js +184 -82
  37. package/dist/llm/llm-service.js.map +1 -1
  38. package/dist/llm/ollama-embedding.d.ts +46 -0
  39. package/dist/llm/ollama-embedding.js +93 -0
  40. package/dist/llm/ollama-embedding.js.map +1 -0
  41. package/dist/llm/ollama-provider.d.ts +80 -0
  42. package/dist/llm/ollama-provider.js +178 -0
  43. package/dist/llm/ollama-provider.js.map +1 -0
  44. package/dist/llm/provider.d.ts +120 -0
  45. package/dist/llm/provider.js +104 -0
  46. package/dist/llm/provider.js.map +1 -0
  47. package/dist/missions/mission-engine.d.ts +4 -0
  48. package/dist/missions/mission-engine.js +30 -8
  49. package/dist/missions/mission-engine.js.map +1 -1
  50. package/dist/notifications/__tests__/notification-service.test.d.ts +1 -0
  51. package/dist/notifications/__tests__/notification-service.test.js +176 -0
  52. package/dist/notifications/__tests__/notification-service.test.js.map +1 -0
  53. package/dist/notifications/discord-provider.d.ts +30 -0
  54. package/dist/notifications/discord-provider.js +89 -0
  55. package/dist/notifications/discord-provider.js.map +1 -0
  56. package/dist/notifications/email-provider.d.ts +41 -0
  57. package/dist/notifications/email-provider.js +101 -0
  58. package/dist/notifications/email-provider.js.map +1 -0
  59. package/dist/notifications/index.d.ts +8 -0
  60. package/dist/notifications/index.js +5 -0
  61. package/dist/notifications/index.js.map +1 -0
  62. package/dist/notifications/notification-provider.d.ts +75 -0
  63. package/dist/notifications/notification-provider.js +47 -0
  64. package/dist/notifications/notification-provider.js.map +1 -0
  65. package/dist/notifications/notification-service.d.ts +85 -0
  66. package/dist/notifications/notification-service.js +184 -0
  67. package/dist/notifications/notification-service.js.map +1 -0
  68. package/dist/notifications/telegram-provider.d.ts +30 -0
  69. package/dist/notifications/telegram-provider.js +78 -0
  70. package/dist/notifications/telegram-provider.js.map +1 -0
  71. package/dist/plugin/__tests__/plugin-registry.test.d.ts +1 -0
  72. package/dist/plugin/__tests__/plugin-registry.test.js +166 -0
  73. package/dist/plugin/__tests__/plugin-registry.test.js.map +1 -0
  74. package/dist/plugin/plugin-registry.d.ts +38 -0
  75. package/dist/plugin/plugin-registry.js +185 -0
  76. package/dist/plugin/plugin-registry.js.map +1 -0
  77. package/dist/plugin/types.d.ts +59 -0
  78. package/dist/plugin/types.js +2 -0
  79. package/dist/plugin/types.js.map +1 -0
  80. package/dist/research/adapters/__tests__/web-adapters.test.d.ts +1 -0
  81. package/dist/research/adapters/__tests__/web-adapters.test.js +106 -0
  82. package/dist/research/adapters/__tests__/web-adapters.test.js.map +1 -0
  83. package/dist/research/adapters/firecrawl-adapter.d.ts +57 -0
  84. package/dist/research/adapters/firecrawl-adapter.js +137 -0
  85. package/dist/research/adapters/firecrawl-adapter.js.map +1 -0
  86. package/dist/research/adapters/index.d.ts +3 -0
  87. package/dist/research/adapters/index.js +2 -0
  88. package/dist/research/adapters/index.js.map +1 -1
  89. package/dist/research/adapters/playwright-adapter.d.ts +54 -0
  90. package/dist/research/adapters/playwright-adapter.js +130 -0
  91. package/dist/research/adapters/playwright-adapter.js.map +1 -0
  92. package/dist/research/research-orchestrator.d.ts +3 -0
  93. package/dist/research/research-orchestrator.js +19 -1
  94. package/dist/research/research-orchestrator.js.map +1 -1
  95. package/dist/techradar/__tests__/techradar-engine.test.d.ts +1 -0
  96. package/dist/techradar/__tests__/techradar-engine.test.js +246 -0
  97. package/dist/techradar/__tests__/techradar-engine.test.js.map +1 -0
  98. package/dist/techradar/daily-digest.d.ts +18 -0
  99. package/dist/techradar/daily-digest.js +100 -0
  100. package/dist/techradar/daily-digest.js.map +1 -0
  101. package/dist/techradar/index.d.ts +5 -0
  102. package/dist/techradar/index.js +5 -0
  103. package/dist/techradar/index.js.map +1 -0
  104. package/dist/techradar/relevance-scorer.d.ts +29 -0
  105. package/dist/techradar/relevance-scorer.js +139 -0
  106. package/dist/techradar/relevance-scorer.js.map +1 -0
  107. package/dist/techradar/repo-watcher.d.ts +24 -0
  108. package/dist/techradar/repo-watcher.js +87 -0
  109. package/dist/techradar/repo-watcher.js.map +1 -0
  110. package/dist/techradar/techradar-engine.d.ts +69 -0
  111. package/dist/techradar/techradar-engine.js +382 -0
  112. package/dist/techradar/techradar-engine.js.map +1 -0
  113. package/dist/techradar/types.d.ts +87 -0
  114. package/dist/techradar/types.js +5 -0
  115. package/dist/techradar/types.js.map +1 -0
  116. package/dist/watchdog/__tests__/watchdog-service.test.d.ts +1 -0
  117. package/dist/watchdog/__tests__/watchdog-service.test.js +113 -0
  118. package/dist/watchdog/__tests__/watchdog-service.test.js.map +1 -0
  119. package/dist/watchdog/watchdog-service.d.ts +60 -0
  120. package/dist/watchdog/watchdog-service.js +275 -0
  121. package/dist/watchdog/watchdog-service.js.map +1 -0
  122. package/dist/watchdog/windows-service.d.ts +39 -0
  123. package/dist/watchdog/windows-service.js +179 -0
  124. package/dist/watchdog/windows-service.js.map +1 -0
  125. package/package.json +20 -2
@@ -0,0 +1,87 @@
1
+ /**
2
+ * Repo Watcher — Überwacht GitHub Repos auf neue Releases/Changelogs
3
+ *
4
+ * Einrichten:
5
+ * Braucht GITHUB_TOKEN in .env für höheres Rate Limit (optional, 60 req/h ohne).
6
+ * Repos hinzufügen:
7
+ * brain techradar repos add anthropics/claude-code
8
+ * brain techradar repos add modelcontextprotocol/servers
9
+ */
10
+ import { getLogger } from '../utils/logger.js';
11
+ const log = getLogger();
12
+ export class RepoWatcher {
13
+ githubToken;
14
+ constructor(githubToken) {
15
+ this.githubToken = githubToken ?? process.env.GITHUB_TOKEN ?? null;
16
+ }
17
+ /**
18
+ * Check a repo for new releases since the last known tag.
19
+ * Returns new releases (newest first).
20
+ */
21
+ async checkReleases(repo) {
22
+ try {
23
+ const headers = {
24
+ 'Accept': 'application/vnd.github+json',
25
+ 'User-Agent': 'BrainEcosystem/1.0',
26
+ };
27
+ if (this.githubToken) {
28
+ headers['Authorization'] = `Bearer ${this.githubToken}`;
29
+ }
30
+ const response = await fetch(`https://api.github.com/repos/${repo.full_name}/releases?per_page=10`, { headers });
31
+ if (!response.ok) {
32
+ log.warn(`[RepoWatcher] GitHub API error for ${repo.full_name}: ${response.status}`);
33
+ return [];
34
+ }
35
+ const data = await response.json();
36
+ // Filter to only new releases (after last known tag)
37
+ const releases = [];
38
+ for (const release of data) {
39
+ if (repo.last_release_tag && release.tag_name === repo.last_release_tag) {
40
+ break; // We've seen this one, stop
41
+ }
42
+ releases.push({
43
+ tag: release.tag_name,
44
+ name: release.name || release.tag_name,
45
+ body: release.body || '',
46
+ published_at: release.published_at,
47
+ url: release.html_url,
48
+ is_prerelease: release.prerelease,
49
+ });
50
+ }
51
+ return releases;
52
+ }
53
+ catch (err) {
54
+ log.warn(`[RepoWatcher] Error checking ${repo.full_name}: ${err.message}`);
55
+ return [];
56
+ }
57
+ }
58
+ /**
59
+ * Fetch the CHANGELOG.md or CHANGES.md from a repo.
60
+ * Returns the content or null if not found.
61
+ */
62
+ async fetchChangelog(repoFullName) {
63
+ const candidates = ['CHANGELOG.md', 'CHANGES.md', 'HISTORY.md', 'changelog.md'];
64
+ for (const filename of candidates) {
65
+ try {
66
+ const headers = {
67
+ 'Accept': 'application/vnd.github.raw+json',
68
+ 'User-Agent': 'BrainEcosystem/1.0',
69
+ };
70
+ if (this.githubToken) {
71
+ headers['Authorization'] = `Bearer ${this.githubToken}`;
72
+ }
73
+ const response = await fetch(`https://api.github.com/repos/${repoFullName}/contents/${filename}`, { headers });
74
+ if (response.ok) {
75
+ const content = await response.text();
76
+ // Truncate to first ~5000 chars (recent entries)
77
+ return content.substring(0, 5000);
78
+ }
79
+ }
80
+ catch {
81
+ // Try next candidate
82
+ }
83
+ }
84
+ return null;
85
+ }
86
+ }
87
+ //# sourceMappingURL=repo-watcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"repo-watcher.js","sourceRoot":"","sources":["../../src/techradar/repo-watcher.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,69 @@
1
+ /**
2
+ * TechRadar Engine — Täglicher Internet-Scan + Relevanz-Analyse
3
+ *
4
+ * ═══════════════════════════════════════════════════════════════
5
+ * EINRICHTEN
6
+ * ═══════════════════════════════════════════════════════════════
7
+ *
8
+ * Funktioniert out of the box (nutzt SignalScanner-Daten).
9
+ *
10
+ * Für bessere Ergebnisse:
11
+ * 1. GITHUB_TOKEN in .env → höheres Rate Limit für Repo-Watching
12
+ * 2. LLMService angebunden → intelligentes Relevanz-Scoring
13
+ * 3. Repos watchlisten:
14
+ * brain techradar repos add anthropics/claude-code
15
+ * brain techradar repos add modelcontextprotocol/servers
16
+ *
17
+ * CLI:
18
+ * brain techradar → Heutigen Digest anzeigen
19
+ * brain techradar scan → Jetzt scannen
20
+ * brain techradar repos list → Überwachte Repos
21
+ * brain techradar repos add <repo>
22
+ * ═══════════════════════════════════════════════════════════════
23
+ */
24
+ import Database from 'better-sqlite3';
25
+ import type { LLMService } from '../llm/llm-service.js';
26
+ import type { TechRadarConfig, TechRadarEntry, TechRadarScanResult, WatchedRepo, DailyDigest, TechRadarSource } from './types.js';
27
+ export declare function runTechRadarMigration(db: Database.Database): void;
28
+ export declare class TechRadarEngine {
29
+ private readonly db;
30
+ private readonly config;
31
+ private readonly repoWatcher;
32
+ private readonly relevanceScorer;
33
+ private readonly digestGenerator;
34
+ private scanTimer;
35
+ constructor(db: Database.Database, config?: Partial<TechRadarConfig>);
36
+ setLLMService(llmService: LLMService): void;
37
+ /** Start periodic scanning */
38
+ start(): void;
39
+ /** Stop periodic scanning */
40
+ stop(): void;
41
+ /** Run a full scan */
42
+ scan(): Promise<TechRadarScanResult>;
43
+ addWatchedRepo(fullName: string, reason?: string): void;
44
+ removeWatchedRepo(fullName: string): void;
45
+ getWatchedRepos(): WatchedRepo[];
46
+ private ensureDefaultWatchedRepos;
47
+ private checkWatchedRepos;
48
+ /**
49
+ * Import high-scoring repos from existing SignalScanner data.
50
+ * Only imports breakout and signal-level repos.
51
+ */
52
+ private importFromSignalScanner;
53
+ private upsertEntry;
54
+ getEntries(options?: {
55
+ minScore?: number;
56
+ source?: TechRadarSource;
57
+ ring?: string;
58
+ limit?: number;
59
+ }): TechRadarEntry[];
60
+ generateDigest(date?: string): Promise<DailyDigest>;
61
+ getDigest(date?: string): DailyDigest | null;
62
+ getStats(): {
63
+ totalEntries: number;
64
+ bySource: Record<string, number>;
65
+ byRing: Record<string, number>;
66
+ watchedRepos: number;
67
+ lastDigest: string | null;
68
+ };
69
+ }
@@ -0,0 +1,382 @@
1
+ /**
2
+ * TechRadar Engine — Täglicher Internet-Scan + Relevanz-Analyse
3
+ *
4
+ * ═══════════════════════════════════════════════════════════════
5
+ * EINRICHTEN
6
+ * ═══════════════════════════════════════════════════════════════
7
+ *
8
+ * Funktioniert out of the box (nutzt SignalScanner-Daten).
9
+ *
10
+ * Für bessere Ergebnisse:
11
+ * 1. GITHUB_TOKEN in .env → höheres Rate Limit für Repo-Watching
12
+ * 2. LLMService angebunden → intelligentes Relevanz-Scoring
13
+ * 3. Repos watchlisten:
14
+ * brain techradar repos add anthropics/claude-code
15
+ * brain techradar repos add modelcontextprotocol/servers
16
+ *
17
+ * CLI:
18
+ * brain techradar → Heutigen Digest anzeigen
19
+ * brain techradar scan → Jetzt scannen
20
+ * brain techradar repos list → Überwachte Repos
21
+ * brain techradar repos add <repo>
22
+ * ═══════════════════════════════════════════════════════════════
23
+ */
24
+ import { getLogger } from '../utils/logger.js';
25
+ import { RepoWatcher } from './repo-watcher.js';
26
+ import { RelevanceScorer } from './relevance-scorer.js';
27
+ import { DigestGenerator } from './daily-digest.js';
28
+ const log = getLogger();
29
+ const DEFAULT_CONFIG = {
30
+ enabled: true,
31
+ scanIntervalMs: 6 * 60 * 60 * 1000, // 6h
32
+ digestTime: '06:00',
33
+ maxEntriesPerScan: 50,
34
+ relevanceThreshold: 30,
35
+ watchedRepos: [
36
+ 'anthropics/claude-code',
37
+ 'modelcontextprotocol/servers',
38
+ 'anthropics/anthropic-sdk-python',
39
+ ],
40
+ };
41
+ // ── Migration ────────────────────────────────────────────
42
+ export function runTechRadarMigration(db) {
43
+ db.exec(`
44
+ CREATE TABLE IF NOT EXISTS techradar_entries (
45
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
46
+ name TEXT NOT NULL,
47
+ source TEXT NOT NULL,
48
+ source_url TEXT NOT NULL DEFAULT '',
49
+ category TEXT NOT NULL DEFAULT 'other',
50
+ ring TEXT NOT NULL DEFAULT 'assess',
51
+ description TEXT NOT NULL DEFAULT '',
52
+ relevance_score REAL DEFAULT 0,
53
+ relevance_reason TEXT DEFAULT '',
54
+ action_type TEXT DEFAULT 'none',
55
+ action_detail TEXT DEFAULT '',
56
+ first_seen_at TEXT DEFAULT (datetime('now')),
57
+ last_seen_at TEXT DEFAULT (datetime('now')),
58
+ is_active INTEGER DEFAULT 1
59
+ );
60
+
61
+ CREATE INDEX IF NOT EXISTS idx_techradar_score ON techradar_entries(relevance_score DESC);
62
+ CREATE INDEX IF NOT EXISTS idx_techradar_source ON techradar_entries(source);
63
+ CREATE INDEX IF NOT EXISTS idx_techradar_ring ON techradar_entries(ring);
64
+
65
+ CREATE TABLE IF NOT EXISTS techradar_watched_repos (
66
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
67
+ full_name TEXT UNIQUE NOT NULL,
68
+ url TEXT NOT NULL DEFAULT '',
69
+ reason TEXT DEFAULT '',
70
+ last_release_tag TEXT,
71
+ last_release_at TEXT,
72
+ last_checked_at TEXT,
73
+ is_active INTEGER DEFAULT 1
74
+ );
75
+
76
+ CREATE TABLE IF NOT EXISTS techradar_digests (
77
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
78
+ date TEXT UNIQUE NOT NULL,
79
+ summary TEXT NOT NULL DEFAULT '',
80
+ entries_json TEXT DEFAULT '[]',
81
+ opportunities_json TEXT DEFAULT '[]',
82
+ action_items_json TEXT DEFAULT '[]',
83
+ created_at TEXT DEFAULT (datetime('now'))
84
+ );
85
+ `);
86
+ }
87
+ // ── Engine ────────────────────────────────────────────────
88
+ export class TechRadarEngine {
89
+ db;
90
+ config;
91
+ repoWatcher;
92
+ relevanceScorer;
93
+ digestGenerator;
94
+ scanTimer = null;
95
+ constructor(db, config = {}) {
96
+ this.db = db;
97
+ this.config = { ...DEFAULT_CONFIG, ...config };
98
+ this.repoWatcher = new RepoWatcher(this.config.githubToken);
99
+ this.relevanceScorer = new RelevanceScorer();
100
+ this.digestGenerator = new DigestGenerator();
101
+ runTechRadarMigration(db);
102
+ this.ensureDefaultWatchedRepos();
103
+ }
104
+ setLLMService(llmService) {
105
+ this.relevanceScorer.setLLMService(llmService);
106
+ this.digestGenerator.setLLMService(llmService);
107
+ }
108
+ /** Start periodic scanning */
109
+ start() {
110
+ if (this.scanTimer)
111
+ return;
112
+ this.scanTimer = setInterval(() => {
113
+ this.scan().catch(err => {
114
+ log.error(`[TechRadar] Scan error: ${err.message}`);
115
+ });
116
+ }, this.config.scanIntervalMs);
117
+ log.info(`[TechRadar] Engine started (interval: ${this.config.scanIntervalMs / 1000}s)`);
118
+ }
119
+ /** Stop periodic scanning */
120
+ stop() {
121
+ if (this.scanTimer) {
122
+ clearInterval(this.scanTimer);
123
+ this.scanTimer = null;
124
+ }
125
+ }
126
+ /** Run a full scan */
127
+ async scan() {
128
+ const startedAt = new Date().toISOString();
129
+ const errors = [];
130
+ let newEntries = 0;
131
+ let updatedEntries = 0;
132
+ let releasesFound = 0;
133
+ log.info('[TechRadar] Starting scan...');
134
+ // 1. Check watched repos for new releases
135
+ try {
136
+ const releases = await this.checkWatchedRepos();
137
+ releasesFound = releases;
138
+ newEntries += releases;
139
+ }
140
+ catch (err) {
141
+ errors.push(`Repo watch: ${err.message}`);
142
+ }
143
+ // 2. Import high-scoring entries from SignalScanner (if available)
144
+ try {
145
+ const imported = this.importFromSignalScanner();
146
+ newEntries += imported.new;
147
+ updatedEntries += imported.updated;
148
+ }
149
+ catch (err) {
150
+ errors.push(`Signal import: ${err.message}`);
151
+ }
152
+ // 3. Generate digest if we have new entries
153
+ let digestGenerated = false;
154
+ const today = new Date().toISOString().split('T')[0];
155
+ if (newEntries > 0 || updatedEntries > 0) {
156
+ try {
157
+ await this.generateDigest(today);
158
+ digestGenerated = true;
159
+ }
160
+ catch (err) {
161
+ errors.push(`Digest: ${err.message}`);
162
+ }
163
+ }
164
+ const result = {
165
+ started_at: startedAt,
166
+ finished_at: new Date().toISOString(),
167
+ duration_ms: Date.now() - new Date(startedAt).getTime(),
168
+ new_entries: newEntries,
169
+ updated_entries: updatedEntries,
170
+ releases_found: releasesFound,
171
+ digest_generated: digestGenerated,
172
+ errors,
173
+ };
174
+ log.info(`[TechRadar] Scan complete: ${newEntries} new, ${updatedEntries} updated, ${releasesFound} releases`);
175
+ return result;
176
+ }
177
+ // ── Watched Repos ──────────────────────────────────────
178
+ addWatchedRepo(fullName, reason = '') {
179
+ const stmt = this.db.prepare(`
180
+ INSERT OR IGNORE INTO techradar_watched_repos (full_name, url, reason)
181
+ VALUES (?, ?, ?)
182
+ `);
183
+ stmt.run(fullName, `https://github.com/${fullName}`, reason);
184
+ }
185
+ removeWatchedRepo(fullName) {
186
+ this.db.prepare('UPDATE techradar_watched_repos SET is_active = 0 WHERE full_name = ?').run(fullName);
187
+ }
188
+ getWatchedRepos() {
189
+ return this.db.prepare('SELECT * FROM techradar_watched_repos WHERE is_active = 1').all();
190
+ }
191
+ ensureDefaultWatchedRepos() {
192
+ for (const repo of this.config.watchedRepos) {
193
+ this.addWatchedRepo(repo, 'default watchlist');
194
+ }
195
+ }
196
+ async checkWatchedRepos() {
197
+ const repos = this.getWatchedRepos();
198
+ let count = 0;
199
+ for (const repo of repos) {
200
+ const releases = await this.repoWatcher.checkReleases(repo);
201
+ if (releases.length > 0) {
202
+ const latest = releases[0];
203
+ // Score relevance
204
+ const relevance = await this.relevanceScorer.score(`${repo.full_name} ${latest.tag}`, `New release: ${latest.name}. ${latest.body.substring(0, 500)}`, 'github_release');
205
+ // Create/update radar entry
206
+ this.upsertEntry({
207
+ name: `${repo.full_name}@${latest.tag}`,
208
+ source: 'github_release',
209
+ source_url: latest.url,
210
+ category: relevance.category,
211
+ ring: relevance.ring,
212
+ description: `Release ${latest.tag}: ${latest.name}. ${latest.body.substring(0, 300)}`,
213
+ relevance_score: relevance.score,
214
+ relevance_reason: relevance.reason,
215
+ action_type: relevance.action,
216
+ action_detail: relevance.actionDetail,
217
+ first_seen_at: new Date().toISOString(),
218
+ last_seen_at: new Date().toISOString(),
219
+ is_active: true,
220
+ });
221
+ // Update watched repo
222
+ this.db.prepare(`
223
+ UPDATE techradar_watched_repos
224
+ SET last_release_tag = ?, last_release_at = ?, last_checked_at = datetime('now')
225
+ WHERE full_name = ?
226
+ `).run(latest.tag, latest.published_at, repo.full_name);
227
+ count += releases.length;
228
+ }
229
+ else {
230
+ // Update last checked
231
+ this.db.prepare(`
232
+ UPDATE techradar_watched_repos SET last_checked_at = datetime('now') WHERE full_name = ?
233
+ `).run(repo.full_name);
234
+ }
235
+ }
236
+ return count;
237
+ }
238
+ // ── SignalScanner Integration ──────────────────────────
239
+ /**
240
+ * Import high-scoring repos from existing SignalScanner data.
241
+ * Only imports breakout and signal-level repos.
242
+ */
243
+ importFromSignalScanner() {
244
+ let newCount = 0;
245
+ let updatedCount = 0;
246
+ try {
247
+ // Check if scanned_repos table exists
248
+ const tableExists = this.db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='scanned_repos'").get();
249
+ if (!tableExists)
250
+ return { new: 0, updated: 0 };
251
+ const repos = this.db.prepare(`
252
+ SELECT full_name, url, description, language, topics, current_stars,
253
+ signal_score, signal_level, star_velocity_24h
254
+ FROM scanned_repos
255
+ WHERE signal_level IN ('breakout', 'signal')
256
+ AND is_active = 1
257
+ ORDER BY signal_score DESC
258
+ LIMIT ?
259
+ `).all(this.config.maxEntriesPerScan);
260
+ for (const repo of repos) {
261
+ const existing = this.db.prepare('SELECT id FROM techradar_entries WHERE name = ? AND source = ?').get(repo.full_name, 'github_trending');
262
+ // Score relevance
263
+ const relevance = this.relevanceScorer.scoreKeywords(repo.full_name, `${repo.description ?? ''} ${repo.language ?? ''} ${repo.topics ?? ''}`);
264
+ if (relevance.score < this.config.relevanceThreshold)
265
+ continue;
266
+ if (existing) {
267
+ this.db.prepare(`
268
+ UPDATE techradar_entries
269
+ SET relevance_score = ?, last_seen_at = datetime('now'), description = ?
270
+ WHERE name = ? AND source = ?
271
+ `).run(relevance.score, `${repo.description ?? ''}. Stars: ${repo.current_stars}, velocity: ${repo.star_velocity_24h}/day`, repo.full_name, 'github_trending');
272
+ updatedCount++;
273
+ }
274
+ else {
275
+ this.upsertEntry({
276
+ name: repo.full_name,
277
+ source: 'github_trending',
278
+ source_url: repo.url,
279
+ category: relevance.category,
280
+ ring: relevance.ring,
281
+ description: `${repo.description ?? ''}. Stars: ${repo.current_stars}, velocity: ${repo.star_velocity_24h}/day`,
282
+ relevance_score: relevance.score,
283
+ relevance_reason: relevance.reason,
284
+ action_type: relevance.action,
285
+ action_detail: relevance.actionDetail,
286
+ first_seen_at: new Date().toISOString(),
287
+ last_seen_at: new Date().toISOString(),
288
+ is_active: true,
289
+ });
290
+ newCount++;
291
+ }
292
+ }
293
+ }
294
+ catch (err) {
295
+ log.warn(`[TechRadar] SignalScanner import error: ${err.message}`);
296
+ }
297
+ return { new: newCount, updated: updatedCount };
298
+ }
299
+ // ── Entries ────────────────────────────────────────────
300
+ upsertEntry(entry) {
301
+ const existing = this.db.prepare('SELECT id FROM techradar_entries WHERE name = ? AND source = ?').get(entry.name, entry.source);
302
+ if (existing) {
303
+ this.db.prepare(`
304
+ UPDATE techradar_entries
305
+ SET relevance_score = ?, relevance_reason = ?, ring = ?,
306
+ action_type = ?, action_detail = ?, last_seen_at = datetime('now'),
307
+ description = ?, category = ?
308
+ WHERE id = ?
309
+ `).run(entry.relevance_score, entry.relevance_reason, entry.ring, entry.action_type, entry.action_detail, entry.description, entry.category, existing.id);
310
+ }
311
+ else {
312
+ this.db.prepare(`
313
+ INSERT INTO techradar_entries
314
+ (name, source, source_url, category, ring, description,
315
+ relevance_score, relevance_reason, action_type, action_detail)
316
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
317
+ `).run(entry.name, entry.source, entry.source_url, entry.category, entry.ring, entry.description, entry.relevance_score, entry.relevance_reason, entry.action_type, entry.action_detail);
318
+ }
319
+ }
320
+ getEntries(options = {}) {
321
+ let sql = 'SELECT * FROM techradar_entries WHERE is_active = 1';
322
+ const params = [];
323
+ if (options.minScore !== undefined) {
324
+ sql += ' AND relevance_score >= ?';
325
+ params.push(options.minScore);
326
+ }
327
+ if (options.source) {
328
+ sql += ' AND source = ?';
329
+ params.push(options.source);
330
+ }
331
+ if (options.ring) {
332
+ sql += ' AND ring = ?';
333
+ params.push(options.ring);
334
+ }
335
+ sql += ' ORDER BY relevance_score DESC LIMIT ?';
336
+ params.push(options.limit ?? 50);
337
+ return this.db.prepare(sql).all(...params);
338
+ }
339
+ // ── Digest ─────────────────────────────────────────────
340
+ async generateDigest(date) {
341
+ const today = date ?? new Date().toISOString().split('T')[0];
342
+ const entries = this.getEntries({ minScore: this.config.relevanceThreshold });
343
+ const digest = await this.digestGenerator.generate(entries, today);
344
+ // Store digest
345
+ this.db.prepare(`
346
+ INSERT OR REPLACE INTO techradar_digests
347
+ (date, summary, entries_json, opportunities_json, action_items_json)
348
+ VALUES (?, ?, ?, ?, ?)
349
+ `).run(today, digest.summary, JSON.stringify(digest.entries), JSON.stringify(digest.opportunities), JSON.stringify(digest.action_items));
350
+ return digest;
351
+ }
352
+ getDigest(date) {
353
+ const today = date ?? new Date().toISOString().split('T')[0];
354
+ const row = this.db.prepare('SELECT * FROM techradar_digests WHERE date = ?').get(today);
355
+ if (!row)
356
+ return null;
357
+ return {
358
+ date: row.date,
359
+ summary: row.summary,
360
+ entries: JSON.parse(row.entries_json),
361
+ opportunities: JSON.parse(row.opportunities_json),
362
+ action_items: JSON.parse(row.action_items_json),
363
+ created_at: row.created_at,
364
+ };
365
+ }
366
+ // ── Stats ──────────────────────────────────────────────
367
+ getStats() {
368
+ const total = this.db.prepare('SELECT COUNT(*) as c FROM techradar_entries WHERE is_active = 1').get().c;
369
+ const bySrc = this.db.prepare('SELECT source, COUNT(*) as c FROM techradar_entries WHERE is_active = 1 GROUP BY source').all();
370
+ const byRing = this.db.prepare('SELECT ring, COUNT(*) as c FROM techradar_entries WHERE is_active = 1 GROUP BY ring').all();
371
+ const watched = this.db.prepare('SELECT COUNT(*) as c FROM techradar_watched_repos WHERE is_active = 1').get().c;
372
+ const lastDigest = this.db.prepare('SELECT date FROM techradar_digests ORDER BY date DESC LIMIT 1').get();
373
+ return {
374
+ totalEntries: total,
375
+ bySource: Object.fromEntries(bySrc.map(r => [r.source, r.c])),
376
+ byRing: Object.fromEntries(byRing.map(r => [r.ring, r.c])),
377
+ watchedRepos: watched,
378
+ lastDigest: lastDigest?.date ?? null,
379
+ };
380
+ }
381
+ }
382
+ //# sourceMappingURL=techradar-engine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"techradar-engine.js","sourceRoot":"","sources":["../../src/techradar/techradar-engine.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,87 @@
1
+ /**
2
+ * TechRadar Types — Täglicher Internet-Scan + Relevanz-Analyse
3
+ */
4
+ export interface TechRadarEntry {
5
+ id?: number;
6
+ name: string;
7
+ source: TechRadarSource;
8
+ source_url: string;
9
+ category: TechRadarCategory;
10
+ ring: TechRadarRing;
11
+ description: string;
12
+ relevance_score: number;
13
+ relevance_reason: string;
14
+ action_type: TechRadarAction;
15
+ action_detail: string;
16
+ first_seen_at: string;
17
+ last_seen_at: string;
18
+ is_active: boolean;
19
+ }
20
+ export type TechRadarSource = 'github_release' | 'github_trending' | 'hackernews' | 'web' | 'changelog' | 'npm' | 'manual';
21
+ export type TechRadarCategory = 'framework' | 'library' | 'tool' | 'language' | 'platform' | 'technique' | 'ai_model' | 'crypto' | 'other';
22
+ export type TechRadarRing = 'adopt' | 'trial' | 'assess' | 'hold';
23
+ export type TechRadarAction = 'integrate' | 'update' | 'investigate' | 'monitor' | 'none';
24
+ export interface WatchedRepo {
25
+ id?: number;
26
+ full_name: string;
27
+ url: string;
28
+ reason: string;
29
+ last_release_tag: string | null;
30
+ last_release_at: string | null;
31
+ last_checked_at: string | null;
32
+ is_active: boolean;
33
+ }
34
+ export interface RepoRelease {
35
+ tag: string;
36
+ name: string;
37
+ body: string;
38
+ published_at: string;
39
+ url: string;
40
+ is_prerelease: boolean;
41
+ }
42
+ export interface DailyDigest {
43
+ id?: number;
44
+ date: string;
45
+ summary: string;
46
+ entries: DigestEntry[];
47
+ opportunities: DigestOpportunity[];
48
+ action_items: DigestActionItem[];
49
+ created_at: string;
50
+ }
51
+ export interface DigestEntry {
52
+ name: string;
53
+ source: TechRadarSource;
54
+ category: TechRadarCategory;
55
+ relevance_score: number;
56
+ summary: string;
57
+ }
58
+ export interface DigestOpportunity {
59
+ title: string;
60
+ description: string;
61
+ effort: 'low' | 'medium' | 'high';
62
+ impact: 'low' | 'medium' | 'high';
63
+ }
64
+ export interface DigestActionItem {
65
+ action: string;
66
+ priority: 'critical' | 'high' | 'medium' | 'low';
67
+ related_entry: string;
68
+ }
69
+ export interface TechRadarConfig {
70
+ enabled: boolean;
71
+ scanIntervalMs: number;
72
+ digestTime: string;
73
+ maxEntriesPerScan: number;
74
+ relevanceThreshold: number;
75
+ githubToken?: string;
76
+ watchedRepos: string[];
77
+ }
78
+ export interface TechRadarScanResult {
79
+ started_at: string;
80
+ finished_at: string;
81
+ duration_ms: number;
82
+ new_entries: number;
83
+ updated_entries: number;
84
+ releases_found: number;
85
+ digest_generated: boolean;
86
+ errors: string[];
87
+ }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * TechRadar Types — Täglicher Internet-Scan + Relevanz-Analyse
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/techradar/types.ts"],"names":[],"mappings":"AAAA;;GAEG"}
@@ -0,0 +1 @@
1
+ export {};