mirror of
https://github.com/stablyai/orca.git
synced 2026-09-30 16:02:56 +00:00
116 lines
3.2 KiB
TypeScript
116 lines
3.2 KiB
TypeScript
/**
|
|
* Agents Orca can place an installed skill for.
|
|
*
|
|
* `null` segments mean the agent reads the canonical `.agents/skills` root at
|
|
* that scope, so it needs no placement of its own. Ids match the detection ids
|
|
* in `tui-agent-config.ts` so a detected agent maps straight to a destination.
|
|
*/
|
|
export type SkillInstallProviderId =
|
|
| 'codex'
|
|
| 'claude'
|
|
| 'cursor'
|
|
| 'gemini'
|
|
| 'droid'
|
|
| 'continue'
|
|
| 'trae'
|
|
| 'grok'
|
|
| 'aug'
|
|
|
|
export type SkillInstallProviderDefinition = {
|
|
id: SkillInstallProviderId
|
|
displayName: string
|
|
globalSegments: readonly string[] | null
|
|
workspaceSegments: readonly string[] | null
|
|
}
|
|
|
|
export const SKILL_INSTALL_PROVIDERS: readonly SkillInstallProviderDefinition[] = [
|
|
// Why: Codex reads the canonical .agents/skills root at both scopes.
|
|
{
|
|
id: 'codex',
|
|
displayName: 'Codex',
|
|
globalSegments: null,
|
|
workspaceSegments: null
|
|
},
|
|
{
|
|
id: 'claude',
|
|
displayName: 'Claude Code',
|
|
globalSegments: ['.claude', 'skills'],
|
|
workspaceSegments: ['.claude', 'skills']
|
|
},
|
|
// Why: Cursor and Gemini read the canonical root inside a project but keep
|
|
// their own home directory, so they only need a placement at global scope.
|
|
{
|
|
id: 'cursor',
|
|
displayName: 'Cursor',
|
|
globalSegments: ['.cursor', 'skills'],
|
|
workspaceSegments: null
|
|
},
|
|
{
|
|
id: 'gemini',
|
|
displayName: 'Gemini CLI',
|
|
globalSegments: ['.gemini', 'skills'],
|
|
workspaceSegments: null
|
|
},
|
|
{
|
|
id: 'droid',
|
|
displayName: 'Droid',
|
|
globalSegments: ['.factory', 'skills'],
|
|
workspaceSegments: ['.factory', 'skills']
|
|
},
|
|
{
|
|
id: 'continue',
|
|
displayName: 'Continue',
|
|
globalSegments: ['.continue', 'skills'],
|
|
workspaceSegments: ['.continue', 'skills']
|
|
},
|
|
{
|
|
id: 'trae',
|
|
displayName: 'Trae',
|
|
globalSegments: ['.trae-cn', 'skills'],
|
|
workspaceSegments: ['.trae', 'skills']
|
|
},
|
|
{
|
|
id: 'grok',
|
|
displayName: 'Grok',
|
|
globalSegments: ['.grok', 'skills'],
|
|
workspaceSegments: ['.grok', 'skills']
|
|
},
|
|
{
|
|
id: 'aug',
|
|
displayName: 'Augment',
|
|
globalSegments: ['.augment', 'skills'],
|
|
workspaceSegments: ['.augment', 'skills']
|
|
}
|
|
]
|
|
|
|
const PROVIDERS_BY_ID = new Map(SKILL_INSTALL_PROVIDERS.map((provider) => [provider.id, provider]))
|
|
|
|
export function isSkillInstallProviderId(value: string): value is SkillInstallProviderId {
|
|
return PROVIDERS_BY_ID.has(value as SkillInstallProviderId)
|
|
}
|
|
|
|
export function skillInstallProvider(
|
|
id: SkillInstallProviderId
|
|
): SkillInstallProviderDefinition | undefined {
|
|
return PROVIDERS_BY_ID.get(id)
|
|
}
|
|
|
|
/** Detected agents Orca can actually place skills for, in registry order. */
|
|
export function installableSkillProviders(
|
|
detectedProviders: readonly string[]
|
|
): SkillInstallProviderDefinition[] {
|
|
const detected = new Set(detectedProviders)
|
|
return SKILL_INSTALL_PROVIDERS.filter((provider) => detected.has(provider.id))
|
|
}
|
|
|
|
/**
|
|
* An explicit choice is authoritative, including agents the target may install
|
|
* later. Removal passes no choice so it can clean every previously used root.
|
|
*/
|
|
export function selectedOrDetectedSkillProviders(
|
|
detectedProviders: readonly string[],
|
|
selectedProviders: readonly string[] | undefined
|
|
): readonly string[] {
|
|
return selectedProviders ?? detectedProviders
|
|
}
|