import { execFileSync } from 'node:child_process'; import { existsSync, mkdirSync, writeFileSync } from 'node:fs'; import path from 'node:path'; import { assertCurrentReleasedBaselinePublished } from '../database/schema-baseline.mjs'; import { buildImpactPlanTemplate, 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'); const impactPlan = path.join(gitnexusDirectory, 'impact-plan.md'); // Schema 基线必须在新版本的功能档案和 GitNexus 分析之前已经独立提交; // 这里仅做只读验证,绝不在一般功能开发命令中连接数据库或静默生成历史产物。 assertCurrentReleasedBaselinePublished(repositoryRoot); const existingReports = [beforeReport, impactPlan].filter((file) => existsSync(file)); if (existingReports.length > 0) { throw new Error(`开发前报告已存在,为保护历史不会覆盖:${existingReports.join(', ')}`); } 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', ); writeFileSync(impactPlan, buildImpactPlanTemplate(featureId), 'utf8'); process.stdout.write(`已创建开发前基线:${beforeReport}\n已创建影响计划:${impactPlan}\n`);