d68f003000
CI / Change detection (push) Has been cancelled
CI / Version drift (push) Has been cancelled
CI / Lint (push) Has been cancelled
CI / Workflow RLM cache (push) Has been cancelled
CI / Test (macos-latest) (push) Has been cancelled
CI / Test (ubuntu-latest) (push) Has been cancelled
CI / Test (windows-latest) (push) Has been cancelled
CI / npm wrapper smoke (push) Has been cancelled
CI / Mobile runtime smoke (push) Has been cancelled
CI / Workflow lint (push) Has been cancelled
CI / Documentation (push) Has been cancelled
Web Frontend / Lint & Type Check (push) Failing after 1s
Auto-close harvested PRs / close (push) Failing after 1s
cargo-deny / cargo-deny (bans licenses sources) (push) Failing after 1s
Security audit / cargo-audit (push) Failing after 1s
Sync to CNB / sync (push) Failing after 1s
Web Frontend / Deploy to Cloudflare (push) Waiting to run
cargo-deny / cargo-deny (advisories) (push) Failing after 3s
88 lines
3.2 KiB
JavaScript
88 lines
3.2 KiB
JavaScript
#!/usr/bin/env node
|
|
/**
|
|
* derive-facts.mjs — extract mechanical facts from the parent repo and write
|
|
* them as a typed TS module. Run as `prebuild`. The same logic also runs in
|
|
* the content-drift cron against raw.githubusercontent.com so the deployed
|
|
* worker can detect repo→site drift between deploys.
|
|
*
|
|
* This script delegates all derivation logic to facts-lib.mjs so that
|
|
* check-facts.mjs can reuse the same code for the CI drift gate.
|
|
*/
|
|
import { writeFileSync, readFileSync, existsSync } from "node:fs";
|
|
import { dirname, resolve } from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
import { buildFacts } from "./facts-lib.mjs";
|
|
|
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
const target = resolve(__dirname, "..", "lib", "facts.generated.ts");
|
|
|
|
const out = buildFacts();
|
|
|
|
// Preserve the committed `generatedAt` when every *checked* fact is unchanged,
|
|
// so a clean rebuild doesn't dirty the tracked file on every run. The drift
|
|
// gate (check-facts.mjs) ignores generatedAt + latestRelease; we mirror that
|
|
// volatile set here. Only when a real fact changes do we stamp a fresh time.
|
|
const VOLATILE = new Set(["generatedAt", "latestRelease"]);
|
|
function readCommittedFacts() {
|
|
if (!existsSync(target)) return null;
|
|
const src = readFileSync(target, "utf-8");
|
|
const m = src.match(/export const FACTS\s*:\s*\w+\s*=\s*([\s\S]*?);?\s*$/);
|
|
if (!m) return null;
|
|
try {
|
|
return JSON.parse(m[1]);
|
|
} catch {
|
|
return null;
|
|
}
|
|
}
|
|
const committed = readCommittedFacts();
|
|
if (committed && typeof committed.generatedAt === "string") {
|
|
const sameChecked = Object.keys(out).every(
|
|
(k) => VOLATILE.has(k) || JSON.stringify(out[k]) === JSON.stringify(committed[k]),
|
|
);
|
|
if (sameChecked) out.generatedAt = committed.generatedAt;
|
|
}
|
|
|
|
// latestRelease is intentionally null at build time — populated at runtime by the drift cron.
|
|
const RUNTIME_ONLY = new Set(["latestRelease"]);
|
|
const missing = Object.entries(out).filter(
|
|
([k, v]) =>
|
|
k !== "generatedAt" &&
|
|
!RUNTIME_ONLY.has(k) &&
|
|
(v == null || (Array.isArray(v) && v.length === 0)),
|
|
);
|
|
if (missing.length > 0) {
|
|
console.warn("[derive-facts] missing values:", missing.map(([k]) => k).join(", "));
|
|
}
|
|
|
|
|
|
const ts = `// AUTO-GENERATED by web/scripts/derive-facts.mjs at prebuild.
|
|
// DO NOT EDIT — re-run \`npm run prebuild\` (or just \`npm run build\`) after changing the parent repo.
|
|
// To override at runtime, write the same shape to KV under key "facts:current".
|
|
|
|
export interface ProviderFact { id: string; label: string; env: string }
|
|
|
|
export interface RepoFacts {
|
|
generatedAt: string;
|
|
version: string | null;
|
|
crates: string[];
|
|
sandboxBackends: string[];
|
|
providers: ProviderFact[];
|
|
defaultModel: string | null;
|
|
nodeEngines: string | null;
|
|
toolCount: number | null;
|
|
license: string | null;
|
|
latestRelease: string | null;
|
|
}
|
|
|
|
export const FACTS: RepoFacts = ${JSON.stringify(out, null, 2)};
|
|
`;
|
|
|
|
writeFileSync(target, ts);
|
|
console.log(`[derive-facts] wrote ${target}`);
|
|
console.log(
|
|
`[derive-facts] version=${out.version} crates=${out.crates.length} ` +
|
|
`providers=${out.providers.length} sandboxes=${out.sandboxBackends.length} ` +
|
|
`default-model=${out.defaultModel} node=${out.nodeEngines} ` +
|
|
`tools=${out.toolCount} license=${out.license}`,
|
|
);
|