fix: load skill content via lazyContentLoader in slashcommand tool

- Fix #542: slashcommand tool returns empty content for skills
- Add lazyContentLoader to CommandInfo type
- Load skill content in formatLoadedCommand when content is empty
- Filter non-ultrawork keywords in subagent sessions
This commit is contained in:
YeonGyu-Kim
2026-01-07 01:41:42 +09:00
parent d331b484f9
commit ad44af9d15
3 changed files with 35 additions and 3 deletions

View File

@@ -21,12 +21,37 @@ export function createKeywordDetectorHook(ctx: PluginInput) {
} }
): Promise<void> => { ): Promise<void> => {
const promptText = extractPromptText(output.parts) const promptText = extractPromptText(output.parts)
const detectedKeywords = detectKeywordsWithType(removeCodeBlocks(promptText), input.agent) let detectedKeywords = detectKeywordsWithType(removeCodeBlocks(promptText), input.agent)
if (detectedKeywords.length === 0) { if (detectedKeywords.length === 0) {
return return
} }
// Check if this is a subagent session (has parent)
// Only ultrawork keywords work in subagent sessions
// Other keywords (search, analyze, etc.) only work in main sessions
try {
const sessionInfo = await ctx.client.session.get({ path: { id: input.sessionID } })
const isSubagentSession = !!sessionInfo.data?.parentID
if (isSubagentSession) {
// Filter to only ultrawork keywords in subagent sessions
detectedKeywords = detectedKeywords.filter((k) => k.type === "ultrawork")
if (detectedKeywords.length === 0) {
log(`[keyword-detector] Skipping non-ultrawork keywords in subagent session`, {
sessionID: input.sessionID,
parentID: sessionInfo.data?.parentID,
})
return
}
}
} catch (err) {
log(`[keyword-detector] Failed to get session info, proceeding with all keywords`, {
error: err,
sessionID: input.sessionID,
})
}
const hasUltrawork = detectedKeywords.some((k) => k.type === "ultrawork") const hasUltrawork = detectedKeywords.some((k) => k.type === "ultrawork")
if (hasUltrawork) { if (hasUltrawork) {
log(`[keyword-detector] Ultrawork mode activated`, { sessionID: input.sessionID }) log(`[keyword-detector] Ultrawork mode activated`, { sessionID: input.sessionID })

View File

@@ -80,6 +80,7 @@ function skillToCommandInfo(skill: LoadedSkill): CommandInfo {
}, },
content: skill.definition.template, content: skill.definition.template,
scope: skill.scope, scope: skill.scope,
lazyContentLoader: skill.lazyContent,
} }
} }
@@ -112,8 +113,13 @@ async function formatLoadedCommand(cmd: CommandInfo): Promise<string> {
sections.push("---\n") sections.push("---\n")
sections.push("## Command Instructions\n") sections.push("## Command Instructions\n")
let content = cmd.content || ""
if (!content && cmd.lazyContentLoader) {
content = await cmd.lazyContentLoader.load()
}
const commandDir = cmd.path ? dirname(cmd.path) : process.cwd() const commandDir = cmd.path ? dirname(cmd.path) : process.cwd()
const withFileRefs = await resolveFileReferencesInText(cmd.content || "", commandDir) const withFileRefs = await resolveFileReferencesInText(content, commandDir)
const resolvedContent = await resolveCommandsInText(withFileRefs) const resolvedContent = await resolveCommandsInText(withFileRefs)
sections.push(resolvedContent.trim()) sections.push(resolvedContent.trim())

View File

@@ -1,4 +1,4 @@
import type { LoadedSkill } from "../../features/opencode-skill-loader" import type { LoadedSkill, LazyContentLoader } from "../../features/opencode-skill-loader"
export type CommandScope = "builtin" | "config" | "user" | "project" | "opencode" | "opencode-project" export type CommandScope = "builtin" | "config" | "user" | "project" | "opencode" | "opencode-project"
@@ -17,6 +17,7 @@ export interface CommandInfo {
metadata: CommandMetadata metadata: CommandMetadata
content?: string content?: string
scope: CommandScope scope: CommandScope
lazyContentLoader?: LazyContentLoader
} }
export interface SlashcommandToolOptions { export interface SlashcommandToolOptions {