Foundation lib for v1.12.0 cron rewrite — closes brief deliverable
"log-rotate" that was missing from the original plan (Phase 9 scope
revision). Standard logrotate idiom, zero dependencies.
- rotateLog(logPath, opts) returns {rotated, dropped, kept}
- Defaults: maxSizeBytes 10 MB, maxGenerations 5 (1 active + 4 rotated)
- No-op when log missing or under threshold
- Over-size: drop oldest, shift .N..1 down by one, move active → .1
- maxGenerations=1 keeps only the active slot (no rotated copies)
- Pure stdlib fs.renameSync chain with silent try/catch on missing gens
8/8 tests pass: missing/under-size/over-size paths, chained 6 rotations
capped at maxGenerations, oldest dropped, two-step content shift.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Foundation lib for v1.12.0 cron rewrite. Detects which Claude auth mode is
in scope and rejects modes that are architecturally incompatible with cron.
Resolution order:
- ANTHROPIC_API_KEY env-var → 'api-key'
- CLAUDE_CODE_OAUTH_TOKEN env-var → 'long-oauth'
- ~/.claude.json onboarded + runner exit 0 → 'subscription-browser-only'
- otherwise → 'unauthenticated'
Subscription browser-OAuth tokens expire ~15h and cannot survive cron — the
detector flags them explicitly so validateAuthForCron throws EAUTHCRON with
a remediation message pointing to `claude setup-token` or ANTHROPIC_API_KEY.
Both runner (subprocess invoker) and claudeJsonPath (~/.claude.json) are
dependency-injected. Tests stub them — no real subprocess spawn, no home-
directory reads.
15/15 tests pass: precedence, env-var detection, onboarded subscription,
non-onboarded fallback, validateAuthForCron throw paths.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Foundation lib for v1.12.0 cron rewrite skill-tree backup/restore.
Zero dependencies. Uses fs.cpSync (recursive + preserveTimestamps) without
dereference (Node 22.17.x regression) and without filter (Windows symlink-
type bug).
- backupDir(srcDir, backupRoot, opts) → {backupPath, retentionDays, restore()}
- Backup-id format YYYY-MM-DDTHH-MM-SS (filesystem-safe; no colons)
- .backup-meta.json sentinel written as first action inside backupPath
- restore() writes .rollback-in-progress at backupRoot BEFORE rmSync+cpSync
so a crashed restore leaves the sentinel for the next run to detect
- detectStaleRollback(backupRoot) — boolean predicate over sentinel
- cleanupOldBackups(backupRoot, retentionDays) — 3-step age resolution:
meta.created_at → dir mtime → skip-with-warning (never delete a dir
whose age cannot be established)
12/12 tests pass: timestamp format, content round-trip, sentinel lifecycle,
retention, mtime fallback, unparseable-meta skip, missing-root no-op.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Foundation lib for v1.12.0 cron rewrite. Atomic exclusive create via
fs.writeFileSync('wx'); on EEXIST resolves staleness with OR semantics:
stale if PID is dead OR mtime exceeds threshold. Either alone breaks the
lock — handles SIGKILL orphans (mtime), PID-reuse races (mtime), and
crashed-then-replaced runs (PID).
- acquireLock(lockPath, opts) → {lockPath, release()}
- staleThresholdMs default 1h; refreshIntervalMs opt-in for long runs
- registerCleanup default true (exit/SIGINT/SIGTERM/SIGHUP/uncaughtException)
- isPidAlive uses kill(pid, 0) with EPERM-as-alive nuance
12/12 tests pass: PID liveness, fixture concurrency, idempotent release,
stale variants (dead+old, live+old, fresh+live), staleThresholdMs honored.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Pure auth-mode-aware cost estimator for v1.12.0 cron pre-flight.
Heuristic: critical+high files only (medium/low excluded per brief);
3000 input + 1500 output tokens per file at Sonnet pricing
($3/M in, $15/M out).
Auth-mode behavior:
- api-key: numeric usd, kvote_warn off (subject to dollar-cap)
- long-oauth, subscription-browser-only:
usd null, kvote_warn on (quota, no dollar billing)
- unauthenticated/missing: best-effort api-key estimate
11/11 tests pass; covers both billing modes plus token-math
invariance across auth-mode (auth only affects dollar-field, not tokens).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Foundation lib for status-fil + lock-fil writes in v1.12.0 cron rewrite.
Pattern: writeFileSync to <path>.tmp.<pid>.<random> then renameSync to
target. Defends against half-written files; readers either see the
previous version or the new one, never a partial.
- atomicWriteSync(path, content) — string or Buffer
- atomicWriteJson(path, obj) — 2-space indent, trailing newline
- Windows EEXIST/EPERM defensive fallback (unlink target + rename)
- Best-effort tmp cleanup on writeFileSync failure
- crypto.randomInt(0, 2**32) two-arg form (unambiguous across Node)
9/9 tests pass including 50-way concurrent-write fuzzer (async-aware
withTmp helper).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
First foundation lib for v1.12.0 auto-KB-update. Resolves per-OS paths:
- macOS: ~/Library/{Caches,Logs,Application Support}/<app>/
- Linux: XDG_CACHE_HOME / XDG_STATE_HOME with ~/.cache, ~/.local/state fallbacks
- Windows: %LOCALAPPDATA%\<app>\{Cache,Logs,State}
Plus getBackupDir(pluginRoot) → <pluginRoot>/.kb-backup (gitignored).
All four functions auto-mkdir target. Dependency-injection via opts
({platform, homedir, env}) makes the lib pure-testable; 13/13 tests
pass under tmpdir isolation without touching real ~/ paths.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Remove file limit (was 10, now processes all critical+high+medium)
- Increase max-turns to 200 and timeout to 60min
- Add medium priority to update filter
- Update README KB note to reflect automated weekly updates
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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>
Adds a zero-dependency Node.js pipeline that polls Microsoft Learn sitemaps
weekly to detect when source documentation changes. Replaces the broken
mtime-based staleness check (all files had identical mtime after release).
Components:
- build-registry.mjs: extracts 1342 URLs from 387 reference files
- poll-sitemaps.mjs: streams ~18 child sitemaps, matches against registry
- report-changes.mjs: prioritized change report (critical/high/medium/low)
- discover-new-urls.mjs: finds relevant new MS Learn pages not yet covered
- run-weekly-update.mjs: orchestrator with --force/--discover/--dry-run
Integration:
- session-start hook reads change-report.json instead of broken mtime check
- hook triggers background poll if >7 days since last check
- generate-skills --update reads change report for targeted MCP updates
Current stats: 69% match rate (924/1342 URLs tracked via sitemaps).
~31% unmatched due to Microsoft URL restructuring (ai-foundry/openai paths).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>