skills.ts 2.2 KB

1234567891011121314151617181920212223242526272829303132333435363738
  1. // Codex 技能的展示 ID 与按 Profile 选择(与 Claude 侧的 providers/claude/skills.ts 对应)
  2. import fs from 'node:fs'
  3. import path from 'node:path'
  4. import { COMMUNITY_SKILL_PLUGIN } from '@agent-server/shared'
  5. import type { SkillMetadata } from './protocol/v2'
  6. /** 服务场景下始终禁用的系统技能:会联网下载或写入 Codex 自身目录 */
  7. export const ALWAYS_DISABLED = new Set(['skill-installer', 'skill-creator', 'plugin-creator'])
  8. /**
  9. * 展示 ID:
  10. * - 系统技能 → codex-system:<name>
  11. * - 从 openai/skills 安装的技能(CODEX_HOME/skills 下有标记文件)→ openai-skills:<name>
  12. * - 本地技能目录与第三方技能目录(extraRoots,Codex 按 plugin.json 加了前缀)→ 原样,如 agent-skills:report-conventions
  13. * - 其他用户技能 → codex-user:<name>
  14. */
  15. export function skillDisplayId(s: Pick<SkillMetadata, 'name' | 'scope' | 'path'>, codexHome: string): string {
  16. if (s.scope === 'system') return `codex-system:${s.name}`
  17. // Codex 用 SKILL.md 的 name 命名(可能是 "Excel Analysis"),Claude 用目录名;第三方技能统一按目录名,两个引擎 ID 一致
  18. if (s.name.startsWith(`${COMMUNITY_SKILL_PLUGIN}:`)) return `${COMMUNITY_SKILL_PLUGIN}:${path.basename(path.dirname(s.path))}`
  19. if (s.name.includes(':')) return s.name
  20. const managedRoot = path.join(codexHome, 'skills')
  21. const dir = path.dirname(s.path)
  22. if (path.dirname(dir) === managedRoot && fs.existsSync(path.join(dir, '.agent-server.json'))) return `openai-skills:${s.name}`
  23. return `codex-user:${s.name}`
  24. }
  25. /** 计算需要在本次对话中禁用的技能(按路径选择);选择"全部技能"时第三方技能仍需单独勾选 */
  26. export function skillsToDisable(all: SkillMetadata[], selected: string[] | 'all', codexHome: string, localPlugin: string): { path: string; enabled: false }[] {
  27. const wanted = selected === 'all' ? null : new Set(selected.map(s => (s.includes(':') ? s : `${localPlugin}:${s}`)))
  28. return all
  29. .filter(s => {
  30. if (ALWAYS_DISABLED.has(s.name)) return true
  31. const id = skillDisplayId(s, codexHome)
  32. return wanted === null ? id.startsWith(`${COMMUNITY_SKILL_PLUGIN}:`) : !wanted.has(id)
  33. })
  34. .map(s => ({ path: s.path, enabled: false as const }))
  35. }