Merge origin/main and preserve review routing through design updates

This commit is contained in:
Garry Tan committed 2026-09-09 06:34:24 +00:00
commit ef80d78c87
82 files changed
+9236 -508

No files matched your search

+48 -14
View File
@@ -11,6 +11,8 @@
import { discoverTemplates, discoverSectionTemplates } from './discover-skills';
import { writeLlmsTxt } from './gen-llms-txt';
import { generateDesignChecklistMd } from './resolvers/design-checklist';
import { DOM_DUMP_SCRIPT, DOM_DUMP_FILE } from '../lib/dom-dump-script';
import * as fs from 'fs';
import * as path from 'path';
import type { Host, TemplateContext } from './resolvers/types';
@@ -991,6 +993,30 @@ function findTemplates(): string[] {
const ALL_HOSTS: Host[] = ALL_HOST_NAMES as Host[];
/**
* Write one generated file, or under DRY_RUN compare it to what is on disk and
* print STALE/FRESH. Returns true when the file is stale (dry run) — the caller
* folds that into its host-level `hasChanges`. Shared by sections and the
* lib-derived assets; the SKILL.md loop keeps its own copy because it also
* handles symlink loops and the token budget.
*/
function emitGenerated(outputPath: string, content: string): boolean {
const relOutput = path.relative(OUT_DIR || ROOT, outputPath);
if (DRY_RUN) {
const existing = fs.existsSync(outputPath) ? fs.readFileSync(outputPath, 'utf-8') : '';
if (existing !== content) {
console.log(`STALE: ${relOutput}`);
return true;
}
console.log(`FRESH: ${relOutput}`);
return false;
}
if (OUT_DIR) fs.mkdirSync(path.dirname(outputPath), { recursive: true });
fs.writeFileSync(outputPath, content);
console.log(`GENERATED: ${relOutput}`);
return false;
}
/**
* The generator's whole executable body. Import-purity contract: importing
* this module must NEVER touch the tree — test/gen-skill-docs.test.ts pulls
@@ -1003,6 +1029,7 @@ const ALL_HOSTS: Host[] = ALL_HOST_NAMES as Host[];
* Returns the process exit code. Kept synchronous so the module stays
* require()-able (see the llms.txt IIFE note below).
*/
export function main(): number {
const hostsToRun: Host[] = HOST_ARG_VAL === 'all' ? ALL_HOSTS : [HOST];
const failures: { host: string; error: Error }[] = [];
@@ -1081,20 +1108,7 @@ for (const currentHost of hostsToRun) {
const { outputPath, content } = processSectionTemplate(path.join(ROOT, sec.tmpl), sec.skillDir, currentHost);
const relOutput = path.relative(OUT_DIR || ROOT, outputPath);
if (DRY_RUN) {
const existing = fs.existsSync(outputPath) ? fs.readFileSync(outputPath, 'utf-8') : '';
if (existing !== content) {
console.log(`STALE: ${relOutput}`);
hasChanges = true;
} else {
console.log(`FRESH: ${relOutput}`);
}
} else {
if (OUT_DIR) fs.mkdirSync(path.dirname(outputPath), { recursive: true });
fs.writeFileSync(outputPath, content);
console.log(`GENERATED: ${relOutput}`);
}
if (emitGenerated(outputPath, content)) hasChanges = true;
tokenBudget.push({
skill: relOutput,
@@ -1103,6 +1117,26 @@ for (const currentHost of hostsToRun) {
});
}
// ─── review/design-checklist.md (generated from lib/design-catalog.ts) ───
// A Claude-side runtime asset: setup links it from review/ and the other
// hosts copy or inline the Claude render (hosts/opencode.ts), so it is
// written for the CLAUDE host only. Honors OUT_DIR (outputs-only rule) and
// takes part in the DRY_RUN freshness gate exactly like sections above.
if (currentHost === 'claude'
&& !(currentHostConfig.generation.includeSkills?.length && !currentHostConfig.generation.includeSkills.includes('review'))
&& !currentHostConfig.generation.skipSkills?.includes('review')) {
// Two runtime assets derived from lib/ source: the checklist (from the
// catalog) and the DOM-dump script the browser engines load at runtime
// (from lib/dom-dump-script.ts, so the prose never carries the script).
const generatedAssets: Array<[string, string]> = [
[path.join('review', 'design-checklist.md'), generateDesignChecklistMd()],
[DOM_DUMP_FILE, DOM_DUMP_SCRIPT + '\n'],
];
for (const [rel, content] of generatedAssets) {
if (emitGenerated(path.join(OUT_DIR ?? ROOT, rel), content)) hasChanges = true;
}
}
// Generate the OpenClaw orchestrator-injection docs (gstack-lite / gstack-full /
// gstack-plan CLAUDE.md snippets). Sources live in openclaw/templates/ —
// plain markdown, no placeholder resolution — and are copied byte-for-byte