@xgent-ai/skills 0.4.0 → 0.6.0
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/README.md +94 -4
- package/bin/xgent-skills.js +221 -17
- package/docs/claude-context-goal-guard.md +124 -0
- package/docs/codex-context-goal-guard.md +109 -0
- package/hooks/claude/context-goal-guard.js +139 -0
- package/hooks/claude/settings.example.json +26 -0
- package/hooks/codex/context-goal-guard.py +189 -0
- package/hooks/codex/hooks.example.json +26 -0
- package/package.json +7 -1
- package/skills/agi-mode/SKILL.md +27 -2
- package/skills/agi-mode/assets/directory-index.md +18 -0
- package/skills/agi-mode/assets/sdlc/event.md +33 -0
- package/skills/agi-mode/assets/sdlc/index.md +17 -0
- package/skills/agi-mode/assets/sdlc/object-status.md +25 -0
- package/skills/agi-mode/assets/sdlc/protocol.md +98 -0
- package/skills/agi-mode/assets/sdlc/state-model.md +78 -0
- package/skills/agi-mode/assets/sdlc/type-index.md +10 -0
- package/skills/agi-mode/evals/scenarios.md +45 -0
- package/skills/agi-mode/playbooks/program.md +1 -1
- package/skills/agi-mode/playbooks/reflection.md +8 -0
- package/skills/agi-mode/playbooks/sdlc.md +99 -0
- package/skills/agi-mode/playbooks/what-next.md +79 -0
- package/skills/agi-mode/references/continuity.md +3 -1
- package/skills/agi-mode/references/workspace-layout.md +76 -0
- package/skills/apply-code-review/SKILL.md +17 -1
- package/skills/apply-code-review/references/record-contract.md +14 -1
- package/skills/apply-doc-review/SKILL.md +30 -6
- package/skills/apply-doc-review/references/disposition-contract.md +15 -2
- package/skills/archify/SKILL.md +1 -1
- package/skills/architect/SKILL.md +1 -1
- package/skills/arena/SKILL.md +1 -1
- package/skills/automate-me/SKILL.md +1 -1
- package/skills/autoresearch/SKILL.md +1 -1
- package/skills/crd/SKILL.md +106 -0
- package/skills/crd/assets/cr-template.md +66 -0
- package/skills/debugging/SKILL.md +1 -1
- package/skills/dev-plan/SKILL.md +16 -7
- package/skills/dev-plan/references/plan-skeleton.md +8 -6
- package/skills/dev-plan/scripts/check_progress.sh +2 -2
- package/skills/documentation-writer/SKILL.md +1 -1
- package/skills/elintp/SKILL.md +1 -1
- package/skills/experience-capture/SKILL.md +64 -0
- package/skills/experience-capture/agents/openai.yaml +5 -0
- package/skills/figure-it-out/SKILL.md +1 -1
- package/skills/gdpr-compliant/SKILL.md +1 -1
- package/skills/how/SKILL.md +1 -1
- package/skills/humanize-writing/SKILL.md +1 -1
- package/skills/kpi-dashboard-design/SKILL.md +1 -1
- package/skills/landing-page-conversion-audit/SKILL.md +1 -1
- package/skills/meeting-minutes/SKILL.md +1 -1
- package/skills/pardon/SKILL.md +1 -1
- package/skills/portal-app-exchange/SKILL.md +1 -1
- package/skills/portal-dev-setup/SKILL.md +1 -1
- package/skills/portal-external-app/SKILL.md +1 -1
- package/skills/portal-logging/SKILL.md +1 -1
- package/skills/portal-micro-app/SKILL.md +1 -1
- package/skills/prd/SKILL.md +8 -1
- package/skills/react/SKILL.md +1 -11
- package/skills/reflect/SKILL.md +1 -1
- package/skills/review-code/SKILL.md +25 -4
- package/skills/review-code/references/report-contract.md +17 -1
- package/skills/review-dev-plan/SKILL.md +22 -2
- package/skills/review-dev-plan/references/report-contract.md +30 -0
- package/skills/review-prd/SKILL.md +22 -2
- package/skills/review-prd/references/report-contract.md +30 -0
- package/skills/review-prd-dev-gaps/SKILL.md +24 -4
- package/skills/review-prd-dev-gaps/references/report-contract.md +14 -0
- package/skills/rust/SKILL.md +1 -10
- package/skills/security-audit/SKILL.md +1 -1
- package/skills/sql-optimization/SKILL.md +1 -1
- package/skills/story-points/SKILL.md +2 -1
- package/skills/summarize/SKILL.md +1 -1
- package/skills/swarm/SKILL.md +1 -1
- package/skills/tdd/SKILL.md +1 -1
- package/skills/teach/SKILL.md +1 -1
- package/skills/test-plan/SKILL.md +2 -1
- package/skills/why/SKILL.md +1 -1
- package/skills/working-with-mbx/SKILL.md +1 -1
- package/skills/working-with-mise/SKILL.md +1 -1
- package/skills/xgent-app-release/SKILL.md +1 -1
- package/skills/xgent-image-push/SKILL.md +1 -1
- package/skills/xgent-init/SKILL.md +1 -1
package/README.md
CHANGED
|
@@ -16,9 +16,9 @@ npx skills add XGENT-ai/skills
|
|
|
16
16
|
npx skills add XGENT-ai/skills --skill dev-plan
|
|
17
17
|
```
|
|
18
18
|
|
|
19
|
-
## Claude Code
|
|
19
|
+
## 项目辅助工具(Claude Code / Codex)
|
|
20
20
|
|
|
21
|
-
本仓库同时以 [`@xgent-ai/skills`](https://www.npmjs.com/package/@xgent-ai/skills) 发布到 npm,自带 `xgent-skills` 命令,可为任意项目安装 XGENT 的 Claude Code hooks(当前包含 statusline)、在项目 `.claude/settings.json` 中启用对应配置,装上随包 vendor 的 [impeccable](#vendor-的-impeccable),并可选创建通用的 `AGENTS.md
|
|
21
|
+
本仓库同时以 [`@xgent-ai/skills`](https://www.npmjs.com/package/@xgent-ai/skills) 发布到 npm,自带 `xgent-skills` 命令,可为任意项目安装 XGENT 的 Claude Code hooks(当前包含 statusline)、在项目 `.claude/settings.json` 中启用对应配置,装上随包 vendor 的 [impeccable](#vendor-的-impeccable),并可选创建通用的 `AGENTS.md`、安装 Codex 或 Claude Code 的 goal 上下文收尾提醒:
|
|
22
22
|
|
|
23
23
|
```bash
|
|
24
24
|
# 在目标项目根目录执行(也可显式传目录:npx @xgent-ai/skills install <dir>)
|
|
@@ -32,6 +32,12 @@ npx @xgent-ai/skills install
|
|
|
32
32
|
| `--no-impeccable` | 跳过 impeccable,仍安装 XGENT 的 hooks 与 settings |
|
|
33
33
|
| `--xgent-init` | 直接创建仓根 `AGENTS.md` (已有则跳过),不再询问 |
|
|
34
34
|
| `--no-xgent-init` | 跳过创建 `AGENTS.md`,不再询问 |
|
|
35
|
+
| `--context-goal-guard` | 显式安装 Codex goal 上下文收尾提醒(默认不安装);需要 Python 3.9+ |
|
|
36
|
+
| `--no-context-goal-guard` | 跳过 Codex goal guard(默认行为);已有 guard 保留 |
|
|
37
|
+
| `--context-goal-guard-threshold=N` | Codex guard 的触发阈值百分比(1–99 整数,默认 65),同时表示安装;重装不给则沿用已装的值 |
|
|
38
|
+
| `--claude-context-goal-guard` | 显式安装 Claude Code goal 上下文收尾提醒(默认不安装) |
|
|
39
|
+
| `--no-claude-context-goal-guard` | 跳过 Claude Code goal guard(默认行为);已有 guard 保留 |
|
|
40
|
+
| `--claude-context-goal-guard-threshold=N` | Claude Code guard 的触发阈值百分比(1–99 整数,默认 70),同时表示安装;重装不给则沿用已装的值 |
|
|
35
41
|
| `--providers=a,b` | 指定 impeccable 装进哪些 harness 目录(如 `--providers=.claude,.cursor`);默认按项目里已有的目录判断,一个都没有时只装 `.claude` |
|
|
36
42
|
| `--force` | 强制重装,并允许覆盖非法 JSON 的 hook 配置(先存 `.bak`);不覆盖已有 `AGENTS.md` |
|
|
37
43
|
|
|
@@ -41,6 +47,20 @@ npx @xgent-ai/skills install
|
|
|
41
47
|
|
|
42
48
|
非交互环境默认跳过,可用 `--xgent-init` 显式创建,或用 `--no-xgent-init` 跳过询问。文件位于仓根,不受 `--providers` 影响。模板没有待填占位,通用编码准则支持不同 coding agent;Portal App 的 onebox 联调与有前端改动时的真实浏览器验收分别按适用条件执行。
|
|
43
49
|
|
|
50
|
+
`install` 默认不安装 Codex goal 上下文收尾提醒,也不询问;仅在显式传入 `--context-goal-guard` 或 `--context-goal-guard-threshold=N` 时安装。此选项不受 `--providers` 或 `--no-impeccable` 影响。请安装到 Git 仓库根目录;Codex 运行环境需要 git 和 Python 3.9+。显式安装时先检查含 SQLite 标准库的 Python 3.9+,复制脚本到 `.codex/hooks/context-goal-guard.py`,合并 `.codex/hooks.json` 的同步 `PreToolUse` / `Stop` handler(3 秒超时),运行时从 Git 根目录定位脚本,配置不包含本机项目绝对路径,保留其他 hooks 与配置;重复安装只更新 guard,不重复添加。
|
|
51
|
+
|
|
52
|
+
安装后会显示用户必须完成的步骤:从目标项目启动 Codex、信任项目 `.codex/` 层,在 `/hooks` 中审阅、信任并启用两个 handler,对**当前 goal** 明确超过阈值(默认 65%)时先保存进度和交接、再暂停的策略。安装输出提供可复制的指令;安装和信任本身不构成暂停授权。恢复 goal 或新开对话后需重新明确策略。当前仅验证 Codex 0.160.0、macOS arm64,完整限制与停用方法见 [启用说明](docs/codex-context-goal-guard.md)。
|
|
53
|
+
|
|
54
|
+
Codex guard 已接入源码与 npm 打包清单,尚未发布到 npm;发布后可用 `npx @xgent-ai/skills install --context-goal-guard`。当前可从本仓库源码为目标项目安装:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
node bin/xgent-skills.js install /absolute/path/to/project --context-goal-guard
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
`install` 默认不安装 Claude Code goal 上下文收尾提醒,也不询问;仅在显式传入 `--claude-context-goal-guard` 或 `--claude-context-goal-guard-threshold=N` 时安装,不受 `--providers` 或 `--no-impeccable` 影响。显式安装时复制脚本到 `.claude/hooks/context-goal-guard.js`,在个人的 `.claude/settings.local.json` 合并 `PostToolBatch` / `Stop` 两个 handler(5 秒超时),保留其他 hooks 与设置;重复安装只更新 guard。guard 只读当前会话记录:本会话 `/goal` 仍 active 且估算上下文严格超过阈值(默认 70%)时提醒 agent 按既有约定更新进度并交接,回合结束时由 Stop hook 结束回合,Claude Code 原生把 goal 置为 Goal paused,再由你在同一项目目录新开对话或 `/clear` 后重新设置 goal。hook 不写任何文件,也不清除或转移 goal。
|
|
61
|
+
|
|
62
|
+
安装后需重启会话、信任工作区,并在 `/hooks` 中确认两个 handler 来源为 local settings。当前仅验证 Claude Code 2.1.288 交互式 CLI、macOS arm64 与 Opus 5.5 / Sonnet 5.5 / Haiku 4.5,完整限制、接续与停用方法见 [启用说明](docs/claude-context-goal-guard.md)。从源码安装:`node bin/xgent-skills.js install /absolute/path/to/project --claude-context-goal-guard`。
|
|
63
|
+
|
|
44
64
|
Portal 的产品和设计规范仍保留在 [PRODUCT 模板](skills/xgent-init/references/external-app-PRODUCT.template.md) 与 [DESIGN 模板](skills/xgent-init/references/external-app-DESIGN.template.md) 中。需要生成项目上下文时,显式安装并在 Agent 对话中使用 [xgent-init](skills/xgent-init/SKILL.md),它读取清单与代码事实,补齐 PRODUCT.md / DESIGN.md (无前端的 service 型不新生成 DESIGN.md),已有文件保留:
|
|
45
65
|
|
|
46
66
|
```bash
|
|
@@ -81,6 +101,7 @@ node scripts/publish-vendor-r2.mjs # engine 传 R2,下载地址回写 VERSION
|
|
|
81
101
|
| Skill | 说明 |
|
|
82
102
|
| --- | --- |
|
|
83
103
|
| [prd](skills/prd/SKILL.md) | 撰写或优化 PRD,明确产品目标、FR/NFR、UAT、分期与终验,可按授权录入 SPMS |
|
|
104
|
+
| [crd](skills/crd/SKILL.md) | 以整份 CRD 往返协作:起草需求、文末追加答复、整合对方返回版本并维护 Q&A |
|
|
84
105
|
| [dev-plan](skills/dev-plan/SKILL.md) | 基于需求、仓库规则与代码事实撰写或评审可执行、可跨对话续做的开发计划 |
|
|
85
106
|
| [test-plan](skills/test-plan/SKILL.md) | 从需求与验收标准生成测试用例,覆盖正常、边界、权限和并发场景,可按授权写入 SPMS |
|
|
86
107
|
| [story-points](skills/story-points/SKILL.md) | 按客观因子估算故事点,回写 SPMS 规划点数并复核 Sprint 容量 |
|
|
@@ -89,7 +110,69 @@ node scripts/publish-vendor-r2.mjs # engine 传 R2,下载地址回写 VERSION
|
|
|
89
110
|
| [review-code](skills/review-code/SKILL.md) | 评审未提交变更、commit 或分支差异,可对照开发计划,输出有证据的代码评审报告 |
|
|
90
111
|
| [review-prd-dev-gaps](skills/review-prd-dev-gaps/SKILL.md) | 核对 PRD 与开发交付,将遗漏、合理变更和待拍板差异分流,交互 Triage 后按需调用 dev-plan 生成 gaps plan |
|
|
91
112
|
| [apply-code-review](skills/apply-code-review/SKILL.md) | 核实代码评审意见,实施合理修复、验证结果并回写实现记录与必要进度 |
|
|
92
|
-
| [apply-doc-review](skills/apply-doc-review/SKILL.md) |
|
|
113
|
+
| [apply-doc-review](skills/apply-doc-review/SKILL.md) | 可只传评审报告,沿报告的原文档引用定位并修订 PRD 或开发计划,复核并记录逐条处置结果 |
|
|
114
|
+
|
|
115
|
+
把上述 skill 串成完整交付流水线(想法 → PRD → 分期 → 每期开发与并行测试 → 交付)的方法见 [AI Native SDLC](docs/ai-native-sdlc.md),含各环节产物路径约定与测试线待补环节的现状核对。
|
|
116
|
+
|
|
117
|
+
在任意阶段通过 `$agi-mode sdlc <问题>` 或自然语言获取 [SDLC 指引](skills/agi-mode/playbooks/sdlc.md):解释 PRD、CRD、计划与测试的分工,判断交接条件,选择下一步。手册随 agi-mode 分发;咨询默认只读,涉及项目现状时复用 what-next 核对证据,实际能力以当前项目和已安装技能为准。
|
|
118
|
+
|
|
119
|
+
这 10 个 SDLC skill 及 `agi-mode` 均在 `SKILL.md` 的 `argument-hint` 中提供参数提示。`<…>` 表示任务所需输入,可沿已有上下文或文档引用定位;`[…]` 是可选补充,`/` 分隔同一位置的备选,不是要求照抄的参数或新增命令解析器。例如:
|
|
120
|
+
|
|
121
|
+
```text
|
|
122
|
+
$review-prd <PRD路径/链接/内容> [上轮报告] [复审/完整评审] [问题ID/范围] [报告路径] [仅聊天]
|
|
123
|
+
$review-code [未提交/commit/A..B/基准分支] [上轮报告] [复审/完整评审] [问题ID/文件范围] [开发计划] [报告路径] [仅聊天]
|
|
124
|
+
$apply-doc-review <文档评审报告> [原文路径] [上轮报告/处置记录] [修复/仅复核] [问题ID/范围]
|
|
125
|
+
$agi-mode <任务描述> 或 sdlc [流程/阶段/问题] 或 init-sdlc [PRD/计划/范围] 或 what-next [查询/更新] [PRD/计划/范围]
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
提示的展示取决于客户端:[Claude Code](https://code.claude.com/docs/en/skills#frontmatter-reference) 在 `/skill` 补全中支持 `argument-hint`;Codex 的 `$skill` 参数预览仍有[未关闭的功能请求](https://github.com/openai/codex/issues/31014),不能仅凭新增字段保证弹出提示。未展示时可直接参考上述用法或各技能的 frontmatter。
|
|
129
|
+
|
|
130
|
+
4 个 `review-*` 支持“对照上轮报告复审修复效果”:逐项保留来源 ID,区分已解决、仍存在、部分解决、回归、待核实、不再适用和本轮未复核;新增问题单列,默认另存报告。代码旧问题的复核不受本次修复 diff 限制。`review-prd-dev-gaps` 会先核对已有 gaps plan,支持“仅报告”,避免重复规划。
|
|
131
|
+
|
|
132
|
+
2 个 `apply-*` 支持“继续修复”与“仅复核”:前者处理剩余问题,后者保留目标产物并保存必要处置记录;完全只读则仅聊天交付。重复执行先核对已有证据,无实质变化不改文件或时间;apply 的复核不自动成为新一轮独立 review。
|
|
133
|
+
|
|
134
|
+
项目状态与下一步能力已合并到 `agi-mode` 的 [what-next 流程](skills/agi-mode/playbooks/what-next.md),不再单独发布 `what-next` skill。查询默认只读;初始化/更新才保存,既有执行授权继续有效。
|
|
135
|
+
|
|
136
|
+
```text
|
|
137
|
+
使用 $agi-mode sdlc,解释从需求、CRD 往返到开发、验收和发布的交接。
|
|
138
|
+
使用 $agi-mode init-sdlc 初始化项目状态跟进。
|
|
139
|
+
使用 $agi-mode what-next 看当前项目状态和下一步。
|
|
140
|
+
使用 $agi-mode what-next 更新状态,核对并行计划和最近几轮评审。
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
`init-sdlc` 按需创建状态目录和索引,核实并登记现有材料;可重复运行,沿用已有台账并补齐缺项,不重置历史。兼容原有 `what-next 初始化` 写法。其他 SDLC skill 在台账启用后维护相关状态,首次启用可直接运行上述初始化入口。
|
|
144
|
+
|
|
145
|
+
[状态目录约定](skills/agi-mode/references/workspace-layout.md)使用仓根 `.xgent-ai/sdlc/` **只保存开发状态**。PRD、开发计划、评审报告、实施/验收记录和证据继续按用户习惯存放,台账通过链接引用,不改变其路径或复制正文。
|
|
146
|
+
|
|
147
|
+
```text
|
|
148
|
+
.xgent-ai/
|
|
149
|
+
index.md 工作状态总入口
|
|
150
|
+
sdlc/
|
|
151
|
+
index.md 本层导航与当前重点
|
|
152
|
+
protocol.md 状态回写和索引维护协议
|
|
153
|
+
state-model.md 固定状态、证据门槛和自愈规则
|
|
154
|
+
event-template.md 状态变化模板
|
|
155
|
+
status/
|
|
156
|
+
index.md 类型入口
|
|
157
|
+
<prd|plan|review>/
|
|
158
|
+
index.md 对象目录
|
|
159
|
+
<对象UUID>.md 各 PRD、计划、评审的状态
|
|
160
|
+
events/
|
|
161
|
+
index.md 事件类型入口
|
|
162
|
+
<类型>/
|
|
163
|
+
index.md 对象入口
|
|
164
|
+
<对象UUID>/
|
|
165
|
+
index.md 事件清单
|
|
166
|
+
<事件UUID>.md 单次变化
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
每个实际创建的状态目录都有 `index.md`,非开发任务的 `tasks/` 及任务子目录也一样;不预建空目录。索引只列本层内容,数量增多后可按领域/年份分片。写入者按[索引维护规范](skills/agi-mode/assets/sdlc/protocol.md#目录索引维护)同步受影响入口,无变化不重写;多机合并保留双方条目并核对实际文件,查询只报告缺项。索引文件不算事件。
|
|
170
|
+
|
|
171
|
+
状态按对象拆分、历史按需读取。PRD 与计划保持多对多关系,每轮评审有独立状态 ID,原报告文件名不必改变。UUID 事件保留并发记录,冲突待核对,不用机器时间覆盖。
|
|
172
|
+
|
|
173
|
+
[固定状态模型](skills/agi-mode/assets/sdlc/state-model.md)将文档就绪、计划实施、每轮评审及处置分开:例如 `dev-plan-ready` 表示可开工,`dev-plan-completed` 表示实施范围和规定验证已完成。what-next 会从 `.review.md`、`.codereview.md`、`.code-review.md` 等候选补查漏记评审,并从报告处置节、`.applied.md` 或实施记录核实整改。原计划状态可能滞后,足够的实现/验证证据可纠正 SDLC 状态;原文自述、差异及证据质量仍保留。查询只读重算,更新才保存修复;证据不足用 `unknown`,独立验收线枚举暂为 TBD。
|
|
174
|
+
|
|
175
|
+
相关撰写、评审、修复技能和计划实施模板仅增加状态回写规则,原产物落盘方式保持原有约定。已有台账可继续使用,不自动迁移或双写。状态协议随仓同步,另一台机器无需安装所有技能也能回写;状态已同步不代表原文和证据已同步。安装 `agi-mode`:`npx skills add XGENT-ai/skills --skill agi-mode`。
|
|
93
176
|
|
|
94
177
|
### 开发、调试与质量
|
|
95
178
|
|
|
@@ -109,16 +192,19 @@ node scripts/publish-vendor-r2.mjs # engine 传 R2,下载地址回写 VERSION
|
|
|
109
192
|
|
|
110
193
|
| Skill | 说明 |
|
|
111
194
|
| --- | --- |
|
|
112
|
-
| [agi-mode](skills/agi-mode/SKILL.md) |
|
|
195
|
+
| [agi-mode](skills/agi-mode/SKILL.md) | 自主推进复杂任务到可验证交付;含 SDLC 阶段指引、项目状态/what-next 与分类状态记录 |
|
|
113
196
|
| [arena](skills/arena/SKILL.md) | agi-mode 的多候选比较兼容入口,选择基础版本并重新验证合成结果 |
|
|
114
197
|
| [swarm](skills/swarm/SKILL.md) | 为任务选择多 agent 协作机制,设计角色、分工、执行与收尾流程 |
|
|
115
198
|
| [autoresearch](skills/autoresearch/SKILL.md) | agi-mode 的 Hillclimb 兼容入口,在固定协议下搜索并确认改进 |
|
|
116
199
|
| [reflect](skills/reflect/SKILL.md) | agi-mode 的 Reflection 兼容入口,从会话证据提炼并验证改进假设 |
|
|
200
|
+
| [experience-capture](skills/experience-capture/SKILL.md) | 开发中轻量收集踩坑、纠正及自动化线索,供用户随后发起复盘 |
|
|
117
201
|
|
|
118
202
|
自进化流程集中在 `agi-mode` 内:[Eval](skills/agi-mode/playbooks/eval.md) 建立可信判定,[Hillclimb](skills/agi-mode/playbooks/hillclimb.md) 管理搜索,[Arena](skills/agi-mode/playbooks/arena.md) 提供不同候选,[Reflection](skills/agi-mode/playbooks/reflection.md) 提炼教训。协作与记录约定见 [技能演化](skills/agi-mode/references/skill-evolution.md)。
|
|
119
203
|
|
|
120
204
|
只需安装 `agi-mode` 即可使用上述流程;保留的 `autoresearch`、`arena`、`reflect` 名称是兼容入口,需要同时安装 `agi-mode`。它们不再独立维护执行规则。
|
|
121
205
|
|
|
206
|
+
`experience-capture` 可独立安装,默认允许自动选择;本仓 `AGENTS.md` 也提供触发约定。它只在开发的自然间隙,把当前上下文已有的线索用 3–4 行保存到 `.xgent-ai/experience/`,不打断主任务,不额外检索取证或回读完整记录;没有合适间隙则跳过,纯咨询和只读任务不落盘。自动选择不等于可靠的后台事件监听;其他项目可在自己的 `AGENTS.md` 中约定出现这些信号时读取已安装的 skill。任务结束后用 `$agi-mode 复盘` 或 `$agi-mode reflect` 深入挖掘、查找和核对证据;默认给出建议,明确授权沉淀时落实到 know-how、playbook、principle 或自动化工具,并回写处置。
|
|
207
|
+
|
|
122
208
|
整体方法见 [agi-mode 自进化方法论](docs/agi-mode-evolution-methodology.md),说明样本沉淀、重放、进化实践和能力评估,以及通用方法与业务实践案例的边界。
|
|
123
209
|
|
|
124
210
|
### 文档、表达与图示
|
|
@@ -157,6 +243,10 @@ node scripts/publish-vendor-r2.mjs # engine 传 R2,下载地址回写 VERSION
|
|
|
157
243
|
|
|
158
244
|
每个 skill 位于 `skills/<name>/` 目录下,包含一个带 `name` 与 `description` frontmatter 的 `SKILL.md`:
|
|
159
245
|
|
|
246
|
+
`description` 用于加载前的技能选择,按「触发条件与关键排除条件 → 核心产出」组织。整条建议不超过 200 字符,中文尽量在 100 字符左右;前 100 字符应能独立表达适用边界。这是本仓库的编辑目标,不是所有 coding agent 的统一截断上限。
|
|
247
|
+
|
|
248
|
+
容易混淆的限制要紧跟触发条件,例如「仅写/评审计划,不用于按计划实施」,不能放在长段落末尾或只留在正文。操作步骤、完整错误码清单、工具细节和重复的双语说明放入正文或 references;精简后检查前缀是否仍表达原意,不要直接机械截字。
|
|
249
|
+
|
|
160
250
|
```
|
|
161
251
|
skills/
|
|
162
252
|
└── dev-plan/
|
package/bin/xgent-skills.js
CHANGED
|
@@ -19,6 +19,12 @@ const BUNDLE_DIR = path.join(VENDOR_DIR, 'bundle');
|
|
|
19
19
|
const BLOBS_DIR = path.join(BUNDLE_DIR, 'blobs');
|
|
20
20
|
const MANIFEST_FILE = path.join(BUNDLE_DIR, 'manifest.json');
|
|
21
21
|
const AGENTS_TEMPLATE = path.join(PKG_ROOT, 'skills', 'xgent-init', 'references', 'external-app-AGENTS.template.md');
|
|
22
|
+
const CONTEXT_GOAL_GUARD_SRC = path.join(PKG_ROOT, 'hooks', 'codex', 'context-goal-guard.py');
|
|
23
|
+
// 不放进 .claude/hooks:那里的文件会被无条件复制到目标项目,绕过用户选择。
|
|
24
|
+
const CLAUDE_CONTEXT_GOAL_GUARD_SRC = path.join(PKG_ROOT, 'hooks', 'claude', 'context-goal-guard.js');
|
|
25
|
+
// 与两份脚本内置的默认阈值一致;安装器总是把阈值写进 handler 命令,在 /hooks 里可见。
|
|
26
|
+
const CONTEXT_GOAL_GUARD_DEFAULT_THRESHOLD = 65;
|
|
27
|
+
const CLAUDE_CONTEXT_GOAL_GUARD_DEFAULT_THRESHOLD = 70;
|
|
22
28
|
|
|
23
29
|
// 写入目标项目 .claude/settings.json 的配置,按顶层 key 合并:
|
|
24
30
|
// 这里列出的 key 以本包为准覆盖,其余已有配置保持不动。
|
|
@@ -503,23 +509,167 @@ function installImpeccable(targetDir, options) {
|
|
|
503
509
|
|
|
504
510
|
// ─── install ────────────────────────────────────────────────────────────────
|
|
505
511
|
|
|
506
|
-
async function
|
|
512
|
+
async function confirm(question, skipMessage, answers) {
|
|
507
513
|
if (!process.stdin.isTTY) {
|
|
508
|
-
console.log(
|
|
514
|
+
console.log(skipMessage);
|
|
509
515
|
return false;
|
|
510
516
|
}
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
517
|
+
process.stdout.write(question);
|
|
518
|
+
const { value = '' } = await answers.next();
|
|
519
|
+
return /^(y|yes)$/i.test(value.trim());
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
// 重装没给阈值 flag 时沿用旧 handler 里的值。
|
|
523
|
+
function guardThreshold(command) {
|
|
524
|
+
return Number(/ --threshold ([1-9][0-9]?)$/.exec(command)?.[1]) || undefined;
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
function installContextGoalGuard(targetDir, force, threshold) {
|
|
528
|
+
const python = spawnSync('python3', ['-c', 'import sys, sqlite3; sys.exit(0 if sys.version_info >= (3, 9) else 1)'],
|
|
529
|
+
{ encoding: 'utf8', timeout: 5000 });
|
|
530
|
+
if (python.status !== 0) {
|
|
531
|
+
throw new Error('Codex goal guard 需要含 sqlite3 的 Python 3.9 或更高版本。请先安装并用 python3 --version 核对,确保 Codex 运行环境也能找到 python3,再重试;或加 --no-context-goal-guard 跳过。');
|
|
532
|
+
}
|
|
533
|
+
const manifestPath = path.join(targetDir, '.codex', 'hooks.json');
|
|
534
|
+
let existing = {};
|
|
535
|
+
let backup = false;
|
|
536
|
+
if (fs.existsSync(manifestPath)) {
|
|
537
|
+
try {
|
|
538
|
+
existing = readJson(manifestPath);
|
|
539
|
+
} catch (error) {
|
|
540
|
+
if (!(error instanceof SyntaxError)) throw error;
|
|
541
|
+
if (!force) throw new Error(`${manifestPath} 不是合法 JSON,未修改;请先手动修复,或加 --force 备份为 .bak 后覆盖。`);
|
|
542
|
+
backup = true;
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
// 合法 JSON 的未知结构不能当成空配置,否则会丢失用户的 hooks。
|
|
546
|
+
if (!existing || typeof existing !== 'object' || Array.isArray(existing)
|
|
547
|
+
|| (existing.hooks !== undefined && (!existing.hooks || typeof existing.hooks !== 'object' || Array.isArray(existing.hooks)))
|
|
548
|
+
|| Object.values(existing.hooks || {}).some((entries) => !Array.isArray(entries))) {
|
|
549
|
+
throw new Error(`${manifestPath} 的 hooks 结构不受支持,未修改;请先手动修复为事件数组。`);
|
|
550
|
+
}
|
|
551
|
+
const scriptPath = path.join(fs.realpathSync(targetDir), '.codex', 'hooks', 'context-goal-guard.py');
|
|
552
|
+
let previous;
|
|
553
|
+
const hooks = { ...existing.hooks };
|
|
554
|
+
for (const event of ['PreToolUse', 'Stop']) {
|
|
555
|
+
const kept = [];
|
|
556
|
+
for (const entry of hooks[event] || []) {
|
|
557
|
+
if (!Array.isArray(entry?.hooks)) {
|
|
558
|
+
kept.push(entry);
|
|
559
|
+
continue;
|
|
560
|
+
}
|
|
561
|
+
const handlers = entry.hooks.filter((handler) => {
|
|
562
|
+
const guard = handler?.type === 'command' && typeof handler.command === 'string'
|
|
563
|
+
&& /\.codex\/hooks\/context-goal-guard\.py(?:['"\s]|$)/.test(handler.command);
|
|
564
|
+
if (guard) previous ??= guardThreshold(handler.command);
|
|
565
|
+
return !guard;
|
|
566
|
+
});
|
|
567
|
+
if (handlers.length === entry.hooks.length) kept.push(entry);
|
|
568
|
+
else if (handlers.length > 0) kept.push({ ...entry, hooks: handlers });
|
|
569
|
+
}
|
|
570
|
+
hooks[event] = kept;
|
|
571
|
+
}
|
|
572
|
+
const limit = threshold ?? previous ?? CONTEXT_GOAL_GUARD_DEFAULT_THRESHOLD;
|
|
573
|
+
// 运行时从 Git 根目录定位,避免配置绑定安装机器或会话子目录。
|
|
574
|
+
const command = `python3 "$(git rev-parse --show-toplevel)/.codex/hooks/context-goal-guard.py" --threshold ${limit}`;
|
|
575
|
+
for (const event of ['PreToolUse', 'Stop']) hooks[event].push({ hooks: [{ type: 'command', command, timeout: 3 }] });
|
|
576
|
+
const script = fs.readFileSync(CONTEXT_GOAL_GUARD_SRC);
|
|
577
|
+
const manifest = Buffer.from(JSON.stringify({ ...existing, hooks }, null, 2) + '\n');
|
|
578
|
+
if (backup) fs.copyFileSync(manifestPath, `${manifestPath}.bak`);
|
|
579
|
+
console.log(` ${writeFileIfChanged(scriptPath, script) ? '写入' : '未变'} .codex/hooks/context-goal-guard.py`);
|
|
580
|
+
console.log(` ${writeFileIfChanged(manifestPath, manifest) ? '写入' : '未变'} .codex/hooks.json (context goal guard)`);
|
|
581
|
+
return limit;
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
function printContextGoalGuardSteps(threshold) {
|
|
585
|
+
console.log(`
|
|
586
|
+
Codex goal guard 已部署,请完成以下操作后使用:
|
|
587
|
+
1. 在目标项目运行 codex --version;目前仅验证 Codex 0.160.0、macOS arm64。
|
|
588
|
+
其他版本的会话格式不自动兼容;请先在隔离项目验证。
|
|
589
|
+
2. 从目标项目启动 Codex,审阅并信任项目 .codex/ 层。
|
|
590
|
+
在 Codex 对话中输入 /hooks,找到本项目 .codex/hooks.json 的
|
|
591
|
+
PreToolUse 和 Stop 两个 context-goal-guard.py handler,分别审阅、信任并启用。
|
|
592
|
+
核对两者来源和状态,确认其他 hooks 仍保留;配置或脚本更新后重新审阅信任。
|
|
593
|
+
3. 安装与信任不构成暂停授权。请在当前 goal 的用户指令中明确(可复制):
|
|
594
|
+
对当前 goal,如果本地估算上下文使用率严格超过 ${threshold}%,请先安全收尾,
|
|
595
|
+
按已有任务约定保存进度和交接说明,再使用原生 goal 工具将其设为 paused
|
|
596
|
+
并核对,无需二次确认。未完成工作不要标为 complete。请提醒我自己新开对话继续。
|
|
597
|
+
4. 先用测试 goal 验证提醒与真实 paused 状态。/goal resume 撤销先前暂停请求,
|
|
598
|
+
需重新明确策略;新开对话也需手动设置新 goal 并重新明确策略。
|
|
599
|
+
暂停失败时在原对话输入 /goal pause;临时停用可在 /hooks 中禁用这两个 handler。
|
|
600
|
+
提示: 请安装到 Git 仓库根目录;Codex 运行环境必须能找到 git 和 Python 3.9+。
|
|
601
|
+
hook 运行时从 Git 根目录定位脚本;没有 active goal 时不会触发。
|
|
602
|
+
`);
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
// 与 installContextGoalGuard 形状相似,但文件、事件和匹配式都不同,暂不抽公共函数。
|
|
606
|
+
function installClaudeContextGoalGuard(targetDir, force, threshold) {
|
|
607
|
+
const settingsPath = path.join(targetDir, '.claude', 'settings.local.json');
|
|
608
|
+
let existing = {};
|
|
609
|
+
let backup = false;
|
|
610
|
+
if (fs.existsSync(settingsPath)) {
|
|
611
|
+
try {
|
|
612
|
+
existing = readJson(settingsPath);
|
|
613
|
+
} catch (error) {
|
|
614
|
+
if (!(error instanceof SyntaxError)) throw error;
|
|
615
|
+
if (!force) throw new Error(`${settingsPath} 不是合法 JSON,未修改;请先手动修复,或加 --force 备份为 .bak 后覆盖。`);
|
|
616
|
+
backup = true;
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
// 合法 JSON 的未知结构不能当成空配置,否则会丢失用户的设置。
|
|
620
|
+
if (!existing || typeof existing !== 'object' || Array.isArray(existing)
|
|
621
|
+
|| (existing.hooks !== undefined && (!existing.hooks || typeof existing.hooks !== 'object' || Array.isArray(existing.hooks)))
|
|
622
|
+
|| Object.values(existing.hooks || {}).some((entries) => !Array.isArray(entries))) {
|
|
623
|
+
throw new Error(`${settingsPath} 的 hooks 结构不受支持,未修改;请先手动修复为事件数组。`);
|
|
624
|
+
}
|
|
625
|
+
let previous;
|
|
626
|
+
const hooks = { ...existing.hooks };
|
|
627
|
+
for (const event of ['PostToolBatch', 'Stop']) {
|
|
628
|
+
const kept = [];
|
|
629
|
+
for (const entry of hooks[event] || []) {
|
|
630
|
+
if (!Array.isArray(entry?.hooks)) {
|
|
631
|
+
kept.push(entry);
|
|
632
|
+
continue;
|
|
633
|
+
}
|
|
634
|
+
const handlers = entry.hooks.filter((handler) => {
|
|
635
|
+
const guard = handler?.type === 'command' && typeof handler.command === 'string'
|
|
636
|
+
&& /\.claude\/hooks\/context-goal-guard\.js(?:['"\s]|$)/.test(handler.command);
|
|
637
|
+
if (guard) previous ??= guardThreshold(handler.command);
|
|
638
|
+
return !guard;
|
|
639
|
+
});
|
|
640
|
+
if (handlers.length === entry.hooks.length) kept.push(entry);
|
|
641
|
+
else if (handlers.length > 0) kept.push({ ...entry, hooks: handlers });
|
|
642
|
+
}
|
|
643
|
+
hooks[event] = kept;
|
|
644
|
+
}
|
|
645
|
+
const limit = threshold ?? previous ?? CLAUDE_CONTEXT_GOAL_GUARD_DEFAULT_THRESHOLD;
|
|
646
|
+
const command = `node "$CLAUDE_PROJECT_DIR/.claude/hooks/context-goal-guard.js" --threshold ${limit}`;
|
|
647
|
+
for (const event of ['PostToolBatch', 'Stop']) hooks[event].push({ hooks: [{ type: 'command', command, timeout: 5 }] });
|
|
648
|
+
const script = fs.readFileSync(CLAUDE_CONTEXT_GOAL_GUARD_SRC);
|
|
649
|
+
const settings = Buffer.from(JSON.stringify({ ...existing, hooks }, null, 2) + '\n');
|
|
650
|
+
if (backup) fs.copyFileSync(settingsPath, `${settingsPath}.bak`);
|
|
651
|
+
console.log(` ${writeFileIfChanged(path.join(targetDir, '.claude', 'hooks', 'context-goal-guard.js'), script) ? '写入' : '未变'} .claude/hooks/context-goal-guard.js`);
|
|
652
|
+
console.log(` ${writeFileIfChanged(settingsPath, settings) ? '写入' : '未变'} .claude/settings.local.json (context goal guard)`);
|
|
653
|
+
return limit;
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
function printClaudeContextGoalGuardSteps(threshold) {
|
|
657
|
+
console.log(`
|
|
658
|
+
Claude Code goal guard 已部署,请完成以下操作后使用:
|
|
659
|
+
1. 运行 claude --version;目前仅验证 Claude Code 2.1.288 交互式 CLI、macOS arm64,
|
|
660
|
+
以及 claude-opus-5-5、claude-sonnet-5-5(1M)与 claude-haiku-4-5-20251001(200k)。
|
|
661
|
+
可在 statusLine 输入的 context_window.context_window_size 核对窗口,不一致时不要启用。
|
|
662
|
+
2. 重启 Claude Code 会话并信任本工作区;输入 /hooks,确认 PostToolBatch 与 Stop
|
|
663
|
+
各有一个 context-goal-guard.js handler,来源为 .claude/settings.local.json,其他 hooks 仍在。
|
|
664
|
+
3. 先用测试 goal 验证:估算上下文严格超过 ${threshold}% 时 agent 收到收尾提醒;回合结束时
|
|
665
|
+
界面可能先出现「Stop hook error: …」(收尾请求,属正常),随后出现 Goal paused。
|
|
666
|
+
4. 接续:在同一项目目录新开对话或 /clear,提供计划路径或交接摘要,并重新设置 /goal;
|
|
667
|
+
新对话不继承 goal。原会话发消息或 --resume 会恢复 goal 并再次触发暂停,
|
|
668
|
+
不再需要时在原会话 /goal clear。
|
|
669
|
+
5. 停用:从 .claude/settings.local.json 删除这两个 handler 并重启会话;
|
|
670
|
+
不要用 disableAllHooks,它会连 /goal 一起禁用。
|
|
671
|
+
说明见 @xgent-ai/skills 包内 docs/claude-context-goal-guard.md;没有 active goal 时不会触发。
|
|
672
|
+
`);
|
|
523
673
|
}
|
|
524
674
|
|
|
525
675
|
function createAgents(targetDir) {
|
|
@@ -540,13 +690,22 @@ function usage() {
|
|
|
540
690
|
install [dir] 为目标项目(默认当前目录)安装 .claude/hooks 下的全部
|
|
541
691
|
hook,在 .claude/settings.json 中启用对应配置,并装上
|
|
542
692
|
vendor 的 impeccable(skills + hooks,以及按需下载的
|
|
543
|
-
engine 二进制),并询问是否创建通用的 AGENTS.md
|
|
693
|
+
engine 二进制),并询问是否创建通用的 AGENTS.md;
|
|
694
|
+
Codex / Claude Code goal 上下文收尾提醒默认不安装
|
|
544
695
|
help 显示本帮助
|
|
545
696
|
|
|
546
697
|
install 选项:
|
|
547
698
|
--no-impeccable 跳过 impeccable,仍安装 XGENT 的 hooks 与 settings
|
|
548
699
|
--xgent-init 创建 AGENTS.md (已有则跳过),不再询问
|
|
549
700
|
--no-xgent-init 跳过 AGENTS.md,不再询问
|
|
701
|
+
--context-goal-guard 显式安装 Codex goal guard(默认不安装,需要 Python 3.9+)
|
|
702
|
+
--no-context-goal-guard 跳过 Codex goal guard(默认行为,保留已有 guard)
|
|
703
|
+
--context-goal-guard-threshold=N Codex guard 的阈值百分比(1–99 整数,默认 ${CONTEXT_GOAL_GUARD_DEFAULT_THRESHOLD};
|
|
704
|
+
重装时不给则沿用已装的值),同时表示安装
|
|
705
|
+
--claude-context-goal-guard 显式安装 Claude Code goal guard(默认不安装)
|
|
706
|
+
--no-claude-context-goal-guard 跳过 Claude Code goal guard(默认行为,保留已有 guard)
|
|
707
|
+
--claude-context-goal-guard-threshold=N Claude Code guard 的阈值百分比(1–99 整数,
|
|
708
|
+
默认 ${CLAUDE_CONTEXT_GOAL_GUARD_DEFAULT_THRESHOLD};重装时不给则沿用已装的值),同时表示安装
|
|
550
709
|
--providers=a,b 指定 impeccable 装进哪些 harness 目录(默认按项目里
|
|
551
710
|
已有的目录判断,都没有时装 ${DEFAULT_TARGETS.join(' 和 ')})
|
|
552
711
|
--force 强制重装,并允许覆盖非法 JSON 的 hook 配置(先存 .bak),
|
|
@@ -557,7 +716,8 @@ install 选项:
|
|
|
557
716
|
async function install(args) {
|
|
558
717
|
const flags = args.filter((a) => a.startsWith('--'));
|
|
559
718
|
const dirArg = args.find((a) => !a.startsWith('--'));
|
|
560
|
-
const unknown = flags.filter((f) => !['--no-impeccable', '--xgent-init', '--no-xgent-init', '--force'].includes(f)
|
|
719
|
+
const unknown = flags.filter((f) => !['--no-impeccable', '--xgent-init', '--no-xgent-init', '--context-goal-guard', '--no-context-goal-guard', '--claude-context-goal-guard', '--no-claude-context-goal-guard', '--force'].includes(f)
|
|
720
|
+
&& !['--providers=', '--context-goal-guard-threshold=', '--claude-context-goal-guard-threshold='].some((p) => f.startsWith(p)));
|
|
561
721
|
if (unknown.length > 0) {
|
|
562
722
|
console.error(`错误: 未知选项: ${unknown.join(', ')}\n`);
|
|
563
723
|
usage();
|
|
@@ -567,6 +727,32 @@ async function install(args) {
|
|
|
567
727
|
console.error('错误: --xgent-init 与 --no-xgent-init 不能同时使用');
|
|
568
728
|
process.exit(1);
|
|
569
729
|
}
|
|
730
|
+
if (flags.includes('--context-goal-guard') && flags.includes('--no-context-goal-guard')) {
|
|
731
|
+
console.error('错误: --context-goal-guard 与 --no-context-goal-guard 不能同时使用');
|
|
732
|
+
process.exit(1);
|
|
733
|
+
}
|
|
734
|
+
if (flags.includes('--claude-context-goal-guard') && flags.includes('--no-claude-context-goal-guard')) {
|
|
735
|
+
console.error('错误: --claude-context-goal-guard 与 --no-claude-context-goal-guard 不能同时使用');
|
|
736
|
+
process.exit(1);
|
|
737
|
+
}
|
|
738
|
+
const thresholds = {};
|
|
739
|
+
for (const [name, skip] of [['--context-goal-guard-threshold', '--no-context-goal-guard'],
|
|
740
|
+
['--claude-context-goal-guard-threshold', '--no-claude-context-goal-guard']]) {
|
|
741
|
+
const flag = flags.find((f) => f.startsWith(`${name}=`));
|
|
742
|
+
if (flag === undefined) continue;
|
|
743
|
+
const value = flag.slice(name.length + 1);
|
|
744
|
+
if (!/^[1-9][0-9]?$/.test(value)) {
|
|
745
|
+
console.error(`错误: ${name} 需要 1–99 的整数百分比,收到 "${value}"`);
|
|
746
|
+
process.exit(1);
|
|
747
|
+
}
|
|
748
|
+
if (flags.includes(skip)) {
|
|
749
|
+
console.error(`错误: ${name} 与 ${skip} 不能同时使用`);
|
|
750
|
+
process.exit(1);
|
|
751
|
+
}
|
|
752
|
+
thresholds[name] = Number(value);
|
|
753
|
+
}
|
|
754
|
+
const codexThreshold = thresholds['--context-goal-guard-threshold'];
|
|
755
|
+
const claudeThreshold = thresholds['--claude-context-goal-guard-threshold'];
|
|
570
756
|
const options = {
|
|
571
757
|
impeccable: !flags.includes('--no-impeccable'),
|
|
572
758
|
force: flags.includes('--force'),
|
|
@@ -582,7 +768,23 @@ async function install(args) {
|
|
|
582
768
|
options.detected = detectProviders(targetDir);
|
|
583
769
|
if (options.providers) resolveProviders(options.detected, options.providers);
|
|
584
770
|
const agentsExists = fs.existsSync(path.join(targetDir, 'AGENTS.md'));
|
|
585
|
-
const
|
|
771
|
+
const askAgents = !flags.includes('--xgent-init') && !flags.includes('--no-xgent-init') && !agentsExists;
|
|
772
|
+
const guard = flags.includes('--context-goal-guard') || codexThreshold !== undefined;
|
|
773
|
+
const claudeGuard = flags.includes('--claude-context-goal-guard') || claudeThreshold !== undefined;
|
|
774
|
+
const rl = process.stdin.isTTY && askAgents
|
|
775
|
+
? readline.createInterface({ input: process.stdin, output: process.stdout }) : null;
|
|
776
|
+
const answers = rl?.[Symbol.asyncIterator]();
|
|
777
|
+
rl?.once('SIGINT', () => { rl.close(); process.exit(130); });
|
|
778
|
+
let agents;
|
|
779
|
+
try {
|
|
780
|
+
agents = flags.includes('--xgent-init') || (askAgents && await confirm(
|
|
781
|
+
'是否同时创建通用的 AGENTS.md (含 Portal 联调与前端验收约定)? [y/N] ',
|
|
782
|
+
' 跳过 AGENTS.md:非交互环境,可加 --xgent-init 创建', answers));
|
|
783
|
+
} finally {
|
|
784
|
+
rl?.close();
|
|
785
|
+
}
|
|
786
|
+
const codexLimit = guard && installContextGoalGuard(targetDir, options.force, codexThreshold);
|
|
787
|
+
const claudeLimit = claudeGuard && installClaudeContextGoalGuard(targetDir, options.force, claudeThreshold);
|
|
586
788
|
|
|
587
789
|
const hooksDestDir = path.join(targetDir, '.claude', 'hooks');
|
|
588
790
|
fs.mkdirSync(hooksDestDir, { recursive: true });
|
|
@@ -625,6 +827,8 @@ async function install(args) {
|
|
|
625
827
|
|
|
626
828
|
if (agents) createAgents(targetDir);
|
|
627
829
|
else if (agentsExists && !flags.includes('--no-xgent-init')) console.log(' 跳过 AGENTS.md (已存在,保留原文)');
|
|
830
|
+
if (codexLimit) printContextGoalGuardSteps(codexLimit);
|
|
831
|
+
if (claudeLimit) printClaudeContextGoalGuardSteps(claudeLimit);
|
|
628
832
|
console.log(`完成: ${targetDir}`);
|
|
629
833
|
}
|
|
630
834
|
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
# Claude Code goal 上下文收尾提醒
|
|
2
|
+
|
|
3
|
+
当前会话的 `/goal` 仍 active,且本地估算上下文使用率**严格超过阈值**(默认 70%,可配置)时,本 hook 提醒 agent 收尾:停止开始新的实质任务,按任务已有约定更新进度并交接。回合结束时由 Stop hook 结束回合,Claude Code 原生把 goal 置为「Goal paused」,再由你自己新开对话(或 `/clear`)接续。恰好等于阈值不触发。hook 只读当前会话记录,不写任何文件,也不清除、转移或恢复 goal。
|
|
4
|
+
|
|
5
|
+
## 兼容范围与限制
|
|
6
|
+
|
|
7
|
+
- 已验证:Claude Code **2.1.288** 交互式 CLI、macOS arm64、Node v25.2.1(安装器要求 Node ≥ 18)。完整验收见 [M1 记录](plan/claude-context-goal-guard.records/M1.md)、[M2 记录](plan/claude-context-goal-guard.records/M2.md)、[M3 记录](plan/claude-context-goal-guard.records/M3.md)、[M4 记录](plan/claude-context-goal-guard.records/M4.md)。新版本不自动视为兼容。
|
|
8
|
+
- 未验证:`claude -p` 非交互模式、桌面应用、Remote Control、云端会话。
|
|
9
|
+
- 只保护主会话;子 agent 内的事件直接跳过。
|
|
10
|
+
- 上下文窗口:hook 输入和会话记录都不含窗口大小,脚本只认下表中验证过的模型。其他模型,或设置了 `CLAUDE_CODE_DISABLE_1M_CONTEXT`、`DISABLE_COMPACT`、`CLAUDE_CODE_MAX_CONTEXT_TOKENS` 任一变量时,报告「检测不可用」,不触发。
|
|
11
|
+
|
|
12
|
+
| 模型 id(会话记录中的 `message.model`) | 窗口 |
|
|
13
|
+
| --- | --- |
|
|
14
|
+
| `claude-opus-5-5` | 1,000,000(是否选 `[1m]` 相同) |
|
|
15
|
+
| `claude-sonnet-5-5` | 1,000,000(是否选 `[1m]` 相同) |
|
|
16
|
+
| `claude-haiku-4-5-20251001` | 200,000 |
|
|
17
|
+
|
|
18
|
+
窗口还会因账号与服务端能力而不同,上表只在验证时用的 Claude Max 账号上核对过。启用前用 statusLine 自查:statusLine 命令的 stdin JSON 里 `model.id` 和 `context_window.context_window_size` 应与上表一致,不一致时不要启用。
|
|
19
|
+
|
|
20
|
+
### 用量口径
|
|
21
|
+
|
|
22
|
+
```text
|
|
23
|
+
used = input_tokens + cache_creation_input_tokens + cache_read_input_tokens # 取最新主链 assistant 记录;有 iterations 时取最后一项
|
|
24
|
+
trigger = used * 100 > window * threshold # threshold 默认 70,见「阈值配置」
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
与 statusLine 的 `used_percentage` 同口径,不计 output。会话记录异步写入,可能落后一条消息。自动压缩后,出现新统计前不判定。
|
|
28
|
+
|
|
29
|
+
Claude Code 界面右下角的「NN% context used」按扣除输出预留后的有效窗口计算,读数比本 guard 高。例如 Haiku 4.5 实测 155,100 token 时,界面显示 86%(≈ 155,100 / 180,000),guard 计为 78%。
|
|
30
|
+
|
|
31
|
+
## 安装
|
|
32
|
+
|
|
33
|
+
### 使用 install
|
|
34
|
+
|
|
35
|
+
```sh
|
|
36
|
+
# 默认不安装 guard;从本仓库源码显式安装
|
|
37
|
+
# 发布到 npm 后可用 npx @xgent-ai/skills install --claude-context-goal-guard
|
|
38
|
+
node bin/xgent-skills.js install /absolute/path/to/project --claude-context-goal-guard
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
交互和非交互安装均默认跳过 guard,不再询问。仅在显式传入 `--claude-context-goal-guard` 或 `--claude-context-goal-guard-threshold=N` 时安装;`--no-claude-context-goal-guard` 显式跳过并保留已有 guard,不能与安装参数同时使用。这个选项与 `--providers`、`--no-impeccable`、`--xgent-init` 及 Codex guard 的选项互不影响。
|
|
42
|
+
|
|
43
|
+
安装器会:
|
|
44
|
+
|
|
45
|
+
1. 复制脚本到目标项目 `.claude/hooks/context-goal-guard.js`;
|
|
46
|
+
2. 把 `PostToolBatch` 与 `Stop` 两个 handler 合并进个人的 `.claude/settings.local.json`(不进共享的 `settings.json`),command 为 `node "$CLAUDE_PROJECT_DIR/.claude/hooks/context-goal-guard.js"`,超时 5 秒;
|
|
47
|
+
3. 保留其他事件、handler、matcher 和顶层字段,重复安装只更新 guard。非法 JSON 默认报错,`--force` 先备份为 `.bak` 再覆盖;合法 JSON 但结构不认识时报错,需要手动修复。
|
|
48
|
+
|
|
49
|
+
### 阈值配置
|
|
50
|
+
|
|
51
|
+
阈值写在 handler 命令末尾:`--threshold N`,N 为 1–99 的整数百分比;不带参数时为 70。与 Codex 版(默认 65)各自独立。
|
|
52
|
+
|
|
53
|
+
```sh
|
|
54
|
+
# 安装时指定(同时表示安装,不再询问)
|
|
55
|
+
node bin/xgent-skills.js install /absolute/path/to/project --claude-context-goal-guard-threshold=75
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
安装器总是把阈值明确写进两个 handler 的 command,在 `/hooks` 里看得到。之后重装时不给这个 flag,就沿用已装的值。也可以直接改 `.claude/settings.local.json` 里两条 command 末尾的数字,两条要一致。参数无效时(如 `0`、`100`、`6.5`)guard 不猜测数值,按「检测不可用」处理。
|
|
59
|
+
|
|
60
|
+
阈值不宜太高:收尾本身还要消耗上下文,而 Claude Code 在接近有效窗口上限时会自动压缩(见上面的界面读数说明)。建议不超过 75%。
|
|
61
|
+
|
|
62
|
+
### 手动部署
|
|
63
|
+
|
|
64
|
+
```sh
|
|
65
|
+
mkdir -p "/absolute/path/to/project/.claude/hooks"
|
|
66
|
+
cp hooks/claude/context-goal-guard.js "/absolute/path/to/project/.claude/hooks/context-goal-guard.js"
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
把 [设置示例](../hooks/claude/settings.example.json) 里的两组 handler(默认 `--threshold 70`,按需修改)**追加**到目标项目 `.claude/settings.local.json` 已有的 `PostToolBatch`、`Stop` 数组,不要用示例覆盖整个文件。Claude Code 的 hook 运行环境里必须能找到 `node`。
|
|
70
|
+
|
|
71
|
+
## 信任与生效确认
|
|
72
|
+
|
|
73
|
+
1. 运行 `claude --version`,确认是上面验证过的版本。
|
|
74
|
+
2. 从目标项目启动 Claude Code,信任该工作区。工作区未被信任时,设置里的 hook 和 `/goal` 都不可用。
|
|
75
|
+
3. 输入 `/hooks`,确认 `PostToolBatch` 和 `Stop` 下各有一条 `[Local] node "$CLAUDE_PROJECT_DIR/.claude/hooks/context-g…`,其他 hooks 仍在。
|
|
76
|
+
4. 先用测试 goal 走一遍:越过阈值后应看到提醒,回合结束后出现「Goal paused · a hook ended the turn」。
|
|
77
|
+
|
|
78
|
+
## goal 条件怎么写
|
|
79
|
+
|
|
80
|
+
guard 不管进度写到哪里,提醒只要求 agent 按任务**已有约定**更新进度。最好让 goal 条件指向一份带进度区的计划,例如:
|
|
81
|
+
|
|
82
|
+
```text
|
|
83
|
+
/goal 按 docs/plan/xxx.md 开发:全部里程碑完成并回写进度
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
没有计划文件时,agent 会在最终回复里给出交接摘要,不会新建文件。
|
|
87
|
+
|
|
88
|
+
## 触发后会看到什么
|
|
89
|
+
|
|
90
|
+
1. 越线后的每个工具批次,agent 都会收到同一条收尾提醒:停止新工作,把手上的工作处理到可交接,更新进度,停止后台任务,写明「因上下文收尾而暂停,工作未完成」。
|
|
91
|
+
2. agent 第一次结束回合时,guard 可能先请求补做收尾。界面上显示为「Stop hook error: 上下文估算使用率 NN% …」,这是正常的继续请求,不是故障。
|
|
92
|
+
3. 下一次结束回合时,guard 结束回合,界面显示 guard 的说明和「Goal paused · a hook ended the turn · send a message to continue」。goal 评估器会照常判定「未达成」,但不会再自动续跑。
|
|
93
|
+
|
|
94
|
+
提醒没有强制力。在 goal 的自动续轮里越线时,agent 可能只收到一次提醒、甚至一次都没收到就被暂停。交接不完整时,在原会话发一句「按上下文收尾提醒补交接」,回合结束后会再次暂停。
|
|
95
|
+
|
|
96
|
+
## 接续
|
|
97
|
+
|
|
98
|
+
在同一项目目录新开对话,或在原会话输入 `/clear`。告诉 agent 计划路径(或粘贴交接摘要),再重新设置 `/goal`。新对话和 `/clear` 后都**不继承** goal:不重新设置,guard 就不会触发。
|
|
99
|
+
|
|
100
|
+
原会话的 goal 只是暂停:在原会话里发任何消息都会恢复 goal,guard 随即再次收口;`claude --resume` 也会恢复 goal(不会自动运行)。不再需要时,在原会话 `/goal clear`。
|
|
101
|
+
|
|
102
|
+
### 后台任务
|
|
103
|
+
|
|
104
|
+
暂停时如果还有后台命令或子 agent 在跑,它们完成时的通知(以及 goal 的 idle check-in)会唤醒会话。guard 会先请求一次收尾,在请求里列出仍在运行的任务,再结束回合;进度不会前进,但每次唤醒多花两次简短的模型调用。这种被唤醒后再结束的回合,界面可能显示「Goal not yet met… continuing」,状态栏仍是「/goal active」,没有「Goal paused」提示;实测此后约 7 分钟内没有自动回合。
|
|
105
|
+
|
|
106
|
+
## 停用
|
|
107
|
+
|
|
108
|
+
从 `.claude/settings.local.json` 删除 command 含 `context-goal-guard.js` 的两个 handler,保留其他 hooks,再删除 `.claude/hooks/context-goal-guard.js`。实测会话运行中修改后,`/hooks` 数秒内就不再列出它们;保险起见仍建议重启会话。已暂停的 goal 不受影响。
|
|
109
|
+
|
|
110
|
+
不要用 `disableAllHooks`:它会连 `/goal` 一起禁用。
|
|
111
|
+
|
|
112
|
+
## 排查
|
|
113
|
+
|
|
114
|
+
guard 只在 **Stop** 时显示告警,不会在每个工具批次刷屏。告警格式为「context goal guard 检测不可用:<原因>」:
|
|
115
|
+
|
|
116
|
+
| 原因 | 处理 |
|
|
117
|
+
| --- | --- |
|
|
118
|
+
| 模型 `X` 的上下文窗口未经验证 | 换用上表中的模型,或停用 guard;补表需要先在同环境核对 statusLine 的窗口 |
|
|
119
|
+
| 设置了改变上下文窗口的环境变量 `X` | 取消该变量,或停用 guard |
|
|
120
|
+
| 无法读取会话记录 / hook 输入缺少会话记录路径 | 核对 Claude Code 版本;持续出现时停用 guard |
|
|
121
|
+
| 用量统计格式未知 | Claude Code 的会话记录格式变了,停用 guard 并等待重新验证 |
|
|
122
|
+
| 阈值参数无效 | 把两条 command 末尾改为 `--threshold` 加 1–99 的整数,或重新运行安装器 |
|
|
123
|
+
|
|
124
|
+
检测不可用时,guard 不提醒、不结束回合,也不显示 0%。
|