fix(auto-slash-command): load skill content via lazyContentLoader and include builtin skills
This commit is contained in:
@@ -10,7 +10,7 @@ import {
|
|||||||
} from "../../shared"
|
} from "../../shared"
|
||||||
import type { CommandFrontmatter } from "../../features/claude-code-command-loader/types"
|
import type { CommandFrontmatter } from "../../features/claude-code-command-loader/types"
|
||||||
import { isMarkdownFile } from "../../shared/file-utils"
|
import { isMarkdownFile } from "../../shared/file-utils"
|
||||||
import { discoverAllSkills, type LoadedSkill } from "../../features/opencode-skill-loader"
|
import { discoverAllSkills, type LoadedSkill, type LazyContentLoader } from "../../features/opencode-skill-loader"
|
||||||
import type { ParsedSlashCommand } from "./types"
|
import type { ParsedSlashCommand } from "./types"
|
||||||
|
|
||||||
interface CommandScope {
|
interface CommandScope {
|
||||||
@@ -32,6 +32,7 @@ interface CommandInfo {
|
|||||||
metadata: CommandMetadata
|
metadata: CommandMetadata
|
||||||
content?: string
|
content?: string
|
||||||
scope: CommandScope["type"]
|
scope: CommandScope["type"]
|
||||||
|
lazyContentLoader?: LazyContentLoader
|
||||||
}
|
}
|
||||||
|
|
||||||
function discoverCommandsFromDir(commandsDir: string, scope: CommandScope["type"]): CommandInfo[] {
|
function discoverCommandsFromDir(commandsDir: string, scope: CommandScope["type"]): CommandInfo[] {
|
||||||
@@ -91,10 +92,15 @@ function skillToCommandInfo(skill: LoadedSkill): CommandInfo {
|
|||||||
},
|
},
|
||||||
content: skill.definition.template,
|
content: skill.definition.template,
|
||||||
scope: "skill",
|
scope: "skill",
|
||||||
|
lazyContentLoader: skill.lazyContent,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function discoverAllCommands(): Promise<CommandInfo[]> {
|
export interface ExecutorOptions {
|
||||||
|
skills?: LoadedSkill[]
|
||||||
|
}
|
||||||
|
|
||||||
|
async function discoverAllCommands(options?: ExecutorOptions): Promise<CommandInfo[]> {
|
||||||
const userCommandsDir = join(getClaudeConfigDir(), "commands")
|
const userCommandsDir = join(getClaudeConfigDir(), "commands")
|
||||||
const projectCommandsDir = join(process.cwd(), ".claude", "commands")
|
const projectCommandsDir = join(process.cwd(), ".claude", "commands")
|
||||||
const opencodeGlobalDir = join(homedir(), ".config", "opencode", "command")
|
const opencodeGlobalDir = join(homedir(), ".config", "opencode", "command")
|
||||||
@@ -105,7 +111,7 @@ async function discoverAllCommands(): Promise<CommandInfo[]> {
|
|||||||
const projectCommands = discoverCommandsFromDir(projectCommandsDir, "project")
|
const projectCommands = discoverCommandsFromDir(projectCommandsDir, "project")
|
||||||
const opencodeProjectCommands = discoverCommandsFromDir(opencodeProjectDir, "opencode-project")
|
const opencodeProjectCommands = discoverCommandsFromDir(opencodeProjectDir, "opencode-project")
|
||||||
|
|
||||||
const skills = await discoverAllSkills()
|
const skills = options?.skills ?? await discoverAllSkills()
|
||||||
const skillCommands = skills.map(skillToCommandInfo)
|
const skillCommands = skills.map(skillToCommandInfo)
|
||||||
|
|
||||||
return [
|
return [
|
||||||
@@ -117,8 +123,8 @@ async function discoverAllCommands(): Promise<CommandInfo[]> {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
async function findCommand(commandName: string): Promise<CommandInfo | null> {
|
async function findCommand(commandName: string, options?: ExecutorOptions): Promise<CommandInfo | null> {
|
||||||
const allCommands = await discoverAllCommands()
|
const allCommands = await discoverAllCommands(options)
|
||||||
return allCommands.find(
|
return allCommands.find(
|
||||||
(cmd) => cmd.name.toLowerCase() === commandName.toLowerCase()
|
(cmd) => cmd.name.toLowerCase() === commandName.toLowerCase()
|
||||||
) ?? null
|
) ?? null
|
||||||
@@ -149,8 +155,13 @@ async function formatCommandTemplate(cmd: CommandInfo, args: string): Promise<st
|
|||||||
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())
|
||||||
|
|
||||||
@@ -169,8 +180,8 @@ export interface ExecuteResult {
|
|||||||
error?: string
|
error?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function executeSlashCommand(parsed: ParsedSlashCommand): Promise<ExecuteResult> {
|
export async function executeSlashCommand(parsed: ParsedSlashCommand, options?: ExecutorOptions): Promise<ExecuteResult> {
|
||||||
const command = await findCommand(parsed.command)
|
const command = await findCommand(parsed.command, options)
|
||||||
|
|
||||||
if (!command) {
|
if (!command) {
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import {
|
|||||||
detectSlashCommand,
|
detectSlashCommand,
|
||||||
extractPromptText,
|
extractPromptText,
|
||||||
} from "./detector"
|
} from "./detector"
|
||||||
import { executeSlashCommand } from "./executor"
|
import { executeSlashCommand, type ExecutorOptions } from "./executor"
|
||||||
import { log } from "../../shared"
|
import { log } from "../../shared"
|
||||||
import {
|
import {
|
||||||
AUTO_SLASH_COMMAND_TAG_OPEN,
|
AUTO_SLASH_COMMAND_TAG_OPEN,
|
||||||
@@ -12,6 +12,7 @@ import type {
|
|||||||
AutoSlashCommandHookInput,
|
AutoSlashCommandHookInput,
|
||||||
AutoSlashCommandHookOutput,
|
AutoSlashCommandHookOutput,
|
||||||
} from "./types"
|
} from "./types"
|
||||||
|
import type { LoadedSkill } from "../../features/opencode-skill-loader"
|
||||||
|
|
||||||
export * from "./detector"
|
export * from "./detector"
|
||||||
export * from "./executor"
|
export * from "./executor"
|
||||||
@@ -20,7 +21,15 @@ export * from "./types"
|
|||||||
|
|
||||||
const sessionProcessedCommands = new Set<string>()
|
const sessionProcessedCommands = new Set<string>()
|
||||||
|
|
||||||
export function createAutoSlashCommandHook() {
|
export interface AutoSlashCommandHookOptions {
|
||||||
|
skills?: LoadedSkill[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createAutoSlashCommandHook(options?: AutoSlashCommandHookOptions) {
|
||||||
|
const executorOptions: ExecutorOptions = {
|
||||||
|
skills: options?.skills,
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"chat.message": async (
|
"chat.message": async (
|
||||||
input: AutoSlashCommandHookInput,
|
input: AutoSlashCommandHookInput,
|
||||||
@@ -52,7 +61,7 @@ export function createAutoSlashCommandHook() {
|
|||||||
args: parsed.args,
|
args: parsed.args,
|
||||||
})
|
})
|
||||||
|
|
||||||
const result = await executeSlashCommand(parsed)
|
const result = await executeSlashCommand(parsed, executorOptions)
|
||||||
|
|
||||||
const idx = output.parts.findIndex((p) => p.type === "text" && p.text)
|
const idx = output.parts.findIndex((p) => p.type === "text" && p.text)
|
||||||
if (idx < 0) {
|
if (idx < 0) {
|
||||||
|
|||||||
@@ -166,10 +166,6 @@ const OhMyOpenCodePlugin: Plugin = async (ctx) => {
|
|||||||
})
|
})
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
const autoSlashCommand = isHookEnabled("auto-slash-command")
|
|
||||||
? createAutoSlashCommandHook()
|
|
||||||
: null;
|
|
||||||
|
|
||||||
const editErrorRecovery = isHookEnabled("edit-error-recovery")
|
const editErrorRecovery = isHookEnabled("edit-error-recovery")
|
||||||
? createEditErrorRecoveryHook(ctx)
|
? createEditErrorRecoveryHook(ctx)
|
||||||
: null;
|
: null;
|
||||||
@@ -239,6 +235,10 @@ const OhMyOpenCodePlugin: Plugin = async (ctx) => {
|
|||||||
skills: mergedSkills,
|
skills: mergedSkills,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const autoSlashCommand = isHookEnabled("auto-slash-command")
|
||||||
|
? createAutoSlashCommandHook({ skills: mergedSkills })
|
||||||
|
: null;
|
||||||
|
|
||||||
const googleAuthHooks = pluginConfig.google_auth !== false
|
const googleAuthHooks = pluginConfig.google_auth !== false
|
||||||
? await createGoogleAntigravityAuthPlugin(ctx)
|
? await createGoogleAntigravityAuthPlugin(ctx)
|
||||||
: null;
|
: null;
|
||||||
|
|||||||
Reference in New Issue
Block a user