From 2cf0d294ee27f60fbf0bab991a18746a397b2b9f Mon Sep 17 00:00:00 2001 From: Harlan Wilton Date: Wed, 7 Oct 2026 13:20:01 +1100 Subject: [PATCH 1/2] feat(skills): add batch 3 package Skill rules from five runs Five direct runs (@nuxtjs/robots, @nuxt/scripts, @unhead/vue, which-nuxt, retriv) and their independent reviews found the same gaps. Every run hand-wrote a code-block extractor. Most review findings came from prose claims, which the Skill never called examples. One run tested npm latest (1.x) while the branch published 2.0 betas. Node fetch dropped the Host header the robots run needed. Reviewers had no definition of the three finding levels. Add extract-blocks.mjs, --header and response headers to serve-fixture, an internal-package gate, the branch version rule, prose-claim and failure-input checks, and defined review levels. The Harness requests now state the Skillgen output shape and keep fixtures out of the output. --- .../harness/test/unit/extract-blocks.test.ts | 75 +++++++++++++++ .../harness/test/unit/serve-fixture.test.ts | 21 +++++ skills/generate-package-skill/SKILL.md | 42 +++++++-- .../assets/harness-request.md | 3 +- .../scripts/extract-blocks.mjs | 94 +++++++++++++++++++ .../scripts/serve-fixture.mjs | 62 ++++++++---- skills/review-skill/SKILL.md | 17 +++- skills/review-skill/assets/harness-request.md | 3 +- 8 files changed, 283 insertions(+), 34 deletions(-) create mode 100644 packages/harness/test/unit/extract-blocks.test.ts create mode 100644 skills/generate-package-skill/scripts/extract-blocks.mjs diff --git a/packages/harness/test/unit/extract-blocks.test.ts b/packages/harness/test/unit/extract-blocks.test.ts new file mode 100644 index 00000000..b8d56d3d --- /dev/null +++ b/packages/harness/test/unit/extract-blocks.test.ts @@ -0,0 +1,75 @@ +import { spawnSync } from 'node:child_process' +import { mkdtemp, readFile, rm, writeFile } from 'node:fs/promises' +import { tmpdir } from 'node:os' +import { join, resolve } from 'node:path' + +const script = resolve(import.meta.dirname, '../../../../skills/generate-package-skill/scripts/extract-blocks.mjs') + +const skill = [ + '# Example', + '', + '```ts', + '// server/api/search.ts', + 'export default defineEventHandler(() => fetch(\'https://example.com/api\'))', + '```', + '', + '````md', + '```ts', + 'nested', + '```', + '````', + '', + '```vue', + '', + '', + '```', + '', + '```sh', + 'pnpm add retriv', + '```', + '', + '```ts', + '// ../outside.ts', + 'export {}', + '```', + '', +].join('\n') + +describe('extract-blocks script', () => { + let dir: string + + beforeEach(async () => { + dir = await mkdtemp(join(tmpdir(), 'extract-blocks-')) + await writeFile(join(dir, 'SKILL.md'), skill) + }) + + afterEach(async () => { + await rm(dir, { recursive: true, force: true }) + }) + + it('writes each block to its own directory under the path its first line names', async () => { + const out = join(dir, 'blocks') + const run = spawnSync(process.execPath, [script, join(dir, 'SKILL.md'), out, '--replace', 'https://example.com=http://localhost:4000'], { encoding: 'utf8' }) + + expect(await readFile(join(out, '1/server/api/search.ts'), 'utf8')).toBe('// server/api/search.ts\nexport default defineEventHandler(() => fetch(\'http://localhost:4000/api\'))\n') + expect(await readFile(join(out, '2/block.md'), 'utf8')).toBe('```ts\nnested\n```\n') + expect(await readFile(join(out, '3/app/pages/index.vue'), 'utf8')).toContain('