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.
Files changed (49) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/.codex-plugin/plugin.json +1 -1
  3. package/README.md +34 -34
  4. package/README_CN.md +36 -34
  5. package/bootstrap-lite.md +20 -20
  6. package/bootstrap.md +23 -21
  7. package/gemini-extension.json +1 -1
  8. package/install.ps1 +2 -2
  9. package/install.sh +2 -2
  10. package/package.json +1 -1
  11. package/scripts/cli-branch.mjs +7 -3
  12. package/scripts/cli-codex.mjs +6 -5
  13. package/scripts/cli-config.mjs +8 -0
  14. package/scripts/cli-doctor-codex.mjs +10 -5
  15. package/scripts/cli-doctor-render.mjs +16 -0
  16. package/scripts/cli-doctor.mjs +2 -3
  17. package/scripts/cli-lifecycle-hosts.mjs +6 -1
  18. package/scripts/cli-lifecycle.mjs +16 -2
  19. package/scripts/cli-messages.mjs +8 -7
  20. package/scripts/cli-runtime-carrier.mjs +3 -3
  21. package/scripts/cli-utils.mjs +9 -0
  22. package/scripts/guard.mjs +1 -1
  23. package/scripts/notify-context.mjs +1 -1
  24. package/scripts/notify-route.mjs +3 -4
  25. package/scripts/notify.mjs +6 -1
  26. package/scripts/project-storage.mjs +4 -4
  27. package/scripts/replay-state.mjs +22 -4
  28. package/scripts/runtime-context.mjs +14 -2
  29. package/scripts/runtime-scope.mjs +144 -2
  30. package/scripts/session-capsule.mjs +14 -0
  31. package/scripts/turn-state.mjs +7 -0
  32. package/scripts/turn-stop-gate.mjs +5 -5
  33. package/skills/commands/auto/SKILL.md +2 -2
  34. package/skills/commands/build/SKILL.md +4 -4
  35. package/skills/commands/commit/SKILL.md +2 -2
  36. package/skills/commands/global/SKILL.md +71 -0
  37. package/skills/commands/help/SKILL.md +8 -7
  38. package/skills/commands/init/SKILL.md +14 -31
  39. package/skills/commands/loop/SKILL.md +1 -1
  40. package/skills/commands/plan/SKILL.md +1 -1
  41. package/skills/commands/prd/SKILL.md +1 -1
  42. package/skills/commands/test/SKILL.md +1 -1
  43. package/skills/commands/verify/SKILL.md +5 -5
  44. package/skills/commands/wiki/SKILL.md +1 -1
  45. package/skills/hello-review/SKILL.md +1 -1
  46. package/skills/hello-subagent/SKILL.md +1 -1
  47. package/skills/hello-ui/SKILL.md +6 -6
  48. package/skills/hello-verify/SKILL.md +7 -7
  49. package/skills/helloagents/SKILL.md +9 -8
package/bootstrap.md CHANGED
@@ -6,7 +6,7 @@
6
6
  配置文件: ~/.helloagents/helloagents.json
7
7
  `output_language` 非空时,所有用户可见文本使用该语言;为空则跟随用户当前语言。
8
8
  会话级缓存优先:当前上下文已有"当前用户设置"、原始 JSON 或读取摘要,且覆盖所需配置项时,直接复用。
9
- 仅在缺少所需项、用户要求刷新,或本轮修改后需要核验时读取;对 Codex 来说,首次对话前若当前上下文仍缺少所需配置项,必须先读取一次 `~/.helloagents/helloagents.json`,压缩/恢复后的首次对话同样先重读一次;输出格式只在缺少 `output_format` 已知值时触发读取。
9
+ 仅在缺少所需项、用户要求刷新,或本次修改后需要核验时读取;对 Codex 来说,首次对话前若当前上下文仍缺少所需配置项,必须先读取一次 `~/.helloagents/helloagents.json`,压缩/恢复后的首次对话同样先重读一次;输出格式只在缺少 `output_format` 已知值时触发读取。
10
10
  同一会话内,同一路径的配置文件、模块、SKILL、模板只读一次并跨轮复用;读取失败必须明示,并按默认值或已知设置执行。
11
11
 
12
12
  ## 通用交付规则(强制)
@@ -107,8 +107,8 @@
107
107
  ## 交互、停顿与收尾
108
108
  ### 输出格式
109
109
  适用条件:
110
- - 当 `helloagents.json` 的 `output_format` 为 `true` 时,主代理必须在本轮最后一条、且确认**不再继续调用工具、不再继续执行**的**收尾消息**中使用输出格式。
111
- - 若某个 skill 在本轮明确要求输出停顿、确认或总结,也仅当该消息同时是**本轮最终收尾消息**时,才可使用输出格式。
110
+ - 当 `helloagents.json` 的 `output_format` 为 `true` 时,主代理必须在每轮对话最后一条、且确认**不再继续调用工具、不再继续执行**的**最终回复**中使用输出格式。
111
+ - 若某个 skill 在当前对话明确要求输出停顿、确认或总结,也仅当该消息同时是**当前对话的最终回复**时,才可使用输出格式。
112
112
 
113
113
  排除条件:
114
114
  - 当 `output_format` 为 `false` 时,所有回复保持自然输出,不得使用输出格式。
@@ -126,16 +126,16 @@
126
126
  图标:💡直接响应(一次性答复 / 只读分析) | ⚡快速执行(低风险直接执行) | 🔵规划流程(方案 / 规划产出) | ✅完成(已完成且无待确认动作) | ❓等待输入(等待用户输入 / 授权) | ⚠️警告(存在重要风险或限制) | ❌错误(发生错误或已阻塞)
127
127
 
128
128
  使用约束:
129
- - 首行必须保留 `【HelloAGENTS】` 和连字符 `-`,不得省略;状态图标与收尾内容必须一致。正文仍在等待用户输入、确认、授权或补充信息(含确认是否执行已给出的方案或修改)时,只能使用 `❓等待输入`;仅在本轮执行已完成且不存在待确认动作时,才能使用 `✅完成`。同一条最终收尾消息只使用一次该格式;若主体需要分段,在同一个外层块内分节,不得在正文中再次输出 `【HelloAGENTS】` 或第二个 `🔄 下一步`。
129
+ - 首行必须保留 `【HelloAGENTS】` 和连字符 `-`,不得省略;状态图标与收尾内容必须一致。正文仍在等待用户输入、确认、授权或补充信息(含确认是否执行已给出的方案或修改)时,只能使用 `❓等待输入`;仅在当前对话执行已完成且不存在待确认动作时,才能使用 `✅完成`。同一条最终回复只使用一次该格式;若主体需要分段,在同一个外层块内分节,不得在正文中再次输出 `【HelloAGENTS】` 或第二个 `🔄 下一步`。
130
130
  - `🔄 下一步` 必须写真正的下一步动作,不写单纯当前状态或条件式能力表述。若正在等待确认,写清待确认动作;若仍有已授权且可继续执行的动作,不得收尾,必须继续执行;若当前任务已完整结束且确无合理后续,可明确写出任务已结束、无后续动作,不补条件式邀约。
131
131
 
132
132
  ### 收尾状态信号
133
- - `turn-state` 只在运行时必须识别本轮“完成 / 等待输入 / 阻塞”时写入;普通问候、普通问答、T0 只读分析和一次性解释不调用
134
- - 必须调用场景:显式 `~auto` / `~loop`;非只读任务完成验证并进入收尾;需要让运行时识别本轮已完成、等待输入或已阻塞时;已进入项目连续流程或方案包闭环
133
+ - `turn-state` 只在运行时必须识别当前对话“完成 / 等待输入 / 阻塞”时写入;普通问候、普通问答、T0 只读分析和一次性解释不调用
134
+ - 必须调用场景:显式 `~auto` / `~loop`;非只读任务完成验证并进入收尾;需要让运行时识别当前对话已完成、等待输入或已阻塞时;已进入项目连续流程或方案包闭环
135
135
  - 首选参数式调用,保证一次完成:`helloagents-turn-state write --kind complete --role main`;也可用 stdin JSON。不要查找、读取或拼接 `turn-state.mjs` 源码路径
136
- - 本轮已完成且不再等待用户输入 → `helloagents-turn-state write --kind complete --role main`
136
+ - 当前对话已完成且不再等待用户输入 → `helloagents-turn-state write --kind complete --role main`
137
137
  - 因阻塞判定等待用户输入、确认、授权或补充信息(含未授权的外部副作用确认) → 写 `kind=waiting`、`role=main`,并同时写 `reasonCategory` 与 `reason`
138
- - 因错误、缺少前置条件或外部依赖而本轮停下 → 写 `kind=blocked`、`role=main`,并同时写 `reasonCategory` 与 `reason`
138
+ - 因错误、缺少前置条件或外部依赖而当前对话停下 → 写 `kind=blocked`、`role=main`,并同时写 `reasonCategory` 与 `reason`
139
139
  - `reasonCategory` 只允许:`ambiguity`、`missing-input`、`missing-file`、`missing-credential`、`unauthorized-side-effect`、`high-risk-confirmation`、`external-dependency`、`error`
140
140
  - 显式 `~auto` / `~loop` 下,`waiting` / `blocked` 还必须写入 `blocker.target`、`blocker.evidence`、`blocker.requiredAction`;阶段汇报、单轮探测完成、路线调整或“下一步建议”不构成停下理由
141
141
  - 子代理不得写 turn-state;子代理结束只直接返回结果,不为主代理代写完成态
@@ -173,7 +173,7 @@
173
173
  以下情况才构成中途停下并请求用户输入的正当理由:
174
174
  - 需求存在影响执行结果的真实歧义
175
175
  - 缺少继续执行所必需的信息、文件、路径或凭据
176
- - 将产生外部副作用,但本轮尚未获得对应授权(含等待确认是否实施已给方案)
176
+ - 将产生外部副作用,但当前任务尚未获得对应授权(含等待确认是否实施已给方案)
177
177
  - 操作属于高风险或不可逆,按安全规则必须确认
178
178
  除上述情况外,默认继续执行。
179
179
 
@@ -209,7 +209,7 @@
209
209
  - 审查 / 执行验证 → `~verify`
210
210
  - 不确定或希望端到端自动推进时使用 `~auto`
211
211
 
212
- 当前项目只要已建立 `.helloagents/`(例如执行过 `~wiki`、`~init`,或已进入项目级连续流程),就按项目级完整流程执行。
212
+ 当前项目只要已初始化(例如执行过 `~global`,或当前项目级规则文件已包含 `<!-- HELLOAGENTS_PROFILE: full -->`),就按项目级完整流程执行。
213
213
 
214
214
  #### 2. SPEC — 澄清目标与验收
215
215
  根据任务需要,按需读取项目上下文(知识库文件和项目文件),明确:
@@ -221,13 +221,13 @@
221
221
 
222
222
  #### 3. PLAN — 规划与上下文准备
223
223
  根据 skills/ 目录下各 hello-* 技能的 SKILL.md frontmatter(name + description),标记本次任务可能需要的技能(不读取文件内容,仅记录名称)。
224
- 路径定义:`{HELLOAGENTS_READ_ROOT}` = 本轮已确定的 HelloAGENTS 读取根目录,统一用于读取 `skills/` 与 `templates/`
224
+ 路径定义:`{HELLOAGENTS_READ_ROOT}` = 当前对话已确定的 HelloAGENTS 读取根目录,统一用于读取 `skills/` 与 `templates/`
225
225
  先确定当前技能根目录:
226
- - 优先使用当前上下文中已注入的“本轮 HelloAGENTS 读取根目录”
226
+ - 优先使用当前上下文中已注入的“当前对话 HelloAGENTS 读取根目录”
227
227
  - 若当前上下文未注入,则使用稳定运行根目录 `~/.helloagents/helloagents`
228
228
  - 宿主固定链接(Codex `~/.codex/helloagents`、Claude `~/.claude/helloagents`、Gemini `~/.gemini/helloagents`)只作为兼容别名,不作为优先探测路径
229
229
  - 仍无法确定时,明确说明缺少 HelloAGENTS 读取根目录;不要递归扫描 `$HOME`、`Downloads`、项目目录或旧版本目录
230
- - 已激活项目或全局模式下,技能是否需要使用由当前已加载 AGENTS 规则决定;不要因此额外探测项目目录里的 HelloAGENTS skills 路径
230
+ - 全局模式或已初始化项目时,技能是否需要使用由当前已加载 AGENTS 规则决定;不要因此额外探测项目目录里的 HelloAGENTS skills 路径
231
231
  路径确定一次即可,不预读、不扫描整个目录,也不重复探测同一路径。
232
232
  hello-* 技能读取路径:`{HELLOAGENTS_READ_ROOT}/skills/{技能名}/SKILL.md`
233
233
  包内脚本优先使用稳定命令入口;涉及 turn-state 时按“收尾状态信号”执行。
@@ -265,12 +265,14 @@ hello-* 技能读取路径:`{HELLOAGENTS_READ_ROOT}/skills/{技能名}/SKILL.m
265
265
  - 有方案包且准备报告完成 → 优先调用 `scripts/closeout-state.mjs write` 写当前会话 `artifacts/closeout.json`,记录“需求覆盖”和“交付清单”;每项写明 `PASS` / `BLOCKED` 与简要摘要,再进入最终交付
266
266
  - 状态文件维护:按上文“流程状态”中的适用范围执行。属于“强制创建并持续更新”范围时,重写 `state_path` 指向的文件(“正在做什么”更新为已完成,清空关键上下文 / 下一步 / 阻塞项);属于“已有则更新”范围时,仅在文件已存在时重写;属于“不创建”范围时不生成此文件
267
267
  - 有方案包且任务已完成 → 将整个 `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`)
268
- - 按 `kb_create_mode` 同步知识库(0=关闭 / 1=已激活项目或全局模式中编码自动 / 2=已激活项目或全局模式中始终):
269
- - `.helloagents/` 不存在则按 templates/ 创建知识库文件(`context.md`、`guidelines.md`、`verify.yaml`、`CHANGELOG.md`、`modules/`)
268
+ - 按 `kb_create_mode` 同步知识库(0=关闭 / 1=知识库已存在时自动同步,未创建则不自动补建 / 2=编码任务在知识库已存在或全局模式下自动创建或同步):
269
+ - `0` 跳过
270
+ - `1` → 仅在知识库已存在时按模板增量同步;未创建则不自动补建
271
+ - `2` → 仅在编码任务中生效;知识库已存在时按模板增量同步;若知识库不存在但当前项目已处于全局模式,则按 templates/ 创建或补全 `context.md`、`guidelines.md`、`verify.yaml`、`CHANGELOG.md`、`modules/`
270
272
  - 已存在但不完整(缺少上述核心文件)→ 按 templates/ 补全缺失文件,不覆盖已有文件
271
273
  - 已存在且完整则按模板格式更新 `CHANGELOG.md`、相关 `modules/*.md`、增量经验 delta 追加
272
274
  - 符合条件时触发 `hello-reflect`(详见 `hello-reflect` SKILL.md)
273
- - 本地版本检查点:非只读任务完成验证且产生工作区变更时,若 `auto_commit_enabled=true`,最终收尾前自动执行本地提交;若 `auto_commit_enabled=false`,跳过这一步。先检查 `git status --short`;若不是 git 仓库或无变更则跳过。若发现 `.env`、密钥、凭据、明显不应提交的大文件或二进制产物,停止提交并说明风险;否则执行 `git add -A`,使用当前回复语言生成简洁 conventional commit message 后执行 `git commit`。显式 `~commit` 不受这个开关影响。不自动远程 `git push`,除非用户明确要求
275
+ - 本地版本检查点:非只读任务完成验证且产生工作区变更时,若 `auto_commit_enabled=true`,最终回复前自动执行本地提交;若 `auto_commit_enabled=false`,跳过这一步。先检查 `git status --short`;若不是 git 仓库或无变更则跳过。若发现 `.env`、密钥、凭据、明显不应提交的大文件或二进制产物,停止提交并说明风险;否则执行 `git add -A`,使用当前回复语言生成简洁 conventional commit message 后执行 `git commit`。显式 `~commit` 不受这个开关影响。不自动远程 `git push`,除非用户明确要求
274
276
 
275
277
  ### 完成判定
276
278
  - 未进入 VERIFY / CONSOLIDATE 的路径,声称完成前必须完成与任务类型匹配的必要检查;无法执行的检查必须明确说明,不得直接宣称完成
@@ -287,19 +289,19 @@ hello-* 技能读取路径:`{HELLOAGENTS_READ_ROOT}/skills/{技能名}/SKILL.m
287
289
  ### .helloagents/ 目录
288
290
  路径: {CWD}/.helloagents/
289
291
  所有文件的创建和更新必须按 templates/ 目录中对应模板的格式执行,不可自由发挥格式。
290
- - `.helloagents/` 表示项目级存储路径,也是标准模式的项目激活信号
292
+ - `.helloagents/` 表示项目本地存储路径,负责知识、方案、状态与运行态;它不再作为项目是否已初始化的判定信号
291
293
  - `state_path` 指向的状态文件、当前会话 `capsule.json`、`events.jsonl`、`artifacts/*.json`、`artifacts/loop-results.tsv` 等运行态文件始终保留在项目本地 `.helloagents/sessions/{workspace}/{session}/`
292
294
  - `state_path` 是状态文件的唯一位置。宿主提供会话标识时,写入 `.helloagents/sessions/{workspace}/{session}/STATE.md`;没有稳定会话标识时,写入 `.helloagents/sessions/{workspace}/default/STATE.md`
293
295
  - `{workspace}` 为当前 Git 分支、`detached-{sha}` 或非 Git 项目的 `workspace`;`.helloagents/sessions/active.json` 只记录当前活跃会话索引,避免同一会话被拆成多个目录
294
296
  - 若 helloagents.json 中 `project_store_mode = "repo-shared"`,`context.md`、`guidelines.md`、`CHANGELOG.md`、`verify.yaml`、`DESIGN.md`、`modules/`、`plans/`、`archive/` 改按当前上下文中已注入的“当前项目存储”/“项目知识/方案目录”解析;未注入具体路径时,按当前存储模式自行解析,不要假定这些文件一定实际位于当前工作树中
295
- templates/ 查找路径(按优先级;首次确定模板根目录后,本轮复用):
297
+ templates/ 查找路径(按优先级;首次确定模板根目录后,本会话复用):
296
298
  按上文相同的技能根目录规则确定;确定根目录后读取其中的 `templates/`。
297
299
 
298
300
  ### 流程状态(不受 `kb_create_mode` 控制,始终可写)
299
301
  - 状态文件(`state_path`)— ≤70 行,用来记录“上次做到哪里”。判断当前任务时,当前用户消息、显式命令、活跃方案包 / PRD、代码与验证证据优先于状态文件
300
302
  内容:主线目标、正在做什么、关键上下文(决策/变更/假设)、下一步(具体可执行动作含文件路径)、阻塞项
301
303
  适用边界:
302
- - 强制创建并持续更新:`~wiki`、`~init`、`~plan`、`~build`、`~auto`、`~prd`、`~loop`,以及进入工作流阶段或已激活项目的连续任务
304
+ - 强制创建并持续更新:`~wiki`、`~init`、`~global`、`~plan`、`~build`、`~auto`、`~prd`、`~loop`,以及进入工作流阶段、已初始化项目的连续任务,或任何会创建/修改本地文件、会在当前工作区留下实际输出或操作记录的非只读任务
303
305
  - 强制更新,不要求首次创建:`~clean`,主代理汇总子代理结果后
304
306
  - 已有则更新:`~verify`、`~review`(兼容别名)、`~test`、`~commit`
305
307
  - 不创建:`~help`、`~idea`、普通问答、一次性只读任务、子代理自身执行过程、压缩/恢复钩子
@@ -320,7 +322,7 @@ templates/ 查找路径(按优先级;首次确定模板根目录后,本轮
320
322
  - archive/_index.md — 归档索引
321
323
 
322
324
  ### 知识记录(受 `kb_create_mode` 控制)
323
- - 0=关闭;1=已激活项目或全局模式中的编码任务自动同步;2=已激活项目或全局模式中始终同步
325
+ - 0=关闭;1=知识库已存在时自动同步;2=编码任务在知识库已存在或全局模式下自动创建或同步
324
326
  - context.md — 项目架构、技术栈、目录结构、模块索引
325
327
  - guidelines.md — 编码约定(仅含非显而易见的约定)
326
328
  - CHANGELOG.md — 变更历史
@@ -335,7 +337,7 @@ templates/ 查找路径(按优先级;首次确定模板根目录后,本轮
335
337
  - artifacts/closeout.json — 当前会话最近一次成功收尾的交付证据快照
336
338
 
337
339
  ### 主线判断依据
338
- 1. 当前用户最新消息、显式 `~command`、本轮已确认的范围与结论
340
+ 1. 当前用户最新消息、显式 `~command`、当前对话已确认的范围与结论
339
341
  2. 当前活跃方案包 / PRD、代码与验证证据
340
342
  3. 当前状态文件(`state_path`,只用于补齐最近进度)
341
343
  4. 其他知识记录与历史归档
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "helloagents",
3
- "version": "3.0.29",
3
+ "version": "3.0.31",
4
4
  "description": "Quality-driven orchestration kernel for AI CLIs",
5
5
  "contextFileName": "bootstrap.md",
6
6
  "author": "HelloWind",
package/install.ps1 CHANGED
@@ -6,7 +6,7 @@
6
6
  # HELLOAGENTS_TARGET=all|claude|gemini|codex
7
7
  # HELLOAGENTS_MODE=standby|global
8
8
  # HELLOAGENTS_BRANCH=main|beta|...
9
- # HELLOAGENTS_PACKAGE=helloagents|github:owner/repo#ref|...
9
+ # HELLOAGENTS_PACKAGE=helloagents|https://github.com/owner/repo/archive/refs/heads/ref.tar.gz|...
10
10
 
11
11
  $ErrorActionPreference = "Stop"
12
12
 
@@ -39,7 +39,7 @@ if ($Mode -and @("standby", "global") -notcontains $Mode) {
39
39
 
40
40
  if (-not $Package) {
41
41
  if ($Branch) {
42
- $Package = "github:hellowind777/helloagents#$Branch"
42
+ $Package = "https://github.com/hellowind777/helloagents/archive/refs/heads/$Branch.tar.gz"
43
43
  } else {
44
44
  $Package = "helloagents"
45
45
  }
package/install.sh CHANGED
@@ -9,7 +9,7 @@ set -eu
9
9
  # HELLOAGENTS_TARGET=all|claude|gemini|codex
10
10
  # HELLOAGENTS_MODE=standby|global
11
11
  # HELLOAGENTS_BRANCH=main|beta|...
12
- # HELLOAGENTS_PACKAGE=helloagents|github:owner/repo#ref|...
12
+ # HELLOAGENTS_PACKAGE=helloagents|https://github.com/owner/repo/archive/refs/heads/ref.tar.gz|...
13
13
 
14
14
  ACTION="${HELLOAGENTS_ACTION:-install}"
15
15
  TARGET="${HELLOAGENTS_TARGET:-}"
@@ -49,7 +49,7 @@ fi
49
49
 
50
50
  if [ -z "$PACKAGE" ]; then
51
51
  if [ -n "$BRANCH" ]; then
52
- PACKAGE="github:hellowind777/helloagents#$BRANCH"
52
+ PACKAGE="https://github.com/hellowind777/helloagents/archive/refs/heads/$BRANCH.tar.gz"
53
53
  else
54
54
  PACKAGE="helloagents"
55
55
  fi
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "helloagents",
3
- "version": "3.0.29",
3
+ "version": "3.0.31",
4
4
  "type": "module",
5
5
  "description": "HelloAGENTS — The orchestration kernel that makes any AI CLI smarter. Adds intelligent routing, quality verification (Ralph Loop), safety guards, and notifications.",
6
6
  "author": "HelloWind",
@@ -2,7 +2,7 @@ import { spawnSync } from 'node:child_process'
2
2
 
3
3
  import { normalizeHost } from './cli-lifecycle.mjs'
4
4
 
5
- const DEFAULT_REPO_SPEC = 'github:hellowind777/helloagents'
5
+ const DEFAULT_REPO_ARCHIVE_BASE = 'https://github.com/hellowind777/helloagents/archive/refs/heads'
6
6
 
7
7
  function runCommand(command, args) {
8
8
  const needsShell = process.platform === 'win32' && /\.cmd$/i.test(command)
@@ -19,6 +19,10 @@ function runCommand(command, args) {
19
19
  }
20
20
  }
21
21
 
22
+ function getDefaultNpmCommand() {
23
+ return process.platform === 'win32' ? 'npm.cmd' : 'npm'
24
+ }
25
+
22
26
  function parseModeFlag(args) {
23
27
  const hasGlobal = args.includes('--global')
24
28
  const hasStandby = args.includes('--standby')
@@ -56,7 +60,7 @@ function parseBranchArgs(args) {
56
60
 
57
61
  function buildPackageSpec(ref) {
58
62
  if (/^(github:|git\+|https?:|file:)/i.test(ref)) return ref
59
- return `${DEFAULT_REPO_SPEC}#${ref}`
63
+ return `${DEFAULT_REPO_ARCHIVE_BASE}/${ref}.tar.gz`
60
64
  }
61
65
 
62
66
  function buildSyncArgs({ host, mode }) {
@@ -76,7 +80,7 @@ function buildSyncArgs({ host, mode }) {
76
80
 
77
81
  export function runBranchSwitch(args, options = {}) {
78
82
  const parsed = parseBranchArgs(args)
79
- const npmCommand = options.npmCommand || process.env.HELLOAGENTS_NPM_CMD || 'npm'
83
+ const npmCommand = options.npmCommand || process.env.HELLOAGENTS_NPM_CMD || getDefaultNpmCommand()
80
84
 
81
85
  const packageSpec = buildPackageSpec(parsed.branch)
82
86
  runCommand(npmCommand, ['install', '-g', packageSpec])
@@ -121,17 +121,17 @@ function removeCodexMarketplaceEntry(marketplaceFile) {
121
121
  return true;
122
122
  }
123
123
 
124
- function injectCodexRuntimeCarrier(filePath, bootstrapPath, settings) {
124
+ function injectCodexRuntimeCarrier(filePath, bootstrapPath, settings, options = {}) {
125
125
  const bootstrapContent = safeRead(bootstrapPath);
126
126
  if (!bootstrapContent) return false;
127
- injectMarkedContent(filePath, buildRuntimeCarrier(bootstrapContent, settings).trimEnd());
127
+ injectMarkedContent(filePath, buildRuntimeCarrier(bootstrapContent, settings, options).trimEnd());
128
128
  return true;
129
129
  }
130
130
 
131
- function writeCodexRuntimeCarrier(filePath, bootstrapPath, settings) {
131
+ function writeCodexRuntimeCarrier(filePath, bootstrapPath, settings, options = {}) {
132
132
  const bootstrapContent = safeRead(bootstrapPath);
133
133
  if (!bootstrapContent) return false;
134
- safeWrite(filePath, buildRuntimeCarrier(bootstrapContent, settings));
134
+ safeWrite(filePath, buildRuntimeCarrier(bootstrapContent, settings, options));
135
135
  return true;
136
136
  }
137
137
 
@@ -298,9 +298,10 @@ export function installCodexGlobal(home, pkgRoot) {
298
298
  join(pkgRoot, CODEX_RUNTIME_CARRIER),
299
299
  join(pkgRoot, 'bootstrap.md'),
300
300
  settings,
301
+ { profile: 'full' },
301
302
  );
302
303
  const homeCarrierPath = join(codexDir, CODEX_RUNTIME_CARRIER);
303
- injectCodexRuntimeCarrier(homeCarrierPath, join(pkgRoot, 'bootstrap.md'), settings);
304
+ injectCodexRuntimeCarrier(homeCarrierPath, join(pkgRoot, 'bootstrap.md'), settings, { profile: 'full' });
304
305
 
305
306
  ensureDir(join(home, '.agents', 'plugins'));
306
307
  updateCodexMarketplace(marketplaceFile);
@@ -34,6 +34,14 @@ export function ensureConfig(helloagentsHome, configFile, safeJson, ensureDir) {
34
34
  for (const [key, val] of Object.entries(DEFAULTS)) {
35
35
  if (!(key in reconciled)) reconciled[key] = val;
36
36
  }
37
+ if (!reconciled.host_install_modes || typeof reconciled.host_install_modes !== 'object' || Array.isArray(reconciled.host_install_modes)) {
38
+ reconciled.host_install_modes = {};
39
+ } else {
40
+ reconciled.host_install_modes = Object.fromEntries(
41
+ Object.entries(reconciled.host_install_modes)
42
+ .filter(([host, mode]) => ['claude', 'gemini', 'codex'].includes(host) && typeof mode === 'string' && mode),
43
+ );
44
+ }
37
45
  if (JSON.stringify(reconciled) !== JSON.stringify(existing)) {
38
46
  writeFileSync(configFile, JSON.stringify(reconciled, null, 2), 'utf-8');
39
47
  }
@@ -64,9 +64,9 @@ function readExpectedHooks(runtime, hooksFile, pathVar) {
64
64
  return pickManagedHooks(loadHooksWithCliEntry(runtime.pkgRoot, hooksFile, pathVar)?.hooks || {})
65
65
  }
66
66
 
67
- function readExpectedCarrierContent(runtime, fileName, settings) {
67
+ function readExpectedCarrierContent(runtime, fileName, settings, options = {}) {
68
68
  const bootstrap = safeRead(join(runtime.pkgRoot, fileName)) || ''
69
- return normalizeText(buildRuntimeCarrier(bootstrap, settings))
69
+ return normalizeText(buildRuntimeCarrier(bootstrap, settings, options))
70
70
  }
71
71
 
72
72
  function buildDoctorIssue(runtime, code, cn, en) {
@@ -168,7 +168,12 @@ function buildCodexChecks(runtime, settings, trackedMode, detectedMode) {
168
168
  checks: {
169
169
  carrierMarker: (safeRead(join(codexDir, 'AGENTS.md')) || '').includes('HELLOAGENTS_START'),
170
170
  carrierContentMatch: normalizeText((safeRead(join(codexDir, 'AGENTS.md')) || '').match(/<!-- HELLOAGENTS_START -->([\s\S]*?)<!-- HELLOAGENTS_END -->/)?.[1] || '')
171
- === readExpectedCarrierContent(runtime, expectedHomeCarrier, settings),
171
+ === readExpectedCarrierContent(
172
+ runtime,
173
+ expectedHomeCarrier,
174
+ settings,
175
+ expectedHomeCarrier === 'bootstrap.md' ? { profile: 'full' } : {},
176
+ ),
172
177
  homeLink: homeLinkTarget === (safeRealTarget(runtime.pkgRoot) || normalizePath(runtime.pkgRoot)),
173
178
  globalHomeLink: homeLinkTarget === runtimeRoot,
174
179
  modelInstructionsFile: !!modelInstructionsLine,
@@ -187,8 +192,8 @@ function buildCodexChecks(runtime, settings, trackedMode, detectedMode) {
187
192
  pluginCache: existsSync(pluginCacheRoot),
188
193
  pluginRootLink: pluginRootTarget === runtimeRoot,
189
194
  pluginCacheLink: pluginCacheTarget === runtimeRoot,
190
- pluginCarrierMatch: normalizeText(safeRead(join(pluginRoot, 'AGENTS.md')) || '') === readExpectedCarrierContent(runtime, 'bootstrap.md', settings),
191
- pluginCacheCarrierMatch: normalizeText(safeRead(join(pluginCacheRoot, 'AGENTS.md')) || '') === readExpectedCarrierContent(runtime, 'bootstrap.md', settings),
195
+ pluginCarrierMatch: normalizeText(safeRead(join(pluginRoot, 'AGENTS.md')) || '') === readExpectedCarrierContent(runtime, 'bootstrap.md', settings, { profile: 'full' }),
196
+ pluginCacheCarrierMatch: normalizeText(safeRead(join(pluginCacheRoot, 'AGENTS.md')) || '') === readExpectedCarrierContent(runtime, 'bootstrap.md', settings, { profile: 'full' }),
192
197
  marketplaceEntry: Array.isArray(marketplace.plugins) && marketplace.plugins.some((plugin) => plugin?.name === CODEX_PLUGIN_NAME),
193
198
  pluginEnabled: codexConfig.includes(CODEX_PLUGIN_CONFIG_HEADER) && codexConfig.includes('enabled = true'),
194
199
  globalNotifyPathMatch: codexConfig.includes(CODEX_MANAGED_NOTIFY_VALUE),
@@ -17,6 +17,22 @@ export function printDoctorText(runtime, report) {
17
17
  for (const [key, value] of Object.entries(entry.checks)) {
18
18
  console.log(` ${key}: ${value ? 'ok' : 'missing'}`)
19
19
  }
20
+ if (entry.nativeDoctor) {
21
+ console.log(` native_doctor.available: ${entry.nativeDoctor.available ? 'ok' : 'missing'}`)
22
+ if (entry.nativeDoctor.available) {
23
+ console.log(` native_doctor.ok: ${entry.nativeDoctor.ok ? 'ok' : 'missing'}`)
24
+ }
25
+ if (entry.nativeDoctor.summary) {
26
+ if (entry.nativeDoctor.summary.version) console.log(` native_doctor.version: ${entry.nativeDoctor.summary.version}`)
27
+ if (entry.nativeDoctor.summary.configPath) console.log(` native_doctor.config_path: ${entry.nativeDoctor.summary.configPath}`)
28
+ if (entry.nativeDoctor.summary.resolvedProvider) console.log(` native_doctor.resolved_provider: ${entry.nativeDoctor.summary.resolvedProvider}`)
29
+ if (entry.nativeDoctor.summary.resolvedModel) console.log(` native_doctor.resolved_model: ${entry.nativeDoctor.summary.resolvedModel}`)
30
+ if (entry.nativeDoctor.summary.sandboxAvailable !== null) console.log(` native_doctor.sandbox_available: ${entry.nativeDoctor.summary.sandboxAvailable}`)
31
+ console.log(` native_doctor.mcp_present: ${entry.nativeDoctor.summary.mcpPresent ? 'ok' : 'missing'}`)
32
+ console.log(` native_doctor.skills_selected: ${entry.nativeDoctor.summary.skillsSelected.join(', ') || '(none)'}`)
33
+ }
34
+ if (entry.nativeDoctor.output) console.log(` native_doctor.output: ${entry.nativeDoctor.output}`)
35
+ }
20
36
  for (const note of entry.notes) {
21
37
  console.log(` note: ${note}`)
22
38
  }
@@ -5,7 +5,6 @@ import { DEFAULTS } from './cli-config.mjs'
5
5
  import { inspectCodexDoctor as inspectCodexDoctorImpl } from './cli-doctor-codex.mjs'
6
6
  import { printDoctorText } from './cli-doctor-render.mjs'
7
7
  import { buildRuntimeCarrier } from './cli-runtime-carrier.mjs'
8
- import { readTopLevelTomlLine } from './cli-toml.mjs'
9
8
  import { loadHooksWithCliEntry, safeJson, safeRead } from './cli-utils.mjs'
10
9
 
11
10
  const runtime = {
@@ -78,9 +77,9 @@ function managedHooksMatch(actualHooks, expectedHooks) {
78
77
  return stringifySorted(pickManagedHooks(actualHooks || {})) === stringifySorted(expectedHooks || {})
79
78
  }
80
79
 
81
- function readExpectedCarrierContent(fileName, settings) {
80
+ function readExpectedCarrierContent(fileName, settings, options = {}) {
82
81
  const bootstrap = safeRead(join(runtime.pkgRoot, fileName)) || ''
83
- return normalizeText(buildRuntimeCarrier(bootstrap, settings))
82
+ return normalizeText(buildRuntimeCarrier(bootstrap, settings, options))
84
83
  }
85
84
 
86
85
  function buildDoctorIssue(code, cn, en) {
@@ -1,6 +1,11 @@
1
1
  import { spawnSync } from 'node:child_process'
2
2
 
3
- import { installClaudeStandby, installGeminiStandby, uninstallClaudeStandby, uninstallGeminiStandby } from './cli-hosts.mjs'
3
+ import {
4
+ installClaudeStandby,
5
+ installGeminiStandby,
6
+ uninstallClaudeStandby,
7
+ uninstallGeminiStandby,
8
+ } from './cli-hosts.mjs'
4
9
  import {
5
10
  cleanupCodexGlobalResidueForStandby,
6
11
  installCodexGlobal,
@@ -28,14 +28,28 @@ export function initCliLifecycle(options) {
28
28
  Object.assign(runtime, options)
29
29
  }
30
30
 
31
+ function sanitizeSettings(settings = {}) {
32
+ const next = settings && typeof settings === 'object' ? { ...settings } : {}
33
+ const tracked = next.host_install_modes
34
+ if (!tracked || typeof tracked !== 'object' || Array.isArray(tracked)) {
35
+ next.host_install_modes = {}
36
+ return next
37
+ }
38
+ next.host_install_modes = Object.fromEntries(
39
+ Object.entries(tracked).filter(([host, mode]) => HOSTS.includes(host) && typeof mode === 'string' && mode),
40
+ )
41
+ return next
42
+ }
43
+
31
44
  export function readSettings(shouldEnsure = false) {
32
45
  if (shouldEnsure) ensureConfig(runtime.helloagentsHome, runtime.configFile, safeJson, ensureDir)
33
- return safeJson(runtime.configFile) || {}
46
+ return sanitizeSettings(safeJson(runtime.configFile) || {})
34
47
  }
35
48
 
36
49
  function writeSettings(settings) {
50
+ const sanitized = sanitizeSettings(settings)
37
51
  ensureDir(runtime.helloagentsHome)
38
- writeFileSync(runtime.configFile, JSON.stringify(settings, null, 2), 'utf-8')
52
+ writeFileSync(runtime.configFile, JSON.stringify(sanitized, null, 2), 'utf-8')
39
53
  }
40
54
 
41
55
  function hasTrackedHostModes(settings) {
@@ -65,18 +65,18 @@ function renderInstallMessage(context, mode, state) {
65
65
 
66
66
  if (install) {
67
67
  return msg(
68
- `\n ✅ HelloAGENTS 已安装(standby 模式)!\n\n Claude Code: 已自动配置(~/.claude/CLAUDE.md + hooks)\n Gemini CLI: 已自动配置(~/.gemini/GEMINI.md)\n Codex: ${codexStandbyStatus(context)}\n\n ${restartHint(msg)}\n\n standby 模式下,hello-* 技能不会自动触发。\n 在项目中使用 ~wiki 仅创建/同步知识库,或用 ~init 完整初始化项目;也可用 ~command 按需调用。\n\n 切换模式:\n helloagents --global 全局模式(自动尝试 Claude/Gemini 插件或扩展;Codex 自动装原生本地插件)`,
69
- `\n ✅ HelloAGENTS installed (standby mode)!\n\n Claude Code: Auto-configured (~/.claude/CLAUDE.md + hooks)\n Gemini CLI: Auto-configured (~/.gemini/GEMINI.md)\n Codex: ${codexStandbyStatus(context)}\n\n ${restartHint(msg)}\n\n In standby mode, hello-* skills won't auto-trigger.\n Use ~wiki to create or sync the KB only, or ~init for the full project setup; ~command stays available on demand.\n\n Switch modes:\n helloagents --global Global mode (auto-attempts Claude/Gemini plugins or extensions; native local plugin auto-install for Codex)`,
68
+ `\n ✅ HelloAGENTS 已安装(standby 模式)!\n\n Claude Code: 已自动配置(~/.claude/CLAUDE.md + hooks)\n Gemini CLI: 已自动配置(~/.gemini/GEMINI.md)\n Codex: ${codexStandbyStatus(context)}\n\n ${restartHint(msg)}\n\n standby 模式下,hello-* 技能不会自动触发。\n 在项目中使用 ~wiki ~init 仅创建/同步知识库;用 ~global 初始化项目级全局模式;也可用 ~command 按需调用。\n\n 切换模式:\n helloagents --global 项目级全局模式(自动尝试 Claude/Gemini 插件或扩展;Codex 自动装原生本地插件)`,
69
+ `\n ✅ HelloAGENTS installed (standby mode)!\n\n Claude Code: Auto-configured (~/.claude/CLAUDE.md + hooks)\n Gemini CLI: Auto-configured (~/.gemini/GEMINI.md)\n Codex: ${codexStandbyStatus(context)}\n\n ${restartHint(msg)}\n\n In standby mode, hello-* skills won't auto-trigger.\n Use ~wiki or ~init to create or sync the KB only; use ~global to initialize project-level global mode; ~command stays available on demand.\n\n Switch modes:\n helloagents --global Project-level global mode (auto-attempts Claude/Gemini plugins or extensions; native local plugin auto-install for Codex)`,
70
70
  )
71
71
  }
72
72
 
73
73
  return msg(
74
74
  refresh
75
75
  ? ` standby 模式已刷新,CLI 注入与链接已同步最新文件。\n ${restartHint(msg)}\n ${removeHint(msg)}`
76
- : ` 项目可通过 ~wiki 创建/同步知识库,或通过 ~init 完整初始化;未激活项目仅注入通用规则。\n ${restartHint(msg)}\n ${removeHint(msg)}`,
76
+ : ` 项目可通过 ~wiki ~init 创建/同步知识库;用 ~global 初始化项目级全局模式;未初始化时仅注入轻量规则。\n ${restartHint(msg)}\n ${removeHint(msg)}`,
77
77
  refresh
78
78
  ? ` Standby mode refreshed; injected files and links were synchronized.\n ${restartHint(msg)}\n ${removeHint(msg)}`
79
- : ` Projects can use ~wiki for KB-only activation or ~init for the full project setup. Unactivated projects get lite rules only.\n ${restartHint(msg)}\n ${removeHint(msg)}`,
79
+ : ` Projects can use ~wiki or ~init to create/sync the KB; use ~global to initialize project-level global mode. Projects that are not initialized get lite rules only.\n ${restartHint(msg)}\n ${removeHint(msg)}`,
80
80
  )
81
81
  }
82
82
 
@@ -84,17 +84,18 @@ function renderHelp({ pkgVersion, msg }) {
84
84
  return `
85
85
  HelloAGENTS v${pkgVersion} — The orchestration kernel for AI CLIs
86
86
 
87
- ${msg('安装', 'Install')}:
87
+ ${msg('安装', 'Install')}:
88
88
  npm install -g helloagents ${msg('(安装命令并同步稳定运行根目录;CLI 部署需显式执行 helloagents install ...)', '(installs the command and syncs the stable runtime root; deploy to CLIs explicitly with helloagents install ...)')}
89
89
  HELLOAGENTS=codex:global npm install -g helloagents
90
90
  helloagents-js ${msg('(受管宿主配置的跨平台稳定入口)', '(cross-platform stable entrypoint for managed host configs)')}
91
91
 
92
92
  ${msg('模式切换', 'Mode switching')}:
93
- helloagents --global ${msg('全局模式(自动尝试 Claude/Gemini 插件或扩展;Codex 自动装原生本地插件)', 'Global mode (auto-attempts Claude/Gemini plugins or extensions; native local plugin auto-install for Codex)')}
93
+ helloagents --global ${msg('项目级全局模式(自动尝试 Claude/Gemini 插件或扩展;Codex 自动装原生本地插件)', 'Project-level global mode (auto-attempts Claude/Gemini plugins or extensions; native local plugin auto-install for Codex)')}
94
94
  helloagents --standby ${msg('标准模式(非插件安装,hello-* 不自动触发,默认)', "Standby mode (non-plugin install, hello-* won't auto-trigger, default)")}
95
95
 
96
96
  ${msg('单 CLI 管理', 'Scoped CLI management')}:
97
97
  helloagents install codex --standby
98
+ helloagents install gemini --standby
98
99
  helloagents install --all --global
99
100
  helloagents update codex
100
101
  helloagents cleanup claude --global
@@ -104,7 +105,7 @@ ${msg('单 CLI 管理', 'Scoped CLI management')}:
104
105
  ${msg('分支切换', 'Branch switching')}:
105
106
  helloagents switch-branch beta
106
107
  helloagents switch-branch beta claude --global
107
- helloagents branch github:hellowind777/helloagents#beta --all --standby
108
+ helloagents branch beta --all --standby
108
109
  ${msg('先通过 npm 安装指定 ref,再通过 npm 脚本同步宿主 CLI', 'Installs the requested ref with npm first, then syncs host CLIs through npm scripts')}
109
110
 
110
111
  ${msg('诊断', 'Diagnostics')}:
@@ -1,15 +1,15 @@
1
1
  import { join } from 'node:path'
2
2
 
3
- import { safeJson } from './cli-utils.mjs'
3
+ import { safeJson, withCarrierProfile } from './cli-utils.mjs'
4
4
 
5
5
  export function readCarrierSettings(home) {
6
6
  return safeJson(join(home, '.helloagents', 'helloagents.json')) || {}
7
7
  }
8
8
 
9
- export function buildRuntimeCarrier(bootstrapContent, settings = {}) {
9
+ export function buildRuntimeCarrier(bootstrapContent, settings = {}, options = {}) {
10
10
  void settings
11
11
  const normalized = String(bootstrapContent || '').trim()
12
12
  if (!normalized) return ''
13
13
 
14
- return `${normalized}\n`
14
+ return withCarrierProfile(normalized, options.profile || '')
15
15
  }
@@ -54,8 +54,17 @@ export function removeLink(p) {
54
54
 
55
55
  const MARKER = '<!-- HELLOAGENTS_START -->';
56
56
  const MARKER_END = '<!-- HELLOAGENTS_END -->';
57
+ export const FULL_CARRIER_PROFILE_MARKER = '<!-- HELLOAGENTS_PROFILE: full -->';
57
58
  const MARKER_RE = new RegExp(`\\n*${MARKER}[\\s\\S]*?${MARKER_END}\\n*`, 'g');
58
59
 
60
+ export function withCarrierProfile(content, profile = '') {
61
+ const normalized = String(content || '').trim();
62
+ if (!normalized) return '';
63
+ if (profile !== 'full') return `${normalized}\n`;
64
+ if (normalized.includes(FULL_CARRIER_PROFILE_MARKER)) return `${normalized}\n`;
65
+ return `${FULL_CARRIER_PROFILE_MARKER}\n${normalized}\n`;
66
+ }
67
+
59
68
  /** Inject content wrapped in markers, preserving existing content outside markers. */
60
69
  export function injectMarkedContent(filePath, content) {
61
70
  const existing = safeRead(filePath) || '';
package/scripts/guard.mjs CHANGED
@@ -133,7 +133,7 @@ function buildPostWriteWarnings(data) {
133
133
  const filePath = data.tool_input?.file_path || ''
134
134
  return [
135
135
  ...(detectIdeaBoundaryContext(data)?.zeroSideEffect
136
- ? ['~idea 本轮要求只读探索;检测到写入文件的工具调用,请回到探索输出,或升级到 ~plan / ~build / ~prd / ~auto 后再修改文件']
136
+ ? ['~idea 当前任务要求只读探索;检测到写入文件的工具调用,请回到探索输出,或升级到 ~plan / ~build / ~prd / ~auto 后再修改文件']
137
137
  : []),
138
138
  ...scanUnrequestedFiles(filePath, data.tool_name),
139
139
  ...(content ? [...scanForSecrets(content), ...scanDangerousPackages(content, filePath)] : []),
@@ -34,7 +34,7 @@ function buildReadRootBlock(readRoot) {
34
34
  turnStateCommand: 'helloagents-turn-state write --kind complete --role main',
35
35
  turnStateUsage: '仅在运行时需要识别完成、等待或阻塞时调用;普通问答不调用',
36
36
  };
37
- return `## 本轮 HelloAGENTS 读取根目录\n\`\`\`json\n${JSON.stringify(block, null, 2)}\n\`\`\``;
37
+ return `## 当前对话 HelloAGENTS 读取根目录\n\`\`\`json\n${JSON.stringify(block, null, 2)}\n\`\`\``;
38
38
  }
39
39
 
40
40
  export function resolveCanonicalCommandSkill(skillName) {
@@ -1,4 +1,4 @@
1
- import { isProjectRuntimeActive } from './runtime-scope.mjs'
1
+ import { hasProjectFullCarrier } from './runtime-scope.mjs'
2
2
 
3
3
  export function resolveRuntimeInstallMode(settings = {}, host = '') {
4
4
  if (!settings || typeof settings !== 'object') return 'standby'
@@ -13,8 +13,7 @@ export function resolveBootstrapFile(cwd, settings = {}, host = '') {
13
13
  const installMode = typeof settings === 'string'
14
14
  ? settings
15
15
  : resolveRuntimeInstallMode(settings, host)
16
- const isActivated = isProjectRuntimeActive(cwd)
17
- return (installMode === 'global' || isActivated) ? 'bootstrap.md' : 'bootstrap-lite.md'
16
+ return (installMode === 'global' || hasProjectFullCarrier(cwd, host)) ? 'bootstrap.md' : 'bootstrap-lite.md'
18
17
  }
19
18
 
20
19
  function shouldBypassRoute(prompt) {
@@ -23,7 +22,7 @@ function shouldBypassRoute(prompt) {
23
22
 
24
23
  function buildHelpExtraRules(skillName) {
25
24
  if (skillName !== 'help') return ''
26
- return ' 这是 HelloAGENTS 的帮助命令,不是宿主 CLI 的内置帮助。仅显示 HelloAGENTS 的帮助和当前设置;优先使用当前会话上下文中已注入的“当前用户设置”、配置文件原始 JSON 或此前读取结果摘要,上下文不存在或缺少要展示的配置项时才读取一次 ~/.helloagents/helloagents.json;自动激活技能说明仅在全局模式或已激活项目中生效。不要调用宿主 CLI 的帮助工具(如 cli_help 或 /help),不要使用子代理,不要读取项目文件;若受工作区限制无法读取配置,必须明确说明并按已知默认值或已注入设置展示。'
25
+ return ' 这是 HelloAGENTS 的帮助命令,不是宿主 CLI 的内置帮助。仅显示 HelloAGENTS 的帮助和当前设置;优先使用当前会话上下文中已注入的“当前用户设置”、配置文件原始 JSON 或此前读取结果摘要,上下文不存在或缺少要展示的配置项时才读取一次 ~/.helloagents/helloagents.json;自动激活技能说明仅在全局模式或已初始化项目时生效。不要调用宿主 CLI 的帮助工具(如 cli_help 或 /help),不要使用子代理,不要读取项目文件;若受工作区限制无法读取配置,必须明确说明并按已知默认值或已注入设置展示。'
27
26
  }
28
27
 
29
28
  function routeExplicitCommand({
@@ -391,6 +391,7 @@ function cmdInject() {
391
391
  const cwd = payload.cwd || process.cwd();
392
392
  const settings = getSettings();
393
393
  const bootstrapFile = resolveBootstrapFile(cwd, settings, HOST);
394
+ const shouldEnsureProjectLocal = bootstrapFile === 'bootstrap.md' || source === 'resume' || source === 'compact';
394
395
 
395
396
  startReplaySession(cwd, {
396
397
  host: HOST,
@@ -398,6 +399,7 @@ function cmdInject() {
398
399
  bootstrapFile,
399
400
  installMode: settings.install_mode || '',
400
401
  payload,
402
+ ensureProjectLocal: shouldEnsureProjectLocal,
401
403
  });
402
404
  if (!IS_SILENT) {
403
405
  appendReplayEvent(cwd, {
@@ -413,7 +415,10 @@ function cmdInject() {
413
415
  });
414
416
  }
415
417
  clearRouteContext({ cwd, payload });
416
- clearTurnState(cwd, { payload });
418
+ clearTurnState(cwd, {
419
+ payload,
420
+ ensureProjectLocal: shouldEnsureProjectLocal,
421
+ });
417
422
  cleanupProjectSessions(cwd, {
418
423
  minIntervalMs: IS_SILENT ? PROJECT_SESSION_CLEANUP_COOLDOWN_MS : 0,
419
424
  });
@@ -250,7 +250,7 @@ export function buildProjectStorageHint(cwd, options = {}) {
250
250
  hints.push(`当前宿主未提供稳定会话标识,因此使用工作区默认位置 \`${summary.stateSessionToken}\``)
251
251
  }
252
252
  if (summary.usesSharedStore) {
253
- hints.push(`项目存储:\`project_store_mode=repo-shared\`;本地激活/会话运行态目录仍是 \`${summary.promptActivationDir}\`,知识库/方案目录改为 \`${summary.promptStoreDir}\``)
253
+ hints.push(`项目存储:\`project_store_mode=repo-shared\`;项目本地存储/会话运行态目录仍是 \`${summary.promptActivationDir}\`,知识库/方案目录改为 \`${summary.promptStoreDir}\``)
254
254
  }
255
255
  return hints.join('。') + (hints.length > 0 ? '。' : '')
256
256
  }
@@ -263,7 +263,7 @@ export function buildProjectStorageBlock(cwd, options = {}) {
263
263
 
264
264
  const details = {
265
265
  project_store_mode: summary.projectStoreMode,
266
- activation_dir: summary.promptActivationDir,
266
+ project_local_dir: summary.promptActivationDir,
267
267
  state_scope: summary.stateScope,
268
268
  state_path: summary.promptStatePath,
269
269
  state_workspace: summary.stateWorkspace,
@@ -281,9 +281,9 @@ export function buildProjectStorageBlock(cwd, options = {}) {
281
281
  explanations.push('说明:当前宿主未提供稳定会话标识,因此使用工作区默认位置。')
282
282
  }
283
283
  if (summary.usesSharedStore) {
284
- explanations.push('说明:状态文件与会话产物写本地激活目录;`context.md`、`guidelines.md`、`DESIGN.md`、`verify.yaml`、`modules/`、`plans/`、`archive/` 写知识库/方案目录。')
284
+ explanations.push('说明:状态文件与会话产物写项目本地存储目录;`context.md`、`guidelines.md`、`DESIGN.md`、`verify.yaml`、`modules/`、`plans/`、`archive/` 写知识库/方案目录。')
285
285
  } else {
286
- explanations.push('说明:当前使用项目本地 `.helloagents/` 作为激活目录、知识库目录和方案目录。')
286
+ explanations.push('说明:当前使用项目本地 `.helloagents/` 作为知识、方案、状态和运行态目录。')
287
287
  }
288
288
 
289
289
  return [