Fix: omit allowed-tools from Claude output only (#736)

Keep allowed-tools in shared source for other providers; drop it from the
Claude Code transformer and plugin rewrite so claude -p can activate the
skill. Verify gate now checks parsed frontmatter, not body text.

AI-assisted commit.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Abdul Wahab
2026-09-05 17:11:50 +05:00
co-authored by Cursor
parent 681569712f
commit c8f93c55db
4 changed files with 19 additions and 7 deletions
+1 -1
View File
@@ -156,7 +156,7 @@ export function verifyPluginSkillRewrite(skillMdPath) {
'scripts/lib/plugin-paths.js (issue #523); update SETUP_FALLBACK_TEXT to the new wording.',
);
}
if (/^allowed-tools:/m.test(content)) {
if (parseFrontmatter(content).frontmatter['allowed-tools'] !== undefined) {
throw new Error(
`Plugin rewrite drift: ${skillMdPath} still declares allowed-tools in frontmatter. ` +
'The plugin copy must drop the entire block so non-interactive sessions can activate ' +
+3 -1
View File
@@ -29,7 +29,9 @@ export const PROVIDERS = {
providerTags: ['claude-code', 'claude'],
configDir: '.claude',
displayName: 'Claude Code',
frontmatterFields: ['user-invocable', 'argument-hint', 'license', 'compatibility', 'metadata', 'allowed-tools'],
frontmatterFields: ['user-invocable', 'argument-hint', 'license', 'compatibility', 'metadata'],
// allowed-tools omitted: Claude Code blocks skill activation in non-interactive
// sessions when the field is present (issue #736). Other providers keep it.
agentFormat: 'claude-md',
emitHooks: 'claude',
// Project-local Claude Code hooks live in `.claude/settings.json`.
+3
View File
@@ -3,6 +3,9 @@ name: impeccable
description: "Use when the user wants to design, redesign, shape, critique, audit, polish, clarify, distill, harden, optimize, adapt, animate, colorize, extract, or otherwise improve a frontend interface. Covers websites, landing pages, dashboards, product UI, app shells, components, forms, settings, onboarding, and empty states. Handles UX review, visual hierarchy, information architecture, cognitive load, accessibility, performance, responsive behavior, theming, anti-patterns, typography, fonts, spacing, layout, alignment, color, motion, micro-interactions, UX copy, error states, edge cases, i18n, and reusable design systems or tokens. Also use for bland designs that need to become bolder or more delightful, loud designs that should become quieter, live browser iteration on UI elements, or ambitious visual effects that should feel technically extraordinary. Not for backend-only or non-UI tasks."
argument-hint: "[{{command_hint}}] [target]"
user-invocable: true
allowed-tools:
- Bash(npx impeccable *)
- Bash({{scripts_path}}/impeccable *)
license: Apache 2.0
---
+12 -5
View File
@@ -290,9 +290,16 @@ describe('verifyPluginSkillRewrite', () => {
});
test('fails the build when allowed-tools frontmatter survives the removal', () => {
const p = writeSkill(
'allowed-tools:\n - Bash(npx impeccable *)\n' + rewritePluginMarkdown(goodSkill),
);
const p = writeSkill([
'---',
'name: impeccable',
'allowed-tools:',
' - Bash(npx impeccable *)',
'license: Apache 2.0',
'---',
'',
rewritePluginMarkdown(goodSkill),
].join('\n'));
expect(() => verifyPluginSkillRewrite(p)).toThrow(/allowed-tools/);
});
@@ -317,12 +324,12 @@ describe('verifyPluginSkillRewrite', () => {
});
describe('SKILL.src.md frontmatter', () => {
test('does not declare allowed-tools (issue #736)', () => {
test('keeps allowed-tools in source for non-Claude providers (issue #736)', () => {
const src = fs.readFileSync(
path.join(import.meta.dirname, '../skill/SKILL.src.md'),
'utf-8',
);
const { frontmatter } = parseFrontmatter(src);
expect(frontmatter['allowed-tools']).toBeUndefined();
expect(frontmatter['allowed-tools']).toBeDefined();
});
});