helloagents 3.0.33 → 3.0.37
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/.claude-plugin/marketplace.json +1 -4
- package/.claude-plugin/plugin.json +2 -2
- package/.codex-plugin/plugin.json +3 -4
- package/README.md +78 -74
- package/README_CN.md +78 -74
- package/bootstrap-lite.md +9 -11
- package/bootstrap.md +21 -23
- package/gemini-extension.json +1 -1
- package/install.ps1 +27 -4
- package/install.sh +27 -3
- package/package.json +2 -2
- package/scripts/capability-registry.mjs +5 -3
- package/scripts/cli-doctor-codex.mjs +153 -1
- package/scripts/cli-doctor-render.mjs +2 -1
- package/scripts/cli-doctor.mjs +3 -3
- package/scripts/cli-hosts.mjs +1 -1
- package/scripts/cli-lifecycle-hosts.mjs +124 -54
- package/scripts/cli-lifecycle.mjs +50 -15
- package/scripts/cli-messages.mjs +7 -7
- package/scripts/cli-runtime-root.mjs +9 -1
- package/scripts/delivery-gate-messages.mjs +5 -4
- package/scripts/delivery-gate.mjs +11 -22
- package/scripts/guard.mjs +1 -1
- package/scripts/notify-closeout.mjs +61 -22
- package/scripts/notify-context.mjs +5 -5
- package/scripts/notify-route.mjs +1 -1
- package/scripts/notify-sound.mjs +2 -1
- package/scripts/notify.mjs +2 -2
- package/scripts/plan-contract.mjs +10 -14
- package/scripts/project-session-cleanup.mjs +91 -31
- package/scripts/qa-review-state.mjs +313 -0
- package/scripts/ralph-loop.mjs +32 -13
- package/scripts/runtime-artifacts.mjs +2 -2
- package/scripts/runtime-scope.mjs +14 -13
- package/scripts/runtime-ttl.mjs +7 -4
- package/scripts/session-capsule.mjs +75 -13
- package/scripts/session-token.mjs +44 -9
- package/scripts/state-document.mjs +77 -0
- package/scripts/workflow-core.mjs +13 -19
- package/scripts/workflow-plan-files.mjs +1 -1
- package/scripts/workflow-recommendation.mjs +55 -67
- package/scripts/workflow-state.mjs +8 -8
- package/skills/commands/auto/SKILL.md +12 -12
- package/skills/commands/build/SKILL.md +9 -10
- package/skills/commands/commit/SKILL.md +1 -1
- package/skills/commands/help/SKILL.md +11 -13
- package/skills/commands/init/SKILL.md +18 -9
- package/skills/commands/loop/SKILL.md +70 -96
- package/skills/commands/plan/SKILL.md +7 -8
- package/skills/commands/prd/SKILL.md +3 -3
- package/skills/commands/qa/SKILL.md +49 -0
- package/skills/hello-ui/SKILL.md +3 -3
- package/skills/helloagents/SKILL.md +11 -14
- package/skills/qa-review/SKILL.md +92 -0
- package/templates/plans/contract.json +4 -7
- package/templates/plans/plan.md +1 -1
- package/templates/plans/tasks.md +1 -1
- package/templates/verify.yaml +1 -1
- package/scripts/review-state.mjs +0 -193
- package/scripts/verify-state.mjs +0 -175
- package/skills/commands/global/SKILL.md +0 -71
- package/skills/commands/verify/SKILL.md +0 -46
- package/skills/commands/wiki/SKILL.md +0 -57
- package/skills/hello-review/SKILL.md +0 -42
- package/skills/hello-verify/SKILL.md +0 -144
- /package/hooks/{hooks.json → hooks-gemini.json} +0 -0
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: qa-review
|
|
3
|
+
description: 统一质量审查、命令验证、阻断修复与交付前质量闭环。
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
`qa-review` 是新的统一质量入口。
|
|
7
|
+
它取代旧的“先 review、再 verify”双路径,统一负责:
|
|
8
|
+
|
|
9
|
+
1. 识别当前范围与风险边界
|
|
10
|
+
2. 做代码与架构层面的质量审查
|
|
11
|
+
3. 运行验证命令
|
|
12
|
+
4. 修复阻断项并回归验证
|
|
13
|
+
5. 写当前会话 `artifacts/qa-review.json`
|
|
14
|
+
6. 若当前契约仍要求 advisor / visual / closeout,再继续补齐对应证据
|
|
15
|
+
|
|
16
|
+
## 质量模式
|
|
17
|
+
|
|
18
|
+
- `standard`:默认模式。聚焦当前变更、相关配置和真实风险边界,避免无关扩查
|
|
19
|
+
- `deep`:高风险或长任务收尾模式。按 12 维做更完整的阻断性审查,并优先补齐证据链
|
|
20
|
+
|
|
21
|
+
若 `contract.json` 提供 `qaMode` 与 `qaFocus`,优先服从它。
|
|
22
|
+
|
|
23
|
+
## 审查维度
|
|
24
|
+
|
|
25
|
+
所有模式至少覆盖以下维度:
|
|
26
|
+
|
|
27
|
+
- 功能正确性:边界条件、空值、错误路径、真实数据流
|
|
28
|
+
- 安全性:鉴权、注入、敏感信息、权限绕过
|
|
29
|
+
- 可靠性:超时、资源释放、异常恢复、一致性
|
|
30
|
+
- 性能与容量:重复计算、低效查询、大循环 I/O、构建产物体积
|
|
31
|
+
- 可维护性:职责边界、重复逻辑、命名、死代码、过度抽象
|
|
32
|
+
- 交付契约:requirements / tasks / contract 是否真实满足
|
|
33
|
+
|
|
34
|
+
`deep` 模式下,再补查:
|
|
35
|
+
|
|
36
|
+
- 兼容性
|
|
37
|
+
- 可观测与运维
|
|
38
|
+
- 测试有效性
|
|
39
|
+
- 架构与依赖边界
|
|
40
|
+
- 易用性
|
|
41
|
+
- 可演进性
|
|
42
|
+
|
|
43
|
+
## 证据要求
|
|
44
|
+
|
|
45
|
+
阻断问题必须给出:
|
|
46
|
+
|
|
47
|
+
- 文件定位:`{file}:{line}`
|
|
48
|
+
- 观察到的现象
|
|
49
|
+
- 为什么构成阻断
|
|
50
|
+
- 具体修复方向
|
|
51
|
+
|
|
52
|
+
不要只给泛泛评价。
|
|
53
|
+
|
|
54
|
+
## 验证命令
|
|
55
|
+
|
|
56
|
+
验证命令来源:
|
|
57
|
+
|
|
58
|
+
- `.helloagents/verify.yaml`
|
|
59
|
+
- `package.json` 的 `lint` / `typecheck` / `test` / `build`
|
|
60
|
+
- `pyproject.toml` 的 `ruff` / `mypy` / `pytest`
|
|
61
|
+
|
|
62
|
+
命令失败时:
|
|
63
|
+
|
|
64
|
+
1. 先说明根因
|
|
65
|
+
2. 修复阻断项
|
|
66
|
+
3. 重新运行相关命令
|
|
67
|
+
4. 直到通过,或命中真实阻塞
|
|
68
|
+
|
|
69
|
+
## 结构化证据
|
|
70
|
+
|
|
71
|
+
完成本次质量闭环后,立即调用:
|
|
72
|
+
|
|
73
|
+
`scripts/qa-review-state.mjs write`
|
|
74
|
+
|
|
75
|
+
写当前会话 `artifacts/qa-review.json`,至少记录:
|
|
76
|
+
|
|
77
|
+
- `qaMode`
|
|
78
|
+
- `scope`
|
|
79
|
+
- `outcome`
|
|
80
|
+
- `conclusion`
|
|
81
|
+
- `findings`
|
|
82
|
+
- `fileReferences`
|
|
83
|
+
- `commands`
|
|
84
|
+
|
|
85
|
+
若仍有阻断问题,`outcome` 必须写为 `findings`。
|
|
86
|
+
不要让运行时从自然语言里猜结论。
|
|
87
|
+
|
|
88
|
+
## 交付要求
|
|
89
|
+
|
|
90
|
+
- 没有看到验证输出,不能声称完成
|
|
91
|
+
- 没有写 `qa-review.json`,不能把当前结果当成可信质量闭环
|
|
92
|
+
- 若当前契约要求 `advisor.json` / `visual.json` / `closeout.json`,必须继续补齐
|
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version":
|
|
2
|
+
"version": 2,
|
|
3
3
|
"source": "{~plan | ~prd}",
|
|
4
4
|
"originCommand": "{plan | prd}",
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
"{
|
|
8
|
-
],
|
|
9
|
-
"testerFocus": [
|
|
10
|
-
"{tester 需要重点验证的边界}"
|
|
5
|
+
"qaMode": "{standard | deep}",
|
|
6
|
+
"qaFocus": [
|
|
7
|
+
"{qa-review 需要重点检查或回归验证的边界}"
|
|
11
8
|
],
|
|
12
9
|
"ui": {
|
|
13
10
|
"required": false,
|
package/templates/plans/plan.md
CHANGED
package/templates/plans/tasks.md
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
- [ ] 任务3(AFK/HITL):端到端行为描述(依赖:...;涉及文件:...;预期变更:...;完成标准:...;验证方式:...)
|
|
13
13
|
|
|
14
14
|
## Codex /goal 执行入口
|
|
15
|
-
[可选。需要长程执行时复制到 Codex:/goal 按 `.helloagents/plans/{feature}/tasks.md` 执行本方案;遵守 `requirements.md`、`plan.md`、`contract.json
|
|
15
|
+
[可选。需要长程执行时复制到 Codex:/goal 按 `.helloagents/plans/{feature}/tasks.md` 执行本方案;遵守 `requirements.md`、`plan.md`、`contract.json`。默认主执行命令是 `~auto`;按顺序完成所有 AFK 任务;HITL 仅在缺少外部决策、凭据或人工验收时暂停。不要把完整 PRD 原文直接当作 `/goal` 目标。全部 AFK 任务完成后必须进入 `~qa`,写最新质量证据并完成 HelloAGENTS 收尾,再标记 goal complete。]
|
|
16
16
|
|
|
17
17
|
## 进度
|
|
18
18
|
[执行过程中更新]
|
package/templates/verify.yaml
CHANGED
package/scripts/review-state.mjs
DELETED
|
@@ -1,193 +0,0 @@
|
|
|
1
|
-
import { readFileSync } from 'node:fs'
|
|
2
|
-
import { fileURLToPath } from 'node:url'
|
|
3
|
-
import { appendReplayEvent } from './replay-state.mjs'
|
|
4
|
-
import {
|
|
5
|
-
captureWorkspaceFingerprint,
|
|
6
|
-
clearRuntimeEvidence,
|
|
7
|
-
getRuntimeEvidencePath,
|
|
8
|
-
getRuntimeEvidenceRelativePath,
|
|
9
|
-
readRuntimeEvidence,
|
|
10
|
-
validateEvidenceFingerprint,
|
|
11
|
-
validateEvidenceTimestamp,
|
|
12
|
-
writeRuntimeEvidence,
|
|
13
|
-
} from './runtime-artifacts.mjs'
|
|
14
|
-
|
|
15
|
-
export const REVIEW_EVIDENCE_FILE_NAME = 'review.json'
|
|
16
|
-
const VALID_REVIEW_OUTCOMES = new Set(['clean', 'findings'])
|
|
17
|
-
|
|
18
|
-
function normalizeStringArray(values) {
|
|
19
|
-
if (!Array.isArray(values)) return []
|
|
20
|
-
return [...new Set(values
|
|
21
|
-
.map((value) => (typeof value === 'string' ? value.trim() : ''))
|
|
22
|
-
.filter(Boolean))]
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function normalizeReviewOutcome(value) {
|
|
26
|
-
const normalized = typeof value === 'string' ? value.trim().toLowerCase() : ''
|
|
27
|
-
return VALID_REVIEW_OUTCOMES.has(normalized) ? normalized : ''
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export function getReviewEvidencePath(cwd, options = {}) {
|
|
31
|
-
return getRuntimeEvidencePath(cwd, REVIEW_EVIDENCE_FILE_NAME, options)
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export function readReviewEvidence(cwd, options = {}) {
|
|
35
|
-
return readRuntimeEvidence(cwd, REVIEW_EVIDENCE_FILE_NAME, options)
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export function clearReviewEvidence(cwd, options = {}) {
|
|
39
|
-
clearRuntimeEvidence(cwd, REVIEW_EVIDENCE_FILE_NAME, options)
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export function normalizeReviewEvidence(input = {}) {
|
|
43
|
-
return {
|
|
44
|
-
source: typeof input.source === 'string' && input.source.trim() ? input.source.trim() : 'manual',
|
|
45
|
-
originCommand: typeof input.originCommand === 'string' ? input.originCommand.trim() : '',
|
|
46
|
-
reviewMode: typeof input.reviewMode === 'string' ? input.reviewMode.trim() : '',
|
|
47
|
-
outcome: normalizeReviewOutcome(input.outcome),
|
|
48
|
-
conclusion: typeof input.conclusion === 'string' ? input.conclusion.trim() : '',
|
|
49
|
-
findings: normalizeStringArray(input.findings),
|
|
50
|
-
fileReferences: normalizeStringArray(input.fileReferences),
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export function writeReviewEvidence(cwd, {
|
|
55
|
-
source = 'stop',
|
|
56
|
-
originCommand = '',
|
|
57
|
-
reviewMode = '',
|
|
58
|
-
outcome = '',
|
|
59
|
-
conclusion = '',
|
|
60
|
-
findings = [],
|
|
61
|
-
fileReferences = [],
|
|
62
|
-
} = {}, options = {}) {
|
|
63
|
-
const normalized = normalizeReviewEvidence({
|
|
64
|
-
source,
|
|
65
|
-
originCommand,
|
|
66
|
-
reviewMode,
|
|
67
|
-
outcome,
|
|
68
|
-
conclusion,
|
|
69
|
-
findings,
|
|
70
|
-
fileReferences,
|
|
71
|
-
})
|
|
72
|
-
const payload = {
|
|
73
|
-
updatedAt: new Date().toISOString(),
|
|
74
|
-
source: normalized.source,
|
|
75
|
-
originCommand: normalized.originCommand,
|
|
76
|
-
reviewMode: normalized.reviewMode,
|
|
77
|
-
conclusion: normalized.conclusion,
|
|
78
|
-
outcome: normalized.outcome,
|
|
79
|
-
findings: normalized.findings,
|
|
80
|
-
fileReferences: normalized.fileReferences,
|
|
81
|
-
fingerprint: captureWorkspaceFingerprint(cwd),
|
|
82
|
-
}
|
|
83
|
-
writeRuntimeEvidence(cwd, REVIEW_EVIDENCE_FILE_NAME, payload, options)
|
|
84
|
-
appendReplayEvent(cwd, {
|
|
85
|
-
event: 'review_evidence_written',
|
|
86
|
-
source: normalized.source,
|
|
87
|
-
skillName: normalized.originCommand,
|
|
88
|
-
payload: options.payload || {},
|
|
89
|
-
details: {
|
|
90
|
-
reviewMode: normalized.reviewMode,
|
|
91
|
-
outcome: normalized.outcome,
|
|
92
|
-
conclusion: normalized.conclusion,
|
|
93
|
-
findings: normalized.findings,
|
|
94
|
-
fileReferences: normalized.fileReferences,
|
|
95
|
-
},
|
|
96
|
-
artifacts: [getRuntimeEvidenceRelativePath(cwd, REVIEW_EVIDENCE_FILE_NAME, options)],
|
|
97
|
-
})
|
|
98
|
-
return payload
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
function readRequiredReviewEvidence(cwd, options = {}) {
|
|
102
|
-
const evidence = readReviewEvidence(cwd, options)
|
|
103
|
-
if (evidence) return { evidence }
|
|
104
|
-
return {
|
|
105
|
-
error: {
|
|
106
|
-
required: true,
|
|
107
|
-
status: 'missing',
|
|
108
|
-
details: ['缺少 review-first 收尾所需的成功审查证据'],
|
|
109
|
-
},
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
function validateReviewTimestamp(evidence, now) {
|
|
114
|
-
return validateEvidenceTimestamp(evidence, now, '审查证据')
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
function validateReviewFingerprint(cwd, evidence) {
|
|
118
|
-
return validateEvidenceFingerprint(cwd, evidence, '成功审查证据')
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
function validateReviewOutcome(evidence) {
|
|
122
|
-
if (!normalizeReviewOutcome(evidence.outcome) || !String(evidence.conclusion || '').trim()) {
|
|
123
|
-
return {
|
|
124
|
-
required: true,
|
|
125
|
-
status: 'invalid',
|
|
126
|
-
evidence,
|
|
127
|
-
details: ['审查证据必须记录明确的 outcome 和 conclusion'],
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
if (normalizeReviewOutcome(evidence.outcome) !== 'clean') {
|
|
131
|
-
return {
|
|
132
|
-
required: true,
|
|
133
|
-
status: 'blocked',
|
|
134
|
-
evidence,
|
|
135
|
-
details: ['最新审查证据仍记录阻塞问题'],
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
return null
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
export function getReviewEvidenceStatus(cwd, { required = false, now = Date.now(), ...options } = {}) {
|
|
142
|
-
if (!required) {
|
|
143
|
-
return {
|
|
144
|
-
required: false,
|
|
145
|
-
status: 'not-applicable',
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
const requiredEvidence = readRequiredReviewEvidence(cwd, options)
|
|
150
|
-
if (requiredEvidence.error) return requiredEvidence.error
|
|
151
|
-
|
|
152
|
-
const { evidence } = requiredEvidence
|
|
153
|
-
const timestampError = validateReviewTimestamp(evidence, now)
|
|
154
|
-
if (timestampError) return timestampError
|
|
155
|
-
|
|
156
|
-
const fingerprintError = validateReviewFingerprint(cwd, evidence)
|
|
157
|
-
if (fingerprintError) return fingerprintError
|
|
158
|
-
|
|
159
|
-
const outcomeError = validateReviewOutcome(evidence)
|
|
160
|
-
if (outcomeError) return outcomeError
|
|
161
|
-
|
|
162
|
-
return {
|
|
163
|
-
required: true,
|
|
164
|
-
status: 'valid',
|
|
165
|
-
evidence,
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
function readStdinJson() {
|
|
170
|
-
try {
|
|
171
|
-
return JSON.parse(readFileSync(0, 'utf-8'))
|
|
172
|
-
} catch {
|
|
173
|
-
return {}
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
function main() {
|
|
178
|
-
const command = process.argv[2] || ''
|
|
179
|
-
if (command !== 'write') return
|
|
180
|
-
|
|
181
|
-
const input = readStdinJson()
|
|
182
|
-
const cwd = input.cwd || process.cwd()
|
|
183
|
-
const payload = writeReviewEvidence(cwd, input, { payload: input })
|
|
184
|
-
process.stdout.write(JSON.stringify({
|
|
185
|
-
suppressOutput: true,
|
|
186
|
-
path: getReviewEvidencePath(cwd, { payload: input }),
|
|
187
|
-
payload,
|
|
188
|
-
}))
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
if (process.argv[1] && fileURLToPath(import.meta.url) === process.argv[1]) {
|
|
192
|
-
main()
|
|
193
|
-
}
|
package/scripts/verify-state.mjs
DELETED
|
@@ -1,175 +0,0 @@
|
|
|
1
|
-
import { existsSync, readFileSync } from 'node:fs'
|
|
2
|
-
import { join } from 'node:path'
|
|
3
|
-
import { appendReplayEvent } from './replay-state.mjs'
|
|
4
|
-
import {
|
|
5
|
-
getProjectVerifyYamlPath,
|
|
6
|
-
} from './project-storage.mjs'
|
|
7
|
-
import {
|
|
8
|
-
captureWorkspaceFingerprint,
|
|
9
|
-
clearRuntimeEvidence,
|
|
10
|
-
getRuntimeEvidencePath,
|
|
11
|
-
getRuntimeEvidenceRelativePath,
|
|
12
|
-
readRuntimeEvidence,
|
|
13
|
-
validateEvidenceFingerprint,
|
|
14
|
-
validateEvidenceTimestamp,
|
|
15
|
-
writeRuntimeEvidence,
|
|
16
|
-
} from './runtime-artifacts.mjs'
|
|
17
|
-
|
|
18
|
-
export const VERIFY_EVIDENCE_FILE_NAME = 'verify.json'
|
|
19
|
-
const SHELL_OPERATORS = /[;&|`$(){}\n\r]/
|
|
20
|
-
|
|
21
|
-
export function getVerifyEvidencePath(cwd, options = {}) {
|
|
22
|
-
return getRuntimeEvidencePath(cwd, VERIFY_EVIDENCE_FILE_NAME, options)
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export function readVerifyEvidence(cwd, options = {}) {
|
|
26
|
-
return readRuntimeEvidence(cwd, VERIFY_EVIDENCE_FILE_NAME, options)
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export function clearVerifyEvidence(cwd, options = {}) {
|
|
30
|
-
clearRuntimeEvidence(cwd, VERIFY_EVIDENCE_FILE_NAME, options)
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
function loadVerifyYaml(cwd) {
|
|
34
|
-
const f = getProjectVerifyYamlPath(cwd)
|
|
35
|
-
if (!existsSync(f)) return null
|
|
36
|
-
try {
|
|
37
|
-
const content = readFileSync(f, 'utf-8')
|
|
38
|
-
const cmds = []
|
|
39
|
-
let inCmds = false
|
|
40
|
-
for (const line of content.split('\n')) {
|
|
41
|
-
const s = line.trim()
|
|
42
|
-
if (s.startsWith('commands:')) { inCmds = true; continue }
|
|
43
|
-
if (inCmds) {
|
|
44
|
-
if (s.startsWith('- ') && !s.startsWith('# ')) {
|
|
45
|
-
const cmd = s.slice(2).trim().replace(/^["']|["']$/g, '')
|
|
46
|
-
if (cmd && !cmd.startsWith('#')) cmds.push(cmd)
|
|
47
|
-
} else if (s && !s.startsWith('#')) {
|
|
48
|
-
break
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
return cmds.length ? cmds : null
|
|
53
|
-
} catch {
|
|
54
|
-
return null
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
function detectFromPackageJson(cwd) {
|
|
59
|
-
const f = join(cwd, 'package.json')
|
|
60
|
-
if (!existsSync(f)) return []
|
|
61
|
-
try {
|
|
62
|
-
const scripts = JSON.parse(readFileSync(f, 'utf-8')).scripts || {}
|
|
63
|
-
return ['lint', 'typecheck', 'type-check', 'test', 'build']
|
|
64
|
-
.filter((k) => k in scripts)
|
|
65
|
-
.map((k) => `npm run ${k}`)
|
|
66
|
-
} catch {
|
|
67
|
-
return []
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
function detectFromPyproject(cwd) {
|
|
72
|
-
const f = join(cwd, 'pyproject.toml')
|
|
73
|
-
if (!existsSync(f)) return []
|
|
74
|
-
try {
|
|
75
|
-
const content = readFileSync(f, 'utf-8')
|
|
76
|
-
const cmds = []
|
|
77
|
-
if (content.includes('[tool.ruff')) cmds.push('ruff check .')
|
|
78
|
-
if (content.includes('[tool.mypy')) cmds.push('mypy .')
|
|
79
|
-
if (content.includes('[tool.pytest')) cmds.push('pytest --tb=short -q')
|
|
80
|
-
return cmds
|
|
81
|
-
} catch {
|
|
82
|
-
return []
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
export function detectCommands(cwd) {
|
|
87
|
-
const yaml = loadVerifyYaml(cwd)
|
|
88
|
-
if (yaml?.length) return yaml
|
|
89
|
-
const pkg = detectFromPackageJson(cwd)
|
|
90
|
-
if (pkg.length) return pkg
|
|
91
|
-
return detectFromPyproject(cwd)
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
export function hasUnsafeVerifyCommand(commands = []) {
|
|
95
|
-
return commands.some((cmd) => SHELL_OPERATORS.test(cmd))
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
export function writeVerifyEvidence(cwd, { commands = [], fastOnly = false, source = 'ralph-loop' } = {}, options = {}) {
|
|
99
|
-
const payload = {
|
|
100
|
-
updatedAt: new Date().toISOString(),
|
|
101
|
-
commands,
|
|
102
|
-
fastOnly,
|
|
103
|
-
source,
|
|
104
|
-
fingerprint: captureWorkspaceFingerprint(cwd),
|
|
105
|
-
}
|
|
106
|
-
writeRuntimeEvidence(cwd, VERIFY_EVIDENCE_FILE_NAME, payload, options)
|
|
107
|
-
appendReplayEvent(cwd, {
|
|
108
|
-
event: 'verify_evidence_written',
|
|
109
|
-
source,
|
|
110
|
-
payload: options.payload || {},
|
|
111
|
-
details: {
|
|
112
|
-
commands,
|
|
113
|
-
fastOnly,
|
|
114
|
-
},
|
|
115
|
-
artifacts: [getRuntimeEvidenceRelativePath(cwd, VERIFY_EVIDENCE_FILE_NAME, options)],
|
|
116
|
-
})
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
function validateVerifyEvidencePresence(commands, evidence) {
|
|
120
|
-
if (evidence) return null
|
|
121
|
-
return {
|
|
122
|
-
required: true,
|
|
123
|
-
status: 'missing',
|
|
124
|
-
commands,
|
|
125
|
-
details: ['缺少当前工作流的成功验证证据'],
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
function validateVerifyEvidenceFreshness(cwd, commands, evidence, now) {
|
|
130
|
-
if (evidence.fastOnly) {
|
|
131
|
-
return {
|
|
132
|
-
required: true,
|
|
133
|
-
status: 'fast-only',
|
|
134
|
-
commands,
|
|
135
|
-
evidence,
|
|
136
|
-
details: ['最新验证证据只覆盖子代理快速检查'],
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
const timestampError = validateEvidenceTimestamp(evidence, now, '验证证据')
|
|
141
|
-
return timestampError ? { ...timestampError, commands } : null
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
function validateVerifyFingerprint(cwd, commands, evidence) {
|
|
145
|
-
const fingerprintError = validateEvidenceFingerprint(cwd, evidence, '成功验证证据')
|
|
146
|
-
return fingerprintError ? { ...fingerprintError, commands } : null
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
export function getVerifyEvidenceStatus(cwd, { now = Date.now(), ...options } = {}) {
|
|
150
|
-
const commands = detectCommands(cwd)
|
|
151
|
-
if (!commands.length) {
|
|
152
|
-
return {
|
|
153
|
-
required: false,
|
|
154
|
-
status: 'not-applicable',
|
|
155
|
-
commands,
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
const evidence = readVerifyEvidence(cwd, options)
|
|
160
|
-
const missingError = validateVerifyEvidencePresence(commands, evidence)
|
|
161
|
-
if (missingError) return missingError
|
|
162
|
-
|
|
163
|
-
const freshnessError = validateVerifyEvidenceFreshness(cwd, commands, evidence, now)
|
|
164
|
-
if (freshnessError) return freshnessError
|
|
165
|
-
|
|
166
|
-
const fingerprintError = validateVerifyFingerprint(cwd, commands, evidence)
|
|
167
|
-
if (fingerprintError) return fingerprintError
|
|
168
|
-
|
|
169
|
-
return {
|
|
170
|
-
required: true,
|
|
171
|
-
status: 'valid',
|
|
172
|
-
commands,
|
|
173
|
-
evidence,
|
|
174
|
-
}
|
|
175
|
-
}
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: ~global
|
|
3
|
-
description: 初始化项目级全局模式(~global 命令)
|
|
4
|
-
policy:
|
|
5
|
-
allow_implicit_invocation: false
|
|
6
|
-
---
|
|
7
|
-
Trigger: ~global
|
|
8
|
-
|
|
9
|
-
`~global` 是用户显式命令,用来初始化项目级全局模式。
|
|
10
|
-
|
|
11
|
-
`~global` 不受 `kb_create_mode` 限制。
|
|
12
|
-
执行 `~global` 时,`.helloagents/` 目录结构、模板格式和状态文件规则按当前已加载的 HelloAGENTS 规则执行;本命令额外负责项目级规则文件和各宿主项目级 HelloAGENTS 包根链接。
|
|
13
|
-
`.helloagents/` 在本 skill 中统一按项目级存储路径理解:项目本地 `.helloagents/` 继续承担项目本地存储目录;状态文件只使用 `state_path`;若 `project_store_mode=repo-shared`,知识库、`DESIGN.md` 与方案包按当前上下文中已注入的项目知识/方案目录写入。
|
|
14
|
-
|
|
15
|
-
## 流程
|
|
16
|
-
|
|
17
|
-
### 阶段 1:环境搭建(必做)
|
|
18
|
-
|
|
19
|
-
1. 创建 `.helloagents/` 目录 + `state_path`(按 templates/STATE.md 格式,初始“主线目标”写当前初始化任务,初始状态为空闲)
|
|
20
|
-
2. 定位插件根目录:优先读取当前上下文中已注入的“当前 HelloAGENTS 包根目录”;若上下文未提供,再根据当前已加载的 HelloAGENTS 规则来源反推,禁止猜测其他目录
|
|
21
|
-
3. 刷新各宿主项目级 HelloAGENTS 包根链接(删除旧的重建):
|
|
22
|
-
- `.claude/skills/helloagents` symlink → `{插件根目录}/`
|
|
23
|
-
- `.gemini/skills/helloagents` symlink → `{插件根目录}/`
|
|
24
|
-
- `.codex/skills/helloagents` symlink → `{插件根目录}/`
|
|
25
|
-
这些链接用于项目级规则定位 HelloAGENTS 的 `skills/`、`templates/` 和 `scripts/`;宿主若支持递归发现 `SKILL.md`,也可直接识别包内 skills。
|
|
26
|
-
4. 读取 `{插件根目录}` 中的全量规则模板,在受管内容第一行写入 `<!-- HELLOAGENTS_PROFILE: full -->`,再用 `<!-- HELLOAGENTS_START -->` / `<!-- HELLOAGENTS_END -->` 标记包裹后写入:
|
|
27
|
-
- `AGENTS.md`(项目根目录,Codex 读取)
|
|
28
|
-
- `CLAUDE.md`(项目根目录,Claude Code 读取)
|
|
29
|
-
- `.gemini/GEMINI.md`(Gemini CLI 读取,需先创建 .gemini/ 目录)
|
|
30
|
-
注意:如果文件已存在且包含标记,替换标记内的内容;如果文件已存在但无标记,追加到末尾;如果文件不存在,创建新文件
|
|
31
|
-
5. 追加 `.gitignore`(如果对应行不存在):
|
|
32
|
-
```
|
|
33
|
-
.helloagents/
|
|
34
|
-
.claude/skills/helloagents
|
|
35
|
-
.gemini/skills/helloagents
|
|
36
|
-
.codex/skills/helloagents
|
|
37
|
-
AGENTS.md
|
|
38
|
-
CLAUDE.md
|
|
39
|
-
.gemini/GEMINI.md
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
### 阶段 2:知识库创建(条件性)
|
|
43
|
-
|
|
44
|
-
检查项目是否有实际代码文件(非空项目):
|
|
45
|
-
- 有代码文件 → 执行完整知识库创建(下方流程)
|
|
46
|
-
- 空项目 → 跳过,告知用户"项目为空,知识库将在后续开发中创建"
|
|
47
|
-
|
|
48
|
-
知识库创建流程(与原 ~global 一致;逻辑写入 `.helloagents/`,`project_store_mode=repo-shared` 时实际落在共享知识目录):
|
|
49
|
-
1. 按 templates/ 目录的模板格式,分析项目代码库后生成:
|
|
50
|
-
- context.md — 按 templates/context.md 格式,填入项目概述、技术栈、架构、目录结构、模块链接
|
|
51
|
-
- guidelines.md — 按 templates/guidelines.md 格式,从现有代码推断编码约定
|
|
52
|
-
- verify.yaml — 验证命令(从 package.json/pyproject.toml 检测)
|
|
53
|
-
- CHANGELOG.md — 按 templates/CHANGELOG.md 格式,初始版本
|
|
54
|
-
- DESIGN.md — 如果项目包含 UI 代码,按 templates/DESIGN.md 格式提取项目级设计契约(产品表面、设计 token、组件与模式、状态覆盖、无障碍要求、禁止事项等)
|
|
55
|
-
2. 创建 modules/ 目录,按 templates/modules/module.md 格式为主要模块生成文档
|
|
56
|
-
3. 不覆盖已存在的文件
|
|
57
|
-
|
|
58
|
-
## verify.yaml 格式
|
|
59
|
-
```yaml
|
|
60
|
-
commands:
|
|
61
|
-
- npm run lint
|
|
62
|
-
- npm run test
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
## 幂等性
|
|
66
|
-
重复执行 ~global 是安全的:
|
|
67
|
-
- 已存在的 .helloagents/ 文件不覆盖
|
|
68
|
-
- `state_path` 只记录当前初始化任务;后续进入其他任务时必须按新任务重写
|
|
69
|
-
- 各宿主项目级 HelloAGENTS 包根链接会刷新(删除旧的重建)
|
|
70
|
-
- AGENTS.md/CLAUDE.md/GEMINI.md 中标记内容替换更新
|
|
71
|
-
- .gitignore 只追加缺失行
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: ~verify
|
|
3
|
-
description: 验证总入口 — 审查、lint、typecheck、test、build 与修复循环(~verify 命令)
|
|
4
|
-
policy:
|
|
5
|
-
allow_implicit_invocation: false
|
|
6
|
-
---
|
|
7
|
-
Trigger: ~verify [scope]
|
|
8
|
-
|
|
9
|
-
## 流程
|
|
10
|
-
|
|
11
|
-
0. 先对齐当前工作流状态:
|
|
12
|
-
- 若当前上下文中已注入“当前工作流约束”或“当前推荐下一命令”,先服从它
|
|
13
|
-
- 即使命令通过,也不能越过当前方案包边界:不完整方案包不能视为可信交付记录,未闭合方案包不能被整体报告为已完成
|
|
14
|
-
- 当推荐路径已进入 `~verify` / 收尾时,优先把本命令用于审查、验真和交付收尾
|
|
15
|
-
- 若当前存在活跃方案包,先读取 `requirements.md`、`plan.md`、`tasks.md`、`contract.json`,把它们当作当前验证契约;不要只看命令结果
|
|
16
|
-
- 若当前运行在 Codex active goal 下,按 active goal 关联方案包和 `state_path` 复核范围;`/goal` 只负责续跑,不改变验证契约
|
|
17
|
-
- 若 `contract.json` 声明 `advisor.required=true` 或 `ui.styleAdvisor.required=true`,则本次验证还必须补齐当前会话 `artifacts/advisor.json`;advisor / style advisor 都是可选能力,不是默认常驻步骤
|
|
18
|
-
- 若 `contract.json` 声明 `ui.visualValidation.required=true`,则本次验证还必须补齐当前会话 `artifacts/visual.json`;视觉验收优先用截图/浏览器工具,没有工具时才降级为结构化代码级自检
|
|
19
|
-
1. 先决定验证分流:
|
|
20
|
-
- 若当前上下文中已注入“验证分流”,先按该分流执行
|
|
21
|
-
- 用户显式使用 `~review` 时,即使当前没有注入分流,也按审查优先起步
|
|
22
|
-
- 若没有注入分流、也不是 `~review`,默认先做全量验证;执行中一旦发现高风险流程、关键权限/配置/迁移/发布边界或明显未覆盖的风险点,立即补做 `hello-review`
|
|
23
|
-
2. 审查优先模式:
|
|
24
|
-
- 获取变更范围:无参数默认未提交变更;`staged` 代表暂存区;指定文件/目录则只审查对应范围
|
|
25
|
-
- 按 hello-* 技能查找路径读取 `hello-review` SKILL.md,执行逐文件审查
|
|
26
|
-
- 高风险流程除显式范围外,还要主动补查相关配置、迁移、权限、部署或安全边界文件,不能只盯住单个功能文件
|
|
27
|
-
- 审查结论确定后,立即调用 `scripts/review-state.mjs write` 写当前会话 `artifacts/review.json`;用结构化字段记录 `outcome`、`conclusion`、`findings`、`fileReferences`,不要让后续检查脚本再从自然语言消息里猜结论
|
|
28
|
-
3. 全量验证模式或审查后继续验证:
|
|
29
|
-
- 读取 `hello-verify` SKILL.md
|
|
30
|
-
- 按其“验证命令来源”优先级检测命令
|
|
31
|
-
- 逐个运行所有检测到的命令
|
|
32
|
-
- 收集每个命令的输出和退出码
|
|
33
|
-
- 对照当前契约逐项核对:requirements 是否覆盖、tasks 中每项“完成标准”是否满足、`plan.md` 中风险与设计约束是否被验证、`contract.json` 中声明的 `verifyMode` / reviewer / tester 关注边界是否已被覆盖
|
|
34
|
-
- 若 Codex active goal 存在,还要确认 `tasks.md` 的 AFK/HITL 边界:仍有可执行 AFK 项时,不进入 complete;只在目标、任务、验证和收尾都闭合后标记 goal complete
|
|
35
|
-
- 若 `advisor.required=true` 或 `ui.styleAdvisor.required=true`,在进入收尾前调用 `scripts/advisor-state.mjs write` 写当前会话 `artifacts/advisor.json`;记录触发原因、focus、consultedSources、结论与建议,禁止只在自然语言里留一段 advisor 意见
|
|
36
|
-
- 若 `ui.visualValidation.required=true`,在进入收尾前调用 `scripts/visual-state.mjs write` 写当前会话 `artifacts/visual.json`;记录 `reason`、`tooling`、`screensChecked`、`statesChecked`、`status`、`summary`、`findings` 与 `recommendations`
|
|
37
|
-
4. 汇总报告:
|
|
38
|
-
- ✅ 通过的审查项 / 命令
|
|
39
|
-
- ❌ 失败的审查项 / 命令 + 错误详情
|
|
40
|
-
- 合同核对结论:哪些需求 / 任务完成标准已满足,哪些仍未满足
|
|
41
|
-
- 修复建议
|
|
42
|
-
- 高风险流程额外说明:不能把“命令通过”直接等同于“风险已解除”;若仍存在未验证的风险边界、待授权操作或不可逆步骤,必须明确列出并停下
|
|
43
|
-
|
|
44
|
-
## 失败处理
|
|
45
|
-
- 有失败 → 逐个修复,修复后重新运行对应审查或验证
|
|
46
|
-
- 全部通过 → 按当前已加载的 HelloAGENTS 规则进入 CONSOLIDATE 收尾;若 Codex active goal 的目标也已满足,再标记 goal complete,并按交付边界报告完成
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: ~wiki
|
|
3
|
-
description: 初始化或同步项目知识库(与 ~init 同义)
|
|
4
|
-
policy:
|
|
5
|
-
allow_implicit_invocation: false
|
|
6
|
-
---
|
|
7
|
-
Trigger: ~wiki
|
|
8
|
-
|
|
9
|
-
`~wiki` 是用户显式命令,仅创建、补全或同步项目知识库。
|
|
10
|
-
|
|
11
|
-
`~wiki` 是显式知识库命令,不受 `kb_create_mode` 限制。
|
|
12
|
-
执行 `~wiki` 时,`.helloagents/` 目录结构、模板格式和状态文件重写规则按当前已加载的 HelloAGENTS 规则执行;不写入项目级规则文件,也不创建项目级 HelloAGENTS 包根链接。
|
|
13
|
-
`.helloagents/` 在本 skill 中统一按项目级存储路径理解:状态文件只使用 `state_path`;若 `project_store_mode=repo-shared`,`context.md`、`guidelines.md`、`verify.yaml`、`CHANGELOG.md`、`DESIGN.md`、`modules/` 改按当前上下文中已注入的项目知识目录写入。
|
|
14
|
-
|
|
15
|
-
## 流程
|
|
16
|
-
|
|
17
|
-
### 阶段 1:基础准备(必做)
|
|
18
|
-
|
|
19
|
-
1. 创建 `.helloagents/` 目录 + `state_path`(按 templates/STATE.md 格式);初始“主线目标”只写当前知识库初始化 / 同步目标,不把它写成长期项目总目标
|
|
20
|
-
2. 追加 `.gitignore`(如果对应行不存在):
|
|
21
|
-
```
|
|
22
|
-
.helloagents/
|
|
23
|
-
```
|
|
24
|
-
3. 明确不执行以下操作:
|
|
25
|
-
- 不创建或更新项目级规则文件(`AGENTS.md`、`CLAUDE.md`、`.gemini/GEMINI.md`)
|
|
26
|
-
- 不创建项目级 HelloAGENTS 包根链接
|
|
27
|
-
|
|
28
|
-
### 阶段 2:知识库创建或补全(条件性)
|
|
29
|
-
|
|
30
|
-
检查项目是否有实际代码文件(非空项目):
|
|
31
|
-
- 有代码文件 → 执行完整知识库创建/补全(下方流程)
|
|
32
|
-
- 空项目 → 保留 `.helloagents/` 和 `state_path`,告知用户“项目为空,其余知识文件将在后续开发或首次编码任务中补全”
|
|
33
|
-
|
|
34
|
-
知识库创建/补全流程(统一写入 `.helloagents/` 对应的项目级存储路径;`project_store_mode=repo-shared` 时实际落在共享知识目录):
|
|
35
|
-
1. 按 templates/ 目录的模板格式,分析项目代码库后创建或补全:
|
|
36
|
-
- context.md — 按 templates/context.md 格式,填入项目概述、技术栈、架构、目录结构、模块链接
|
|
37
|
-
- guidelines.md — 按 templates/guidelines.md 格式,从现有代码推断编码约定
|
|
38
|
-
- verify.yaml — 验证命令(从 package.json/pyproject.toml 检测)
|
|
39
|
-
- CHANGELOG.md — 按 templates/CHANGELOG.md 格式创建或更新
|
|
40
|
-
- DESIGN.md — 如果项目包含 UI 代码,按 templates/DESIGN.md 格式提取或补全项目级设计契约(产品表面、设计 token、组件与模式、状态覆盖、无障碍要求、禁止事项等)
|
|
41
|
-
2. 创建或补全 modules/ 目录,按 templates/modules/module.md 格式为主要模块生成文档
|
|
42
|
-
3. 已存在的文件按模板格式增量更新,不自由改写结构;无新增信息时保持原样
|
|
43
|
-
|
|
44
|
-
## verify.yaml 格式
|
|
45
|
-
```yaml
|
|
46
|
-
commands:
|
|
47
|
-
- npm run lint
|
|
48
|
-
- npm run test
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
## 幂等性
|
|
52
|
-
重复执行 `~wiki` 是安全的:
|
|
53
|
-
- `.helloagents/` 缺失时创建,已存在时复用
|
|
54
|
-
- `state_path` 按当前任务状态重写,不追加历史;它只记录当前知识库任务,不承担项目的长期记忆
|
|
55
|
-
- 知识库文件缺失时补全,已存在时按模板增量更新
|
|
56
|
-
- `.gitignore` 只追加缺失行
|
|
57
|
-
- 永不写入项目级规则文件,也不创建任何项目级 HelloAGENTS 包根链接
|