-
Notifications
You must be signed in to change notification settings - Fork 4.6k
Expand file tree
/
Copy pathinvocation.ts
More file actions
44 lines (40 loc) · 1.81 KB
/
Copy pathinvocation.ts
File metadata and controls
44 lines (40 loc) · 1.81 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
/**
* Command Invocation Styles
*
* How a tool spells an OpenSpec slash command is decided by the file the
* adapter writes, not by a list maintained by hand:
*
* - `.../commands/opsx/<id>.md` — the directory namespaces the command, so the
* tool registers `/opsx:<id>` (Claude Code, Gemini, Crush, ...).
* - `.../commands/opsx-<id>.md` — the filename *is* the command name, so the
* tool registers `/opsx-<id>` (Cursor, GitHub Copilot, OpenCode, ...).
*
* Deriving the style from `getFilePath` keeps generated cross-references and
* onboarding hints in step with the files OpenSpec actually writes. A
* hand-maintained list drifted before: only OpenCode was rewritten when the
* hyphen form was introduced (#727), and Cursor still advertised `/opsx:`
* commands its palette never registered (#1307).
*/
import path from 'path';
import type { ToolCommandAdapter } from './types.js';
export type CommandInvocationStyle = 'namespaced' | 'flat';
/**
* Classifies a generated command file by the name the tool will answer to.
*
* @param commandFilePath - Path returned by an adapter's `getFilePath`
* @returns 'flat' when the filename carries the `opsx-` prefix, otherwise
* 'namespaced'
*/
export function getInvocationStyleForPath(commandFilePath: string): CommandInvocationStyle {
return path.basename(commandFilePath).startsWith('opsx-') ? 'flat' : 'namespaced';
}
/**
* Classifies an adapter by the command files it writes.
*
* @param adapter - The tool-specific command adapter
* @returns The invocation style the tool's command files produce
*/
export function getInvocationStyleForAdapter(adapter: ToolCommandAdapter): CommandInvocationStyle {
// Any command id works: every adapter applies one naming rule to all of them.
return getInvocationStyleForPath(adapter.getFilePath('explore'));
}