跳转至

OpenCode 支持设计

日期: 2025-11-22 作者: Bot & Jesse 状态: 设计完成,等待实现

概述

使用原生 OpenCode 插件架构为 OpenCode.ai 添加完整的 superpowers 支持,并与现有 Codex 实现共享核心功能。

背景

OpenCode.ai 是一个类似于 Claude Code 和 Codex 的编码代理。之前将 superpowers 移植到 OpenCode 的尝试(PR #93、PR #116)使用了文件复制方式。本设计采用不同方法:使用其 JavaScript/TypeScript 插件系统构建原生 OpenCode 插件,同时与 Codex 实现共享代码。

平台之间的主要差异

  • Claude Code:原生 Anthropic 插件系统 + 基于文件的技能
  • Codex:无插件系统 → bootstrap markdown + CLI 脚本
  • OpenCode:带有事件钩子和自定义工具 API 的 JavaScript/TypeScript 插件

OpenCode 的代理系统

  • 主要代理:Build(默认,完全访问权限)和 Plan(受限,只读)
  • 子代理:General(研究、搜索、多步骤任务)
  • 调用:由主要代理自动分发,或手动 @mention 语法
  • 配置:在 opencode.json 或 ~/.config/opencode/agent/ 中定义自定义代理

架构

高层结构

  1. 共享核心模块 (lib/skills-core.js)
  2. 通用的技能发现和解析逻辑
  3. 同时用于 Codex 和 OpenCode 实现

  4. 平台特定封装

  5. Codex:CLI 脚本 (.codex/superpowers-codex)
  6. OpenCode:插件模块 (.opencode/plugin/superpowers.js)

  7. 技能目录

  8. 核心:~/.config/opencode/superpowers/skills/(或安装位置)
  9. 个人:~/.config/opencode/skills/(遮蔽核心技能)

代码复用策略

从 .codex/superpowers-codex 中提取通用功能到共享模块:

// lib/skills-core.js
module.exports = {
  extractFrontmatter(filePath),      // Parse name + description from YAML
  findSkillsInDir(dir, maxDepth),    // Recursive SKILL.md discovery
  findAllSkills(dirs),                // Scan multiple directories
  resolveSkillPath(skillName, dirs), // Handle shadowing (personal > core)
  checkForUpdates(repoDir)           // Git fetch/status check
};

技能前置元数据格式

当前格式(没有 when_to_use 字段):

---
name: skill-name
description: Use when [condition] - [what it does]; [additional context]
---

OpenCode 插件实现

自定义工具

工具 1:use_skill

将特定技能的内容加载到对话中(等同于 Claude 的 Skill 工具)。

{
  name: 'use_skill',
  description: 'Load and read a specific skill to guide your work',
  schema: z.object({
    skill_name: z.string().describe('Name of skill (e.g., "superpowers:brainstorming")')
  }),
  execute: async ({ skill_name }) => {
    const { skillPath, content, frontmatter } = resolveAndReadSkill(skill_name);
    const skillDir = path.dirname(skillPath);

    return `# ${frontmatter.name}
# ${frontmatter.description}
# Supporting tools and docs are in ${skillDir}
# ============================================

${content}`;
  }
}

工具 2:find_skills

列出所有可用技能及其元数据。

{
  name: 'find_skills',
  description: 'List all available skills',
  schema: z.object({}),
  execute: async () => {
    const skills = discoverAllSkills();
    return skills.map(s =>
      `${s.namespace}:${s.name}
  ${s.description}
  Directory: ${s.directory}
`).join('\n');
  }
}

会话启动钩子

当新会话启动时(session.started 事件):

  1. 注入 using-superpowers 内容
  2. using-superpowers 技能的完整内容
  3. 建立强制工作流

  4. 自动运行 find_skills

  5. 预先显示所有可用技能的完整列表
  6. 包含每个技能的目录

  7. 注入工具映射说明

    **Tool Mapping for OpenCode:**
    When skills reference tools you don't have, substitute:
    - `TodoWrite` → `update_plan`
    - `Task` with subagents → Use OpenCode subagent system (@mention)
    - `Skill` tool → `use_skill` custom tool
    - Read, Write, Edit, Bash → Your native equivalents
    
    **Skill directories contain:**
    - Supporting scripts (run with bash)
    - Additional documentation (read with read tool)
    - Utilities specific to that skill
    

  8. 检查更新(非阻塞)

  9. 带超时的快速 git fetch
  10. 如果有可用更新则通知

插件结构

// .opencode/plugin/superpowers.js
const skillsCore = require('../../lib/skills-core');
const path = require('path');
const fs = require('fs');
const { z } = require('zod');

export const SuperpowersPlugin = async ({ client, directory, $ }) => {
  const superpowersDir = path.join(process.env.HOME, '.config/opencode/superpowers');
  const personalDir = path.join(process.env.HOME, '.config/opencode/skills');

  return {
    'session.started': async () => {
      const usingSuperpowers = await readSkill('using-superpowers');
      const skillsList = await findAllSkills();
      const toolMapping = getToolMappingInstructions();

      return {
        context: `${usingSuperpowers}\n\n${skillsList}\n\n${toolMapping}`
      };
    },

    tools: [
      {
        name: 'use_skill',
        description: 'Load and read a specific skill',
        schema: z.object({
          skill_name: z.string()
        }),
        execute: async ({ skill_name }) => {
          // Implementation using skillsCore
        }
      },
      {
        name: 'find_skills',
        description: 'List all available skills',
        schema: z.object({}),
        execute: async () => {
          // Implementation using skillsCore
        }
      }
    ]
  };
};

文件结构

superpowers/
├── lib/
│   └── skills-core.js           # NEW: Shared skill logic
├── .codex/
│   ├── superpowers-codex        # UPDATED: Use skills-core
│   ├── superpowers-bootstrap.md
│   └── INSTALL.md
├── .opencode/
│   ├── plugin/
│   │   └── superpowers.js       # NEW: OpenCode plugin
│   └── INSTALL.md               # NEW: Installation guide
└── skills/                       # Unchanged

实施计划

第一阶段:重构共享核心

  1. 创建 lib/skills-core.js
  2. 从 .codex/superpowers-codex 中提取 frontmatter 解析逻辑
  3. 提取技能发现逻辑
  4. 提取路径解析逻辑(包含 shadowing 机制)
  5. 更新为仅使用 name 和 description(不再使用 when_to_use)

  6. 更新 .codex/superpowers-codex 以使用共享核心

  7. 从 ../lib/skills-core.js 导入
  8. 移除重复代码
  9. 保留 CLI 包装逻辑

  10. 测试 Codex 实现仍然可用

  11. 验证 bootstrap 命令
  12. 验证 use-skill 命令
  13. 验证 find-skills 命令

第二阶段:构建 OpenCode 插件

  1. 创建 .opencode/plugin/superpowers.js
  2. 从 ../../lib/skills-core.js 导入共享核心
  3. 实现插件函数
  4. 定义自定义工具(use_skill、find_skills)
  5. 实现 session.started 钩子

  6. 创建 .opencode/INSTALL.md

  7. 安装说明
  8. 目录设置
  9. 配置指南

  10. 测试 OpenCode 实现

  11. 验证会话启动时的 bootstrap
  12. 验证 use_skill 工具正常工作
  13. 验证 find_skills 工具正常工作
  14. 验证技能目录可被访问

第三阶段:文档与完善

  1. 更新 README,加入 OpenCode 支持说明
  2. 在主文档中添加 OpenCode 安装说明
  3. 更新 RELEASE-NOTES
  4. 测试 Codex 和 OpenCode 均能正常工作

后续步骤

  1. 创建隔离工作区(使用 git worktrees)
  2. 分支:feature/opencode-support

  3. 在适用处遵循 TDD

  4. 测试共享核心函数
  5. 测试技能发现与解析
  6. 针对两个平台进行集成测试

  7. 增量实施

  8. 第一阶段:重构共享核心 + 更新 Codex
  9. 在继续之前先验证 Codex 仍然正常工作
  10. 第二阶段:构建 OpenCode 插件
  11. 第三阶段:文档与完善

  12. 测试策略

  13. 使用真实的 OpenCode 安装进行手动测试
  14. 验证技能加载、目录、脚本均能正常工作
  15. 并排测试 Codex 和 OpenCode
  16. 验证工具映射正常工作

  17. PR 与合并

  18. 创建包含完整实现的 PR
  19. 在干净环境中测试
  20. 合并到 main

收益

  • 代码复用:技能发现/解析的唯一真源
  • 可维护性:缺陷修复同时适用于两个平台
  • 可扩展性:未来可轻松添加更多平台(Cursor、Windsurf 等)
  • 原生集成:正确使用 OpenCode 的插件系统
  • 一致性:所有平台获得相同的技能体验

本页原文 Markdown:在 AtomGit 查看·内容源自开源项目 su/superpowers