- Fix #1991 crash: optional chaining for task-history sessionID access - Fix #1992 think-mode: add antigravity entries to HIGH_VARIANT_MAP - Fix #1949 Copilot premium misattribution: use createInternalAgentTextPart - Fix #1982 load_skills: pass directory to discoverSkills for project-level skills - Fix command priority: sort scopePriority before .find(), project-first return - Fix Google provider transform: apply in userFallbackModels path - Fix ralph-loop TUI: optional chaining for event handler - Fix runtime-fallback: unify dual fallback engines, remove HTTP 400 from retry, fix pendingFallbackModel stuck state, add priority gate to skip model-fallback when runtime-fallback is active - Fix Prometheus task system: exempt from todowrite/todoread deny - Fix background_output: default full_session to true - Remove orphan hooks: hashline-edit-diff-enhancer (redundant with hashline_edit built-in diff), task-reminder (dead code) - Remove orphan config entries: 3 stale hook names from Zod schema - Fix disabled_hooks schema: accept arbitrary strings for forward compatibility - Register json-error-recovery hook in tool-guard pipeline - Add disabled_hooks gating for question-label-truncator, task-resume-info, claude-code-hooks - Update test expectations to match new behavior
86 lines
3.0 KiB
TypeScript
86 lines
3.0 KiB
TypeScript
import { existsSync, readdirSync, readFileSync } from "fs"
|
|
import { basename, join } from "path"
|
|
import { parseFrontmatter, sanitizeModelField, getOpenCodeConfigDir } from "../../shared"
|
|
import type { CommandFrontmatter } from "../../features/claude-code-command-loader/types"
|
|
import { isMarkdownFile } from "../../shared/file-utils"
|
|
import { getClaudeConfigDir } from "../../shared"
|
|
import { loadBuiltinCommands } from "../../features/builtin-commands"
|
|
import type { CommandInfo, CommandMetadata, CommandScope } from "./types"
|
|
|
|
function discoverCommandsFromDir(commandsDir: string, scope: CommandScope): CommandInfo[] {
|
|
if (!existsSync(commandsDir)) return []
|
|
|
|
const entries = readdirSync(commandsDir, { withFileTypes: true })
|
|
const commands: CommandInfo[] = []
|
|
|
|
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 isOpencodeSource = scope === "opencode" || scope === "opencode-project"
|
|
const metadata: CommandMetadata = {
|
|
name: commandName,
|
|
description: data.description || "",
|
|
argumentHint: data["argument-hint"],
|
|
model: sanitizeModelField(data.model, isOpencodeSource ? "opencode" : "claude-code"),
|
|
agent: data.agent,
|
|
subtask: Boolean(data.subtask),
|
|
}
|
|
|
|
commands.push({
|
|
name: commandName,
|
|
path: commandPath,
|
|
metadata,
|
|
content: body,
|
|
scope,
|
|
})
|
|
} catch {
|
|
continue
|
|
}
|
|
}
|
|
|
|
return commands
|
|
}
|
|
|
|
export function discoverCommandsSync(directory?: string): CommandInfo[] {
|
|
const configDir = getOpenCodeConfigDir({ binary: "opencode" })
|
|
const userCommandsDir = join(getClaudeConfigDir(), "commands")
|
|
const projectCommandsDir = join(directory ?? process.cwd(), ".claude", "commands")
|
|
const opencodeGlobalDir = join(configDir, "command")
|
|
const opencodeProjectDir = join(directory ?? process.cwd(), ".opencode", "command")
|
|
|
|
const userCommands = discoverCommandsFromDir(userCommandsDir, "user")
|
|
const opencodeGlobalCommands = discoverCommandsFromDir(opencodeGlobalDir, "opencode")
|
|
const projectCommands = discoverCommandsFromDir(projectCommandsDir, "project")
|
|
const opencodeProjectCommands = discoverCommandsFromDir(opencodeProjectDir, "opencode-project")
|
|
|
|
const builtinCommandsMap = loadBuiltinCommands()
|
|
const builtinCommands: CommandInfo[] = Object.values(builtinCommandsMap).map((command) => ({
|
|
name: command.name,
|
|
metadata: {
|
|
name: command.name,
|
|
description: command.description || "",
|
|
argumentHint: command.argumentHint,
|
|
model: command.model,
|
|
agent: command.agent,
|
|
subtask: command.subtask,
|
|
},
|
|
content: command.template,
|
|
scope: "builtin",
|
|
}))
|
|
|
|
return [
|
|
...projectCommands,
|
|
...userCommands,
|
|
...opencodeProjectCommands,
|
|
...opencodeGlobalCommands,
|
|
...builtinCommands,
|
|
]
|
|
}
|