From f04eb6e766adb86be0ef0300fd5fee94bcc3a8c7 Mon Sep 17 00:00:00 2001 From: lanrtop Date: Wed, 15 Jul 2026 13:38:32 +0900 Subject: [PATCH] =?UTF-8?q?feat(onboarding):=20=E6=8E=A5=E5=85=A5=E5=8C=85?= =?UTF-8?q?=20v1.6.0=E2=80=94=E2=80=94=E8=93=9D=E5=9B=BE=E6=9C=BA=E5=99=A8?= =?UTF-8?q?=E9=97=A8=E6=8E=A7=E5=8F=8C=E5=B1=82=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A: feat: 提交须含 Feature-Confirmed: true trailer - lefthook.yml.tmpl commit-msg 新增 feature-confirmed 命令 - AGENTS.md.tmpl 需求对齐协议补 trailer 说明 B: pre-commit 检查未关闭 🔵 任务卡(warn only) - 新增 .claude/hooks/blueprint-gate.cjs(CommonJS,兼容 ESM 项目) - lefthook.yml.tmpl pre-commit 新增 blueprint-gate 命令 - onboarding.rs dispatch 新增 blueprint-gate.cjs Feature-Confirmed: true --- .../.claude/hooks/blueprint-gate.cjs | 31 +++++++++++++++++++ src-tauri/resources/onboarding/AGENTS.md.tmpl | 4 ++- .../resources/onboarding/lefthook.yml.tmpl | 6 ++++ src-tauri/src/commands/onboarding.rs | 2 ++ 4 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 src-tauri/resources/onboarding/.claude/hooks/blueprint-gate.cjs diff --git a/src-tauri/resources/onboarding/.claude/hooks/blueprint-gate.cjs b/src-tauri/resources/onboarding/.claude/hooks/blueprint-gate.cjs new file mode 100644 index 0000000..cf379f7 --- /dev/null +++ b/src-tauri/resources/onboarding/.claude/hooks/blueprint-gate.cjs @@ -0,0 +1,31 @@ +#!/usr/bin/env node +// 蓝图门控:pre-commit 检查未关闭的 🔵 任务卡,warn only(exit 0,不阻断提交)。 + +const fs = require('fs'); +const path = require('path'); + +const modulesDir = path.join(process.cwd(), '.blueprint', 'modules'); + +if (!fs.existsSync(modulesDir)) { + process.exit(0); +} + +const unclosed = []; +for (const file of fs.readdirSync(modulesDir).filter(f => f.endsWith('.md'))) { + const content = fs.readFileSync(path.join(modulesDir, file), 'utf8'); + for (const line of content.split('\n')) { + if (line.startsWith('### 🔵')) { + unclosed.push({ file, title: line.replace(/^###\s*🔵\s*/, '').trim() }); + } + } +} + +if (unclosed.length > 0) { + process.stderr.write('\n⚠️ 蓝图门控:发现未关闭任务卡\n'); + for (const { file, title } of unclosed) { + process.stderr.write(` 🔵 ${title}(${file})\n`); + } + process.stderr.write('\n 已完成 → 改为 ✅;仍进行中 → 属预期,可忽略本提示。\n\n'); +} + +process.exit(0); diff --git a/src-tauri/resources/onboarding/AGENTS.md.tmpl b/src-tauri/resources/onboarding/AGENTS.md.tmpl index 1b29911..1c8c10f 100644 --- a/src-tauri/resources/onboarding/AGENTS.md.tmpl +++ b/src-tauri/resources/onboarding/AGENTS.md.tmpl @@ -18,7 +18,7 @@ - + ## 核心开发约束 ### 包管理 @@ -55,6 +55,8 @@ **边界模糊时**:保守判断,按 Feature 处理,走完整确认卡。 +**提交时**:`feat:` 提交须在 commit message 末尾加 `Feature-Confirmed: true` trailer(lefthook commit-msg 强制检查)。这是确认卡已输出的机器层存证。 + > ⚠️ Session 结束汇总补录 ≠ 确认卡替代——补录仅适用于漂移检测触发后用户主动选择补录的场景,不得作为「先做再补」的通道。 ## Git 工作流 diff --git a/src-tauri/resources/onboarding/lefthook.yml.tmpl b/src-tauri/resources/onboarding/lefthook.yml.tmpl index b292980..bbe11a8 100644 --- a/src-tauri/resources/onboarding/lefthook.yml.tmpl +++ b/src-tauri/resources/onboarding/lefthook.yml.tmpl @@ -17,8 +17,14 @@ pre-commit: # run: pnpm --filter api typecheck # monorepo workspace # # run: pnpm exec tsc -p api/tsconfig.json --noEmit # 独立 tsconfig # # run: pnpm -r typecheck # 递归所有包 + blueprint-gate: + run: node .claude/hooks/blueprint-gate.cjs || true commit-msg: commands: conventional: run: "head -1 .git/COMMIT_EDITMSG | grep -qE '^(feat|fix|docs|chore|refactor|ci|perf|style|test|build|revert)(\\(.+\\))?!?: .+' || exit 1" + feature-confirmed: + run: | + head -1 .git/COMMIT_EDITMSG | grep -qE '^feat' || exit 0 + grep -q 'Feature-Confirmed: true' .git/COMMIT_EDITMSG || { printf '\n⚠️ feat: 提交须含 Feature-Confirmed: true trailer\n 在 commit message 末尾加一行:Feature-Confirmed: true\n (确认卡已与用户对齐,方可提交)\n\n' >&2; exit 1; } diff --git a/src-tauri/src/commands/onboarding.rs b/src-tauri/src/commands/onboarding.rs index b15540e..c115e4d 100644 --- a/src-tauri/src/commands/onboarding.rs +++ b/src-tauri/src/commands/onboarding.rs @@ -17,6 +17,7 @@ const TMPL_AGENTS: &str = include_str!("../../resources/onboarding/AGENTS.md.tmp const TMPL_LEFTHOOK: &str = include_str!("../../resources/onboarding/lefthook.yml.tmpl"); const TMPL_GIT_WORKFLOW: &str = include_str!("../../resources/onboarding/git-workflow.md.tmpl"); const TMPL_ENVOY: &str = include_str!("../../resources/onboarding/.claude/commands/envoy.md"); +const TMPL_BLUEPRINT_GATE: &str = include_str!("../../resources/onboarding/.claude/hooks/blueprint-gate.cjs"); /// 单个模板的分发结果。 #[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] @@ -147,6 +148,7 @@ pub fn dispatch_templates(project_path: &str) -> Vec { dispatch_one(root, "lefthook.yml", TMPL_LEFTHOOK), dispatch_versioned(root, "docs/ai-context/git-workflow.md", TMPL_GIT_WORKFLOW), dispatch_one(root, ".claude/commands/envoy.md", TMPL_ENVOY), + dispatch_one(root, ".claude/hooks/blueprint-gate.cjs", TMPL_BLUEPRINT_GATE), ] }