mcp-astgl-knowledge 1.0.2 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/README.md +146 -38
  2. package/data/knowledge.db +0 -0
  3. package/dist/alerts.d.ts +22 -0
  4. package/dist/alerts.js +433 -0
  5. package/dist/alerts.js.map +1 -0
  6. package/dist/citation-test.d.ts +14 -0
  7. package/dist/citation-test.js +298 -0
  8. package/dist/citation-test.js.map +1 -0
  9. package/dist/daily-report.d.ts +15 -0
  10. package/dist/daily-report.js +441 -0
  11. package/dist/daily-report.js.map +1 -0
  12. package/dist/discover.js +3 -1
  13. package/dist/discover.js.map +1 -1
  14. package/dist/freshness.d.ts +20 -0
  15. package/dist/freshness.js +508 -0
  16. package/dist/freshness.js.map +1 -0
  17. package/dist/index.d.ts +6 -1
  18. package/dist/index.js +253 -14
  19. package/dist/index.js.map +1 -1
  20. package/dist/ingest-projects.d.ts +16 -0
  21. package/dist/ingest-projects.js +196 -0
  22. package/dist/ingest-projects.js.map +1 -0
  23. package/dist/knowledge-db.d.ts +13 -0
  24. package/dist/knowledge-db.js +156 -0
  25. package/dist/knowledge-db.js.map +1 -0
  26. package/dist/pipeline.d.ts +12 -0
  27. package/dist/pipeline.js +83 -0
  28. package/dist/pipeline.js.map +1 -0
  29. package/dist/query-log.d.ts +15 -0
  30. package/dist/query-log.js +93 -0
  31. package/dist/query-log.js.map +1 -0
  32. package/dist/rate-limit.d.ts +34 -0
  33. package/dist/rate-limit.js +206 -0
  34. package/dist/rate-limit.js.map +1 -0
  35. package/dist/related-articles.d.ts +15 -0
  36. package/dist/related-articles.js +217 -0
  37. package/dist/related-articles.js.map +1 -0
  38. package/dist/search.d.ts +13 -4
  39. package/dist/search.js +274 -39
  40. package/dist/search.js.map +1 -1
  41. package/dist/structure.d.ts +11 -0
  42. package/dist/structure.js +451 -0
  43. package/dist/structure.js.map +1 -0
  44. package/dist/types.d.ts +65 -0
  45. package/dist/types.js.map +1 -1
  46. package/package.json +10 -2
@@ -0,0 +1,508 @@
1
+ #!/usr/bin/env tsx
2
+ /**
3
+ * Content freshness automation.
4
+ *
5
+ * WHAT: Detects stale content and ecosystem version changes, sends Discord alerts
6
+ * WHY: Proactive freshness tracking prevents serving outdated info that hurts
7
+ * citation quality and reader trust
8
+ *
9
+ * Checks:
10
+ * 1. Stale content — articles older than 90 days (pub_date or processed_at)
11
+ * 2. MCP SDK version — polls npm registry for @modelcontextprotocol/sdk updates
12
+ * 3. Key tool releases — polls GitHub releases for Ollama, MCP servers, Open WebUI
13
+ *
14
+ * Usage:
15
+ * npm run freshness Check all, print to stdout (JSON)
16
+ * npm run freshness -- --discord Also send triggered alerts to Discord
17
+ *
18
+ * Env: DISCORD_WEBHOOK_URL — Discord webhook for alert delivery
19
+ */
20
+ import { join } from "path";
21
+ import { existsSync, mkdirSync } from "fs";
22
+ import Database from "better-sqlite3";
23
+ import { initKnowledgeDb } from "./knowledge-db.js";
24
+ const DATA_DIR = join(import.meta.dirname, "..", "data");
25
+ const KNOWLEDGE_PATH = join(DATA_DIR, "knowledge.db");
26
+ const DISCOVERY_PATH = join(DATA_DIR, "discovery.db");
27
+ const ALERT_DB_PATH = join(DATA_DIR, "alerts.db");
28
+ const DISCORD_WEBHOOK_URL = process.env.DISCORD_WEBHOOK_URL || "";
29
+ // --- Thresholds ---
30
+ const STALE_THRESHOLD_DAYS = 90;
31
+ const ALERT_COOLDOWN_HOURS = 168; // 7 days — stale content doesn't change daily
32
+ // --- Tracked Ecosystem Packages ---
33
+ const TRACKED_NPM_PACKAGES = ["@modelcontextprotocol/sdk"];
34
+ const TRACKED_GITHUB_REPOS = [
35
+ { owner: "ollama", repo: "ollama", label: "Ollama" },
36
+ { owner: "modelcontextprotocol", repo: "servers", label: "MCP Reference Servers" },
37
+ { owner: "open-webui", repo: "open-webui", label: "Open WebUI" },
38
+ ];
39
+ // --- Alert History DB ---
40
+ // WHAT: Reuse the same alerts.db as alerts.ts for cooldown tracking
41
+ // WHY: Single source of truth for alert suppression across all alert types
42
+ function initAlertDb() {
43
+ if (!existsSync(DATA_DIR))
44
+ mkdirSync(DATA_DIR, { recursive: true });
45
+ const db = new Database(ALERT_DB_PATH);
46
+ db.exec(`
47
+ CREATE TABLE IF NOT EXISTS alert_history (
48
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
49
+ alert_type TEXT NOT NULL,
50
+ alert_key TEXT NOT NULL,
51
+ fired_at TEXT NOT NULL,
52
+ details TEXT,
53
+ UNIQUE(alert_type, alert_key, fired_at)
54
+ )
55
+ `);
56
+ db.exec("CREATE INDEX IF NOT EXISTS idx_alert_history_key ON alert_history(alert_type, alert_key)");
57
+ return db;
58
+ }
59
+ function wasRecentlyFired(alertDb, type, key) {
60
+ const cutoff = new Date();
61
+ cutoff.setHours(cutoff.getHours() - ALERT_COOLDOWN_HOURS);
62
+ const row = alertDb
63
+ .prepare(`SELECT id FROM alert_history
64
+ WHERE alert_type = ? AND alert_key = ? AND fired_at > ?
65
+ LIMIT 1`)
66
+ .get(type, key, cutoff.toISOString());
67
+ return !!row;
68
+ }
69
+ function recordAlert(alertDb, alert, key) {
70
+ alertDb
71
+ .prepare("INSERT OR IGNORE INTO alert_history (alert_type, alert_key, fired_at, details) VALUES (?, ?, ?, ?)")
72
+ .run(alert.type, key, new Date().toISOString(), alert.title);
73
+ }
74
+ // --- Ecosystem Snapshots ---
75
+ // WHAT: Store last-known version for each tracked package/repo
76
+ // WHY: Comparing against previous version detects ecosystem changes
77
+ function initEcosystemTable(knowledgeDb) {
78
+ knowledgeDb.exec(`
79
+ CREATE TABLE IF NOT EXISTS ecosystem_snapshots (
80
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
81
+ check_type TEXT NOT NULL,
82
+ package_name TEXT NOT NULL,
83
+ current_version TEXT NOT NULL,
84
+ previous_version TEXT,
85
+ checked_at TEXT NOT NULL,
86
+ UNIQUE(check_type, package_name)
87
+ )
88
+ `);
89
+ }
90
+ function getSnapshot(knowledgeDb, checkType, packageName) {
91
+ return knowledgeDb
92
+ .prepare("SELECT current_version, previous_version FROM ecosystem_snapshots WHERE check_type = ? AND package_name = ?")
93
+ .get(checkType, packageName);
94
+ }
95
+ function upsertSnapshot(knowledgeDb, checkType, packageName, version) {
96
+ const existing = getSnapshot(knowledgeDb, checkType, packageName);
97
+ if (existing) {
98
+ if (existing.current_version !== version) {
99
+ knowledgeDb
100
+ .prepare(`UPDATE ecosystem_snapshots
101
+ SET previous_version = current_version, current_version = ?, checked_at = ?
102
+ WHERE check_type = ? AND package_name = ?`)
103
+ .run(version, new Date().toISOString(), checkType, packageName);
104
+ }
105
+ else {
106
+ knowledgeDb
107
+ .prepare("UPDATE ecosystem_snapshots SET checked_at = ? WHERE check_type = ? AND package_name = ?")
108
+ .run(new Date().toISOString(), checkType, packageName);
109
+ }
110
+ }
111
+ else {
112
+ knowledgeDb
113
+ .prepare(`INSERT INTO ecosystem_snapshots (check_type, package_name, current_version, checked_at)
114
+ VALUES (?, ?, ?, ?)`)
115
+ .run(checkType, packageName, version, new Date().toISOString());
116
+ }
117
+ }
118
+ // --- Backfill pub_date from discovery.db ---
119
+ // WHAT: Copy pub_date from discovered_content into articles table
120
+ // WHY: pub_date wasn't carried through the pipeline until now — backfill existing articles
121
+ function backfillPubDates(knowledgeDb) {
122
+ if (!existsSync(DISCOVERY_PATH))
123
+ return 0;
124
+ const discoveryDb = new Database(DISCOVERY_PATH, { readonly: true });
125
+ const tableCheck = discoveryDb
126
+ .prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='discovered_content'")
127
+ .get();
128
+ if (!tableCheck) {
129
+ discoveryDb.close();
130
+ return 0;
131
+ }
132
+ const rows = discoveryDb
133
+ .prepare(`SELECT url, pub_date FROM discovered_content
134
+ WHERE pub_date IS NOT NULL AND pub_date != ''`)
135
+ .all();
136
+ discoveryDb.close();
137
+ if (rows.length === 0)
138
+ return 0;
139
+ const update = knowledgeDb.prepare("UPDATE articles SET pub_date = ? WHERE (url = ? OR source_url = ?) AND pub_date IS NULL");
140
+ let updated = 0;
141
+ const runAll = knowledgeDb.transaction(() => {
142
+ for (const row of rows) {
143
+ const result = update.run(row.pub_date, row.url, row.url);
144
+ updated += result.changes;
145
+ }
146
+ });
147
+ runAll();
148
+ return updated;
149
+ }
150
+ // --- Check #1: Stale Content by Age ---
151
+ // WHAT: Flag articles where effective age exceeds 90 days
152
+ // WHY: Old content may have outdated info that hurts citation quality
153
+ function checkStaleContent(knowledgeDb, alertDb) {
154
+ const totalRow = knowledgeDb
155
+ .prepare("SELECT COUNT(*) as count FROM articles")
156
+ .get();
157
+ // WHAT: Use COALESCE priority: last_reviewed_at > pub_date > processed_at
158
+ // WHY: If reviewed recently, that resets the clock. Otherwise use real pub date.
159
+ const staleDate = new Date();
160
+ staleDate.setDate(staleDate.getDate() - STALE_THRESHOLD_DAYS);
161
+ const staleDateStr = staleDate.toISOString();
162
+ const staleArticles = knowledgeDb
163
+ .prepare(`SELECT title, url,
164
+ COALESCE(last_reviewed_at, pub_date, processed_at) as effective_date
165
+ FROM articles
166
+ WHERE COALESCE(last_reviewed_at, pub_date, processed_at) IS NOT NULL
167
+ AND COALESCE(last_reviewed_at, pub_date, processed_at) < ?
168
+ ORDER BY COALESCE(last_reviewed_at, pub_date, processed_at) ASC`)
169
+ .all(staleDateStr);
170
+ if (staleArticles.length === 0) {
171
+ return { alerts: [], staleCount: 0, totalCount: totalRow.count };
172
+ }
173
+ // Update freshness_status for stale articles
174
+ const markStale = knowledgeDb.prepare("UPDATE articles SET freshness_status = 'review_needed' WHERE url = ? AND freshness_status = 'current'");
175
+ for (const article of staleArticles) {
176
+ markStale.run(article.url);
177
+ }
178
+ const key = `stale-${staleArticles.length}`;
179
+ if (wasRecentlyFired(alertDb, "stale_content", key)) {
180
+ return { alerts: [], staleCount: staleArticles.length, totalCount: totalRow.count };
181
+ }
182
+ const now = Date.now();
183
+ const articleList = staleArticles.slice(0, 10).map((a) => {
184
+ const days = Math.floor((now - new Date(a.effective_date).getTime()) / (1000 * 60 * 60 * 24));
185
+ return ` - ${a.title} (${days}d old)\n ${a.url}`;
186
+ });
187
+ const alert = {
188
+ type: "stale_content",
189
+ severity: staleArticles.length >= 6 ? "critical" : "warning",
190
+ title: `${staleArticles.length} articles need freshness review (${STALE_THRESHOLD_DAYS}d+ old)`,
191
+ details: [
192
+ `${staleArticles.length} of ${totalRow.count} articles are older than ${STALE_THRESHOLD_DAYS} days:`,
193
+ ...articleList,
194
+ staleArticles.length > 10 ? ` ... and ${staleArticles.length - 10} more` : "",
195
+ "",
196
+ "Action: Review and update stale articles, or mark as reviewed if still current.",
197
+ ]
198
+ .filter(Boolean)
199
+ .join("\n"),
200
+ data: {
201
+ stale_count: staleArticles.length,
202
+ total_count: totalRow.count,
203
+ threshold_days: STALE_THRESHOLD_DAYS,
204
+ articles: staleArticles.slice(0, 10).map((a) => ({
205
+ title: a.title,
206
+ url: a.url,
207
+ effective_date: a.effective_date,
208
+ })),
209
+ },
210
+ };
211
+ recordAlert(alertDb, alert, key);
212
+ return { alerts: [alert], staleCount: staleArticles.length, totalCount: totalRow.count };
213
+ }
214
+ // --- Check #2: npm Package Version Changes ---
215
+ // WHAT: Poll npm registry for version changes in tracked packages
216
+ // WHY: New MCP SDK versions may invalidate articles about MCP development
217
+ async function checkNpmVersions(knowledgeDb, alertDb) {
218
+ const alerts = [];
219
+ for (const pkg of TRACKED_NPM_PACKAGES) {
220
+ try {
221
+ // WHAT: Use the dist-tags endpoint for minimal response size
222
+ // WHY: Full package metadata can be megabytes — we only need the latest version
223
+ const encodedPkg = pkg.replace("/", "%2f");
224
+ const resp = await fetch(`https://registry.npmjs.org/-/package/${encodedPkg}/dist-tags`, { signal: AbortSignal.timeout(10_000) });
225
+ if (!resp.ok) {
226
+ console.error(` npm registry returned ${resp.status} for ${pkg}`);
227
+ continue;
228
+ }
229
+ const tags = (await resp.json());
230
+ const latestVersion = tags.latest;
231
+ if (!latestVersion)
232
+ continue;
233
+ const existing = getSnapshot(knowledgeDb, "npm_version", pkg);
234
+ upsertSnapshot(knowledgeDb, "npm_version", pkg, latestVersion);
235
+ // WHAT: Don't alert on first detection (bootstrap)
236
+ // WHY: Every package would trigger an alert on the first run
237
+ if (!existing) {
238
+ console.error(` Bootstrapped ${pkg} at v${latestVersion}`);
239
+ continue;
240
+ }
241
+ if (existing.current_version === latestVersion)
242
+ continue;
243
+ const key = `npm-${pkg}-${latestVersion}`;
244
+ if (wasRecentlyFired(alertDb, "npm_version_change", key))
245
+ continue;
246
+ // WHAT: Find articles that cover this package
247
+ // WHY: Alert should list which content may need updating
248
+ const affectedArticles = findArticlesByTopic(knowledgeDb, ["mcp", "model context protocol", "mcp server"]);
249
+ const alert = {
250
+ type: "npm_version_change",
251
+ severity: "warning",
252
+ title: `${pkg} updated: ${existing.current_version} → ${latestVersion}`,
253
+ details: [
254
+ `**Package:** ${pkg}`,
255
+ `**Previous:** ${existing.current_version}`,
256
+ `**Current:** ${latestVersion}`,
257
+ `**npm:** https://www.npmjs.com/package/${pkg}`,
258
+ "",
259
+ affectedArticles.length > 0
260
+ ? `**${affectedArticles.length} article(s) may need review:**`
261
+ : "No directly related articles found.",
262
+ ...affectedArticles.slice(0, 5).map((a) => ` - ${a.title}\n ${a.url}`),
263
+ "",
264
+ "Action: Check changelog for breaking changes and update affected articles.",
265
+ ].join("\n"),
266
+ data: {
267
+ package: pkg,
268
+ previous_version: existing.current_version,
269
+ current_version: latestVersion,
270
+ affected_articles: affectedArticles.slice(0, 5),
271
+ },
272
+ };
273
+ recordAlert(alertDb, alert, key);
274
+ alerts.push(alert);
275
+ }
276
+ catch (err) {
277
+ const message = err instanceof Error ? err.message : String(err);
278
+ console.error(` npm check failed for ${pkg}: ${message}`);
279
+ }
280
+ }
281
+ return alerts;
282
+ }
283
+ // --- Check #3: GitHub Release Version Changes ---
284
+ // WHAT: Poll GitHub releases API for version changes in tracked repos
285
+ // WHY: New Ollama/Open WebUI versions may require article updates
286
+ async function checkGitHubReleases(knowledgeDb, alertDb) {
287
+ const alerts = [];
288
+ for (const { owner, repo, label } of TRACKED_GITHUB_REPOS) {
289
+ try {
290
+ const resp = await fetch(`https://api.github.com/repos/${owner}/${repo}/releases/latest`, {
291
+ headers: { Accept: "application/vnd.github.v3+json" },
292
+ signal: AbortSignal.timeout(10_000),
293
+ });
294
+ if (!resp.ok) {
295
+ // 404 = no releases, rate limit = 403
296
+ if (resp.status === 403) {
297
+ console.error(` GitHub rate limit hit for ${owner}/${repo}`);
298
+ }
299
+ else {
300
+ console.error(` GitHub returned ${resp.status} for ${owner}/${repo}`);
301
+ }
302
+ continue;
303
+ }
304
+ const release = (await resp.json());
305
+ const version = release.tag_name;
306
+ const packageKey = `${owner}/${repo}`;
307
+ const existing = getSnapshot(knowledgeDb, "github_release", packageKey);
308
+ upsertSnapshot(knowledgeDb, "github_release", packageKey, version);
309
+ // Bootstrap: don't alert on first detection
310
+ if (!existing) {
311
+ console.error(` Bootstrapped ${label} at ${version}`);
312
+ continue;
313
+ }
314
+ if (existing.current_version === version)
315
+ continue;
316
+ const key = `github-${packageKey}-${version}`;
317
+ if (wasRecentlyFired(alertDb, "github_release_change", key))
318
+ continue;
319
+ // Find related articles by searching topics for the tool name
320
+ const searchTerms = label.toLowerCase().split(/\s+/);
321
+ const affectedArticles = findArticlesByTopic(knowledgeDb, searchTerms);
322
+ const alert = {
323
+ type: "github_release_change",
324
+ severity: "info",
325
+ title: `${label} released: ${existing.current_version} → ${version}`,
326
+ details: [
327
+ `**Repository:** ${owner}/${repo}`,
328
+ `**Release:** ${release.name || version}`,
329
+ `**Previous:** ${existing.current_version}`,
330
+ `**Current:** ${version}`,
331
+ `**URL:** ${release.html_url}`,
332
+ `**Published:** ${release.published_at}`,
333
+ "",
334
+ affectedArticles.length > 0
335
+ ? `**${affectedArticles.length} article(s) may need review:**`
336
+ : "No directly related articles found.",
337
+ ...affectedArticles.slice(0, 5).map((a) => ` - ${a.title}\n ${a.url}`),
338
+ "",
339
+ "Action: Review release notes for changes that affect existing article content.",
340
+ ].join("\n"),
341
+ data: {
342
+ repo: packageKey,
343
+ label,
344
+ previous_version: existing.current_version,
345
+ current_version: version,
346
+ release_url: release.html_url,
347
+ affected_articles: affectedArticles.slice(0, 5),
348
+ },
349
+ };
350
+ recordAlert(alertDb, alert, key);
351
+ alerts.push(alert);
352
+ }
353
+ catch (err) {
354
+ const message = err instanceof Error ? err.message : String(err);
355
+ console.error(` GitHub check failed for ${owner}/${repo}: ${message}`);
356
+ }
357
+ }
358
+ return alerts;
359
+ }
360
+ // --- Helper: Find articles by topic keywords ---
361
+ // WHAT: Search articles table for any whose title or content_type matches search terms
362
+ // WHY: Links ecosystem version changes to specific articles that may need updating
363
+ function findArticlesByTopic(knowledgeDb, searchTerms) {
364
+ // Build a WHERE clause matching any search term in title (case-insensitive)
365
+ const conditions = searchTerms.map(() => "LOWER(title) LIKE ?").join(" OR ");
366
+ const params = searchTerms.map((t) => `%${t.toLowerCase()}%`);
367
+ return knowledgeDb
368
+ .prepare(`SELECT DISTINCT title, url FROM articles WHERE ${conditions} LIMIT 10`)
369
+ .all(...params);
370
+ }
371
+ // --- Discord Delivery ---
372
+ function severityColor(severity) {
373
+ switch (severity) {
374
+ case "critical": return 0xff0000;
375
+ case "warning": return 0xffa500;
376
+ case "info": return 0x2196f3;
377
+ }
378
+ }
379
+ function severityEmoji(severity) {
380
+ switch (severity) {
381
+ case "critical": return "🔴";
382
+ case "warning": return "🟡";
383
+ case "info": return "🔵";
384
+ }
385
+ }
386
+ async function sendAlertsToDiscord(alerts) {
387
+ if (!DISCORD_WEBHOOK_URL) {
388
+ console.error("DISCORD_WEBHOOK_URL not set.");
389
+ return;
390
+ }
391
+ if (alerts.length === 0)
392
+ return;
393
+ const embeds = alerts.slice(0, 10).map((alert) => ({
394
+ title: `${severityEmoji(alert.severity)} ${alert.title}`,
395
+ description: alert.details,
396
+ color: severityColor(alert.severity),
397
+ footer: { text: `Freshness check: ${alert.type}` },
398
+ }));
399
+ const resp = await fetch(DISCORD_WEBHOOK_URL, {
400
+ method: "POST",
401
+ headers: { "Content-Type": "application/json" },
402
+ body: JSON.stringify({ embeds }),
403
+ });
404
+ if (!resp.ok) {
405
+ const body = await resp.text();
406
+ console.error(`Discord webhook failed: ${resp.status} ${body}`);
407
+ }
408
+ else {
409
+ console.error(`${alerts.length} freshness alert(s) sent to Discord.`);
410
+ }
411
+ }
412
+ // --- CLI ---
413
+ function parseArgs() {
414
+ const args = process.argv.slice(2);
415
+ return { sendToDiscord: args.includes("--discord") };
416
+ }
417
+ async function main() {
418
+ const { sendToDiscord } = parseArgs();
419
+ console.error("=== ASTGL Content Freshness Checker ===\n");
420
+ if (!existsSync(KNOWLEDGE_PATH)) {
421
+ console.error("knowledge.db not found. Run 'npm run ingest' first.");
422
+ process.exit(1);
423
+ }
424
+ // WHAT: Use initKnowledgeDb to run schema migrations (adds pub_date, freshness_status, etc.)
425
+ // WHY: The new columns won't exist until migrations run
426
+ const knowledgeDb = initKnowledgeDb();
427
+ const alertDb = initAlertDb();
428
+ // Ensure ecosystem_snapshots table exists (also created by migration, but safe to re-run)
429
+ initEcosystemTable(knowledgeDb);
430
+ // Backfill pub_date from discovery.db (idempotent)
431
+ console.error("Backfilling pub_date from discovery.db...");
432
+ const backfilled = backfillPubDates(knowledgeDb);
433
+ if (backfilled > 0) {
434
+ console.error(` Updated ${backfilled} article(s) with pub_date\n`);
435
+ }
436
+ else {
437
+ console.error(" No articles needed backfill\n");
438
+ }
439
+ const checksRun = [];
440
+ const allAlerts = [];
441
+ const ecosystemVersions = [];
442
+ // Check #1: Stale content
443
+ console.error("Checking: stale content (90+ days)...");
444
+ checksRun.push("stale_content");
445
+ const { alerts: staleAlerts, staleCount, totalCount } = checkStaleContent(knowledgeDb, alertDb);
446
+ allAlerts.push(...staleAlerts);
447
+ console.error(` ${staleCount} of ${totalCount} articles are stale\n`);
448
+ // Check #2: npm version changes
449
+ console.error("Checking: npm package versions...");
450
+ checksRun.push("npm_version_check");
451
+ const npmAlerts = await checkNpmVersions(knowledgeDb, alertDb);
452
+ allAlerts.push(...npmAlerts);
453
+ console.error(` ${npmAlerts.length} version change(s) detected\n`);
454
+ // Collect ecosystem versions for report
455
+ for (const pkg of TRACKED_NPM_PACKAGES) {
456
+ const snap = getSnapshot(knowledgeDb, "npm_version", pkg);
457
+ if (snap) {
458
+ ecosystemVersions.push({
459
+ package: pkg,
460
+ version: snap.current_version,
461
+ type: "npm",
462
+ });
463
+ }
464
+ }
465
+ // Check #3: GitHub release changes
466
+ console.error("Checking: GitHub releases...");
467
+ checksRun.push("github_release_check");
468
+ const ghAlerts = await checkGitHubReleases(knowledgeDb, alertDb);
469
+ allAlerts.push(...ghAlerts);
470
+ console.error(` ${ghAlerts.length} release change(s) detected\n`);
471
+ // Collect GitHub versions for report
472
+ for (const { owner, repo, label } of TRACKED_GITHUB_REPOS) {
473
+ const snap = getSnapshot(knowledgeDb, "github_release", `${owner}/${repo}`);
474
+ if (snap) {
475
+ ecosystemVersions.push({
476
+ package: label,
477
+ version: snap.current_version,
478
+ type: "github",
479
+ });
480
+ }
481
+ }
482
+ knowledgeDb.close();
483
+ alertDb.close();
484
+ const report = {
485
+ generated_at: new Date().toISOString(),
486
+ alerts_fired: allAlerts,
487
+ alerts_suppressed: 0,
488
+ checks_run: checksRun,
489
+ ecosystem_versions: ecosystemVersions,
490
+ stale_articles: staleCount,
491
+ total_articles: totalCount,
492
+ };
493
+ console.log(JSON.stringify(report, null, 2));
494
+ if (sendToDiscord && allAlerts.length > 0) {
495
+ await sendAlertsToDiscord(allAlerts);
496
+ }
497
+ else if (sendToDiscord && allAlerts.length === 0) {
498
+ console.error("No freshness alerts to send.");
499
+ }
500
+ console.error(`\n=== Done: ${allAlerts.length} alert(s) fired ===`);
501
+ }
502
+ main()
503
+ .then(() => process.exit(0))
504
+ .catch((err) => {
505
+ console.error("Freshness checker failed:", err);
506
+ process.exit(1);
507
+ });
508
+ //# sourceMappingURL=freshness.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"freshness.js","sourceRoot":"","sources":["../src/freshness.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,9 +1,14 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
3
  * MCP server for ASTGL knowledge base.
4
- * Exposes 3 tools: search_articles, get_answer, list_topics
4
+ * Exposes 7 tools: search_articles, get_answer, list_topics, get_tutorial,
5
+ * compare_topics, get_latest, register
5
6
  *
6
7
  * WHAT: Lets any MCP-compatible AI assistant search and cite ASTGL articles
7
8
  * WHY: Drives traffic and citations back to astgl.ai when AI answers questions
9
+ *
10
+ * Rate limits:
11
+ * Public tier: 50 queries/day (anonymous)
12
+ * Registered tier: 500 queries/day (ASTGL_API_KEY env var)
8
13
  */
9
14
  export {};