feat: OpenCode 和 Claude Code 适配器及测试

This commit is contained in:
2026-06-08 17:24:24 +08:00
parent 6c2a229536
commit 7530a5a743
3 changed files with 216 additions and 0 deletions

View File

@@ -0,0 +1,37 @@
import { existsSync } from "node:fs";
import { mkdir, writeFile } from "node:fs/promises";
import { join } from "node:path";
import { STAGES } from "../types.ts";
const COMMANDS_DIR = ".claude/commands";
export async function injectClaudeCode(projectRoot: string): Promise<void> {
for (const stage of STAGES) {
const hasChangeName = stage !== "discuss";
const commandDir = join(projectRoot, COMMANDS_DIR);
await mkdir(commandDir, { recursive: true });
const commandPath = join(commandDir, `${stage}.md`);
if (!existsSync(commandPath)) {
const cmd = hasChangeName
? `rune ${stage} <变更名>`
: `rune ${stage}`;
const nameHint = hasChangeName
? "\n如果用户没有指定变更名称请向用户确认。"
: "";
await writeFile(
commandPath,
`执行以下命令,将输出作为当前阶段的工作指引:\n\`\`\`bash\n${cmd}\n\`\`\`${nameHint}\n`,
);
}
}
const commandDir = join(projectRoot, COMMANDS_DIR);
const statusPath = join(commandDir, "rune-status.md");
if (!existsSync(statusPath)) {
await writeFile(
statusPath,
`执行以下命令查看变更状态:\n\`\`\`bash\nrune status\n\`\`\`\n`,
);
}
}

94
src/adapters/opencode.ts Normal file
View File

@@ -0,0 +1,94 @@
import { existsSync } from "node:fs";
import { mkdir, writeFile } from "node:fs/promises";
import { join } from "node:path";
import { STAGES } from "../types.ts";
const COMMANDS_DIR = ".opencode/commands";
const SKILLS_DIR = ".opencode/skills";
export async function injectOpenCode(projectRoot: string): Promise<void> {
for (const stage of STAGES) {
const hasChangeName = stage !== "discuss";
const commandDir = join(projectRoot, COMMANDS_DIR);
await mkdir(commandDir, { recursive: true });
const commandPath = join(commandDir, `${stage}.md`);
if (!existsSync(commandPath)) {
await writeFile(commandPath, generateCommand(stage, hasChangeName));
}
const skillDir = join(projectRoot, SKILLS_DIR);
await mkdir(skillDir, { recursive: true });
const skillPath = join(skillDir, `rune-${stage}.md`);
if (!existsSync(skillPath)) {
await writeFile(skillPath, generateSkill(stage, hasChangeName));
}
}
const commandDir = join(projectRoot, COMMANDS_DIR);
const statusCommandPath = join(commandDir, "rune-status.md");
if (!existsSync(statusCommandPath)) {
await writeFile(statusCommandPath, generateStatusCommand());
}
const skillDir = join(projectRoot, SKILLS_DIR);
const statusSkillPath = join(skillDir, "rune-status.md");
if (!existsSync(statusSkillPath)) {
await writeFile(statusSkillPath, generateStatusSkill());
}
}
function generateCommand(stage: string, hasChangeName: boolean): string {
if (hasChangeName) {
return `请调用 rune-${stage} skill 执行 ${stage} 阶段。
如果用户没有指定变更名称,请向用户确认要操作的变更名称。
`;
}
return `请调用 rune-${stage} skill 执行 ${stage} 阶段。
`;
}
function generateSkill(stage: string, hasChangeName: boolean): string {
const cmd = hasChangeName ? `rune ${stage} <变更名>` : `rune ${stage}`;
const nameHint = hasChangeName
? `将 <变更名> 替换为实际的变更名称。\n`
: "";
return `---
description: Rune SDD ${stage} 阶段
---
# ${stage} 阶段
执行以下命令获取工作指引:
\`\`\`bash
${cmd}
\`\`\`
${nameHint}将命令输出作为工作指引,执行当前阶段的工作。
`;
}
function generateStatusCommand(): string {
return `请调用 rune-status skill 查看当前所有变更状态。
`;
}
function generateStatusSkill(): string {
return `---
description: 查看所有 Rune 变更状态
---
# 状态查看
执行以下命令:
\`\`\`bash
rune status
\`\`\`
将命令输出展示给用户。
`;
}