helloagents 3.0.7 → 3.0.9-beta.1

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.
Files changed (48) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +6 -6
  3. package/.codex-plugin/plugin.json +1 -1
  4. package/README.md +65 -58
  5. package/README_CN.md +60 -53
  6. package/bootstrap-lite.md +46 -28
  7. package/bootstrap.md +51 -34
  8. package/gemini-extension.json +1 -1
  9. package/package.json +12 -2
  10. package/scripts/capability-registry.mjs +9 -9
  11. package/scripts/cli-codex-config.mjs +49 -55
  12. package/scripts/cli-codex.mjs +69 -77
  13. package/scripts/cli-doctor.mjs +26 -18
  14. package/scripts/cli-host-detect.mjs +18 -2
  15. package/scripts/cli-messages.mjs +1 -1
  16. package/scripts/cli-toml.mjs +30 -0
  17. package/scripts/delivery-gate.mjs +5 -4
  18. package/scripts/guard-rules.mjs +26 -1
  19. package/scripts/guard.mjs +43 -14
  20. package/scripts/notify-context.mjs +30 -33
  21. package/scripts/notify-route.mjs +5 -2
  22. package/scripts/notify-source.mjs +3 -60
  23. package/scripts/notify.mjs +43 -11
  24. package/scripts/project-storage.mjs +107 -15
  25. package/scripts/session-token.mjs +73 -0
  26. package/scripts/turn-state.mjs +173 -0
  27. package/scripts/workflow-core.mjs +19 -11
  28. package/scripts/workflow-plan-files.mjs +17 -6
  29. package/scripts/workflow-recommendation.mjs +14 -14
  30. package/scripts/workflow-state.mjs +14 -14
  31. package/skills/_meta/SKILL.md +1 -1
  32. package/skills/commands/auto/SKILL.md +24 -9
  33. package/skills/commands/build/SKILL.md +4 -4
  34. package/skills/commands/clean/SKILL.md +3 -3
  35. package/skills/commands/commit/SKILL.md +1 -1
  36. package/skills/commands/help/SKILL.md +3 -3
  37. package/skills/commands/idea/SKILL.md +2 -2
  38. package/skills/commands/init/SKILL.md +13 -8
  39. package/skills/commands/loop/SKILL.md +4 -4
  40. package/skills/commands/plan/SKILL.md +13 -11
  41. package/skills/commands/prd/SKILL.md +10 -8
  42. package/skills/commands/verify/SKILL.md +5 -5
  43. package/skills/commands/wiki/SKILL.md +9 -11
  44. package/skills/hello-review/SKILL.md +1 -1
  45. package/skills/hello-subagent/SKILL.md +3 -2
  46. package/skills/hello-ui/SKILL.md +13 -13
  47. package/skills/hello-verify/SKILL.md +6 -5
  48. package/skills/helloagents/SKILL.md +17 -12
@@ -0,0 +1,173 @@
1
+ import { mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs'
2
+ import { dirname, join, normalize, resolve } from 'node:path'
3
+ import { homedir } from 'node:os'
4
+ import { fileURLToPath } from 'node:url'
5
+
6
+ import { appendReplayEvent } from './replay-state.mjs'
7
+
8
+ const TURN_STATE_PATH = join(homedir(), '.helloagents', 'runtime', 'turn-state.json')
9
+ const TURN_STATE_TTL_MS = 30 * 60 * 1000
10
+ const VALID_KINDS = new Set(['complete', 'waiting', 'blocked', 'progress'])
11
+ const VALID_ROLES = new Set(['main', 'subagent'])
12
+
13
+ function normalizePath(filePath = '') {
14
+ return filePath ? normalize(resolve(filePath)) : ''
15
+ }
16
+
17
+ function ensureRuntimeDir() {
18
+ mkdirSync(dirname(TURN_STATE_PATH), { recursive: true })
19
+ }
20
+
21
+ function readStore() {
22
+ try {
23
+ return JSON.parse(readFileSync(TURN_STATE_PATH, 'utf-8'))
24
+ } catch {
25
+ return {}
26
+ }
27
+ }
28
+
29
+ function writeStore(store) {
30
+ const keys = Object.keys(store)
31
+ if (keys.length === 0) {
32
+ rmSync(TURN_STATE_PATH, { force: true })
33
+ return
34
+ }
35
+
36
+ ensureRuntimeDir()
37
+ writeFileSync(TURN_STATE_PATH, `${JSON.stringify(store, null, 2)}\n`, 'utf-8')
38
+ }
39
+
40
+ function getTurnStateKey(cwd = process.cwd()) {
41
+ return normalizePath(cwd)
42
+ }
43
+
44
+ function normalizeTurnState(input = {}) {
45
+ const kind = typeof input.kind === 'string' ? input.kind.trim().toLowerCase() : ''
46
+ const role = typeof input.role === 'string' ? input.role.trim().toLowerCase() : 'main'
47
+
48
+ return {
49
+ kind: VALID_KINDS.has(kind) ? kind : '',
50
+ role: VALID_ROLES.has(role) ? role : 'main',
51
+ phase: typeof input.phase === 'string' ? input.phase.trim().toLowerCase() : '',
52
+ source: typeof input.source === 'string' && input.source.trim() ? input.source.trim() : 'manual',
53
+ requiresDeliveryGate: Boolean(input.requiresDeliveryGate),
54
+ }
55
+ }
56
+
57
+ function pruneInvalidEntry(store, key) {
58
+ delete store[key]
59
+ writeStore(store)
60
+ }
61
+
62
+ export function clearTurnState(cwd = process.cwd()) {
63
+ const key = getTurnStateKey(cwd)
64
+ if (!key) return false
65
+ const store = readStore()
66
+ if (!(key in store)) return false
67
+ delete store[key]
68
+ writeStore(store)
69
+ return true
70
+ }
71
+
72
+ export function readTurnState(cwd = process.cwd(), { now = Date.now() } = {}) {
73
+ const key = getTurnStateKey(cwd)
74
+ if (!key) return null
75
+
76
+ const store = readStore()
77
+ const entry = store[key]
78
+ if (!entry?.cwd || !entry?.kind || !entry?.updatedAt) {
79
+ if (entry) pruneInvalidEntry(store, key)
80
+ return null
81
+ }
82
+
83
+ const updatedAt = Date.parse(entry.updatedAt)
84
+ if (!Number.isFinite(updatedAt) || (now - updatedAt > TURN_STATE_TTL_MS)) {
85
+ pruneInvalidEntry(store, key)
86
+ return null
87
+ }
88
+
89
+ const normalized = normalizeTurnState(entry)
90
+ if (!normalized.kind) {
91
+ pruneInvalidEntry(store, key)
92
+ return null
93
+ }
94
+
95
+ return {
96
+ cwd: normalizePath(entry.cwd),
97
+ updatedAt: entry.updatedAt,
98
+ ...normalized,
99
+ }
100
+ }
101
+
102
+ export function writeTurnState(cwd = process.cwd(), input = {}) {
103
+ const key = getTurnStateKey(cwd)
104
+ const normalized = normalizeTurnState(input)
105
+ if (!key || !normalized.kind) {
106
+ throw new Error('turn-state requires cwd and a valid kind')
107
+ }
108
+
109
+ const store = readStore()
110
+ const payload = {
111
+ cwd: key,
112
+ updatedAt: new Date().toISOString(),
113
+ ...normalized,
114
+ }
115
+ store[key] = payload
116
+ writeStore(store)
117
+
118
+ appendReplayEvent(cwd, {
119
+ event: 'turn_state_written',
120
+ source: normalized.source,
121
+ details: {
122
+ kind: normalized.kind,
123
+ role: normalized.role,
124
+ phase: normalized.phase,
125
+ requiresDeliveryGate: normalized.requiresDeliveryGate,
126
+ },
127
+ })
128
+
129
+ return payload
130
+ }
131
+
132
+ function readStdinJson() {
133
+ try {
134
+ return JSON.parse(readFileSync(0, 'utf-8'))
135
+ } catch {
136
+ return {}
137
+ }
138
+ }
139
+
140
+ function main() {
141
+ const command = process.argv[2] || ''
142
+ const input = readStdinJson()
143
+ const cwd = input.cwd || process.cwd()
144
+
145
+ if (command === 'write') {
146
+ const payload = writeTurnState(cwd, input)
147
+ process.stdout.write(JSON.stringify({
148
+ suppressOutput: true,
149
+ path: TURN_STATE_PATH,
150
+ payload,
151
+ }))
152
+ return
153
+ }
154
+
155
+ if (command === 'clear') {
156
+ process.stdout.write(JSON.stringify({
157
+ suppressOutput: true,
158
+ cleared: clearTurnState(cwd),
159
+ }))
160
+ return
161
+ }
162
+
163
+ if (command === 'read') {
164
+ process.stdout.write(JSON.stringify({
165
+ suppressOutput: true,
166
+ state: readTurnState(cwd),
167
+ }))
168
+ }
169
+ }
170
+
171
+ if (process.argv[1] && fileURLToPath(import.meta.url) === process.argv[1]) {
172
+ main()
173
+ }
@@ -13,6 +13,13 @@ import { describeProjectStoreFile, getProjectDesignContractPath } from './projec
13
13
  export function getTargetPlans(snapshot) {
14
14
  return snapshot.activePlans.length > 0 ? snapshot.activePlans : snapshot.plans
15
15
  }
16
+
17
+ function describeStateLabel(state) {
18
+ if (state.stateSessionMode === 'default') {
19
+ return '当前分支默认会话槽位的 `STATE.md`'
20
+ }
21
+ return '当前会话的 `STATE.md`'
22
+ }
16
23
  export function classifyPlan(plan) {
17
24
  if (!plan) {
18
25
  return {
@@ -63,7 +70,7 @@ export function determineVerifyMode(plan) {
63
70
  if (plan.contractIssues.length > 0) {
64
71
  return {
65
72
  mode: 'metadata-first',
66
- reason: '方案包缺少可信的结构化 contract',
73
+ reason: '方案包缺少可信的结构化契约',
67
74
  guidance: '验证分流:当前还不适合直接进入 reviewer / tester;先回到 ~plan / ~prd 补齐 `contract.json`,明确 `verifyMode`、`reviewerFocus` 和 `testerFocus`。',
68
75
  }
69
76
  }
@@ -73,7 +80,7 @@ export function determineVerifyMode(plan) {
73
80
  const testerFocus = plan.contract.testerFocus.join(';')
74
81
  return {
75
82
  mode: 'review-first',
76
- reason: '方案 contract 已明确要求审查优先',
83
+ reason: '方案契约已明确要求审查优先',
77
84
  guidance: `验证分流:当前更适合审查优先;先执行 reviewer / hello-review 范围审查,再交给 tester / hello-verify 跑完整验证。${reviewerFocus ? ` reviewer 重点:${reviewerFocus}。` : ''}${testerFocus ? ` tester 重点:${testerFocus}。` : ''}`.trim(),
78
85
  }
79
86
  }
@@ -88,7 +95,7 @@ export function determineVerifyMode(plan) {
88
95
 
89
96
  return {
90
97
  mode: 'test-first',
91
- reason: '方案 contract 已明确验证主路径,且任务 contract 已完整',
98
+ reason: '方案契约已明确验证主路径,且任务契约已完整',
92
99
  guidance: `验证分流:当前更适合测试优先;先执行 tester / hello-verify 跑完整验证,再针对失败点或关键边界补充 hello-review。${plan.contract?.testerFocus?.length ? ` tester 重点:${plan.contract.testerFocus.join(';')}。` : ''}`.trim(),
93
100
  }
94
101
  }
@@ -97,27 +104,28 @@ function collectStateSyncIssues(snapshot) {
97
104
  const issues = []
98
105
  const hasPlans = snapshot.plans.length > 0
99
106
  const state = snapshot.state
107
+ const stateLabel = describeStateLabel(state)
100
108
 
101
109
  if (!hasPlans) {
102
110
  return issues
103
111
  }
104
112
 
105
113
  if (!state.exists) {
106
- issues.push('当前已存在方案包,但 `.helloagents/STATE.md` 缺失')
114
+ issues.push(`当前已存在方案包,但${stateLabel} 缺失`)
107
115
  return issues
108
116
  }
109
117
 
110
118
  if (!state.referencedPlanDir) {
111
- issues.push('当前已存在方案包,但 `STATE.md` 未记录活跃方案路径')
119
+ issues.push(`${stateLabel} 未记录活跃方案路径`)
112
120
  }
113
121
  if (!state.sections['主线目标']) {
114
- issues.push('`STATE.md` 缺少“主线目标”')
122
+ issues.push(`${stateLabel} 缺少“主线目标”`)
115
123
  }
116
124
  if (!state.sections['正在做什么']) {
117
- issues.push('`STATE.md` 缺少“正在做什么”')
125
+ issues.push(`${stateLabel} 缺少“正在做什么”`)
118
126
  }
119
127
  if (!state.sections['下一步']) {
120
- issues.push('`STATE.md` 缺少“下一步”')
128
+ issues.push(`${stateLabel} 缺少“下一步”`)
121
129
  }
122
130
 
123
131
  return issues
@@ -137,7 +145,7 @@ export function buildStateSyncHintFromSnapshot(snapshot) {
137
145
 
138
146
  export function buildStateRoleHintFromSnapshot(snapshot) {
139
147
  if (!snapshot.state.exists || snapshot.plans.length > 0) return ''
140
- return '恢复约束:当前仅检测到 `.helloagents/STATE.md`;先以当前用户消息、显式命令和代码事实确认主线,STATE.md 只用于找回上次停在哪,不是当前任务的自动授权或唯一事实源。'
148
+ return `恢复约束:当前仅检测到${describeStateLabel(snapshot.state)};先以当前用户消息、显式命令和代码事实确认主线,STATE.md 只用于找回上次停在哪,不是当前任务的自动授权或唯一判断依据。`
141
149
  }
142
150
 
143
151
  export function buildUiContractHint(cwd, snapshot) {
@@ -154,10 +162,10 @@ export function buildUiContractHint(cwd, snapshot) {
154
162
 
155
163
  const extraHints = []
156
164
  if (styleAdvisorRequired) {
157
- extraHints.push('若当前 UI contract 要求 style advisor,收尾前需复用 `.helloagents/.ralph-advisor.json` 留下独立复查证据')
165
+ extraHints.push('若当前 UI 契约要求 style advisor,收尾前需复用 `.helloagents/.ralph-advisor.json` 留下独立复查证据')
158
166
  }
159
167
  if (visualValidationRequired) {
160
- extraHints.push('若当前 UI contract 要求视觉验收,收尾前需写 `.helloagents/.ralph-visual.json` 记录关键视口、状态与结论')
168
+ extraHints.push('若当前 UI 契约要求视觉验收,收尾前需写 `.helloagents/.ralph-visual.json` 记录关键视口、状态与结论')
161
169
  }
162
170
  return `UI 约束提示:如本次属于视觉/交互链路,设计决策优先级固定为:当前活跃 plan.md / prd/03-ui-design.md → ${describeProjectStoreFile(cwd, 'DESIGN.md')} → hello-ui。${extraHints.length > 0 ? ` ${extraHints.join(';')}。` : ''}`
163
171
  }
@@ -2,7 +2,11 @@ import { existsSync, readdirSync, readFileSync } from 'node:fs'
2
2
  import { isAbsolute, join, normalize } from 'node:path'
3
3
 
4
4
  import { getPlanContractIssues, readPlanContract } from './plan-contract.mjs'
5
- import { getProjectPlansDir, getProjectStatePath, resolveProjectPlanDir } from './project-storage.mjs'
5
+ import {
6
+ getProjectPlansDir,
7
+ getProjectSessionStateScope,
8
+ resolveProjectPlanDir,
9
+ } from './project-storage.mjs'
6
10
 
7
11
  const PLAN_TEMPLATE_MARKERS = {
8
12
  'requirements.md': [
@@ -170,15 +174,22 @@ function comparePlanEntries(a, b) {
170
174
  return a.planName.localeCompare(b.planName)
171
175
  }
172
176
 
173
- export function readStateSnapshot(cwd) {
174
- const statePath = getProjectStatePath(cwd)
177
+ export function readStateSnapshot(cwd, options = {}) {
178
+ const stateScope = getProjectSessionStateScope(cwd, options)
179
+ const statePath = stateScope.statePath
180
+ const exists = existsSync(statePath)
175
181
  const content = readText(statePath)
176
182
  const sections = parseMarkdownSections(content)
177
183
  const referencedPlanDir = resolvePlanDir(cwd, sections['方案'])
178
184
 
179
185
  return {
180
186
  statePath,
181
- exists: existsSync(statePath),
187
+ stateScope: stateScope.stateScope,
188
+ stateSessionToken: stateScope.stateSessionToken,
189
+ stateSessionMode: stateScope.stateSessionMode,
190
+ stateBranch: stateScope.stateBranch,
191
+ sessionScoped: stateScope.stateScope === 'session',
192
+ exists,
182
193
  content,
183
194
  sections,
184
195
  referencedPlanDir,
@@ -230,8 +241,8 @@ export function listPlanPackages(cwd) {
230
241
  .sort(comparePlanEntries)
231
242
  }
232
243
 
233
- export function getWorkflowSnapshot(cwd) {
234
- const state = readStateSnapshot(cwd)
244
+ export function getWorkflowSnapshot(cwd, options = {}) {
245
+ const state = readStateSnapshot(cwd, options)
235
246
  const plans = listPlanPackages(cwd).map((entry) => ({
236
247
  ...entry,
237
248
  referencedByState: state.referencedPlanDir ? normalize(entry.dirPath) === normalize(state.referencedPlanDir) : false,
@@ -59,7 +59,7 @@ function buildConsolidateAction(recommendation) {
59
59
  phase: 'consolidate',
60
60
  mode: recommendation.mode,
61
61
  routeHint: recommendation.guidance,
62
- gateHint: '交付门控:审查与验证证据已满足;先写 `.helloagents/.ralph-closeout.json` 记录需求覆盖与交付清单,再完成 STATE.md / 归档后才可交付。',
62
+ gateHint: '交付把关:审查与验证证据已满足;先写 `.helloagents/.ralph-closeout.json` 记录需求覆盖与交付清单,再完成 STATE.md / 归档后才可交付。',
63
63
  }
64
64
  }
65
65
 
@@ -67,7 +67,7 @@ function buildConsolidateAction(recommendation) {
67
67
  phase: 'consolidate',
68
68
  mode: recommendation.mode || 'ready',
69
69
  routeHint: recommendation.guidance,
70
- gateHint: '交付门控:当前已具备 closeout evidence;完成 STATE.md、知识沉淀与归档后即可交付。',
70
+ gateHint: '交付把关:当前已具备收尾证据;完成 STATE.md、知识沉淀与归档后即可交付。',
71
71
  }
72
72
  }
73
73
 
@@ -88,7 +88,7 @@ function buildVerifyAction(plan, verifyMode) {
88
88
  phase: 'verify',
89
89
  mode: verifyMode.mode,
90
90
  routeHint: verifyMode.guidance,
91
- gateHint: `交付门控:进入 CONSOLIDATE 前,必须先完成 reviewer / hello-review 范围审查,再完成 tester / hello-verify 全量验证,并留下最新验证证据;两步都通过后才可交付。${gateSuffix}`.trim(),
91
+ gateHint: `交付把关:进入 CONSOLIDATE 前,必须先完成 reviewer / hello-review 范围审查,再完成 tester / hello-verify 全量验证,并留下最新验证证据;两步都通过后才可交付。${gateSuffix}`.trim(),
92
92
  }
93
93
  }
94
94
  if (verifyMode.mode === 'metadata-first') {
@@ -97,8 +97,8 @@ function buildVerifyAction(plan, verifyMode) {
97
97
  mode: verifyMode.mode,
98
98
  routeHint: verifyMode.guidance,
99
99
  gateHint: plan.contractIssues.length > 0
100
- ? '交付门控:当前还不能进入 CONSOLIDATE;先补齐 `contract.json` 中的 `verifyMode`、`reviewerFocus`、`testerFocus`,再进入 reviewer / tester。'
101
- : '交付门控:当前还不能进入 CONSOLIDATE;先补齐 tasks.md 中每个任务的“涉及文件”“完成标准”和“验证方式”,再进入 reviewer / tester。',
100
+ ? '交付把关:当前还不能进入 CONSOLIDATE;先补齐 `contract.json` 中的 `verifyMode`、`reviewerFocus`、`testerFocus`,再进入 reviewer / tester。'
101
+ : '交付把关:当前还不能进入 CONSOLIDATE;先补齐 tasks.md 中每个任务的“涉及文件”“完成标准”和“验证方式”,再进入 reviewer / tester。',
102
102
  }
103
103
  }
104
104
 
@@ -106,7 +106,7 @@ function buildVerifyAction(plan, verifyMode) {
106
106
  phase: 'verify',
107
107
  mode: verifyMode.mode,
108
108
  routeHint: verifyMode.guidance,
109
- gateHint: `交付门控:进入 CONSOLIDATE 前,先完成 tester / hello-verify 全量验证并留下最新验证证据,再针对失败点或关键边界补充 hello-review;确认通过后才可交付。${gateSuffix}`.trim(),
109
+ gateHint: `交付把关:进入 CONSOLIDATE 前,先完成 tester / hello-verify 全量验证并留下最新验证证据,再针对失败点或关键边界补充 hello-review;确认通过后才可交付。${gateSuffix}`.trim(),
110
110
  }
111
111
  }
112
112
 
@@ -124,13 +124,13 @@ export function buildDeliveryActionFromSnapshot(snapshot, cwd, recommendation =
124
124
  if (recommendation.nextCommand === 'build') {
125
125
  return {
126
126
  phase: 'build',
127
- gateHint: '交付门控:当前还不能报告完成;先回到 ~build 完成剩余任务,再进入 ~verify。',
127
+ gateHint: '交付把关:当前还不能报告完成;先回到 ~build 完成剩余任务,再进入 ~verify。',
128
128
  }
129
129
  }
130
130
  if (recommendation.nextCommand === 'plan') {
131
131
  return {
132
132
  phase: 'plan',
133
- gateHint: '交付门控:当前还不能报告完成;先回到 ~plan 修复或补齐当前方案包,再进入 ~build / ~verify。',
133
+ gateHint: '交付把关:当前还不能报告完成;先回到 ~plan 修复或补齐当前方案包,再进入 ~build / ~verify。',
134
134
  }
135
135
  }
136
136
 
@@ -153,7 +153,7 @@ function buildPlanRecommendation(scopeLabel, plan, classification) {
153
153
  ? `${scopeLabel} "${plan.planName}" 仍不完整(${classification.details.join(';')})。`
154
154
  : `${scopeLabel} "${plan.planName}" 尚未形成可执行任务清单。`,
155
155
  guidance: classification.status === 'incomplete'
156
- ? '优先先走 ~plan 修复或补全当前方案包,再进入实现或验证;不要把不完整 artifact 直接当成可交付依据。'
156
+ ? '优先先走 ~plan 修复或补全当前方案包,再进入实现或验证;不要把不完整的结构化产物直接当成可交付依据。'
157
157
  : '先回到 ~plan 补齐 tasks.md 的原子任务,再进入实现、验证或收尾。',
158
158
  }
159
159
  }
@@ -180,7 +180,7 @@ function buildClosedRecommendation(scopeLabel, plan, cwd) {
180
180
  status: 'closed',
181
181
  nextCommand: 'verify',
182
182
  nextPath: '~verify -> CONSOLIDATE',
183
- summary: `${scopeLabel} "${plan.planName}" 的任务已全部闭合,但验证 contract 仍未结构化。`,
183
+ summary: `${scopeLabel} "${plan.planName}" 的任务已全部闭合,但验证契约仍未结构化。`,
184
184
  guidance: closedPlanEvidence.verifyMode.guidance,
185
185
  }
186
186
  }
@@ -197,7 +197,7 @@ function buildClosedRecommendation(scopeLabel, plan, cwd) {
197
197
  status: 'closed',
198
198
  nextCommand: 'verify',
199
199
  nextPath: '~verify -> CONSOLIDATE',
200
- summary: `${scopeLabel} "${plan.planName}" 的任务已闭合,但当前 UI contract 仍要求独立 advisor 复查与视觉验收。`,
200
+ summary: `${scopeLabel} "${plan.planName}" 的任务已闭合,但当前 UI 契约仍要求独立 advisor 复查与视觉验收。`,
201
201
  guidance: '先在 ~verify 阶段完成独立 advisor / style advisor 复查,并写入 `.helloagents/.ralph-advisor.json`;再完成视觉验收并写入 `.helloagents/.ralph-visual.json`,记录 reason、tooling、screensChecked、statesChecked、status 与 summary;两项都通过后再进入 CONSOLIDATE。',
202
202
  }
203
203
  }
@@ -209,7 +209,7 @@ function buildClosedRecommendation(scopeLabel, plan, cwd) {
209
209
  status: 'closed',
210
210
  nextCommand: 'verify',
211
211
  nextPath: '~verify -> CONSOLIDATE',
212
- summary: `${scopeLabel} "${plan.planName}" 的任务已闭合,但当前 contract 仍要求独立 advisor 复查。`,
212
+ summary: `${scopeLabel} "${plan.planName}" 的任务已闭合,但当前契约仍要求独立 advisor 复查。`,
213
213
  guidance: '先在 ~verify 阶段完成独立 advisor / style advisor 复查,并写入 `.helloagents/.ralph-advisor.json` 记录复查原因、focus、来源与结论;advisor 通过后再进入 CONSOLIDATE。',
214
214
  }
215
215
  }
@@ -221,7 +221,7 @@ function buildClosedRecommendation(scopeLabel, plan, cwd) {
221
221
  status: 'closed',
222
222
  nextCommand: 'verify',
223
223
  nextPath: '~verify -> CONSOLIDATE',
224
- summary: `${scopeLabel} "${plan.planName}" 的任务已闭合,但当前 UI contract 仍要求视觉验收。`,
224
+ summary: `${scopeLabel} "${plan.planName}" 的任务已闭合,但当前 UI 契约仍要求视觉验收。`,
225
225
  guidance: '先在 ~verify 阶段完成视觉验收,并写入 `.helloagents/.ralph-visual.json` 记录 reason、tooling、screensChecked、statesChecked、status 与 summary;视觉验收通过后再进入 CONSOLIDATE。',
226
226
  }
227
227
  }
@@ -307,7 +307,7 @@ function buildBuildOrchestrationHint(plan) {
307
307
  return `编排提示:检测到可并行的开放任务;如需提速,可先读取 hello-subagent 再按 tasks.md 分派。任务A:${describeTask(pair[0])};任务B:${describeTask(pair[1])}。`
308
308
  }
309
309
  if (openTasks.every((item) => item.files.length === 0)) {
310
- return '编排提示:当前有多个开放任务,但 tasks.md 尚未写清 contract 元数据;考虑子代理并行前先补足文件路径、完成标准与验证方式。'
310
+ return '编排提示:当前有多个开放任务,但 tasks.md 尚未写清契约元数据;考虑子代理并行前先补足文件路径、完成标准与验证方式。'
311
311
  }
312
312
  return '编排提示:当前仍有多个开放任务,但文件范围存在重叠;暂不建议并行子代理,优先串行推进。'
313
313
  }
@@ -16,27 +16,27 @@ import {
16
16
  buildRecommendation,
17
17
  } from './workflow-recommendation.mjs'
18
18
 
19
- export function getDeliveryAction(cwd) {
20
- const snapshot = getWorkflowSnapshot(cwd)
19
+ export function getDeliveryAction(cwd, options = {}) {
20
+ const snapshot = getWorkflowSnapshot(cwd, options)
21
21
  const recommendation = buildRecommendation(snapshot, cwd)
22
22
  return buildDeliveryActionFromSnapshot(snapshot, cwd, recommendation)
23
23
  }
24
24
 
25
- export function getWorkflowRecommendation(cwd) {
26
- return buildRecommendation(getWorkflowSnapshot(cwd), cwd)
25
+ export function getWorkflowRecommendation(cwd, options = {}) {
26
+ return buildRecommendation(getWorkflowSnapshot(cwd, options), cwd)
27
27
  }
28
28
 
29
- export function buildStateSyncHint(cwd) {
30
- return buildStateSyncHintFromSnapshot(getWorkflowSnapshot(cwd))
29
+ export function buildStateSyncHint(cwd, options = {}) {
30
+ return buildStateSyncHintFromSnapshot(getWorkflowSnapshot(cwd, options))
31
31
  }
32
32
 
33
- export function buildDeliveryGateHint(cwd) {
34
- const snapshot = getWorkflowSnapshot(cwd)
33
+ export function buildDeliveryGateHint(cwd, options = {}) {
34
+ const snapshot = getWorkflowSnapshot(cwd, options)
35
35
  return buildDeliveryGateHintFromSnapshot(snapshot, cwd, buildRecommendation(snapshot, cwd))
36
36
  }
37
37
 
38
- export function buildWorkflowRouteHint(cwd) {
39
- const snapshot = getWorkflowSnapshot(cwd)
38
+ export function buildWorkflowRouteHint(cwd, options = {}) {
39
+ const snapshot = getWorkflowSnapshot(cwd, options)
40
40
  const recommendation = buildRecommendation(snapshot, cwd)
41
41
  const stateSyncHint = buildStateSyncHintFromSnapshot(snapshot)
42
42
  const stateRoleHint = buildStateRoleHintFromSnapshot(snapshot)
@@ -57,8 +57,8 @@ export function buildWorkflowRouteHint(cwd) {
57
57
  function buildCommandRouteMessage(skillName, recommendation, verifyModeHint) {
58
58
  if (skillName === 'auto') {
59
59
  return recommendation.stage === 'consolidate'
60
- ? `当前工作流约束:${recommendation.summary} 当前建议下一阶段:CONSOLIDATE。${recommendation.guidance}`
61
- : `当前工作流约束:${recommendation.summary} 当前建议主路径:${recommendation.nextPath}。${recommendation.guidance}`
60
+ ? `当前工作流约束:${recommendation.summary} 当前建议下一阶段:CONSOLIDATE。${recommendation.guidance} 若本次明确使用 ~auto,则在未命中阻塞判定时直接完成当前收尾,不再额外停下询问。`
61
+ : `当前工作流约束:${recommendation.summary} 当前建议主路径:${recommendation.nextPath}。${recommendation.guidance} 若本次明确使用 ~auto,则命中主路径后继续衔接后续阶段,除非触发阻塞判定,否则不要在方案/PRD 阶段额外停下。`
62
62
  }
63
63
  if (skillName === 'plan') {
64
64
  if (recommendation.stage === 'consolidate') {
@@ -87,8 +87,8 @@ function buildCommandRouteMessage(skillName, recommendation, verifyModeHint) {
87
87
  return `当前工作流约束:${recommendation.summary} 当前建议下一命令:~${recommendation.nextCommand}。${recommendation.guidance}`
88
88
  }
89
89
 
90
- export function buildCommandRouteHint(skillName, cwd) {
91
- const snapshot = getWorkflowSnapshot(cwd)
90
+ export function buildCommandRouteHint(skillName, cwd, options = {}) {
91
+ const snapshot = getWorkflowSnapshot(cwd, options)
92
92
  const recommendation = buildRecommendation(snapshot, cwd)
93
93
  const contextHints = [
94
94
  buildStateRoleHintFromSnapshot(snapshot),
@@ -7,7 +7,7 @@ policy:
7
7
 
8
8
  ## Skill 系统
9
9
  Skills 是带 YAML frontmatter 的 Markdown 文件。
10
- - helloagents: 检查清单驱动的质量门控(每次对话自动加载)
10
+ - helloagents: 由检查清单驱动的质量把关(每次对话自动加载)
11
11
  - hello-*: 质量技能(根据任务自动激活,提供实现标准和交付检查清单)
12
12
  - commands/*: 用户通过 ~command 调用
13
13
 
@@ -1,27 +1,28 @@
1
1
  ---
2
2
  name: ~auto
3
- description: 自动选路命令根据任务自动选择 ~idea / ~plan / ~build / ~verify / ~prd 的组合路径(~auto 命令)
3
+ description: 自动编排命令自动选择并串联 ~idea / ~plan / ~build / ~verify / ~prd,默认持续推进直到交付完成(~auto 命令)
4
4
  policy:
5
5
  allow_implicit_invocation: false
6
6
  ---
7
7
  Trigger: ~auto <任务描述>
8
8
 
9
- `~auto` 是自动选路命令。它根据任务类型、复杂度、风险等级与项目状态,自动在 `~idea`、`~plan`、`~build`、`~verify`、`~prd` 之间选择合适路径。
10
- `~auto` 只做选路。路径一旦确定,立即读取对应 command skill 并按其流程执行。
9
+ `~auto` 是自动编排命令。它根据任务类型、复杂度、风险等级与项目状态,自动在 `~idea`、`~plan`、`~build`、`~verify`、`~prd` 之间选择合适主路径,并把这些阶段串成一条连续交付链路。
10
+ `~auto` 不止做一次选路;主路径一旦确定,就按需要继续衔接后续阶段,默认持续推进直到完成交付,只有命中 bootstrap 的阻塞判定时才停下。
11
11
 
12
12
  ## 铁律
13
13
  - 不为了“自动化”而强行走重流程
14
14
  - 复杂度与风险不足以支撑更重路径时,优先选更轻但能保证质量的路线
15
15
  - `T3` 高风险或不可逆链路默认不直接进入 `~build`;优先先走 `~plan` 或 `~prd`,纯审查/纯验证请求才可先进入 `~verify`
16
- - 选路一旦确定,立即读取对应 command skill,避免重复探索
16
+ - 主路径一旦确定,立即读取对应 command skill,并在阶段完成后继续衔接后续阶段,避免同一任务重复探索或重复等待
17
17
  - 选路不替代授权;涉及外部副作用或高风险不可逆操作时,仍遵守 bootstrap 的阻塞判定与确认规则
18
- - 优先消费当前上下文已注入的 ROUTE / TIER、当前工作流约束与项目状态;不要在 `~auto` 内另建一套关键词路由表
18
+ - 用户显式使用 `~auto`,表示已授权在当前任务边界内沿选定主路径持续执行;`~plan` / `~prd` 作为中间阶段时,不再额外询问“是否开始执行”,除非仍有真实阻塞
19
+ - 优先消费当前上下文中已注入的 ROUTE / TIER、当前工作流约束与项目状态;不要在 `~auto` 内另建一套关键词路由表
19
20
 
20
21
  ## 流程
21
22
 
22
23
  ### 0. 当前工作流优先
23
24
 
24
- - 若当前上下文已注入“当前工作流提示”或“当前工作流约束”,优先服从其中的推荐下一命令 / 主路径
25
+ - 若当前上下文中已注入“当前工作流提示”或“当前工作流约束”,优先服从其中的推荐下一命令 / 主路径
25
26
  - 默认原则:
26
27
  - 活跃方案包不完整或缺少任务清单 → 先 `~plan`
27
28
  - 活跃方案包仍在执行 → 先 `~build`,完成当前实现后再 `~verify`
@@ -31,7 +32,7 @@ Trigger: ~auto <任务描述>
31
32
  ### 1. 选路
32
33
 
33
34
  - 先按当前上下文里已注入的 ROUTE / TIER 语义约束判断,不依赖关键词命中做机械分流
34
- - 若当前轮没有足够的注入约束,再结合以下信号补足判断:影响范围、风险等级、是否需要 artifact、是否已有活跃方案包、用户是否只想先比较方向
35
+ - 若本轮没有足够的注入约束,再结合以下信号补足判断:影响范围、风险等级、是否需要结构化产物、是否已有活跃方案包、用户是否只想先比较方向
35
36
  - 选路优先级:
36
37
  - 纯探索 / 点子 / 方向比较 → `~idea`
37
38
  - 明确要求验证 / 审查 / 跑检查 → `~verify`
@@ -43,10 +44,10 @@ Trigger: ~auto <任务描述>
43
44
 
44
45
  - `T0` → 保持在 `~idea`,不创建项目文件
45
46
  - `T1` → 在 `~build` / `~verify` 间选择最短可交付路径
46
- - `T2` → 需要 artifact 或范围未完全收敛时优先 `~plan`
47
+ - `T2` → 需要结构化产物或范围未完全收敛时优先 `~plan`
47
48
  - `T3` → 纯审查/验真走 `~verify`;其余默认 `~plan` 或 `~prd`,待方案与风险边界明确后再进入实现
48
49
 
49
- ### 3. 读取对应命令并执行
50
+ ### 3. 读取对应命令并执行主路径
50
51
 
51
52
  - 选中 `idea` → 读取 `skills/commands/idea/SKILL.md`
52
53
  - 选中 `plan` → 读取 `skills/commands/plan/SKILL.md`
@@ -55,3 +56,17 @@ Trigger: ~auto <任务描述>
55
56
  - 选中 `prd` → 读取 `skills/commands/prd/SKILL.md`
56
57
 
57
58
  不要额外读取未选中的 command skill。
59
+
60
+ ### 4. 自动衔接直到完成
61
+
62
+ - 若主路径是 `~build` → 完成实现后继续进入 `~verify`,再按当前链路进入收尾
63
+ - 若主路径是 `~plan` → 方案包落地后,若当前链路来自 `~auto` 且未命中阻塞判定,直接继续进入 `~build`,不要把“方案已形成”当作最终停点
64
+ - 若主路径是 `~prd` → PRD / 任务 / 契约落地后,若当前链路来自 `~auto` 且未命中阻塞判定,按收敛结果继续进入 `~build`,必要时先补一轮轻量 `~plan`
65
+ - 若主路径是 `~verify` → 完成审查 / 验证 / 收尾后结束
66
+ - 若主路径是 `~idea`,且用户本意就是探索/比较,则在探索输出后结束;若探索后已收敛成明确方向且当前任务仍要求落地,则继续进入 `~plan` 或 `~build`
67
+
68
+ ### 5. 何时允许停下
69
+
70
+ - 仅在 bootstrap 的阻塞判定成立时停下:真实歧义、缺必需信息/文件/凭据、未授权外部副作用、高风险或不可逆操作
71
+ - 不得把 `~plan` / `~prd` 中“是否进入执行”的默认询问原样带入 `~auto` 链路
72
+ - 不得把“给出方案”“给出任务列表”“给出建议下一步”当作 `~auto` 的默认完成态;用户显式要求 `~auto` 时,默认目标是把当前任务推进到可交付完成
@@ -8,7 +8,7 @@ Trigger: ~build [description]
8
8
 
9
9
  `~build` 是执行实现命令。它负责读取现有需求、方案包与项目上下文,完成实现、局部验证、修复循环,并把结果衔接到后续验证与收尾。
10
10
  执行 `~build` 时,通用阶段边界按当前已加载 bootstrap 执行;本 skill 负责补充实现前定位、实现约束,以及进入 `~verify` / 收尾前的实现边界。
11
- `.helloagents/` 在本 skill 中表示逻辑项目空间:`STATE.md` 与 `.ralph-*.json` 保持项目本地;若 `project_store_mode=repo-shared`,知识库、`DESIGN.md`、`verify.yaml` 与方案包按当前会话注入的项目知识/方案目录解析。
11
+ `.helloagents/` 在本 skill 中统一按项目级存储路径理解:`STATE.md` 与 `.ralph-*.json` 保持项目本地;若当前上下文中的“当前项目存储”给出 `state_path`,本轮恢复快照统一读写该路径;若 `project_store_mode=repo-shared`,知识库、`DESIGN.md`、`verify.yaml` 与方案包按当前上下文中已注入的项目知识/方案目录解析。
12
12
 
13
13
  ## 铁律
14
14
  - 默认先定位上下文与范围,再修改代码
@@ -20,15 +20,15 @@ Trigger: ~build [description]
20
20
 
21
21
  ### 1. 恢复与定位
22
22
 
23
- - 优先按当前已加载 bootstrap 的“.helloagents/ 文件读取优先级”恢复当前链路;若当前消息显式继续既有链路,或会话刚经历恢复 / 压缩,先读取 `.helloagents/STATE.md` 作为恢复快照,再用当前用户消息、活跃方案包 / PRD 与代码事实校正主线
23
+ - 优先按当前已加载 bootstrap 的“.helloagents/ 文件读取优先级”恢复当前链路;若当前消息显式继续既有链路,或会话刚经历恢复 / 压缩,先读取 `.helloagents/STATE.md` 作为恢复快照(若当前项目存储给出 `state_path`,则优先读取该当前会话的 `STATE.md`),再用当前用户消息、活跃方案包 / PRD 与代码事实校正主线
24
24
  - 若存在最近的活跃方案包,读取对应的:
25
25
  - `requirements.md`
26
26
  - `plan.md`
27
27
  - `tasks.md`
28
28
  - `contract.json`
29
- - 实现时优先把 `tasks.md` 中每个任务的“完成标准”当作本轮 build contract,不要只按任务标题猜测范围
29
+ - 实现时优先把 `tasks.md` 中每个任务的“完成标准”当作本轮实现约束,不要只按任务标题猜测范围
30
30
  - `contract.json` 存在时,优先按其中的 `verifyMode`、`reviewerFocus`、`testerFocus` 理解后续验证边界
31
- - 若当前上下文已注入“当前工作流约束”或“当前建议下一命令”,先服从它;只有推荐仍为 `~build`,或用户明确提出新增实现范围时,才继续 `~build`
31
+ - 若当前上下文中已注入“当前工作流约束”或“当前建议下一命令”,先服从它;只有推荐仍为 `~build`,或用户明确提出新增实现范围时,才继续 `~build`
32
32
  - 其余项目知识库与相关代码文件,按 bootstrap 的项目上下文规则按需读取
33
33
  - 若任务涉及 UI,按以下优先级读取并遵循:当前活跃 `plan.md` / PRD 中的 UI 决策 > 逻辑 `.helloagents/DESIGN.md`(实际路径按当前项目存储模式解析) > `hello-ui` 通用规则
34
34
  - 若已激活项目且当前任务属于整页新建、设计系统改造、或跨多个组件的视觉重做,但逻辑 `.helloagents/DESIGN.md` 不存在,先按模板创建最小设计契约,再继续大规模实现
@@ -7,13 +7,13 @@ policy:
7
7
  Trigger: ~clean
8
8
 
9
9
  执行 `~clean` 时,方案包归档、临时文件清理和 `STATE.md` 更新边界按当前已加载 bootstrap 执行;本命令只负责判定哪些方案包可以清理,以及输出清理摘要。
10
- `.helloagents/` 在本 skill 中表示逻辑项目空间:`STATE.md` 和临时运行态文件保持项目本地;若 `project_store_mode=repo-shared`,`plans/` 与 `archive/` 按当前会话注入的项目知识/方案目录解析。
10
+ `.helloagents/` 在本 skill 中统一按项目级存储路径理解:`STATE.md` 和临时运行态文件保持项目本地;若当前上下文中的“当前项目存储”给出 `state_path`,本轮恢复快照统一读写该路径;若 `project_store_mode=repo-shared`,`plans/` 与 `archive/` 按当前上下文中已注入的项目知识/方案目录解析。
11
11
 
12
12
  ## 流程
13
13
 
14
- 1. 扫描逻辑 `.helloagents/plans/` 下的方案包(`project_store_mode=repo-shared` 时按当前知识/方案目录解析)
14
+ 1. 扫描 `.helloagents/plans/` 下的方案包(按当前项目存储模式解析;`project_store_mode=repo-shared` 时使用共享知识/方案目录)
15
15
  2. 判定完成状态:优先以 tasks.md 中所有任务已标记 [√] 为准;只有任务清单无法判断时,才把 `STATE.md` 中与当前方案一致的“主线目标”+“正在做什么”作为辅助信号,避免把旧恢复快照误当当前主线
16
- 3. 已完成的方案包 → 按 bootstrap 的归档规则移入逻辑 `.helloagents/archive/YYYY-MM/`,并同步更新逻辑 `.helloagents/archive/_index.md`
16
+ 3. 已完成的方案包 → 按 bootstrap 的归档规则移入 `.helloagents/archive/YYYY-MM/`(按当前项目存储模式解析),并同步更新 `.helloagents/archive/_index.md`
17
17
  4. 清理 bootstrap 中定义的临时文件
18
18
  5. 按 bootstrap 的流程状态规则更新 `STATE.md`;若当前状态指向已归档方案包,则清空对应方案路径
19
19
  7. 输出清理摘要(归档了几个方案包、清理了哪些文件)
@@ -20,7 +20,7 @@ Trigger: ~commit [message]
20
20
  - ""(空,默认)→ 不添加归属
21
21
  - 有内容(如 "Co-Authored-By: HelloAGENTS")→ 添加该内容到 commit message
22
22
  6. 执行 git commit
23
- 7. 若项目已有 `.helloagents/STATE.md`,按 bootstrap 的“已有则更新”规则同步当前已提交状态
23
+ 7. 若当前 `STATE.md` 已存在(优先取当前项目存储中的 `state_path`,未注入时回退 `.helloagents/STATE.md`),按 bootstrap 的“已有则更新”规则同步当前已提交状态
24
24
 
25
25
  ## 知识库同步
26
26
  提交后,继续复用上方已解析的同一份设置获取 `kb_create_mode`,不要再次读取 `~/.helloagents/helloagents.json`: