harveyz-skill 0.2.1 → 0.3.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/README.md +94 -15
- package/bin/cli.js +12 -2
- package/lib/bundles.js +16 -0
- package/package.json +2 -1
- package/skills/harness/git-workflow-init/SKILL.md +321 -0
- package/skills/harness/git-workflow-init/evals/evals.json +104 -0
- package/skills/harness/git-workflow-init/references/git-workflow-template.md +94 -0
- package/skills/harness/git-workflow-init/references/hook-templates.md +232 -0
- package/skills/harness/git-workflow-init/references/lock-file-format.md +34 -0
- package/skills/harness/git-workflow-init/references/render_docs.py +261 -0
- package/skills/harness/git-workflow-init/references/workflow-config.yml +99 -0
- package/skills-index.json +2 -1
- package/tools/p-launch/p-launch.sh +32 -7
- package/tools/p-launch/tests/unit.bats +78 -1
package/README.md
CHANGED
|
@@ -4,12 +4,73 @@ Harvey 的个人 Claude Code 技能仓库。
|
|
|
4
4
|
|
|
5
5
|
## 技能清单
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
按 bundle 分组,`npx harveyz-skill --bundle <bundle>` 安装对应分组。
|
|
8
|
+
|
|
9
|
+
### analysis — 分析工具
|
|
10
|
+
|
|
11
|
+
| 技能 | 说明 |
|
|
12
|
+
|------|------|
|
|
13
|
+
| **skill-analyzer** | 系统化分析 Skill 仓库的框架,基于洋葱模型四层结构 |
|
|
14
|
+
|
|
15
|
+
### brainstorming — 设计与规划工具
|
|
16
|
+
|
|
17
|
+
| 技能 | 说明 |
|
|
18
|
+
|------|------|
|
|
19
|
+
| **brainstorming** | 设计前强制探索阶段 — 在实现任何功能前,先理解意图、需求和设计方案(HARD-GATE) |
|
|
20
|
+
| **writing-plans** | 将设计拆解为可执行的小任务(2–5 分钟/任务),含精确文件路径和验证步骤 |
|
|
21
|
+
|
|
22
|
+
### dev — 开发工作流
|
|
23
|
+
|
|
24
|
+
| 技能 | 说明 |
|
|
25
|
+
|------|------|
|
|
26
|
+
| **git-workflow-init** | 初始化或更新 git 分支管理规范,差量部署 git hooks,生成工作流文档 |
|
|
27
|
+
| **executing-plans** | 执行书面实施计划,含两阶段 review(规格合规性 → 代码质量) |
|
|
28
|
+
| **systematic-debugging** | 系统化 debug — 必须先找到根本原因,再提修复方案 |
|
|
29
|
+
| **using-git-worktrees** | 创建隔离 worktree 进行特性开发,验证干净的测试基线后再开始 |
|
|
30
|
+
|
|
31
|
+
### document — 文档工具
|
|
32
|
+
|
|
33
|
+
| 技能 | 说明 |
|
|
34
|
+
|------|------|
|
|
35
|
+
| **diataxis-docs** | 管理 `docs/` 目录 — 遵循 Diátaxis 方法论,写新文档、更新或删除时触发 |
|
|
36
|
+
|
|
37
|
+
### harness — 测试工具
|
|
38
|
+
|
|
39
|
+
| 技能 | 说明 |
|
|
40
|
+
|------|------|
|
|
41
|
+
| **full-stack-debug-env** | 多组件应用全栈日志监控环境搭建 — 为前端、后端、worker 等各层建立独立日志文件 |
|
|
42
|
+
|
|
43
|
+
### task — 任务管理
|
|
44
|
+
|
|
45
|
+
| 技能 | 说明 |
|
|
46
|
+
|------|------|
|
|
47
|
+
| **pm-task-dispatch** | PM 任务派发 — 需求澄清 → 分析细化 → 创建任务文档 → 派发给 Agent → 追踪反馈 |
|
|
48
|
+
| **task-close** | 任务收尾 — Agent 完成任务后执行验收、总结、文档归档和问题记录 |
|
|
49
|
+
|
|
50
|
+
### web-fetch — 网页抓取
|
|
51
|
+
|
|
52
|
+
| 技能 | 说明 |
|
|
53
|
+
|------|------|
|
|
54
|
+
| **article-fetcher** | 抓取 URL → 翻译为中文 → 存入 Obsidian;支持 X.com / Twitter(Playwright + Chrome Profile) |
|
|
55
|
+
|
|
56
|
+
### writing — 写作工具
|
|
57
|
+
|
|
58
|
+
| 技能 | 说明 |
|
|
59
|
+
|------|------|
|
|
60
|
+
| **mermaid-diagram** | Mermaid 专业作图 — 图类型选择、Roland Berger 配色、语法禁区、渲染前 12 项检查清单 |
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## 工具清单
|
|
65
|
+
|
|
66
|
+
Shell 工具,通过 `npx harveyz-skill --bundle shell-tools` 安装。
|
|
67
|
+
|
|
68
|
+
| 工具 | 说明 |
|
|
69
|
+
|------|------|
|
|
70
|
+
| **p-launch** | 交互式项目启动器 — 从多个目录中快速选择并跳转到项目 |
|
|
71
|
+
|
|
72
|
+
---
|
|
11
73
|
|
|
12
|
-
> 更多技能陆续添加中。
|
|
13
74
|
|
|
14
75
|
## 安装
|
|
15
76
|
|
|
@@ -32,25 +93,37 @@ npx harveyz-skill --bundle brainstorming,dev --target all
|
|
|
32
93
|
npx harveyz-skill list
|
|
33
94
|
```
|
|
34
95
|
|
|
35
|
-
###
|
|
96
|
+
### 本地源码安装
|
|
97
|
+
|
|
98
|
+
克隆仓库后,用 CLI 安装:
|
|
36
99
|
|
|
37
100
|
```bash
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
```
|
|
101
|
+
# 交互式选择 bundle 和目标工具
|
|
102
|
+
node bin/cli.js
|
|
41
103
|
|
|
42
|
-
|
|
104
|
+
# 安装指定 skill
|
|
105
|
+
node bin/cli.js --skill mermaid-diagram --target claude
|
|
106
|
+
node bin/cli.js --skill brainstorming,writing-plans --target claude
|
|
43
107
|
|
|
44
|
-
|
|
45
|
-
|
|
108
|
+
# 安装整个 skill bundle
|
|
109
|
+
node bin/cli.js --bundle dev --target claude
|
|
110
|
+
|
|
111
|
+
# 安装指定 shell 工具(固定安装到 ~/.local/bin)
|
|
112
|
+
node bin/cli.js --tool p-launch
|
|
113
|
+
|
|
114
|
+
# 覆盖已有安装
|
|
115
|
+
node bin/cli.js --skill mermaid-diagram --target claude --force
|
|
116
|
+
node bin/cli.js --tool p-launch --force
|
|
46
117
|
```
|
|
47
118
|
|
|
119
|
+
Skills 安装到 `~/.claude/skills/`,shell 工具安装到 `~/.local/bin/`。
|
|
120
|
+
|
|
48
121
|
## Skill 开发指南
|
|
49
122
|
|
|
50
123
|
### 命名规范
|
|
51
124
|
|
|
52
|
-
-
|
|
53
|
-
-
|
|
125
|
+
- Flat skill:直接放 `skills/<category>/<skill-name>/SKILL.md`
|
|
126
|
+
- Skill group:`skills/<group>/` 下多个子目录,每个含 `SKILL.md`
|
|
54
127
|
|
|
55
128
|
### SKILL.md 格式
|
|
56
129
|
|
|
@@ -63,7 +136,13 @@ version: "x.x.x"
|
|
|
63
136
|
---
|
|
64
137
|
```
|
|
65
138
|
|
|
66
|
-
###
|
|
139
|
+
### 发布流程
|
|
140
|
+
|
|
141
|
+
1. 在 `skills/<category>/<skill-name>/` 下创建 `SKILL.md`
|
|
142
|
+
2. 在 `skills-index.json` 的 `skills[]` 中添加条目,指定 `path` 和 `bundle`
|
|
143
|
+
3. 运行 `node scripts/generate-npmignore.js`(`prepack` 钩子会自动执行)
|
|
144
|
+
|
|
145
|
+
### 共享输出规范
|
|
67
146
|
|
|
68
147
|
**Org-mode 输出:**
|
|
69
148
|
- 加粗:`*text*`(单星号)
|
package/bin/cli.js
CHANGED
|
@@ -3,7 +3,7 @@ import { checkbox } from '@inquirer/prompts'
|
|
|
3
3
|
import chalk from 'chalk'
|
|
4
4
|
import {
|
|
5
5
|
buildAllChoices, getAllSkillItems, getAllToolItems,
|
|
6
|
-
resolveSkills, resolveTools,
|
|
6
|
+
resolveSkills, resolveSkillsByName, resolveTools, resolveToolsByName,
|
|
7
7
|
TOOL_BUNDLE_CHOICES,
|
|
8
8
|
} from '../lib/bundles.js'
|
|
9
9
|
import { TARGET_CHOICES, resolveTargets, TARGETS } from '../lib/targets.js'
|
|
@@ -13,8 +13,12 @@ const args = process.argv.slice(2)
|
|
|
13
13
|
const forceFlag = args.includes('--force')
|
|
14
14
|
const bundleIdx = args.indexOf('--bundle')
|
|
15
15
|
const targetIdx = args.indexOf('--target')
|
|
16
|
+
const toolIdx = args.indexOf('--tool')
|
|
17
|
+
const skillIdx = args.indexOf('--skill')
|
|
16
18
|
const bundleArg = bundleIdx !== -1 ? args[bundleIdx + 1] : undefined
|
|
17
19
|
const targetArg = targetIdx !== -1 ? args[targetIdx + 1] : undefined
|
|
20
|
+
const toolArg = toolIdx !== -1 ? args[toolIdx + 1] : undefined
|
|
21
|
+
const skillArg = skillIdx !== -1 ? args[skillIdx + 1] : undefined
|
|
18
22
|
|
|
19
23
|
if (args[0] === 'list') {
|
|
20
24
|
const { createRequire } = await import('module')
|
|
@@ -58,7 +62,13 @@ try {
|
|
|
58
62
|
let skillItems = []
|
|
59
63
|
let toolItems = []
|
|
60
64
|
|
|
61
|
-
if (
|
|
65
|
+
if (toolArg) {
|
|
66
|
+
const names = toolArg.split(',').map(s => s.trim()).filter(Boolean)
|
|
67
|
+
toolItems = resolveToolsByName(names).map(t => ({ kind: 'tool', ...t }))
|
|
68
|
+
} else if (skillArg) {
|
|
69
|
+
const names = skillArg.split(',').map(s => s.trim()).filter(Boolean)
|
|
70
|
+
skillItems = resolveSkillsByName(names).map(s => ({ kind: 'skill', ...s }))
|
|
71
|
+
} else if (bundleArg) {
|
|
62
72
|
const bundles = bundleArg.split(',').map(s => s.trim()).filter(Boolean)
|
|
63
73
|
const skillBundles = bundles.filter(b => !TOOL_BUNDLE_VALUES.has(b))
|
|
64
74
|
const toolBundles = bundles.filter(b => TOOL_BUNDLE_VALUES.has(b))
|
package/lib/bundles.js
CHANGED
|
@@ -26,6 +26,14 @@ export const BUNDLE_CHOICES = [
|
|
|
26
26
|
{ name: `${'all'.padEnd(16)} — 全部 skill`, value: 'all' },
|
|
27
27
|
]
|
|
28
28
|
|
|
29
|
+
export function resolveSkillsByName(names) {
|
|
30
|
+
return names.map(name => {
|
|
31
|
+
const skill = skillDefs.find(s => s.path.split('/').pop() === name)
|
|
32
|
+
if (!skill) throw new Error(`Unknown skill: "${name}"`)
|
|
33
|
+
return { skillName: name, srcPath: path.join(skillsRoot, skill.path) }
|
|
34
|
+
})
|
|
35
|
+
}
|
|
36
|
+
|
|
29
37
|
export function resolveSkills(selectedBundles) {
|
|
30
38
|
const expanded = selectedBundles.includes('all') ? namedBundles : selectedBundles
|
|
31
39
|
|
|
@@ -96,6 +104,14 @@ export const TOOL_BUNDLE_CHOICES = namedToolBundles.map(name => ({
|
|
|
96
104
|
value: name,
|
|
97
105
|
}))
|
|
98
106
|
|
|
107
|
+
export function resolveToolsByName(names) {
|
|
108
|
+
return names.map(name => {
|
|
109
|
+
const tool = toolDefs.find(t => t.name === name)
|
|
110
|
+
if (!tool) throw new Error(`Unknown tool: "${name}"`)
|
|
111
|
+
return { toolName: tool.name, srcPath: path.join(repoRoot, 'tools', tool.name) }
|
|
112
|
+
})
|
|
113
|
+
}
|
|
114
|
+
|
|
99
115
|
export function resolveTools(selectedBundles) {
|
|
100
116
|
const expanded = selectedBundles.includes('all') ? namedToolBundles : selectedBundles
|
|
101
117
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "harveyz-skill",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "One-click skill installer for Claude Code, Cursor, and Codex",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
"skills/harness/diataxis-docs/",
|
|
20
20
|
"skills/harness/full-stack-debug-env/",
|
|
21
21
|
"skills/superpowers-fork/brainstorming/",
|
|
22
|
+
"skills/harness/git-workflow-init/",
|
|
22
23
|
"skills/superpowers-fork/executing-plans/",
|
|
23
24
|
"skills/superpowers-fork/systematic-debugging/",
|
|
24
25
|
"skills/superpowers-fork/using-git-worktrees/",
|
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: git-workflow-init
|
|
3
|
+
description: 初始化或更新 git 分支管理规范:读取项目的 workflow-config.yml,审核配置,差量生成并部署 git hooks(pre-commit、commit-msg、pre-push、post-checkout),生成工作流文档,可选写入 AI 配置文件引用。支持差量更新、MANAGED 块 hash 校验(检测用户手改)、lock 文件 diff(检测配置变更)、conflict scanner(检测用户代码与新配置的交叉冲突)。触发时机:初始化新 git 仓库、新项目首次配置 git、用户要求设置/更新分支保护或分支规范、安装或重新部署 git hooks、skill 或模板更新后需要同步、或问到分支命名规范。只要项目需要配置或更新 git 工作流,就应使用此 skill。
|
|
4
|
+
user_invocable: true
|
|
5
|
+
version: "4.0.0"
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Git 工作流初始化
|
|
9
|
+
|
|
10
|
+
读取 `workflow-config.yml`,审核配置,差量部署 git hooks。
|
|
11
|
+
重新运行时自动检测配置变更、用户手改冲突、用户代码与新规则的交叉冲突,一次性汇总让用户决策后再写入。
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## 执行步骤
|
|
16
|
+
|
|
17
|
+
### Step 1 — 确认 git 仓库
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
git rev-parse --show-toplevel
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
若不在 git 仓库中,询问用户是否先执行 `git init`,用户拒绝则优雅停止。
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
### Step 2 — 读取配置
|
|
28
|
+
|
|
29
|
+
按以下顺序查找 `workflow-config.yml`:
|
|
30
|
+
|
|
31
|
+
1. 项目根目录 `workflow-config.yml`
|
|
32
|
+
2. 项目根目录 `.claude/workflow-config.yml`
|
|
33
|
+
|
|
34
|
+
若两处均不存在,询问用户:
|
|
35
|
+
- 使用默认配置(从此 skill 的 `references/workflow-config.yml` 复制到项目根目录)
|
|
36
|
+
- 还是中止并自行创建后重新运行
|
|
37
|
+
|
|
38
|
+
找到后读取并解析 YAML。
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
### Step 3 — 审核配置
|
|
43
|
+
|
|
44
|
+
对配置内容逐项检查,**发现所有问题后一次性报告,不逐条中止**。
|
|
45
|
+
|
|
46
|
+
**结构校验:**
|
|
47
|
+
- `meta.preset` 若存在,必须是 `gitflow`、`github-flow`、`trunk-based`、`custom` 之一
|
|
48
|
+
- `commit_message.format` 必须是 `conventional`、`regex`、`none` 之一
|
|
49
|
+
- 若 `format: regex`,必须同时存在 `pattern` 字段
|
|
50
|
+
|
|
51
|
+
**逻辑校验:**
|
|
52
|
+
- `branches.protected` 中任何分支的 `merge_from` 不得包含自身(循环依赖)
|
|
53
|
+
- `push_rules.block_force_push` 中的分支建议与 `branches.protected` 保持一致,不一致则警告
|
|
54
|
+
- `branch_naming.exempt` 中的分支不应同时被 `allowed_patterns` 覆盖(冗余)
|
|
55
|
+
|
|
56
|
+
**正则校验:**(对每个 pattern 执行,返回 2 = 非法)
|
|
57
|
+
```bash
|
|
58
|
+
echo "" | grep -E "<pattern>" > /dev/null 2>&1; echo $?
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
审核通过打印 `✅ 配置审核通过`,审核失败列出所有问题并停止。
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
### Step 4 — 分析当前状态(仅当 `.githooks/` 已存在时)
|
|
66
|
+
|
|
67
|
+
**首次安装时跳过此步骤,直接进入 Step 5。**
|
|
68
|
+
|
|
69
|
+
此步骤目标:在写入任何文件之前,全面了解当前状态,收集所有需要用户决策的冲突,在 Step 5 一次性呈现。
|
|
70
|
+
|
|
71
|
+
#### 4a. Lock 文件 diff — 配置发生了什么变化
|
|
72
|
+
|
|
73
|
+
读取 `.githooks/.workflow-config.lock.yml`(若不存在则视为全量新增,跳过 diff)。
|
|
74
|
+
|
|
75
|
+
将 lock 文件中记录的上一次配置与当前配置对比,生成变更摘要:
|
|
76
|
+
|
|
77
|
+
```
|
|
78
|
+
配置变更摘要:
|
|
79
|
+
+ branches.protected 新增: develop(merge_from: feature/*)
|
|
80
|
+
~ commit_message.conventional.types 修改: 新增 wip,移除 perf
|
|
81
|
+
- tags.allowed_patterns 删除: ^v[0-9]+\.[0-9]+\.[0-9]+-rc\.[0-9]+$
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
**YAML 分支名提取规则(重要):**
|
|
85
|
+
|
|
86
|
+
不要用宽泛的 `grep "name:"` 提取分支名——YAML 多个层级都可能含有 `name:` 字段,会导致误匹配。用 `python3` 精确解析,进入 `protected:` 块后再匹配 `- name:`,遇到非缩进行则停止:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
# FILE 传入要解析的文件路径(workflow-config.yml 或 lock 文件均适用)
|
|
90
|
+
python3 -c "
|
|
91
|
+
import re, sys
|
|
92
|
+
content = open(sys.argv[1]).read()
|
|
93
|
+
in_protected = False
|
|
94
|
+
for line in content.splitlines():
|
|
95
|
+
if 'protected:' in line:
|
|
96
|
+
in_protected = True; continue
|
|
97
|
+
if in_protected:
|
|
98
|
+
m = re.match(r'\s+- name:\s+(\S+)', line)
|
|
99
|
+
if m: print(m.group(1))
|
|
100
|
+
elif line.strip() and not line.startswith(' '): break
|
|
101
|
+
" "$FILE"
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
这份摘要用于后续冲突检测的输入。
|
|
105
|
+
|
|
106
|
+
#### 4b. MANAGED 块 hash 校验 — 用户是否手改了生成的代码
|
|
107
|
+
|
|
108
|
+
读取每个 hook 文件,提取所有 `BEGIN MANAGED` / `END MANAGED` 块。
|
|
109
|
+
|
|
110
|
+
MANAGED 块格式:
|
|
111
|
+
```sh
|
|
112
|
+
# --- BEGIN MANAGED: <block-id> (hash:<8位hex>) ---
|
|
113
|
+
<generated content>
|
|
114
|
+
# --- END MANAGED: <block-id> ---
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
对每个块:重新计算块内容(两行标记之间的部分,去首尾空白)的 hash:
|
|
118
|
+
```bash
|
|
119
|
+
actual_hash=$(printf '%s' "<block_content>" | git hash-object --stdin | cut -c1-8)
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
若 `actual_hash` 与标记里记录的 hash 不一致 → 用户手改了此块,记录为冲突:
|
|
123
|
+
|
|
124
|
+
```
|
|
125
|
+
[手改冲突] .githooks/pre-commit 的 MANAGED 块 branches.protected/main 被手动修改
|
|
126
|
+
原始生成内容 hash: a3f9c2b1
|
|
127
|
+
当前内容 hash: d7e42f0c
|
|
128
|
+
差异:(展示 diff)
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
#### 4c. 外部代码扫描 — 用户在 MANAGED 块外添加了什么
|
|
132
|
+
|
|
133
|
+
提取每个 hook 文件中 MANAGED 块之外的所有代码(即用户手写区)。
|
|
134
|
+
|
|
135
|
+
从用户代码中提取可解析的引用:
|
|
136
|
+
|
|
137
|
+
| 提取目标 | 扫描方式 |
|
|
138
|
+
|---------|---------|
|
|
139
|
+
| 分支名 | `"$BRANCH" = "name"`、`case "name"`、`branch = "name"` |
|
|
140
|
+
| 提交类型 | `grep -qE "...(type\|...)"`、字符串字面量 `wip`、`hotfix` |
|
|
141
|
+
| Tag/分支 pattern | `grep -qE "pattern"` |
|
|
142
|
+
| 外部脚本调用 | `./`、`bash `、`sh `、`npm run`、`make ` 开头的行 |
|
|
143
|
+
|
|
144
|
+
#### 4d. 冲突检测 — 用户代码 × 新配置的交叉分析
|
|
145
|
+
|
|
146
|
+
综合 4a(配置变更)、4b(手改块)、4c(用户代码)的结果,识别以下冲突类型:
|
|
147
|
+
|
|
148
|
+
**冲突类型 A:用户代码覆盖了与新配置相同的条件**
|
|
149
|
+
- 用户代码处理了分支 X,新配置也将 X 加入 `branches.protected`
|
|
150
|
+
- 两段代码同时执行,可能产生矛盾行为
|
|
151
|
+
|
|
152
|
+
**冲突类型 B:用户代码引用了配置中已删除的内容**
|
|
153
|
+
- 用户代码里有对类型 `wip` 的处理,新配置删除了 `wip`
|
|
154
|
+
- 用户代码逻辑失去对应的配置支撑
|
|
155
|
+
|
|
156
|
+
**冲突类型 C:MANAGED 块被手动修改**
|
|
157
|
+
- 来自 4b 的结果
|
|
158
|
+
- 重新生成会覆盖用户修改
|
|
159
|
+
|
|
160
|
+
**冲突类型 D:用户代码引用了新配置新增的内容(信息提示,非阻断)**
|
|
161
|
+
- 用户已手写了对 `develop` 的处理,新配置也打算生成同名 MANAGED 块
|
|
162
|
+
- 不一定冲突,但值得用户确认
|
|
163
|
+
|
|
164
|
+
---
|
|
165
|
+
|
|
166
|
+
### Step 5 — 冲突解决(一次性汇总,用户逐条决策)
|
|
167
|
+
|
|
168
|
+
将 Step 4 发现的所有冲突汇总后**一次性呈现**,每条冲突附带建议选项。
|
|
169
|
+
|
|
170
|
+
示例输出:
|
|
171
|
+
|
|
172
|
+
```
|
|
173
|
+
发现 3 处需要决策的冲突,请逐条确认:
|
|
174
|
+
|
|
175
|
+
─────────────────────────────────────────────────────────
|
|
176
|
+
[1/3] 手改冲突(类型 C)
|
|
177
|
+
文件: .githooks/pre-commit,块: branches.protected/main
|
|
178
|
+
用户对生成代码做了如下修改:
|
|
179
|
+
- echo "❌ 禁止直接在 main 上提交。"
|
|
180
|
+
+ echo "❌ [POLICY] 禁止直接在 main 上提交,违规请联系 @team-lead。"
|
|
181
|
+
选项:
|
|
182
|
+
A) 保留用户修改(此块不重新生成)
|
|
183
|
+
B) 用新配置覆盖(丢弃用户修改)
|
|
184
|
+
─────────────────────────────────────────────────────────
|
|
185
|
+
[2/3] 条件重叠(类型 A)
|
|
186
|
+
文件: .githooks/pre-commit,用户代码第 58 行
|
|
187
|
+
用户手写了 develop 分支的保护逻辑
|
|
188
|
+
新配置将 develop 加入 branches.protected,也会生成对应 MANAGED 块
|
|
189
|
+
选项:
|
|
190
|
+
A) 保留用户代码,跳过生成 develop 的 MANAGED 块
|
|
191
|
+
B) 用新配置生成 MANAGED 块,删除用户手写的重复代码
|
|
192
|
+
C) 两者都保留(会重复执行,请确认逻辑不矛盾)
|
|
193
|
+
─────────────────────────────────────────────────────────
|
|
194
|
+
[3/3] 引用断裂(类型 B)
|
|
195
|
+
文件: .githooks/commit-msg,用户代码第 34 行
|
|
196
|
+
用户代码引用了 commit 类型 wip,但新配置已从类型列表中移除 wip
|
|
197
|
+
选项:
|
|
198
|
+
A) 保留用户代码(wip 检查逻辑继续生效,但配置层不再管理)
|
|
199
|
+
B) 删除用户代码中对 wip 的引用
|
|
200
|
+
─────────────────────────────────────────────────────────
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
用户全部决策完成后,带着决策结果进入 Step 6。
|
|
204
|
+
若无任何冲突,直接进入 Step 6。
|
|
205
|
+
|
|
206
|
+
---
|
|
207
|
+
|
|
208
|
+
### Step 6 — 差量生成并部署 hooks
|
|
209
|
+
|
|
210
|
+
```bash
|
|
211
|
+
mkdir -p .githooks
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
#### 生成原则
|
|
215
|
+
|
|
216
|
+
根据 Step 5 的决策结果,对每个 hook 文件按以下规则处理:
|
|
217
|
+
|
|
218
|
+
1. **MANAGED 块**:根据当前配置重新生成内容,更新块内容及 hash
|
|
219
|
+
- 若 Step 5 中用户选择"保留用户修改"→ 跳过此块,保持现有内容和 hash 不变
|
|
220
|
+
- 若配置中某节 `enforce: false` 且对应 MANAGED 块存在 → 删除该块(保留块外用户代码)
|
|
221
|
+
|
|
222
|
+
2. **用户代码区(MANAGED 块外)**:永远不覆盖,原样保留
|
|
223
|
+
|
|
224
|
+
3. **差量写入**:生成全文后与磁盘文件对比——内容相同标记 `UNCHANGED`,不同标记 `UPDATED`,新建标记 `NEW`
|
|
225
|
+
|
|
226
|
+
各 hook 的触发条件、固定头部代码、MANAGED 块结构、块 ID 规范、hash 计算方式及多行内容写入技巧,见 `references/hook-templates.md`。
|
|
227
|
+
|
|
228
|
+
#### 设置权限和 hooksPath
|
|
229
|
+
|
|
230
|
+
```bash
|
|
231
|
+
chmod +x .githooks/*
|
|
232
|
+
git config core.hooksPath .githooks
|
|
233
|
+
git config merge.ff false
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
`merge.ff false` 禁止 fast-forward 合并,确保每次合并都产生 merge commit,pre-commit 钩子才能检查合并来源分支。
|
|
237
|
+
|
|
238
|
+
---
|
|
239
|
+
|
|
240
|
+
### Step 7 — 从配置渲染并写入工作流文档(差量)
|
|
241
|
+
|
|
242
|
+
每次运行都根据当前 `workflow-config.yml` 的最终状态重新渲染文档,确保文档与配置始终一致。
|
|
243
|
+
|
|
244
|
+
#### 7a. 渲染文档
|
|
245
|
+
|
|
246
|
+
```bash
|
|
247
|
+
python3 <skill-path>/references/render_docs.py \
|
|
248
|
+
workflow-config.yml \
|
|
249
|
+
<skill-path>/references/git-workflow-template.md \
|
|
250
|
+
docs/reference/git-workflow.md
|
|
251
|
+
# 输出 NEW / UPDATED / UNCHANGED
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
脚本自动处理所有占位符(`{{BRANCH_TOPOLOGY_ASCII}}`、`{{BRANCH_TABLE}}`、`{{PROTECTION_RULES}}`、`{{NAMING_TABLE}}`、`{{COMMIT_FORMAT_SECTION}}`、`{{NAMING_EXEMPT}}`、`{{FAQ_SECTION}}` 等)——无需逐一处理,渲染逻辑详见 `references/render_docs.py`。
|
|
255
|
+
|
|
256
|
+
#### 7b. 差量写入
|
|
257
|
+
|
|
258
|
+
1. 若 `docs/reference/` 不存在则创建
|
|
259
|
+
2. 将渲染后的内容与现有 `docs/reference/git-workflow.md` 对比
|
|
260
|
+
- 内容相同 → 跳过,标记 `UNCHANGED`
|
|
261
|
+
- 内容不同或文件不存在 → 写入,标记 `UPDATED` 或 `NEW`
|
|
262
|
+
3. 若 `docs/INDEX.md` 存在,追加索引行(已存在则跳过)
|
|
263
|
+
|
|
264
|
+
---
|
|
265
|
+
|
|
266
|
+
### Step 8 — 更新 AI 配置文件(可选)
|
|
267
|
+
|
|
268
|
+
若文件中已包含 `docs/reference/git-workflow.md` 链接,跳过。
|
|
269
|
+
|
|
270
|
+
否则询问用户是否在已存在的 `CLAUDE.md`、`AGENTS.md`、`GEMINI.md` 中追加:
|
|
271
|
+
|
|
272
|
+
```markdown
|
|
273
|
+
## Git 工作流
|
|
274
|
+
|
|
275
|
+
分支命名规范、保护规则与合并流程详见 [docs/reference/git-workflow.md](docs/reference/git-workflow.md)。
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
---
|
|
279
|
+
|
|
280
|
+
### Step 9 — 更新 lock 文件并汇报
|
|
281
|
+
|
|
282
|
+
#### 更新 lock 文件
|
|
283
|
+
|
|
284
|
+
将本次生效配置的关键字段写入 `.githooks/.workflow-config.lock.yml`,格式见 `references/lock-file-format.md`。
|
|
285
|
+
|
|
286
|
+
#### 汇报结果
|
|
287
|
+
|
|
288
|
+
用表格展示每个操作的状态:
|
|
289
|
+
|
|
290
|
+
```
|
|
291
|
+
文件 状态
|
|
292
|
+
─────────────────────────────────────────────────────
|
|
293
|
+
workflow-config.yml 已读取
|
|
294
|
+
.githooks/.workflow-config.lock UPDATED(记录新配置快照)
|
|
295
|
+
.githooks/pre-commit UPDATED(main 块 hash 更新;develop 块新增)
|
|
296
|
+
.githooks/commit-msg UNCHANGED
|
|
297
|
+
.githooks/pre-push UNCHANGED
|
|
298
|
+
.githooks/post-checkout NEW
|
|
299
|
+
core.hooksPath = .githooks
|
|
300
|
+
docs/reference/git-workflow.md UPDATED
|
|
301
|
+
CLAUDE.md 已有引用,跳过
|
|
302
|
+
─────────────────────────────────────────────────────
|
|
303
|
+
冲突决策摘要:
|
|
304
|
+
[1/3] branches.protected/main 手改块 → 用户选择保留修改
|
|
305
|
+
[2/3] develop 分支条件重叠 → 用户选择使用新配置
|
|
306
|
+
[3/3] wip 类型引用断裂 → 用户选择保留用户代码
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
若有保留的无法映射规则,附注提示。
|
|
310
|
+
|
|
311
|
+
---
|
|
312
|
+
|
|
313
|
+
## 参考文件
|
|
314
|
+
|
|
315
|
+
| 文件 | 说明 | 读取时机 |
|
|
316
|
+
|------|------|---------|
|
|
317
|
+
| `references/workflow-config.yml` | 配置文件模板 | Step 2:用户无配置时复制 |
|
|
318
|
+
| `references/hook-templates.md` | 4 个 hook 的代码模板、块 ID 规范、hash 计算、多行写入技巧 | Step 6:生成 hooks 前 |
|
|
319
|
+
| `references/lock-file-format.md` | lock 文件 YAML 格式 | Step 9:写入 lock 文件前 |
|
|
320
|
+
| `references/git-workflow-template.md` | 工作流文档模板(含占位符) | Step 7:由 render_docs.py 读取 |
|
|
321
|
+
| `references/render_docs.py` | 文档渲染脚本 | Step 7:直接执行 |
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
{
|
|
2
|
+
"skill_name": "git-workflow-init",
|
|
3
|
+
"evals": [
|
|
4
|
+
{
|
|
5
|
+
"id": 1,
|
|
6
|
+
"prompt": "我刚在 /tmp/gwi-test-basic 创建了一个新的 Python 项目目录,已经 git init 了。目录里有一个 workflow-config.yml,内容是默认的 gitflow 配置(branches.protected 包含 main 和 staging,commit_message.enforce: true,tags.enforce: true,push_rules.enforce: true)。请帮我完整运行 git 工作流初始化,不需要更新 AI 配置文件。",
|
|
7
|
+
"expected_output": "skill 读取 workflow-config.yml,审核通过,在 /tmp/gwi-test-basic 中生成 .githooks/pre-commit、.githooks/commit-msg、.githooks/pre-push,设置 core.hooksPath,并生成 docs/reference/git-workflow.md",
|
|
8
|
+
"files": [],
|
|
9
|
+
"expectations": [
|
|
10
|
+
"skill 读取了项目根目录的 workflow-config.yml",
|
|
11
|
+
"审核步骤执行且通过,打印审核通过信息",
|
|
12
|
+
"pre-commit hook 内容包含对 main 和 staging 的保护逻辑,且基于配置动态生成",
|
|
13
|
+
"commit-msg hook 内容包含 Conventional Commits 检查和 max_subject_length 检查",
|
|
14
|
+
"pre-push hook 内容包含 tag 命名校验(refs/tags/* 分支)和 force push 阻断(refs/heads/* 分支)",
|
|
15
|
+
"所有 hook 安装在 .githooks/ 目录,core.hooksPath 已设置为 .githooks",
|
|
16
|
+
"docs/reference/git-workflow.md 已创建且内容反映配置中的实际规则"
|
|
17
|
+
]
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"id": 2,
|
|
21
|
+
"prompt": "我的项目在 /tmp/gwi-test-custom,已 git init,根目录有 workflow-config.yml,其中 branch_naming.enforce: true,commit_message.format: regex,commit_message.pattern: '^(JIRA-\\d+|NOJIRA): .{1,80}',tags.enforce: false,push_rules.enforce: false。请运行 git 工作流初始化。",
|
|
22
|
+
"expected_output": "skill 安装 pre-commit、commit-msg、post-checkout hook,不安装 pre-push hook;commit-msg hook 使用自定义 regex 而非 Conventional Commits",
|
|
23
|
+
"files": [],
|
|
24
|
+
"expectations": [
|
|
25
|
+
"commit-msg hook 使用配置中的 pattern 字段进行校验,不使用 Conventional Commits 类型列表",
|
|
26
|
+
"post-checkout hook 已安装,包含分支命名检查逻辑",
|
|
27
|
+
"pre-push hook 未创建(tags.enforce 和 push_rules.enforce 均为 false)",
|
|
28
|
+
"core.hooksPath 已设置为 .githooks"
|
|
29
|
+
]
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"id": 3,
|
|
33
|
+
"prompt": "我的项目在 /tmp/gwi-test-claudemd,已 git init,目录里有默认 workflow-config.yml 和一个内容为 '# My Project\\n\\n这是一个 Node.js 项目。' 的 CLAUDE.md。请完整运行初始化并在 CLAUDE.md 中追加对 git 文档的索引引用。",
|
|
34
|
+
"expected_output": "hooks 已安装,docs/reference/git-workflow.md 已创建,CLAUDE.md 末尾追加了 Git Workflow 引用段落(只是索引链接,非完整内容)",
|
|
35
|
+
"files": [],
|
|
36
|
+
"expectations": [
|
|
37
|
+
"所有 hooks 已安装在 .githooks/ 目录",
|
|
38
|
+
"core.hooksPath 已设置为 .githooks",
|
|
39
|
+
"docs/reference/git-workflow.md 已创建",
|
|
40
|
+
"CLAUDE.md 中追加了对 docs/reference/git-workflow.md 的链接引用",
|
|
41
|
+
"CLAUDE.md 的引用只是索引链接,没有把完整 git 规范内容写进去"
|
|
42
|
+
]
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
"id": 4,
|
|
46
|
+
"prompt": "帮我配置 git 分支管理规范。我当前目录是 /tmp/gwi-test-nogit(目录存在但没有 git init 过)。",
|
|
47
|
+
"expected_output": "skill 检测到不在 git 仓库中,向用户说明情况并询问是否先执行 git init,而不是直接报错退出或静默跳过",
|
|
48
|
+
"files": [],
|
|
49
|
+
"expectations": [
|
|
50
|
+
"skill 执行了 git rev-parse --show-toplevel 或等效命令来检测 git 仓库",
|
|
51
|
+
"skill 检测到非 git 仓库后,没有静默跳过,也没有直接崩溃报错",
|
|
52
|
+
"skill 向用户询问是否先执行 git init(而不是自动执行)",
|
|
53
|
+
"用户拒绝后 skill 优雅停止,没有留下半完成的状态"
|
|
54
|
+
]
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
"id": 5,
|
|
58
|
+
"prompt": "我的项目在 /tmp/gwi-test-badconfig,已 git init,根目录有一个 workflow-config.yml,内容存在以下问题:1) main 的 merge_from 包含 'main' 自身;2) branch_naming.allowed_patterns 里有一个非法正则 '[unclosed';3) commit_message.format 设为 'regex' 但没有 pattern 字段。请运行初始化。",
|
|
59
|
+
"expected_output": "skill 在审核阶段发现三个问题并一次性列出,停止执行,不部署任何 hook 文件",
|
|
60
|
+
"files": [],
|
|
61
|
+
"expectations": [
|
|
62
|
+
"skill 执行了配置审核步骤",
|
|
63
|
+
"审核报告一次性列出所有三个问题:循环依赖、非法正则、缺少 pattern 字段",
|
|
64
|
+
"审核失败后 skill 停止,没有创建任何 .githooks/ 文件",
|
|
65
|
+
"skill 提示用户修复配置后重新运行"
|
|
66
|
+
]
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
"id": 6,
|
|
70
|
+
"prompt": "帮我配置 git 分支管理规范。我的项目在 /tmp/gwi-test-noconfig,已 git init,但目录里没有 workflow-config.yml。",
|
|
71
|
+
"expected_output": "skill 提示找不到配置文件,询问用户是否使用默认配置(从 references/workflow-config.yml 复制),用户同意后继续执行完整流程",
|
|
72
|
+
"files": [],
|
|
73
|
+
"expectations": [
|
|
74
|
+
"skill 检测到项目根目录和 .claude/ 目录均无 workflow-config.yml",
|
|
75
|
+
"skill 询问用户是否使用默认配置,未自动复制",
|
|
76
|
+
"用户同意后,skill 将 references/workflow-config.yml 复制到项目根目录",
|
|
77
|
+
"随后继续完整的审核和部署流程"
|
|
78
|
+
]
|
|
79
|
+
}
|
|
80
|
+
],
|
|
81
|
+
"v4_evals": [
|
|
82
|
+
{
|
|
83
|
+
"id": 7,
|
|
84
|
+
"name": "hash-check",
|
|
85
|
+
"prompt": "这个项目的 git hooks 已经安装过(有 MANAGED 块和 hash 标记),但我手动修改了 pre-commit 里 main 分支 MANAGED 块的错误提示文字,没有更新 hash。现在重新运行 git-workflow-init,处理这个变更。",
|
|
86
|
+
"expected_output": "skill 重算 MANAGED 块 hash,发现与标记不符,报告 type C 冲突(手改冲突),展示 diff,询问用户保留修改还是用新配置覆盖,按用户决策处理。",
|
|
87
|
+
"assertions": []
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
"id": 8,
|
|
91
|
+
"name": "lock-diff-add-branch",
|
|
92
|
+
"prompt": "我在 workflow-config.yml 里新增了 develop 分支保护规则(merge_from: feature/*)。上次安装时的 lock 文件里没有 develop。现在重新运行 git-workflow-init,同步变更。",
|
|
93
|
+
"expected_output": "skill 对比 lock 文件与当前配置,检测到 develop 是新增分支,在 pre-commit 插入对应 MANAGED 块,更新 lock 文件,报告 pre-commit 状态为 UPDATED。",
|
|
94
|
+
"assertions": []
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
"id": 9,
|
|
98
|
+
"name": "conflict-scanner",
|
|
99
|
+
"prompt": "我在 pre-commit 的 MANAGED 块外手写了 develop 分支的保护逻辑。现在 workflow-config.yml 也把 develop 加入了 branches.protected。重新运行 git-workflow-init。",
|
|
100
|
+
"expected_output": "skill 扫描 MANAGED 块外的用户代码,发现 develop 分支在用户代码和新配置中都有处理,报告 type A 冲突(条件重叠),提供三个选项让用户决策后再写入。",
|
|
101
|
+
"assertions": []
|
|
102
|
+
}
|
|
103
|
+
]
|
|
104
|
+
}
|