helloagents 3.0.19 → 3.0.21-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 (44) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/.codex-plugin/plugin.json +1 -1
  3. package/README.md +26 -20
  4. package/README_CN.md +24 -18
  5. package/bootstrap-lite.md +4 -2
  6. package/bootstrap.md +4 -2
  7. package/gemini-extension.json +1 -1
  8. package/package.json +1 -1
  9. package/scripts/cli-doctor-codex.mjs +5 -5
  10. package/scripts/cli-doctor-render.mjs +1 -1
  11. package/scripts/cli-doctor.mjs +2 -2
  12. package/scripts/cli-messages.mjs +5 -5
  13. package/scripts/delivery-gate-messages.mjs +4 -4
  14. package/scripts/guard-rules.mjs +2 -2
  15. package/scripts/guard.mjs +3 -3
  16. package/scripts/notify-context.mjs +1 -1
  17. package/scripts/notify.mjs +3 -1
  18. package/scripts/project-session-cleanup.mjs +106 -0
  19. package/scripts/project-storage.mjs +5 -5
  20. package/scripts/ralph-loop.mjs +1 -1
  21. package/scripts/runtime-scope.mjs +132 -62
  22. package/scripts/runtime-user-cleanup.mjs +63 -0
  23. package/scripts/session-capsule.mjs +29 -2
  24. package/scripts/session-token.mjs +0 -2
  25. package/scripts/workflow-core.mjs +1 -1
  26. package/scripts/workflow-plan-files.mjs +1 -1
  27. package/scripts/workflow-recommendation.mjs +1 -1
  28. package/skills/commands/auto/SKILL.md +3 -3
  29. package/skills/commands/build/SKILL.md +6 -6
  30. package/skills/commands/clean/SKILL.md +5 -5
  31. package/skills/commands/commit/SKILL.md +3 -3
  32. package/skills/commands/init/SKILL.md +3 -3
  33. package/skills/commands/loop/SKILL.md +2 -2
  34. package/skills/commands/plan/SKILL.md +7 -7
  35. package/skills/commands/prd/SKILL.md +7 -6
  36. package/skills/commands/verify/SKILL.md +2 -2
  37. package/skills/commands/wiki/SKILL.md +1 -1
  38. package/skills/hello-arch/SKILL.md +2 -2
  39. package/skills/hello-errors/SKILL.md +1 -1
  40. package/skills/hello-subagent/SKILL.md +1 -1
  41. package/skills/hello-ui/SKILL.md +4 -4
  42. package/skills/hello-verify/SKILL.md +1 -1
  43. package/skills/hello-write/SKILL.md +1 -1
  44. package/skills/helloagents/SKILL.md +9 -10
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "helloagents",
3
- "version": "3.0.19",
3
+ "version": "3.0.21-beta.1",
4
4
  "description": "HelloAGENTS — The orchestration kernel that makes any AI CLI smarter. Adds intelligent routing, quality verification (Ralph Loop), 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.19",
3
+ "version": "3.0.21-beta.1",
4
4
  "description": "HelloAGENTS — Quality-driven orchestration kernel for AI CLIs with intelligent routing, quality verification (Ralph Loop), 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.19-orange.svg)](./package.json)
11
+ [![Version](https://img.shields.io/badge/version-3.0.21-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)
@@ -116,7 +116,7 @@ Commands run inside the AI CLI chat with a `~` prefix. The command skill is read
116
116
  | `~prd` | Modern product requirements document through guided dimension-by-dimension exploration |
117
117
  | `~loop` | Iterative improvement with metric, guard command, keep/revert decisions |
118
118
  | `~wiki` | Create or sync only the project knowledge base |
119
- | `~init` | Full project bootstrap: knowledge base plus project-level rule files and package-root links |
119
+ | `~init` | Full project setup: knowledge base plus project-level rule files and package-root links |
120
120
  | `~test` | Write tests for a target module or recent change |
121
121
  | `~verify` | Review, run verification commands, fix failures, and close out |
122
122
  | `~commit` | Generate a conventional commit message and sync knowledge |
@@ -187,8 +187,10 @@ Long tasks need a small recovery snapshot, but one shared state file is not safe
187
187
 
188
188
  HelloAGENTS now resolves the current state file from `state_path`:
189
189
 
190
- - with a stable session id: `.helloagents/sessions/<branch>/<session>/STATE.md`
191
- - without a stable session id: `.helloagents/sessions/<branch>/default/STATE.md`
190
+ - with a stable session id: `.helloagents/sessions/<workspace>/<session>/STATE.md`
191
+ - without a stable session id: `.helloagents/sessions/<workspace>/default/STATE.md`
192
+
193
+ `<workspace>` is the current Git branch, `detached-<sha>` for a detached HEAD, or `workspace` for non-Git projects. `.helloagents/sessions/active.json` only records the active session index.
192
194
 
193
195
  `STATE.md` records where the current workflow stopped. It is not a universal memory file for every conversation.
194
196
 
@@ -198,13 +200,16 @@ HelloAGENTS does not treat “tests passed” and “task complete” as the sam
198
200
 
199
201
  Runtime evidence files include:
200
202
 
201
- - `.helloagents/sessions/<branch>/<session>/capsule.json`
202
- - `.helloagents/sessions/<branch>/<session>/events.jsonl`
203
- - `.helloagents/sessions/<branch>/<session>/artifacts/review.json`
204
- - `.helloagents/sessions/<branch>/<session>/artifacts/advisor.json`
205
- - `.helloagents/sessions/<branch>/<session>/artifacts/visual.json`
206
- - `.helloagents/sessions/<branch>/<session>/artifacts/closeout.json`
207
- - `.helloagents/sessions/<branch>/<session>/artifacts/loop-results.tsv`
203
+ - `.helloagents/sessions/<workspace>/<session>/capsule.json`
204
+ - `.helloagents/sessions/<workspace>/<session>/events.jsonl`
205
+ - `.helloagents/sessions/active.json`
206
+ - `.helloagents/sessions/<workspace>/<session>/artifacts/review.json`
207
+ - `.helloagents/sessions/<workspace>/<session>/artifacts/advisor.json`
208
+ - `.helloagents/sessions/<workspace>/<session>/artifacts/visual.json`
209
+ - `.helloagents/sessions/<workspace>/<session>/artifacts/closeout.json`
210
+ - `.helloagents/sessions/<workspace>/<session>/artifacts/loop-results.tsv`
211
+
212
+ Delivery gate, guard, and loop messages use action-oriented wording such as processing path, closeout action, and visual validation action, so blocked flows show what to do next without turning executable steps into optional suggestions.
208
213
 
209
214
  ### 7) Safer install, update, cleanup, and diagnostics
210
215
 
@@ -268,7 +273,7 @@ For knowledge base only:
268
273
  ~wiki
269
274
  ```
270
275
 
271
- For full project bootstrap:
276
+ For full project setup:
272
277
 
273
278
  ```text
274
279
  ~init
@@ -496,10 +501,11 @@ When `project_store_mode = "repo-shared"`:
496
501
  Runtime state and evidence remain local to the working project:
497
502
 
498
503
  - `state_path`
499
- - `.helloagents/sessions/<branch>/<session>/capsule.json`
500
- - `.helloagents/sessions/<branch>/<session>/events.jsonl`
501
- - `.helloagents/sessions/<branch>/<session>/artifacts/*.json`
502
- - `.helloagents/sessions/<branch>/<session>/artifacts/loop-results.tsv`
504
+ - `.helloagents/sessions/<workspace>/<session>/capsule.json`
505
+ - `.helloagents/sessions/<workspace>/<session>/events.jsonl`
506
+ - `.helloagents/sessions/active.json`
507
+ - `.helloagents/sessions/<workspace>/<session>/artifacts/*.json`
508
+ - `.helloagents/sessions/<workspace>/<session>/artifacts/loop-results.tsv`
503
509
 
504
510
  ### Unactivated or temporary sessions
505
511
 
@@ -638,7 +644,7 @@ Codex is rules-file driven by default.
638
644
  - standby writes silent Codex hooks to `~/.codex/hooks.json`
639
645
  - standby creates `~/.codex/helloagents -> ~/.helloagents/helloagents`
640
646
  - global mode installs the native local-plugin chain and also loads silent hooks from `~/.codex/hooks.json`
641
- - Codex hooks only synchronize runtime state and enforce Stop gates; they do not inject bootstrap or route text through hook output
647
+ - Codex hooks only synchronize runtime state and enforce Stop gates; they do not inject HelloAGENTS rules or route text through hook output
642
648
  - `/goal` remains Codex-native. Enable it explicitly with `helloagents codex goals enable` when long-running plan execution is needed
643
649
  - Goal-aware commands resume from `tasks.md`, `contract.json`, and `state_path`; they do not create goals automatically or mark them complete before HelloAGENTS verification and closeout
644
650
 
@@ -666,14 +672,14 @@ The current test suite covers:
666
672
 
667
673
  ### What is the role of `docs/`?
668
674
 
669
- `docs/` is reference material for users and AI agents. It may lag behind implementation; runtime behavior is defined by source code, bootstrap files, skills, templates, and tests.
675
+ `docs/` is reference material for users and AI agents. It may lag behind implementation; runtime behavior is defined by source code, rule templates, skills, templates, and tests.
670
676
 
671
677
  ### Is this a CLI tool or a prompt framework?
672
678
 
673
679
  Both.
674
680
 
675
681
  - `cli.mjs` handles install, update, cleanup, diagnostics, and host config
676
- - `bootstrap.md` and `bootstrap-lite.md` define workflow rules
682
+ - rule templates define the loaded workflow rules
677
683
  - `skills/` defines task-specific behavior
678
684
  - `scripts/` provides runtime helpers for routing, guard, notify, verification, state, and evidence
679
685
 
@@ -691,7 +697,7 @@ Use `~init` when you also want project-level rule files and project-level HelloA
691
697
 
692
698
  ### Do Codex hooks show injected content?
693
699
 
694
- No bootstrap or route text is injected through hooks. HelloAGENTS Codex hooks only write runtime state and enforce Stop gates; successful hooks stay quiet, while blocked or failed hooks show the necessary reason.
700
+ No HelloAGENTS rule or route text is injected through hooks. HelloAGENTS Codex hooks only write runtime state and enforce Stop gates; successful hooks stay quiet, while blocked or failed hooks show the necessary reason.
695
701
 
696
702
  ### Can I turn off notifications or guard checks?
697
703
 
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.19-orange.svg)](./package.json)
11
+ [![Version](https://img.shields.io/badge/version-3.0.21-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)
@@ -187,8 +187,10 @@ HelloAGENTS 可以在 `.helloagents/` 下创建和维护项目知识库。
187
187
 
188
188
  HelloAGENTS 现在只从 `state_path` 解析当前状态文件:
189
189
 
190
- - 宿主提供稳定会话标识时:`.helloagents/sessions/<branch>/<session>/STATE.md`
191
- - 宿主未提供稳定会话标识时:`.helloagents/sessions/<branch>/default/STATE.md`
190
+ - 宿主提供稳定会话标识时:`.helloagents/sessions/<workspace>/<session>/STATE.md`
191
+ - 宿主未提供稳定会话标识时:`.helloagents/sessions/<workspace>/default/STATE.md`
192
+
193
+ `<workspace>` 是当前 Git 分支、detached HEAD 的 `detached-<sha>`,或非 Git 项目的 `workspace`。`.helloagents/sessions/active.json` 只记录当前活跃会话索引。
192
194
 
193
195
  `STATE.md` 只记录当前工作流做到哪里,不承担所有对话的统一记忆。
194
196
 
@@ -198,13 +200,16 @@ HelloAGENTS 不把“命令通过”和“任务完成”简单画等号。交
198
200
 
199
201
  运行态证据文件包括:
200
202
 
201
- - `.helloagents/sessions/<branch>/<session>/capsule.json`
202
- - `.helloagents/sessions/<branch>/<session>/events.jsonl`
203
- - `.helloagents/sessions/<branch>/<session>/artifacts/review.json`
204
- - `.helloagents/sessions/<branch>/<session>/artifacts/advisor.json`
205
- - `.helloagents/sessions/<branch>/<session>/artifacts/visual.json`
206
- - `.helloagents/sessions/<branch>/<session>/artifacts/closeout.json`
207
- - `.helloagents/sessions/<branch>/<session>/artifacts/loop-results.tsv`
203
+ - `.helloagents/sessions/<workspace>/<session>/capsule.json`
204
+ - `.helloagents/sessions/<workspace>/<session>/events.jsonl`
205
+ - `.helloagents/sessions/active.json`
206
+ - `.helloagents/sessions/<workspace>/<session>/artifacts/review.json`
207
+ - `.helloagents/sessions/<workspace>/<session>/artifacts/advisor.json`
208
+ - `.helloagents/sessions/<workspace>/<session>/artifacts/visual.json`
209
+ - `.helloagents/sessions/<workspace>/<session>/artifacts/closeout.json`
210
+ - `.helloagents/sessions/<workspace>/<session>/artifacts/loop-results.tsv`
211
+
212
+ 交付门控、守卫和循环提示使用执行性表述,例如处理路径、收尾动作和视觉验收动作。阻塞流程会说明下一步要做什么,而不是把可执行步骤写成泛化建议。
208
213
 
209
214
  ### 7)更安全的安装、更新、清理和诊断
210
215
 
@@ -498,10 +503,11 @@ Codex 全局模式由 HelloAGENTS 通过本地插件路径自动安装。
498
503
  运行态文件仍保留在当前项目本地:
499
504
 
500
505
  - `state_path`
501
- - `.helloagents/sessions/<branch>/<session>/capsule.json`
502
- - `.helloagents/sessions/<branch>/<session>/events.jsonl`
503
- - `.helloagents/sessions/<branch>/<session>/artifacts/*.json`
504
- - `.helloagents/sessions/<branch>/<session>/artifacts/loop-results.tsv`
506
+ - `.helloagents/sessions/<workspace>/<session>/capsule.json`
507
+ - `.helloagents/sessions/<workspace>/<session>/events.jsonl`
508
+ - `.helloagents/sessions/active.json`
509
+ - `.helloagents/sessions/<workspace>/<session>/artifacts/*.json`
510
+ - `.helloagents/sessions/<workspace>/<session>/artifacts/loop-results.tsv`
505
511
 
506
512
  ### 未激活或临时会话
507
513
 
@@ -640,7 +646,7 @@ Codex 默认走规则文件驱动。
640
646
  - 标准模式把静默 Codex hooks 写入 `~/.codex/hooks.json`
641
647
  - 标准模式创建 `~/.codex/helloagents -> ~/.helloagents/helloagents`
642
648
  - 全局模式安装原生本地插件流程,并同样用 `~/.codex/hooks.json` 加载静默 hooks
643
- - Codex hooks 只做静默运行态同步和 Stop 门禁,不通过 hook 注入 bootstrap 或路由说明
649
+ - Codex hooks 只做静默运行态同步和 Stop 门禁,不通过 hook 注入 HelloAGENTS 规则或路由说明
644
650
  - `/goal` 保持 Codex 原生能力;需要长程执行时,用 `helloagents codex goals enable` 显式启用
645
651
  - 感知 goal 的命令从 `tasks.md`、`contract.json` 和 `state_path` 恢复;不会自动创建 goal,也不会在 HelloAGENTS 验证和收尾前标记完成
646
652
 
@@ -668,14 +674,14 @@ npm test
668
674
 
669
675
  ### `docs/` 的作用是什么?
670
676
 
671
- `docs/` 只作为用户和 AI 理解项目的参考材料,可能滞后于实现。运行时行为以源码、bootstrap 文件、skills、templates 和测试为准。
677
+ `docs/` 只作为用户和 AI 理解项目的参考材料,可能滞后于实现。运行时行为以源码、规则模板、skills、templates 和测试为准。
672
678
 
673
679
  ### 这是 CLI 工具还是提示词框架?
674
680
 
675
681
  两者都是。
676
682
 
677
683
  - `cli.mjs` 负责安装、更新、清理、诊断和宿主配置
678
- - `bootstrap.md` 与 `bootstrap-lite.md` 定义工作流规则
684
+ - 规则模板定义运行时加载的工作流规则
679
685
  - `skills/` 定义任务类型相关行为
680
686
  - `scripts/` 提供选路、Guard、通知、验证、状态和证据等运行时辅助能力
681
687
 
@@ -693,7 +699,7 @@ npm test
693
699
 
694
700
  ### Codex hooks 会显示注入内容吗?
695
701
 
696
- 不会显示 bootstrap 或路由说明。HelloAGENTS 的 Codex hooks 只写运行态和执行 Stop 门禁,成功路径返回静默结果;只有阻塞或错误时显示必要原因。
702
+ 不会显示 HelloAGENTS 规则或路由说明。HelloAGENTS 的 Codex hooks 只写运行态和执行 Stop 门禁,成功路径返回静默结果;只有阻塞或错误时显示必要原因。
697
703
 
698
704
  ### 可以关闭通知或 Guard 吗?
699
705
 
package/bootstrap-lite.md CHANGED
@@ -33,6 +33,7 @@
33
33
  - 不写黑话、营销话、内部化表述或空泛形容;源码字段名、协议名、命令、路径、配置键等必须保留原名时除外
34
34
  - 不写无执行价值的客套、邀约、重复确认、能力陈述或空泛建议
35
35
  - 同一概念前后用语保持一致;先给结论再给细节,避免同义反复、重复解释和堆砌近义句
36
+ - 优化既有约束或文案时,优先在原条目内收敛表达;只有边界独立且原条目无法承载时才新增条目,并同步删除重复表述
36
37
 
37
38
  ### 完整交付(强制)
38
39
  - 一次做完:用户需求明确且已获得执行授权时,必须持续执行到完成;只有符合下文“阻塞判定”的情况,才可中途停下
@@ -207,8 +208,9 @@
207
208
  所有文件的创建和更新必须按 templates/ 目录中对应模板的格式执行,不可自由发挥格式。
208
209
  说明:
209
210
  - `.helloagents/` 表示项目级存储路径,也是标准模式的项目激活信号
210
- - `state_path` 指向的状态文件、当前会话 `capsule.json`、`events.jsonl`、`artifacts/*.json`、`artifacts/loop-results.tsv` 等运行态文件始终保留在项目本地 `.helloagents/sessions/{branch}/{session}/`
211
- - `state_path` 是状态文件的唯一位置。宿主提供会话标识时,写入 `.helloagents/sessions/{branch}/{session}/STATE.md`;没有稳定会话标识时,写入 `.helloagents/sessions/{branch}/default/STATE.md`
211
+ - `state_path` 指向的状态文件、当前会话 `capsule.json`、`events.jsonl`、`artifacts/*.json`、`artifacts/loop-results.tsv` 等运行态文件始终保留在项目本地 `.helloagents/sessions/{workspace}/{session}/`
212
+ - `state_path` 是状态文件的唯一位置。宿主提供会话标识时,写入 `.helloagents/sessions/{workspace}/{session}/STATE.md`;没有稳定会话标识时,写入 `.helloagents/sessions/{workspace}/default/STATE.md`
213
+ - `{workspace}` 为当前 Git 分支、`detached-{sha}` 或非 Git 项目的 `workspace`;`.helloagents/sessions/active.json` 只记录当前活跃会话索引,避免同一会话被拆成多个目录
212
214
  - 若 helloagents.json 中 `project_store_mode = "repo-shared"`,`context.md`、`guidelines.md`、`CHANGELOG.md`、`verify.yaml`、`DESIGN.md`、`modules/`、`plans/`、`archive/` 改按当前上下文中已注入的“当前项目存储”/“项目知识/方案目录”解析;未注入具体路径时,按当前存储模式自行解析,不要假定这些文件一定实际位于当前工作树中
213
215
  templates/ 查找路径(按优先级;首次确定模板根目录后,本轮复用):
214
216
  按上文 `~command` 路由中的相同技能根目录规则确定;确定根目录后读取其中的 `templates/`。
package/bootstrap.md CHANGED
@@ -33,6 +33,7 @@
33
33
  - 不写黑话、营销话、内部化表述或空泛形容;源码字段名、协议名、命令、路径、配置键等必须保留原名时除外
34
34
  - 不写无执行价值的客套、邀约、重复确认、能力陈述或空泛建议
35
35
  - 同一概念前后用语保持一致;先给结论再给细节,避免同义反复、重复解释和堆砌近义句
36
+ - 优化既有约束或文案时,优先在原条目内收敛表达;只有边界独立且原条目无法承载时才新增条目,并同步删除重复表述
36
37
 
37
38
  ### 完整交付(强制)
38
39
  - 一次做完:用户需求明确且已获得执行授权时,必须持续执行到完成;只有符合下文“阻塞判定”的情况,才可中途停下
@@ -273,8 +274,9 @@ hello-* 技能读取路径:`{HELLOAGENTS_READ_ROOT}/skills/{技能名}/SKILL.m
273
274
  所有文件的创建和更新必须按 templates/ 目录中对应模板的格式执行,不可自由发挥格式。
274
275
  说明:
275
276
  - `.helloagents/` 表示项目级存储路径,也是标准模式的项目激活信号
276
- - `state_path` 指向的状态文件、当前会话 `capsule.json`、`events.jsonl`、`artifacts/*.json`、`artifacts/loop-results.tsv` 等运行态文件始终保留在项目本地 `.helloagents/sessions/{branch}/{session}/`
277
- - `state_path` 是状态文件的唯一位置。宿主提供会话标识时,写入 `.helloagents/sessions/{branch}/{session}/STATE.md`;没有稳定会话标识时,写入 `.helloagents/sessions/{branch}/default/STATE.md`
277
+ - `state_path` 指向的状态文件、当前会话 `capsule.json`、`events.jsonl`、`artifacts/*.json`、`artifacts/loop-results.tsv` 等运行态文件始终保留在项目本地 `.helloagents/sessions/{workspace}/{session}/`
278
+ - `state_path` 是状态文件的唯一位置。宿主提供会话标识时,写入 `.helloagents/sessions/{workspace}/{session}/STATE.md`;没有稳定会话标识时,写入 `.helloagents/sessions/{workspace}/default/STATE.md`
279
+ - `{workspace}` 为当前 Git 分支、`detached-{sha}` 或非 Git 项目的 `workspace`;`.helloagents/sessions/active.json` 只记录当前活跃会话索引,避免同一会话被拆成多个目录
278
280
  - 若 helloagents.json 中 `project_store_mode = "repo-shared"`,`context.md`、`guidelines.md`、`CHANGELOG.md`、`verify.yaml`、`DESIGN.md`、`modules/`、`plans/`、`archive/` 改按当前上下文中已注入的“当前项目存储”/“项目知识/方案目录”解析;未注入具体路径时,按当前存储模式自行解析,不要假定这些文件一定实际位于当前工作树中
279
281
  templates/ 查找路径(按优先级;首次确定模板根目录后,本轮复用):
280
282
  按上文相同的技能根目录规则确定;确定根目录后读取其中的 `templates/`。
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "helloagents",
3
- "version": "3.0.19",
3
+ "version": "3.0.21-beta.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.19",
3
+ "version": "3.0.21-beta.1",
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",
@@ -92,7 +92,7 @@ function suggestCodexDoctorFix(status, trackedMode) {
92
92
 
93
93
  function appendCodexStandbyIssues(runtime, issues, checks) {
94
94
  if (!checks.carrierMarker) issues.push(buildDoctorIssue(runtime, 'standby-carrier-missing', 'standby `~/.codex/AGENTS.md` 缺少 HelloAGENTS 标记', 'Standby `~/.codex/AGENTS.md` is missing the HELLOAGENTS marker'))
95
- if (checks.carrierMarker && !checks.carrierContentMatch) issues.push(buildDoctorIssue(runtime, 'standby-carrier-drift', 'standby `~/.codex/AGENTS.md` 与当前 bootstrap-lite.md 不一致', 'Standby `~/.codex/AGENTS.md` differs from the current bootstrap-lite.md'))
95
+ if (checks.carrierMarker && !checks.carrierContentMatch) issues.push(buildDoctorIssue(runtime, 'standby-carrier-drift', 'standby `~/.codex/AGENTS.md` 与当前标准模式规则不一致', 'Standby `~/.codex/AGENTS.md` differs from the current standby rules'))
96
96
  if (!checks.homeLink) issues.push(buildDoctorIssue(runtime, 'standby-link-missing', 'standby `~/.codex/helloagents` 链接缺失或未指向稳定运行根目录', 'Standby `~/.codex/helloagents` link is missing or points to a different runtime root'))
97
97
  if (!checks.modelInstructionsFile) issues.push(buildDoctorIssue(runtime, 'standby-model-instructions-missing', 'standby config 缺少受管 model_instructions_file', 'Standby config is missing the managed model_instructions_file'))
98
98
  if (checks.modelInstructionsFile && !checks.modelInstructionsPathMatch) issues.push(buildDoctorIssue(runtime, 'standby-model-instructions-drift', 'standby model_instructions_file 未指向受管 `~/.codex/AGENTS.md`', 'Standby model_instructions_file does not point to the managed `~/.codex/AGENTS.md`'))
@@ -108,12 +108,12 @@ function appendCodexStandbyIssues(runtime, issues, checks) {
108
108
 
109
109
  function appendCodexGlobalIssues(runtime, issues, checks, pluginVersion, cacheVersion) {
110
110
  if (!checks.carrierMarker) issues.push(buildDoctorIssue(runtime, 'global-home-carrier-missing', 'global `~/.codex/AGENTS.md` 缺少 HelloAGENTS 规则内容', 'Global `~/.codex/AGENTS.md` is missing the HelloAGENTS carrier'))
111
- if (checks.carrierMarker && !checks.carrierContentMatch) issues.push(buildDoctorIssue(runtime, 'global-home-carrier-drift', 'global `~/.codex/AGENTS.md` 与当前 bootstrap.md 不一致', 'Global `~/.codex/AGENTS.md` differs from the current bootstrap.md'))
111
+ if (checks.carrierMarker && !checks.carrierContentMatch) issues.push(buildDoctorIssue(runtime, 'global-home-carrier-drift', 'global `~/.codex/AGENTS.md` 与当前全局模式规则不一致', 'Global `~/.codex/AGENTS.md` differs from the current global rules'))
112
112
  if (!checks.globalHomeLink) issues.push(buildDoctorIssue(runtime, 'global-read-root-link-missing', 'global `~/.codex/helloagents` 链接缺失或未指向当前插件根目录', 'Global `~/.codex/helloagents` link is missing or does not point to the current plugin root'))
113
113
  if (!checks.pluginRoot) issues.push(buildDoctorIssue(runtime, 'global-plugin-root-missing', 'global 插件根目录缺失', 'Global plugin root is missing'))
114
114
  if (!checks.pluginCache) issues.push(buildDoctorIssue(runtime, 'global-plugin-cache-missing', 'global 插件缓存目录缺失', 'Global plugin cache directory is missing'))
115
- if (checks.pluginRoot && !checks.pluginCarrierMatch) issues.push(buildDoctorIssue(runtime, 'global-plugin-carrier-drift', 'global 插件根目录中的 AGENTS.md 与当前 bootstrap.md 不一致', 'Global plugin AGENTS.md differs from the current bootstrap.md'))
116
- if (checks.pluginCache && !checks.pluginCacheCarrierMatch) issues.push(buildDoctorIssue(runtime, 'global-plugin-cache-carrier-drift', 'global 插件缓存中的 AGENTS.md 与当前 bootstrap.md 不一致', 'Global plugin cache AGENTS.md differs from the current bootstrap.md'))
115
+ if (checks.pluginRoot && !checks.pluginCarrierMatch) issues.push(buildDoctorIssue(runtime, 'global-plugin-carrier-drift', 'global 插件根目录中的 AGENTS.md 与当前全局模式规则不一致', 'Global plugin AGENTS.md differs from the current global rules'))
116
+ if (checks.pluginCache && !checks.pluginCacheCarrierMatch) issues.push(buildDoctorIssue(runtime, 'global-plugin-cache-carrier-drift', 'global 插件缓存中的 AGENTS.md 与当前全局模式规则不一致', 'Global plugin cache AGENTS.md differs from the current global rules'))
117
117
  if (!checks.marketplaceEntry) issues.push(buildDoctorIssue(runtime, 'global-marketplace-missing', 'global marketplace 条目缺失', 'Global marketplace entry is missing'))
118
118
  if (!checks.pluginEnabled) issues.push(buildDoctorIssue(runtime, 'global-plugin-disabled', 'global config 中缺少插件启用段', 'Global plugin enablement block is missing from config'))
119
119
  if (!checks.modelInstructionsFile) issues.push(buildDoctorIssue(runtime, 'global-model-instructions-missing', 'global config 缺少受管 model_instructions_file', 'Global config is missing the managed model_instructions_file'))
@@ -201,7 +201,7 @@ export function inspectCodexDoctor(runtime, settings) {
201
201
  if (!checks.pluginVersionMatch && !pluginVersion && detectedMode === 'global') notes.push(runtime.msg('未读到 global 插件根目录版本信息', 'Global plugin root version was not readable'))
202
202
  if (!checks.pluginCacheVersionMatch && !cacheVersion && detectedMode === 'global') notes.push(runtime.msg('未读到 global 插件缓存版本信息', 'Global plugin cache version was not readable'))
203
203
  if (detectedMode !== 'none' && !checks.codexGoalsFeature) notes.push(runtime.msg('Codex /goal 未启用;如需长程执行,可运行 `helloagents codex goals enable`。', 'Codex /goal is not enabled; run `helloagents codex goals enable` if you need long-running goals.'))
204
- if (detectedMode !== 'none' && checks.legacyCodexHooksFeature) notes.push(runtime.msg('检测到旧版 `codex_hooks`;HelloAGENTS 只兼容 Codex 最新版,建议移除旧 key。', 'Legacy `codex_hooks` was detected; HelloAGENTS targets latest Codex only, so remove the old key.'))
204
+ if (detectedMode !== 'none' && checks.legacyCodexHooksFeature) notes.push(runtime.msg('检测到旧版 `codex_hooks`;HelloAGENTS 只兼容 Codex 最新版,请移除旧 key。', 'Legacy `codex_hooks` was detected; HelloAGENTS targets latest Codex only, so remove the old key.'))
205
205
 
206
206
  const status = summarizeDoctorStatus(issues, { trackedMode, detectedMode })
207
207
  return { host, label: runtime.getHostLabel(host), trackedMode, detectedMode, status, checks, issues, notes, suggestedFix: suggestCodexDoctorFix(status, trackedMode) }
@@ -24,7 +24,7 @@ export function printDoctorText(runtime, report) {
24
24
  console.log(` issue[${issue.code}]: ${issue.message}`)
25
25
  }
26
26
  if (entry.suggestedFix) {
27
- console.log(` suggested_fix: ${entry.suggestedFix}`)
27
+ console.log(` fix: ${entry.suggestedFix}`)
28
28
  }
29
29
  }
30
30
 
@@ -145,7 +145,7 @@ function inspectClaudeDoctor(settings) {
145
145
  }
146
146
  if (detectedMode === 'standby') {
147
147
  if (!checks.carrierMarker) issues.push(buildDoctorIssue('standby-carrier-missing', 'standby 规则文件缺少 HELLOAGENTS 标记', 'Standby carrier is missing the HELLOAGENTS marker'))
148
- if (checks.carrierMarker && !checks.carrierContentMatch) issues.push(buildDoctorIssue('standby-carrier-drift', 'standby 规则文件内容与当前 bootstrap-lite.md 不一致', 'Standby carrier content differs from the current bootstrap-lite.md'))
148
+ if (checks.carrierMarker && !checks.carrierContentMatch) issues.push(buildDoctorIssue('standby-carrier-drift', 'standby 规则文件内容与当前标准模式规则不一致', 'Standby carrier content differs from the current standby rules'))
149
149
  if (!checks.homeLink) issues.push(buildDoctorIssue('standby-link-missing', 'standby home 链接缺失或未指向稳定运行根目录', 'Standby home link is missing or points to a different runtime root'))
150
150
  if (!checks.settingsHooks) issues.push(buildDoctorIssue('standby-hooks-missing', 'standby settings hooks 缺失', 'Standby settings hooks are missing'))
151
151
  if (checks.settingsHooks && !checks.settingsHooksMatch) issues.push(buildDoctorIssue('standby-hooks-drift', 'standby settings hooks 与当前 hooks 配置不一致', 'Standby settings hooks differ from the current hook configuration'))
@@ -194,7 +194,7 @@ function inspectGeminiDoctor(settings) {
194
194
  }
195
195
  if (detectedMode === 'standby') {
196
196
  if (!checks.carrierMarker) issues.push(buildDoctorIssue('standby-carrier-missing', 'standby 规则文件缺少 HELLOAGENTS 标记', 'Standby carrier is missing the HELLOAGENTS marker'))
197
- if (checks.carrierMarker && !checks.carrierContentMatch) issues.push(buildDoctorIssue('standby-carrier-drift', 'standby 规则文件内容与当前 bootstrap-lite.md 不一致', 'Standby carrier content differs from the current bootstrap-lite.md'))
197
+ if (checks.carrierMarker && !checks.carrierContentMatch) issues.push(buildDoctorIssue('standby-carrier-drift', 'standby 规则文件内容与当前标准模式规则不一致', 'Standby carrier content differs from the current standby rules'))
198
198
  if (!checks.homeLink) issues.push(buildDoctorIssue('standby-link-missing', 'standby home 链接缺失或未指向稳定运行根目录', 'Standby home link is missing or points to a different runtime root'))
199
199
  if (!checks.settingsHooks) issues.push(buildDoctorIssue('standby-hooks-missing', 'standby settings hooks 缺失', 'Standby settings hooks are missing'))
200
200
  if (checks.settingsHooks && !checks.settingsHooksMatch) issues.push(buildDoctorIssue('standby-hooks-drift', 'standby settings hooks 与当前 hooks 配置不一致', 'Standby settings hooks differ from the current hook configuration'))
@@ -29,8 +29,8 @@ function pluginCommands() {
29
29
 
30
30
  function removeHint(msg) {
31
31
  return msg(
32
- '如已安装 Claude Code 插件,建议手动移除: /plugin remove helloagents\n 如已安装 Gemini CLI 扩展,建议手动移除: gemini extensions uninstall helloagents',
33
- 'If Claude Code plugin installed, consider removing: /plugin remove helloagents\n If Gemini CLI extension installed, consider removing: gemini extensions uninstall helloagents',
32
+ '如已安装 Claude Code 插件,可手动移除: /plugin remove helloagents\n 如已安装 Gemini CLI 扩展,可手动移除: gemini extensions uninstall helloagents',
33
+ 'If the Claude Code plugin is installed, you can remove it: /plugin remove helloagents\n If the Gemini CLI extension is installed, you can remove it: gemini extensions uninstall helloagents',
34
34
  )
35
35
  }
36
36
 
@@ -66,7 +66,7 @@ function renderInstallMessage(context, mode, state) {
66
66
  if (install) {
67
67
  return msg(
68
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 bootstrap; ~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)`,
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)`,
70
70
  )
71
71
  }
72
72
 
@@ -76,7 +76,7 @@ function renderInstallMessage(context, mode, state) {
76
76
  : ` 项目可通过 ~wiki 创建/同步知识库,或通过 ~init 完整初始化;未激活项目仅注入通用规则。\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 bootstrap. Unactivated projects get lite rules only.\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)}`,
80
80
  )
81
81
  }
82
82
 
@@ -118,7 +118,7 @@ ${msg('Codex /goal', 'Codex /goal')}:
118
118
  ${msg('仅显式管理 Codex 最新版 [features].goals,不替代 /goal', 'Explicitly manages only latest Codex [features].goals; does not replace /goal')}
119
119
 
120
120
  ${msg('卸载', 'Uninstall')}:
121
- helloagents cleanup ${msg('(推荐先执行,显式清理所有 CLI 注入/链接)', '(recommended first, explicitly cleans CLI injections/links)')}
121
+ helloagents cleanup ${msg('(先清理所有 CLI 注入/链接)', '(cleans all CLI injections/links first)')}
122
122
  npm uninstall -g helloagents
123
123
  ${msg('如宿主命令不可用,另需手动移除:', 'If host commands are unavailable, also remove manually:')}
124
124
  Claude Code: /plugin remove helloagents
@@ -54,17 +54,17 @@ export function buildDeliveryBlockReason(issues, recommendation, gateHint) {
54
54
 
55
55
  lines.push('')
56
56
  if (recommendation?.nextPath) {
57
- lines.push(`建议路径:${recommendation.nextPath}`)
57
+ lines.push(`处理路径:${recommendation.nextPath}`)
58
58
  }
59
59
  if (issues.some((issue) => issue.type === 'missing-closeout-evidence')) {
60
- lines.push('下一步收尾:先写入当前会话 `artifacts/closeout.json`,记录 `requirementsCoverage` 和 `deliveryChecklist`,再报告完成。')
60
+ lines.push('收尾动作:先写入当前会话 `artifacts/closeout.json`,记录 `requirementsCoverage` 和 `deliveryChecklist`,再报告完成。')
61
61
  }
62
62
  if (issues.some((issue) => issue.type === 'missing-visual-evidence')) {
63
- lines.push('下一步视觉验收:先写入当前会话 `artifacts/visual.json`,记录 `tooling`、`screensChecked`、`statesChecked`、`status` 和 `summary`,再报告完成。')
63
+ lines.push('视觉验收动作:先写入当前会话 `artifacts/visual.json`,记录 `tooling`、`screensChecked`、`statesChecked`、`status` 和 `summary`,再报告完成。')
64
64
  }
65
65
  if (gateHint) {
66
66
  lines.push(gateHint)
67
67
  }
68
- lines.push('暂不要报告完成。先完成剩余任务、明确关闭任务,或修复方案包,使其成为可信的交付记录。')
68
+ lines.push('暂不要报告完成。先完成剩余任务、补齐收尾证据,或修复方案包,使其成为可信的交付记录。')
69
69
  return lines.join('\n')
70
70
  }
@@ -81,13 +81,13 @@ export function scanShellSafetyWarnings(command = '') {
81
81
  .map((entry) => entry.trim())
82
82
  .filter(Boolean)
83
83
  if (logicalLines.length > 3) {
84
- warnings.push('PowerShell 内联脚本超过 3 个逻辑行,建议改用临时 .ps1 文件')
84
+ warnings.push('PowerShell 内联脚本超过 3 个逻辑行,请改用临时 .ps1 文件')
85
85
  }
86
86
  }
87
87
 
88
88
  const fileOps = normalized.match(/\b(remove-item|move-item|copy-item|new-item|set-content|add-content|out-file|mkdir|md|touch|cp|copy|mv|move|ren|rename|del|erase|rm|rmdir)\b/ig) || []
89
89
  if (fileOps.length > 1 && /[;\r\n]/.test(normalized)) {
90
- warnings.push('单条 shell 命令串联了多个文件操作,建议拆成独立命令')
90
+ warnings.push('单条 shell 命令串联了多个文件操作,请拆成独立命令')
91
91
  }
92
92
 
93
93
  return warnings
package/scripts/guard.mjs CHANGED
@@ -76,12 +76,12 @@ function buildHighRiskGate(matches, cwd, payload = {}) {
76
76
  if (!recommendation) return null
77
77
  if (matches.some((match) => match.gate === 'post-verify')) {
78
78
  return {
79
- reason: `[HelloAGENTS Guard] 已阻止 T3 命令:当前工作流尚未进入 VERIFY / CONSOLIDATE。\n当前工作流:${recommendation.summary}\n建议路径:${recommendation.nextPath}\n${recommendation.guidance}`,
79
+ reason: `[HelloAGENTS Guard] 已阻止 T3 命令:当前工作流尚未进入 VERIFY / CONSOLIDATE。\n当前工作流:${recommendation.summary}\n处理路径:${recommendation.nextPath}\n${recommendation.guidance}`,
80
80
  }
81
81
  }
82
82
  if (matches.some((match) => match.gate === 'plan-first') && recommendation.nextCommand === 'plan') {
83
83
  return {
84
- reason: `[HelloAGENTS Guard] 已阻止 T3 命令:高风险 schema 变更前仍需先完成 ~plan。\n当前工作流:${recommendation.summary}\n建议路径:${recommendation.nextPath}\n${recommendation.guidance}`,
84
+ reason: `[HelloAGENTS Guard] 已阻止 T3 命令:高风险 schema 变更前仍需先完成 ~plan。\n当前工作流:${recommendation.summary}\n处理路径:${recommendation.nextPath}\n${recommendation.guidance}`,
85
85
  }
86
86
  }
87
87
  return null
@@ -207,7 +207,7 @@ function emitShellWarnings(data, command, highRiskWarnings, shellSafetyWarnings)
207
207
  sections.push(`⚠️ [HelloAGENTS 高风险操作提醒] 检测到高风险命令:\n${highRiskWarnings.map((warning) => ` - ${warning}`).join('\n')}\n请确认已完成相应规划/审查并获得必要授权。`)
208
208
  }
209
209
  if (shellSafetyWarnings.length > 0) {
210
- sections.push(`⚠️ [HelloAGENTS Shell 安全提醒] 检测到建议调整的命令写法:\n${shellSafetyWarnings.map((warning) => ` - ${warning}`).join('\n')}\n当前仅提示,不中断执行。`)
210
+ sections.push(`⚠️ [HelloAGENTS Shell 安全提醒] 检测到需要关注的命令写法:\n${shellSafetyWarnings.map((warning) => ` - ${warning}`).join('\n')}\n当前仅提示,不中断执行。`)
211
211
  }
212
212
  if (sections.length === 0) return
213
213
 
@@ -76,7 +76,7 @@ export function buildCompactionContext({ payload, pkgRoot, settings, bootstrapFi
76
76
  } catch {}
77
77
  if (bootstrap) {
78
78
  summaryParts.push('');
79
- summaryParts.push('## 核心规则(从 bootstrap 重新注入)');
79
+ summaryParts.push('## 核心 HelloAGENTS 规则(重新注入)');
80
80
  summaryParts.push(bootstrap);
81
81
  }
82
82
 
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- // notify.mjs — Unified notification & bootstrap injection for HelloAGENTS
2
+ // notify.mjs — Unified notification and rule injection for HelloAGENTS
3
3
  // Zero external dependencies, ES module, cross-platform
4
4
 
5
5
  import { join, dirname } from 'node:path';
@@ -12,6 +12,7 @@ import { buildCompactionContext, buildInjectContext, buildRouteInstruction, buil
12
12
  import { resolveNotifyHost, shouldIgnoreCodexNotifyClient } from './notify-events.mjs';
13
13
  import { runGateScript } from './notify-gates.mjs';
14
14
  import { normalizeNotifyPayload } from './notify-payload.mjs';
15
+ import { cleanupProjectSessions } from './project-session-cleanup.mjs';
15
16
  import { handleRouteCommand, resolveBootstrapFile } from './notify-route.mjs';
16
17
  import { readSettings, readStdinJson, output, suppressedOutput, emptySuppress } from './notify-shared.mjs';
17
18
  import { clearRouteContext, getApplicableRouteContext, writeRouteContext } from './runtime-context.mjs';
@@ -248,6 +249,7 @@ function cmdInject() {
248
249
  });
249
250
  clearRouteContext({ cwd, payload });
250
251
  clearTurnState(cwd, { payload });
252
+ cleanupProjectSessions(cwd);
251
253
  if (IS_SILENT) {
252
254
  emptySuppress();
253
255
  return;
@@ -0,0 +1,106 @@
1
+ import { existsSync, readdirSync, rmSync } from 'node:fs'
2
+ import { join } from 'node:path'
3
+
4
+ import {
5
+ ACTIVE_SESSION_FILE_NAME,
6
+ CAPSULE_FILE_NAME,
7
+ EVENTS_FILE_NAME,
8
+ PROJECT_ARTIFACTS_DIR_NAME,
9
+ PROJECT_SESSIONS_DIR_NAME,
10
+ getProjectActivationDir,
11
+ getProjectRoot,
12
+ readJsonFile,
13
+ } from './runtime-scope.mjs'
14
+
15
+ function removePath(filePath, result, bucket) {
16
+ try {
17
+ rmSync(filePath, { recursive: true, force: true })
18
+ result[bucket].push(filePath)
19
+ } catch (error) {
20
+ result.errors.push(`${filePath}: ${error.message}`)
21
+ }
22
+ }
23
+
24
+ function isDirectoryEmptyRecursive(dirPath) {
25
+ const entries = readdirSync(dirPath, { withFileTypes: true })
26
+ if (entries.length === 0) return true
27
+ return entries.every((entry) => {
28
+ const entryPath = join(dirPath, entry.name)
29
+ return entry.isDirectory() && isDirectoryEmptyRecursive(entryPath)
30
+ })
31
+ }
32
+
33
+ function listFilesRecursive(dirPath) {
34
+ const entries = readdirSync(dirPath, { withFileTypes: true })
35
+ return entries.flatMap((entry) => {
36
+ const entryPath = join(dirPath, entry.name)
37
+ if (entry.isDirectory()) {
38
+ return listFilesRecursive(entryPath).map((child) => `${entry.name}/${child}`)
39
+ }
40
+ return entry.isFile() ? [entry.name] : []
41
+ })
42
+ }
43
+
44
+ function isRouteOnlySessionDir(sessionDir) {
45
+ if (existsSync(join(sessionDir, 'STATE.md'))) return false
46
+ const files = listFilesRecursive(sessionDir).map((file) => file.replace(/\\/g, '/'))
47
+ if (files.length === 0) return false
48
+ if (!files.includes(`${PROJECT_ARTIFACTS_DIR_NAME}/codex-native-stop.json`)) return false
49
+ return files.every((file) => [
50
+ CAPSULE_FILE_NAME,
51
+ EVENTS_FILE_NAME,
52
+ `${PROJECT_ARTIFACTS_DIR_NAME}/codex-native-stop.json`,
53
+ ].includes(file))
54
+ }
55
+
56
+ function shouldKeepSession(active, workspace, session) {
57
+ const activeWorkspace = active.workspace || active.branch || ''
58
+ return activeWorkspace === workspace && active.session === session
59
+ }
60
+
61
+ export function cleanupProjectSessions(cwd) {
62
+ const projectRoot = getProjectRoot(cwd)
63
+ const activationDir = getProjectActivationDir(projectRoot)
64
+ const sessionsDir = join(activationDir, PROJECT_SESSIONS_DIR_NAME)
65
+ const activePath = join(sessionsDir, ACTIVE_SESSION_FILE_NAME)
66
+ const active = readJsonFile(activePath, null) || {}
67
+ const result = {
68
+ sessionsDir,
69
+ removedEmptyDirs: [],
70
+ removedRouteOnlyDirs: [],
71
+ errors: [],
72
+ }
73
+
74
+ if (!existsSync(sessionsDir)) return result
75
+
76
+ for (const workspaceEntry of readdirSync(sessionsDir, { withFileTypes: true })) {
77
+ if (!workspaceEntry.isDirectory()) continue
78
+ const workspaceDir = join(sessionsDir, workspaceEntry.name)
79
+
80
+ for (const sessionEntry of readdirSync(workspaceDir, { withFileTypes: true })) {
81
+ if (!sessionEntry.isDirectory()) continue
82
+ const sessionDir = join(workspaceDir, sessionEntry.name)
83
+ if (shouldKeepSession(active, workspaceEntry.name, sessionEntry.name)) continue
84
+
85
+ try {
86
+ if (isDirectoryEmptyRecursive(sessionDir)) {
87
+ removePath(sessionDir, result, 'removedEmptyDirs')
88
+ } else if (isRouteOnlySessionDir(sessionDir)) {
89
+ removePath(sessionDir, result, 'removedRouteOnlyDirs')
90
+ }
91
+ } catch (error) {
92
+ result.errors.push(`${sessionDir}: ${error.message}`)
93
+ }
94
+ }
95
+
96
+ try {
97
+ if (isDirectoryEmptyRecursive(workspaceDir)) {
98
+ removePath(workspaceDir, result, 'removedEmptyDirs')
99
+ }
100
+ } catch (error) {
101
+ result.errors.push(`${workspaceDir}: ${error.message}`)
102
+ }
103
+ }
104
+
105
+ return result
106
+ }