Merge pull request #709 from Momentum96/fix/skill-lazy-loading

fix(skill-loader): implement eager loading for skills
This commit is contained in:
Kenny 2026-01-12 22:50:31 -05:00 committed by GitHub
commit d9aabb33fd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -63,7 +63,7 @@ async function loadSkillFromPath(
): Promise<LoadedSkill | null> { ): Promise<LoadedSkill | null> {
try { try {
const content = await fs.readFile(skillPath, "utf-8") const content = await fs.readFile(skillPath, "utf-8")
const { data } = parseFrontmatter<SkillMetadata>(content) const { data, body } = parseFrontmatter<SkillMetadata>(content)
const frontmatterMcp = parseSkillMcpConfigFromFrontmatter(content) const frontmatterMcp = parseSkillMcpConfigFromFrontmatter(content)
const mcpJsonMcp = await loadMcpJsonFromDir(resolvedPath) const mcpJsonMcp = await loadMcpJsonFromDir(resolvedPath)
const mcpConfig = mcpJsonMcp || frontmatterMcp const mcpConfig = mcpJsonMcp || frontmatterMcp
@ -73,14 +73,7 @@ async function loadSkillFromPath(
const isOpencodeSource = scope === "opencode" || scope === "opencode-project" const isOpencodeSource = scope === "opencode" || scope === "opencode-project"
const formattedDescription = `(${scope} - Skill) ${originalDescription}` const formattedDescription = `(${scope} - Skill) ${originalDescription}`
const lazyContent: LazyContentLoader = { const templateContent = `<skill-instruction>
loaded: false,
content: undefined,
load: async () => {
if (!lazyContent.loaded) {
const fileContent = await fs.readFile(skillPath, "utf-8")
const { body } = parseFrontmatter<SkillMetadata>(fileContent)
lazyContent.content = `<skill-instruction>
Base directory for this skill: ${resolvedPath}/ Base directory for this skill: ${resolvedPath}/
File references (@path) in this skill are relative to this directory. File references (@path) in this skill are relative to this directory.
@ -90,16 +83,20 @@ ${body.trim()}
<user-request> <user-request>
$ARGUMENTS $ARGUMENTS
</user-request>` </user-request>`
lazyContent.loaded = true
} // RATIONALE: We read the file eagerly to ensure atomic consistency between
return lazyContent.content! // metadata and body. We maintain the LazyContentLoader interface for
}, // compatibility, but the state is effectively eager.
const eagerLoader: LazyContentLoader = {
loaded: true,
content: templateContent,
load: async () => templateContent,
} }
const definition: CommandDefinition = { const definition: CommandDefinition = {
name: skillName, name: skillName,
description: formattedDescription, description: formattedDescription,
template: "", template: templateContent,
model: sanitizeModelField(data.model, isOpencodeSource ? "opencode" : "claude-code"), model: sanitizeModelField(data.model, isOpencodeSource ? "opencode" : "claude-code"),
agent: data.agent, agent: data.agent,
subtask: data.subtask, subtask: data.subtask,
@ -117,7 +114,7 @@ $ARGUMENTS
metadata: data.metadata, metadata: data.metadata,
allowedTools: parseAllowedTools(data["allowed-tools"]), allowedTools: parseAllowedTools(data["allowed-tools"]),
mcpConfig, mcpConfig,
lazyContent, lazyContent: eagerLoader,
} }
} catch { } catch {
return null return null