hamster-wheel-cli 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/ISSUE_TEMPLATE/bug_report.yml +107 -0
- package/.github/ISSUE_TEMPLATE/config.yml +15 -0
- package/.github/ISSUE_TEMPLATE/feature_request.yml +56 -0
- package/.github/workflows/ci-pr.yml +50 -0
- package/.github/workflows/publish.yml +121 -0
- package/.github/workflows/sync-master-to-dev.yml +100 -0
- package/AGENTS.md +20 -0
- package/CHANGELOG.md +12 -0
- package/LICENSE +21 -0
- package/README.md +90 -0
- package/dist/cli.d.ts +6 -0
- package/dist/cli.js +2678 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +80 -0
- package/dist/index.js +2682 -0
- package/dist/index.js.map +1 -0
- package/docs/ai-workflow.md +58 -0
- package/package.json +44 -0
- package/src/ai.ts +173 -0
- package/src/cli.ts +189 -0
- package/src/config.ts +134 -0
- package/src/deps.ts +210 -0
- package/src/gh.ts +228 -0
- package/src/git.ts +285 -0
- package/src/global-config.ts +296 -0
- package/src/index.ts +3 -0
- package/src/logger.ts +122 -0
- package/src/logs-viewer.ts +420 -0
- package/src/logs.ts +132 -0
- package/src/loop.ts +422 -0
- package/src/monitor.ts +291 -0
- package/src/runtime-tracker.ts +65 -0
- package/src/summary.ts +255 -0
- package/src/types.ts +176 -0
- package/src/utils.ts +179 -0
- package/src/webhook.ts +107 -0
- package/tests/deps.test.ts +72 -0
- package/tests/e2e/cli.e2e.test.ts +77 -0
- package/tests/e2e/gh-pr-create.e2e.test.ts +55 -0
- package/tests/e2e/gh-run-list.e2e.test.ts +47 -0
- package/tests/gh-pr-create.test.ts +55 -0
- package/tests/gh-run-list.test.ts +35 -0
- package/tests/global-config.test.ts +52 -0
- package/tests/logger-file.test.ts +56 -0
- package/tests/logger.test.ts +72 -0
- package/tests/logs-viewer.test.ts +57 -0
- package/tests/logs.test.ts +33 -0
- package/tests/prompt.test.ts +20 -0
- package/tests/run-command-stream.test.ts +60 -0
- package/tests/summary.test.ts +58 -0
- package/tests/token-usage.test.ts +33 -0
- package/tests/utils.test.ts +8 -0
- package/tests/webhook.test.ts +89 -0
- package/tsconfig.json +18 -0
- package/tsup.config.ts +18 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/cli.ts","../src/config.ts","../src/utils.ts","../src/global-config.ts","../src/git.ts","../src/logs.ts","../src/logs-viewer.ts","../src/loop.ts","../src/ai.ts","../src/deps.ts","../src/gh.ts","../src/logger.ts","../src/runtime-tracker.ts","../src/summary.ts","../src/webhook.ts","../src/monitor.ts"],"sourcesContent":["export { runCli } from './cli';\nexport { runLoop } from './loop';\nexport type { LoopConfig, AiCliConfig, WorktreeConfig, PrConfig, TestConfig, WebhookConfig } from './types';\n","import { spawn } from 'node:child_process';\nimport { Command } from 'commander';\nimport { buildLoopConfig, CliOptions, defaultNotesPath, defaultPlanPath, defaultWorkflowDoc } from './config';\nimport { applyShortcutArgv, loadGlobalConfig } from './global-config';\nimport { generateBranchName, getCurrentBranch } from './git';\nimport { buildAutoLogFilePath } from './logs';\nimport { runLogsViewer } from './logs-viewer';\nimport { runLoop } from './loop';\nimport { defaultLogger } from './logger';\nimport { runMonitor } from './monitor';\nimport { resolvePath } from './utils';\n\nfunction parseInteger(value: string, defaultValue: number): number {\n const parsed = Number.parseInt(value, 10);\n if (Number.isNaN(parsed)) return defaultValue;\n return parsed;\n}\n\nfunction collect(value: string, previous: string[]): string[] {\n return [...previous, value];\n}\n\nfunction normalizeOptional(value: unknown): string | undefined {\n if (typeof value !== 'string') return undefined;\n const trimmed = value.trim();\n return trimmed.length > 0 ? trimmed : undefined;\n}\n\nfunction hasOption(argv: string[], option: string): boolean {\n return argv.some(arg => arg === option || arg.startsWith(`${option}=`));\n}\n\nfunction buildBackgroundArgs(argv: string[], logFile: string, branchName?: string, injectBranch = false): string[] {\n const rawArgs = argv.slice(1);\n const filtered = rawArgs.filter(arg => !(arg === '--background' || arg.startsWith('--background=')));\n if (!hasOption(filtered, '--log-file')) {\n filtered.push('--log-file', logFile);\n }\n if (injectBranch && branchName && !hasOption(filtered, '--branch')) {\n filtered.push('--branch', branchName);\n }\n return filtered;\n}\n\n/**\n * CLI 入口。\n */\nexport async function runCli(argv: string[]): Promise<void> {\n const globalConfig = await loadGlobalConfig(defaultLogger);\n const effectiveArgv = applyShortcutArgv(argv, globalConfig);\n const program = new Command();\n\n program\n .name('wheel-ai')\n .description('基于 AI CLI 的持续迭代开发工具')\n .version('1.0.0');\n\n program\n .command('run')\n .requiredOption('-t, --task <task>', '需要完成的任务描述(会进入 AI 提示)')\n .option('-i, --iterations <number>', '最大迭代次数', value => parseInteger(value, 5), 5)\n .option('--ai-cli <command>', 'AI CLI 命令', 'claude')\n .option('--ai-args <args...>', 'AI CLI 参数', [])\n .option('--ai-prompt-arg <flag>', '用于传入 prompt 的参数(为空则使用 stdin)')\n .option('--notes-file <path>', '持久化记忆文件', defaultNotesPath())\n .option('--plan-file <path>', '计划文件', defaultPlanPath())\n .option('--workflow-doc <path>', 'AI 工作流程说明文件', defaultWorkflowDoc())\n .option('--worktree', '在独立 worktree 上执行', false)\n .option('--branch <name>', 'worktree 分支名(默认自动生成或当前分支)')\n .option('--worktree-path <path>', 'worktree 路径,默认 ../worktrees/<branch>')\n .option('--base-branch <name>', '创建分支的基线分支', 'main')\n .option('--skip-install', '跳过开始任务前的依赖检查', false)\n .option('--run-tests', '运行单元测试命令', false)\n .option('--run-e2e', '运行 e2e 测试命令', false)\n .option('--unit-command <cmd>', '单元测试命令', 'yarn test')\n .option('--e2e-command <cmd>', 'e2e 测试命令', 'yarn e2e')\n .option('--auto-commit', '自动 git commit', false)\n .option('--auto-push', '自动 git push', false)\n .option('--pr', '使用 gh 创建 PR', false)\n .option('--pr-title <title>', 'PR 标题')\n .option('--pr-body <path>', 'PR 描述文件路径(可留空自动生成)')\n .option('--draft', '以草稿形式创建 PR', false)\n .option('--reviewer <user...>', 'PR reviewers', collect, [])\n .option('--webhook <url>', 'webhook 通知 URL(可重复)', collect, [])\n .option('--webhook-timeout <ms>', 'webhook 请求超时(毫秒)', value => parseInteger(value, 8000))\n .option('--stop-signal <token>', 'AI 输出中的停止标记', '<<DONE>>')\n .option('--log-file <path>', '日志输出文件路径')\n .option('--background', '切入后台运行', false)\n .option('-v, --verbose', '输出调试日志', false)\n .action(async (options) => {\n const useWorktree = Boolean(options.worktree);\n const branchInput = normalizeOptional(options.branch);\n const logFileInput = normalizeOptional(options.logFile);\n const background = Boolean(options.background);\n\n let branchName = branchInput;\n if (useWorktree && !branchName) {\n branchName = generateBranchName();\n }\n\n let logFile = logFileInput;\n if (background && !logFile) {\n let branchForLog = branchName;\n if (!branchForLog) {\n try {\n const current = await getCurrentBranch(process.cwd(), defaultLogger);\n branchForLog = current || 'detached';\n } catch {\n branchForLog = 'unknown';\n }\n }\n logFile = buildAutoLogFilePath(branchForLog);\n }\n\n if (background) {\n if (!logFile) {\n throw new Error('后台运行需要指定日志文件');\n }\n const args = buildBackgroundArgs(effectiveArgv, logFile, branchName, useWorktree && !branchInput);\n const child = spawn(process.execPath, [...process.execArgv, ...args], {\n detached: true,\n stdio: 'ignore'\n });\n child.unref();\n const displayLogFile = resolvePath(process.cwd(), logFile);\n console.log(`已切入后台运行,日志输出至 ${displayLogFile}`);\n return;\n }\n\n const cliOptions: CliOptions = {\n task: options.task as string,\n iterations: options.iterations as number,\n aiCli: options.aiCli as string,\n aiArgs: (options.aiArgs as string[]) ?? [],\n aiPromptArg: options.aiPromptArg as string | undefined,\n notesFile: options.notesFile as string,\n planFile: options.planFile as string,\n workflowDoc: options.workflowDoc as string,\n useWorktree,\n branch: branchName,\n worktreePath: options.worktreePath as string | undefined,\n baseBranch: options.baseBranch as string,\n runTests: Boolean(options.runTests),\n runE2e: Boolean(options.runE2e),\n unitCommand: options.unitCommand as string | undefined,\n e2eCommand: options.e2eCommand as string | undefined,\n autoCommit: Boolean(options.autoCommit),\n autoPush: Boolean(options.autoPush),\n pr: Boolean(options.pr),\n prTitle: options.prTitle as string | undefined,\n prBody: options.prBody as string | undefined,\n draft: Boolean(options.draft),\n reviewers: (options.reviewer as string[]) ?? [],\n webhookUrls: (options.webhook as string[]) ?? [],\n webhookTimeout: options.webhookTimeout as number | undefined,\n stopSignal: options.stopSignal as string,\n logFile,\n verbose: Boolean(options.verbose),\n skipInstall: Boolean(options.skipInstall)\n };\n\n const config = buildLoopConfig(cliOptions, process.cwd());\n await runLoop(config);\n });\n\n program\n .command('monitor')\n .description('查看后台运行日志')\n .action(async () => {\n await runMonitor();\n });\n\n program\n .command('logs')\n .description('查看历史日志')\n .action(async () => {\n await runLogsViewer();\n });\n\n await program.parseAsync(effectiveArgv);\n}\n\nif (require.main === module) {\n runCli(process.argv).catch(error => {\n const message = error instanceof Error ? error.stack ?? error.message : String(error);\n defaultLogger.error(message);\n process.exitCode = 1;\n });\n}\n","import path from 'node:path';\nimport { AiCliConfig, LoopConfig, PrConfig, TestConfig, WebhookConfig, WorktreeConfig, WorkflowFiles } from './types';\nimport { resolvePath } from './utils';\n\n/**\n * CLI 参数解析后的配置。\n */\nexport interface CliOptions {\n readonly task: string;\n readonly iterations: number;\n readonly aiCli: string;\n readonly aiArgs: string[];\n readonly aiPromptArg?: string;\n readonly notesFile: string;\n readonly planFile: string;\n readonly workflowDoc: string;\n readonly useWorktree: boolean;\n readonly branch?: string;\n readonly worktreePath?: string;\n readonly baseBranch: string;\n readonly runTests: boolean;\n readonly runE2e: boolean;\n readonly unitCommand?: string;\n readonly e2eCommand?: string;\n readonly autoCommit: boolean;\n readonly autoPush: boolean;\n readonly pr: boolean;\n readonly prTitle?: string;\n readonly prBody?: string;\n readonly draft: boolean;\n readonly reviewers?: string[];\n readonly webhookUrls: string[];\n readonly webhookTimeout?: number;\n readonly stopSignal: string;\n readonly logFile?: string;\n readonly verbose: boolean;\n readonly skipInstall: boolean;\n}\n\nfunction buildAiConfig(options: CliOptions): AiCliConfig {\n return {\n command: options.aiCli,\n args: options.aiArgs,\n promptArg: options.aiPromptArg\n };\n}\n\nfunction buildWorktreeConfig(options: CliOptions): WorktreeConfig {\n return {\n useWorktree: options.useWorktree,\n branchName: options.branch,\n worktreePath: options.worktreePath,\n baseBranch: options.baseBranch\n };\n}\n\nfunction buildTestConfig(options: CliOptions): TestConfig {\n return {\n unitCommand: options.unitCommand,\n e2eCommand: options.e2eCommand\n };\n}\n\nfunction buildPrConfig(options: CliOptions): PrConfig {\n return {\n enable: options.pr,\n title: options.prTitle,\n bodyPath: options.prBody,\n draft: options.draft,\n reviewers: options.reviewers\n };\n}\n\nfunction buildWebhookConfig(options: CliOptions): WebhookConfig | undefined {\n if (!options.webhookUrls || options.webhookUrls.length === 0) return undefined;\n return {\n urls: options.webhookUrls,\n timeoutMs: options.webhookTimeout\n };\n}\n\nfunction buildWorkflowFiles(options: CliOptions, cwd: string): WorkflowFiles {\n return {\n workflowDoc: resolvePath(cwd, options.workflowDoc),\n notesFile: resolvePath(cwd, options.notesFile),\n planFile: resolvePath(cwd, options.planFile)\n };\n}\n\n/**\n * 构建循环执行所需的配置对象。\n */\nexport function buildLoopConfig(options: CliOptions, cwd: string): LoopConfig {\n return {\n task: options.task,\n iterations: options.iterations,\n stopSignal: options.stopSignal,\n ai: buildAiConfig(options),\n workflowFiles: buildWorkflowFiles(options, cwd),\n git: buildWorktreeConfig(options),\n tests: buildTestConfig(options),\n pr: buildPrConfig(options),\n webhooks: buildWebhookConfig(options),\n cwd,\n logFile: options.logFile ? resolvePath(cwd, options.logFile) : undefined,\n verbose: options.verbose,\n runTests: options.runTests,\n runE2e: options.runE2e,\n autoCommit: options.autoCommit,\n autoPush: options.autoPush,\n skipInstall: options.skipInstall\n };\n}\n\n/**\n * 默认 notes 文件路径。\n */\nexport function defaultNotesPath(): string {\n return path.join('memory', 'notes.md');\n}\n\n/**\n * 默认 plan 文件路径。\n */\nexport function defaultPlanPath(): string {\n return path.join('memory', 'plan.md');\n}\n\n/**\n * 默认工作流说明文件路径。\n */\nexport function defaultWorkflowDoc(): string {\n return path.join('docs', 'ai-workflow.md');\n}\n","import path from 'node:path';\nimport fs from 'fs-extra';\nimport { CommandOptions, CommandResult } from './types';\n\ntype ExecaModule = typeof import('execa');\ntype ExecaError = import('execa').ExecaError;\n\nconst importExeca = async (): Promise<ExecaModule> => {\n // 通过运行时动态 import 兼容 CommonJS 下加载 ESM 包\n const importer = new Function('specifier', 'return import(specifier)') as (specifier: string) => Promise<ExecaModule>;\n return importer('execa');\n};\n\n/**\n * 执行外部命令,支持日志与流式输出。\n */\nexport async function runCommand(command: string, args: string[], options: CommandOptions = {}): Promise<CommandResult> {\n const label = options.verboseLabel ?? 'cmd';\n const displayCmd = options.verboseCommand ?? [command, ...args].join(' ');\n const cwd = options.cwd ?? process.cwd();\n options.logger?.debug(`[${label}] ${displayCmd} (cwd: ${cwd})`);\n\n const logger = options.logger;\n const streamEnabled = Boolean(options.stream?.enabled && logger);\n const stdoutPrefix = options.stream?.stdoutPrefix ?? `[${label}] `;\n const stderrPrefix = options.stream?.stderrPrefix ?? `[${label} stderr] `;\n\n const createLineStreamer = (prefix: string) => {\n let buffer = '';\n const emit = (line: string): void => {\n logger?.info(`${prefix}${line}`);\n };\n const push = (chunk: string | Buffer): void => {\n const text = typeof chunk === 'string' ? chunk : chunk.toString('utf8');\n buffer += text.replace(/\\r/g, '\\n');\n const parts = buffer.split('\\n');\n buffer = parts.pop() ?? '';\n parts.forEach(emit);\n };\n const flush = (): void => {\n if (buffer.length === 0) return;\n emit(buffer);\n buffer = '';\n };\n return { push, flush };\n };\n\n const attachStream = (stream: NodeJS.ReadableStream | null | undefined, streamer: ReturnType<typeof createLineStreamer>): void => {\n if (!stream) return;\n if (typeof stream.setEncoding === 'function') {\n stream.setEncoding('utf8');\n }\n stream.on('data', streamer.push);\n stream.on('end', streamer.flush);\n };\n\n const stdoutStreamer = streamEnabled ? createLineStreamer(stdoutPrefix) : null;\n const stderrStreamer = streamEnabled ? createLineStreamer(stderrPrefix) : null;\n\n try {\n const { execa } = await importExeca();\n const subprocess = execa(command, args, {\n cwd: options.cwd,\n env: options.env,\n input: options.input,\n all: false\n });\n if (stdoutStreamer) {\n attachStream(subprocess.stdout, stdoutStreamer);\n }\n if (stderrStreamer) {\n attachStream(subprocess.stderr, stderrStreamer);\n }\n const result = await subprocess;\n stdoutStreamer?.flush();\n stderrStreamer?.flush();\n const commandResult: CommandResult = {\n stdout: String(result.stdout ?? ''),\n stderr: String(result.stderr ?? ''),\n exitCode: result.exitCode ?? 0\n };\n if (logger) {\n const stdout = commandResult.stdout.trim();\n const stderr = commandResult.stderr.trim();\n if (stdout.length > 0) {\n logger.debug(`[${label}] stdout: ${stdout}`);\n }\n if (stderr.length > 0) {\n logger.debug(`[${label}] stderr: ${stderr}`);\n }\n logger.debug(`[${label}] exit ${commandResult.exitCode}`);\n }\n return commandResult;\n } catch (error) {\n const execaError = error as ExecaError;\n stdoutStreamer?.flush();\n stderrStreamer?.flush();\n const commandResult: CommandResult = {\n stdout: String(execaError.stdout ?? ''),\n stderr: String(execaError.stderr ?? String(error)),\n exitCode: execaError.exitCode ?? 1\n };\n if (logger) {\n const stdout = commandResult.stdout.trim();\n const stderr = commandResult.stderr.trim();\n if (stdout.length > 0) {\n logger.debug(`[${label}] stdout: ${stdout}`);\n }\n if (stderr.length > 0) {\n logger.debug(`[${label}] stderr: ${stderr}`);\n }\n logger.debug(`[${label}] exit ${commandResult.exitCode}`);\n }\n return commandResult;\n }\n}\n\n/**\n * 返回 ISO 格式时间戳。\n */\nexport function isoNow(): string {\n return new Date().toISOString();\n}\n\n/**\n * 基于 cwd 解析相对路径。\n */\nexport function resolvePath(cwd: string, target: string): string {\n return path.isAbsolute(target) ? target : path.join(cwd, target);\n}\n\n/**\n * 确保目录存在。\n */\nexport async function ensureDir(dirPath: string): Promise<void> {\n await fs.mkdirp(dirPath);\n}\n\n/**\n * 确保文件存在(必要时创建)。\n */\nexport async function ensureFile(filePath: string, initialContent = ''): Promise<void> {\n await ensureDir(path.dirname(filePath));\n const exists = await fs.pathExists(filePath);\n if (!exists) {\n await fs.writeFile(filePath, initialContent, 'utf8');\n }\n}\n\n/**\n * 向文件末尾追加一段内容(包含换行)。\n */\nexport async function appendSection(filePath: string, content: string): Promise<void> {\n await ensureDir(path.dirname(filePath));\n await fs.appendFile(filePath, `\\n${content}\\n`, 'utf8');\n}\n\n/**\n * 安全读取文件内容,若不存在则返回空字符串。\n */\nexport async function readFileSafe(filePath: string): Promise<string> {\n const exists = await fs.pathExists(filePath);\n if (!exists) return '';\n return fs.readFile(filePath, 'utf8');\n}\n\n/**\n * 格式化 Markdown 标题。\n */\nexport function formatHeading(title: string): string {\n return `## ${title}\\n`;\n}\n\n/**\n * 补齐两位数字字符串。\n */\nexport function pad2(value: number): string {\n return String(value).padStart(2, '0');\n}\n","import os from 'node:os';\nimport path from 'node:path';\nimport fs from 'fs-extra';\nimport type { Logger } from './logger';\n\n/**\n * 全局快捷指令配置。\n */\nexport interface ShortcutConfig {\n readonly name: string;\n readonly command: string;\n}\n\n/**\n * 全局配置结构。\n */\nexport interface GlobalConfig {\n readonly shortcut?: ShortcutConfig;\n}\n\n/**\n * 获取全局配置文件路径。\n */\nexport function getGlobalConfigPath(): string {\n return path.join(os.homedir(), '.wheel-ai', 'config.toml');\n}\n\nfunction stripTomlComment(line: string): string {\n let quote: '\"' | '\\'' | null = null;\n let escaped = false;\n for (let i = 0; i < line.length; i += 1) {\n const char = line[i];\n if (escaped) {\n escaped = false;\n continue;\n }\n if (quote) {\n if (quote === '\"' && char === '\\\\') {\n escaped = true;\n continue;\n }\n if (char === quote) {\n quote = null;\n }\n continue;\n }\n if (char === '\"' || char === '\\'') {\n quote = char;\n continue;\n }\n if (char === '#' || char === ';') {\n return line.slice(0, i);\n }\n }\n return line;\n}\n\nfunction findUnquotedIndex(text: string, target: string): number {\n let quote: '\"' | '\\'' | null = null;\n let escaped = false;\n for (let i = 0; i < text.length; i += 1) {\n const char = text[i];\n if (escaped) {\n escaped = false;\n continue;\n }\n if (quote) {\n if (quote === '\"' && char === '\\\\') {\n escaped = true;\n continue;\n }\n if (char === quote) {\n quote = null;\n }\n continue;\n }\n if (char === '\"' || char === '\\'') {\n quote = char;\n continue;\n }\n if (char === target) {\n return i;\n }\n }\n return -1;\n}\n\nfunction parseTomlString(raw: string): string | null {\n const value = raw.trim();\n if (value.length < 2) return null;\n const quote = value[0];\n if (quote !== '\"' && quote !== '\\'') return null;\n let result = '';\n let escaped = false;\n for (let i = 1; i < value.length; i += 1) {\n const char = value[i];\n if (quote === '\"') {\n if (escaped) {\n switch (char) {\n case 'n':\n result += '\\n';\n break;\n case 't':\n result += '\\t';\n break;\n case 'r':\n result += '\\r';\n break;\n case '\"':\n case '\\\\':\n result += char;\n break;\n default:\n result += char;\n break;\n }\n escaped = false;\n continue;\n }\n if (char === '\\\\') {\n escaped = true;\n continue;\n }\n if (char === quote) {\n const rest = value.slice(i + 1).trim();\n if (rest.length > 0) return null;\n return result;\n }\n result += char;\n continue;\n }\n\n if (char === quote) {\n const rest = value.slice(i + 1).trim();\n if (rest.length > 0) return null;\n return result;\n }\n result += char;\n }\n return null;\n}\n\nfunction normalizeShortcutName(name: string): string | null {\n const trimmed = name.trim();\n if (!trimmed) return null;\n if (/\\s/.test(trimmed)) return null;\n return trimmed;\n}\n\n/**\n * 解析全局 TOML 配置文本。\n */\nexport function parseGlobalConfig(content: string): GlobalConfig {\n const lines = content.split(/\\r?\\n/);\n let currentSection: string | null = null;\n const shortcut: Record<string, string> = {};\n\n for (const rawLine of lines) {\n const line = stripTomlComment(rawLine).trim();\n if (!line) continue;\n\n const sectionMatch = /^\\[(.+)\\]$/.exec(line);\n if (sectionMatch) {\n currentSection = sectionMatch[1].trim();\n continue;\n }\n\n if (currentSection !== 'shortcut') continue;\n\n const equalIndex = findUnquotedIndex(line, '=');\n if (equalIndex <= 0) continue;\n\n const key = line.slice(0, equalIndex).trim();\n const valuePart = line.slice(equalIndex + 1).trim();\n if (!key || !valuePart) continue;\n\n const parsedValue = parseTomlString(valuePart);\n if (parsedValue === null) continue;\n\n shortcut[key] = parsedValue;\n }\n\n const name = normalizeShortcutName(shortcut.name ?? '');\n const command = (shortcut.command ?? '').trim();\n if (!name || !command) {\n return {};\n }\n\n return {\n shortcut: {\n name,\n command\n }\n };\n}\n\n/**\n * 读取用户目录下的全局配置。\n */\nexport async function loadGlobalConfig(logger?: Logger): Promise<GlobalConfig | null> {\n const filePath = getGlobalConfigPath();\n const exists = await fs.pathExists(filePath);\n if (!exists) return null;\n\n try {\n const content = await fs.readFile(filePath, 'utf8');\n return parseGlobalConfig(content);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n logger?.warn(`读取全局配置失败,已忽略:${message}`);\n return null;\n }\n}\n\n/**\n * 将命令行字符串拆解为参数数组(支持引号与转义)。\n */\nexport function splitCommandArgs(command: string): string[] {\n const args: string[] = [];\n let current = '';\n let quote: '\"' | '\\'' | null = null;\n let escaped = false;\n\n for (let i = 0; i < command.length; i += 1) {\n const char = command[i];\n if (escaped) {\n current += char;\n escaped = false;\n continue;\n }\n\n if (quote) {\n if (quote === '\"' && char === '\\\\') {\n escaped = true;\n continue;\n }\n if (char === quote) {\n quote = null;\n continue;\n }\n current += char;\n continue;\n }\n\n if (char === '\"' || char === '\\'') {\n quote = char;\n continue;\n }\n\n if (/\\s/.test(char)) {\n if (current.length > 0) {\n args.push(current);\n current = '';\n }\n continue;\n }\n\n if (char === '\\\\') {\n escaped = true;\n continue;\n }\n\n current += char;\n }\n\n if (current.length > 0) {\n args.push(current);\n }\n\n return args;\n}\n\nfunction normalizeShortcutArgs(args: string[]): string[] {\n if (args.length > 0 && args[0] === 'run') {\n return args.slice(1);\n }\n return args;\n}\n\n/**\n * 应用全局快捷指令,将别名替换为 run 子命令参数。\n */\nexport function applyShortcutArgv(argv: string[], config: GlobalConfig | null): string[] {\n if (!config?.shortcut) return argv;\n if (argv.length < 3) return argv;\n const commandIndex = 2;\n if (argv[commandIndex] !== config.shortcut.name) return argv;\n\n const shortcutArgs = normalizeShortcutArgs(splitCommandArgs(config.shortcut.command));\n return [\n ...argv.slice(0, commandIndex),\n 'run',\n ...shortcutArgs,\n ...argv.slice(commandIndex + 1)\n ];\n}\n","import path from 'node:path';\nimport { Logger } from './logger';\nimport { CommitMessage, WorktreeConfig, WorktreeResult } from './types';\nimport { runCommand, resolvePath } from './utils';\n\nasync function branchExists(branch: string, cwd: string, logger?: Logger): Promise<boolean> {\n const result = await runCommand('git', ['rev-parse', '--verify', branch], {\n cwd,\n logger,\n verboseLabel: 'git',\n verboseCommand: `git rev-parse --verify ${branch}`\n });\n return result.exitCode === 0;\n}\n\nasync function resolveBaseBranch(baseBranch: string, repoRoot: string, logger: Logger): Promise<string> {\n const baseExists = await branchExists(baseBranch, repoRoot, logger);\n if (baseExists) return baseBranch;\n\n const current = await getCurrentBranch(repoRoot, logger);\n const currentExists = await branchExists(current, repoRoot, logger);\n if (currentExists) {\n logger.warn(`基线分支 ${baseBranch} 不存在,改用当前分支 ${current} 作为基线`);\n return current;\n }\n\n throw new Error(`基线分支 ${baseBranch} 不存在,且无法确定可用的当前分支`);\n}\n\n/**\n * 获取仓库根目录。\n */\nexport async function getRepoRoot(cwd: string, logger?: Logger): Promise<string> {\n const result = await runCommand('git', ['rev-parse', '--show-toplevel'], {\n cwd,\n logger,\n verboseLabel: 'git',\n verboseCommand: 'git rev-parse --show-toplevel'\n });\n if (result.exitCode !== 0) {\n throw new Error('当前目录不是 git 仓库,无法继续');\n }\n return result.stdout.trim();\n}\n\n/**\n * 获取当前分支名。\n */\nexport async function getCurrentBranch(cwd: string, logger?: Logger): Promise<string> {\n const result = await runCommand('git', ['branch', '--show-current'], {\n cwd,\n logger,\n verboseLabel: 'git',\n verboseCommand: 'git branch --show-current'\n });\n if (result.exitCode !== 0) {\n throw new Error(`无法获取当前分支: ${result.stderr}`);\n }\n return result.stdout.trim();\n}\n\nasync function getUpstreamBranch(branchName: string, cwd: string, logger?: Logger): Promise<string | null> {\n const result = await runCommand('git', ['rev-parse', '--abbrev-ref', '--symbolic-full-name', `${branchName}@{u}`], {\n cwd,\n logger,\n verboseLabel: 'git',\n verboseCommand: `git rev-parse --abbrev-ref --symbolic-full-name ${branchName}@{u}`\n });\n if (result.exitCode !== 0) {\n logger?.warn(`分支 ${branchName} 没有关联的 upstream: ${result.stderr || result.stdout}`);\n return null;\n }\n return result.stdout.trim();\n}\n\nfunction defaultWorktreePath(repoRoot: string, branchName: string): string {\n return path.join(repoRoot, '..', 'worktrees', branchName);\n}\n\n/**\n * 确保目标分支存在。\n */\nexport async function ensureBranchExists(branchName: string, baseBranch: string, repoRoot: string, logger: Logger): Promise<void> {\n const exists = await branchExists(branchName, repoRoot, logger);\n if (exists) return;\n const create = await runCommand('git', ['branch', branchName, baseBranch], {\n cwd: repoRoot,\n logger,\n verboseLabel: 'git',\n verboseCommand: `git branch ${branchName} ${baseBranch}`\n });\n if (create.exitCode !== 0) {\n throw new Error(`创建分支失败: ${create.stderr}`);\n }\n logger.info(`已基于 ${baseBranch} 创建分支 ${branchName}`);\n}\n\n/**\n * 根据配置创建或复用 worktree。\n */\nexport async function ensureWorktree(config: WorktreeConfig, repoRoot: string, logger: Logger): Promise<WorktreeResult> {\n if (!config.useWorktree) {\n return { path: repoRoot, created: false };\n }\n\n const branchName = config.branchName ?? generateBranchName();\n const baseBranch = await resolveBaseBranch(config.baseBranch, repoRoot, logger);\n const worktreePath = resolvePath(repoRoot, config.worktreePath ?? defaultWorktreePath(repoRoot, branchName));\n\n await ensureBranchExists(branchName, baseBranch, repoRoot, logger);\n\n const addResult = await runCommand('git', ['worktree', 'add', worktreePath, branchName], {\n cwd: repoRoot,\n logger,\n verboseLabel: 'git',\n verboseCommand: `git worktree add ${worktreePath} ${branchName}`\n });\n if (addResult.exitCode !== 0) {\n const alreadyExists = addResult.stderr.includes('already exists') || addResult.stdout.includes('already exists');\n if (alreadyExists) {\n logger.warn(`worktree 路径已存在,跳过创建: ${worktreePath}`);\n return { path: worktreePath, created: false };\n }\n throw new Error(`创建 worktree 失败: ${addResult.stderr || addResult.stdout}`);\n }\n\n logger.success(`已在 ${worktreePath} 创建并挂载 worktree (${branchName})`);\n return { path: worktreePath, created: true };\n}\n\n/**\n * 判断 worktree 是否干净。\n */\nexport async function isWorktreeClean(cwd: string, logger?: Logger): Promise<boolean> {\n const status = await runCommand('git', ['status', '--porcelain'], {\n cwd,\n logger,\n verboseLabel: 'git',\n verboseCommand: 'git status --porcelain'\n });\n if (status.exitCode !== 0) {\n logger?.warn(`无法获取 git 状态: ${status.stderr || status.stdout}`);\n return false;\n }\n return status.stdout.trim().length === 0;\n}\n\n/**\n * 判断分支是否已推送到远端。\n */\nexport async function isBranchPushed(branchName: string, cwd: string, logger: Logger): Promise<boolean> {\n const upstream = await getUpstreamBranch(branchName, cwd, logger);\n if (!upstream) return false;\n\n const countResult = await runCommand('git', ['rev-list', '--left-right', '--count', `${upstream}...${branchName}`], {\n cwd,\n logger,\n verboseLabel: 'git',\n verboseCommand: `git rev-list --left-right --count ${upstream}...${branchName}`\n });\n if (countResult.exitCode !== 0) {\n logger.warn(`无法比较分支 ${branchName} 与 ${upstream}: ${countResult.stderr || countResult.stdout}`);\n return false;\n }\n\n const [behindStr, aheadStr] = countResult.stdout.trim().split(/\\s+/);\n const ahead = Number.parseInt(aheadStr ?? '0', 10);\n if (Number.isNaN(ahead)) {\n logger.warn(`无法解析分支推送状态: ${countResult.stdout}`);\n return false;\n }\n if (ahead > 0) {\n logger.warn(`分支 ${branchName} 仍有 ${ahead} 个本地提交未推送`);\n return false;\n }\n return true;\n}\n\nfunction normalizeCommitTitle(title: string): string {\n return title.replace(/\\s+/g, ' ').trim();\n}\n\nfunction normalizeCommitBody(body?: string): string | undefined {\n if (!body) return undefined;\n const normalized = body.replace(/\\r\\n?/g, '\\n').trim();\n return normalized.length > 0 ? normalized : undefined;\n}\n\nfunction formatCommitCommand(message: CommitMessage): string {\n const title = normalizeCommitTitle(message.title) || 'chore: 更新迭代产出';\n const parts = ['git commit -m', JSON.stringify(title)];\n const body = normalizeCommitBody(message.body);\n if (body) {\n parts.push('-m', JSON.stringify(body));\n }\n return parts.join(' ');\n}\n\nfunction buildCommitArgs(message: CommitMessage): string[] {\n const title = normalizeCommitTitle(message.title) || 'chore: 更新迭代产出';\n const args = ['commit', '-m', title];\n const body = normalizeCommitBody(message.body);\n if (body) {\n args.push('-m', body);\n }\n return args;\n}\n\n/**\n * 提交当前变更。\n */\nexport async function commitAll(message: CommitMessage, cwd: string, logger: Logger): Promise<void> {\n const add = await runCommand('git', ['add', '-A'], {\n cwd,\n logger,\n verboseLabel: 'git',\n verboseCommand: 'git add -A'\n });\n if (add.exitCode !== 0) {\n throw new Error(`git add 失败: ${add.stderr}`);\n }\n const commit = await runCommand('git', buildCommitArgs(message), {\n cwd,\n logger,\n verboseLabel: 'git',\n verboseCommand: formatCommitCommand(message)\n });\n if (commit.exitCode !== 0) {\n logger.warn(`git commit 跳过或失败: ${commit.stderr}`);\n return;\n }\n logger.success('已提交当前变更');\n}\n\n/**\n * 推送分支到远端。\n */\nexport async function pushBranch(branchName: string, cwd: string, logger: Logger): Promise<void> {\n const push = await runCommand('git', ['push', '-u', 'origin', branchName], {\n cwd,\n logger,\n verboseLabel: 'git',\n verboseCommand: `git push -u origin ${branchName}`\n });\n if (push.exitCode !== 0) {\n throw new Error(`git push 失败: ${push.stderr}`);\n }\n logger.success(`已推送分支 ${branchName}`);\n}\n\n/**\n * 删除 worktree 并清理。\n */\nexport async function removeWorktree(worktreePath: string, repoRoot: string, logger: Logger): Promise<void> {\n const remove = await runCommand('git', ['worktree', 'remove', '--force', worktreePath], {\n cwd: repoRoot,\n logger,\n verboseLabel: 'git',\n verboseCommand: `git worktree remove --force ${worktreePath}`\n });\n if (remove.exitCode !== 0) {\n throw new Error(`删除 worktree 失败: ${remove.stderr || remove.stdout}`);\n }\n\n const prune = await runCommand('git', ['worktree', 'prune'], {\n cwd: repoRoot,\n logger,\n verboseLabel: 'git',\n verboseCommand: 'git worktree prune'\n });\n if (prune.exitCode !== 0) {\n logger.warn(`worktree prune 失败: ${prune.stderr || prune.stdout}`);\n }\n\n logger.success(`已删除 worktree: ${worktreePath}`);\n}\n\n/**\n * 生成默认分支名。\n */\nexport function generateBranchName(): string {\n const now = new Date();\n const stamp = `${now.getFullYear()}${(now.getMonth() + 1).toString().padStart(2, '0')}${now.getDate().toString().padStart(2, '0')}-${now.getHours().toString().padStart(2, '0')}${now.getMinutes().toString().padStart(2, '0')}`;\n return `wheel-aii/${stamp}`;\n}\n","import os from 'node:os';\nimport path from 'node:path';\nimport fs from 'fs-extra';\nimport { pad2 } from './utils';\n\nexport interface RunMetadata {\n readonly command: string;\n readonly round: number;\n readonly tokenUsed: number;\n readonly path: string;\n}\n\nexport interface CurrentRegistryEntry extends RunMetadata {\n readonly logFile?: string;\n}\n\nexport type CurrentRegistry = Record<string, CurrentRegistryEntry>;\n\nconst LOGS_DIR = path.join(os.homedir(), '.wheel-ai', 'logs');\n\nexport function getLogsDir(): string {\n return LOGS_DIR;\n}\n\nexport function getCurrentRegistryPath(): string {\n return path.join(LOGS_DIR, 'current.json');\n}\n\nexport async function ensureLogsDir(): Promise<void> {\n await fs.mkdirp(LOGS_DIR);\n}\n\n/**\n * 生成时间字符串(YYYYMMDDHHmmss)。\n */\nexport function formatTimeString(date: Date = new Date()): string {\n const year = date.getFullYear();\n const month = pad2(date.getMonth() + 1);\n const day = pad2(date.getDate());\n const hours = pad2(date.getHours());\n const minutes = pad2(date.getMinutes());\n const seconds = pad2(date.getSeconds());\n return `${year}${month}${day}${hours}${minutes}${seconds}`;\n}\n\n/**\n * 清理分支名中的非法字符。\n */\nexport function sanitizeBranchName(branchName: string): string {\n const normalized = branchName.trim();\n if (!normalized) return '';\n const replaced = normalized.replace(/[\\\\/:*?\"<>|\\s]+/g, '-');\n return replaced.replace(/-+/g, '-').replace(/^-+|-+$/g, '');\n}\n\nexport function buildAutoLogFilePath(branchName: string, date: Date = new Date()): string {\n const safeBranch = sanitizeBranchName(branchName) || 'unknown';\n return path.join(LOGS_DIR, `wheel-ai-auto-log-${formatTimeString(date)}-${safeBranch}.log`);\n}\n\nexport function getLogMetaPath(logFile: string): string {\n const baseName = path.basename(logFile, path.extname(logFile));\n return path.join(LOGS_DIR, `${baseName}.json`);\n}\n\nfunction buildLogKey(logFile: string): string {\n return path.basename(logFile);\n}\n\n/**\n * 格式化命令行字符串(用于写入元信息)。\n */\nexport function formatCommandLine(argv: string[]): string {\n const quote = (value: string): string => {\n if (/[\\s\"'\\\\]/.test(value)) {\n return JSON.stringify(value);\n }\n return value;\n };\n return argv.map(quote).join(' ').trim();\n}\n\nasync function writeJsonFile(filePath: string, data: unknown): Promise<void> {\n await ensureLogsDir();\n await fs.writeFile(filePath, `${JSON.stringify(data, null, 2)}\\n`, 'utf8');\n}\n\n/**\n * 写入单次运行的元信息。\n */\nexport async function writeRunMetadata(logFile: string, metadata: RunMetadata): Promise<void> {\n const metaPath = getLogMetaPath(logFile);\n await writeJsonFile(metaPath, metadata);\n}\n\n/**\n * 读取 current.json 注册表。\n */\nexport async function readCurrentRegistry(): Promise<CurrentRegistry> {\n const filePath = getCurrentRegistryPath();\n const exists = await fs.pathExists(filePath);\n if (!exists) return {};\n try {\n const content = await fs.readFile(filePath, 'utf8');\n const parsed = JSON.parse(content) as CurrentRegistry;\n if (!parsed || typeof parsed !== 'object') return {};\n return parsed;\n } catch {\n return {};\n }\n}\n\n/**\n * 更新 current.json 中的运行记录。\n */\nexport async function upsertCurrentRegistry(logFile: string, metadata: RunMetadata): Promise<void> {\n const registry = await readCurrentRegistry();\n const key = buildLogKey(logFile);\n registry[key] = { ...metadata, logFile };\n await writeJsonFile(getCurrentRegistryPath(), registry);\n}\n\n/**\n * 从 current.json 中移除运行记录。\n */\nexport async function removeCurrentRegistry(logFile: string): Promise<void> {\n const registry = await readCurrentRegistry();\n const key = buildLogKey(logFile);\n if (!(key in registry)) return;\n delete registry[key];\n await writeJsonFile(getCurrentRegistryPath(), registry);\n}\n","import fs from 'fs-extra';\nimport path from 'node:path';\nimport { CurrentRegistry, RunMetadata, getLogsDir, readCurrentRegistry } from './logs';\nimport { pad2 } from './utils';\n\nexport interface LogEntry {\n readonly fileName: string;\n readonly filePath: string;\n readonly size: number;\n readonly mtimeMs: number;\n readonly meta?: RunMetadata;\n}\n\ninterface ViewState {\n entry: LogEntry;\n lines: string[];\n pageOffset: number;\n}\n\ninterface LogsViewerState {\n mode: 'list' | 'view';\n logs: LogEntry[];\n selectedIndex: number;\n listOffset: number;\n view?: ViewState;\n lastError?: string;\n}\n\nfunction isRunMetadata(value: unknown): value is RunMetadata {\n if (!value || typeof value !== 'object') return false;\n const record = value as Record<string, unknown>;\n return (\n typeof record.command === 'string' &&\n typeof record.round === 'number' &&\n typeof record.tokenUsed === 'number' &&\n typeof record.path === 'string'\n );\n}\n\nfunction buildLogMetaPath(logsDir: string, logFile: string): string {\n const baseName = path.basename(logFile, path.extname(logFile));\n return path.join(logsDir, `${baseName}.json`);\n}\n\nasync function readLogMetadata(logsDir: string, logFile: string): Promise<RunMetadata | undefined> {\n const metaPath = buildLogMetaPath(logsDir, logFile);\n const exists = await fs.pathExists(metaPath);\n if (!exists) return undefined;\n try {\n const content = await fs.readFile(metaPath, 'utf8');\n const parsed = JSON.parse(content) as unknown;\n return isRunMetadata(parsed) ? parsed : undefined;\n } catch {\n return undefined;\n }\n}\n\nexport function buildRunningLogKeys(registry: CurrentRegistry): Set<string> {\n const keys = new Set<string>();\n for (const [key, entry] of Object.entries(registry)) {\n keys.add(key);\n if (entry.logFile) {\n keys.add(path.basename(entry.logFile));\n }\n }\n return keys;\n}\n\nexport async function loadLogEntries(logsDir: string, registry: CurrentRegistry): Promise<LogEntry[]> {\n const exists = await fs.pathExists(logsDir);\n if (!exists) return [];\n const running = buildRunningLogKeys(registry);\n const names = await fs.readdir(logsDir);\n const entries: LogEntry[] = [];\n for (const name of names) {\n if (path.extname(name).toLowerCase() !== '.log') continue;\n if (running.has(name)) continue;\n const filePath = path.join(logsDir, name);\n let stat: fs.Stats;\n try {\n stat = await fs.stat(filePath);\n } catch {\n continue;\n }\n if (!stat.isFile()) continue;\n const meta = await readLogMetadata(logsDir, filePath);\n entries.push({\n fileName: name,\n filePath,\n size: stat.size,\n mtimeMs: stat.mtimeMs,\n meta\n });\n }\n return entries.sort((a, b) => b.mtimeMs - a.mtimeMs);\n}\n\nfunction getTerminalSize(): { rows: number; columns: number } {\n const rows = process.stdout.rows ?? 24;\n const columns = process.stdout.columns ?? 80;\n return { rows, columns };\n}\n\nfunction truncateLine(line: string, width: number): string {\n if (width <= 0) return '';\n if (line.length <= width) return line;\n return line.slice(0, width);\n}\n\nfunction formatTimestamp(ms: number): string {\n const date = new Date(ms);\n const year = date.getFullYear();\n const month = pad2(date.getMonth() + 1);\n const day = pad2(date.getDate());\n const hours = pad2(date.getHours());\n const minutes = pad2(date.getMinutes());\n const seconds = pad2(date.getSeconds());\n return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;\n}\n\nfunction formatBytes(size: number): string {\n if (size < 1024) return `${size}B`;\n const kb = size / 1024;\n if (kb < 1024) return `${kb.toFixed(1)}KB`;\n const mb = kb / 1024;\n return `${mb.toFixed(1)}MB`;\n}\n\nfunction getPageSize(rows: number): number {\n return Math.max(1, rows - 2);\n}\n\nasync function readLogLines(logFile: string): Promise<string[]> {\n try {\n const content = await fs.readFile(logFile, 'utf8');\n const normalized = content.replace(/\\r\\n?/g, '\\n');\n const lines = normalized.split('\\n');\n return lines.length > 0 ? lines : [''];\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n return [`(无法读取日志文件:${message})`];\n }\n}\n\nfunction buildListHeader(state: LogsViewerState, columns: number): string {\n const total = state.logs.length;\n const title = `日志列表(${total} 条)|↑/↓ 选择 Enter 查看 q 退出`;\n return truncateLine(title, columns);\n}\n\nfunction buildListStatus(state: LogsViewerState, columns: number): string {\n if (state.logs.length === 0) {\n const text = state.lastError ? `加载失败:${state.lastError}` : '暂无可查看的日志';\n return truncateLine(text, columns);\n }\n const entry = state.logs[state.selectedIndex];\n const meta = entry.meta;\n const detail = meta ? `项目 ${meta.path}` : `文件 ${entry.fileName}`;\n const suffix = state.lastError ? ` | 加载失败:${state.lastError}` : '';\n return truncateLine(`${detail}${suffix}`, columns);\n}\n\nfunction buildListLine(entry: LogEntry, selected: boolean, columns: number): string {\n const marker = selected ? '>' : ' ';\n const time = formatTimestamp(entry.mtimeMs);\n const metaInfo = entry.meta\n ? `轮次 ${entry.meta.round} | Token ${entry.meta.tokenUsed}`\n : `大小 ${formatBytes(entry.size)}`;\n return truncateLine(`${marker} ${entry.fileName} | ${time} | ${metaInfo}`, columns);\n}\n\nfunction buildViewHeader(entry: LogEntry, columns: number): string {\n const title = `日志查看|${entry.fileName}|↑/↓ 翻页 b 返回 q 退出`;\n return truncateLine(title, columns);\n}\n\nfunction buildViewStatus(entry: LogEntry, page: { current: number; total: number }, columns: number): string {\n const meta = entry.meta;\n const metaInfo = meta\n ? `轮次 ${meta.round} | Token ${meta.tokenUsed} | 项目 ${meta.path}`\n : `文件 ${entry.fileName}`;\n const status = `页 ${page.current}/${page.total} | ${metaInfo}`;\n return truncateLine(status, columns);\n}\n\nfunction ensureListOffset(state: LogsViewerState, pageSize: number): void {\n const total = state.logs.length;\n if (total === 0) {\n state.listOffset = 0;\n state.selectedIndex = 0;\n return;\n }\n const maxOffset = Math.max(0, total - pageSize);\n if (state.selectedIndex < state.listOffset) {\n state.listOffset = state.selectedIndex;\n }\n if (state.selectedIndex >= state.listOffset + pageSize) {\n state.listOffset = state.selectedIndex - pageSize + 1;\n }\n state.listOffset = Math.min(Math.max(state.listOffset, 0), maxOffset);\n}\n\nfunction renderList(state: LogsViewerState): void {\n const { rows, columns } = getTerminalSize();\n const pageSize = getPageSize(rows);\n const header = buildListHeader(state, columns);\n ensureListOffset(state, pageSize);\n\n if (state.logs.length === 0) {\n const filler = Array.from({ length: pageSize }, () => '');\n const status = buildListStatus(state, columns);\n const content = [header, ...filler, status].join('\\n');\n process.stdout.write(`\\u001b[2J\\u001b[H${content}`);\n return;\n }\n\n const start = state.listOffset;\n const slice = state.logs.slice(start, start + pageSize);\n const lines = slice.map((entry, index) => {\n const selected = start + index === state.selectedIndex;\n return buildListLine(entry, selected, columns);\n });\n while (lines.length < pageSize) {\n lines.push('');\n }\n const status = buildListStatus(state, columns);\n const content = [header, ...lines, status].join('\\n');\n process.stdout.write(`\\u001b[2J\\u001b[H${content}`);\n}\n\nfunction renderView(view: ViewState): void {\n const { rows, columns } = getTerminalSize();\n const pageSize = getPageSize(rows);\n const header = buildViewHeader(view.entry, columns);\n const maxOffset = Math.max(0, Math.ceil(view.lines.length / pageSize) - 1);\n view.pageOffset = Math.min(Math.max(view.pageOffset, 0), maxOffset);\n\n const start = view.pageOffset * pageSize;\n const pageLines = view.lines.slice(start, start + pageSize).map(line => truncateLine(line, columns));\n while (pageLines.length < pageSize) {\n pageLines.push('');\n }\n\n const status = buildViewStatus(view.entry, { current: view.pageOffset + 1, total: Math.max(1, maxOffset + 1) }, columns);\n const content = [header, ...pageLines, status].join('\\n');\n process.stdout.write(`\\u001b[2J\\u001b[H${content}`);\n}\n\nfunction render(state: LogsViewerState): void {\n if (state.mode === 'view' && state.view) {\n renderView(state.view);\n return;\n }\n renderList(state);\n}\n\nfunction shouldExit(input: string): boolean {\n if (input === '\\u0003') return true;\n if (input.toLowerCase() === 'q') return true;\n return false;\n}\n\nfunction isEnter(input: string): boolean {\n return input.includes('\\r') || input.includes('\\n');\n}\n\nfunction isArrowUp(input: string): boolean {\n return input.includes('\\u001b[A');\n}\n\nfunction isArrowDown(input: string): boolean {\n return input.includes('\\u001b[B');\n}\n\nfunction isEscape(input: string): boolean {\n return input === '\\u001b';\n}\n\nfunction setupCleanup(cleanup: () => void): void {\n const exitHandler = (): void => {\n cleanup();\n };\n const signalHandler = (): void => {\n cleanup();\n process.exit(0);\n };\n process.on('SIGINT', signalHandler);\n process.on('SIGTERM', signalHandler);\n process.on('exit', exitHandler);\n}\n\nfunction clampIndex(value: number, total: number): number {\n if (total <= 0) return 0;\n return Math.min(Math.max(value, 0), total - 1);\n}\n\n/**\n * 启动日志列表查看界面。\n */\nexport async function runLogsViewer(): Promise<void> {\n if (!process.stdout.isTTY || !process.stdin.isTTY) {\n console.log('当前终端不支持交互式 logs。');\n return;\n }\n\n const logsDir = getLogsDir();\n const state: LogsViewerState = {\n mode: 'list',\n logs: [],\n selectedIndex: 0,\n listOffset: 0\n };\n\n let cleaned = false;\n const cleanup = (): void => {\n if (cleaned) return;\n cleaned = true;\n if (process.stdin.isTTY) {\n process.stdin.setRawMode(false);\n process.stdin.pause();\n }\n process.stdout.write('\\u001b[?25h');\n };\n\n setupCleanup(cleanup);\n process.stdout.write('\\u001b[?25l');\n process.stdin.setRawMode(true);\n process.stdin.resume();\n\n let loading = false;\n\n const loadLogs = async (): Promise<void> => {\n try {\n const registry = await readCurrentRegistry();\n state.logs = await loadLogEntries(logsDir, registry);\n state.selectedIndex = clampIndex(state.selectedIndex, state.logs.length);\n state.lastError = undefined;\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n state.lastError = message;\n state.logs = [];\n state.selectedIndex = 0;\n }\n };\n\n const openView = async (): Promise<void> => {\n if (loading || state.logs.length === 0) return;\n loading = true;\n const entry = state.logs[state.selectedIndex];\n state.mode = 'view';\n state.view = {\n entry,\n lines: ['加载中…'],\n pageOffset: 0\n };\n render(state);\n const lines = await readLogLines(entry.filePath);\n const pageSize = getPageSize(getTerminalSize().rows);\n const maxOffset = Math.max(0, Math.ceil(lines.length / pageSize) - 1);\n state.view = {\n entry,\n lines,\n pageOffset: maxOffset\n };\n loading = false;\n render(state);\n };\n\n await loadLogs();\n render(state);\n\n process.stdin.on('data', (data: Buffer) => {\n const input = data.toString('utf8');\n if (shouldExit(input)) {\n cleanup();\n process.exit(0);\n }\n\n if (state.mode === 'list') {\n if (isArrowUp(input)) {\n state.selectedIndex = clampIndex(state.selectedIndex - 1, state.logs.length);\n render(state);\n return;\n }\n if (isArrowDown(input)) {\n state.selectedIndex = clampIndex(state.selectedIndex + 1, state.logs.length);\n render(state);\n return;\n }\n if (isEnter(input)) {\n void openView();\n return;\n }\n return;\n }\n\n if (state.mode === 'view' && state.view) {\n if (isArrowUp(input)) {\n state.view.pageOffset -= 1;\n render(state);\n return;\n }\n if (isArrowDown(input)) {\n state.view.pageOffset += 1;\n render(state);\n return;\n }\n if (input.toLowerCase() === 'b' || isEscape(input)) {\n state.mode = 'list';\n state.view = undefined;\n render(state);\n return;\n }\n }\n });\n\n process.stdout.on('resize', () => {\n render(state);\n });\n}\n","import fs from 'fs-extra';\nimport path from 'node:path';\nimport { buildPrompt, formatIterationRecord, mergeTokenUsage, runAi } from './ai';\nimport { ensureDependencies } from './deps';\nimport { GhPrInfo, createPr, listFailedRuns, viewPr } from './gh';\nimport { Logger } from './logger';\nimport { commitAll, ensureWorktree, getCurrentBranch, getRepoRoot, isBranchPushed, isWorktreeClean, pushBranch, removeWorktree } from './git';\nimport { formatCommandLine } from './logs';\nimport { createRunTracker } from './runtime-tracker';\nimport { buildFallbackSummary, buildSummaryPrompt, ensurePrBodySections, parseDeliverySummary } from './summary';\nimport { CommitMessage, DeliverySummary, LoopConfig, TestRunResult, TokenUsage, WorkflowFiles, WorktreeResult } from './types';\nimport { appendSection, ensureFile, isoNow, readFileSafe, runCommand } from './utils';\nimport { buildWebhookPayload, sendWebhookNotifications } from './webhook';\n\nasync function ensureWorkflowFiles(workflowFiles: WorkflowFiles): Promise<void> {\n await ensureFile(workflowFiles.workflowDoc, '# AI 工作流程基线\\n');\n await ensureFile(workflowFiles.planFile, '# 计划\\n');\n await ensureFile(workflowFiles.notesFile, '# 持久化记忆\\n');\n}\n\nconst MAX_TEST_LOG_LENGTH = 4000;\n\nfunction trimOutput(output: string, limit = MAX_TEST_LOG_LENGTH): string {\n if (!output) return '';\n if (output.length <= limit) return output;\n return `${output.slice(0, limit)}\\n……(输出已截断,原始长度 ${output.length} 字符)`;\n}\n\nasync function safeCommandOutput(command: string, args: string[], cwd: string, logger: Logger, label: string, verboseCommand: string): Promise<string> {\n const result = await runCommand(command, args, {\n cwd,\n logger,\n verboseLabel: label,\n verboseCommand\n });\n if (result.exitCode !== 0) {\n logger.warn(`${label} 命令失败: ${result.stderr || result.stdout}`);\n return '';\n }\n return result.stdout.trim();\n}\n\nasync function runSingleTest(kind: 'unit' | 'e2e', command: string, cwd: string, logger: Logger): Promise<TestRunResult> {\n const label = kind === 'unit' ? '单元测试' : 'e2e 测试';\n logger.info(`执行${label}: ${command}`);\n const result = await runCommand('bash', ['-lc', command], {\n cwd,\n logger,\n verboseLabel: 'shell',\n verboseCommand: `bash -lc \"${command}\"`\n });\n const success = result.exitCode === 0;\n if (success) {\n logger.success(`${label}完成`);\n } else {\n logger.warn(`${label}失败(退出码 ${result.exitCode})`);\n }\n\n return {\n kind,\n command,\n success,\n exitCode: result.exitCode,\n stdout: trimOutput(result.stdout.trim()),\n stderr: trimOutput(result.stderr.trim())\n };\n}\n\nasync function runTests(config: LoopConfig, workDir: string, logger: Logger): Promise<TestRunResult[]> {\n const results: TestRunResult[] = [];\n\n if (config.runTests && config.tests.unitCommand) {\n const unitResult = await runSingleTest('unit', config.tests.unitCommand, workDir, logger);\n results.push(unitResult);\n }\n\n if (config.runE2e && config.tests.e2eCommand) {\n const e2eResult = await runSingleTest('e2e', config.tests.e2eCommand, workDir, logger);\n results.push(e2eResult);\n }\n\n return results;\n}\n\nfunction reRootPath(filePath: string, repoRoot: string, workDir: string): string {\n const relative = path.relative(repoRoot, filePath);\n if (relative.startsWith('..')) return filePath;\n return path.join(workDir, relative);\n}\n\nfunction reRootWorkflowFiles(workflowFiles: WorkflowFiles, repoRoot: string, workDir: string): WorkflowFiles {\n if (repoRoot === workDir) return workflowFiles;\n return {\n workflowDoc: reRootPath(workflowFiles.workflowDoc, repoRoot, workDir),\n notesFile: reRootPath(workflowFiles.notesFile, repoRoot, workDir),\n planFile: reRootPath(workflowFiles.planFile, repoRoot, workDir)\n };\n}\n\nfunction buildBodyFile(workDir: string): string {\n return path.join(workDir, 'memory', 'pr-body.md');\n}\n\nasync function writePrBody(bodyPath: string, content: string, appendExisting: boolean): Promise<void> {\n await fs.mkdirp(path.dirname(bodyPath));\n let finalContent = content.trim();\n if (appendExisting) {\n const existing = await readFileSafe(bodyPath);\n const trimmedExisting = existing.trim();\n if (trimmedExisting.length > 0) {\n finalContent = `${trimmedExisting}\\n\\n---\\n\\n${finalContent}`;\n }\n }\n await fs.writeFile(bodyPath, `${finalContent}\\n`, 'utf8');\n}\n\ninterface WorktreeCleanupContext {\n readonly repoRoot: string;\n readonly workDir: string;\n readonly branchName?: string;\n readonly prInfo: GhPrInfo | null;\n readonly worktreeCreated: boolean;\n readonly logger: Logger;\n}\n\nasync function cleanupWorktreeIfSafe(context: WorktreeCleanupContext): Promise<void> {\n const { repoRoot, workDir, branchName, prInfo, worktreeCreated, logger } = context;\n if (!worktreeCreated) {\n logger.debug('worktree 并非本次创建,跳过自动清理');\n return;\n }\n if (workDir === repoRoot) {\n logger.debug('当前未使用独立 worktree,跳过自动清理');\n return;\n }\n if (!branchName) {\n logger.warn('未能确定 worktree 分支名,保留工作目录以免丢失进度');\n return;\n }\n\n const clean = await isWorktreeClean(workDir, logger);\n if (!clean) {\n logger.warn('worktree 仍有未提交变更,已保留工作目录');\n return;\n }\n\n const pushed = await isBranchPushed(branchName, workDir, logger);\n if (!pushed) {\n logger.warn(`分支 ${branchName} 尚未推送到远端,已保留 worktree`);\n return;\n }\n\n if (!prInfo) {\n logger.warn('未检测到关联 PR,已保留 worktree');\n return;\n }\n\n await removeWorktree(workDir, repoRoot, logger);\n}\n\n/**\n * 执行主迭代循环。\n */\nexport async function runLoop(config: LoopConfig): Promise<void> {\n const logger = new Logger({ verbose: config.verbose, logFile: config.logFile });\n const repoRoot = await getRepoRoot(config.cwd, logger);\n logger.debug(`仓库根目录: ${repoRoot}`);\n\n const worktreeResult: WorktreeResult = config.git.useWorktree\n ? await ensureWorktree(config.git, repoRoot, logger)\n : { path: repoRoot, created: false };\n const workDir = worktreeResult.path;\n const worktreeCreated = worktreeResult.created;\n logger.debug(`工作目录: ${workDir}`);\n\n const commandLine = formatCommandLine(process.argv);\n const runTracker = await createRunTracker({\n logFile: config.logFile,\n command: commandLine,\n path: workDir,\n logger\n });\n\n let branchName = config.git.branchName;\n let lastRound = 0;\n let runError: string | null = null;\n\n const notifyWebhook = async (event: 'task_start' | 'iteration_start' | 'task_end', iteration: number, stage: string): Promise<void> => {\n const payload = buildWebhookPayload({\n event,\n task: config.task,\n branch: branchName,\n iteration,\n stage\n });\n await sendWebhookNotifications(config.webhooks, payload, logger);\n };\n\n try {\n if (!branchName) {\n try {\n branchName = await getCurrentBranch(workDir, logger);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n logger.warn(`读取分支名失败,webhook 中将缺失分支信息:${message}`);\n }\n }\n\n await notifyWebhook('task_start', 0, '任务开始');\n\n if (config.skipInstall) {\n logger.info('已跳过依赖检查');\n } else {\n await ensureDependencies(workDir, logger);\n }\n\n const workflowFiles = reRootWorkflowFiles(config.workflowFiles, repoRoot, workDir);\n await ensureWorkflowFiles(workflowFiles);\n\n const planContent = await readFileSafe(workflowFiles.planFile);\n if (planContent.trim().length === 0) {\n logger.warn('plan 文件为空,建议 AI 首轮生成计划');\n }\n\n const aiConfig = config.ai;\n\n let accumulatedUsage: TokenUsage | null = null;\n let lastTestResults: TestRunResult[] | null = null;\n let lastAiOutput = '';\n let prInfo: GhPrInfo | null = null;\n let prFailed = false;\n\n for (let i = 1; i <= config.iterations; i += 1) {\n await notifyWebhook('iteration_start', i, `开始第 ${i} 轮迭代`);\n\n const workflowGuide = await readFileSafe(workflowFiles.workflowDoc);\n const plan = await readFileSafe(workflowFiles.planFile);\n const notes = await readFileSafe(workflowFiles.notesFile);\n logger.debug(`加载提示上下文,长度:workflow=${workflowGuide.length}, plan=${plan.length}, notes=${notes.length}`);\n\n const prompt = buildPrompt({\n task: config.task,\n workflowGuide,\n plan,\n notes,\n iteration: i\n });\n logger.debug(`第 ${i} 轮提示长度: ${prompt.length}`);\n\n logger.info(`第 ${i} 轮提示构建完成,调用 AI CLI...`);\n const aiResult = await runAi(prompt, aiConfig, logger, workDir);\n accumulatedUsage = mergeTokenUsage(accumulatedUsage, aiResult.usage);\n lastAiOutput = aiResult.output;\n\n const hitStop = aiResult.output.includes(config.stopSignal);\n let testResults: TestRunResult[] = [];\n const shouldRunTests = config.runTests || config.runE2e;\n if (shouldRunTests) {\n try {\n testResults = await runTests(config, workDir, logger);\n } catch (error) {\n const errorMessage = String(error);\n logger.warn(`测试执行异常: ${errorMessage}`);\n testResults = [{\n kind: 'unit',\n command: config.tests.unitCommand ?? '未知测试命令',\n success: false,\n exitCode: -1,\n stdout: '',\n stderr: trimOutput(errorMessage)\n }];\n }\n }\n\n const record = formatIterationRecord({\n iteration: i,\n prompt,\n aiOutput: aiResult.output,\n timestamp: isoNow(),\n testResults\n });\n\n await appendSection(workflowFiles.notesFile, record);\n logger.success(`已将第 ${i} 轮输出写入 ${workflowFiles.notesFile}`);\n\n lastTestResults = testResults;\n lastRound = i;\n await runTracker?.update(i, accumulatedUsage?.totalTokens ?? 0);\n\n const hasTestFailure = testResults.some(result => !result.success);\n\n if (hitStop && !hasTestFailure) {\n logger.info(`检测到停止标记 ${config.stopSignal},提前结束循环`);\n break;\n }\n if (hitStop && hasTestFailure) {\n logger.info(`检测到停止标记 ${config.stopSignal},但测试失败,继续进入下一轮修复`);\n }\n }\n\n const lastTestFailed = lastTestResults?.some(result => !result.success) ?? false;\n\n if (lastTestFailed) {\n logger.warn('存在未通过的测试,已跳过自动提交/推送/PR');\n }\n\n let deliverySummary: DeliverySummary | null = null;\n const shouldPrepareDelivery = !lastTestFailed && (config.autoCommit || config.pr.enable);\n if (shouldPrepareDelivery) {\n const [gitStatus, diffStat] = await Promise.all([\n safeCommandOutput('git', ['status', '--short'], workDir, logger, 'git', 'git status --short'),\n safeCommandOutput('git', ['diff', '--stat'], workDir, logger, 'git', 'git diff --stat')\n ]);\n const summaryPrompt = buildSummaryPrompt({\n task: config.task,\n plan: await readFileSafe(workflowFiles.planFile),\n notes: await readFileSafe(workflowFiles.notesFile),\n lastAiOutput,\n testResults: lastTestResults,\n gitStatus,\n diffStat,\n branchName\n });\n try {\n const summaryResult = await runAi(summaryPrompt, aiConfig, logger, workDir);\n accumulatedUsage = mergeTokenUsage(accumulatedUsage, summaryResult.usage);\n deliverySummary = parseDeliverySummary(summaryResult.output);\n if (!deliverySummary) {\n logger.warn('AI 总结输出解析失败,使用兜底文案');\n }\n } catch (error) {\n logger.warn(`AI 总结生成失败: ${String(error)}`);\n }\n if (!deliverySummary) {\n deliverySummary = buildFallbackSummary({ task: config.task, testResults: lastTestResults });\n }\n }\n await runTracker?.update(lastRound, accumulatedUsage?.totalTokens ?? 0);\n\n if (config.autoCommit && !lastTestFailed) {\n const summary = deliverySummary ?? buildFallbackSummary({ task: config.task, testResults: lastTestResults });\n const commitMessage: CommitMessage = {\n title: summary.commitTitle,\n body: summary.commitBody\n };\n await commitAll(commitMessage, workDir, logger).catch(error => {\n logger.warn(String(error));\n });\n }\n\n if (config.autoPush && branchName && !lastTestFailed) {\n await pushBranch(branchName, workDir, logger).catch(error => {\n logger.warn(String(error));\n });\n }\n\n if (config.pr.enable && branchName && !lastTestFailed) {\n logger.info('开始创建 PR...');\n const summary = deliverySummary ?? buildFallbackSummary({ task: config.task, testResults: lastTestResults });\n const prTitleCandidate = config.pr.title?.trim() || summary.prTitle;\n const prBodyContent = ensurePrBodySections(summary.prBody, {\n commitTitle: summary.commitTitle,\n commitBody: summary.commitBody,\n testResults: lastTestResults\n });\n const bodyFile = config.pr.bodyPath ?? buildBodyFile(workDir);\n await writePrBody(bodyFile, prBodyContent, Boolean(config.pr.bodyPath));\n\n const createdPr = await createPr(branchName, { ...config.pr, title: prTitleCandidate, bodyPath: bodyFile }, workDir, logger);\n prInfo = createdPr;\n if (createdPr) {\n logger.success(`PR 已创建: ${createdPr.url}`);\n const failedRuns = await listFailedRuns(branchName, workDir, logger);\n if (failedRuns.length > 0) {\n failedRuns.forEach(run => {\n logger.warn(`Actions 失败: ${run.name} (${run.status}/${run.conclusion ?? 'unknown'}) ${run.url}`);\n });\n }\n } else {\n prFailed = true;\n logger.error('PR 创建失败,详见上方 gh 输出');\n }\n } else if (branchName && !config.pr.enable) {\n logger.info('未开启 PR 创建(--pr 未传),尝试查看已有 PR');\n const existingPr = await viewPr(branchName, workDir, logger);\n prInfo = existingPr;\n if (existingPr) logger.info(`已有 PR: ${existingPr.url}`);\n }\n\n if (accumulatedUsage) {\n const input = accumulatedUsage.inputTokens ?? '-';\n const output = accumulatedUsage.outputTokens ?? '-';\n logger.info(`Token 消耗汇总:输入 ${input}|输出 ${output}|总计 ${accumulatedUsage.totalTokens}`);\n } else {\n logger.info('未解析到 Token 消耗信息,可检查 AI CLI 输出格式是否包含 token 提示');\n }\n\n if (lastTestFailed || prFailed) {\n throw new Error('流程存在未解决的问题(测试未通过或 PR 创建失败)');\n }\n\n if (config.git.useWorktree && workDir !== repoRoot) {\n await cleanupWorktreeIfSafe({\n repoRoot,\n workDir,\n branchName,\n prInfo,\n worktreeCreated,\n logger\n });\n }\n\n logger.success(`wheel-ai 迭代流程结束|Token 总计 ${accumulatedUsage?.totalTokens ?? '未知'}`);\n } catch (error) {\n runError = error instanceof Error ? error.message : String(error);\n throw error;\n } finally {\n const stage = runError ? '任务结束(失败)' : '任务结束';\n await notifyWebhook('task_end', lastRound, stage);\n await runTracker?.finalize();\n }\n}\n","import { AiCliConfig, AiResult, IterationRecord, TokenUsage } from './types';\nimport { runCommand } from './utils';\nimport { Logger } from './logger';\n\ninterface PromptInput {\n readonly task: string;\n readonly workflowGuide: string;\n readonly plan: string;\n readonly notes: string;\n readonly iteration: number;\n}\n\n/**\n * 构建 AI 提示文本。\n */\nexport function buildPrompt(input: PromptInput): string {\n const sections = [\n '# 背景任务',\n input.task,\n '# 工作流程基线(供 AI 自主执行)',\n input.workflowGuide,\n '# 当前持久化计划',\n input.plan || '(暂无计划,首轮请生成可执行计划并写入 plan 文件)',\n '# 历史迭代与记忆',\n input.notes || '(首次执行,暂无历史)',\n '# 本轮执行要求',\n [\n '1. 自我检查并补全需求;明确交付物与验收标准。',\n '2. 更新/细化计划,必要时在 plan 文件中重写任务树与优先级。',\n '3. 设计开发步骤并直接生成代码(无需再次请求确认)。',\n '4. 进行代码自审,给出风险与改进清单。',\n '5. 生成单元测试与 e2e 测试代码并给出运行命令;如果环境允许可直接运行命令。',\n '6. 维护持久化记忆文件:摘要本轮关键结论、遗留问题、下一步建议。',\n '7. 准备提交 PR 所需的标题与描述(含变更摘要、测试结果、风险)。',\n '8. 当所有目标完成时,在输出中加入标记 <<DONE>> 以便外层停止循环。'\n ].join('\\n')\n ];\n\n return sections.join('\\n\\n');\n}\n\nfunction pickNumber(pattern: RegExp, text: string): number | undefined {\n const match = pattern.exec(text);\n if (!match || match.length < 2) return undefined;\n const value = Number.parseInt(match[match.length - 1], 10);\n return Number.isNaN(value) ? undefined : value;\n}\n\n/**\n * 从日志文本中解析 token 使用量。\n */\nexport function parseTokenUsage(logs: string): TokenUsage | null {\n const total = pickNumber(/total[_\\s]tokens:\\s*(\\d+)/i, logs);\n const input = pickNumber(/(input|prompt)[_\\s]tokens:\\s*(\\d+)/i, logs);\n const output = pickNumber(/(output|completion)[_\\s]tokens:\\s*(\\d+)/i, logs);\n const consumed = pickNumber(/tokens?\\s+used:\\s*(\\d+)/i, logs) ?? pickNumber(/consumed\\s+(\\d+)\\s+tokens?/i, logs);\n\n const totalTokens = total ?? (input !== undefined || output !== undefined ? (input ?? 0) + (output ?? 0) : consumed);\n if (totalTokens === undefined) return null;\n\n return {\n inputTokens: input,\n outputTokens: output,\n totalTokens\n };\n}\n\nfunction addOptional(a?: number, b?: number): number | undefined {\n if (typeof a !== 'number' && typeof b !== 'number') return undefined;\n return (a ?? 0) + (b ?? 0);\n}\n\n/**\n * 合并多轮 token 统计。\n */\nexport function mergeTokenUsage(previous: TokenUsage | null, current?: TokenUsage | null): TokenUsage | null {\n if (!current) return previous;\n if (!previous) return { ...current };\n return {\n inputTokens: addOptional(previous.inputTokens, current.inputTokens),\n outputTokens: addOptional(previous.outputTokens, current.outputTokens),\n totalTokens: previous.totalTokens + current.totalTokens\n };\n}\n\n/**\n * 调用 AI CLI 并返回输出。\n */\nexport async function runAi(prompt: string, ai: AiCliConfig, logger: Logger, cwd: string): Promise<AiResult> {\n const args = [...ai.args];\n const verboseCommand = ai.promptArg\n ? [ai.command, ...ai.args, ai.promptArg, '<prompt>'].join(' ')\n : [ai.command, ...ai.args, '<stdin>'].join(' ');\n const streamPrefix = `[${ai.command}] `;\n const streamErrorPrefix = `[${ai.command} stderr] `;\n\n let result;\n if (ai.promptArg) {\n args.push(ai.promptArg, prompt);\n result = await runCommand(ai.command, args, {\n cwd,\n logger,\n verboseLabel: 'ai',\n verboseCommand,\n stream: {\n enabled: true,\n stdoutPrefix: streamPrefix,\n stderrPrefix: streamErrorPrefix\n }\n });\n } else {\n result = await runCommand(ai.command, args, {\n cwd,\n input: prompt,\n logger,\n verboseLabel: 'ai',\n verboseCommand,\n stream: {\n enabled: true,\n stdoutPrefix: streamPrefix,\n stderrPrefix: streamErrorPrefix\n }\n });\n }\n\n if (result.exitCode !== 0) {\n throw new Error(`AI CLI 执行失败: ${result.stderr || result.stdout}`);\n }\n\n logger.success('AI 输出完成');\n const usage = parseTokenUsage([result.stdout, result.stderr].filter(Boolean).join('\\n'));\n return {\n output: result.stdout.trim(),\n usage\n };\n}\n\n/**\n * 生成 notes 迭代记录文本。\n */\nexport function formatIterationRecord(record: IterationRecord): string {\n const lines = [\n `### 迭代 ${record.iteration} | ${record.timestamp}`,\n '',\n '#### 提示上下文',\n '```',\n record.prompt,\n '```',\n '',\n '#### AI 输出',\n '```',\n record.aiOutput,\n '```',\n ''\n ];\n\n if (record.testResults && record.testResults.length > 0) {\n lines.push('#### 测试结果');\n record.testResults.forEach(result => {\n const label = result.kind === 'unit' ? '单元测试' : 'e2e 测试';\n const status = result.success ? '✅ 通过' : '❌ 失败';\n lines.push(`${status} | ${label} | 命令: ${result.command} | 退出码: ${result.exitCode}`);\n if (!result.success) {\n lines.push('```');\n lines.push(result.stderr || result.stdout || '(无输出)');\n lines.push('```');\n lines.push('');\n }\n });\n }\n\n return lines.join('\\n');\n}\n","import path from 'node:path';\nimport fs from 'fs-extra';\nimport { Logger } from './logger';\nimport { runCommand } from './utils';\n\n/**\n * 支持的包管理器类型。\n */\nexport type PackageManager = 'yarn' | 'pnpm' | 'npm';\n\ntype PackageManagerSource = 'packageManager' | 'lockfile' | 'default';\n\n/**\n * 解析包管理器所需的提示信息。\n */\nexport interface PackageManagerHints {\n readonly packageManagerField?: string;\n readonly hasYarnLock: boolean;\n readonly hasPnpmLock: boolean;\n readonly hasNpmLock: boolean;\n readonly hasNpmShrinkwrap: boolean;\n}\n\n/**\n * 包管理器解析结果。\n */\nexport interface PackageManagerResolution {\n readonly manager: PackageManager;\n readonly source: PackageManagerSource;\n readonly hasLock: boolean;\n}\n\nfunction parsePackageManagerField(value?: string): PackageManager | null {\n if (!value) return null;\n const normalized = value.trim().toLowerCase();\n if (normalized === 'yarn' || normalized.startsWith('yarn@')) return 'yarn';\n if (normalized === 'pnpm' || normalized.startsWith('pnpm@')) return 'pnpm';\n if (normalized === 'npm' || normalized.startsWith('npm@')) return 'npm';\n return null;\n}\n\nfunction hasLockForManager(manager: PackageManager, hints: PackageManagerHints): boolean {\n if (manager === 'yarn') return hints.hasYarnLock;\n if (manager === 'pnpm') return hints.hasPnpmLock;\n return hints.hasNpmLock || hints.hasNpmShrinkwrap;\n}\n\n/**\n * 根据 packageManager 字段或锁文件推断包管理器。\n */\nexport function resolvePackageManager(hints: PackageManagerHints): PackageManagerResolution {\n const fromField = parsePackageManagerField(hints.packageManagerField);\n if (fromField) {\n return {\n manager: fromField,\n source: 'packageManager',\n hasLock: hasLockForManager(fromField, hints)\n };\n }\n\n if (hints.hasYarnLock) {\n return {\n manager: 'yarn',\n source: 'lockfile',\n hasLock: true\n };\n }\n if (hints.hasPnpmLock) {\n return {\n manager: 'pnpm',\n source: 'lockfile',\n hasLock: true\n };\n }\n if (hints.hasNpmLock || hints.hasNpmShrinkwrap) {\n return {\n manager: 'npm',\n source: 'lockfile',\n hasLock: true\n };\n }\n\n return {\n manager: 'yarn',\n source: 'default',\n hasLock: false\n };\n}\n\n/**\n * 生成安装依赖命令。\n */\nexport function buildInstallCommand(resolution: PackageManagerResolution): string {\n switch (resolution.manager) {\n case 'yarn': {\n const args = ['yarn', 'install'];\n if (resolution.hasLock) {\n args.push('--frozen-lockfile');\n } else {\n args.push('--no-lockfile');\n }\n return args.join(' ');\n }\n case 'pnpm': {\n const args = ['pnpm', 'install'];\n if (resolution.hasLock) {\n args.push('--frozen-lockfile');\n }\n return args.join(' ');\n }\n case 'npm': {\n const args = resolution.hasLock ? ['npm', 'ci'] : ['npm', 'install'];\n args.push('--no-audit', '--no-fund');\n return args.join(' ');\n }\n default: {\n return 'yarn install';\n }\n }\n}\n\nfunction resolveSourceLabel(source: PackageManagerSource): string {\n switch (source) {\n case 'packageManager':\n return 'packageManager 字段';\n case 'lockfile':\n return '锁文件';\n case 'default':\n return '默认策略';\n default:\n return '未知来源';\n }\n}\n\nfunction extractPackageManagerField(value: unknown): string | undefined {\n if (typeof value !== 'object' || value === null) return undefined;\n const candidate = value as Record<string, unknown>;\n const field = candidate.packageManager;\n return typeof field === 'string' ? field : undefined;\n}\n\nasync function readPackageManagerHints(cwd: string, logger: Logger): Promise<PackageManagerHints | null> {\n const packageJsonPath = path.join(cwd, 'package.json');\n const hasPackageJson = await fs.pathExists(packageJsonPath);\n if (!hasPackageJson) return null;\n\n let packageManagerField: string | undefined;\n try {\n const packageJson = await fs.readJson(packageJsonPath);\n packageManagerField = extractPackageManagerField(packageJson);\n } catch (error) {\n logger.warn(`读取 package.json 失败,将改用锁文件判断包管理器: ${String(error)}`);\n }\n\n const [hasYarnLock, hasPnpmLock, hasNpmLock, hasNpmShrinkwrap] = await Promise.all([\n fs.pathExists(path.join(cwd, 'yarn.lock')),\n fs.pathExists(path.join(cwd, 'pnpm-lock.yaml')),\n fs.pathExists(path.join(cwd, 'package-lock.json')),\n fs.pathExists(path.join(cwd, 'npm-shrinkwrap.json'))\n ]);\n\n return {\n packageManagerField,\n hasYarnLock,\n hasPnpmLock,\n hasNpmLock,\n hasNpmShrinkwrap\n };\n}\n\n/**\n * 确保依赖已安装(按锁文件或 packageManager 字段选择包管理器)。\n */\nexport async function ensureDependencies(cwd: string, logger: Logger): Promise<void> {\n const hints = await readPackageManagerHints(cwd, logger);\n if (!hints) {\n logger.info('未检测到 package.json,跳过依赖检查');\n return;\n }\n\n const resolution = resolvePackageManager(hints);\n const sourceLabel = resolveSourceLabel(resolution.source);\n logger.info(`依赖检查:使用 ${resolution.manager}(来源:${sourceLabel})`);\n\n if (resolution.source === 'default') {\n logger.warn('未检测到 packageManager 配置或锁文件,将按默认策略安装依赖');\n }\n\n const command = buildInstallCommand(resolution);\n logger.info(`开始安装依赖: ${command}`);\n\n const result = await runCommand('bash', ['-lc', command], {\n cwd,\n logger,\n verboseLabel: 'deps',\n verboseCommand: `bash -lc \"${command}\"`,\n stream: {\n enabled: true,\n stdoutPrefix: '[deps] ',\n stderrPrefix: '[deps err] '\n }\n });\n\n if (result.exitCode !== 0) {\n const details = result.stderr || result.stdout || '无输出';\n throw new Error(`依赖安装失败: ${details}`);\n }\n\n logger.success('依赖检查完成');\n}\n","import { Logger } from './logger';\nimport { PrConfig } from './types';\nimport { runCommand } from './utils';\n\n/**\n * PR 基础信息。\n */\nexport interface GhPrInfo {\n readonly number: number;\n readonly url: string;\n readonly title: string;\n readonly state: string;\n readonly headRefName: string;\n}\n\n/**\n * Actions 运行信息。\n */\nexport interface GhRunInfo {\n readonly databaseId: number;\n readonly name: string;\n readonly status: string;\n readonly conclusion?: string | null;\n readonly url: string;\n}\n\nfunction isGhPrInfo(input: unknown): input is GhPrInfo {\n if (typeof input !== 'object' || input === null) return false;\n const candidate = input as Record<string, unknown>;\n return typeof candidate.number === 'number'\n && typeof candidate.url === 'string'\n && typeof candidate.title === 'string'\n && typeof candidate.state === 'string'\n && typeof candidate.headRefName === 'string';\n}\n\nfunction resolveRunDatabaseId(candidate: Record<string, unknown>): number | null {\n const databaseId = candidate.databaseId;\n if (typeof databaseId === 'number' && Number.isFinite(databaseId)) return databaseId;\n const id = candidate.id;\n if (typeof id === 'number' && Number.isFinite(id)) return id;\n if (typeof id === 'string') {\n const parsed = Number(id);\n if (Number.isFinite(parsed)) return parsed;\n }\n return null;\n}\n\nfunction parseGhRunInfo(input: unknown): GhRunInfo | null {\n if (typeof input !== 'object' || input === null) return null;\n const candidate = input as Record<string, unknown>;\n const databaseId = resolveRunDatabaseId(candidate);\n if (databaseId === null) return null;\n if (typeof candidate.name !== 'string') return null;\n if (typeof candidate.status !== 'string') return null;\n if (typeof candidate.url !== 'string') return null;\n const conclusion = candidate.conclusion;\n const hasValidConclusion = conclusion === undefined || conclusion === null || typeof conclusion === 'string';\n if (!hasValidConclusion) return null;\n return {\n databaseId,\n name: candidate.name,\n status: candidate.status,\n conclusion: conclusion ?? null,\n url: candidate.url\n };\n}\n\n/**\n * 解析 gh run list 的 JSON 输出。\n */\nexport function parseGhRunList(output: string): GhRunInfo[] {\n try {\n const parsed = JSON.parse(output);\n if (!Array.isArray(parsed)) return [];\n return parsed\n .map(parseGhRunInfo)\n .filter((run): run is GhRunInfo => run !== null);\n } catch {\n return [];\n }\n}\n\n/**\n * 解析 PR 标题,必要时给出兜底标题。\n */\nexport function resolvePrTitle(branch: string, title?: string): string {\n const trimmed = title?.trim();\n if (trimmed) return trimmed;\n return `chore: 自动 PR (${branch})`;\n}\n\n/**\n * 组装 gh pr create 所需参数。\n */\nexport function buildPrCreateArgs(branch: string, config: PrConfig): string[] {\n const args = ['pr', 'create', '--head', branch, '--title', resolvePrTitle(branch, config.title)];\n if (config.bodyPath) {\n args.push('--body-file', config.bodyPath);\n } else {\n args.push('--body', '自动生成 PR(未提供 body 文件)');\n }\n if (config.draft) {\n args.push('--draft');\n }\n if (config.reviewers && config.reviewers.length > 0) {\n args.push('--reviewer', config.reviewers.join(','));\n }\n return args;\n}\n\n/**\n * 判断 gh pr create 是否提示 PR 已存在。\n */\nexport function isPrAlreadyExistsMessage(output: string): boolean {\n const trimmed = output.trim();\n if (!trimmed) return false;\n const ghPattern =\n /a pull request for branch [\"']?[^\"']+[\"']? into branch [\"']?[^\"']+[\"']? already exists/i;\n if (ghPattern.test(trimmed)) return true;\n\n const hasAlreadyExists = /already exists/i.test(trimmed);\n const hasPrKeyword = /\\b(pull request|pr)\\b/i.test(trimmed);\n const hasBranch = /\\bbranch\\b/i.test(trimmed);\n if (hasAlreadyExists && hasPrKeyword && hasBranch) return true;\n\n const hasChineseExists = trimmed.includes('已存在');\n const hasChinesePr = trimmed.includes('拉取请求') || trimmed.includes('合并请求') || /\\bPR\\b/i.test(trimmed);\n const hasChineseBranch = trimmed.includes('分支');\n if (hasChineseExists && hasChinesePr && hasChineseBranch) return true;\n return false;\n}\n\nfunction extractPrUrl(output: string): string | null {\n const match = output.match(/https?:\\/\\/\\S+/);\n if (!match) return null;\n return match[0].replace(/[),.]+$/, '');\n}\n\n/**\n * 读取当前分支 PR 信息。\n */\nexport async function viewPr(branch: string, cwd: string, logger: Logger): Promise<GhPrInfo | null> {\n const result = await runCommand('gh', ['pr', 'view', branch, '--json', 'number,title,url,state,headRefName'], {\n cwd,\n logger,\n verboseLabel: 'gh',\n verboseCommand: `gh pr view ${branch} --json number,title,url,state,headRefName`\n });\n if (result.exitCode !== 0) {\n logger.warn(`gh pr view 失败: ${result.stderr}`);\n return null;\n }\n try {\n const parsed = JSON.parse(result.stdout);\n if (isGhPrInfo(parsed)) return parsed;\n logger.warn('gh pr view 返回格式异常');\n return null;\n } catch (error) {\n logger.warn(`解析 gh pr view 输出失败: ${String(error)}`);\n return null;\n }\n}\n\n/**\n * 创建 PR 并返回 PR 信息。\n */\nexport async function createPr(branch: string, config: PrConfig, cwd: string, logger: Logger): Promise<GhPrInfo | null> {\n if (!config.enable) return null;\n const args = buildPrCreateArgs(branch, config);\n\n const result = await runCommand('gh', args, {\n cwd,\n logger,\n verboseLabel: 'gh',\n verboseCommand: `gh ${args.join(' ')}`\n });\n if (result.exitCode !== 0) {\n const output = `${result.stderr}\\n${result.stdout}`.trim();\n if (isPrAlreadyExistsMessage(output)) {\n const existingPr = await viewPr(branch, cwd, logger);\n if (existingPr) {\n logger.warn(`创建 PR 失败,但检测到已有 PR,视为创建完成: ${existingPr.url}`);\n return existingPr;\n }\n const fallbackUrl = extractPrUrl(output);\n logger.warn('创建 PR 失败,提示已存在 PR,但读取 PR 信息失败,视为创建完成');\n return {\n number: 0,\n url: fallbackUrl ?? '未获取到链接',\n title: '已存在 PR(未获取详情)',\n state: 'unknown',\n headRefName: branch\n };\n }\n logger.warn(`创建 PR 失败: ${output || '未知错误'}`);\n return null;\n }\n\n return viewPr(branch, cwd, logger);\n}\n\n/**\n * 获取最近失败的 Actions 运行。\n */\nexport async function listFailedRuns(branch: string, cwd: string, logger: Logger): Promise<GhRunInfo[]> {\n const result = await runCommand('gh', ['run', 'list', '--branch', branch, '--json', 'databaseId,name,status,conclusion,url', '--limit', '5'], {\n cwd,\n logger,\n verboseLabel: 'gh',\n verboseCommand: `gh run list --branch ${branch} --json databaseId,name,status,conclusion,url --limit 5`\n });\n if (result.exitCode !== 0) {\n logger.warn(`获取 Actions 运行失败: ${result.stderr}`);\n return [];\n }\n try {\n const runs = parseGhRunList(result.stdout);\n const failed = runs.filter(run => run.conclusion && run.conclusion !== 'success');\n if (failed.length === 0) {\n logger.info('最近 5 次 Actions 运行无失败');\n }\n return failed;\n } catch (error) {\n logger.warn(`解析 Actions 输出失败: ${String(error)}`);\n return [];\n }\n}\n","import fs from 'fs-extra';\nimport { pad2 } from './utils';\n\ntype Colorizer = (value: string) => string;\ntype ConsoleMethodName = 'log' | 'warn' | 'error';\n\nconst wrap = (code: string): Colorizer => (value: string) => `\\u001b[${code}m${value}\\u001b[0m`;\n\nconst colors = {\n blue: wrap('34'),\n green: wrap('32'),\n yellow: wrap('33'),\n red: wrap('31'),\n magenta: wrap('35'),\n gray: wrap('90')\n} as const;\n\n/**\n * 日志器配置项。\n */\nexport interface LoggerOptions {\n readonly verbose?: boolean;\n readonly logFile?: string;\n}\n\n/**\n * 带颜色的日志输出器,可选写入日志文件。\n */\nexport class Logger {\n private readonly verbose: boolean;\n private readonly logFile?: string;\n private logFileEnabled: boolean;\n private logFileErrored: boolean;\n\n constructor(options: LoggerOptions = {}) {\n this.verbose = options.verbose ?? false;\n const trimmedPath = options.logFile?.trim();\n this.logFile = trimmedPath && trimmedPath.length > 0 ? trimmedPath : undefined;\n this.logFileEnabled = Boolean(this.logFile);\n this.logFileErrored = false;\n\n if (this.logFile) {\n try {\n fs.ensureFileSync(this.logFile);\n } catch (error) {\n this.disableFileWithError(error);\n }\n }\n }\n\n info(message: string): void {\n this.emit('log', colors.blue, 'info', ' ', message);\n }\n\n success(message: string): void {\n this.emit('log', colors.green, 'ok', ' ', message);\n }\n\n warn(message: string): void {\n this.emit('warn', colors.yellow, 'warn', ' ', message);\n }\n\n error(message: string): void {\n this.emit('error', colors.red, 'err', ' ', message);\n }\n\n debug(message: string): void {\n if (!this.verbose) return;\n this.emit('log', colors.magenta, 'dbg', ' ', message);\n }\n\n private emit(method: ConsoleMethodName, colorizer: Colorizer, label: string, padding: string, message: string): void {\n const now = new Date();\n const consoleLine = this.formatConsoleLine(now, colorizer(label), padding, message);\n const fileLine = this.formatFileLine(now, label, padding, message);\n console[method](consoleLine);\n this.writeFileLine(fileLine);\n }\n\n private formatConsoleLine(date: Date, label: string, padding: string, message: string): string {\n const timestamp = this.formatTimestamp(date);\n return `${colors.gray(timestamp)} ${label}${padding}${message}`;\n }\n\n private formatFileLine(date: Date, label: string, padding: string, message: string): string {\n const timestamp = this.formatTimestamp(date);\n return `${timestamp} ${label}${padding}${message}`;\n }\n\n private writeFileLine(line: string): void {\n if (!this.logFileEnabled || !this.logFile) return;\n try {\n fs.appendFileSync(this.logFile, `${line}\\n`, 'utf8');\n } catch (error) {\n this.disableFileWithError(error);\n }\n }\n\n private disableFileWithError(error: unknown): void {\n this.logFileEnabled = false;\n if (this.logFileErrored) return;\n this.logFileErrored = true;\n const message = error instanceof Error ? error.message : String(error);\n const target = this.logFile ? ` (${this.logFile})` : '';\n console.warn(`日志文件写入失败${target},已停止写入:${message}`);\n }\n\n private formatTimestamp(date: Date): string {\n const year = date.getFullYear();\n const month = pad2(date.getMonth() + 1);\n const day = pad2(date.getDate());\n const hours = pad2(date.getHours());\n const minutes = pad2(date.getMinutes());\n const seconds = pad2(date.getSeconds());\n return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;\n }\n}\n\n/**\n * 默认日志器实例。\n */\nexport const defaultLogger = new Logger();\n","import { Logger } from './logger';\nimport { RunMetadata, removeCurrentRegistry, upsertCurrentRegistry, writeRunMetadata } from './logs';\n\nexport interface RunTracker {\n readonly update: (round: number, tokenUsed: number) => Promise<void>;\n readonly finalize: () => Promise<void>;\n}\n\ninterface RunTrackerOptions {\n readonly logFile?: string;\n readonly command: string;\n readonly path: string;\n readonly logger?: Logger;\n}\n\nasync function safeWrite(logFile: string, metadata: RunMetadata, logger?: Logger): Promise<void> {\n try {\n await writeRunMetadata(logFile, metadata);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n logger?.warn(`写入运行元信息失败: ${message}`);\n }\n try {\n await upsertCurrentRegistry(logFile, metadata);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n logger?.warn(`更新 current.json 失败: ${message}`);\n }\n}\n\nasync function safeRemove(logFile: string, logger?: Logger): Promise<void> {\n try {\n await removeCurrentRegistry(logFile);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n logger?.warn(`清理 current.json 失败: ${message}`);\n }\n}\n\n/**\n * 创建运行中任务的追踪器(写入 JSON 元数据)。\n */\nexport async function createRunTracker(options: RunTrackerOptions): Promise<RunTracker | null> {\n const { logFile, command, path, logger } = options;\n if (!logFile) return null;\n\n const update = async (round: number, tokenUsed: number): Promise<void> => {\n const metadata: RunMetadata = {\n command,\n round,\n tokenUsed,\n path\n };\n await safeWrite(logFile, metadata, logger);\n };\n\n await update(0, 0);\n\n return {\n update,\n finalize: async (): Promise<void> => {\n await safeRemove(logFile, logger);\n }\n };\n}\n","import { DeliverySummary, TestRunResult } from './types';\n\n/**\n * 生成交付摘要提示的输入。\n */\nexport interface SummaryPromptInput {\n readonly task: string;\n readonly plan: string;\n readonly notes: string;\n readonly lastAiOutput: string;\n readonly testResults: TestRunResult[] | null;\n readonly gitStatus: string;\n readonly diffStat: string;\n readonly branchName?: string;\n}\n\n/**\n * 兜底摘要输入。\n */\nexport interface SummaryFallbackInput {\n readonly task: string;\n readonly testResults: TestRunResult[] | null;\n}\n\n/**\n * PR 文案兜底输入。\n */\nexport interface PrBodyFallbackInput {\n readonly commitTitle: string;\n readonly commitBody?: string;\n readonly testResults: TestRunResult[] | null;\n}\n\nconst REQUIRED_SECTIONS = ['# 变更摘要', '# 测试结果', '# 风险与回滚'] as const;\n\nfunction normalizeText(text: string): string {\n return text.replace(/\\r\\n?/g, '\\n');\n}\n\nfunction compactLine(text: string): string {\n return text.replace(/\\s+/g, ' ').trim();\n}\n\nfunction trimTail(text: string, limit: number, emptyFallback: string): string {\n const normalized = normalizeText(text).trim();\n if (!normalized) return emptyFallback;\n if (normalized.length <= limit) return normalized;\n return `(内容过长,保留最后 ${limit} 字符)\\n${normalized.slice(-limit)}`;\n}\n\nfunction formatTestResultLines(testResults: TestRunResult[] | null): string[] {\n if (!testResults || testResults.length === 0) {\n return ['- 未运行(本次未执行测试)'];\n }\n return testResults.map(result => {\n const label = result.kind === 'unit' ? '单元测试' : 'e2e 测试';\n const status = result.success ? '通过' : `失败(退出码 ${result.exitCode})`;\n const command = result.command ? `|命令: ${result.command}` : '';\n return `- ${label}: ${status} ${command}`.trim();\n });\n}\n\nfunction formatTestResultsForPrompt(testResults: TestRunResult[] | null): string {\n return formatTestResultLines(testResults).join('\\n');\n}\n\nfunction buildSummaryLinesFromCommit(commitTitle: string, commitBody?: string): string[] {\n const bulletLines = extractBulletLines(commitBody);\n if (bulletLines.length > 0) return bulletLines;\n const summary = stripCommitType(commitTitle);\n return [`- ${summary}`];\n}\n\nfunction stripCommitType(title: string): string {\n const trimmed = compactLine(title);\n if (!trimmed) return '更新迭代产出';\n const match = trimmed.match(/^[^:]+:\\s*(.+)$/);\n return match?.[1]?.trim() || trimmed;\n}\n\nfunction buildPrBody(summaryLines: string[], testLines: string[]): string {\n const riskLines = ['- 风险:待评估', '- 回滚:git revert 对应提交或关闭 PR'];\n return [\n '# 变更摘要',\n summaryLines.join('\\n'),\n '',\n '# 测试结果',\n testLines.join('\\n'),\n '',\n '# 风险与回滚',\n riskLines.join('\\n')\n ].join('\\n');\n}\n\n/**\n * 构建交付摘要提示词。\n */\nexport function buildSummaryPrompt(input: SummaryPromptInput): string {\n const planSnippet = trimTail(input.plan, 2000, '(计划为空)');\n const notesSnippet = trimTail(input.notes, 4000, '(notes 为空)');\n const aiSnippet = trimTail(input.lastAiOutput, 3000, '(本轮无 AI 输出)');\n const statusSnippet = trimTail(input.gitStatus, 1000, '(git status 为空)');\n const diffSnippet = trimTail(input.diffStat, 1000, '(diff 统计为空)');\n const testSummary = formatTestResultsForPrompt(input.testResults);\n\n return [\n '# 角色',\n '你是资深工程师,需要为本次迭代生成提交信息与 PR 文案。',\n '# 任务',\n '基于输入信息输出严格 JSON(不要 markdown、不要代码块、不要多余文字)。',\n '要求:',\n '- 全部中文。',\n '- commitTitle / prTitle 使用 Conventional Commits 格式:<type>: <概要>,简洁具体,不要出现“自动迭代提交/自动 PR”等字样。',\n '- commitBody 为多行要点列表(可为空字符串)。',\n '- prBody 为 Markdown,必须包含标题:# 变更摘要、# 测试结果、# 风险与回滚,并在变更摘要中体现工作总结。',\n '- 不确定处可基于现有信息合理推断,但不要编造测试结果。',\n '# 输出 JSON',\n '{\"commitTitle\":\"...\",\"commitBody\":\"...\",\"prTitle\":\"...\",\"prBody\":\"...\"}',\n '# 输入信息',\n `任务: ${compactLine(input.task) || '(空)'}`,\n `分支: ${input.branchName ?? '(未知)'}`,\n '计划(节选):',\n planSnippet,\n 'notes(节选):',\n notesSnippet,\n '最近一次 AI 输出(节选):',\n aiSnippet,\n '测试结果:',\n testSummary,\n 'git status --short:',\n statusSnippet,\n 'git diff --stat:',\n diffSnippet\n ].join('\\n\\n');\n}\n\nfunction pickString(record: Record<string, unknown>, keys: string[]): string | null {\n for (const key of keys) {\n const value = record[key];\n if (typeof value === 'string' && value.trim().length > 0) {\n return value.trim();\n }\n }\n return null;\n}\n\nfunction extractJson(text: string): string | null {\n const fenced = text.match(/```(?:json)?\\s*([\\s\\S]*?)```/i);\n if (fenced?.[1]) return fenced[1].trim();\n const start = text.indexOf('{');\n const end = text.lastIndexOf('}');\n if (start >= 0 && end > start) {\n return text.slice(start, end + 1).trim();\n }\n return null;\n}\n\nfunction normalizeTitle(title: string): string {\n return compactLine(title);\n}\n\nfunction normalizeBody(body?: string | null): string | undefined {\n if (!body) return undefined;\n const normalized = normalizeText(body).trim();\n return normalized.length > 0 ? normalized : undefined;\n}\n\nfunction extractBulletLines(text?: string | null): string[] {\n if (!text) return [];\n const lines = normalizeText(text)\n .split('\\n')\n .map(line => line.trim())\n .filter(Boolean);\n const bullets = lines.filter(line => line.startsWith('- ') || line.startsWith('* '));\n return bullets.map(line => (line.startsWith('* ') ? `- ${line.slice(2).trim()}` : line));\n}\n\n/**\n * 解析 AI 输出的交付摘要 JSON。\n */\nexport function parseDeliverySummary(output: string): DeliverySummary | null {\n const jsonText = extractJson(output);\n if (!jsonText) return null;\n try {\n const parsed = JSON.parse(jsonText) as Record<string, unknown>;\n let commitTitle = pickString(parsed, ['commitTitle', 'commit_message', 'commitMessage', 'commit_title']);\n let commitBody = pickString(parsed, ['commitBody', 'commit_body']);\n let prTitle = pickString(parsed, ['prTitle', 'pr_title']);\n let prBody = pickString(parsed, ['prBody', 'pr_body']);\n\n const commitObj = parsed.commit;\n if ((!commitTitle || !commitBody) && typeof commitObj === 'object' && commitObj !== null) {\n const commitRecord = commitObj as Record<string, unknown>;\n commitTitle = commitTitle ?? pickString(commitRecord, ['title', 'commitTitle']);\n commitBody = commitBody ?? pickString(commitRecord, ['body', 'commitBody']);\n }\n\n const prObj = parsed.pr;\n if ((!prTitle || !prBody) && typeof prObj === 'object' && prObj !== null) {\n const prRecord = prObj as Record<string, unknown>;\n prTitle = prTitle ?? pickString(prRecord, ['title', 'prTitle']);\n prBody = prBody ?? pickString(prRecord, ['body', 'prBody']);\n }\n\n if (!commitTitle || !prTitle || !prBody) return null;\n\n const normalizedCommitTitle = normalizeTitle(commitTitle);\n const normalizedPrTitle = normalizeTitle(prTitle);\n const normalizedCommitBody = normalizeBody(commitBody);\n const normalizedPrBody = normalizeText(prBody).trim();\n\n if (!normalizedCommitTitle || !normalizedPrTitle || !normalizedPrBody) return null;\n\n return {\n commitTitle: normalizedCommitTitle,\n commitBody: normalizedCommitBody,\n prTitle: normalizedPrTitle,\n prBody: normalizedPrBody\n };\n } catch {\n return null;\n }\n}\n\n/**\n * 构建兜底交付摘要。\n */\nexport function buildFallbackSummary(input: SummaryFallbackInput): DeliverySummary {\n const taskLine = compactLine(input.task);\n const shortTask = taskLine.length > 50 ? `${taskLine.slice(0, 50)}...` : taskLine;\n const baseTitle = shortTask || '更新迭代产出';\n const title = `chore: ${baseTitle}`;\n const summaryLines = [`- ${baseTitle}`];\n const testLines = formatTestResultLines(input.testResults);\n const prBody = buildPrBody(summaryLines, testLines);\n return {\n commitTitle: title,\n commitBody: summaryLines.join('\\n'),\n prTitle: title,\n prBody\n };\n}\n\n/**\n * 确保 PR 文案包含必要章节。\n */\nexport function ensurePrBodySections(prBody: string, fallback: PrBodyFallbackInput): string {\n const normalized = normalizeText(prBody).trim();\n const hasAll = REQUIRED_SECTIONS.every(section => normalized.includes(section));\n if (hasAll) return normalized;\n\n const summaryLines = buildSummaryLinesFromCommit(fallback.commitTitle, fallback.commitBody);\n const testLines = formatTestResultLines(fallback.testResults);\n return buildPrBody(summaryLines, testLines);\n}\n","import { Logger } from './logger';\nimport { isoNow } from './utils';\nimport type { WebhookConfig } from './types';\n\nexport type WebhookEvent = 'task_start' | 'iteration_start' | 'task_end';\n\nexport interface WebhookPayload {\n readonly event: WebhookEvent;\n readonly task: string;\n readonly branch: string;\n readonly iteration: number;\n readonly stage: string;\n readonly timestamp: string;\n}\n\nexport interface WebhookPayloadInput {\n readonly event: WebhookEvent;\n readonly task: string;\n readonly branch?: string;\n readonly iteration: number;\n readonly stage: string;\n readonly timestamp?: string;\n}\n\nexport type FetchLikeResponse = {\n readonly ok: boolean;\n readonly status: number;\n readonly statusText: string;\n};\n\nexport type FetchLike = (url: string, init: {\n readonly method: string;\n readonly headers: Record<string, string>;\n readonly body: string;\n readonly signal?: AbortSignal;\n}) => Promise<FetchLikeResponse>;\n\nconst DEFAULT_TIMEOUT_MS = 8000;\n\nexport function normalizeWebhookUrls(urls?: string[]): string[] {\n if (!urls || urls.length === 0) return [];\n return urls\n .map(url => url.trim())\n .filter(url => url.length > 0);\n}\n\nexport function buildWebhookPayload(input: WebhookPayloadInput): WebhookPayload {\n return {\n event: input.event,\n task: input.task,\n branch: input.branch ?? '',\n iteration: input.iteration,\n stage: input.stage,\n timestamp: input.timestamp ?? isoNow()\n };\n}\n\nfunction resolveFetcher(fetcher?: FetchLike): FetchLike | null {\n if (fetcher) return fetcher;\n const globalFetcher = globalThis.fetch;\n if (typeof globalFetcher !== 'function') return null;\n return (globalFetcher as typeof fetch) as FetchLike;\n}\n\nasync function postWebhook(url: string, payload: WebhookPayload, timeoutMs: number, logger: Logger, fetcher: FetchLike): Promise<void> {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeoutMs);\n try {\n const response = await fetcher(url, {\n method: 'POST',\n headers: {\n 'content-type': 'application/json'\n },\n body: JSON.stringify(payload),\n signal: controller.signal\n });\n if (!response.ok) {\n logger.warn(`webhook 请求失败(${response.status} ${response.statusText}):${url}`);\n } else {\n logger.debug(`webhook 通知成功:${url}`);\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n logger.warn(`webhook 通知异常:${url}|${message}`);\n } finally {\n clearTimeout(timer);\n }\n}\n\nexport async function sendWebhookNotifications(\n config: WebhookConfig | null | undefined,\n payload: WebhookPayload,\n logger: Logger,\n fetcher?: FetchLike\n): Promise<void> {\n const urls = normalizeWebhookUrls(config?.urls);\n if (urls.length === 0) return;\n\n const resolvedFetcher = resolveFetcher(fetcher);\n if (!resolvedFetcher) {\n logger.warn('当前 Node 环境不支持 fetch,已跳过 webhook 通知');\n return;\n }\n\n const timeoutMs = config?.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n await Promise.all(urls.map(url => postWebhook(url, payload, timeoutMs, logger, resolvedFetcher)));\n}\n","import fs from 'fs-extra';\nimport path from 'node:path';\nimport { CurrentRegistryEntry, getLogsDir, readCurrentRegistry } from './logs';\n\ninterface TaskView {\n readonly key: string;\n readonly logFile: string;\n readonly meta: CurrentRegistryEntry;\n readonly lines: string[];\n}\n\ninterface MonitorState {\n tasks: TaskView[];\n selectedIndex: number;\n selectedKey?: string;\n pageOffsets: Map<string, number>;\n stickToBottom: Map<string, boolean>;\n lastError?: string;\n}\n\nconst REFRESH_INTERVAL = 1000;\n\nfunction getTerminalSize(): { rows: number; columns: number } {\n const rows = process.stdout.rows ?? 24;\n const columns = process.stdout.columns ?? 80;\n return { rows, columns };\n}\n\nfunction truncateLine(line: string, width: number): string {\n if (width <= 0) return '';\n if (line.length <= width) return line;\n return line.slice(0, width);\n}\n\nasync function readLogLines(logFile: string): Promise<string[]> {\n try {\n const content = await fs.readFile(logFile, 'utf8');\n const normalized = content.replace(/\\r\\n?/g, '\\n');\n const lines = normalized.split('\\n');\n return lines.length > 0 ? lines : [''];\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n return [`(无法读取日志文件:${message})`];\n }\n}\n\nasync function loadTasks(logsDir: string): Promise<TaskView[]> {\n const registry = await readCurrentRegistry();\n const entries = Object.entries(registry).sort(([a], [b]) => a.localeCompare(b));\n const tasks = await Promise.all(entries.map(async ([key, meta]) => {\n const logFile = meta.logFile ?? path.join(logsDir, key);\n const lines = await readLogLines(logFile);\n return {\n key,\n logFile,\n meta,\n lines\n } satisfies TaskView;\n }));\n return tasks;\n}\n\nfunction buildHeader(state: MonitorState, columns: number): string {\n if (state.tasks.length === 0) {\n return truncateLine('暂无运行中的任务,按 q 退出', columns);\n }\n const current = state.tasks[state.selectedIndex];\n const total = state.tasks.length;\n const index = state.selectedIndex + 1;\n const title = `任务 ${index}/${total} | ${current.key} | ←/→ 切换任务 ↑/↓ 翻页 q 退出`;\n return truncateLine(title, columns);\n}\n\nfunction buildStatus(\n task: TaskView,\n page: { current: number; total: number },\n columns: number,\n errorMessage?: string\n): string {\n const meta = task.meta;\n const status = `轮次 ${meta.round} | Token ${meta.tokenUsed} | 页 ${page.current}/${page.total} | 项目 ${meta.path}`;\n const suffix = errorMessage ? ` | 刷新失败:${errorMessage}` : '';\n return truncateLine(`${status}${suffix}`, columns);\n}\n\nfunction getPageSize(rows: number): number {\n return Math.max(1, rows - 2);\n}\n\nfunction render(state: MonitorState): void {\n const { rows, columns } = getTerminalSize();\n const pageSize = getPageSize(rows);\n const header = buildHeader(state, columns);\n\n if (state.tasks.length === 0) {\n const filler = Array.from({ length: pageSize }, () => '');\n const statusText = state.lastError ? `刷新失败:${state.lastError}` : '等待后台任务启动…';\n const status = truncateLine(statusText, columns);\n const content = [header, ...filler, status].join('\\n');\n process.stdout.write(`\\u001b[2J\\u001b[H${content}`);\n return;\n }\n\n const current = state.tasks[state.selectedIndex];\n const lines = current.lines;\n const maxOffset = Math.max(0, Math.ceil(lines.length / pageSize) - 1);\n const offset = state.pageOffsets.get(current.key) ?? maxOffset;\n const stick = state.stickToBottom.get(current.key) ?? true;\n const nextOffset = Math.min(Math.max(stick ? maxOffset : offset, 0), maxOffset);\n state.pageOffsets.set(current.key, nextOffset);\n state.stickToBottom.set(current.key, nextOffset === maxOffset);\n\n const start = nextOffset * pageSize;\n const pageLines = lines.slice(start, start + pageSize).map(line => truncateLine(line, columns));\n while (pageLines.length < pageSize) {\n pageLines.push('');\n }\n\n const status = buildStatus(\n current,\n { current: nextOffset + 1, total: Math.max(1, maxOffset + 1) },\n columns,\n state.lastError\n );\n const content = [header, ...pageLines, status].join('\\n');\n process.stdout.write(`\\u001b[2J\\u001b[H${content}`);\n}\n\nfunction updateSelection(state: MonitorState, tasks: TaskView[]): void {\n state.tasks = tasks;\n if (tasks.length === 0) {\n state.selectedIndex = 0;\n state.selectedKey = undefined;\n return;\n }\n\n if (state.selectedKey) {\n const index = tasks.findIndex(task => task.key === state.selectedKey);\n if (index >= 0) {\n state.selectedIndex = index;\n } else {\n state.selectedIndex = 0;\n }\n } else {\n state.selectedIndex = 0;\n }\n\n state.selectedKey = tasks[state.selectedIndex]?.key;\n\n const existing = new Set(tasks.map(task => task.key));\n for (const key of state.pageOffsets.keys()) {\n if (!existing.has(key)) {\n state.pageOffsets.delete(key);\n }\n }\n for (const key of state.stickToBottom.keys()) {\n if (!existing.has(key)) {\n state.stickToBottom.delete(key);\n }\n }\n}\n\nfunction moveSelection(state: MonitorState, direction: -1 | 1): void {\n if (state.tasks.length === 0) return;\n const total = state.tasks.length;\n state.selectedIndex = (state.selectedIndex + direction + total) % total;\n state.selectedKey = state.tasks[state.selectedIndex]?.key;\n}\n\nfunction movePage(state: MonitorState, direction: -1 | 1): void {\n if (state.tasks.length === 0) return;\n const { rows } = getTerminalSize();\n const pageSize = getPageSize(rows);\n const current = state.tasks[state.selectedIndex];\n const lines = current.lines;\n const maxOffset = Math.max(0, Math.ceil(lines.length / pageSize) - 1);\n const offset = state.pageOffsets.get(current.key) ?? maxOffset;\n const nextOffset = Math.min(Math.max(offset + direction, 0), maxOffset);\n state.pageOffsets.set(current.key, nextOffset);\n state.stickToBottom.set(current.key, nextOffset === maxOffset);\n}\n\nfunction shouldExit(input: string): boolean {\n if (input === '\\u0003') return true;\n if (input.toLowerCase() === 'q') return true;\n return false;\n}\n\nfunction handleInput(state: MonitorState, input: string): void {\n if (input.includes('\\u001b[D')) {\n moveSelection(state, -1);\n return;\n }\n if (input.includes('\\u001b[C')) {\n moveSelection(state, 1);\n return;\n }\n if (input.includes('\\u001b[A')) {\n movePage(state, -1);\n return;\n }\n if (input.includes('\\u001b[B')) {\n movePage(state, 1);\n return;\n }\n}\n\nfunction setupCleanup(cleanup: () => void): void {\n const exitHandler = (): void => {\n cleanup();\n };\n const signalHandler = (): void => {\n cleanup();\n process.exit(0);\n };\n process.on('SIGINT', signalHandler);\n process.on('SIGTERM', signalHandler);\n process.on('exit', exitHandler);\n}\n\n/**\n * 启动 monitor 终端界面。\n */\nexport async function runMonitor(): Promise<void> {\n if (!process.stdout.isTTY || !process.stdin.isTTY) {\n console.log('当前终端不支持交互式 monitor。');\n return;\n }\n\n const logsDir = getLogsDir();\n const state: MonitorState = {\n tasks: [],\n selectedIndex: 0,\n pageOffsets: new Map(),\n stickToBottom: new Map()\n };\n\n let cleaned = false;\n const cleanup = (): void => {\n if (cleaned) return;\n cleaned = true;\n if (process.stdin.isTTY) {\n process.stdin.setRawMode(false);\n process.stdin.pause();\n }\n process.stdout.write('\\u001b[?25h');\n };\n\n setupCleanup(cleanup);\n process.stdout.write('\\u001b[?25l');\n process.stdin.setRawMode(true);\n process.stdin.resume();\n\n let refreshing = false;\n\n const refresh = async (): Promise<void> => {\n if (refreshing) return;\n refreshing = true;\n try {\n const tasks = await loadTasks(logsDir);\n state.lastError = undefined;\n updateSelection(state, tasks);\n render(state);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n state.lastError = message;\n render(state);\n } finally {\n refreshing = false;\n }\n };\n\n await refresh();\n\n const timer = setInterval(refresh, REFRESH_INTERVAL);\n\n process.stdin.on('data', (data: Buffer) => {\n const input = data.toString('utf8');\n if (shouldExit(input)) {\n clearInterval(timer);\n cleanup();\n process.exit(0);\n }\n handleInput(state, input);\n render(state);\n });\n\n process.stdout.on('resize', () => {\n render(state);\n });\n}\n"],"mappings":"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","names":["import_node_path","path","fs","path","import_node_path","import_fs_extra","path","os","fs","import_node_path","path","import_node_os","import_node_path","import_fs_extra","path","os","fs","import_fs_extra","import_node_path","path","fs","status","content","import_fs_extra","import_node_path","import_node_path","import_fs_extra","path","fs","import_fs_extra","fs","path","path","fs","import_fs_extra","import_node_path","getTerminalSize","truncateLine","readLogLines","fs","path","getPageSize","render","status","content","shouldExit","setupCleanup"]}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# wheel-ai AI 工作流程指南
|
|
2
|
+
|
|
3
|
+
> 将本文件作为每轮提示的前置上下文,帮助 AI 自主完成从需求到 PR 的闭环。所有输出请保持中文,能落地的步骤直接执行,不要重复询问。
|
|
4
|
+
|
|
5
|
+
## 总体原则
|
|
6
|
+
- 充分利用持久化文件:`plan` 维护可执行计划,`notes` 记录每轮结论/风险/遗留问题。每轮必须更新 notes,必要时重写 plan 使其保持最新。
|
|
7
|
+
- 开发分支统一在 git worktree 中进行,遵循“基线分支 → 派生分支 → 迭代 → PR”的流程。
|
|
8
|
+
- 与 git/PR 相关的操作仅使用 `gh` 命令(查看 PR、创建 PR、查看 Actions 失败记录)。
|
|
9
|
+
- 默认测试命令:单元测试 `yarn test`,e2e 测试 `yarn e2e`,如需调整请在 plan 中显式写出新的命令。
|
|
10
|
+
|
|
11
|
+
## 步骤 1:完善需求
|
|
12
|
+
- 复述并澄清任务,标出输入、输出、约束、验收标准。
|
|
13
|
+
- 列出不确定点并自行做出合理假设(在 notes 记录假设)。
|
|
14
|
+
- 产出:需求摘要(要写入 notes)。
|
|
15
|
+
|
|
16
|
+
## 步骤 2:生成计划
|
|
17
|
+
- 形成分阶段的任务树:需求澄清 → 设计 → 开发 → 自审 → 测试 → PR。
|
|
18
|
+
- 为每个阶段列出可执行子任务、负责人(默认 AI)、预计产出、检查点。
|
|
19
|
+
- 将计划写入 `plan` 文件,保持随迭代更新,已完成项用 ✅ 标记。
|
|
20
|
+
|
|
21
|
+
## 步骤 3:设计与开发
|
|
22
|
+
- 先给出技术方案:文件/模块变更列表、数据结构、关键算法、外部依赖、潜在风险。
|
|
23
|
+
- 直接生成或修改代码;若需脚手架/依赖,请写出命令并在可行时直接执行。
|
|
24
|
+
- 代码须符合 TypeScript 严格类型(避免 any),遵循项目现有规范。
|
|
25
|
+
|
|
26
|
+
## 步骤 4:代码自审
|
|
27
|
+
- 自检清单:
|
|
28
|
+
- 需求覆盖与边界条件是否完整。
|
|
29
|
+
- 类型安全、错误处理、日志可读性。
|
|
30
|
+
- 与 git worktree 兼容性、命令幂等性。
|
|
31
|
+
- 产出:风险与改进列表,写入 notes。
|
|
32
|
+
|
|
33
|
+
## 步骤 5:生成与执行测试
|
|
34
|
+
- 至少输出:
|
|
35
|
+
- 单元测试范围与用例表。
|
|
36
|
+
- e2e 场景与前置条件。
|
|
37
|
+
- 对应的命令行(可直接运行)。
|
|
38
|
+
- 在环境允许时直接执行测试命令,收集结果与失败原因写入 notes。
|
|
39
|
+
|
|
40
|
+
## 步骤 6:推送并提交 PR
|
|
41
|
+
- 检查 git 状态,准备提交信息(建议格式:`chore: <任务概要>`)。
|
|
42
|
+
- 使用 `gh pr create --head <branch> --title "<标题>" --body-file <path>`(或 `--body "<正文>"`)创建 PR,正文应包含:
|
|
43
|
+
- 变更摘要(bullet 列表)
|
|
44
|
+
- 测试结果(含失败原因)
|
|
45
|
+
- 风险与回滚方案
|
|
46
|
+
- 若已有 PR,使用 `gh pr view <branch>` 获取链接;查看 Actions 失败可运行 `gh run list --branch <branch>`。
|
|
47
|
+
|
|
48
|
+
## 步骤 7:持久化记忆与对话续航
|
|
49
|
+
- 每轮结束必须向 notes 追加:
|
|
50
|
+
- 关键决策与理由
|
|
51
|
+
- 代码/测试进展
|
|
52
|
+
- 阻塞与下一步计划
|
|
53
|
+
- 当阶段性任务完成或需要清理上下文时,开启新对话并把 plan 与 notes 作为前置信息继续。
|
|
54
|
+
|
|
55
|
+
## 输出规范
|
|
56
|
+
- 在所有目标完成时,输出中加入标记 `<<DONE>>`,外层循环据此停止。
|
|
57
|
+
- 优先输出可执行命令与文件路径,便于外层自动化调用。
|
|
58
|
+
- 日志/说明保持简洁,用中文短句,避免重复。
|
package/package.json
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "hamster-wheel-cli",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "基于 AI CLI 的持续迭代开发工具,封装工作流、git worktree 与 gh PR 协作",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"wheel-ai",
|
|
8
|
+
"ai",
|
|
9
|
+
"cli",
|
|
10
|
+
"continuous-integration",
|
|
11
|
+
"continuous-delivery",
|
|
12
|
+
"continuous-deployment"
|
|
13
|
+
],
|
|
14
|
+
"bin": {
|
|
15
|
+
"wheel-ai": "dist/cli.js"
|
|
16
|
+
},
|
|
17
|
+
"repository": "git@github.com:wszxdhr/hamster-wheel-cli.git",
|
|
18
|
+
"author": "ZX <wszxdhr@126.com>",
|
|
19
|
+
"license": "MIT",
|
|
20
|
+
"type": "commonjs",
|
|
21
|
+
"engines": {
|
|
22
|
+
"node": ">=18"
|
|
23
|
+
},
|
|
24
|
+
"scripts": {
|
|
25
|
+
"build:all": "tsup",
|
|
26
|
+
"dev": "ts-node src/cli.ts",
|
|
27
|
+
"start": "node dist/cli.js",
|
|
28
|
+
"test": "node --test --require ts-node/register tests/*.test.ts",
|
|
29
|
+
"e2e": "node --test --test-concurrency=1 --require ts-node/register tests/e2e/**/*.ts"
|
|
30
|
+
},
|
|
31
|
+
"dependencies": {
|
|
32
|
+
"commander": "^14.0.2",
|
|
33
|
+
"execa": "^9.6.1",
|
|
34
|
+
"fs-extra": "^11.3.3"
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@types/fs-extra": "^11.0.4",
|
|
38
|
+
"@types/node": "^25.0.3",
|
|
39
|
+
"ts-node": "^10.9.2",
|
|
40
|
+
"tsup": "^8.5.1",
|
|
41
|
+
"typescript": "^5.9.3"
|
|
42
|
+
},
|
|
43
|
+
"packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
|
|
44
|
+
}
|