helloagents 3.0.12 → 3.0.16-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 (73) hide show
  1. package/.claude-plugin/marketplace.json +6 -4
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/.codex-plugin/plugin.json +1 -1
  4. package/README.md +182 -35
  5. package/README_CN.md +184 -37
  6. package/bootstrap-lite.md +32 -26
  7. package/bootstrap.md +35 -29
  8. package/cli.mjs +119 -11
  9. package/gemini-extension.json +1 -1
  10. package/install.ps1 +128 -0
  11. package/install.sh +121 -0
  12. package/package.json +23 -4
  13. package/scripts/advisor-state.mjs +36 -63
  14. package/scripts/capability-registry.mjs +4 -4
  15. package/scripts/cli-branch.mjs +84 -0
  16. package/scripts/cli-codex-config.mjs +14 -20
  17. package/scripts/cli-codex.mjs +32 -38
  18. package/scripts/cli-doctor-render.mjs +4 -0
  19. package/scripts/cli-doctor.mjs +40 -30
  20. package/scripts/cli-host-detect.mjs +0 -1
  21. package/scripts/cli-hosts.mjs +16 -8
  22. package/scripts/cli-lifecycle-hosts.mjs +119 -32
  23. package/scripts/cli-lifecycle.mjs +24 -13
  24. package/scripts/cli-messages.mjs +34 -16
  25. package/scripts/cli-runtime-carrier.mjs +15 -0
  26. package/scripts/cli-runtime-root.mjs +72 -0
  27. package/scripts/cli-toml.mjs +0 -79
  28. package/scripts/cli-utils.mjs +30 -4
  29. package/scripts/closeout-state.mjs +35 -62
  30. package/scripts/delivery-gate-messages.mjs +70 -0
  31. package/scripts/delivery-gate.mjs +9 -75
  32. package/scripts/guard-rules.mjs +42 -42
  33. package/scripts/guard.mjs +44 -24
  34. package/scripts/notify-context.mjs +19 -28
  35. package/scripts/notify-events.mjs +3 -1
  36. package/scripts/notify-gates.mjs +2 -0
  37. package/scripts/notify-route.mjs +9 -7
  38. package/scripts/notify-ui.mjs +42 -32
  39. package/scripts/notify.mjs +72 -36
  40. package/scripts/project-storage.mjs +35 -66
  41. package/scripts/ralph-loop.mjs +36 -31
  42. package/scripts/replay-state.mjs +31 -128
  43. package/scripts/review-state.mjs +34 -61
  44. package/scripts/runtime-artifacts.mjs +95 -0
  45. package/scripts/runtime-context.mjs +35 -29
  46. package/scripts/runtime-scope.mjs +313 -0
  47. package/scripts/session-capsule.mjs +202 -0
  48. package/scripts/turn-state-cli.mjs +17 -0
  49. package/scripts/turn-state.mjs +185 -66
  50. package/scripts/turn-stop-gate.mjs +24 -6
  51. package/scripts/verify-state.mjs +34 -85
  52. package/scripts/visual-state.mjs +38 -65
  53. package/scripts/workflow-core.mjs +3 -3
  54. package/scripts/workflow-plan-files.mjs +1 -1
  55. package/scripts/workflow-recommendation.mjs +17 -13
  56. package/scripts/workflow-state.mjs +5 -5
  57. package/skills/commands/build/SKILL.md +1 -1
  58. package/skills/commands/commit/SKILL.md +1 -1
  59. package/skills/commands/help/SKILL.md +5 -3
  60. package/skills/commands/loop/SKILL.md +1 -1
  61. package/skills/commands/plan/SKILL.md +8 -6
  62. package/skills/commands/prd/SKILL.md +5 -3
  63. package/skills/commands/verify/SKILL.md +5 -5
  64. package/skills/hello-debug/SKILL.md +20 -3
  65. package/skills/hello-review/SKILL.md +2 -2
  66. package/skills/hello-subagent/SKILL.md +2 -2
  67. package/skills/hello-test/SKILL.md +6 -2
  68. package/skills/hello-ui/SKILL.md +7 -7
  69. package/skills/hello-verify/SKILL.md +10 -7
  70. package/skills/helloagents/SKILL.md +14 -9
  71. package/templates/context.md +6 -0
  72. package/templates/plans/plan.md +3 -0
  73. package/templates/plans/tasks.md +8 -3
package/bootstrap.md CHANGED
@@ -4,10 +4,10 @@
4
4
 
5
5
  ## 配置
6
6
  配置文件: ~/.helloagents/helloagents.json
7
- 如果当前上下文中已包含"当前用户设置",视为配置已完成读取,本轮直接复用。
8
- 否则,当本轮首次遇到受配置影响的行为时,再读取一次配置文件并复用本轮结果;不要为了展示、确认或同一结论重复读取。
9
- 同一轮内对同一配置文件、模块、SKILL、模板只读取一次,后续直接复用已得结论,不要重复探测或重复读取同一路径。
10
- 在受限 CLI(如工作区限制导致家目录不可读)中,确需读取但失败时必须明确说明,并按默认值或当前已知设置执行;禁止静默回退或假装读取成功。
7
+ `output_language` 非空时,所有用户可见文本使用该语言;为空则跟随用户当前语言。
8
+ 会话级缓存优先:当前上下文已有"当前用户设置"、原始 JSON 或读取摘要,且覆盖所需配置项时,直接复用。
9
+ 仅在缺少所需项、用户要求刷新,或本轮修改后需要核验时读取;输出格式只在缺少 `output_format` 已知值时触发读取。
10
+ 同一会话内,同一路径的配置文件、模块、SKILL、模板只读一次并跨轮复用;读取失败必须明示,并按默认值或已知设置执行。
11
11
 
12
12
  ## 编码原则
13
13
  - 代码是唯一判断依据,文档与代码不一致时以代码为准
@@ -54,8 +54,8 @@
54
54
  - 项目已有技术栈、设计系统或方案包时必须遵循既有决策
55
55
 
56
56
  ### UI 质量基线(涉及视觉/交互任务时,全阶段生效)
57
- 任务涉及界面视觉、交互体验、页面结构、组件外观、信息呈现或设计需求时,统一遵循以下基线;适用于标准模式、标准模式+已激活项目与全局模式。
58
- 纯逻辑修复、纯文案修改、纯数据处理、纯后端实现等不涉及视觉/交互变化的任务,不触发本节;项目已有更高优先级的 UI 契约时,只用本节兜底,不得覆盖上层决策。
57
+ 任务涉及界面视觉、交互体验、页面结构、组件外观、信息呈现或设计需求时,统一遵循以下基线;适用于标准模式未激活项目、标准模式已激活项目与全局模式。
58
+ 纯逻辑修复、纯文案修改、纯数据处理、纯后端实现等不涉及视觉/交互变化的任务,不触发本节。本基线是最低质量线;已有 `plan.md` / PRD、`DESIGN.md` 或 `hello-ui` 约束时,与其共同生效,不覆盖上层决策。
59
59
 
60
60
  - 先判断本次视觉变更是延续既有风格、演进式优化还是探索性方案,再形成简短但明确的内部设计简报:界面目的、目标用户与场景、主要视口、情绪方向、记忆点;不得直接滑入泛化风格标签或模型默认审美
61
61
  - 已有项目优先复用现有组件、token、品牌资产、内容语气与交互模式;先建立最小设计系统:至少明确背景/表面/正文/弱化/强调/语义色,以及 display/headline/body/caption 等排版角色;缺少关键设计上下文时明确说明,不凭空发明视觉语言
@@ -97,7 +97,7 @@
97
97
 
98
98
  ## 输出格式
99
99
  适用条件:
100
- - 当 `helloagents.json` 的 `output_format` 为 `true` 时,主代理仅可在本轮最后一条、且确认**不再继续调用工具、不再继续执行**的**收尾消息**中使用输出格式。
100
+ - 当 `helloagents.json` 的 `output_format` 为 `true` 时,主代理必须在本轮最后一条、且确认**不再继续调用工具、不再继续执行**的**收尾消息**中使用输出格式。
101
101
  - 若某个 skill 在本轮明确要求输出停顿、确认或总结,也仅当该消息同时是**本轮最终收尾消息**时,才可使用输出格式。
102
102
 
103
103
  排除条件:
@@ -116,16 +116,18 @@
116
116
  图标:💡直接响应 | ⚡快速执行 | 🔵规划流程 | ✅完成 | ❓等待输入 | ⚠️警告 | ❌错误
117
117
 
118
118
  使用约束:
119
- - 状态图标与收尾内容必须一致。等待用户输入、确认、授权或补充信息时,只能使用 `❓等待输入`;仅在本轮执行已完成且不再等待用户输入时,才能使用 `✅完成`。
120
- - `🔄 下一步` 必须填写当前最合适的下一步动作。若存在自然后续动作,直接给出明确引导;若当前任务已完整结束且确无合理后续,可填写“当前任务已完成;无后续动作。”
121
- - `🔄 下一步` 只写真实下一步,不改写成条件式能力表述或询问句。
119
+ - 状态图标与收尾内容必须一致。正文仍在等待用户输入、确认、授权或补充信息(含确认是否执行已给出的方案)时,只能使用 `❓等待输入`;仅在本轮执行已完成且不存在待确认动作时,才能使用 `✅完成`。
120
+ - `🔄 下一步` 必须写真实下一步,不改写成条件式能力表述或空泛询问。若正在等待确认,写清待确认动作;若存在自然后续动作,直接给出明确引导;若当前任务已完整结束且确无合理后续,可填写“当前任务已完成;无后续动作。”
122
121
 
123
122
  ### 收尾状态信号
124
- - 为避免运行时从自然语言、图标或格式反推“完成 / 等待输入”,主代理在本轮最终收尾前必须先调用 `scripts/turn-state.mjs write`
125
- - 本轮已完成且不再等待用户输入 `kind=complete`、`role=main`
126
- - 因阻塞判定等待用户输入、确认、授权或补充信息 `kind=waiting`、`role=main`,并同时写 `reasonCategory` `reason`
123
+ - `turn-state` 只在运行时必须识别本轮“完成 / 等待输入 / 阻塞”时写入;普通问候、普通问答、T0 只读分析和一次性解释不调用
124
+ - 必须调用场景:显式 `~auto` / `~loop`;非只读任务完成验证并进入收尾;需要 delivery gate / Ralph Loop / closeout evidence;需要等待或阻塞且运行时必须识别状态;已进入项目连续流程或方案包闭环
125
+ - 首选参数式调用,保证一次完成:`helloagents-turn-state write --kind complete --role main`;也可用 stdin JSON。不要查找、读取或拼接 `turn-state.mjs` 源码路径
126
+ - 本轮已完成且不再等待用户输入 → `helloagents-turn-state write --kind complete --role main`
127
+ - 因阻塞判定等待用户输入、确认、授权或补充信息(含未授权的外部副作用确认) → 写 `kind=waiting`、`role=main`,并同时写 `reasonCategory` 与 `reason`
127
128
  - 因错误、缺少前置条件或外部依赖而本轮停下 → 写 `kind=blocked`、`role=main`,并同时写 `reasonCategory` 与 `reason`
128
129
  - `reasonCategory` 只允许:`ambiguity`、`missing-input`、`missing-file`、`missing-credential`、`unauthorized-side-effect`、`high-risk-confirmation`、`external-dependency`、`error`
130
+ - 显式 `~auto` / `~loop` 下,`waiting` / `blocked` 还必须写入 `blocker.target`、`blocker.evidence`、`blocker.requiredAction`;阶段汇报、单轮 probe 完成、内部路线调整或“下一步建议”不构成停下理由
129
131
  - 子代理不得写 turn-state;子代理结束只直接返回结果,不为主代理代写完成态
130
132
 
131
133
  ## 交互规则
@@ -163,7 +165,7 @@
163
165
  以下情况才构成中途停下并请求用户输入的正当理由:
164
166
  - 需求存在影响执行结果的真实歧义
165
167
  - 缺少继续执行所必需的信息、文件、路径或凭据
166
- - 将产生外部副作用,但本轮尚未获得对应授权
168
+ - 将产生外部副作用,但本轮尚未获得对应授权(含等待确认是否实施已给方案)
167
169
  - 操作属于高风险或不可逆,按安全规则必须确认
168
170
  除上述情况外,默认继续执行,不以“建议下一步”替代实际推进。
169
171
 
@@ -205,13 +207,16 @@
205
207
 
206
208
  ### 3. PLAN — 规划与上下文准备
207
209
  根据 skills/ 目录下各 hello-* 技能的 SKILL.md frontmatter(name + description),标记本次任务可能需要的技能(不读取文件内容,仅记录名称)。
208
- 路径定义:`{HELLOAGENTS_READ_ROOT}` = 本轮已确定的 HelloAGENTS 读取根目录
210
+ 路径定义:`{HELLOAGENTS_READ_ROOT}` = 本轮已确定的 HelloAGENTS 读取根目录,统一用于读取 `skills/` 与 `templates/`
209
211
  先确定当前技能根目录:
210
212
  - 优先使用当前上下文中已注入的“本轮 HelloAGENTS 读取根目录”
211
- - 若当前上下文未注入,则将当前宿主 home 目录下的 `helloagents/` 链接作为 `{HELLOAGENTS_READ_ROOT}`
213
+ - 若当前上下文未注入,则使用稳定运行根目录 `~/.helloagents/helloagents`
214
+ - 宿主固定链接(Codex `~/.codex/helloagents`、Claude `~/.claude/helloagents`、Gemini `~/.gemini/helloagents`)只作为兼容别名,不作为优先探测路径
215
+ - 仍无法确定时,明确说明缺少 HelloAGENTS 读取根目录;不要递归扫描 `$HOME`、`Downloads`、项目目录或旧版本目录
212
216
  - 已激活项目或全局模式下,技能是否需要使用由当前已加载 AGENTS 规则决定;不要因此额外探测项目目录里的 HelloAGENTS skills 路径
213
217
  路径确定一次即可,不预读、不扫描整个目录,也不重复探测同一路径。
214
218
  hello-* 技能读取路径:`{HELLOAGENTS_READ_ROOT}/skills/{技能名}/SKILL.md`
219
+ 包内脚本优先使用稳定命令入口;需要写收尾状态时优先调用 `helloagents-turn-state write --kind complete --role main`,不要拼接 `turn-state.mjs` 路径。
215
220
 
216
221
  命令职责:
217
222
  - `~plan` 生成 `requirements.md`、`plan.md`、`tasks.md`、`contract.json`
@@ -235,7 +240,7 @@ hello-* 技能读取路径:`{HELLOAGENTS_READ_ROOT}/skills/{技能名}/SKILL.m
235
240
  ### 5. VERIFY — 审查与验证
236
241
  编码任务:
237
242
  - 读取 `skills/hello-verify/SKILL.md`,执行完整验证循环(Ralph Loop)→ 失败则修复 → 循环直到通过
238
- - 审查优先或显式使用 `~review` 时,先读取 `skills/hello-review/SKILL.md` 做范围审查;审查完成后调用 `scripts/review-state.mjs write` `.helloagents/.ralph-review.json`,再进入验证
243
+ - 审查优先或显式使用 `~review` 时,先读取 `skills/hello-review/SKILL.md` 做范围审查;审查完成后调用 `scripts/review-state.mjs write` 写当前会话 `artifacts/review.json`,再进入验证
239
244
  - 通过后收集已读取技能的交付检查清单,逐项附带证据确认,并确认用户目标已达成
240
245
 
241
246
  非编码任务(文档 / 方案 / 审查等):
@@ -243,14 +248,15 @@ hello-* 技能读取路径:`{HELLOAGENTS_READ_ROOT}/skills/{技能名}/SKILL.m
243
248
 
244
249
  ### 6. CONSOLIDATE — 状态、资料与归档
245
250
  所有任务:
246
- - 有方案包且准备报告完成 → 优先调用 `scripts/closeout-state.mjs write` `.helloagents/.ralph-closeout.json`,记录“需求覆盖”和“交付清单”;每项写明 `PASS` / `BLOCKED` 与简要摘要,再进入最终交付
251
+ - 有方案包且准备报告完成 → 优先调用 `scripts/closeout-state.mjs write` 写当前会话 `artifacts/closeout.json`,记录“需求覆盖”和“交付清单”;每项写明 `PASS` / `BLOCKED` 与简要摘要,再进入最终交付
247
252
  - 状态文件维护:按上文“流程状态”中的适用范围执行。属于“强制创建并持续更新”范围时,重写 `state_path` 指向的文件(“正在做什么”更新为已完成,清空关键上下文 / 下一步 / 阻塞项);属于“已有则更新”范围时,仅在文件已存在时重写;属于“不创建”范围时不生成此文件
248
- - 有方案包且任务已完成 → 将整个 `plans/{feature}/` 目录归档到 `.helloagents/archive/YYYY-MM/`,并更新 `archive/_index.md`。清理临时文件(`loop-results.tsv`、`.ralph-breaker.json`、`.ralph-verify.json`、`.ralph-review.json`、`.ralph-closeout.json`)
253
+ - 有方案包且任务已完成 → 将整个 `plans/{feature}/` 目录归档到 `.helloagents/archive/YYYY-MM/`,并更新 `archive/_index.md`。清理当前会话临时文件(`artifacts/loop-results.tsv`、`capsule.json`、`events.jsonl`、`artifacts/loop-breaker.json`、`artifacts/verify.json`、`artifacts/review.json`、`artifacts/closeout.json`)
249
254
  - 按 `kb_create_mode` 同步知识库(0=关闭 / 1=已激活项目或全局模式中编码自动 / 2=已激活项目或全局模式中始终):
250
255
  - `.helloagents/` 不存在则按 templates/ 创建知识库文件(`context.md`、`guidelines.md`、`verify.yaml`、`CHANGELOG.md`、`modules/`)
251
256
  - 已存在但不完整(缺少上述核心文件)→ 按 templates/ 补全缺失文件,不覆盖已有文件
252
257
  - 已存在且完整则按模板格式更新 `CHANGELOG.md`、相关 `modules/*.md`、增量经验 delta 追加
253
258
  - 符合条件时触发 `hello-reflect`(详见 `hello-reflect` SKILL.md)
259
+ - 本地版本检查点:非只读任务完成验证且产生工作区变更时,最终收尾前自动执行本地提交。先检查 `git status --short`;若不是 git 仓库或无变更则跳过。若发现 `.env`、密钥、凭据、明显不应提交的大文件或二进制产物,停止提交并说明风险;否则执行 `git add -A`,使用当前回复语言生成简洁 conventional commit message 后执行 `git commit`。不自动远程 `git push`,除非用户明确要求
254
260
 
255
261
  ## 完成约束
256
262
  - 未进入 VERIFY / CONSOLIDATE 的路径,声称完成前必须完成与任务类型匹配的必要检查;无法执行的检查必须明确说明,不得直接宣称完成
@@ -269,8 +275,8 @@ hello-* 技能读取路径:`{HELLOAGENTS_READ_ROOT}/skills/{技能名}/SKILL.m
269
275
  路径: {CWD}/.helloagents/
270
276
  所有文件的创建和更新必须按 templates/ 目录中对应模板的格式执行,不可自由发挥格式。
271
277
  说明:
272
- - `.helloagents/` 表示项目级存储路径,也是 standby 模式的激活信号
273
- - `state_path` 指向的状态文件、`.ralph-*.json`、`loop-results.tsv` 等运行态文件始终保留在项目本地 `.helloagents/`
278
+ - `.helloagents/` 表示项目级存储路径,也是标准模式的项目激活信号
279
+ - `state_path` 指向的状态文件、当前会话 `capsule.json`、`events.jsonl`、`artifacts/*.json`、`artifacts/loop-results.tsv` 等运行态文件始终保留在项目本地 `.helloagents/sessions/{branch}/{session}/`
274
280
  - `state_path` 是状态文件的唯一位置。宿主提供会话标识时,写入 `.helloagents/sessions/{branch}/{session}/STATE.md`;没有稳定会话标识时,写入 `.helloagents/sessions/{branch}/default/STATE.md`
275
281
  - 若 helloagents.json 中 `project_store_mode = "repo-shared"`,`context.md`、`guidelines.md`、`CHANGELOG.md`、`verify.yaml`、`DESIGN.md`、`modules/`、`plans/`、`archive/` 改按当前上下文中已注入的“当前项目存储”/“项目知识/方案目录”解析;未注入具体路径时,按当前存储模式自行解析,不要假定这些文件一定实际位于当前工作树中
276
282
  templates/ 查找路径(按优先级;首次确定模板根目录后,本轮复用):
@@ -296,7 +302,7 @@ templates/ 查找路径(按优先级;首次确定模板根目录后,本轮
296
302
  - “关键上下文”只保留恢复所需的信息,已不再相关的决策和变更移除
297
303
  - DESIGN.md — 项目级稳定 UI 契约(仅 UI 项目),`~plan` / `~auto` / `~prd` 创建或更新;不存在且当前任务涉及 UI → 按 templates/DESIGN.md 创建;不替代单次需求的 `plan.md`
298
304
  - plans/{feature}/ — 活跃方案包。`~plan` / `~auto` 生成:`requirements.md` + `plan.md` + `tasks.md` + `contract.json`;`~prd` 生成:`prd/` 目录(多维度文档)+ `tasks.md` + `decisions.md` + `contract.json`
299
- - .ralph-advisor.json — 可选 advisor 证据;仅当 `contract.json` 明确要求独立 advisor 时写入,记录 reason / focus / consultedSources / outcome
305
+ - artifacts/advisor.json — 当前会话的可选 advisor 证据;仅当 `contract.json` 明确要求独立 advisor 时写入,记录 reason / focus / consultedSources / outcome
300
306
  - archive/YYYY-MM/ — 已归档的方案包(整个 plans/{feature}/ 目录移入)
301
307
  - archive/_index.md — 归档索引
302
308
 
@@ -308,11 +314,11 @@ templates/ 查找路径(按优先级;首次确定模板根目录后,本轮
308
314
  - modules/*.md — 模块文档和经验
309
315
 
310
316
  ### 临时文件(流程产物,~clean 时清理)
311
- - loop-results.tsv — ~loop 迭代记录
312
- - .ralph-breaker.json — hello-verify 断路器状态
313
- - .ralph-verify.json — 最近一次成功验证的证据快照
314
- - .ralph-review.json — 最近一次成功审查的证据快照
315
- - .ralph-closeout.json — 最近一次成功收尾的交付证据快照
317
+ - artifacts/loop-results.tsv — 当前会话的 ~loop 迭代记录
318
+ - artifacts/loop-breaker.json — 当前会话的 hello-verify 断路器状态,仅在 `~loop` 或自动验证触发时写入
319
+ - artifacts/verify.json — 当前会话最近一次成功验证的证据快照
320
+ - artifacts/review.json — 当前会话最近一次成功审查的证据快照
321
+ - artifacts/closeout.json — 当前会话最近一次成功收尾的交付证据快照
316
322
 
317
323
  ## 项目上下文
318
324
 
@@ -325,11 +331,11 @@ templates/ 查找路径(按优先级;首次确定模板根目录后,本轮
325
331
  ### .helloagents/ 文件读取优先级
326
332
  以下文件在任务需要时按需读取,按优先级分层:
327
333
  说明:
328
- - Tier 1 始终读取当前 `state_path`
334
+ - Tier 1 在恢复、压缩、连续流程或活跃方案包场景读取当前 `state_path`;普通问答和一次性只读任务不强制读取
329
335
  - Tier 2 / Tier 3 中的 `.helloagents/...` 路径默认按项目级存储路径解析;`project_store_mode=repo-shared` 时按共享知识/方案目录解析
330
336
 
331
337
  Tier 1 — 恢复当前任务时优先读取:
332
- - 当前状态文件(`state_path`)→ 先确认当前消息仍是同一任务,再用它找回最近进度
338
+ - 当前状态文件(`state_path`)→ 仅在恢复、压缩、连续流程或活跃方案包场景读取;先确认当前消息仍是同一任务,再用它找回最近进度
333
339
 
334
340
  Tier 2 — 理解项目时读取:
335
341
  - .helloagents/context.md → 项目架构、技术栈、目录结构、模块索引
package/cli.mjs CHANGED
@@ -6,6 +6,8 @@
6
6
  'use strict'
7
7
 
8
8
  import { homedir } from 'node:os'
9
+ import { existsSync } from 'node:fs'
10
+ import { spawnSync } from 'node:child_process'
9
11
  import { dirname, join, resolve } from 'node:path'
10
12
  import { fileURLToPath } from 'node:url'
11
13
 
@@ -23,11 +25,14 @@ import {
23
25
  syncVersion,
24
26
  } from './scripts/cli-lifecycle.mjs'
25
27
  import { initCliDoctor, runDoctor } from './scripts/cli-doctor.mjs'
28
+ import { runBranchSwitch } from './scripts/cli-branch.mjs'
26
29
  import { createMessageHelpers, createInstallMessagePrinter } from './scripts/cli-messages.mjs'
30
+ import { getStableRuntimeRoot, removeRuntimeRoot, syncRuntimeRoot } from './scripts/cli-runtime-root.mjs'
27
31
 
28
32
  const HOME = homedir()
29
33
  const PKG_ROOT = resolve(dirname(fileURLToPath(import.meta.url)))
30
34
  const HELLOAGENTS_HOME = join(HOME, '.helloagents')
35
+ const RUNTIME_ROOT = getStableRuntimeRoot(HOME)
31
36
  const CONFIG_FILE = join(HELLOAGENTS_HOME, 'helloagents.json')
32
37
  const pkg = loadPackageVersion(PKG_ROOT)
33
38
 
@@ -44,7 +49,8 @@ const { printHelp, printInstallMsg } = createInstallMessagePrinter({
44
49
  })
45
50
  initCliLifecycle({
46
51
  home: HOME,
47
- pkgRoot: PKG_ROOT,
52
+ pkgRoot: RUNTIME_ROOT,
53
+ sourceRoot: PKG_ROOT,
48
54
  helloagentsHome: HELLOAGENTS_HOME,
49
55
  configFile: CONFIG_FILE,
50
56
  pkgVersion: pkg.version,
@@ -54,7 +60,8 @@ initCliLifecycle({
54
60
  })
55
61
  initCliDoctor({
56
62
  home: HOME,
57
- pkgRoot: PKG_ROOT,
63
+ pkgRoot: RUNTIME_ROOT,
64
+ sourceRoot: PKG_ROOT,
58
65
  pkgVersion: pkg.version,
59
66
  msg,
60
67
  readSettings,
@@ -64,17 +71,29 @@ initCliDoctor({
64
71
  getHostLabel,
65
72
  })
66
73
 
74
+ function ensureRuntimeRoot() {
75
+ syncRuntimeRoot(PKG_ROOT, RUNTIME_ROOT)
76
+ }
77
+
67
78
  function printPostinstallMessage() {
68
79
  console.log(`\n HelloAGENTS v${pkg.version}\n`)
69
80
  ensureConfig(HELLOAGENTS_HOME, CONFIG_FILE, safeJson, ensureDir)
81
+ ensureRuntimeRoot()
70
82
  ok('~/.helloagents/helloagents.json')
83
+ ok('~/.helloagents/helloagents')
71
84
 
72
85
  const settings = readSettings()
73
86
  const mode = settings.install_mode || DEFAULTS.install_mode
74
- console.log(msg(
75
- ` HelloAGENTS 包已安装,尚未自动部署到任何 CLI。\n 使用显式命令部署:\n helloagents install codex --${mode}\n helloagents install --all --${mode}\n`,
76
- ` HelloAGENTS package installed. No CLI targets were configured automatically.\n Deploy explicitly with:\n helloagents install codex --${mode}\n helloagents install --all --${mode}\n`,
77
- ))
87
+ const deployMessage = shouldDeployFromEnv()
88
+ ? msg(
89
+ ' HelloAGENTS 包已安装,正在按环境变量部署。\n',
90
+ ' HelloAGENTS package installed; deploying from environment variables.\n',
91
+ )
92
+ : msg(
93
+ ` HelloAGENTS 包已安装,尚未自动部署到任何 CLI。\n 使用显式命令部署:\n helloagents install codex --${mode}\n helloagents install --all --${mode}\n`,
94
+ ` HelloAGENTS package installed. No CLI targets were configured automatically.\n Deploy explicitly with:\n helloagents install codex --${mode}\n helloagents install --all --${mode}\n`,
95
+ )
96
+ console.log(deployMessage)
78
97
  }
79
98
 
80
99
  function runSafely(handler) {
@@ -86,21 +105,110 @@ function runSafely(handler) {
86
105
  }
87
106
  }
88
107
 
108
+ function resolveRuntimeScript(scriptName) {
109
+ const runtimeScript = join(RUNTIME_ROOT, 'scripts', scriptName)
110
+ if (existsSync(runtimeScript)) return runtimeScript
111
+ return join(PKG_ROOT, 'scripts', scriptName)
112
+ }
113
+
114
+ function runRuntimeScript(scriptName, scriptArgs) {
115
+ const result = spawnSync(process.execPath, [resolveRuntimeScript(scriptName), ...scriptArgs], {
116
+ stdio: 'inherit',
117
+ windowsHide: true,
118
+ })
119
+ if (result.error) {
120
+ console.error(`\n ✗ ${result.error.message}\n`)
121
+ process.exitCode = 1
122
+ return
123
+ }
124
+ process.exitCode = typeof result.status === 'number' ? result.status : 1
125
+ }
126
+
127
+ function envFlag(name) {
128
+ return ['1', 'true', 'yes', 'on'].includes(String(process.env[name] || '').toLowerCase())
129
+ }
130
+
131
+ function parseCompactLifecycleSpec() {
132
+ const raw = String(process.env.HELLOAGENTS || '').trim()
133
+ if (!raw) return null
134
+
135
+ const parts = raw.split(':')
136
+ if (parts.length > 2 || !parts[0]) {
137
+ throw new Error(msg('HELLOAGENTS 必须是 target[:mode],例如 codex:global', 'HELLOAGENTS must be target[:mode], for example codex:global'))
138
+ }
139
+
140
+ const target = normalizeHost(parts[0].trim().toLowerCase())
141
+ const mode = (parts[1] || '').trim().toLowerCase()
142
+ if (!target) throw new Error(msg(`不支持的 HELLOAGENTS 目标:${parts[0]}`, `Unsupported HELLOAGENTS target: ${parts[0]}`))
143
+ if (mode && !['standby', 'global'].includes(mode)) {
144
+ throw new Error(msg(`不支持的 HELLOAGENTS 模式:${mode}`, `Unsupported HELLOAGENTS mode: ${mode}`))
145
+ }
146
+
147
+ return { target, mode }
148
+ }
149
+
150
+ function lifecycleArgsFromEnv(defaultTarget = 'all') {
151
+ const compact = parseCompactLifecycleSpec()
152
+ const target = (
153
+ process.env.HELLOAGENTS_TARGET
154
+ || process.env.HELLOAGENTS_HOST
155
+ || compact?.target
156
+ || defaultTarget
157
+ ).trim()
158
+ const mode = (process.env.HELLOAGENTS_MODE || compact?.mode || '').trim().toLowerCase()
159
+ const args = [target === 'all' ? '--all' : target]
160
+ if (mode) args.push(`--${mode}`)
161
+ return args
162
+ }
163
+
164
+ function shouldDeployFromEnv() {
165
+ return envFlag('HELLOAGENTS_DEPLOY') || Boolean(String(process.env.HELLOAGENTS || '').trim())
166
+ }
167
+
89
168
  const argv = process.argv.slice(2)
90
169
  const cmd = argv[0] || ''
91
170
 
92
- if (cmd === 'postinstall') {
171
+ if (cmd === 'codex-notify') {
172
+ runRuntimeScript('notify.mjs', ['codex-notify', ...argv.slice(1)])
173
+ } else if (cmd === 'notify') {
174
+ runRuntimeScript('notify.mjs', argv.slice(1))
175
+ } else if (cmd === 'guard') {
176
+ runRuntimeScript('guard.mjs', argv.slice(1))
177
+ } else if (cmd === 'ralph-loop') {
178
+ runRuntimeScript('ralph-loop.mjs', argv.slice(1))
179
+ } else if (cmd === 'postinstall') {
93
180
  printPostinstallMessage()
181
+ if (shouldDeployFromEnv()) {
182
+ runSafely(() => runScopedLifecycle('install', lifecycleArgsFromEnv()))
183
+ }
94
184
  } else if (cmd === 'preuninstall') {
95
- runScopedLifecycle('cleanup', [])
185
+ runSafely(() => {
186
+ const cleanupArgs = argv.length > 1 ? argv.slice(1) : lifecycleArgsFromEnv('all')
187
+ runScopedLifecycle('cleanup', cleanupArgs)
188
+ if (cleanupArgs.includes('--all')) removeRuntimeRoot(RUNTIME_ROOT)
189
+ })
96
190
  } else if (cmd === 'sync-version') {
97
191
  syncVersion()
98
192
  } else if (cmd === 'doctor') {
99
193
  runSafely(() => runDoctor(argv.slice(1)))
100
194
  } else if (cmd === '--global' || cmd === '--standby') {
101
- switchMode(cmd === '--global' ? 'global' : 'standby')
102
- } else if (['install', 'update', 'uninstall', 'cleanup', '--cleanup'].includes(cmd)) {
103
- runSafely(() => runScopedLifecycle(cmd === '--cleanup' ? 'cleanup' : cmd, argv.slice(1)))
195
+ runSafely(() => {
196
+ ensureRuntimeRoot()
197
+ switchMode(cmd === '--global' ? 'global' : 'standby')
198
+ })
199
+ } else if (cmd === 'branch' || cmd === 'switch-branch') {
200
+ runSafely(() => runBranchSwitch(argv.slice(1)))
201
+ } else if (['install', 'update', 'uninstall', 'cleanup'].includes(cmd)) {
202
+ runSafely(() => {
203
+ const action = cmd
204
+ const lifecycleArgs = argv.slice(1)
205
+ if (cmd === 'install' || cmd === 'update') ensureRuntimeRoot()
206
+ runScopedLifecycle(action, lifecycleArgs)
207
+ const positionals = lifecycleArgs.filter((arg) => !arg.startsWith('--'))
208
+ if (action === 'uninstall' && (lifecycleArgs.includes('--all') || positionals.length === 0)) {
209
+ removeRuntimeRoot(RUNTIME_ROOT)
210
+ }
211
+ })
104
212
  } else {
105
213
  printHelp()
106
214
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "helloagents",
3
- "version": "3.0.12",
3
+ "version": "3.0.16-beta.1",
4
4
  "description": "Quality-driven orchestration kernel for AI CLIs",
5
5
  "contextFileName": "bootstrap.md",
6
6
  "author": "HelloWind",
package/install.ps1 ADDED
@@ -0,0 +1,128 @@
1
+ # HelloAGENTS one-shot installer.
2
+ #
3
+ # Environment:
4
+ # HELLOAGENTS=all|claude|gemini|codex[:standby|global]
5
+ # HELLOAGENTS_ACTION=install|update|cleanup|uninstall|switch-branch|branch
6
+ # HELLOAGENTS_TARGET=all|claude|gemini|codex
7
+ # HELLOAGENTS_MODE=standby|global
8
+ # HELLOAGENTS_BRANCH=main|beta|...
9
+ # HELLOAGENTS_PACKAGE=helloagents|github:owner/repo#ref|...
10
+
11
+ $ErrorActionPreference = "Stop"
12
+
13
+ $Action = if ($env:HELLOAGENTS_ACTION) { $env:HELLOAGENTS_ACTION } else { "install" }
14
+ $Target = if ($env:HELLOAGENTS_TARGET) { $env:HELLOAGENTS_TARGET } else { "" }
15
+ $Mode = if ($env:HELLOAGENTS_MODE) { $env:HELLOAGENTS_MODE } else { "" }
16
+ $Branch = if ($env:HELLOAGENTS_BRANCH) { $env:HELLOAGENTS_BRANCH } else { "" }
17
+ $Package = if ($env:HELLOAGENTS_PACKAGE) { $env:HELLOAGENTS_PACKAGE } else { "" }
18
+
19
+ if ($env:HELLOAGENTS) {
20
+ $Parts = $env:HELLOAGENTS.Split(":", 2)
21
+ if (-not $Parts[0]) {
22
+ throw "HELLOAGENTS must be target[:mode], for example codex:global"
23
+ }
24
+ if (-not $Target) { $Target = $Parts[0] }
25
+ if (-not $Mode -and $Parts.Count -gt 1) { $Mode = $Parts[1] }
26
+ }
27
+
28
+ if (-not $Target) { $Target = "all" }
29
+ if (-not $Mode) { $Mode = "standby" }
30
+ $Target = $Target.ToLowerInvariant()
31
+ $Mode = $Mode.ToLowerInvariant()
32
+
33
+ if (@("all", "claude", "gemini", "codex") -notcontains $Target) {
34
+ throw "Unsupported HELLOAGENTS target: $Target"
35
+ }
36
+
37
+ if (@("standby", "global") -notcontains $Mode) {
38
+ throw "Unsupported HELLOAGENTS mode: $Mode"
39
+ }
40
+
41
+ if (-not $Package) {
42
+ if ($Branch) {
43
+ $Package = "github:hellowind777/helloagents#$Branch"
44
+ } else {
45
+ $Package = "helloagents"
46
+ }
47
+ }
48
+
49
+ function Invoke-Npm {
50
+ param([string[]]$Args)
51
+ & npm @Args
52
+ if ($LASTEXITCODE -ne 0) {
53
+ throw "npm $($Args -join ' ') failed with exit code $LASTEXITCODE"
54
+ }
55
+ }
56
+
57
+ function Enable-PostinstallDeploy {
58
+ $env:HELLOAGENTS_DEPLOY = "1"
59
+ $env:HELLOAGENTS_TARGET = $Target
60
+ $env:HELLOAGENTS_MODE = $Mode
61
+ }
62
+
63
+ function Invoke-HostScript {
64
+ param([string]$ScriptName)
65
+ if ($Target -eq "all") {
66
+ Invoke-Npm @("explore", "-g", "helloagents", "--", "npm", "run", $ScriptName, "--", "--all", "--$Mode")
67
+ } else {
68
+ Invoke-Npm @("explore", "-g", "helloagents", "--", "npm", "run", $ScriptName, "--", $Target, "--$Mode")
69
+ }
70
+ }
71
+
72
+ function Sync-Hosts {
73
+ Invoke-HostScript "sync-hosts"
74
+ }
75
+
76
+ function Cleanup-Hosts {
77
+ Invoke-HostScript "cleanup-hosts"
78
+ }
79
+
80
+ function Uninstall-Hosts {
81
+ Invoke-HostScript "uninstall"
82
+ }
83
+
84
+ switch ($Action) {
85
+ "install" {
86
+ Enable-PostinstallDeploy
87
+ Invoke-Npm @("install", "-g", $Package)
88
+ }
89
+ "update" {
90
+ if ($Branch -or $env:HELLOAGENTS_PACKAGE) {
91
+ Invoke-Npm @("install", "-g", $Package)
92
+ } else {
93
+ & npm update -g helloagents
94
+ if ($LASTEXITCODE -ne 0) {
95
+ Invoke-Npm @("install", "-g", "helloagents")
96
+ }
97
+ }
98
+ Sync-Hosts
99
+ }
100
+ "cleanup" {
101
+ Cleanup-Hosts
102
+ }
103
+ "switch-branch" {
104
+ if (-not $Branch -and -not $env:HELLOAGENTS_PACKAGE) {
105
+ throw "HELLOAGENTS_BRANCH or HELLOAGENTS_PACKAGE is required for switch-branch"
106
+ }
107
+ Invoke-Npm @("install", "-g", $Package)
108
+ Sync-Hosts
109
+ }
110
+ "branch" {
111
+ if (-not $Branch -and -not $env:HELLOAGENTS_PACKAGE) {
112
+ throw "HELLOAGENTS_BRANCH or HELLOAGENTS_PACKAGE is required for branch"
113
+ }
114
+ Invoke-Npm @("install", "-g", $Package)
115
+ Sync-Hosts
116
+ }
117
+ "uninstall" {
118
+ try {
119
+ Uninstall-Hosts
120
+ } catch {
121
+ Write-Warning "Failed to cleanup HelloAGENTS host integrations before uninstall: $_"
122
+ }
123
+ Invoke-Npm @("uninstall", "-g", "helloagents")
124
+ }
125
+ default {
126
+ throw "Unsupported HELLOAGENTS_ACTION: $Action"
127
+ }
128
+ }
package/install.sh ADDED
@@ -0,0 +1,121 @@
1
+ #!/usr/bin/env sh
2
+ set -eu
3
+
4
+ # HelloAGENTS one-shot installer.
5
+ #
6
+ # Environment:
7
+ # HELLOAGENTS=all|claude|gemini|codex[:standby|global]
8
+ # HELLOAGENTS_ACTION=install|update|cleanup|uninstall|switch-branch|branch
9
+ # HELLOAGENTS_TARGET=all|claude|gemini|codex
10
+ # HELLOAGENTS_MODE=standby|global
11
+ # HELLOAGENTS_BRANCH=main|beta|...
12
+ # HELLOAGENTS_PACKAGE=helloagents|github:owner/repo#ref|...
13
+
14
+ ACTION="${HELLOAGENTS_ACTION:-install}"
15
+ TARGET="${HELLOAGENTS_TARGET:-}"
16
+ MODE="${HELLOAGENTS_MODE:-}"
17
+ BRANCH="${HELLOAGENTS_BRANCH:-}"
18
+ PACKAGE="${HELLOAGENTS_PACKAGE:-}"
19
+
20
+ if [ -n "${HELLOAGENTS:-}" ]; then
21
+ SPEC_TARGET="${HELLOAGENTS%%:*}"
22
+ SPEC_MODE=""
23
+ if [ -z "$SPEC_TARGET" ]; then
24
+ echo "HELLOAGENTS must be target[:mode], for example codex:global" >&2
25
+ exit 1
26
+ fi
27
+ if [ "$SPEC_TARGET" != "$HELLOAGENTS" ]; then
28
+ SPEC_MODE="${HELLOAGENTS#*:}"
29
+ fi
30
+ TARGET="${TARGET:-$SPEC_TARGET}"
31
+ MODE="${MODE:-$SPEC_MODE}"
32
+ fi
33
+
34
+ TARGET="${TARGET:-all}"
35
+ MODE="${MODE:-standby}"
36
+ TARGET="$(printf '%s' "$TARGET" | tr '[:upper:]' '[:lower:]')"
37
+ MODE="$(printf '%s' "$MODE" | tr '[:upper:]' '[:lower:]')"
38
+
39
+ case "$TARGET" in
40
+ all|claude|gemini|codex) ;;
41
+ *) echo "Unsupported HELLOAGENTS target: $TARGET" >&2; exit 1 ;;
42
+ esac
43
+
44
+ case "$MODE" in
45
+ standby|global) ;;
46
+ *) echo "Unsupported HELLOAGENTS mode: $MODE" >&2; exit 1 ;;
47
+ esac
48
+
49
+ if [ -z "$PACKAGE" ]; then
50
+ if [ -n "$BRANCH" ]; then
51
+ PACKAGE="github:hellowind777/helloagents#$BRANCH"
52
+ else
53
+ PACKAGE="helloagents"
54
+ fi
55
+ fi
56
+
57
+ sync_hosts() {
58
+ if [ "$TARGET" = "all" ]; then
59
+ npm explore -g helloagents -- npm run sync-hosts -- --all "--$MODE"
60
+ else
61
+ npm explore -g helloagents -- npm run sync-hosts -- "$TARGET" "--$MODE"
62
+ fi
63
+ }
64
+
65
+ cleanup_hosts() {
66
+ if [ "$TARGET" = "all" ]; then
67
+ npm explore -g helloagents -- npm run cleanup-hosts -- --all "--$MODE"
68
+ else
69
+ npm explore -g helloagents -- npm run cleanup-hosts -- "$TARGET" "--$MODE"
70
+ fi
71
+ }
72
+
73
+ uninstall_hosts() {
74
+ if [ "$TARGET" = "all" ]; then
75
+ npm explore -g helloagents -- npm run uninstall -- --all "--$MODE"
76
+ else
77
+ npm explore -g helloagents -- npm run uninstall -- "$TARGET" "--$MODE"
78
+ fi
79
+ }
80
+
81
+ enable_postinstall_deploy() {
82
+ export HELLOAGENTS_DEPLOY=1
83
+ export HELLOAGENTS_TARGET="$TARGET"
84
+ export HELLOAGENTS_MODE="$MODE"
85
+ }
86
+
87
+ case "$ACTION" in
88
+ install)
89
+ enable_postinstall_deploy
90
+ npm install -g "$PACKAGE"
91
+ ;;
92
+ update)
93
+ if [ -n "$BRANCH" ] || [ -n "${HELLOAGENTS_PACKAGE:-}" ]; then
94
+ npm install -g "$PACKAGE"
95
+ else
96
+ npm update -g helloagents || npm install -g helloagents
97
+ fi
98
+ sync_hosts
99
+ ;;
100
+ cleanup)
101
+ cleanup_hosts
102
+ ;;
103
+ switch-branch|branch)
104
+ if [ -z "$BRANCH" ] && [ -z "${HELLOAGENTS_PACKAGE:-}" ]; then
105
+ echo "HELLOAGENTS_BRANCH or HELLOAGENTS_PACKAGE is required for switch-branch" >&2
106
+ exit 1
107
+ fi
108
+ npm install -g "$PACKAGE"
109
+ sync_hosts
110
+ ;;
111
+ uninstall)
112
+ if ! uninstall_hosts; then
113
+ echo "Warning: failed to cleanup HelloAGENTS host integrations before uninstall" >&2
114
+ fi
115
+ npm uninstall -g helloagents
116
+ ;;
117
+ *)
118
+ echo "Unsupported HELLOAGENTS_ACTION: $ACTION" >&2
119
+ exit 1
120
+ ;;
121
+ esac