@ranger1/dx 0.1.98 → 0.1.100
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 +6 -47
- package/lib/codex-initial.js +68 -17
- package/lib/validate-env.js +21 -5
- package/package.json +1 -1
- package/skills/doctor/SKILL.md +44 -41
- package/skills/doctor/agents/openai.yaml +5 -2
- package/skills/git-pr-ship/SKILL.md +7 -2
- package/skills/git-release/SKILL.md +4 -2
- package/skills/git-release/agents/openai.yaml +3 -0
- package/skills/multi-pr-feature-delivery/SKILL.md +493 -0
- package/skills/multi-pr-feature-delivery/agents/openai.yaml +7 -0
- package/skills/doctor/scripts/doctor.sh +0 -430
package/README.md
CHANGED
|
@@ -192,53 +192,6 @@ target(端)不写死,由 `env-policy.jsonc.targets` 定义;`commands.jso
|
|
|
192
192
|
|
|
193
193
|
查看 `example/`:包含一个最小可读的 `dx/config` 配置示例,以及如何在一个 pnpm+nx monorepo 中接入 dx。
|
|
194
194
|
|
|
195
|
-
## PR Review Loop(自动评审-修复闭环)
|
|
196
|
-
|
|
197
|
-
仓库内提供了基于 Codex Skill 的 PR 评审自动化工作流:并行评审 -> 聚合结论 -> 生成修复清单 -> 自动修复 -> 再评审,最多循环 3 轮,用于让 PR 更快收敛。
|
|
198
|
-
|
|
199
|
-
### 什么时候用
|
|
200
|
-
|
|
201
|
-
- PR 变更较大、想要更系统地覆盖安全/性能/可维护性问题
|
|
202
|
-
- 希望在 CI 通过前提下,把评审建议落成可执行修复清单(fixFile)
|
|
203
|
-
- 希望避免同一个问题在不同轮次被反复提出(Decision Log)
|
|
204
|
-
|
|
205
|
-
### 如何运行
|
|
206
|
-
|
|
207
|
-
在 Codex 会话中触发该技能:
|
|
208
|
-
|
|
209
|
-
```text
|
|
210
|
-
使用 $pr-review-loop 对 PR #<PR_NUMBER> 执行审核闭环
|
|
211
|
-
```
|
|
212
|
-
|
|
213
|
-
技能入口与说明见:
|
|
214
|
-
|
|
215
|
-
- `skills/pr-review-loop/SKILL.md`
|
|
216
|
-
- `skills/pr-review-loop/references/agents/*.md`
|
|
217
|
-
|
|
218
|
-
### 工作流概览
|
|
219
|
-
|
|
220
|
-
- 预检(`pr-precheck`):先做编译/基础 gate,不通过则终止流程
|
|
221
|
-
- 获取上下文(`pr-context`):生成本轮上下文缓存 `contextFile` 与 `runId`
|
|
222
|
-
- 并行评审(reviewers):按 `./reviewer/*-reviewer.md` 并行审查并产出 reviewFile
|
|
223
|
-
- 聚合(`pr-review-aggregate` 模式 A):合并评审结果、去重、发布 Review Summary、生成 `fixFile`
|
|
224
|
-
- 修复(`fixer`):按 `fixFile` 执行修复并产出 `fixReportFile`
|
|
225
|
-
- 发布修复报告(`pr-review-aggregate` 模式 B)
|
|
226
|
-
|
|
227
|
-
### 缓存文件(项目内 `./.cache/`)
|
|
228
|
-
|
|
229
|
-
该流程中间产物写入 `./.cache/`,并在各阶段传递相对路径:
|
|
230
|
-
|
|
231
|
-
- `./.cache/pr-context-pr<PR>-r<ROUND>-<RUN_ID>.md`(contextFile)
|
|
232
|
-
- `./.cache/review-<ROLE_CODE>-pr<PR>-r<ROUND>-<RUN_ID>.md`(reviewFile)
|
|
233
|
-
- `./.cache/fix-pr<PR>-r<ROUND>-<RUN_ID>.md`(fixFile)
|
|
234
|
-
- `./.cache/fix-report-pr<PR>-r<ROUND>-<RUN_ID>.md`(fixReportFile)
|
|
235
|
-
|
|
236
|
-
### Decision Log(跨轮次决策日志)
|
|
237
|
-
|
|
238
|
-
- 文件:`./.cache/decision-log-pr<PR_NUMBER>.md`
|
|
239
|
-
- 作用:记录每轮 Fixed/Rejected 结论,后续轮次用于过滤重复问题
|
|
240
|
-
- 规则:默认 append-only,保留历史决策用于收敛
|
|
241
|
-
|
|
242
195
|
## 命令
|
|
243
196
|
|
|
244
197
|
dx 的命令由 `dx/config/commands.json` 驱动,并且内置了一些 internal runner(避免项目侧依赖任何 `scripts/lib/*.js`):
|
|
@@ -266,6 +219,12 @@ dx test e2e backend apps/backend/e2e/auth
|
|
|
266
219
|
dx test e2e quantify apps/quantify/e2e/health/health.e2e-spec.ts
|
|
267
220
|
```
|
|
268
221
|
|
|
222
|
+
关于 `dx initial`:
|
|
223
|
+
|
|
224
|
+
- `dx initial` 会把 npm 包内置的 `skills/` 同步到 `~/.codex/skills` 与 `~/.claude/skills`。
|
|
225
|
+
- 包内管理的同名 skill 目录会按当前包内容替换;旧版本中已删除的官方 skill 会被清理。
|
|
226
|
+
- 不属于包内管理的其他用户自有 skill 目录会保留。
|
|
227
|
+
|
|
269
228
|
关于 `help`:
|
|
270
229
|
|
|
271
230
|
- `dx --help`
|
package/lib/codex-initial.js
CHANGED
|
@@ -4,18 +4,14 @@ import os from 'node:os'
|
|
|
4
4
|
|
|
5
5
|
import { logger } from './logger.js'
|
|
6
6
|
|
|
7
|
-
const DEPRECATED_SKILL_DIRS = ['pr-review-loop', 'git-commit-and-pr']
|
|
7
|
+
const DEPRECATED_SKILL_DIRS = ['pr-review-loop', 'git-commit-and-pr', 'autospec']
|
|
8
|
+
const TEMP_DIR_PATTERN = /^\..+\.(tmp|backup)-\d+-\d+$/
|
|
8
9
|
|
|
9
10
|
async function collectAllFiles(dir) {
|
|
10
11
|
const out = []
|
|
11
12
|
|
|
12
13
|
async function walk(current) {
|
|
13
|
-
|
|
14
|
-
try {
|
|
15
|
-
entries = await fs.readdir(current, { withFileTypes: true })
|
|
16
|
-
} catch {
|
|
17
|
-
return
|
|
18
|
-
}
|
|
14
|
+
const entries = await fs.readdir(current, { withFileTypes: true })
|
|
19
15
|
|
|
20
16
|
for (const entry of entries) {
|
|
21
17
|
const full = join(current, entry.name)
|
|
@@ -42,6 +38,15 @@ async function ensureDir(path) {
|
|
|
42
38
|
await fs.mkdir(path, { recursive: true })
|
|
43
39
|
}
|
|
44
40
|
|
|
41
|
+
async function pathExists(path) {
|
|
42
|
+
try {
|
|
43
|
+
await fs.access(path)
|
|
44
|
+
return true
|
|
45
|
+
} catch {
|
|
46
|
+
return false
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
45
50
|
async function assertDirExists(path, label) {
|
|
46
51
|
try {
|
|
47
52
|
const st = await fs.stat(path)
|
|
@@ -55,18 +60,53 @@ async function assertDirExists(path, label) {
|
|
|
55
60
|
}
|
|
56
61
|
|
|
57
62
|
async function copyDirMerge({ srcDir, dstDir }) {
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
if (DEPRECATED_SKILL_DIRS.includes(
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
63
|
+
const entries = await fs.readdir(srcDir, { withFileTypes: true })
|
|
64
|
+
let fileCount = 0
|
|
65
|
+
|
|
66
|
+
for (const entry of entries) {
|
|
67
|
+
if (!entry.isDirectory()) continue
|
|
68
|
+
if (DEPRECATED_SKILL_DIRS.includes(entry.name)) continue
|
|
69
|
+
|
|
70
|
+
const srcSkillDir = join(srcDir, entry.name)
|
|
71
|
+
const dstSkillDir = join(dstDir, entry.name)
|
|
72
|
+
const token = `${process.pid}-${Date.now()}`
|
|
73
|
+
const tmpSkillDir = join(dstDir, `.${entry.name}.tmp-${token}`)
|
|
74
|
+
const backupSkillDir = join(dstDir, `.${entry.name}.backup-${token}`)
|
|
75
|
+
let hasBackup = false
|
|
76
|
+
|
|
77
|
+
try {
|
|
78
|
+
const files = await collectAllFiles(srcSkillDir)
|
|
79
|
+
fileCount += files.length
|
|
80
|
+
await ensureDir(tmpSkillDir)
|
|
81
|
+
for (const file of files) {
|
|
82
|
+
const rel = relative(srcSkillDir, file)
|
|
83
|
+
const target = join(tmpSkillDir, rel)
|
|
84
|
+
await ensureDir(dirname(target))
|
|
85
|
+
await fs.copyFile(file, target)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (await pathExists(dstSkillDir)) {
|
|
89
|
+
await fs.rename(dstSkillDir, backupSkillDir)
|
|
90
|
+
hasBackup = true
|
|
91
|
+
}
|
|
92
|
+
await fs.rename(tmpSkillDir, dstSkillDir)
|
|
93
|
+
if (hasBackup) {
|
|
94
|
+
await fs.rm(backupSkillDir, { recursive: true, force: true })
|
|
95
|
+
}
|
|
96
|
+
} catch (error) {
|
|
97
|
+
await fs.rm(tmpSkillDir, { recursive: true, force: true })
|
|
98
|
+
if (hasBackup && !(await pathExists(dstSkillDir))) {
|
|
99
|
+
await fs.rename(backupSkillDir, dstSkillDir)
|
|
100
|
+
hasBackup = false
|
|
101
|
+
}
|
|
102
|
+
if (hasBackup) {
|
|
103
|
+
await fs.rm(backupSkillDir, { recursive: true, force: true })
|
|
104
|
+
}
|
|
105
|
+
throw error
|
|
106
|
+
}
|
|
67
107
|
}
|
|
68
108
|
|
|
69
|
-
return { fileCount
|
|
109
|
+
return { fileCount }
|
|
70
110
|
}
|
|
71
111
|
|
|
72
112
|
async function removeDeprecatedSkillDirs(skillsDir) {
|
|
@@ -75,6 +115,15 @@ async function removeDeprecatedSkillDirs(skillsDir) {
|
|
|
75
115
|
}
|
|
76
116
|
}
|
|
77
117
|
|
|
118
|
+
async function removeStaleTempDirs(skillsDir) {
|
|
119
|
+
const entries = await fs.readdir(skillsDir, { withFileTypes: true })
|
|
120
|
+
for (const entry of entries) {
|
|
121
|
+
if (!entry.isDirectory()) continue
|
|
122
|
+
if (!TEMP_DIR_PATTERN.test(entry.name)) continue
|
|
123
|
+
await fs.rm(join(skillsDir, entry.name), { recursive: true, force: true })
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
78
127
|
export async function runCodexInitial(options = {}) {
|
|
79
128
|
const packageRoot = options.packageRoot
|
|
80
129
|
if (!packageRoot) throw new Error('runCodexInitial: 缺少 packageRoot')
|
|
@@ -91,8 +140,10 @@ export async function runCodexInitial(options = {}) {
|
|
|
91
140
|
const stats = []
|
|
92
141
|
for (const target of targets) {
|
|
93
142
|
await ensureDir(target.dir)
|
|
143
|
+
await removeStaleTempDirs(target.dir)
|
|
94
144
|
await removeDeprecatedSkillDirs(target.dir)
|
|
95
145
|
const copyStats = await copyDirMerge({ srcDir: srcSkillsDir, dstDir: target.dir })
|
|
146
|
+
await removeStaleTempDirs(target.dir)
|
|
96
147
|
await removeDeprecatedSkillDirs(target.dir)
|
|
97
148
|
stats.push({ ...target, ...copyStats })
|
|
98
149
|
}
|
package/lib/validate-env.js
CHANGED
|
@@ -245,15 +245,31 @@ function isAllowedBySimpleGlob(path, globs) {
|
|
|
245
245
|
if (glob === path) return true
|
|
246
246
|
continue
|
|
247
247
|
}
|
|
248
|
-
|
|
249
|
-
if (glob.endsWith('*')) {
|
|
250
|
-
const prefix = glob.slice(0, -1)
|
|
251
|
-
if (path.startsWith(prefix)) return true
|
|
252
|
-
}
|
|
248
|
+
if (globToRegex(glob).test(path)) return true
|
|
253
249
|
}
|
|
254
250
|
return false
|
|
255
251
|
}
|
|
256
252
|
|
|
253
|
+
function globToRegex(glob) {
|
|
254
|
+
let pattern = ''
|
|
255
|
+
for (let i = 0; i < glob.length; i++) {
|
|
256
|
+
const ch = glob[i]
|
|
257
|
+
if (ch === '*') {
|
|
258
|
+
if (glob[i + 1] === '*') {
|
|
259
|
+
pattern += '.*'
|
|
260
|
+
i += 1
|
|
261
|
+
} else {
|
|
262
|
+
pattern += '[^/]*'
|
|
263
|
+
}
|
|
264
|
+
} else if ('\\^$+?.()|[]{}'.includes(ch)) {
|
|
265
|
+
pattern += `\\${ch}`
|
|
266
|
+
} else {
|
|
267
|
+
pattern += ch
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
return new RegExp(`^${pattern}$`)
|
|
271
|
+
}
|
|
272
|
+
|
|
257
273
|
function findOverlaps(namedSets) {
|
|
258
274
|
const seen = new Map()
|
|
259
275
|
const overlaps = []
|
package/package.json
CHANGED
package/skills/doctor/SKILL.md
CHANGED
|
@@ -1,63 +1,66 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: doctor
|
|
3
|
-
description:
|
|
3
|
+
description: 仅在用户显式调用 $doctor 或明确要求使用 doctor 技能时使用;不要通过关键词自动触发。
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Doctor
|
|
7
7
|
|
|
8
8
|
## 概览
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
并且在任何本地检测/修复动作前,必须先拉取并完整执行一次远程 INSTALL 指令(不是只下载)。
|
|
10
|
+
本技能用于把当前机器调整到可稳定运行 Codex 开发工作流的状态。
|
|
12
11
|
|
|
13
|
-
|
|
12
|
+
不要把执行路径写死。模型应先识别当前系统、shell、包管理器、已有工具版本与用户权限,再自行选择最合适的检测和修复方式。完成修复后必须复检,并给出可读报告。
|
|
14
13
|
|
|
15
|
-
|
|
16
|
-
- 发现命令缺失或版本漂移,希望一次性修复。
|
|
14
|
+
## 目标状态
|
|
17
15
|
|
|
18
|
-
|
|
16
|
+
最终环境应尽量满足:
|
|
19
17
|
|
|
20
|
-
|
|
18
|
+
- `python3` 可用。
|
|
19
|
+
- `python` 可调用 Python 3,或有清晰说明当前系统无需/不应创建该别名。
|
|
20
|
+
- `node`、`npm`、`pnpm` 可用,且满足当前工作流需要。
|
|
21
|
+
- `dx` 可用,并已完成必要初始化。
|
|
22
|
+
- `agent-browser` 可用,且 Chromium/浏览器依赖已安装到可运行状态。
|
|
23
|
+
- `rg`(ripgrep)可用。
|
|
24
|
+
- 常用 PATH 配置在当前 shell 中可生效;若需要持久化,说明写入了哪个 shell 配置文件。
|
|
21
25
|
|
|
22
|
-
|
|
23
|
-
INSTALL_URL="https://raw.githubusercontent.com/obra/superpowers/refs/heads/main/.codex/INSTALL.md"
|
|
24
|
-
INSTALL_MD="$(mktemp -t codex-install.XXXXXX.md)"
|
|
26
|
+
## 执行原则
|
|
25
27
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
+
- 先诊断,再修复;不要未经确认就重复安装已经健康的工具。
|
|
29
|
+
- 优先使用系统已有的包管理器和用户态安装路径。
|
|
30
|
+
- 遇到多个可行方案时,选择对系统影响最小、最容易回滚的方案。
|
|
31
|
+
- 对需要管理员权限、网络下载或会修改 shell 配置的动作,执行前简短说明影响。
|
|
32
|
+
- 不要求固定轮次;根据实际结果迭代,直到通过验收或明确无法继续。
|
|
33
|
+
- 不要强制执行远程安装文档。只有当诊断显示确实需要外部安装指引时,才读取可信来源并按实际情况采用。
|
|
28
34
|
|
|
29
|
-
|
|
30
|
-
cat "${INSTALL_MD}"
|
|
31
|
-
```
|
|
35
|
+
## 建议工作流
|
|
32
36
|
|
|
33
|
-
|
|
34
|
-
-
|
|
35
|
-
-
|
|
36
|
-
-
|
|
37
|
+
1. 收集上下文:
|
|
38
|
+
- 操作系统与架构
|
|
39
|
+
- 当前 shell 与 PATH
|
|
40
|
+
- `python3`、`python`、`node`、`npm`、`pnpm`、`dx`、`agent-browser`、`rg` 的存在性与版本
|
|
41
|
+
- `CODEX_HOME` 与相关配置目录是否存在
|
|
42
|
+
2. 对照目标状态判断缺口。
|
|
43
|
+
3. 制定最小修复动作并执行。
|
|
44
|
+
4. 每次修复后重新验证相关项。
|
|
45
|
+
5. 所有项目完成后运行一次最终复检。
|
|
46
|
+
6. 输出报告。
|
|
37
47
|
|
|
38
|
-
|
|
48
|
+
## 验证要求
|
|
39
49
|
|
|
40
|
-
|
|
41
|
-
CODEX_HOME="${CODEX_HOME:-$HOME/.codex}"
|
|
42
|
-
bash "$CODEX_HOME/skills/doctor/scripts/doctor.sh"
|
|
43
|
-
```
|
|
50
|
+
最终复检至少覆盖:
|
|
44
51
|
|
|
45
|
-
|
|
52
|
+
- 每个目标命令是否可被当前 shell 找到。
|
|
53
|
+
- 每个目标命令的版本或基本健康输出。
|
|
54
|
+
- `dx` 的初始化结果或当前初始化状态。
|
|
55
|
+
- `agent-browser` 是否能找到并使用已安装的浏览器依赖。
|
|
56
|
+
- 对未通过项给出失败原因、已尝试动作和下一步建议。
|
|
46
57
|
|
|
47
|
-
|
|
48
|
-
CODEX_HOME="${CODEX_HOME:-$HOME/.codex}"
|
|
49
|
-
bash "$CODEX_HOME/skills/doctor/scripts/doctor.sh" --max-rounds 3
|
|
50
|
-
```
|
|
58
|
+
## 报告格式
|
|
51
59
|
|
|
52
|
-
|
|
60
|
+
最终报告使用中文,至少包含:
|
|
53
61
|
|
|
54
|
-
-
|
|
55
|
-
-
|
|
56
|
-
-
|
|
57
|
-
-
|
|
58
|
-
-
|
|
59
|
-
|
|
60
|
-
## 注意
|
|
61
|
-
|
|
62
|
-
- 某些安装步骤可能需要管理员权限(例如 `sudo` 或 Homebrew 写权限)。
|
|
63
|
-
- 若系统缺少包管理器,脚本会给出明确失败原因。
|
|
62
|
+
- 环境摘要:系统、shell、关键 PATH 变更。
|
|
63
|
+
- 检查结果表:检查项、状态、版本/证据、说明。
|
|
64
|
+
- 已执行修复:实际执行过的安装、链接、初始化或配置变更。
|
|
65
|
+
- 未完成项:若存在,说明阻塞原因和用户需要做什么。
|
|
66
|
+
- 结论:通过 / 部分通过 / 未通过。
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
interface:
|
|
2
2
|
display_name: "Doctor"
|
|
3
|
-
short_description: "
|
|
4
|
-
default_prompt: "使用 $doctor
|
|
3
|
+
short_description: "按目标状态自主诊断、修复并验证 Codex 开发环境"
|
|
4
|
+
default_prompt: "使用 $doctor 对当前系统进行 Codex 开发环境体检;根据实际缺口自主选择修复方式,完成后复检并输出报告。"
|
|
5
|
+
|
|
6
|
+
policy:
|
|
7
|
+
allow_implicit_invocation: false
|
|
@@ -15,6 +15,7 @@ description: PR 交付流程(仅限显式调用)
|
|
|
15
15
|
- 禁止在 `main/master` 直接提交。
|
|
16
16
|
- 每修复一个问题立即 commit 一次,禁止攒到最后一次性提交。
|
|
17
17
|
- AI 自主判断是否拒绝修复某个问题,拒绝必须写明理由。
|
|
18
|
+
- 扫描范围内顺便发现的历史遗留问题(非本次 PR 引入),视同本次问题一并修复,不以"历史遗留"或"超出本 PR 范围"为由跳过。但不主动扩大扫描范围去寻找无关问题。
|
|
18
19
|
- 上次跑完测试/Lint 后如果改过代码,必须重跑验证。
|
|
19
20
|
- 使用 heredoc 写 commit message 和 gh 命令的 body(禁止 `\n`)。
|
|
20
21
|
- 零参数设计:所有信息从仓库状态、当前分支、gh CLI 自动获取,不接受手动参数。
|
|
@@ -281,10 +282,12 @@ Step 3: 运行关联测试(根据以下改动范围判断需要跑哪些)
|
|
|
281
282
|
|
|
282
283
|
审查者 A — 代码质量与架构(派独立 subagent):
|
|
283
284
|
- 关注:架构合理性、SOLID 原则、错误处理、性能、安全
|
|
285
|
+
- 审查 PR diff 涉及的文件时,如果顺便发现同一文件中的历史遗留问题,也一并报告(不主动扩大到 diff 之外的文件)
|
|
284
286
|
- 输入:PR diff
|
|
285
287
|
|
|
286
288
|
审查者 B — 逻辑缺陷与规范(派独立 subagent):
|
|
287
289
|
- 关注:逻辑缺陷、边界条件、命名规范、类型安全、测试覆盖
|
|
290
|
+
- 审查 PR diff 涉及的文件时,如果顺便发现同一文件中的历史遗留问题,也一并报告(不主动扩大到 diff 之外的文件)
|
|
288
291
|
- 输入:PR diff
|
|
289
292
|
|
|
290
293
|
> **禁止使用 `code-review` 技能或 `oh-my-claudecode:code-reviewer` agent 来执行审查。** 这些工具内置了自动发 PR 评论的行为,会导致 PR 上出现多条重复审核报告。必须派独立 subagent,并在 prompt 中明确要求"只返回审查结果文本,禁止调用 gh pr comment 或以任何方式发布 PR 评论"。
|
|
@@ -292,12 +295,14 @@ Step 3: 运行关联测试(根据以下改动范围判断需要跑哪些)
|
|
|
292
295
|
Subagent A prompt:
|
|
293
296
|
```
|
|
294
297
|
作为资深架构师审查此 PR diff,关注架构、性能、安全问题。
|
|
298
|
+
审查 diff 涉及的文件时,如果顺便发现同一文件中已有的历史遗留问题(非本次 diff 引入),也一并报告——不要因为是历史代码就忽略。但不要主动扩大到 diff 未涉及的文件。
|
|
295
299
|
【重要】只返回审查结果文本给调用者。禁止调用 gh pr comment 或以任何方式直接往 PR 发评论——评论由主 agent 统一发布。
|
|
296
300
|
```
|
|
297
301
|
|
|
298
302
|
Subagent B prompt:
|
|
299
303
|
```
|
|
300
304
|
作为质量工程师审查此 PR diff,关注逻辑缺陷、边界条件、规范遵从。
|
|
305
|
+
审查 diff 涉及的文件时,如果顺便发现同一文件中已有的历史遗留问题(非本次 diff 引入),也一并报告——不要因为是历史代码就忽略。但不要主动扩大到 diff 未涉及的文件。
|
|
301
306
|
【重要】只返回审查结果文本给调用者。禁止调用 gh pr comment 或以任何方式直接往 PR 发评论——评论由主 agent 统一发布。
|
|
302
307
|
```
|
|
303
308
|
|
|
@@ -379,8 +384,8 @@ MSG
|
|
|
379
384
|
对每个问题:
|
|
380
385
|
|
|
381
386
|
1. **判断是否修复**:
|
|
382
|
-
-
|
|
383
|
-
-
|
|
387
|
+
- 修复:执行修改(包括扫描过程中顺便发现的历史遗留问题,不以"非本次引入"为由跳过)
|
|
388
|
+
- 拒绝:记录理由(如:误报、设计意图如此)。"历史遗留"或"超出本 PR 范围"不是合法的拒绝理由
|
|
384
389
|
|
|
385
390
|
2. **修复后立即 commit**(一个问题一个 commit):
|
|
386
391
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: git-release
|
|
3
|
-
description:
|
|
3
|
+
description: 仅在用户显式调用 $git-release 或明确要求使用 git-release 技能时使用;不要通过关键词自动触发。
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Git Release
|
|
@@ -15,6 +15,7 @@ description: 在 Git 仓库中执行标准化版本发布流程并自动生成
|
|
|
15
15
|
- 严格执行前置校验,任何硬性条件不满足时立即终止。
|
|
16
16
|
- 发行说明必须结构化、可读、可追溯。
|
|
17
17
|
- 命令默认在仓库根目录执行。
|
|
18
|
+
- 若能从当前 release 分支或自动建分支流程唯一推断出合法版本号,直接使用该版本继续发布,不要询问用户确认。
|
|
18
19
|
|
|
19
20
|
## 流程
|
|
20
21
|
|
|
@@ -33,7 +34,8 @@ description: 在 Git 仓库中执行标准化版本发布流程并自动生成
|
|
|
33
34
|
- `release/v1.2.3` -> `v1.2.3` -> `1.2.3`
|
|
34
35
|
- `release/v1.2.3-beta.2` -> `v1.2.3-beta.2` -> `1.2.3-beta.2`
|
|
35
36
|
7. 检查目标 tag 是否已存在:`git tag -l "v<VERSION>"`。
|
|
36
|
-
8.
|
|
37
|
+
8. 输出推断出的版本号和推断来源,直接使用该版本号继续执行;不要向用户请求确认。
|
|
38
|
+
9. 仅当无法从分支名或自动建分支流程唯一推断出合法版本号时,终止并要求用户显式指定目标版本。
|
|
37
39
|
|
|
38
40
|
### 二、更新版本号
|
|
39
41
|
|