helloagents 3.0.38 → 3.1.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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "helloagents",
3
- "version": "3.0.38",
3
+ "version": "3.1.1",
4
4
  "description": "HelloAGENTS — The orchestration kernel that makes any AI CLI smarter. Adds intelligent routing, unified QA gates, safety guards, and notifications.",
5
5
  "author": {
6
6
  "name": "HelloWind",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "helloagents",
3
- "version": "3.0.38",
3
+ "version": "3.1.1",
4
4
  "description": "HelloAGENTS — Quality-driven orchestration kernel for AI CLIs with intelligent routing, unified QA gates, safety guards, and notifications.",
5
5
  "author": {
6
6
  "name": "HelloWind",
package/README.md CHANGED
@@ -8,7 +8,7 @@
8
8
 
9
9
  **A workflow layer for AI coding CLIs: skills, project knowledge, delivery checks, safer config writes, and resumable execution.**
10
10
 
11
- [![Version](https://img.shields.io/badge/version-3.0.38-orange.svg)](./package.json)
11
+ [![Version](https://img.shields.io/badge/version-3.1.1-orange.svg)](./package.json)
12
12
  [![npm](https://img.shields.io/npm/v/helloagents.svg)](https://www.npmjs.com/package/helloagents)
13
13
  [![Node](https://img.shields.io/badge/node-%3E%3D18-339933.svg)](./package.json)
14
14
  [![Skills](https://img.shields.io/badge/skills-14-6366f1.svg)](./skills)
@@ -189,7 +189,7 @@ HelloAGENTS now resolves the current state file from `state_path`:
189
189
 
190
190
  `<workspace>` is the current Git branch, `detached-<sha>` for a detached HEAD, or `workspace` for non-Git projects. `<session>` is the current project-local session token. `.helloagents/sessions/active.json` only keeps the latest active workspace/session mapping plus alias bridges, so the same CLI session stays in one directory and `/resume` can reuse it.
191
191
 
192
- For project-local sessions, HelloAGENTS first uses stable host identifiers such as `sessionId`, `conversationId`, `threadId`, or `HELLOAGENTS_NOTIFY_SESSION_ID`. If the host only exposes a window or terminal id such as `WT_SESSION`, `TERM_SESSION_ID`, or `WINDOWID`, HelloAGENTS uses it only as a lightweight alias bridge and reuses the mapped session first instead of fanning out duplicate directories.
192
+ For project-local sessions, HelloAGENTS first uses stable host identifiers such as `sessionId`, `conversationId`, `threadId`, or `HELLOAGENTS_NOTIFY_SESSION_ID`. If the host only exposes a window or terminal id such as `WT_SESSION`, `TERM_SESSION_ID`, or `WINDOWID`, HelloAGENTS uses it only as a lightweight alias bridge and reuses the mapped session first instead of fanning out duplicate directories. If a session starts before a stable host identifier is available, HelloAGENTS can begin in `default` and keep reusing that same active directory after the same CLI session later exposes a stable identifier, instead of splitting into a second session directory.
193
193
 
194
194
  `STATE.md` records where the current workflow stopped. It is not a universal memory file for every conversation. Codex `/goal` does not replace `state_path`, `turn-state`, or local evidence files; it only handles long-running continuation on the Codex side.
195
195
 
@@ -210,7 +210,7 @@ Runtime state now stays intentionally small:
210
210
  - `~/.codex/.helloagents/notify-state.json` for Codex-native closeout de-duplication only
211
211
 
212
212
  `STATE.md` only keeps the human-readable recovery snapshot. `runtime.json` is machine-only and keeps the minimal runtime state. `artifacts/*.json` stays limited to structured receipts. `events.jsonl` remains opt-in trace output and stays off by default.
213
- Project-local `STATE.md` is now materialized more lazily, and legacy root-level `.helloagents/artifacts/*.log` files are cleaned up automatically instead of growing as a second history system.
213
+ Project-local `STATE.md` is now materialized more lazily.
214
214
 
215
215
  Standard runtime evidence and transient runtime state now expire after 72 hours. Long-running Codex goal flows still keep their 720-hour upper bound where the workflow explicitly needs it.
216
216
 
@@ -225,8 +225,10 @@ The CLI manages host files explicitly:
225
225
  - `update` refreshes the selected target or all targets
226
226
  - `cleanup` removes managed injections and links
227
227
  - `uninstall` performs scoped cleanup before package removal
228
- - `doctor` reports drift in carriers, links, hooks, config entries, plugin roots, cache copies, and versions; for Codex, it also surfaces native `codex doctor` output when available
228
+ - `doctor` reports drift in carriers, links, hooks, config entries, plugin roots, cache copies, versions, and real Claude/Gemini global install artifacts; for Codex, it also surfaces native `codex doctor` output when available
229
+ - Codex managed `notify = ["helloagents-js", "codex-notify"]` stays portable, and `doctor`, `cleanup`, and `uninstall` also recognize wrapped `--previous-notify` chains used by Codex App / Computer Use
229
230
  - per-host mode tracking is written only after host setup succeeds, and failed native global cleanup keeps the host tracked as `global` instead of silently layering standby on top
231
+ - Windows `.cmd` / `.bat` lifecycle calls now run through an explicit command wrapper, so host installs, branch switching, and doctor flows do not emit Node `DEP0190` shell deprecation warnings
230
232
 
231
233
  ## Quick Start
232
234
 
@@ -313,7 +315,7 @@ If you omit `--standby` or `--global`, HelloAGENTS first reuses the tracked/dete
313
315
 
314
316
  Use these when you do not want to depend on the `helloagents` binary being available during package updates. In `HELLOAGENTS=target[:mode]`, target can be `all`, `claude`, `gemini`, or `codex`; mode can be `standby` or `global`. For install, an omitted mode is treated as `standby`. For update, cleanup, uninstall, and branch switching, an omitted mode is forwarded unchanged so HelloAGENTS can reuse the tracked or detected mode for that CLI first. If you do not provide `HELLOAGENTS`, the one-shot install scripts now behave like plain package install: they install or update the package only and do not auto-deploy any host CLI. For a custom tarball or package spec, set `HELLOAGENTS_PACKAGE` instead of `HELLOAGENTS_BRANCH`. For a guaranteed refresh of an already installed package, prefer `npm explore -g helloagents -- npm run sync-hosts -- ...` after the package command.
315
317
 
316
- Host configs use the stable `helloagents-js` entrypoint and runtime root `~/.helloagents/helloagents`, so Node global package paths can change without breaking managed hooks or Codex `notify`. Codex hooks use standalone `~/.codex/hooks.json` instead of adding large hook blocks to `config.toml`, and Codex global plugin roots plus plugin cache now link back to that same stable runtime root.
318
+ Host configs use the stable `helloagents-js` entrypoint and runtime root `~/.helloagents/helloagents`, so Node global package paths can change without breaking managed hooks or Codex `notify`. Codex hooks use standalone `~/.codex/hooks.json` instead of adding large hook blocks to `config.toml`, and Codex global plugin roots plus plugin cache now link back to that same stable runtime root. Claude Code global installs now use a dedicated local marketplace projection under `~/.helloagents/host-projections/claude-marketplace`, and Gemini global extension packaging uses `~/.helloagents/host-projections/gemini`, so host-specific packaging stays isolated from the shared runtime root.
317
319
 
318
320
  #### npm commands
319
321
 
@@ -445,16 +447,16 @@ npm uninstall -g helloagents
445
447
 
446
448
  | CLI | Install method | Files involved |
447
449
  |-----|----------------|----------------|
448
- | Claude Code | native plugin install | managed by Claude Code plugin system |
449
- | Gemini CLI | native extension install | managed by Gemini extension system |
450
+ | Claude Code | native plugin install | `~/.helloagents/host-projections/claude-marketplace`, Claude Code plugin metadata/cache managed by the host |
451
+ | Gemini CLI | native extension install | `~/.helloagents/host-projections/gemini`, `~/.gemini/extensions/helloagents` |
450
452
  | Codex CLI | native local-plugin chain | `~/.agents/plugins/marketplace.json`, `~/plugins/helloagents/ -> ~/.helloagents/helloagents`, `~/.codex/plugins/cache/local-plugins/helloagents/local/ -> ~/.helloagents/helloagents`, `~/.codex/config.toml`, `~/.codex/hooks.json`, `~/.codex/helloagents -> ~/.helloagents/helloagents` |
451
453
 
452
- In global mode, HelloAGENTS now attempts the host-native install commands automatically. For Claude Code, the marketplace should be added from the Git URL so the plugin source stays on HTTPS and avoids an SSH-only clone during installation. If a host command is unavailable, run the same commands manually:
454
+ In global mode, HelloAGENTS now attempts the host-native install commands automatically. Claude Code uses the local marketplace projection, Gemini uses the local extension projection, and Codex keeps linking back to the same stable runtime root, so install, update, branch switching, mode switching, cleanup, and uninstall all refresh against one consistent runtime copy. If a host command is unavailable, run the same commands manually:
453
455
 
454
456
  ```text
455
- /plugin marketplace add https://github.com/hellowind777/helloagents.git
457
+ /plugin marketplace add "~/.helloagents/host-projections/claude-marketplace"
456
458
  /plugin install helloagents@helloagents
457
- helloagents install gemini --global
459
+ gemini extensions link "~/.helloagents/host-projections/gemini"
458
460
  ```
459
461
 
460
462
  For Claude Code, the CLI also tries the equivalent `claude plugin marketplace add ...` and `claude plugin install ...` commands. The marketplace is named `helloagents`, and the plugin is also named `helloagents`, so the install target is `helloagents@helloagents`. Restart the host CLI after a global install.
@@ -652,15 +654,16 @@ Codex is rules-file driven by default.
652
654
 
653
655
  - standby writes `~/.codex/AGENTS.md`
654
656
  - standby writes a portable managed `model_instructions_file = "~/.codex/AGENTS.md"`
655
- - standby writes a managed `notify = ["helloagents-js", "codex-notify"]` command for closeout notification
657
+ - standby writes a managed and portable `notify = ["helloagents-js", "codex-notify"]` command for closeout notification, so reinstalling, updating, or moving to another machine does not require rewriting an absolute path
656
658
  - standby writes silent Codex hooks to `~/.codex/hooks.json`
657
659
  - Codex `SessionStart` stays silent and reads the current `~/.helloagents/helloagents.json` at runtime instead of baking a config snapshot into `config.toml`, so first-turn and post-compaction settings stay current
658
660
  - install and update also sync HelloAGENTS-managed Codex hook trust state in `~/.codex/config.toml`, so Codex 0.129.0+ does not re-prompt for the managed hooks
659
661
  - that hook trust state is machine-local generated metadata derived from the current absolute `~/.codex/hooks.json` path; unlike `model_instructions_file = "~/.codex/AGENTS.md"`, it is not portable config and should be regenerated on each machine
660
662
  - standby creates `~/.codex/helloagents -> ~/.helloagents/helloagents`
661
663
  - global mode installs the native local-plugin chain, but keeps `~/.helloagents/helloagents` as the single managed runtime source by linking plugin roots, plugin cache, and `~/.codex/helloagents` back to it
664
+ - `doctor`, `cleanup`, and `uninstall` also recognize wrapped notify chains such as `--previous-notify ["helloagents-js", "codex-notify"]`, so Codex App / Computer Use wrappers do not cause false drift reports or break notify restoration
662
665
  - for Codex app/plugin discovery, `global` is the native path; `standby` remains the lighter default for explicit project work
663
- - cleanup removes only the HelloAGENTS-managed hook trust entries and legacy managed notify residues, while keeping user-owned hook state untouched
666
+ - cleanup removes only the HelloAGENTS-managed hook trust entries, while keeping user-owned hook state untouched
664
667
  - Codex hooks only synchronize runtime state and enforce Stop gates; they do not inject HelloAGENTS rules or route text through hook output
665
668
  - Codex closeout de-duplicates Stop hooks and native `codex-notify`, so one turn does not notify twice, and clientless delegated child-completion events stay silent when the managed Stop hook is active
666
669
  - `/goal` remains Codex-native. Enable it explicitly with `helloagents codex goals enable` when long-running plan execution is needed
@@ -678,10 +681,11 @@ npm test
678
681
  The current suite covers:
679
682
 
680
683
  - install, update, cleanup, uninstall, branch switching, and mode switching
684
+ - Windows `.cmd` / `.bat` lifecycle dispatch without Node `DEP0190` warnings
681
685
  - one-shot shell and PowerShell lifecycle dispatch, plus wrapper env cleanup and mode-routing rules for install, update, cleanup, uninstall, and branch switching
682
686
  - Claude, Gemini, and Codex host integration behavior, including global-to-standby cleanup and failed native cleanup tracking
683
687
  - Codex managed `model_instructions_file`, `notify`, `hooks.json`, hook trust state, local plugin, marketplace, and cache behavior
684
- - Codex cleanup of legacy managed notify variants on Windows and canonical managed notify restoration rules
688
+ - Codex cleanup and canonical managed notify restoration rules, including wrapped `--previous-notify` chains
685
689
  - Codex `/goal` feature toggles, long-running route context, and goal-aware command contracts
686
690
  - `helloagents doctor`
687
691
  - project storage and `repo-shared` behavior
package/README_CN.md CHANGED
@@ -8,7 +8,7 @@
8
8
 
9
9
  **面向 AI 编码 CLI 的工作流层:技能、知识库、交付检查、更安全的配置写入,以及可恢复的执行流程。**
10
10
 
11
- [![Version](https://img.shields.io/badge/version-3.0.38-orange.svg)](./package.json)
11
+ [![Version](https://img.shields.io/badge/version-3.1.1-orange.svg)](./package.json)
12
12
  [![npm](https://img.shields.io/npm/v/helloagents.svg)](https://www.npmjs.com/package/helloagents)
13
13
  [![Node](https://img.shields.io/badge/node-%3E%3D18-339933.svg)](./package.json)
14
14
  [![Skills](https://img.shields.io/badge/skills-14-6366f1.svg)](./skills)
@@ -189,7 +189,7 @@ HelloAGENTS 现在只从 `state_path` 解析当前状态文件:
189
189
 
190
190
  `<workspace>` 是当前 Git 分支、detached HEAD 的 `detached-<sha>`,或非 Git 项目的 `workspace`。`<session>` 是当前项目本地会话标识。`.helloagents/sessions/active.json` 只保留最近一次活跃的工作区/会话映射和 alias 桥接,这样同一个 CLI 会话会稳定落在同一个目录里,`/resume` 也能复用它。
191
191
 
192
- 对于项目本地会话目录,HelloAGENTS 会优先使用稳定宿主标识,如 `sessionId`、`conversationId`、`threadId` 或 `HELLOAGENTS_NOTIFY_SESSION_ID`。如果宿主只能提供 `WT_SESSION`、`TERM_SESSION_ID`、`WINDOWID` 这类窗口或终端标识,HelloAGENTS 只把它们当作轻量 alias 桥接,并优先复用已映射的会话目录,而不是继续分裂出重复目录。
192
+ 对于项目本地会话目录,HelloAGENTS 会优先使用稳定宿主标识,如 `sessionId`、`conversationId`、`threadId` 或 `HELLOAGENTS_NOTIFY_SESSION_ID`。如果宿主只能提供 `WT_SESSION`、`TERM_SESSION_ID`、`WINDOWID` 这类窗口或终端标识,HelloAGENTS 只把它们当作轻量 alias 桥接,并优先复用已映射的会话目录,而不是继续分裂出重复目录。如果一个会话启动时还拿不到稳定宿主标识,HelloAGENTS 可以先落到 `default`,等同一个 CLI 会话后续拿到稳定标识时,仍继续复用这个活动目录,而不是再拆出第二个会话目录。
193
193
 
194
194
  `STATE.md` 只记录当前工作流做到哪里,不承担所有对话的统一记忆。Codex `/goal` 也不替代 `state_path`、`turn-state` 或本地证据文件;它只负责 Codex 侧的长程续跑。
195
195
 
@@ -210,7 +210,7 @@ HelloAGENTS 不把“命令通过”和“任务完成”简单画等号。交
210
210
  - 仅用于 Codex 原生收尾去重的 `~/.codex/.helloagents/notify-state.json`
211
211
 
212
212
  `STATE.md` 只保留给人看的恢复快照。`runtime.json` 只给机器用,只保存极少量运行态。`artifacts/*.json` 只保留结构化收据。`events.jsonl` 仍是可选 trace 输出,默认不写。
213
- 项目本地 `STATE.md` 现在会更晚创建;旧版残留的项目根 `.helloagents/artifacts/*.log` 也会自动清理,不再继续充当第二套历史系统。
213
+ 项目本地 `STATE.md` 现在会更晚创建。
214
214
 
215
215
  标准运行态证据和临时运行态现在默认 72 小时过期。只有工作流明确需要的长程 Codex goal 链路,才继续保留 720 小时上限。
216
216
 
@@ -225,8 +225,10 @@ CLI 显式管理宿主文件:
225
225
  - `update` 刷新指定目标或全部目标
226
226
  - `cleanup` 删除受管注入和链接
227
227
  - `uninstall` 在移除包前执行对应清理
228
- - `doctor` 检查规则文件、链接、hooks、配置项、插件根目录、缓存副本和版本漂移;对 Codex 还会在可用时附带原生 `codex doctor` 结果
228
+ - `doctor` 检查规则文件、链接、hooks、配置项、插件根目录、缓存副本、版本漂移,以及 Claude / Gemini 是否真的装上了全局插件或扩展;对 Codex 还会在可用时附带原生 `codex doctor` 结果
229
+ - Codex 受管 `notify = ["helloagents-js", "codex-notify"]` 会继续保持可移植;`doctor`、`cleanup` 和 `uninstall` 也能识别 Codex App / Computer Use 使用的 `--previous-notify` 包装链
229
230
  - 单 CLI 模式记录只会在宿主安装成功后写入;如果原生全局清理失败,也会继续保留 `global` 记录,而不是悄悄叠加 standby
231
+ - Windows 下的 `.cmd` / `.bat` 生命周期调用现在统一走显式命令包装,不再出现 Node `DEP0190` shell 弃用警告
230
232
 
231
233
  ## 快速开始
232
234
 
@@ -313,7 +315,7 @@ helloagents codex goals enable
313
315
 
314
316
  当你不想依赖更新过程中的 `helloagents` 可执行文件时,用 npm 或一键脚本。`HELLOAGENTS=目标[:模式]` 中,目标支持 `all`、`claude`、`gemini`、`codex`;模式支持 `standby`、`global`。用于安装时,省略模式按 `standby` 处理;用于更新、清理、卸载和切换分支时,省略模式会原样下传,让 HelloAGENTS 先复用该 CLI 已记录或检测到的模式。如果未提供 `HELLOAGENTS`,一键安装脚本现在会保持“只装包/只升级包”的默认语义,不会自动部署任何宿主 CLI。若要安装自定义 tarball 或包规格,用 `HELLOAGENTS_PACKAGE`,不要写 `HELLOAGENTS_BRANCH`。对于已经装好的包,如需确保宿主一定刷新,优先在包命令后显式执行一次 `npm explore -g helloagents -- npm run sync-hosts -- ...`。
315
317
 
316
- 宿主配置使用稳定的 `helloagents-js` 入口和运行根目录 `~/.helloagents/helloagents`,Node 全局包路径变化不会破坏受管 hooks 或 Codex `notify`。Codex hooks 使用独立 `~/.codex/hooks.json`,不把大段配置写入 `config.toml`;Codex 全局插件根目录和插件缓存也会回链到这个稳定运行根目录。
318
+ 宿主配置使用稳定的 `helloagents-js` 入口和运行根目录 `~/.helloagents/helloagents`,Node 全局包路径变化不会破坏受管 hooks 或 Codex `notify`。Codex hooks 使用独立 `~/.codex/hooks.json`,不把大段配置写入 `config.toml`;Codex 全局插件根目录和插件缓存也会回链到这个稳定运行根目录。Claude Code 的 global 安装现在使用独立本地 marketplace 投影 `~/.helloagents/host-projections/claude-marketplace`,Gemini 的 global 扩展使用 `~/.helloagents/host-projections/gemini`,宿主专用打包链路不再污染共享运行根。
317
319
 
318
320
  #### npm 命令
319
321
 
@@ -445,16 +447,16 @@ npm uninstall -g helloagents
445
447
 
446
448
  | CLI | 安装方式 | 涉及文件 |
447
449
  |-----|----------|----------|
448
- | Claude Code | 原生插件安装 | Claude Code 插件系统管理 |
449
- | Gemini CLI | 原生扩展安装 | Gemini 扩展系统管理 |
450
+ | Claude Code | 原生插件安装 | `~/.helloagents/host-projections/claude-marketplace`,以及由 Claude Code 宿主管理的插件元数据 / 缓存 |
451
+ | Gemini CLI | 原生扩展安装 | `~/.helloagents/host-projections/gemini`、`~/.gemini/extensions/helloagents` |
450
452
  | Codex CLI | 原生本地插件流程 | `~/.agents/plugins/marketplace.json`、`~/plugins/helloagents/ -> ~/.helloagents/helloagents`、`~/.codex/plugins/cache/local-plugins/helloagents/local/ -> ~/.helloagents/helloagents`、`~/.codex/config.toml`、`~/.codex/hooks.json`、`~/.codex/helloagents -> ~/.helloagents/helloagents` |
451
453
 
452
- 全局模式下,HelloAGENTS 会自动尝试宿主原生命令。对 Claude Code,marketplace 应使用 Git URL 添加,这样插件安装阶段会继续走 HTTPS,不会落回 SSH-only clone。若宿主命令不可用,再手动执行:
454
+ 全局模式下,HelloAGENTS 会自动尝试宿主原生命令。Claude Code 走本地 marketplace 投影,Gemini 走本地 extension 投影,Codex 继续回链同一个稳定运行根,因此安装、更新、切分支、切模式、清理和卸载都会围绕同一份运行时副本刷新。若宿主命令不可用,再手动执行:
453
455
 
454
456
  ```text
455
- /plugin marketplace add https://github.com/hellowind777/helloagents.git
457
+ /plugin marketplace add "~/.helloagents/host-projections/claude-marketplace"
456
458
  /plugin install helloagents@helloagents
457
- helloagents install gemini --global
459
+ gemini extensions link "~/.helloagents/host-projections/gemini"
458
460
  ```
459
461
 
460
462
  Claude Code 会自动尝试等价的 `claude plugin marketplace add ...` 和 `claude plugin install ...` 命令。marketplace 名称和插件名称都是 `helloagents`,所以安装目标是 `helloagents@helloagents`。全局安装后需要重启宿主 CLI。
@@ -656,15 +658,16 @@ Codex 默认走规则文件驱动。
656
658
 
657
659
  - 标准模式写入 `~/.codex/AGENTS.md`
658
660
  - 标准模式写入可移植的受管 `model_instructions_file = "~/.codex/AGENTS.md"`
659
- - 标准模式写入受管 `notify = ["helloagents-js", "codex-notify"]` 命令用于收尾通知
661
+ - 标准模式写入受管且可移植的 `notify = ["helloagents-js", "codex-notify"]` 命令用于收尾通知,因此重装、更新或换电脑时都不需要改写绝对路径
660
662
  - 标准模式把静默 Codex hooks 写入 `~/.codex/hooks.json`
661
663
  - Codex 的 `SessionStart` 保持静默,并在运行时读取当前 `~/.helloagents/helloagents.json`,不会把配置快照固化进 `config.toml`,因此首次对话和上下文压缩后的设置都能保持最新
662
664
  - 安装和更新还会把 HelloAGENTS 受管的 Codex hook trust 状态同步到 `~/.codex/config.toml`,因此 Codex 0.129.0+ 不会再对这些受管 hooks 反复提示确认
663
665
  - 这些 hook trust 状态是基于当前机器 `~/.codex/hooks.json` 真实绝对路径生成的本机状态;它不同于 `model_instructions_file = "~/.codex/AGENTS.md"` 这类可移植配置,应在每台机器上重新生成
664
666
  - 标准模式创建 `~/.codex/helloagents -> ~/.helloagents/helloagents`
665
667
  - 全局模式安装原生本地插件流程,但仍把 `~/.helloagents/helloagents` 作为唯一受管运行时源;插件根目录、插件缓存和 `~/.codex/helloagents` 都会回链到它
668
+ - `doctor`、`cleanup` 和 `uninstall` 也能识别 `--previous-notify ["helloagents-js", "codex-notify"]` 这类包装后的 notify 链,因此 Codex App / Computer Use 不会再触发误报或破坏 notify 恢复
666
669
  - 如果你主要看重 Codex app / 插件发现链路,优先使用 `global`;如果你主要看重更轻量、更显式的项目工作流,保留 `standby`
667
- - 清理时只删除 HelloAGENTS 自己写入的 hook trust 条目和旧式受管 notify 残留,不影响用户已有的 hook 状态
670
+ - 清理时只删除 HelloAGENTS 自己写入的 hook trust 条目,不影响用户已有的 hook 状态
668
671
  - Codex hooks 只做静默运行态同步和 Stop 门禁,不通过 hook 注入 HelloAGENTS 规则或路由说明
669
672
  - Codex 收尾会对 Stop hook 和原生 `codex-notify` 去重,避免同一轮重复通知;受管 Stop hook 生效时,client 为空的委派子任务完成事件也会保持静默
670
673
  - `/goal` 保持 Codex 原生能力;需要长程执行时,用 `helloagents codex goals enable` 显式启用
@@ -682,10 +685,11 @@ npm test
682
685
  当前测试覆盖:
683
686
 
684
687
  - 安装、更新、清理、卸载、分支切换和模式切换
688
+ - Windows `.cmd` / `.bat` 生命周期分发链路,且不再出现 Node `DEP0190` 警告
685
689
  - shell 与 PowerShell 一键脚本分发链路,以及包装脚本在安装、更新、清理、卸载和分支切换中的环境清理与模式传递规则
686
690
  - Claude、Gemini、Codex 的宿主集成行为,包括全局切回标准模式的清理和原生清理失败时的模式保留
687
691
  - Codex 受管 `model_instructions_file`、`notify`、`hooks.json`、hook trust 状态、本地插件、marketplace 和缓存行为
688
- - Windows Codex 旧式受管 notify 变体的清理,以及受管 notify 恢复规则
692
+ - Codex 清理链路,以及包括 wrapped `--previous-notify` 在内的受管 notify 恢复规则
689
693
  - Codex `/goal` 功能开关、长程路由上下文和 goal 感知命令契约
690
694
  - `helloagents doctor`
691
695
  - 项目存储和 `repo-shared`
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "helloagents",
3
- "version": "3.0.38",
3
+ "version": "3.1.1",
4
4
  "description": "Quality-driven orchestration kernel for AI CLIs",
5
5
  "contextFileName": "bootstrap.md",
6
6
  "author": "HelloWind",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "helloagents",
3
- "version": "3.0.38",
3
+ "version": "3.1.1",
4
4
  "type": "module",
5
5
  "description": "HelloAGENTS — The orchestration kernel that makes any AI CLI smarter. Adds intelligent routing, unified QA gates, safety guards, and notifications.",
6
6
  "author": "HelloWind",
@@ -1,15 +1,12 @@
1
- import { spawnSync } from 'node:child_process'
2
-
3
1
  import { normalizeHost } from './cli-lifecycle.mjs'
2
+ import { spawnCommandSync } from './cli-process.mjs'
4
3
 
5
4
  const DEFAULT_REPO_ARCHIVE_BASE = 'https://github.com/hellowind777/helloagents/archive/refs/heads'
6
5
 
7
6
  function runCommand(command, args) {
8
- const needsShell = process.platform === 'win32' && /\.cmd$/i.test(command)
9
- const result = spawnSync(command, args, {
7
+ const result = spawnCommandSync(command, args, {
10
8
  encoding: 'utf-8',
11
9
  errors: 'replace',
12
- shell: needsShell,
13
10
  stdio: 'inherit',
14
11
  windowsHide: true,
15
12
  })
@@ -13,13 +13,8 @@ export const CODEX_MANAGED_TOML_COMMENT = '# helloagents-managed'
13
13
  export const CODEX_MANAGED_MODEL_INSTRUCTIONS_PATH = '~/.codex/AGENTS.md'
14
14
  export const CODEX_MANAGED_NOTIFY_COMMAND = 'helloagents-js'
15
15
  export const CODEX_MANAGED_NOTIFY_VALUE = `["${CODEX_MANAGED_NOTIFY_COMMAND}", "codex-notify"]`
16
- const CODEX_MANAGED_NOTIFY_LEGACY_VALUES = [
17
- `["${CODEX_MANAGED_NOTIFY_COMMAND}.cmd", "codex-notify"]`,
18
- `["${CODEX_MANAGED_NOTIFY_COMMAND}.exe", "codex-notify"]`,
19
- ]
20
16
  export const CODEX_MANAGED_TUI_NOTIFICATIONS_VALUE = '["plan-mode-prompt"]'
21
17
  export const CODEX_HOOKS_FEATURE_KEY = 'hooks'
22
- export const CODEX_LEGACY_HOOKS_FEATURE_KEY = 'codex_hooks'
23
18
  export const CODEX_GOALS_FEATURE_KEY = 'goals'
24
19
  export const CODEX_MANAGED_GOALS_FEATURE_LINE = `${CODEX_GOALS_FEATURE_KEY} = true ${CODEX_MANAGED_TOML_COMMENT}`
25
20
  export const CODEX_MANAGED_GOALS_DISABLED_LINE = `${CODEX_GOALS_FEATURE_KEY} = false ${CODEX_MANAGED_TOML_COMMENT}`
@@ -29,6 +24,155 @@ function normalizePath(value = '') {
29
24
  return String(value || '').replace(/\\/g, '/')
30
25
  }
31
26
 
27
+ function isManagedCodexNotifyParts(parts) {
28
+ return Array.isArray(parts)
29
+ && parts.length === 2
30
+ && parts[0] === CODEX_MANAGED_NOTIFY_COMMAND
31
+ && parts[1] === 'codex-notify'
32
+ }
33
+
34
+ function extractTomlArrayLiteral(text = '') {
35
+ const source = String(text || '')
36
+ const equalsIndex = source.indexOf('=')
37
+ let quoted = false
38
+ let escaped = false
39
+ let commented = false
40
+ let depth = 0
41
+ let start = -1
42
+
43
+ for (let index = equalsIndex >= 0 ? equalsIndex + 1 : 0; index < source.length; index += 1) {
44
+ const char = source[index]
45
+
46
+ if (commented) {
47
+ if (char === '\n') commented = false
48
+ continue
49
+ }
50
+ if (escaped) {
51
+ escaped = false
52
+ continue
53
+ }
54
+ if (char === '\\' && quoted) {
55
+ escaped = true
56
+ continue
57
+ }
58
+ if (char === '"') {
59
+ quoted = !quoted
60
+ continue
61
+ }
62
+ if (quoted) continue
63
+ if (char === '#') {
64
+ commented = true
65
+ continue
66
+ }
67
+ if (char === '[') {
68
+ if (depth === 0) start = index
69
+ depth += 1
70
+ continue
71
+ }
72
+ if (char === ']' && depth > 0) {
73
+ depth -= 1
74
+ if (depth === 0 && start >= 0) return source.slice(start, index + 1)
75
+ }
76
+ }
77
+
78
+ return ''
79
+ }
80
+
81
+ function parseTomlStringArrayLiteral(literal = '') {
82
+ const source = String(literal || '').trim()
83
+ if (!source.startsWith('[') || !source.endsWith(']')) return null
84
+
85
+ const items = []
86
+ let quoted = false
87
+ let escaped = false
88
+ let tokenStart = -1
89
+
90
+ for (let index = 1; index < source.length; index += 1) {
91
+ const char = source[index]
92
+
93
+ if (quoted) {
94
+ if (escaped) {
95
+ escaped = false
96
+ continue
97
+ }
98
+ if (char === '\\') {
99
+ escaped = true
100
+ continue
101
+ }
102
+ if (char === '"') {
103
+ try {
104
+ items.push(JSON.parse(source.slice(tokenStart, index + 1)))
105
+ } catch {
106
+ return null
107
+ }
108
+ quoted = false
109
+ tokenStart = -1
110
+ }
111
+ continue
112
+ }
113
+
114
+ if (char === '#') {
115
+ while (index < source.length && source[index] !== '\n') index += 1
116
+ continue
117
+ }
118
+ if (/\s|,/.test(char)) continue
119
+ if (char === ']') return items
120
+ if (char !== '"') return null
121
+
122
+ quoted = true
123
+ tokenStart = index
124
+ }
125
+
126
+ return null
127
+ }
128
+
129
+ function analyzeNotifyCommandParts(parts = []) {
130
+ if (isManagedCodexNotifyParts(parts)) {
131
+ return {
132
+ managed: true,
133
+ shape: 'direct',
134
+ containsCodexNotify: true,
135
+ entrypoint: [...parts],
136
+ wrapper: '',
137
+ rawCommand: [...parts],
138
+ }
139
+ }
140
+
141
+ let containsCodexNotify = parts.includes('codex-notify')
142
+ for (let index = 0; index < parts.length - 1; index += 1) {
143
+ if (parts[index] !== '--previous-notify') continue
144
+
145
+ try {
146
+ const nested = JSON.parse(parts[index + 1])
147
+ if (!Array.isArray(nested) || !nested.every((entry) => typeof entry === 'string')) continue
148
+
149
+ const nestedAnalysis = analyzeNotifyCommandParts(nested)
150
+ containsCodexNotify = containsCodexNotify || nestedAnalysis.containsCodexNotify
151
+ if (!nestedAnalysis.managed) continue
152
+
153
+ return {
154
+ managed: true,
155
+ shape: 'chained',
156
+ containsCodexNotify: true,
157
+ entrypoint: [...nestedAnalysis.entrypoint],
158
+ wrapper: parts[0] || '',
159
+ rawCommand: [...parts],
160
+ }
161
+ } catch {
162
+ continue
163
+ }
164
+ }
165
+
166
+ return {
167
+ managed: false,
168
+ shape: parts.length ? 'external' : 'invalid',
169
+ containsCodexNotify,
170
+ entrypoint: [],
171
+ wrapper: '',
172
+ rawCommand: [...parts],
173
+ }
174
+ }
175
+
32
176
  function splitTomlLines(text = '') {
33
177
  return String(text || '').replace(/\r\n/g, '\n').split('\n')
34
178
  }
@@ -105,10 +249,6 @@ export function readCodexHooksFeatureLine(text) {
105
249
  return readCodexFeatureLine(text, CODEX_HOOKS_FEATURE_KEY)
106
250
  }
107
251
 
108
- export function readLegacyCodexHooksFeatureLine(text) {
109
- return readCodexFeatureLine(text, CODEX_LEGACY_HOOKS_FEATURE_KEY)
110
- }
111
-
112
252
  export function readCodexGoalsFeatureLine(text) {
113
253
  return readCodexFeatureLine(text, CODEX_GOALS_FEATURE_KEY)
114
254
  }
@@ -146,15 +286,6 @@ export function removeCodexGoalsFeatureConfig(text) {
146
286
  )
147
287
  }
148
288
 
149
- export function removeLegacyManagedCodexHooksFeatureConfig(text) {
150
- return removeTomlSectionLine(
151
- text,
152
- CODEX_FEATURES_HEADER,
153
- CODEX_LEGACY_HOOKS_FEATURE_KEY,
154
- isManagedLegacyCodexHooksFeature,
155
- )
156
- }
157
-
158
289
  export function restoreCodexGoalsFeatureConfig(text, { codexGoalsLine = '' } = {}) {
159
290
  if (!codexGoalsLine) return normalizeToml(text)
160
291
  return upsertTomlSectionLine(
@@ -173,10 +304,44 @@ export function isManagedCodexModelInstruction(line = '') {
173
304
  export function isManagedCodexNotify(line = '') {
174
305
  const value = String(line || '').replace(/\\/g, '/')
175
306
  return value.includes(CODEX_MANAGED_TOML_COMMENT)
176
- && (
177
- value.includes(CODEX_MANAGED_NOTIFY_VALUE)
178
- || CODEX_MANAGED_NOTIFY_LEGACY_VALUES.some((entry) => value.includes(entry))
179
- )
307
+ && value.includes(CODEX_MANAGED_NOTIFY_VALUE)
308
+ }
309
+
310
+ export function analyzeCodexNotifyBlock(block = '') {
311
+ const source = String(block || '').trim()
312
+ if (!source) {
313
+ return {
314
+ exists: false,
315
+ managed: false,
316
+ containsCodexNotify: false,
317
+ shape: 'missing',
318
+ entrypoint: [],
319
+ wrapper: '',
320
+ rawCommand: [],
321
+ rawBlock: '',
322
+ }
323
+ }
324
+
325
+ const literal = extractTomlArrayLiteral(source)
326
+ const parts = literal ? parseTomlStringArrayLiteral(literal) : null
327
+ if (!parts) {
328
+ return {
329
+ exists: true,
330
+ managed: false,
331
+ containsCodexNotify: source.includes('codex-notify'),
332
+ shape: 'invalid',
333
+ entrypoint: [],
334
+ wrapper: '',
335
+ rawCommand: [],
336
+ rawBlock: source,
337
+ }
338
+ }
339
+
340
+ return {
341
+ exists: true,
342
+ ...analyzeNotifyCommandParts(parts),
343
+ rawBlock: source,
344
+ }
180
345
  }
181
346
 
182
347
  export function isManagedCodexTuiNotifications(line = '') {
@@ -193,10 +358,6 @@ export function isManagedCodexHooksFeature(line = '') {
193
358
  return isManagedFeatureLine(line, CODEX_HOOKS_FEATURE_KEY)
194
359
  }
195
360
 
196
- export function isManagedLegacyCodexHooksFeature(line = '') {
197
- return isManagedFeatureLine(line, CODEX_LEGACY_HOOKS_FEATURE_KEY)
198
- }
199
-
200
361
  export function isManagedCodexGoalsFeature(line = '') {
201
362
  return isManagedFeatureLine(line, CODEX_GOALS_FEATURE_KEY)
202
363
  }
@@ -8,6 +8,7 @@ import {
8
8
  } from './cli-utils.mjs';
9
9
  import { ensureTimestampedBackup, readCodexBackup, removeCodexBackup } from './cli-codex-backup.mjs';
10
10
  import {
11
+ analyzeCodexNotifyBlock,
11
12
  CODEX_MANAGED_TOML_COMMENT,
12
13
  CODEX_MANAGED_MODEL_INSTRUCTIONS_PATH,
13
14
  CODEX_PLUGIN_CONFIG_HEADER,
@@ -17,12 +18,9 @@ import {
17
18
  isManagedCodexGoalsFeature,
18
19
  isManagedCodexModelInstruction,
19
20
  isManagedCodexNotify,
20
- isManagedLegacyCodexHooksFeature,
21
21
  readCodexGoalsFeatureLine,
22
- readLegacyCodexHooksFeatureLine,
23
22
  removeCodexGoalsFeatureConfig,
24
23
  removeCodexManagedTuiConfig,
25
- removeLegacyManagedCodexHooksFeatureConfig,
26
24
  removeCodexPluginConfig,
27
25
  restoreCodexGoalsFeatureConfig,
28
26
  restoreCodexTopLevelConfig,
@@ -33,8 +31,10 @@ import {
33
31
  syncManagedCodexHookTrust,
34
32
  } from './cli-codex-hooks-state.mjs';
35
33
  import {
34
+ hasTopLevelTomlBlock,
36
35
  readTopLevelTomlLine,
37
36
  readTopLevelTomlBlock,
37
+ removeTopLevelTomlBlock,
38
38
  removeTopLevelTomlLines,
39
39
  } from './cli-toml.mjs';
40
40
  import { buildRuntimeCarrier, readCarrierSettings } from './cli-runtime-carrier.mjs';
@@ -156,12 +156,11 @@ function cleanupCodexManagedConfig(configPath, { removePluginConfig = false } =
156
156
  const currentModelInstructions = readTopLevelTomlLine(toml, 'model_instructions_file');
157
157
  const currentNotify = readTopLevelTomlBlock(toml, 'notify');
158
158
  const currentCodexGoalsFeature = readCodexGoalsFeatureLine(toml);
159
- const currentLegacyCodexHooksFeature = readLegacyCodexHooksFeatureLine(toml);
159
+ const currentNotifyAnalysis = analyzeCodexNotifyBlock(currentNotify);
160
160
 
161
161
  const shouldRestoreModelInstructions = isManagedCodexModelInstruction(currentModelInstructions);
162
- const shouldRestoreNotify = isManagedCodexNotify(currentNotify);
162
+ const shouldRestoreNotify = currentNotifyAnalysis.managed || isManagedCodexNotify(currentNotify);
163
163
  const shouldRestoreCodexGoalsFeature = isManagedCodexGoalsFeature(currentCodexGoalsFeature);
164
- const shouldRemoveLegacyCodexHooksFeature = isManagedLegacyCodexHooksFeature(currentLegacyCodexHooksFeature);
165
164
 
166
165
  if (removePluginConfig) {
167
166
  toml = removeCodexPluginConfig(toml);
@@ -170,16 +169,15 @@ function cleanupCodexManagedConfig(configPath, { removePluginConfig = false } =
170
169
  toml = removeCodexGoalsFeatureConfig(toml);
171
170
  }
172
171
  toml = removeCodexManagedTuiConfig(toml);
173
- if (shouldRemoveLegacyCodexHooksFeature) {
174
- toml = removeLegacyManagedCodexHooksFeatureConfig(toml);
175
- }
176
172
  if (shouldRestoreModelInstructions) {
177
173
  toml = removeTopLevelTomlLines(toml, (line) =>
178
174
  line.startsWith('model_instructions_file =') && isManagedCodexModelInstruction(line)).text;
179
175
  }
180
176
  if (shouldRestoreNotify) {
181
- toml = removeTopLevelTomlLines(toml, (line) =>
182
- line.startsWith('notify =') && isManagedCodexNotify(line)).text;
177
+ toml = hasTopLevelTomlBlock(toml, 'notify')
178
+ ? removeTopLevelTomlBlock(toml, 'notify')
179
+ : removeTopLevelTomlLines(toml, (line) =>
180
+ line.startsWith('notify =')).text;
183
181
  }
184
182
 
185
183
  const backupModelInstructions = readTopLevelTomlLine(backupToml, 'model_instructions_file');
@@ -190,7 +188,7 @@ function cleanupCodexManagedConfig(configPath, { removePluginConfig = false } =
190
188
  modelInstructionsLine: shouldRestoreModelInstructions && !isManagedCodexBackupInstruction(backupModelInstructions)
191
189
  ? backupModelInstructions
192
190
  : '',
193
- notifyLine: shouldRestoreNotify && !isManagedCodexNotify(backupNotify)
191
+ notifyLine: shouldRestoreNotify && !analyzeCodexNotifyBlock(backupNotify).managed
194
192
  ? backupNotify
195
193
  : '',
196
194
  });
@@ -220,7 +218,6 @@ export function installCodexStandby(home, pkgRoot) {
220
218
  modelInstructionsPath: CODEX_MANAGED_MODEL_INSTRUCTIONS_PATH,
221
219
  });
222
220
  toml = installCodexManagedTuiConfig(toml);
223
- toml = removeLegacyManagedCodexHooksFeatureConfig(toml);
224
221
  safeWrite(configPath, toml);
225
222
  installCodexStandaloneHooks(home, pkgRoot);
226
223
 
@@ -312,7 +309,6 @@ export function installCodexGlobal(home, pkgRoot) {
312
309
  modelInstructionsPath: CODEX_MANAGED_MODEL_INSTRUCTIONS_PATH,
313
310
  });
314
311
  toml = installCodexManagedTuiConfig(toml);
315
- toml = removeLegacyManagedCodexHooksFeatureConfig(toml);
316
312
  toml = upsertCodexPluginConfig(toml);
317
313
  safeWrite(configPath, toml);
318
314
  installCodexStandaloneHooks(home, pkgRoot);