helloagents 3.0.29 → 3.0.31
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/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/README.md +34 -34
- package/README_CN.md +36 -34
- package/bootstrap-lite.md +20 -20
- package/bootstrap.md +23 -21
- package/gemini-extension.json +1 -1
- package/install.ps1 +2 -2
- package/install.sh +2 -2
- package/package.json +1 -1
- package/scripts/cli-branch.mjs +7 -3
- package/scripts/cli-codex.mjs +6 -5
- package/scripts/cli-config.mjs +8 -0
- package/scripts/cli-doctor-codex.mjs +10 -5
- package/scripts/cli-doctor-render.mjs +16 -0
- package/scripts/cli-doctor.mjs +2 -3
- package/scripts/cli-lifecycle-hosts.mjs +6 -1
- package/scripts/cli-lifecycle.mjs +16 -2
- package/scripts/cli-messages.mjs +8 -7
- package/scripts/cli-runtime-carrier.mjs +3 -3
- package/scripts/cli-utils.mjs +9 -0
- package/scripts/guard.mjs +1 -1
- package/scripts/notify-context.mjs +1 -1
- package/scripts/notify-route.mjs +3 -4
- package/scripts/notify.mjs +6 -1
- package/scripts/project-storage.mjs +4 -4
- package/scripts/replay-state.mjs +22 -4
- package/scripts/runtime-context.mjs +14 -2
- package/scripts/runtime-scope.mjs +144 -2
- package/scripts/session-capsule.mjs +14 -0
- package/scripts/turn-state.mjs +7 -0
- package/scripts/turn-stop-gate.mjs +5 -5
- package/skills/commands/auto/SKILL.md +2 -2
- package/skills/commands/build/SKILL.md +4 -4
- package/skills/commands/commit/SKILL.md +2 -2
- package/skills/commands/global/SKILL.md +71 -0
- package/skills/commands/help/SKILL.md +8 -7
- package/skills/commands/init/SKILL.md +14 -31
- package/skills/commands/loop/SKILL.md +1 -1
- package/skills/commands/plan/SKILL.md +1 -1
- package/skills/commands/prd/SKILL.md +1 -1
- package/skills/commands/test/SKILL.md +1 -1
- package/skills/commands/verify/SKILL.md +5 -5
- package/skills/commands/wiki/SKILL.md +1 -1
- package/skills/hello-review/SKILL.md +1 -1
- package/skills/hello-subagent/SKILL.md +1 -1
- package/skills/hello-ui/SKILL.md +6 -6
- package/skills/hello-verify/SKILL.md +7 -7
- package/skills/helloagents/SKILL.md +9 -8
package/scripts/replay-state.mjs
CHANGED
|
@@ -2,10 +2,11 @@ import { dirname } from 'node:path'
|
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
4
|
appendSessionEvent,
|
|
5
|
+
getRuntimeScope,
|
|
5
6
|
getSessionEventsPath,
|
|
6
7
|
resetSessionEvents,
|
|
7
8
|
} from './session-capsule.mjs'
|
|
8
|
-
import { getProjectSessionScope } from './runtime-scope.mjs'
|
|
9
|
+
import { ensureProjectLocalRuntime, getProjectSessionScope } from './runtime-scope.mjs'
|
|
9
10
|
|
|
10
11
|
function sanitizeReplayValue(value) {
|
|
11
12
|
if (typeof value === 'string') {
|
|
@@ -60,10 +61,27 @@ export function startReplaySession(cwd, {
|
|
|
60
61
|
bootstrapFile = '',
|
|
61
62
|
installMode = '',
|
|
62
63
|
payload = {},
|
|
64
|
+
ensureProjectLocal = false,
|
|
63
65
|
env,
|
|
64
66
|
ppid,
|
|
65
67
|
} = {}) {
|
|
66
|
-
const scope =
|
|
68
|
+
const scope = ensureProjectLocal
|
|
69
|
+
? {
|
|
70
|
+
...ensureProjectLocalRuntime(cwd, {
|
|
71
|
+
payload,
|
|
72
|
+
env,
|
|
73
|
+
ppid,
|
|
74
|
+
stateSeed: {
|
|
75
|
+
goal: '进入当前项目级执行流程',
|
|
76
|
+
doing: '正在初始化当前会话运行态',
|
|
77
|
+
context: '由运行时自动创建;后续按实际任务重写',
|
|
78
|
+
next: '根据当前用户请求继续执行当前流程',
|
|
79
|
+
},
|
|
80
|
+
}),
|
|
81
|
+
active: true,
|
|
82
|
+
scope: 'project-session',
|
|
83
|
+
}
|
|
84
|
+
: getProjectSessionScope(cwd, { payload, env, ppid })
|
|
67
85
|
if (!scope.active) return ''
|
|
68
86
|
|
|
69
87
|
const filePath = resetSessionEvents(cwd, { payload, env, ppid })
|
|
@@ -95,8 +113,8 @@ export function appendReplayEvent(cwd, {
|
|
|
95
113
|
env,
|
|
96
114
|
ppid,
|
|
97
115
|
} = {}) {
|
|
98
|
-
const scope =
|
|
99
|
-
if (!scope.active || !event) return ''
|
|
116
|
+
const scope = getRuntimeScope(cwd, { payload, env, ppid })
|
|
117
|
+
if (scope.scope !== 'project-session' || !scope.active || !event) return ''
|
|
100
118
|
|
|
101
119
|
return appendSessionEvent(cwd, sanitizeReplayValue({
|
|
102
120
|
event,
|
|
@@ -78,7 +78,8 @@ export function clearRouteContext(options = {}) {
|
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
export function writeRouteContext({ cwd, skillName, sourceSkillName = skillName, payload = {}, env, ppid }) {
|
|
81
|
-
const
|
|
81
|
+
const shouldEnsureProjectLocal = skillName !== 'idea' && skillName !== 'help'
|
|
82
|
+
const scope = getRuntimeScope(cwd, { payload, env, ppid, ensureProjectLocal: shouldEnsureProjectLocal })
|
|
82
83
|
const context = {
|
|
83
84
|
cwd: normalizePath(cwd),
|
|
84
85
|
skillName,
|
|
@@ -91,7 +92,18 @@ export function writeRouteContext({ cwd, skillName, sourceSkillName = skillName,
|
|
|
91
92
|
key: scope.key,
|
|
92
93
|
updatedAt: Date.now(),
|
|
93
94
|
}
|
|
94
|
-
writeCapsuleSection(cwd, 'route', context, {
|
|
95
|
+
writeCapsuleSection(cwd, 'route', context, {
|
|
96
|
+
payload,
|
|
97
|
+
env,
|
|
98
|
+
ppid,
|
|
99
|
+
ensureProjectLocal: shouldEnsureProjectLocal,
|
|
100
|
+
stateSeed: {
|
|
101
|
+
goal: `执行 ~${sourceSkillName}`,
|
|
102
|
+
doing: `已进入 ~${sourceSkillName} 路由`,
|
|
103
|
+
context: '由运行时首次进入非只读命令时创建;后续按实际任务重写',
|
|
104
|
+
next: `读取并执行 ~${skillName} 对应流程`,
|
|
105
|
+
},
|
|
106
|
+
})
|
|
95
107
|
}
|
|
96
108
|
|
|
97
109
|
export function readRouteContext(options = {}) {
|
|
@@ -7,6 +7,7 @@ import { homedir } from 'node:os'
|
|
|
7
7
|
import { resolveSessionToken } from './session-token.mjs'
|
|
8
8
|
import { USER_RUNTIME_MAX_AGE_MS } from './runtime-ttl.mjs'
|
|
9
9
|
import { cleanupUserRuntimeRoot, getUserRuntimeRoot } from './runtime-user-cleanup.mjs'
|
|
10
|
+
import { FULL_CARRIER_PROFILE_MARKER } from './cli-utils.mjs'
|
|
10
11
|
|
|
11
12
|
export const PROJECT_DIR_NAME = '.helloagents'
|
|
12
13
|
export const PROJECT_SESSIONS_DIR_NAME = 'sessions'
|
|
@@ -143,6 +144,138 @@ export function getProjectRoot(cwd) {
|
|
|
143
144
|
return activeDir ? dirname(activeDir) : normalizePath(cwd || process.cwd())
|
|
144
145
|
}
|
|
145
146
|
|
|
147
|
+
function getCarrierPathForRoot(root, host = '') {
|
|
148
|
+
if (!root) return ''
|
|
149
|
+
if (host === 'codex') return join(root, 'AGENTS.md')
|
|
150
|
+
if (host === 'gemini') return join(root, '.gemini', 'GEMINI.md')
|
|
151
|
+
return join(root, 'CLAUDE.md')
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function getCarrierCandidatePaths(root, host = '', { anyHost = false } = {}) {
|
|
155
|
+
if (!root) return []
|
|
156
|
+
if (!anyHost) return [getCarrierPathForRoot(root, host)]
|
|
157
|
+
return [
|
|
158
|
+
join(root, 'AGENTS.md'),
|
|
159
|
+
join(root, 'CLAUDE.md'),
|
|
160
|
+
join(root, '.gemini', 'GEMINI.md'),
|
|
161
|
+
]
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function hasFullCarrierMarker(filePath = '') {
|
|
165
|
+
if (!filePath || !existsSync(filePath)) return false
|
|
166
|
+
try {
|
|
167
|
+
return readFileSync(filePath, 'utf-8').includes(FULL_CARRIER_PROFILE_MARKER)
|
|
168
|
+
} catch {
|
|
169
|
+
return false
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
function findProjectCarrierRoot(cwd, host = '', options = {}) {
|
|
174
|
+
const normalizedCwd = normalizePath(cwd || process.cwd())
|
|
175
|
+
const gitRoot = resolveGitTopLevel(normalizedCwd)
|
|
176
|
+
const requireFullProfile = options.requireFullProfile === true
|
|
177
|
+
const anyHost = options.anyHost === true
|
|
178
|
+
let current = normalizedCwd
|
|
179
|
+
|
|
180
|
+
while (current) {
|
|
181
|
+
const candidates = getCarrierCandidatePaths(current, host, { anyHost })
|
|
182
|
+
const matched = candidates.some((filePath) =>
|
|
183
|
+
requireFullProfile ? hasFullCarrierMarker(filePath) : existsSync(filePath))
|
|
184
|
+
if (matched) return current
|
|
185
|
+
if (isUserHomeDir(current)) break
|
|
186
|
+
if (gitRoot && samePath(current, gitRoot)) break
|
|
187
|
+
|
|
188
|
+
const parent = dirname(current)
|
|
189
|
+
if (!parent || parent === current) break
|
|
190
|
+
current = parent
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
return ''
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
export function getProjectLocalRoot(cwd) {
|
|
197
|
+
const normalizedCwd = normalizePath(cwd || process.cwd())
|
|
198
|
+
const activeDir = findProjectActivationDir(normalizedCwd)
|
|
199
|
+
if (activeDir) return dirname(activeDir)
|
|
200
|
+
|
|
201
|
+
const fullCarrierRoot = findProjectCarrierRoot(normalizedCwd, '', {
|
|
202
|
+
anyHost: true,
|
|
203
|
+
requireFullProfile: true,
|
|
204
|
+
})
|
|
205
|
+
return fullCarrierRoot || resolveGitTopLevel(normalizedCwd) || normalizedCwd
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
export function getProjectLocalDir(cwd) {
|
|
209
|
+
return join(getProjectLocalRoot(cwd), PROJECT_DIR_NAME)
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
export function getProjectCarrierRoot(cwd) {
|
|
213
|
+
const normalizedCwd = normalizePath(cwd || process.cwd())
|
|
214
|
+
return findProjectCarrierRoot(normalizedCwd, '', { anyHost: true })
|
|
215
|
+
|| resolveGitTopLevel(normalizedCwd)
|
|
216
|
+
|| getProjectRoot(normalizedCwd)
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
export function getProjectCarrierPath(cwd, host = '') {
|
|
220
|
+
const normalizedCwd = normalizePath(cwd || process.cwd())
|
|
221
|
+
const carrierRoot = findProjectCarrierRoot(normalizedCwd, host, {
|
|
222
|
+
requireFullProfile: true,
|
|
223
|
+
}) || findProjectCarrierRoot(normalizedCwd, host)
|
|
224
|
+
|| getProjectCarrierRoot(normalizedCwd)
|
|
225
|
+
return getCarrierPathForRoot(carrierRoot, host)
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
export function hasProjectFullCarrier(cwd, host = '') {
|
|
229
|
+
const carrierPath = getProjectCarrierPath(cwd, host)
|
|
230
|
+
return hasFullCarrierMarker(carrierPath)
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
function buildInitialStateSnapshot({
|
|
234
|
+
goal = '继续当前非只读任务',
|
|
235
|
+
doing = '已进入当前任务执行流程',
|
|
236
|
+
context = '由运行时自动创建;后续按实际任务重写',
|
|
237
|
+
next = '根据当前用户请求继续执行,并按实际任务重写本状态文件',
|
|
238
|
+
} = {}) {
|
|
239
|
+
return [
|
|
240
|
+
'# 恢复快照',
|
|
241
|
+
'',
|
|
242
|
+
'## 主线目标',
|
|
243
|
+
goal,
|
|
244
|
+
'',
|
|
245
|
+
'## 正在做什么',
|
|
246
|
+
doing,
|
|
247
|
+
'',
|
|
248
|
+
'## 关键上下文',
|
|
249
|
+
context,
|
|
250
|
+
'',
|
|
251
|
+
'## 下一步',
|
|
252
|
+
next,
|
|
253
|
+
'',
|
|
254
|
+
'## 阻塞项',
|
|
255
|
+
'(无)',
|
|
256
|
+
'',
|
|
257
|
+
'## 方案',
|
|
258
|
+
'',
|
|
259
|
+
'## 已标记技能',
|
|
260
|
+
'',
|
|
261
|
+
].join('\n')
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
export function ensureProjectLocalRuntime(cwd, options = {}) {
|
|
265
|
+
const normalizedCwd = normalizePath(cwd || process.cwd())
|
|
266
|
+
const localDir = getProjectLocalDir(normalizedCwd)
|
|
267
|
+
mkdirSync(localDir, { recursive: true })
|
|
268
|
+
|
|
269
|
+
const scope = getProjectSessionScope(normalizedCwd, options)
|
|
270
|
+
mkdirSync(dirname(scope.statePath), { recursive: true })
|
|
271
|
+
|
|
272
|
+
if (!existsSync(scope.statePath)) {
|
|
273
|
+
writeFileSync(scope.statePath, `${buildInitialStateSnapshot(options.stateSeed || {})}\n`, 'utf-8')
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
return scope
|
|
277
|
+
}
|
|
278
|
+
|
|
146
279
|
function isUserHomeHelloagentsDir(dirPath) {
|
|
147
280
|
const homeCandidates = [
|
|
148
281
|
getHomeDir(),
|
|
@@ -368,7 +501,16 @@ function buildTransientRuntimeDir(cwd, options = {}) {
|
|
|
368
501
|
}
|
|
369
502
|
|
|
370
503
|
export function getRuntimeScope(cwd = process.cwd(), options = {}) {
|
|
371
|
-
const
|
|
504
|
+
const normalizedOptions = normalizeRuntimeOptions(options)
|
|
505
|
+
if (normalizedOptions.ensureProjectLocal === true) {
|
|
506
|
+
return {
|
|
507
|
+
...ensureProjectLocalRuntime(cwd, normalizedOptions),
|
|
508
|
+
active: true,
|
|
509
|
+
scope: 'project-session',
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
const projectScope = getProjectSessionScope(cwd, normalizedOptions)
|
|
372
514
|
if (projectScope.active) {
|
|
373
515
|
return {
|
|
374
516
|
...projectScope,
|
|
@@ -377,7 +519,7 @@ export function getRuntimeScope(cwd = process.cwd(), options = {}) {
|
|
|
377
519
|
}
|
|
378
520
|
|
|
379
521
|
return {
|
|
380
|
-
...buildTransientRuntimeDir(cwd,
|
|
522
|
+
...buildTransientRuntimeDir(cwd, normalizedOptions),
|
|
381
523
|
active: false,
|
|
382
524
|
scope: 'user-runtime',
|
|
383
525
|
}
|
|
@@ -2,6 +2,7 @@ import { existsSync, mkdirSync, rmSync, writeFileSync } from 'node:fs'
|
|
|
2
2
|
import { basename, dirname, join } from 'node:path'
|
|
3
3
|
|
|
4
4
|
import {
|
|
5
|
+
ensureProjectLocalRuntime,
|
|
5
6
|
getProjectSessionScope,
|
|
6
7
|
getRuntimeScope,
|
|
7
8
|
readJsonFile,
|
|
@@ -44,6 +45,19 @@ function getEventSessionAlias(eventPayload = {}) {
|
|
|
44
45
|
|
|
45
46
|
function getScope(cwd, options = {}) {
|
|
46
47
|
const normalizedOptions = normalizeOptions(options)
|
|
48
|
+
const stateSeed = normalizedOptions.stateSeed && typeof normalizedOptions.stateSeed === 'object'
|
|
49
|
+
? normalizedOptions.stateSeed
|
|
50
|
+
: {}
|
|
51
|
+
if (normalizedOptions.ensureProjectLocal === true) {
|
|
52
|
+
return {
|
|
53
|
+
...ensureProjectLocalRuntime(cwd, {
|
|
54
|
+
...normalizedOptions,
|
|
55
|
+
stateSeed,
|
|
56
|
+
}),
|
|
57
|
+
active: true,
|
|
58
|
+
scope: 'project-session',
|
|
59
|
+
}
|
|
60
|
+
}
|
|
47
61
|
if (normalizedOptions.project === true) {
|
|
48
62
|
return {
|
|
49
63
|
...getProjectSessionScope(cwd, normalizedOptions),
|
package/scripts/turn-state.mjs
CHANGED
|
@@ -119,6 +119,13 @@ export function writeTurnState(cwd = process.cwd(), input = {}) {
|
|
|
119
119
|
payload: input.payload && typeof input.payload === 'object' ? input.payload : input,
|
|
120
120
|
env: input.env || process.env,
|
|
121
121
|
ppid: input.ppid ?? process.ppid,
|
|
122
|
+
ensureProjectLocal: true,
|
|
123
|
+
stateSeed: {
|
|
124
|
+
goal: '记录当前非只读任务状态',
|
|
125
|
+
doing: '正在写入 turn-state',
|
|
126
|
+
context: '由运行时在需要识别完成、等待或阻塞时自动创建',
|
|
127
|
+
next: '根据当前 turn-state 继续或等待后续动作',
|
|
128
|
+
},
|
|
122
129
|
}
|
|
123
130
|
const scope = getRuntimeScope(cwd, runtimeOptions)
|
|
124
131
|
const normalized = normalizeTurnState(input)
|
|
@@ -39,7 +39,7 @@ function buildBlockReason(routeContext, detail, cwd) {
|
|
|
39
39
|
const commandLabel = `~${routeContext.skillName}`
|
|
40
40
|
const workflowHint = buildWorkflowHint(cwd)
|
|
41
41
|
return [
|
|
42
|
-
`[HelloAGENTS Runtime] 显式 ${commandLabel}
|
|
42
|
+
`[HelloAGENTS Runtime] 显式 ${commandLabel} 当前对话不应直接停下。`,
|
|
43
43
|
detail,
|
|
44
44
|
workflowHint,
|
|
45
45
|
'若无真实阻塞,请继续沿当前路径执行。',
|
|
@@ -74,7 +74,7 @@ function validateFormattedCloseoutMessage(routeContext, payload, cwd) {
|
|
|
74
74
|
if (!firstNonEmptyLine || !/^[💡⚡🔵✅❓⚠️❌]【HelloAGENTS】- /.test(firstNonEmptyLine)) {
|
|
75
75
|
return buildBlockReason(
|
|
76
76
|
routeContext,
|
|
77
|
-
'
|
|
77
|
+
'最终回复使用了 HelloAGENTS 外层格式,但首个非空行不是规范标题行。',
|
|
78
78
|
cwd,
|
|
79
79
|
)
|
|
80
80
|
}
|
|
@@ -82,7 +82,7 @@ function validateFormattedCloseoutMessage(routeContext, payload, cwd) {
|
|
|
82
82
|
if (countMatches(message, /[💡⚡🔵✅❓⚠️❌]【HelloAGENTS】-/g) > 1) {
|
|
83
83
|
return buildBlockReason(
|
|
84
84
|
routeContext,
|
|
85
|
-
'
|
|
85
|
+
'最终回复重复输出了 HelloAGENTS 标题;请把所有内容合并到同一个外层块内。',
|
|
86
86
|
cwd,
|
|
87
87
|
)
|
|
88
88
|
}
|
|
@@ -90,7 +90,7 @@ function validateFormattedCloseoutMessage(routeContext, payload, cwd) {
|
|
|
90
90
|
if (countMatches(message, /^🔄 下一步:/gm) > 1) {
|
|
91
91
|
return buildBlockReason(
|
|
92
92
|
routeContext,
|
|
93
|
-
'
|
|
93
|
+
'最终回复重复输出了 `🔄 下一步`;请只保留一个真实下一步。',
|
|
94
94
|
cwd,
|
|
95
95
|
)
|
|
96
96
|
}
|
|
@@ -140,7 +140,7 @@ function validateTurnState(routeContext, turnState, cwd, payload = {}) {
|
|
|
140
140
|
cwd,
|
|
141
141
|
)
|
|
142
142
|
}
|
|
143
|
-
return buildBlockReason(routeContext, `当前 turn-state 为 \`${turnState.kind}
|
|
143
|
+
return buildBlockReason(routeContext, `当前 turn-state 为 \`${turnState.kind}\`,不能作为当前对话结束状态。`, cwd)
|
|
144
144
|
}
|
|
145
145
|
|
|
146
146
|
export function evaluateTurnStopGate(payload = {}) {
|
|
@@ -15,7 +15,7 @@ Trigger: ~auto <任务描述>
|
|
|
15
15
|
- `T3` 高风险或不可逆操作默认不直接进入 `~build`;优先先走 `~plan` 或 `~prd`,纯审查/纯验证请求才可先进入 `~verify`
|
|
16
16
|
- 主路径一旦确定,立即读取对应 command skill,并在阶段完成后继续执行后续阶段,避免同一任务重复探索或重复等待
|
|
17
17
|
- 选路不替代授权;涉及外部副作用或高风险不可逆操作时,仍遵守 HelloAGENTS 阻塞判定与确认规则
|
|
18
|
-
- 用户显式使用 `~auto
|
|
18
|
+
- 用户显式使用 `~auto`,表示已授权在当前任务边界内沿选定主路径持续执行;若当前运行在 Codex `/goal` 下,`/goal` 只提供长程续跑与预算,`~auto` 仍按方案包、`state_path` 与验证契约推进;`~plan` / `~prd` 作为中间阶段时,不再额外询问“是否开始执行”,除非仍有真实阻塞;不得把 `🔄 下一步` 当作阶段交接或继续执行占位
|
|
19
19
|
- 优先消费当前上下文中已注入的 ROUTE / TIER、当前工作流约束与项目状态;不要在 `~auto` 内另建一套关键词路由表
|
|
20
20
|
|
|
21
21
|
## 流程
|
|
@@ -33,7 +33,7 @@ Trigger: ~auto <任务描述>
|
|
|
33
33
|
### 1. 选路
|
|
34
34
|
|
|
35
35
|
- 先按当前上下文里已注入的 ROUTE / TIER 语义约束判断,不依赖关键词命中做机械分流
|
|
36
|
-
-
|
|
36
|
+
- 若当前上下文没有足够的注入约束,再结合以下信号补足判断:影响范围、风险等级、是否需要结构化产物、是否已有活跃方案包、用户是否只想先比较方向
|
|
37
37
|
- 选路优先级:
|
|
38
38
|
- 纯探索 / 点子 / 方向比较 → `~idea`
|
|
39
39
|
- 明确要求验证 / 审查 / 跑检查 → `~verify`
|
|
@@ -20,19 +20,19 @@ Trigger: ~build [description]
|
|
|
20
20
|
|
|
21
21
|
### 1. 恢复与定位
|
|
22
22
|
|
|
23
|
-
- 优先按当前已加载的 HelloAGENTS 规则恢复当前任务,并遵循“.helloagents/ 文件读取优先级”;若当前消息明确要继续上次任务、会话刚经历恢复 /
|
|
23
|
+
- 优先按当前已加载的 HelloAGENTS 规则恢复当前任务,并遵循“.helloagents/ 文件读取优先级”;若当前消息明确要继续上次任务、会话刚经历恢复 / 压缩,或当前运行在 Codex active goal 下,先读取 `state_path`,再用当前用户消息、活跃方案包 / PRD 与代码事实确认当前任务
|
|
24
24
|
- 若存在最近的活跃方案包,读取对应的:
|
|
25
25
|
- `requirements.md`
|
|
26
26
|
- `plan.md`
|
|
27
27
|
- `tasks.md`
|
|
28
28
|
- `contract.json`
|
|
29
|
-
- 实现时优先把 `tasks.md`
|
|
29
|
+
- 实现时优先把 `tasks.md` 中每个任务的“完成标准”当作本次实现约束,不要只按任务标题猜测范围
|
|
30
30
|
- `contract.json` 存在时,优先按其中的 `verifyMode`、`reviewerFocus`、`testerFocus` 理解后续验证边界
|
|
31
|
-
-
|
|
31
|
+
- 若当前运行在 Codex active goal 下,按 `tasks.md` 未完成项、`contract.json` 与 `state_path` 恢复实现位置;不要自动创建新 goal,也不要把 goal 目标原文替代方案包
|
|
32
32
|
- 若当前上下文中已注入“当前工作流约束”或“当前推荐下一命令”,先服从它;只有推荐仍为 `~build`,或用户明确提出新增实现范围时,才继续 `~build`
|
|
33
33
|
- 其余项目知识库与相关代码文件,按 HelloAGENTS 项目上下文要求读取
|
|
34
34
|
- 若任务涉及 UI,按以下优先级读取并遵循:当前活跃 `plan.md` / PRD 中的 UI 决策 > 逻辑 `.helloagents/DESIGN.md`(实际路径按当前项目存储模式解析) > 已读取的 `hello-ui` 规则;同时所有 UI 任务都必须满足 UI 质量基线
|
|
35
|
-
-
|
|
35
|
+
- 若当前项目已有本地项目存储,且当前任务属于整页新建、设计系统改造、或跨多个组件的视觉重做,但逻辑 `.helloagents/DESIGN.md` 不存在,先按模板创建最小设计契约,再继续大规模实现
|
|
36
36
|
|
|
37
37
|
如果 `.helloagents/` 不存在:
|
|
38
38
|
- 按当前已加载的 HelloAGENTS 规则创建 `.helloagents/` 与最小流程状态
|
|
@@ -26,6 +26,6 @@ Trigger: ~commit [message]
|
|
|
26
26
|
## 知识库同步
|
|
27
27
|
提交后,继续复用上方已解析的同一份设置获取 `kb_create_mode`,不要再次读取 `~/.helloagents/helloagents.json`:
|
|
28
28
|
- 0 = 跳过
|
|
29
|
-
- 1 =
|
|
30
|
-
- 2 =
|
|
29
|
+
- 1 = 知识库已存在时自动同步(默认)
|
|
30
|
+
- 2 = 编码任务在知识库已存在或全局模式下自动创建或同步
|
|
31
31
|
同步范围与更新格式按当前已加载的 HelloAGENTS CONSOLIDATE 阶段执行。
|
|
@@ -0,0 +1,71 @@
|
|
|
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 只追加缺失行
|
|
@@ -17,8 +17,9 @@ Trigger: ~help
|
|
|
17
17
|
| ~build | 执行实现:按需求或方案包完成实现与验证 |
|
|
18
18
|
| ~prd | 完整 PRD:头脑风暴式逐维度挖掘,生成现代产品需求文档 |
|
|
19
19
|
| ~loop | 自主迭代优化:设定目标和指标,循环修改-验证-保留/回滚 |
|
|
20
|
-
| ~wiki |
|
|
21
|
-
| ~init |
|
|
20
|
+
| ~wiki | 仅创建/同步项目知识库 |
|
|
21
|
+
| ~init | 同 `~wiki` |
|
|
22
|
+
| ~global | 初始化项目级全局模式 |
|
|
22
23
|
| ~test | 为指定模块或最近变更编写完整测试 |
|
|
23
24
|
| ~verify | 验证总入口:审查 + 运行验证命令 + 修复循环 |
|
|
24
25
|
| ~commit | 规范化提交 + 知识库同步 |
|
|
@@ -31,8 +32,8 @@ Trigger: ~help
|
|
|
31
32
|
- `~review` → 等同 `~verify` 的审查优先模式
|
|
32
33
|
|
|
33
34
|
### 自动激活技能
|
|
34
|
-
|
|
35
|
-
|
|
35
|
+
以下技能仅在全局模式或已初始化项目时自动激活(例如执行过 `~global`,或当前项目级规则文件已包含 `<!-- HELLOAGENTS_PROFILE: full -->`)。
|
|
36
|
+
纯标准模式、且项目未初始化时不会自动触发这些技能;但涉及 UI 的任务仍受 UI 质量基线约束。
|
|
36
37
|
|
|
37
38
|
编码时:hello-ui, hello-api, hello-data, hello-security, hello-errors, hello-perf, hello-arch, hello-test
|
|
38
39
|
特定场景:hello-debug, hello-subagent, hello-write, hello-review
|
|
@@ -44,12 +45,12 @@ Trigger: ~help
|
|
|
44
45
|
| 配置项 | 默认值 | 作用 | 适用 CLI |
|
|
45
46
|
|--------|-------|------|---------|
|
|
46
47
|
| output_language | "" | 空=跟随用户语言/填写则指定(如 zh-CN、en) | Claude Code + Gemini CLI + Codex CLI |
|
|
47
|
-
| output_format | true | true
|
|
48
|
+
| output_format | true | true=主代理最终回复必须使用 HelloAGENTS 格式,流式/中间输出及子代理输出保持自然;false=自然输出 | Claude Code + Gemini CLI + Codex CLI |
|
|
48
49
|
| notify_level | 0 | 0=关闭/1=桌面通知/2=声音/3=两者 | Claude Code + Gemini CLI + Codex CLI |
|
|
49
50
|
| ralph_loop_enabled | true | 自动验证循环(显式 ~verify / ~loop 或收尾要求时触发 lint/test/build) | Claude Code + Gemini CLI + Codex CLI |
|
|
50
51
|
| guard_enabled | true | 阻断危险命令与写入后的安全扫描 | Claude Code + Gemini CLI + Codex CLI |
|
|
51
|
-
| kb_create_mode | 1 | 0=关闭/1
|
|
52
|
-
| project_store_mode | "local" | "local"=知识库/方案包保留在项目本地 `.helloagents/`;"repo-shared"=本地 `.helloagents/`
|
|
52
|
+
| kb_create_mode | 1 | 0=关闭/1=知识库已存在时自动同步/2=编码任务在知识库已存在或全局模式下自动创建或同步 | Claude Code + Gemini CLI + Codex CLI |
|
|
53
|
+
| project_store_mode | "local" | "local"=知识库/方案包保留在项目本地 `.helloagents/`;"repo-shared"=本地 `.helloagents/` 仅保留项目本地状态/运行态,知识库与方案包改写到 `~/.helloagents/projects/<repo-key>/` | Claude Code + Gemini CLI + Codex CLI |
|
|
53
54
|
| auto_commit_enabled | true | true=验证完成且有变更时自动执行本地提交;false=跳过自动提交,仍可手动用 `~commit` | Claude Code + Gemini CLI + Codex CLI |
|
|
54
55
|
| commit_attribution | "" | 空=不添加/填写内容则添加到 commit message | Claude Code + Gemini CLI + Codex CLI |
|
|
55
56
|
| install_mode | "standby" | 当前默认安装模式 | Claude Code + Gemini CLI + Codex CLI |
|
|
@@ -1,49 +1,33 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: ~init
|
|
3
|
-
description:
|
|
3
|
+
description: 初始化或同步项目知识库(与 ~wiki 同义)
|
|
4
4
|
policy:
|
|
5
5
|
allow_implicit_invocation: false
|
|
6
6
|
---
|
|
7
7
|
Trigger: ~init
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
`~init` 是用户显式命令,仅创建、补全或同步项目知识库。
|
|
10
|
+
`~init` 与 `~wiki` 同义,不受 `kb_create_mode` 限制。
|
|
11
|
+
执行 `~init` 时,`.helloagents/` 目录结构、模板格式和状态文件重写规则按当前已加载的 HelloAGENTS 规则执行;不写入项目级规则文件,也不创建项目级 HelloAGENTS 包根链接。
|
|
12
|
+
`.helloagents/` 在本 skill 中统一按项目级存储路径理解:项目本地 `.helloagents/` 继续承担项目本地存储目录;状态文件只使用 `state_path`;若 `project_store_mode=repo-shared`,知识库、`DESIGN.md` 与方案包按当前上下文中已注入的项目知识/方案目录写入。
|
|
12
13
|
|
|
13
14
|
## 流程
|
|
14
15
|
|
|
15
|
-
### 阶段 1
|
|
16
|
+
### 阶段 1:基础准备(必做)
|
|
16
17
|
|
|
17
|
-
1. 创建 `.helloagents/` 目录 + `state_path`(按 templates/STATE.md
|
|
18
|
-
2.
|
|
19
|
-
3. 刷新各宿主项目级 HelloAGENTS 包根链接(删除旧的重建):
|
|
20
|
-
- `.claude/skills/helloagents` symlink → `{插件根目录}/`
|
|
21
|
-
- `.gemini/skills/helloagents` symlink → `{插件根目录}/`
|
|
22
|
-
- `.codex/skills/helloagents` symlink → `{插件根目录}/`
|
|
23
|
-
这些链接用于项目级规则定位 HelloAGENTS 的 `skills/`、`templates/` 和 `scripts/`;宿主若支持递归发现 `SKILL.md`,也可直接识别包内 skills。
|
|
24
|
-
4. 读取 `{插件根目录}` 中的全量规则模板,用 `<!-- HELLOAGENTS_START -->` / `<!-- HELLOAGENTS_END -->` 标记包裹后写入:
|
|
25
|
-
- `AGENTS.md`(项目根目录,Codex 读取)
|
|
26
|
-
- `CLAUDE.md`(项目根目录,Claude Code 读取)
|
|
27
|
-
- `.gemini/GEMINI.md`(Gemini CLI 读取,需先创建 .gemini/ 目录)
|
|
28
|
-
注意:如果文件已存在且包含标记,替换标记内的内容;如果文件已存在但无标记,追加到末尾;如果文件不存在,创建新文件
|
|
29
|
-
5. 追加 `.gitignore`(如果对应行不存在):
|
|
18
|
+
1. 创建 `.helloagents/` 目录 + `state_path`(按 templates/STATE.md 格式,初始“主线目标”写当前知识库初始化 / 同步任务,初始状态为空闲)
|
|
19
|
+
2. 追加 `.gitignore`(如果对应行不存在):
|
|
30
20
|
```
|
|
31
21
|
.helloagents/
|
|
32
|
-
.claude/skills/helloagents
|
|
33
|
-
.gemini/skills/helloagents
|
|
34
|
-
.codex/skills/helloagents
|
|
35
|
-
AGENTS.md
|
|
36
|
-
CLAUDE.md
|
|
37
|
-
.gemini/GEMINI.md
|
|
38
22
|
```
|
|
39
23
|
|
|
40
|
-
### 阶段 2
|
|
24
|
+
### 阶段 2:知识库创建或补全(条件性)
|
|
41
25
|
|
|
42
26
|
检查项目是否有实际代码文件(非空项目):
|
|
43
27
|
- 有代码文件 → 执行完整知识库创建(下方流程)
|
|
44
28
|
- 空项目 → 跳过,告知用户"项目为空,知识库将在后续开发中创建"
|
|
45
29
|
|
|
46
|
-
|
|
30
|
+
知识库创建/补全流程(统一写入 `.helloagents/` 对应的项目级存储路径;`project_store_mode=repo-shared` 时实际落在共享知识目录):
|
|
47
31
|
1. 按 templates/ 目录的模板格式,分析项目代码库后生成:
|
|
48
32
|
- context.md — 按 templates/context.md 格式,填入项目概述、技术栈、架构、目录结构、模块链接
|
|
49
33
|
- guidelines.md — 按 templates/guidelines.md 格式,从现有代码推断编码约定
|
|
@@ -62,8 +46,7 @@ commands:
|
|
|
62
46
|
|
|
63
47
|
## 幂等性
|
|
64
48
|
重复执行 ~init 是安全的:
|
|
65
|
-
-
|
|
66
|
-
- `state_path`
|
|
67
|
-
-
|
|
68
|
-
-
|
|
69
|
-
- .gitignore 只追加缺失行
|
|
49
|
+
- `.helloagents/` 缺失时创建,已存在时复用
|
|
50
|
+
- `state_path` 按当前任务状态重写,不追加历史;它只记录当前知识库任务,不承担项目的长期记忆
|
|
51
|
+
- 知识库文件缺失时补全,已存在时按模板增量更新
|
|
52
|
+
- `.gitignore` 只追加缺失行
|
|
@@ -37,7 +37,7 @@ iteration commit metric delta guard status description
|
|
|
37
37
|
|
|
38
38
|
`~loop` 的八阶段循环是统一执行流程(ROUTE/TIER→SPEC→PLAN→BUILD→VERIFY→CONSOLIDATE)在迭代优化场景下的特化形式。每轮迭代的“修改”阶段遵循已标记的 hello-* 质量技能规范,“验证”阶段遵循 hello-verify 的验证规范。
|
|
39
39
|
执行 `~loop` 时,涉及公共阶段边界、阻塞判定与收尾要求的部分,仍按当前已加载的 HelloAGENTS 规则执行;本 skill 负责补充 loop 场景的迭代顺序与回滚规则。
|
|
40
|
-
|
|
40
|
+
若当前运行在 Codex `/goal` 下,`/goal` 只作为外层长程续跑与预算控制;`~loop` 仍负责指标、守卫、实验提交、keep/revert、results log、`state_path` 与收尾验证,不把 `/goal` 当成循环逻辑本身。
|
|
41
41
|
|
|
42
42
|
除非达到迭代上限或命中阻塞判定,否则继续执行,不额外询问是否继续,也不把 `🔄 下一步` 当作单轮结果或继续执行占位。
|
|
43
43
|
每轮迭代必须完整走完以下八个阶段:
|
|
@@ -102,7 +102,7 @@ Trigger: ~plan [description]
|
|
|
102
102
|
|
|
103
103
|
如果用户已明确表示继续执行,则视为授权成立,可直接继续执行。
|
|
104
104
|
如果当前任务来自 `~auto`,且方案包已足够支撑实现、也未命中阻塞判定,则默认直接进入 `~build`,不再追加一次“是否开始执行”的询问。
|
|
105
|
-
如果当前任务是显式 `~plan` 或 `~design
|
|
105
|
+
如果当前任务是显式 `~plan` 或 `~design`,且尚未获得执行授权,最终回复按通用输出格式使用等待输入态:正文说明方案包与验证结果,`🔄 下一步` 写清待确认动作。
|
|
106
106
|
|
|
107
107
|
## 方案包要求
|
|
108
108
|
|
|
@@ -121,7 +121,7 @@ c. AI 总结该维度的决策结果,进入下一个维度
|
|
|
121
121
|
|
|
122
122
|
如果用户已对当前 PRD 或继续执行作出明确同意,视为执行授权成立,可直接进入执行,或按需先补一轮 `~plan` 明确实现方案。
|
|
123
123
|
如果当前任务来自 `~auto`,且 PRD 已整理成可执行任务、也未命中阻塞判定,则默认继续进入 `~build`,必要时先补一轮轻量 `~plan`,不再额外询问一次“是否开始执行”。
|
|
124
|
-
如果当前任务是显式 `~prd
|
|
124
|
+
如果当前任务是显式 `~prd`,且尚未获得执行授权,最终回复按通用输出格式使用等待输入态:正文说明 PRD / 任务 / 契约结果,`🔄 下一步` 写清待确认动作。
|
|
125
125
|
|
|
126
126
|
### 6. 继续执行
|
|
127
127
|
|
|
@@ -11,7 +11,7 @@ Trigger: ~test [scope]
|
|
|
11
11
|
1. 确定测试范围:
|
|
12
12
|
- 无参数:为最近变更的文件编写测试
|
|
13
13
|
- 指定文件/模块:为指定范围编写测试
|
|
14
|
-
- Codex active goal 下无参数:从 `tasks.md` 未完成项、`contract.json` 与 `state_path`
|
|
14
|
+
- Codex active goal 下无参数:从 `tasks.md` 未完成项、`contract.json` 与 `state_path` 推导本次测试范围
|
|
15
15
|
2. 按 hello-* 技能查找路径读取 hello-test SKILL.md,按其 TDD 规范和边界用例要求编写测试
|
|
16
16
|
3. 运行测试确认全部通过
|
|
17
17
|
4. 同步直接相关的任务状态,报告覆盖情况和遗漏;测试通过只作为 goal 交付证据,不直接标记 goal complete
|