mirror of
https://github.com/garrytan/gstack.git
synced 2026-05-06 05:35:46 +02:00
9d891ba521
New composition.ts resolver module that emits prose instructing Claude
to read another skill's SKILL.md and follow it, skipping preamble
sections. Supports optional skip= parameter for additional sections.
Usage: {{INVOKE_SKILL:plan-ceo-review}} or
{{INVOKE_SKILL:plan-ceo-review:skip=Outside Voice}}
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
49 lines
1.8 KiB
TypeScript
49 lines
1.8 KiB
TypeScript
import type { TemplateContext } from './types';
|
|
|
|
/**
|
|
* {{INVOKE_SKILL:skill-name}} — emits prose instructing Claude to read
|
|
* another skill's SKILL.md and follow it, skipping preamble sections.
|
|
*
|
|
* Supports optional skip= parameter for additional sections to skip:
|
|
* {{INVOKE_SKILL:plan-ceo-review:skip=Outside Voice,Design Outside Voices}}
|
|
*/
|
|
export function generateInvokeSkill(ctx: TemplateContext, args?: string[]): string {
|
|
const skillName = args?.[0];
|
|
if (!skillName || skillName === '') {
|
|
throw new Error('{{INVOKE_SKILL}} requires a skill name, e.g. {{INVOKE_SKILL:plan-ceo-review}}');
|
|
}
|
|
|
|
// Parse optional skip= parameter from args[1+]
|
|
const extraSkips = (args?.slice(1) || [])
|
|
.filter(a => a.startsWith('skip='))
|
|
.flatMap(a => a.slice(5).split(','))
|
|
.map(s => s.trim())
|
|
.filter(Boolean);
|
|
|
|
const DEFAULT_SKIPS = [
|
|
'Preamble (run first)',
|
|
'AskUserQuestion Format',
|
|
'Completeness Principle — Boil the Lake',
|
|
'Search Before Building',
|
|
'Contributor Mode',
|
|
'Completion Status Protocol',
|
|
'Telemetry (run last)',
|
|
'Step 0: Detect platform and base branch',
|
|
'Review Readiness Dashboard',
|
|
'Plan File Review Report',
|
|
'Prerequisite Skill Offer',
|
|
'Plan Status Footer',
|
|
];
|
|
|
|
const allSkips = [...DEFAULT_SKIPS, ...extraSkips];
|
|
|
|
return `Read the \`/${skillName}\` skill file at \`${ctx.paths.skillRoot}/${skillName}/SKILL.md\` using the Read tool.
|
|
|
|
**If unreadable:** Skip with "Could not load /${skillName} — skipping." and continue.
|
|
|
|
Follow its instructions from top to bottom, **skipping these sections** (already handled by the parent skill):
|
|
${allSkips.map(s => `- ${s}`).join('\n')}
|
|
|
|
Execute every other section at full depth. When the loaded skill's instructions are complete, continue with the next step below.`;
|
|
}
|