diff --git a/src/commands/init.ts b/src/commands/init.ts index e7587ef..9a77b64 100644 --- a/src/commands/init.ts +++ b/src/commands/init.ts @@ -1,10 +1,12 @@ import { existsSync } from "node:fs"; -import { mkdir, writeFile } from "node:fs/promises"; +import { mkdir, writeFile, readFile, appendFile } from "node:fs/promises"; import { join } from "node:path"; import { CHANGES_DIR, ARCHIVE_DIR, RUNE_DIR, CONFIG_FILE } from "../types.ts"; import { injectOpenCode } from "../adapters/opencode.ts"; import { injectClaudeCode } from "../adapters/claude-code.ts"; import { CommandError } from "../cli/errors.ts"; +import { detectCommandPrefix, getPmPrefix } from "../core/pm.ts"; +import { parse as parseYaml } from "yaml"; const CONFIG_TEMPLATE = `# Rune 配置文件 # @@ -38,11 +40,29 @@ const CONFIG_TEMPLATE = `# Rune 配置文件 # # {{change-name}} 任务清单 `; -export const SUPPORTED_TOOLS: Record Promise> = { +export const SUPPORTED_TOOLS: Record Promise> = { opencode: injectOpenCode, "claude-code": injectClaudeCode, }; +async function ensureMetadataCommand(configPath: string, command: string): Promise { + const content = await readFile(configPath, "utf-8"); + const parsed = parseYaml(content) as { metadata?: { command?: string } } | null; + if (parsed?.metadata?.command) return; + + if (parsed?.metadata) { + const lines = content.split("\n"); + const metaIdx = lines.findIndex((l) => l.trim() === "metadata:"); + if (metaIdx >= 0) { + lines.splice(metaIdx + 1, 0, ` command: "${command}"`); + await writeFile(configPath, lines.join("\n"), "utf-8"); + return; + } + } + + await appendFile(configPath, `\nmetadata:\n command: "${command}"\n`); +} + export async function runInit(projectRoot: string, tools: string[]): Promise { for (const tool of tools) { if (!SUPPORTED_TOOLS[tool]) { @@ -62,7 +82,13 @@ export async function runInit(projectRoot: string, tools: string[]): Promise { expect(existsSync(join(TMP_DIR, ".opencode", "skills", "rune-discuss", "SKILL.md"))).toBe(true); }); - it("重复 init 不覆盖 config.yaml", async () => { + it("重复 init 不覆盖 config.yaml 已有内容", async () => { await runInit(TMP_DIR, ["opencode"]); await writeFile(join(TMP_DIR, ".rune", "config.yaml"), "自定义内容"); await runInit(TMP_DIR, ["opencode"]); const content = await readFile(join(TMP_DIR, ".rune", "config.yaml"), "utf-8"); - expect(content).toBe("自定义内容"); + expect(content).toContain("自定义内容"); }); it("不支持的工具名抛出 CommandError", async () => { @@ -59,4 +59,12 @@ describe("runInit", () => { expect((e as CommandError).message).toContain("不支持的工具: unknown-tool"); } }); + + it("首次 init 时 config.yaml 包含 metadata.command", async () => { + await runInit(TMP_DIR, ["opencode"]); + + const content = await readFile(join(TMP_DIR, ".rune", "config.yaml"), "utf-8"); + expect(content).toContain("metadata:"); + expect(content).toContain("command:"); + }); });