feat(graceful-handoff): 2.0 — migrate to skills/ with disable-model-invocation [skip-docs]
Step 1 of v2.0 plan. Hard cut from commands/ to skills/ per Anthropic recommendation for new plugins. Frontmatter sets disable-model-invocation: true and pins model: claude-sonnet-4-6. Docs (README, CLAUDE.md, root README) deferred to Step 9 per plan.
This commit is contained in:
parent
65c9242160
commit
1a65d8e4d5
12 changed files with 331 additions and 355 deletions
61
plugins/graceful-handoff/tests/skill-structure.test.mjs
Normal file
61
plugins/graceful-handoff/tests/skill-structure.test.mjs
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
// skill-structure.test.mjs — Verifies SKILL.md frontmatter and commands/ deletion.
|
||||
|
||||
import { test } from 'node:test';
|
||||
import { strict as assert } from 'node:assert';
|
||||
import { existsSync, readFileSync } from 'node:fs';
|
||||
import { join, dirname } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
const PLUGIN_ROOT = join(__dirname, '..');
|
||||
|
||||
test('SKILL.md exists at expected path', () => {
|
||||
const skillPath = join(PLUGIN_ROOT, 'skills', 'graceful-handoff', 'SKILL.md');
|
||||
assert.ok(existsSync(skillPath), `SKILL.md missing at ${skillPath}`);
|
||||
});
|
||||
|
||||
test('commands/ directory is deleted (hard cut to skills/)', () => {
|
||||
const commandsDir = join(PLUGIN_ROOT, 'commands');
|
||||
assert.ok(!existsSync(commandsDir), 'commands/ directory still exists — should be deleted in v2.0');
|
||||
});
|
||||
|
||||
test('SKILL.md has disable-model-invocation: true', () => {
|
||||
const skillPath = join(PLUGIN_ROOT, 'skills', 'graceful-handoff', 'SKILL.md');
|
||||
const content = readFileSync(skillPath, 'utf-8');
|
||||
assert.match(content, /^disable-model-invocation: true$/m);
|
||||
});
|
||||
|
||||
test('SKILL.md has model: claude-sonnet-4-6', () => {
|
||||
const skillPath = join(PLUGIN_ROOT, 'skills', 'graceful-handoff', 'SKILL.md');
|
||||
const content = readFileSync(skillPath, 'utf-8');
|
||||
assert.match(content, /^model: claude-sonnet-4-6$/m);
|
||||
});
|
||||
|
||||
test('SKILL.md has Bash sub-scoped allowed-tools', () => {
|
||||
const skillPath = join(PLUGIN_ROOT, 'skills', 'graceful-handoff', 'SKILL.md');
|
||||
const content = readFileSync(skillPath, 'utf-8');
|
||||
assert.match(content, /Bash\(git:\*\)/);
|
||||
assert.match(content, /Bash\(node:\*\)/);
|
||||
});
|
||||
|
||||
test('SKILL.md does not pre-approve curl or wget', () => {
|
||||
const skillPath = join(PLUGIN_ROOT, 'skills', 'graceful-handoff', 'SKILL.md');
|
||||
const content = readFileSync(skillPath, 'utf-8');
|
||||
// Frontmatter only — find the allowed-tools line
|
||||
const allowedToolsLine = content.match(/^allowed-tools:.*$/m);
|
||||
assert.ok(allowedToolsLine, 'allowed-tools line missing');
|
||||
assert.doesNotMatch(allowedToolsLine[0], /\bcurl\b/);
|
||||
assert.doesNotMatch(allowedToolsLine[0], /\bwget\b/);
|
||||
});
|
||||
|
||||
test('SKILL.md body references handoff-pipeline.mjs', () => {
|
||||
const skillPath = join(PLUGIN_ROOT, 'skills', 'graceful-handoff', 'SKILL.md');
|
||||
const content = readFileSync(skillPath, 'utf-8');
|
||||
assert.match(content, /handoff-pipeline\.mjs/);
|
||||
});
|
||||
|
||||
test('SKILL.md body has Tidsbudsjett (time budget) note', () => {
|
||||
const skillPath = join(PLUGIN_ROOT, 'skills', 'graceful-handoff', 'SKILL.md');
|
||||
const content = readFileSync(skillPath, 'utf-8');
|
||||
assert.match(content, /Tidsbudsjett/);
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue