MCPcopy Create free account
hub / github.com/QodeXcli/QodeX / loadCustomCommands

Function loadCustomCommands

src/cli/custom-commands.ts:69–104  ·  view source on GitHub ↗
(cwd: string)

Source from the content-addressed store, hash-verified

67
68/** Inspect both discovery dirs and return the merged command map. Project wins on collisions. */
69export async function loadCustomCommands(cwd: string): Promise<Map<string, CustomCommandSpec>> {
70 const map = new Map<string, CustomCommandSpec>();
71 // Claude Code commands first (lowest precedence) so a user's own QodeX command of
72 // the same name wins (later entries overwrite earlier ones in the map).
73 const claudeDirs = (await claudeCodeCommandDirs(cwd)).map(d => ({ dir: d.dir, origin: 'plugin' as const }));
74 const dirs: Array<{ dir: string; origin: 'project' | 'user' | 'plugin' }> = [
75 ...claudeDirs,
76 { dir: path.join(os.homedir(), '.qodex', 'commands'), origin: 'user' },
77 { dir: path.join(cwd, '.qodex', 'commands'), origin: 'project' },
78 ];
79 for (const { dir, origin } of dirs) {
80 let entries;
81 try {
82 entries = await fs.readdir(dir, { withFileTypes: true });
83 } catch {
84 continue;
85 }
86 for (const ent of entries) {
87 if (!ent.isFile() || !ent.name.endsWith('.md')) continue;
88 const name = ent.name.slice(0, -3);
89 if (!/^[a-zA-Z][\w-]*$/.test(name)) {
90 logger.debug('Skipping custom command with invalid name', { file: ent.name });
91 continue;
92 }
93 const filePath = path.join(dir, ent.name);
94 try {
95 const raw = await fs.readFile(filePath, 'utf-8');
96 const spec = parseSpec(raw, name, filePath, origin);
97 map.set(name, spec);
98 } catch (e: any) {
99 logger.warn('Failed to load custom command', { file: filePath, err: e.message });
100 }
101 }
102 }
103 return map;
104}
105
106/** Parse a Markdown file into a CustomCommandSpec. */
107export function parseSpec(

Callers 2

handleSlashCommandFunction · 0.85

Calls 5

claudeCodeCommandDirsFunction · 0.85
parseSpecFunction · 0.85
debugMethod · 0.80
warnMethod · 0.80
setMethod · 0.45

Tested by

no test coverage detected