Skill Tracer
Skills › gstack › gstack › gen-ship-goldens.ts

gen-ship-goldens.ts

44 lines · scripts/gen-ship-goldens.ts at 3f79d81

1/**
2 * gen-ship-goldens — refresh the byte-pinned /ship renders under
3 * test/fixtures/golden/ (test/host-config.test.ts compares a fresh render to
4 * them). The claude golden is the tracked ship/SKILL.md; the codex, factory
5 * and agy goldens come from a `--out-dir` render of each host. Registered in
6 * .gstack/generated.json so `gstack-regen check` reports a stale golden
7 * before any remote gate and `gstack-regen write` refreshes it.
8 */
9import { spawnSync } from 'node:child_process';
10import * as fs from 'node:fs';
11import * as os from 'node:os';
12import * as path from 'node:path';
14const ROOT = path.resolve(import.meta.dir, '..');
15const GOLDEN_DIR = path.join(ROOT, 'test', 'fixtures', 'golden');
16const HOSTS: Array<{ host: string; dir: string }> = [
17 { host: 'codex', dir: '.agents' },
18 { host: 'factory', dir: '.factory' },
19 { host: 'agy', dir: '.agy' },
20];
22export function generateShipGoldens(): string[] {
23 const written: string[] = [];
24 const out = fs.mkdtempSync(path.join(os.tmpdir(), 'gstack-ship-goldens-'));
25 try {
26 const copy = (from: string, to: string) => {
27 const bytes = fs.readFileSync(from);
28 const dest = path.join(GOLDEN_DIR, to);
29 if (!fs.existsSync(dest) || !fs.readFileSync(dest).equals(bytes)) { fs.writeFileSync(dest, bytes); written.push(path.relative(ROOT, dest)); }
30 };
31 copy(path.join(ROOT, 'ship', 'SKILL.md'), 'claude-ship-SKILL.md');
32 for (const { host, dir } of HOSTS) {
33 const r = spawnSync('bun', ['run', path.join(ROOT, 'scripts', 'gen-skill-docs.ts'), '--host', host, '--out-dir', out], { cwd: ROOT, encoding: 'utf8', timeout: 180_000 });
34 if (r.status !== 0) throw new Error(`gen-skill-docs --host ${host} --out-dir failed (exit ${r.status}):\n${r.stderr}`);
35 copy(path.join(out, dir, 'skills', 'gstack-ship', 'SKILL.md'), `${host}-ship-SKILL.md`);
36 }
37 } finally { fs.rmSync(out, { recursive: true, force: true }); }
38 return written;
41if (import.meta.main) {
42 const written = generateShipGoldens();
43 console.log(written.length ? `GENERATED: ${written.join(' ')}` : 'ship goldens: fresh');