Slash commands with arguments were silently failing in OpenCode TUI because command definitions included 'name' and 'argumentHint' fields that don't exist in OpenCode's Command schema. Strip these fields before registration across all command/skill loaders to ensure compatibility. Affected loaders: - builtin commands - claude-code command loader - opencode skill loader - claude-code plugin loader 🤖 GENERATED WITH ASSISTANCE OF [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode)
95 lines
3.2 KiB
TypeScript
95 lines
3.2 KiB
TypeScript
import { existsSync, readdirSync, readFileSync } from "fs"
|
|
import { join, basename } from "path"
|
|
import { parseFrontmatter } from "../../shared/frontmatter"
|
|
import { sanitizeModelField } from "../../shared/model-sanitizer"
|
|
import { isMarkdownFile } from "../../shared/file-utils"
|
|
import { getClaudeConfigDir } from "../../shared"
|
|
import type { CommandScope, CommandDefinition, CommandFrontmatter, LoadedCommand } from "./types"
|
|
|
|
function loadCommandsFromDir(commandsDir: string, scope: CommandScope): LoadedCommand[] {
|
|
if (!existsSync(commandsDir)) {
|
|
return []
|
|
}
|
|
|
|
const entries = readdirSync(commandsDir, { withFileTypes: true })
|
|
const commands: LoadedCommand[] = []
|
|
|
|
for (const entry of entries) {
|
|
if (!isMarkdownFile(entry)) continue
|
|
|
|
const commandPath = join(commandsDir, entry.name)
|
|
const commandName = basename(entry.name, ".md")
|
|
|
|
try {
|
|
const content = readFileSync(commandPath, "utf-8")
|
|
const { data, body } = parseFrontmatter<CommandFrontmatter>(content)
|
|
|
|
const wrappedTemplate = `<command-instruction>
|
|
${body.trim()}
|
|
</command-instruction>
|
|
|
|
<user-request>
|
|
$ARGUMENTS
|
|
</user-request>`
|
|
|
|
const formattedDescription = `(${scope}) ${data.description || ""}`
|
|
|
|
const isOpencodeSource = scope === "opencode" || scope === "opencode-project"
|
|
const definition: CommandDefinition = {
|
|
name: commandName,
|
|
description: formattedDescription,
|
|
template: wrappedTemplate,
|
|
agent: data.agent,
|
|
model: sanitizeModelField(data.model, isOpencodeSource ? "opencode" : "claude-code"),
|
|
subtask: data.subtask,
|
|
argumentHint: data["argument-hint"],
|
|
}
|
|
|
|
commands.push({
|
|
name: commandName,
|
|
path: commandPath,
|
|
definition,
|
|
scope,
|
|
})
|
|
} catch {
|
|
continue
|
|
}
|
|
}
|
|
|
|
return commands
|
|
}
|
|
|
|
function commandsToRecord(commands: LoadedCommand[]): Record<string, CommandDefinition> {
|
|
const result: Record<string, CommandDefinition> = {}
|
|
for (const cmd of commands) {
|
|
const { name: _name, argumentHint: _argumentHint, ...openCodeCompatible } = cmd.definition
|
|
result[cmd.name] = openCodeCompatible as CommandDefinition
|
|
}
|
|
return result
|
|
}
|
|
|
|
export function loadUserCommands(): Record<string, CommandDefinition> {
|
|
const userCommandsDir = join(getClaudeConfigDir(), "commands")
|
|
const commands = loadCommandsFromDir(userCommandsDir, "user")
|
|
return commandsToRecord(commands)
|
|
}
|
|
|
|
export function loadProjectCommands(): Record<string, CommandDefinition> {
|
|
const projectCommandsDir = join(process.cwd(), ".claude", "commands")
|
|
const commands = loadCommandsFromDir(projectCommandsDir, "project")
|
|
return commandsToRecord(commands)
|
|
}
|
|
|
|
export function loadOpencodeGlobalCommands(): Record<string, CommandDefinition> {
|
|
const { homedir } = require("os")
|
|
const opencodeCommandsDir = join(homedir(), ".config", "opencode", "command")
|
|
const commands = loadCommandsFromDir(opencodeCommandsDir, "opencode")
|
|
return commandsToRecord(commands)
|
|
}
|
|
|
|
export function loadOpencodeProjectCommands(): Record<string, CommandDefinition> {
|
|
const opencodeProjectDir = join(process.cwd(), ".opencode", "command")
|
|
const commands = loadCommandsFromDir(opencodeProjectDir, "opencode-project")
|
|
return commandsToRecord(commands)
|
|
}
|