mirror of
https://github.com/garrytan/gstack.git
synced 2026-09-10 06:58:59 +02:00
fix(gen): small config scrubs — openclaw blobs to real files, setup host drift, dead artifacts
- The three openclaw markdown blobs hardcoded inside gen-skill-docs.ts (which silently reverted any hand edit to their tracked outputs on regen) move to openclaw/templates/*.md source files; output shasums byte-identical. - setup's --host allowlists gain cursor + slate — both fully registered hosts with generated output, but './setup --host cursor' exited 1 because two hand-rolled lists in setup had drifted from hosts/index.ts. - scripts/proactive-suggestions.json deleted: 31KB regenerated on every run, read by nobody (the catalog-trim design's reader was never built); its emitter and three determinism tests (which guaranteed a file nothing reads didn't churn) retired with stays-retired pins. - claude/SKILL.md.tmpl deleted: a complete 8.9KB skill that never generated output (directory name collides with the host id 'claude'), in no registry. Recoverable from git if ever wanted under a non-colliding name. - openclaw's frozen extraFields.version '0.15.2.0' stamp dropped; includeSkills: [] no-ops omitted (the generator treats [] as absent); llms.txt 55 -> 54 skills. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
5586f57c62
commit
b60fe8bd64
@@ -269,48 +269,15 @@ Original body content here.
|
||||
});
|
||||
});
|
||||
|
||||
describe('proactive-suggestions.json determinism (regression for v1.45.0.0 CI freshness fail)', () => {
|
||||
test('committed JSON keys are alphabetically sorted', () => {
|
||||
// Reads the actual committed file at scripts/proactive-suggestions.json
|
||||
// and verifies sort order. Catches regressions to non-sorted output.
|
||||
describe('proactive-suggestions.json stays retired', () => {
|
||||
test('the generator no longer emits scripts/proactive-suggestions.json', () => {
|
||||
// The aggregated routing registry was removed (no consumer ever read it).
|
||||
// If someone re-adds the emitter, this pins the decision to delete it —
|
||||
// reintroduce only with an actual consumer, and restore the determinism
|
||||
// tests (sorted keys, root keyed as "gstack", no timestamp fields) that
|
||||
// lived here before.
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const json = JSON.parse(
|
||||
fs.readFileSync(path.join(__dirname, '..', 'scripts', 'proactive-suggestions.json'), 'utf-8'),
|
||||
);
|
||||
const keys = Object.keys(json.skills);
|
||||
const sorted = [...keys].sort();
|
||||
expect(keys).toEqual(sorted);
|
||||
});
|
||||
|
||||
test('root skill is keyed as "gstack" (not the checkout directory name)', () => {
|
||||
// Catches the bug where the root SKILL.md.tmpl's catalog parts get
|
||||
// registered under the directory basename ("seville-v3" in a Conductor
|
||||
// worktree, "gstack" on CI).
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const json = JSON.parse(
|
||||
fs.readFileSync(path.join(__dirname, '..', 'scripts', 'proactive-suggestions.json'), 'utf-8'),
|
||||
);
|
||||
expect(json.skills).toHaveProperty('gstack');
|
||||
// The directory the test runs in must NOT appear as a key.
|
||||
const repoDir = path.basename(path.resolve(__dirname, '..'));
|
||||
if (repoDir !== 'gstack') {
|
||||
expect(json.skills).not.toHaveProperty(repoDir);
|
||||
}
|
||||
});
|
||||
|
||||
test('schema + catalog_mode + note fields are stable', () => {
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const json = JSON.parse(
|
||||
fs.readFileSync(path.join(__dirname, '..', 'scripts', 'proactive-suggestions.json'), 'utf-8'),
|
||||
);
|
||||
expect(json).toHaveProperty('$schema');
|
||||
expect(json.catalog_mode).toBe('trim');
|
||||
expect(typeof json.note).toBe('string');
|
||||
// No timestamp field — those cause flapping CI freshness checks.
|
||||
expect(json).not.toHaveProperty('generated_at');
|
||||
expect(json).not.toHaveProperty('timestamp');
|
||||
expect(fs.existsSync(path.join(__dirname, '..', 'scripts', 'proactive-suggestions.json'))).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -7,10 +7,10 @@
|
||||
* timestamp, a random seed, or any other non-deterministic field into a
|
||||
* generated artifact.
|
||||
*
|
||||
* v1.45.0.0 shipped with a `generated_at` ISO timestamp in
|
||||
* scripts/proactive-suggestions.json that updated every run. CI freshness
|
||||
* checks failed because the committed file's timestamp never matched the
|
||||
* latest gen. Fixed in 43e18af4 — this test pins the contract going forward.
|
||||
* v1.45.0.0 shipped a generated artifact with a `generated_at` ISO timestamp
|
||||
* that updated every run. CI freshness checks failed because the committed
|
||||
* file's timestamp never matched the latest gen. Fixed in 43e18af4 — this
|
||||
* test pins the contract going forward.
|
||||
*
|
||||
* The test pays a small cost (~2 gen-skill-docs invocations, ~3s total) but
|
||||
* catches a class of bugs that's invisible until CI fails.
|
||||
@@ -25,7 +25,6 @@ const REPO_ROOT = path.resolve(import.meta.dir, '..');
|
||||
|
||||
/** Files that gen-skill-docs writes and that must be byte-stable across runs. */
|
||||
const STABLE_OUTPUTS = [
|
||||
'scripts/proactive-suggestions.json',
|
||||
'SKILL.md',
|
||||
'ship/SKILL.md',
|
||||
'plan-ceo-review/SKILL.md',
|
||||
@@ -40,7 +39,6 @@ const STABLE_OUTPUTS = [
|
||||
* non-determinism without paying the cost of snapshotting hundreds of files.
|
||||
*/
|
||||
const STABLE_HOST_ALL_OUTPUTS = [
|
||||
'scripts/proactive-suggestions.json',
|
||||
'SKILL.md',
|
||||
'ship/SKILL.md',
|
||||
'.agents/skills/gstack-ship/SKILL.md',
|
||||
@@ -151,8 +149,8 @@ describe('gen-skill-docs idempotency', () => {
|
||||
throw new Error(
|
||||
`${flapping.length} file(s) changed between two consecutive --host all gen runs:\n` +
|
||||
flapping.map(f => ` - ${f}`).join('\n') +
|
||||
`\nLikely cause: a non-deterministic field leaked into a non-Claude host adapter ` +
|
||||
`(scripts/host-adapters/*.ts). CI freshness checks for that host will flap.`,
|
||||
`\nLikely cause: a non-deterministic field leaked into a non-Claude host's ` +
|
||||
`config or resolver output. CI freshness checks for that host will flap.`,
|
||||
);
|
||||
}
|
||||
}, 300_000); // ~5 min budget for two host-all runs
|
||||
|
||||
@@ -66,7 +66,7 @@ describe('gen-skill-docs --out-dir (B2 render isolation)', () => {
|
||||
}
|
||||
});
|
||||
|
||||
test('global extras (proactive-suggestions.json) are NOT written in out-dir mode', () => {
|
||||
test('retired global extras (proactive-suggestions.json) are not written anywhere', () => {
|
||||
const outDir = fs.mkdtempSync(path.join(os.tmpdir(), 'gstack-out-'));
|
||||
try {
|
||||
const res = spawnSync(
|
||||
@@ -75,8 +75,10 @@ describe('gen-skill-docs --out-dir (B2 render isolation)', () => {
|
||||
{ cwd: ROOT, encoding: 'utf-8', timeout: 120_000 },
|
||||
);
|
||||
expect(res.status).toBe(0);
|
||||
// proactive-suggestions.json lives at a repo path; out-dir mode must skip it.
|
||||
// The proactive-suggestions registry was removed (never had a consumer).
|
||||
// A gen run must not resurrect it in the out-dir or at the repo path.
|
||||
expect(fs.existsSync(path.join(outDir, 'scripts', 'proactive-suggestions.json'))).toBe(false);
|
||||
expect(fs.existsSync(path.join(ROOT, 'scripts', 'proactive-suggestions.json'))).toBe(false);
|
||||
} finally {
|
||||
fs.rmSync(outDir, { recursive: true, force: true });
|
||||
}
|
||||
|
||||
@@ -1733,13 +1733,6 @@ describe('Codex skill validation', () => {
|
||||
expect(fs.existsSync(path.join(AGENTS_DIR, 'gstack-codex', 'SKILL.md'))).toBe(false);
|
||||
});
|
||||
|
||||
test('/claude skill is external-host-only — no Claude-host variant', () => {
|
||||
// Claude host should not get an outside-voice skill that shells into Claude.
|
||||
expect(fs.existsSync(path.join(ROOT, 'claude', 'SKILL.md'))).toBe(false);
|
||||
// Codex/external hosts should get the generated wrapper.
|
||||
expect(fs.existsSync(path.join(AGENTS_DIR, 'gstack-claude', 'SKILL.md'))).toBe(true);
|
||||
});
|
||||
|
||||
test('Codex skill names follow gstack-{name} convention', () => {
|
||||
const codexDirs = fs.readdirSync(AGENTS_DIR);
|
||||
for (const dir of codexDirs) {
|
||||
|
||||
Reference in New Issue
Block a user