import { execFileSync } from 'node:child_process'; import { existsSync, mkdirSync, writeFileSync } from 'node:fs'; import path from 'node:path'; import { getFeatureDirectory, validateFeatureId } from './feature-record.mjs'; const [featureId, slug] = process.argv.slice(2); const repositoryRoot = process.cwd(); if (!featureId || !slug || !validateFeatureId(featureId)) { throw new Error('用法:npm run governance:start -- <功能编号> <英文短名称>'); } const featureDirectory = getFeatureDirectory(repositoryRoot, featureId, slug); const gitnexusDirectory = path.join(featureDirectory, 'gitnexus'); const beforeReport = path.join(gitnexusDirectory, 'before.md'); if (existsSync(beforeReport)) { throw new Error(`开发前报告已存在,为保护历史不会覆盖:${beforeReport}`); } mkdirSync(gitnexusDirectory, { recursive: true }); /** * 开发门禁直接调用参数数组,不拼接 shell 字符串,避免功能名称被解释为命令。 * stdio 使用 pipe 是为了把同一次运行的真实输出固化到功能档案中。 */ function run(command, args) { return execFileSync(command, args, { cwd: repositoryRoot, encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'], }).trim(); } const branch = run('git', ['branch', '--show-current']) || '(尚无分支)'; const commit = run('git', ['rev-parse', '--verify', 'HEAD']).slice(0, 12); const worktree = run('git', ['status', '--short']) || '(干净)'; run('npx', ['gitnexus', 'analyze']); const gitnexusStatus = run('npx', ['gitnexus', 'status']); const createdAt = new Intl.DateTimeFormat('zh-CN', { dateStyle: 'long', timeStyle: 'long', timeZone: 'Asia/Shanghai', }).format(new Date()); writeFileSync( beforeReport, `# GitNexus 开发前基线\n\n` + `- 功能编号:${featureId}\n` + `- 记录时间:${createdAt}\n` + `- 分支:${branch}\n` + `- 基线提交:${commit}\n\n` + `## 工作区\n\n\`\`\`text\n${worktree}\n\`\`\`\n\n` + `## GitNexus 状态\n\n\`\`\`text\n${gitnexusStatus}\n\`\`\`\n\n` + `## 后续人工分析\n\n` + `在修改代码前,将 GitNexus query、context、impact 的结论写入 ` + `\`gitnexus/impact-plan.md\`。高风险结果必须先获得用户确认。\n`, 'utf8', ); process.stdout.write(`已创建开发前基线:${beforeReport}\n`);