feat(ms-ai-architect): add local cron wrapper for weekly KB maintenance

Wrapper script that polls Microsoft Learn sitemaps and spawns a local
Claude session to update stale reference files. Designed for crontab,
zero cloud dependencies.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Kjell Tore Guttormsen 2026-04-09 21:47:05 +02:00
commit 901bf0ae12

View file

@ -0,0 +1,147 @@
#!/usr/bin/env node
// weekly-kb-cron.mjs — Local cron wrapper for weekly KB maintenance.
// Runs sitemap polling + change report. If critical/high findings exist,
// spawns a local Claude Code session to update stale reference files.
//
// Crontab: 23 4 * * 3 node /path/to/weekly-kb-cron.mjs >> /tmp/kb-cron.log 2>&1
//
// Zero npm dependencies. Uses only node builtins.
import { execFileSync, execSync } from 'node:child_process';
import { readFileSync, existsSync, appendFileSync } from 'node:fs';
import { join, dirname } from 'node:path';
import { fileURLToPath } from 'node:url';
const __dirname = dirname(fileURLToPath(import.meta.url));
const PLUGIN_ROOT = join(__dirname, '..', '..');
const DATA_DIR = join(__dirname, 'data');
const CLAUDE_BIN = '/Users/ktg/.local/bin/claude';
const LOG_FILE = '/tmp/kb-cron.log';
const MAX_UPDATE_FILES = 10;
function log(msg) {
const ts = new Date().toISOString();
const line = `[${ts}] ${msg}`;
console.log(line);
}
function run(script, args = []) {
const fullPath = join(__dirname, script);
log(`Running ${script} ${args.join(' ')}`);
try {
execFileSync('node', [fullPath, ...args], {
stdio: 'inherit',
timeout: 10 * 60 * 1000,
cwd: PLUGIN_ROOT,
});
} catch (err) {
log(`ERROR: ${script} failed: ${err.message}`);
process.exit(1);
}
}
// --- Step 1: Sitemap polling + discovery ---
log('=== Weekly KB Cron Start ===');
run('run-weekly-update.mjs', ['--force', '--discover']);
// --- Step 2: Read change report ---
const reportPath = join(DATA_DIR, 'change-report.json');
if (!existsSync(reportPath)) {
log('No change report found. Exiting.');
process.exit(0);
}
const report = JSON.parse(readFileSync(reportPath, 'utf8'));
const { critical = 0, high = 0, medium = 0, low = 0 } = report.by_priority || {};
log(`Change report: ${critical} critical, ${high} high, ${medium} medium, ${low} low`);
// --- Step 3: If critical/high exist, spawn Claude for updates ---
if (critical + high === 0) {
log('No critical/high findings. Committing data updates only.');
try {
execSync('git add scripts/kb-update/data/', { cwd: PLUGIN_ROOT, stdio: 'pipe' });
const status = execSync('git status --porcelain scripts/kb-update/data/', { cwd: PLUGIN_ROOT, encoding: 'utf8' });
if (status.trim()) {
execSync(
'git commit -m "docs(architect): weekly KB poll — no stale files"',
{ cwd: PLUGIN_ROOT, stdio: 'pipe' }
);
execSync('git push origin main', { cwd: PLUGIN_ROOT, stdio: 'pipe' });
log('Data committed and pushed.');
} else {
log('No data changes to commit.');
}
} catch (err) {
log(`Git error: ${err.message}`);
}
log('=== Weekly KB Cron Done ===');
process.exit(0);
}
// Build list of stale files (critical + high only, max MAX_UPDATE_FILES)
const staleFiles = (report.files || [])
.filter(f => f.priority === 'critical' || f.priority === 'high')
.slice(0, MAX_UPDATE_FILES);
log(`Spawning Claude to update ${staleFiles.length} stale files...`);
const fileList = staleFiles.map(f => {
const urls = (f.changed_urls || []).slice(0, 5).join('\n ');
return `- ${f.path} [${f.priority}]\n Changed URLs:\n ${urls}`;
}).join('\n');
const prompt = `Du er Cosmo Skyberg. Oppdater ${staleFiles.length} stale kunnskapsreferanser i ms-ai-architect pluginen.
Arbeidsmappe: ${PLUGIN_ROOT}
## Filer å oppdatere
${fileList}
## For HVER fil
1. Les filen med Read
2. Bruk microsoft_docs_fetch de endrede kilde-URLene listet over
3. Bruk microsoft_docs_search for supplerende info
4. Oppdater filen med Edit:
- Oppdater "Last updated" til ${new Date().toISOString().slice(0, 7)}
- Oppdater utdaterte fakta, priser, datoer
- Bevar eksisterende struktur og seksjoner
- Marker oppdatert innhold med "Verified (MCP ${new Date().toISOString().slice(0, 7)})"
## Etter alle oppdateringer
1. Kjør: node scripts/kb-update/build-registry.mjs --merge
2. Kjør: node scripts/kb-update/report-changes.mjs
3. git add skills/ scripts/kb-update/data/
4. git commit -m "docs(architect): weekly KB update ${staleFiles.length} files refreshed
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>"
5. git push origin main
## Regler
- Aldri slett filer, kun oppdater
- Bruk Edit, ikke Write
- Bevar all eksisterende struktur`;
try {
execFileSync(CLAUDE_BIN, [
'-p', prompt,
'--model', 'sonnet',
'--allowedTools', 'Read,Edit,Bash,Glob,Grep,mcp__microsoft-learn__microsoft_docs_search,mcp__microsoft-learn__microsoft_docs_fetch',
'--max-turns', '30',
], {
stdio: 'inherit',
timeout: 15 * 60 * 1000,
cwd: PLUGIN_ROOT,
});
log('Claude session completed.');
} catch (err) {
log(`Claude session error: ${err.message}`);
process.exit(1);
}
log('=== Weekly KB Cron Done ===');