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.
- package/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/README.md +26 -20
- package/README_CN.md +24 -18
- package/bootstrap-lite.md +4 -2
- package/bootstrap.md +4 -2
- package/gemini-extension.json +1 -1
- package/package.json +1 -1
- package/scripts/cli-doctor-codex.mjs +5 -5
- package/scripts/cli-doctor-render.mjs +1 -1
- package/scripts/cli-doctor.mjs +2 -2
- package/scripts/cli-messages.mjs +5 -5
- package/scripts/delivery-gate-messages.mjs +4 -4
- package/scripts/guard-rules.mjs +2 -2
- package/scripts/guard.mjs +3 -3
- package/scripts/notify-context.mjs +1 -1
- package/scripts/notify.mjs +3 -1
- package/scripts/project-session-cleanup.mjs +106 -0
- package/scripts/project-storage.mjs +5 -5
- package/scripts/ralph-loop.mjs +1 -1
- package/scripts/runtime-scope.mjs +132 -62
- package/scripts/runtime-user-cleanup.mjs +63 -0
- package/scripts/session-capsule.mjs +29 -2
- package/scripts/session-token.mjs +0 -2
- package/scripts/workflow-core.mjs +1 -1
- package/scripts/workflow-plan-files.mjs +1 -1
- package/scripts/workflow-recommendation.mjs +1 -1
- package/skills/commands/auto/SKILL.md +3 -3
- package/skills/commands/build/SKILL.md +6 -6
- package/skills/commands/clean/SKILL.md +5 -5
- package/skills/commands/commit/SKILL.md +3 -3
- package/skills/commands/init/SKILL.md +3 -3
- package/skills/commands/loop/SKILL.md +2 -2
- package/skills/commands/plan/SKILL.md +7 -7
- package/skills/commands/prd/SKILL.md +7 -6
- package/skills/commands/verify/SKILL.md +2 -2
- package/skills/commands/wiki/SKILL.md +1 -1
- package/skills/hello-arch/SKILL.md +2 -2
- package/skills/hello-errors/SKILL.md +1 -1
- package/skills/hello-subagent/SKILL.md +1 -1
- package/skills/hello-ui/SKILL.md +4 -4
- package/skills/hello-verify/SKILL.md +1 -1
- package/skills/hello-write/SKILL.md +1 -1
- package/skills/helloagents/SKILL.md +9 -10
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "helloagents",
|
|
3
|
-
"version": "3.0.
|
|
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.
|
|
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
|
-
[](./package.json)
|
|
12
12
|
[](https://www.npmjs.com/package/helloagents)
|
|
13
13
|
[](./package.json)
|
|
14
14
|
[](./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
|
|
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/<
|
|
191
|
-
- without a stable session id: `.helloagents/sessions/<
|
|
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/<
|
|
202
|
-
- `.helloagents/sessions/<
|
|
203
|
-
- `.helloagents/sessions
|
|
204
|
-
- `.helloagents/sessions/<
|
|
205
|
-
- `.helloagents/sessions/<
|
|
206
|
-
- `.helloagents/sessions/<
|
|
207
|
-
- `.helloagents/sessions/<
|
|
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
|
|
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/<
|
|
500
|
-
- `.helloagents/sessions/<
|
|
501
|
-
- `.helloagents/sessions
|
|
502
|
-
- `.helloagents/sessions/<
|
|
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
|
|
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,
|
|
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
|
-
-
|
|
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
|
|
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
|
-
[](./package.json)
|
|
12
12
|
[](https://www.npmjs.com/package/helloagents)
|
|
13
13
|
[](./package.json)
|
|
14
14
|
[](./skills)
|
|
@@ -187,8 +187,10 @@ HelloAGENTS 可以在 `.helloagents/` 下创建和维护项目知识库。
|
|
|
187
187
|
|
|
188
188
|
HelloAGENTS 现在只从 `state_path` 解析当前状态文件:
|
|
189
189
|
|
|
190
|
-
- 宿主提供稳定会话标识时:`.helloagents/sessions/<
|
|
191
|
-
- 宿主未提供稳定会话标识时:`.helloagents/sessions/<
|
|
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/<
|
|
202
|
-
- `.helloagents/sessions/<
|
|
203
|
-
- `.helloagents/sessions
|
|
204
|
-
- `.helloagents/sessions/<
|
|
205
|
-
- `.helloagents/sessions/<
|
|
206
|
-
- `.helloagents/sessions/<
|
|
207
|
-
- `.helloagents/sessions/<
|
|
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/<
|
|
502
|
-
- `.helloagents/sessions/<
|
|
503
|
-
- `.helloagents/sessions
|
|
504
|
-
- `.helloagents/sessions/<
|
|
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 注入
|
|
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
|
|
677
|
+
`docs/` 只作为用户和 AI 理解项目的参考材料,可能滞后于实现。运行时行为以源码、规则模板、skills、templates 和测试为准。
|
|
672
678
|
|
|
673
679
|
### 这是 CLI 工具还是提示词框架?
|
|
674
680
|
|
|
675
681
|
两者都是。
|
|
676
682
|
|
|
677
683
|
- `cli.mjs` 负责安装、更新、清理、诊断和宿主配置
|
|
678
|
-
-
|
|
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
|
-
不会显示
|
|
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/{
|
|
211
|
-
- `state_path` 是状态文件的唯一位置。宿主提供会话标识时,写入 `.helloagents/sessions/{
|
|
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/{
|
|
277
|
-
- `state_path` 是状态文件的唯一位置。宿主提供会话标识时,写入 `.helloagents/sessions/{
|
|
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/`。
|
package/gemini-extension.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "helloagents",
|
|
3
|
-
"version": "3.0.
|
|
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`
|
|
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`
|
|
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
|
|
116
|
-
if (checks.pluginCache && !checks.pluginCacheCarrierMatch) issues.push(buildDoctorIssue(runtime, 'global-plugin-cache-carrier-drift', 'global 插件缓存中的 AGENTS.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
|
|
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) }
|
package/scripts/cli-doctor.mjs
CHANGED
|
@@ -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
|
|
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
|
|
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'))
|
package/scripts/cli-messages.mjs
CHANGED
|
@@ -29,8 +29,8 @@ function pluginCommands() {
|
|
|
29
29
|
|
|
30
30
|
function removeHint(msg) {
|
|
31
31
|
return msg(
|
|
32
|
-
'如已安装 Claude Code
|
|
33
|
-
'If Claude Code plugin installed,
|
|
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
|
|
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
|
|
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('
|
|
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(
|
|
57
|
+
lines.push(`处理路径:${recommendation.nextPath}`)
|
|
58
58
|
}
|
|
59
59
|
if (issues.some((issue) => issue.type === 'missing-closeout-evidence')) {
|
|
60
|
-
lines.push('
|
|
60
|
+
lines.push('收尾动作:先写入当前会话 `artifacts/closeout.json`,记录 `requirementsCoverage` 和 `deliveryChecklist`,再报告完成。')
|
|
61
61
|
}
|
|
62
62
|
if (issues.some((issue) => issue.type === 'missing-visual-evidence')) {
|
|
63
|
-
lines.push('
|
|
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
|
}
|
package/scripts/guard-rules.mjs
CHANGED
|
@@ -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
|
|
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
|
|
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
|
|
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 安全提醒]
|
|
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('##
|
|
79
|
+
summaryParts.push('## 核心 HelloAGENTS 规则(重新注入)');
|
|
80
80
|
summaryParts.push(bootstrap);
|
|
81
81
|
}
|
|
82
82
|
|
package/scripts/notify.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
// notify.mjs — Unified notification
|
|
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
|
+
}
|