Fixes #255 - Add getClaudeConfigDir() utility function that respects CLAUDE_CONFIG_DIR env var - Update all hardcoded ~/.claude paths to use the new utility - Add comprehensive tests for getClaudeConfigDir() - Maintain backward compatibility with default ~/.claude when env var is not set Files updated: - src/shared/claude-config-dir.ts (new utility) - src/shared/claude-config-dir.test.ts (tests) - src/hooks/claude-code-hooks/config.ts - src/hooks/claude-code-hooks/todo.ts - src/hooks/claude-code-hooks/transcript.ts - src/features/claude-code-command-loader/loader.ts - src/features/claude-code-agent-loader/loader.ts - src/features/claude-code-skill-loader/loader.ts - src/features/claude-code-mcp-loader/loader.ts - src/tools/session-manager/constants.ts - src/tools/slashcommand/tools.ts Co-authored-by: sisyphus-dev-ai <sisyphus-dev-ai@users.noreply.github.com>
94 lines
3.1 KiB
TypeScript
94 lines
3.1 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) {
|
|
result[cmd.name] = cmd.definition
|
|
}
|
|
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)
|
|
}
|