harveyz-skill 0.2.1 → 0.4.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.
@@ -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
+ }
@@ -0,0 +1,94 @@
1
+ # Git 工作流规范
2
+
3
+ 本文档定义此项目的分支管理规则与开发协作约定。
4
+
5
+ > 本文档由 `git-workflow-init` 根据 `workflow-config.yml` 自动生成,请勿手动编辑。
6
+ > 如需修改规则,请更新 `workflow-config.yml` 后重新运行 `/git-workflow-init`。
7
+
8
+ ---
9
+
10
+ ## 分支模型
11
+
12
+ ```
13
+ {{BRANCH_TOPOLOGY_ASCII}}
14
+ ```
15
+
16
+ {{BRANCH_TABLE}}
17
+
18
+ ---
19
+
20
+ ## 分支保护规则
21
+
22
+ 以下规则由 `.githooks/pre-commit` 自动强制执行:
23
+
24
+ {{PROTECTION_RULES}}
25
+
26
+ 提交被拒绝时,请检查当前所在分支,改用正确的合并流程操作。
27
+
28
+ ---
29
+
30
+ ## 标准开发流程
31
+
32
+ ### 开始新工作
33
+
34
+ ```bash
35
+ # 始终从集成分支拉取
36
+ {{WORKFLOW_CHECKOUT_EXAMPLE}}
37
+ git pull
38
+ git checkout -b feature/my-feature
39
+ ```
40
+
41
+ ### 合并到集成分支
42
+
43
+ ```bash
44
+ {{WORKFLOW_MERGE_EXAMPLE}}
45
+ git push
46
+ ```
47
+
48
+ ### 发布到主分支
49
+
50
+ ```bash
51
+ {{WORKFLOW_RELEASE_EXAMPLE}}
52
+ ```
53
+
54
+ ---
55
+
56
+ ## 分支命名规范
57
+
58
+ {{NAMING_TABLE}}
59
+
60
+ 使用 kebab-case,名称简短且有描述性。豁免分支({{NAMING_EXEMPT}})不受命名规范约束。
61
+
62
+ ---
63
+
64
+ ## 提交信息格式
65
+
66
+ {{COMMIT_FORMAT_SECTION}}
67
+
68
+ ---
69
+
70
+ ## Hooks 安装说明
71
+
72
+ git hooks 通过 `.githooks/` 目录管理(已纳入版本控制),并设置 `core.hooksPath = .githooks`。
73
+
74
+ 新克隆仓库后需手动激活:
75
+
76
+ ```bash
77
+ git config core.hooksPath .githooks
78
+ git config merge.ff false # 禁止 fast-forward,确保 merge commit 可被钩子审查
79
+ ```
80
+
81
+ 或通过 Claude Code 重新运行安装 skill:
82
+
83
+ ```
84
+ /git-workflow-init
85
+ ```
86
+
87
+ ---
88
+
89
+ ## 常见问题
90
+
91
+ {{FAQ_SECTION}}
92
+
93
+ **Q:能绕过 hooks 吗?**
94
+ A:可以用 `git commit --no-verify`,但请记录原因并告知团队。hooks 存在有其意义,请谨慎绕过。
@@ -0,0 +1,232 @@
1
+ # Hook 代码模板
2
+
3
+ Step 6 生成 hooks 时参考此文件。
4
+
5
+ ---
6
+
7
+ ## 通用结构
8
+
9
+ 每个 hook 文件由三部分组成:
10
+
11
+ ```
12
+ 固定头部(非 MANAGED,每次重新生成时原样保留)
13
+
14
+ ├── # --- BEGIN MANAGED: <block-id> (hash:<8hex>) ---
15
+ │ <配置驱动的生成内容>
16
+ │ # --- END MANAGED: <block-id> ---
17
+
18
+ │ (可有多个 MANAGED 块)
19
+
20
+ 用户自定义区(MANAGED 块之外,永不覆盖)
21
+
22
+ 固定尾部:exit 0
23
+ ```
24
+
25
+ ### MANAGED 块 ID 规范
26
+
27
+ | hook 文件 | 块 ID |
28
+ |-----------|-------|
29
+ | pre-commit | `branches.protected/<branch-name>` |
30
+ | commit-msg | `commit-msg/format`、`commit-msg/length` |
31
+ | pre-push | `pre-push/tags`、`pre-push/force-push` |
32
+ | post-checkout | `post-checkout/branch-naming` |
33
+
34
+ ---
35
+
36
+ ## pre-commit
37
+
38
+ 触发条件:`branches.protected` 存在时生成。
39
+
40
+ **固定头部:**
41
+ ```sh
42
+ #!/bin/sh
43
+ # Generated by git-workflow-init v4.0.0
44
+ # Manual edits outside MANAGED blocks are preserved across runs.
45
+ BRANCH=$(git symbolic-ref --short HEAD 2>/dev/null)
46
+ [ -z "$BRANCH" ] && exit 0
47
+ IS_MERGE=0
48
+ [ -f "$(git rev-parse --git-dir)/MERGE_HEAD" ] && IS_MERGE=1
49
+
50
+ merge_source_branch() {
51
+ msg_file="$(git rev-parse --git-dir)/MERGE_MSG"
52
+ [ -f "$msg_file" ] || { printf ''; return; }
53
+ head -1 "$msg_file" | sed "s/Merge branch '//;s/'.*//"
54
+ }
55
+ ```
56
+
57
+ **每个保护分支生成一个 MANAGED 块**(以 main 为例,merge_from: staging, release/*):
58
+ ```sh
59
+ # --- BEGIN MANAGED: branches.protected/main (hash:<hash>) ---
60
+ if [ "$BRANCH" = "main" ]; then
61
+ if [ "$IS_MERGE" -eq 0 ]; then
62
+ echo "❌ 禁止直接在 main 上提交。请在 staging 或 release/* 分支开发后合并。"
63
+ exit 1
64
+ fi
65
+ SRC=$(merge_source_branch)
66
+ case "$SRC" in
67
+ staging|release/*) exit 0 ;;
68
+ *) echo "❌ main 只接受来自 staging 或 release/* 的合并,当前来源:'${SRC:-unknown}'"; exit 1 ;;
69
+ esac
70
+ fi
71
+ # --- END MANAGED: branches.protected/main ---
72
+ ```
73
+
74
+ `case` 模式从配置的 `merge_from` 列表动态生成,`|` 分隔。
75
+ `allow_direct_commit: true` 时将 `exit 1` 改为 `echo "⚠️ 警告"`(不阻断)。
76
+
77
+ **固定尾部:**`exit 0`
78
+
79
+ ---
80
+
81
+ ## commit-msg
82
+
83
+ 触发条件:`commit_message.enforce: true` 时生成。
84
+
85
+ **固定头部:**
86
+ ```sh
87
+ #!/bin/sh
88
+ # Generated by git-workflow-init v4.0.0
89
+ MSG=$(cat "$1")
90
+ SUBJECT=$(printf '%s\n' "$MSG" | head -1)
91
+ SUBJECT=$(printf '%s\n' "$SUBJECT" | sed '/^#/d' | sed 's/^[[:space:]]*//')
92
+ [ -z "$SUBJECT" ] && exit 0
93
+ ```
94
+
95
+ **格式检查 MANAGED 块(`commit-msg/format`):**
96
+ - `format: conventional`:将 `types` 列表拼接为正则 `^(feat|fix|...)(\(.+\))?: .+`;`require_scope: false` 时 scope 部分为可选 `(\(.+\))?`
97
+ - `format: regex`:使用配置的 `pattern` 字段直接作为 grep 表达式
98
+
99
+ **长度检查 MANAGED 块(`commit-msg/length`):**
100
+ ```sh
101
+ # --- BEGIN MANAGED: commit-msg/length (hash:<hash>) ---
102
+ LEN=$(printf '%s' "$SUBJECT" | wc -c | tr -d ' ')
103
+ if [ "$LEN" -gt <max_subject_length> ]; then
104
+ echo "❌ 提交信息首行超过 <max_subject_length> 个字符(当前 ${LEN} 个字符)"
105
+ exit 1
106
+ fi
107
+ # --- END MANAGED: commit-msg/length ---
108
+ ```
109
+
110
+ **固定尾部:**`exit 0`
111
+
112
+ ---
113
+
114
+ ## pre-push
115
+
116
+ 触发条件:`tags.enforce: true` 或 `push_rules.enforce: true` 时生成。
117
+
118
+ **固定头部:**
119
+ ```sh
120
+ #!/bin/sh
121
+ # Generated by git-workflow-init v4.0.0
122
+ while IFS=' ' read -r local_ref local_sha remote_ref remote_sha; do
123
+ case "$remote_ref" in
124
+ ```
125
+
126
+ **tag 检查 MANAGED 块(`pre-push/tags`,仅当 `tags.enforce: true`):**
127
+ ```sh
128
+ # --- BEGIN MANAGED: pre-push/tags (hash:<hash>) ---
129
+ refs/tags/*)
130
+ TAG=$(printf '%s' "$remote_ref" | sed 's|refs/tags/||')
131
+ MATCHED=0
132
+ for PATTERN in <allowed_patterns>; do
133
+ printf '%s\n' "$TAG" | grep -qE "$PATTERN" && MATCHED=1 && break
134
+ done
135
+ if [ "$MATCHED" -eq 0 ]; then
136
+ echo "❌ Tag 命名不符合规范:$TAG"
137
+ exit 1
138
+ fi
139
+ ;;
140
+ # --- END MANAGED: pre-push/tags ---
141
+ ```
142
+
143
+ **force push 检查 MANAGED 块(`pre-push/force-push`,仅当 `push_rules.enforce: true`):**
144
+ ```sh
145
+ # --- BEGIN MANAGED: pre-push/force-push (hash:<hash>) ---
146
+ refs/heads/main|refs/heads/staging)
147
+ if [ "$local_sha" = "0000000000000000000000000000000000000000" ]; then
148
+ echo "❌ 禁止 force push 到受保护分支:$remote_ref"
149
+ exit 1
150
+ fi
151
+ ;;
152
+ # --- END MANAGED: pre-push/force-push ---
153
+ ```
154
+
155
+ `refs/heads/main|refs/heads/staging` 从 `push_rules.block_force_push` 列表动态生成。
156
+
157
+ **固定尾部:**
158
+ ```sh
159
+ esac
160
+ done
161
+ exit 0
162
+ ```
163
+
164
+ ---
165
+
166
+ ## post-checkout
167
+
168
+ 触发条件:`branch_naming.enforce: true` 时生成。
169
+
170
+ **固定头部:**
171
+ ```sh
172
+ #!/bin/sh
173
+ # Generated by git-workflow-init v4.0.0
174
+ [ "$3" = "1" ] || exit 0
175
+ BRANCH=$(git symbolic-ref --short HEAD 2>/dev/null)
176
+ [ -z "$BRANCH" ] && exit 0
177
+ ```
178
+
179
+ **命名检查 MANAGED 块(`post-checkout/branch-naming`):**
180
+ ```sh
181
+ # --- BEGIN MANAGED: post-checkout/branch-naming (hash:<hash>) ---
182
+ case "$BRANCH" in
183
+ <exempt-branch-1>|<exempt-branch-2>) exit 0 ;;
184
+ esac
185
+ MATCHED=0
186
+ for PATTERN in <allowed_patterns>; do
187
+ printf '%s\n' "$BRANCH" | grep -qE "$PATTERN" && MATCHED=1 && break
188
+ done
189
+ if [ "$MATCHED" -eq 0 ]; then
190
+ echo "⚠️ 分支命名不符合规范:$BRANCH"
191
+ echo " 允许的格式:<allowed_patterns 列表>"
192
+ fi
193
+ # --- END MANAGED: post-checkout/branch-naming ---
194
+ ```
195
+
196
+ `exempt` 列表生成 case 模式(`|` 分隔);`allowed_patterns` 逐条 grep。post-checkout 仅警告不阻断(`exit 0`,不 `exit 1`)。
197
+
198
+ **固定尾部:**`exit 0`
199
+
200
+ ---
201
+
202
+ ## MANAGED 块 hash 计算
203
+
204
+ ```bash
205
+ actual_hash=$(printf '%s' "<block_content>" | git hash-object --stdin | cut -c1-8)
206
+ ```
207
+
208
+ `<block_content>` = BEGIN/END 标记之间的内容,去首尾空白。
209
+
210
+ ## 多行内容写入方式
211
+
212
+ 禁止用 `awk -v` 传多行 shell 脚本(含换行符时 awk 报错)。正确方式:
213
+
214
+ ```bash
215
+ TMPBLOCK=$(mktemp)
216
+ cat > "$TMPBLOCK" << 'BLOCKEOF'
217
+ # --- BEGIN MANAGED: branches.protected/develop (hash:PLACEHOLDER) ---
218
+ if [ "$BRANCH" = "develop" ]; then
219
+ ...
220
+ fi
221
+ # --- END MANAGED: branches.protected/develop ---
222
+ BLOCKEOF
223
+
224
+ python3 - "$HOOKFILE" "$TMPBLOCK" << 'PYEOF'
225
+ import sys
226
+ hook = open(sys.argv[1]).read()
227
+ block = open(sys.argv[2]).read()
228
+ hook = hook.replace('\nexit 0\n', '\n' + block + '\nexit 0\n', 1)
229
+ open(sys.argv[1], 'w').write(hook)
230
+ PYEOF
231
+ rm "$TMPBLOCK"
232
+ ```
@@ -0,0 +1,34 @@
1
+ # Lock 文件格式
2
+
3
+ 路径:`.githooks/.workflow-config.lock.yml`
4
+
5
+ 每次运行 git-workflow-init 成功后写入,记录本次生效的配置快照,供下次运行做 diff。
6
+
7
+ ```yaml
8
+ # Generated by git-workflow-init, do not edit manually
9
+ generated_at: "<ISO 8601 timestamp>"
10
+ skill_version: "4.0.0"
11
+ branches_protected:
12
+ - name: main
13
+ allow_direct_commit: false
14
+ merge_from: [staging, "release/*"]
15
+ - name: staging
16
+ allow_direct_commit: false
17
+ merge_from: ["feature/*", "fix/*", "chore/*", "doc/*"]
18
+ commit_message:
19
+ format: conventional
20
+ types: [feat, fix, chore, docs, refactor, test, style, perf]
21
+ max_subject_length: 80
22
+ branch_naming:
23
+ allowed_patterns: ["^feature/.+", "^fix/.+", "^chore/.+", "^doc/.+", "^release/.+"]
24
+ exempt: [main, staging]
25
+ tags:
26
+ enforce: true
27
+ allowed_patterns: ["^v[0-9]+\\.[0-9]+\\.[0-9]+$"]
28
+ require_annotated: true
29
+ push_rules:
30
+ enforce: true
31
+ block_force_push: [main, staging]
32
+ ```
33
+
34
+ 只记录影响 hook 生成的字段,不需要照搬 `workflow-config.yml` 的完整结构。