mirror of
https://github.com/garrytan/gstack.git
synced 2026-11-02 23:14:33 +01:00
C8: a render given disabled skills drops them from the router (#3018)
The root router named every skill and ends 'When in doubt, invoke the skill', so it routed to skills the user disabled. gen-skill-docs takes --disabled-skills (runGeneration disabledSkills): the router drops their routing rules, keeps the other side of an 'A or B' rule, and names them as disabled. The router and gstack-upgrade cannot be disabled. With no disabled skills the render is byte-identical.
This commit is contained in:
1 parent
3f3655b925
commit
dc7a95a4b4
2 files changed
+79
No files matched your search
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* C8 (#3018): the root router listed every skill and ends "When in doubt,
|
||||
* invoke the skill", so it routed to skills the user disabled. A render given
|
||||
* the install's disabled skills drops their routing rules and names them as
|
||||
* off; the canonical (committed) render is unchanged.
|
||||
*/
|
||||
import { afterAll, describe, expect, test } from 'bun:test';
|
||||
import { spawnSync } from 'child_process';
|
||||
import * as fs from 'fs';
|
||||
import * as os from 'os';
|
||||
import * as path from 'path';
|
||||
import { runGeneration } from '../scripts/gen-skill-docs';
|
||||
|
||||
const ROOT = path.resolve(import.meta.dir, '..');
|
||||
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'gstack-router-disabled-'));
|
||||
afterAll(() => fs.rmSync(tmp, { recursive: true, force: true }));
|
||||
|
||||
async function router(host: 'claude' | 'codex', disabledSkills?: string[]) {
|
||||
const out = fs.mkdtempSync(path.join(tmp, `${host}-`));
|
||||
const r = await runGeneration({ host, outputRoot: out, disabledSkills });
|
||||
expect(r.exitCode).toBe(0);
|
||||
return fs.readFileSync(host === 'claude' ? path.join(out, 'SKILL.md') : path.join(out, '.agents/skills/gstack/SKILL.md'), 'utf8');
|
||||
}
|
||||
|
||||
describe('C8: disabled skills leave the rendered router', () => {
|
||||
for (const host of ['claude', 'codex'] as const) {
|
||||
test(`${host}: routing rules drop disabled skills and keep the other side of an "A or B" rule`, async () => {
|
||||
const text = await router(host, ['retro', 'gstack-cso', '/careful', 'gstack-upgrade']);
|
||||
expect(text).toContain('Disabled on this install (never invoke or suggest them): `/retro`, `/cso`, `/careful`.');
|
||||
expect(text).not.toMatch(/→ invoke `\/retro`/);
|
||||
expect(text).not.toMatch(/→ invoke `\/cso`/);
|
||||
expect(text).toContain('careful mode → invoke `/guard`');
|
||||
expect(text).toContain('→ invoke `/gstack-upgrade`');
|
||||
expect(text).toContain('→ invoke `/ship`');
|
||||
});
|
||||
|
||||
test(`${host}: no disabled skills renders the canonical router byte for byte`, async () => {
|
||||
expect(await router(host, [])).toBe(await router(host));
|
||||
});
|
||||
}
|
||||
|
||||
test('the CLI flag rejects anything but skill names', () => {
|
||||
const r = spawnSync(process.execPath, ['scripts/gen-skill-docs.ts', '--host', 'claude', '--dry-run', '--disabled-skills', 'retro,$(touch x)'],
|
||||
{ cwd: ROOT, encoding: 'utf8', timeout: 60_000 });
|
||||
expect(r.status).toBe(1);
|
||||
expect(r.stderr).toContain('--disabled-skills takes skill names');
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user