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.
- package/README.md +146 -38
- package/data/knowledge.db +0 -0
- package/dist/alerts.d.ts +22 -0
- package/dist/alerts.js +433 -0
- package/dist/alerts.js.map +1 -0
- package/dist/citation-test.d.ts +14 -0
- package/dist/citation-test.js +298 -0
- package/dist/citation-test.js.map +1 -0
- package/dist/daily-report.d.ts +15 -0
- package/dist/daily-report.js +441 -0
- package/dist/daily-report.js.map +1 -0
- package/dist/discover.js +3 -1
- package/dist/discover.js.map +1 -1
- package/dist/freshness.d.ts +20 -0
- package/dist/freshness.js +508 -0
- package/dist/freshness.js.map +1 -0
- package/dist/index.d.ts +6 -1
- package/dist/index.js +253 -14
- package/dist/index.js.map +1 -1
- package/dist/ingest-projects.d.ts +16 -0
- package/dist/ingest-projects.js +196 -0
- package/dist/ingest-projects.js.map +1 -0
- package/dist/knowledge-db.d.ts +13 -0
- package/dist/knowledge-db.js +156 -0
- package/dist/knowledge-db.js.map +1 -0
- package/dist/pipeline.d.ts +12 -0
- package/dist/pipeline.js +83 -0
- package/dist/pipeline.js.map +1 -0
- package/dist/query-log.d.ts +15 -0
- package/dist/query-log.js +93 -0
- package/dist/query-log.js.map +1 -0
- package/dist/rate-limit.d.ts +34 -0
- package/dist/rate-limit.js +206 -0
- package/dist/rate-limit.js.map +1 -0
- package/dist/related-articles.d.ts +15 -0
- package/dist/related-articles.js +217 -0
- package/dist/related-articles.js.map +1 -0
- package/dist/search.d.ts +13 -4
- package/dist/search.js +274 -39
- package/dist/search.js.map +1 -1
- package/dist/structure.d.ts +11 -0
- package/dist/structure.js +451 -0
- package/dist/structure.js.map +1 -0
- package/dist/types.d.ts +65 -0
- package/dist/types.js.map +1 -1
- 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
|
|
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 {};
|