@michelj/context-guard 0.4.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 +203 -0
- package/README.zh-CN.md +203 -0
- package/bin/context-guard-skill.js +185 -0
- package/hooks.json +41 -0
- package/package.json +30 -0
- package/skills/context-guard/README.md +203 -0
- package/skills/context-guard/README.zh-CN.md +203 -0
- package/skills/context-guard/SKILL.md +519 -0
- package/skills/context-guard/agents/openai.yaml +4 -0
- package/skills/context-guard/references/context-template.md +290 -0
- package/skills/context-guard/references/register-template.md +85 -0
- package/skills/context-guard/references/task-case-template.md +63 -0
- package/skills/context-guard/scripts/context_guard.py +4661 -0
- package/skills/context-guard/scripts/context_guard_hook.py +465 -0
- package/skills/context-guard/tests/BC-20260618-063.sh +116 -0
- package/skills/context-guard/tests/BC-20260618-065.sh +66 -0
- package/skills/context-guard/tests/BC-20260626-080.sh +48 -0
- package/skills/context-guard/tests/BC-20260626-081.sh +40 -0
- package/skills/context-guard/tests/BC-20260626-082.sh +32 -0
- package/skills/context-guard/tests/BC-20260626-083.sh +66 -0
- package/skills/context-guard/tests/BC-20260627-084.sh +74 -0
- package/skills/context-guard/tests/BC-20260630-086.sh +50 -0
- package/skills/context-guard/tests/BC-20260630-087.sh +103 -0
- package/skills/context-guard/tests/BC-20260630-088.sh +32 -0
- package/skills/context-guard/tests/BC-20260630-089.sh +63 -0
- package/skills/context-guard/tests/BC-20260701-090.sh +83 -0
package/README.md
ADDED
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
# Context Guard Skill
|
|
2
|
+
|
|
3
|
+
Language: **English** | [中文](README.zh-CN.md)
|
|
4
|
+
|
|
5
|
+
Context Guard is a Codex skill for durable project memory. It keeps the task route, branches, bad cases, and verification paths inside the project's own `.codex/context/` folder, so Codex can understand where the work is, what went wrong before, and how to avoid repeating fixed mistakes across sessions.
|
|
6
|
+
|
|
7
|
+
## What It Does
|
|
8
|
+
|
|
9
|
+
- **Maintains project context**: creates and updates `.codex/context/`.
|
|
10
|
+
- **Records the roadmap**: tracks main routes, side routes, branch points, and progress.
|
|
11
|
+
- **Tracks bad cases**: records symptoms, triggers, causes, fixes, and recurrence checks.
|
|
12
|
+
- **Generates Roadmap HTML**: shows a human-readable roadmap with clickable node details.
|
|
13
|
+
- **Separates human and agent views**: HTML is for humans; Markdown/JSON are for Codex.
|
|
14
|
+
- **Supports record language preferences**: writes future context in Chinese or English.
|
|
15
|
+
- **Handles task switches**: parks, resumes, and branches interrupted work.
|
|
16
|
+
- **Keeps tests human-designed**: Codex reuses approved checks or proposes drafts, but does not silently create durable tests.
|
|
17
|
+
- **Runs approved tests by default**: user-created or user-approved tests run at every development completion unless the user sets another cadence.
|
|
18
|
+
- **Provides a Test Hub entrypoint**: `dev-complete` runs approved always-run tests, cleans success artifacts, and preserves failed evidence.
|
|
19
|
+
|
|
20
|
+
## Install
|
|
21
|
+
|
|
22
|
+
Install with npx:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npx context-guard install
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Install hooks only when you explicitly want Context Guard reminders at Codex lifecycle events:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npx context-guard install --with-hooks
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Use from GitHub before the npm package is published:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
npx github:Michel-Johnson/Context-Guard-Skill install
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Manual install is also supported:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
git clone git@github.com:Michel-Johnson/Context-Guard-Skill.git
|
|
44
|
+
cd Context-Guard-Skill
|
|
45
|
+
mkdir -p ~/.agents/skills/context-guard
|
|
46
|
+
rsync -a --delete skills/context-guard/ ~/.agents/skills/context-guard/
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
After installation, Codex should discover:
|
|
50
|
+
|
|
51
|
+
```text
|
|
52
|
+
~/.agents/skills/context-guard/SKILL.md
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Where Context Lives
|
|
56
|
+
|
|
57
|
+
Context must be saved under the local project currently opened in Codex:
|
|
58
|
+
|
|
59
|
+
```text
|
|
60
|
+
<Codex project root>/.codex/context/
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Do not write project context into:
|
|
64
|
+
|
|
65
|
+
- the skill install directory
|
|
66
|
+
- a chat/thread directory
|
|
67
|
+
- a temporary directory
|
|
68
|
+
- an SSH remote server path
|
|
69
|
+
|
|
70
|
+
When running scripts manually, pass the project root explicitly:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
python3 ~/.agents/skills/context-guard/scripts/context_guard.py show-roadmap --root /path/to/project
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Register a user-approved automated test:
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
python3 ~/.agents/skills/context-guard/scripts/context_guard.py test-hub-add \
|
|
80
|
+
--root /path/to/project \
|
|
81
|
+
--title "Markdown preview rendering" \
|
|
82
|
+
--command-text "npm test"
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
After development, hand completion to the Test Hub:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
python3 ~/.agents/skills/context-guard/scripts/context_guard.py dev-complete --root /path/to/project --jobs 2
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Open the Test Hub page; use the localhost console for one-click runs:
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
python3 ~/.agents/skills/context-guard/scripts/context_guard.py show-test-hub --root /path/to/project --open
|
|
95
|
+
python3 ~/.agents/skills/context-guard/scripts/context_guard.py serve-test-hub --root /path/to/project --port 8772 --open
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Manage tests lightly:
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
python3 ~/.agents/skills/context-guard/scripts/context_guard.py test-hub-list --root /path/to/project
|
|
102
|
+
python3 ~/.agents/skills/context-guard/scripts/context_guard.py test-hub-disable --root /path/to/project --test-id TC-... --reason "not needed every time"
|
|
103
|
+
python3 ~/.agents/skills/context-guard/scripts/context_guard.py test-hub-enable --root /path/to/project --test-id TC-...
|
|
104
|
+
python3 ~/.agents/skills/context-guard/scripts/context_guard.py test-hub-set-policy --root /path/to/project --test-id TC-... --run-policy relevant-only --reason "only editor changes need it"
|
|
105
|
+
python3 ~/.agents/skills/context-guard/scripts/context_guard.py test-hub-remove --root /path/to/project --test-id TC-...
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Common Usage
|
|
109
|
+
|
|
110
|
+
Ask Codex to maintain context:
|
|
111
|
+
|
|
112
|
+
```text
|
|
113
|
+
Use $context-guard to maintain this task context.
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Show the current roadmap:
|
|
117
|
+
|
|
118
|
+
```text
|
|
119
|
+
Use $context-guard to show the roadmap.
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Initialize project context:
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
python3 ~/.agents/skills/context-guard/scripts/context_guard.py init --root /path/to/project
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Set the record language:
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
python3 ~/.agents/skills/context-guard/scripts/context_guard.py set-language --root /path/to/project --language English
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Generate the roadmap:
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
python3 ~/.agents/skills/context-guard/scripts/context_guard.py show-roadmap --root /path/to/project
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Or use the npm CLI as a thin wrapper:
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
npx context-guard show-roadmap --root /path/to/project
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Create a branch task:
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
python3 ~/.agents/skills/context-guard/scripts/context_guard.py create-branch-task \
|
|
150
|
+
--root /path/to/project \
|
|
151
|
+
--title "branch task title" \
|
|
152
|
+
--branch "branch name" \
|
|
153
|
+
--parent-node NODE-YYYYMMDD-001
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
Record a roadmap checkpoint:
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
python3 ~/.agents/skills/context-guard/scripts/context_guard.py checkpoint-roadmap-node \
|
|
160
|
+
--root /path/to/project \
|
|
161
|
+
--title "source title for Codex" \
|
|
162
|
+
--display-title "short human title" \
|
|
163
|
+
--user-request "what the user asked" \
|
|
164
|
+
--progress-summary "current progress" \
|
|
165
|
+
--method-summary "method used" \
|
|
166
|
+
--branch Main \
|
|
167
|
+
--level major \
|
|
168
|
+
--outcome "result"
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## Main Files
|
|
172
|
+
|
|
173
|
+
```text
|
|
174
|
+
.codex/context/
|
|
175
|
+
|-- index.md # quick index and active task
|
|
176
|
+
|-- roadmap.md # agent-readable roadmap
|
|
177
|
+
|-- bad-cases.md # bad-case register
|
|
178
|
+
|-- preferences.json # language and project preferences
|
|
179
|
+
|-- roadmap/
|
|
180
|
+
| |-- roadmap.html # human-facing roadmap
|
|
181
|
+
| |-- roadmap.md # agent-readable export
|
|
182
|
+
| `-- roadmap.json # structured index
|
|
183
|
+
|-- tasks/ # task-level context
|
|
184
|
+
|-- task-cases/ # task-oriented test cases
|
|
185
|
+
|-- test-hub/ # test registry, latest result, and failed evidence
|
|
186
|
+
`-- bad-case-tests/ # reusable bad-case checks
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
## Principles
|
|
190
|
+
|
|
191
|
+
- Record only meaningful progress, not every small action.
|
|
192
|
+
- Human-facing titles should read naturally, not like implementation logs.
|
|
193
|
+
- A bad case should help future Codex prevent recurrence.
|
|
194
|
+
- Test design belongs to humans; Codex can run approved checks or draft a proposal for confirmation.
|
|
195
|
+
- User-approved tests default to `every-dev-completion`; Codex may lower that cadence only when the user asks.
|
|
196
|
+
- Approved automated tests should go into `.codex/context/test-hub/registry.json` and be scheduled through `dev-complete`.
|
|
197
|
+
- Keep the Test Hub simple: one registry, one `dev-complete` runner, one latest-result file, one lightweight HTML control panel, and a few management commands.
|
|
198
|
+
- Verification should reuse existing commands, scripts, screenshots, or manual checks first.
|
|
199
|
+
- Do not create a new script for every bad case.
|
|
200
|
+
- For frontend or HTML changes, inspect the rendered page or screenshot before claiming success.
|
|
201
|
+
- For any new durable test case, draft a short task-case proposal and confirm with the user before making it active.
|
|
202
|
+
|
|
203
|
+
See [`skills/context-guard/SKILL.md`](skills/context-guard/SKILL.md) for the full behavior rules.
|
package/README.zh-CN.md
ADDED
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
# Context Guard Skill
|
|
2
|
+
|
|
3
|
+
语言:[English](README.md) | **中文**
|
|
4
|
+
|
|
5
|
+
Context Guard 是一个给 Codex 用的项目记忆 skill。它把任务主线、支线、bad case 和验证链路保存在项目自己的 `.codex/context/` 里,让 Codex 在不同 session 之间也能知道“现在做到哪里、踩过哪些坑、下次怎么检查”。
|
|
6
|
+
|
|
7
|
+
## 能做什么
|
|
8
|
+
|
|
9
|
+
- **维护项目 context**:自动创建并更新 `.codex/context/`。
|
|
10
|
+
- **记录路线图**:维护主线、支线、分叉节点和当前进度。
|
|
11
|
+
- **记录 bad case**:保存问题现象、触发条件、原因、修复方式和防复发检查。
|
|
12
|
+
- **生成 Roadmap HTML**:给用户查看清晰的路线图,点击节点看详情。
|
|
13
|
+
- **区分人类视图和 agent 视图**:HTML 给人看,Markdown/JSON 给 Codex 读取。
|
|
14
|
+
- **支持多语言记录**:按项目偏好用中文或英文写 context。
|
|
15
|
+
- **处理任务切换**:遇到新方向、支线任务或中断任务时,帮助 Codex park/resume。
|
|
16
|
+
- **测试由人类设计**:Codex 只复用已确认检查,或提出草案等待用户确认,不静默创建长期测试。
|
|
17
|
+
- **默认运行已确认测试**:用户创建或确认的测试,默认每次开发结束都要运行;只有用户说明不必每次运行时才降频。
|
|
18
|
+
- **提供测试中台入口**:`dev-complete` 会统一运行已确认的 always-run 测试,成功清理临时产物,失败保留证据。
|
|
19
|
+
|
|
20
|
+
## 安装
|
|
21
|
+
|
|
22
|
+
使用 npx 安装:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npx context-guard install
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
只有当你明确希望安装 Codex 生命周期 hook 提醒时,才加 `--with-hooks`:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npx context-guard install --with-hooks
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
npm 包正式发布前,也可以直接从 GitHub 使用:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
npx github:Michel-Johnson/Context-Guard-Skill install
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
也支持手动安装:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
git clone git@github.com:Michel-Johnson/Context-Guard-Skill.git
|
|
44
|
+
cd Context-Guard-Skill
|
|
45
|
+
mkdir -p ~/.agents/skills/context-guard
|
|
46
|
+
rsync -a --delete skills/context-guard/ ~/.agents/skills/context-guard/
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
安装后 Codex 应该能发现:
|
|
50
|
+
|
|
51
|
+
```text
|
|
52
|
+
~/.agents/skills/context-guard/SKILL.md
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Context 保存在哪里
|
|
56
|
+
|
|
57
|
+
Context 必须保存在当前打开的本地项目里:
|
|
58
|
+
|
|
59
|
+
```text
|
|
60
|
+
<Codex 打开的项目根目录>/.codex/context/
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
不要把 context 写到:
|
|
64
|
+
|
|
65
|
+
- skill 安装目录
|
|
66
|
+
- chat/thread 名称对应的目录
|
|
67
|
+
- 临时目录
|
|
68
|
+
- SSH 远程服务器路径
|
|
69
|
+
|
|
70
|
+
如果手动运行脚本,建议显式传入项目根目录:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
python3 ~/.agents/skills/context-guard/scripts/context_guard.py show-roadmap --root /path/to/project
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
注册一个用户已确认的自动化测试:
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
python3 ~/.agents/skills/context-guard/scripts/context_guard.py test-hub-add \
|
|
80
|
+
--root /path/to/project \
|
|
81
|
+
--title "Markdown 预览渲染" \
|
|
82
|
+
--command-text "npm test"
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
开发完成后交给测试中台:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
python3 ~/.agents/skills/context-guard/scripts/context_guard.py dev-complete --root /path/to/project --jobs 2
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
查看测试中台页面;需要一键运行时启动 localhost 控制台:
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
python3 ~/.agents/skills/context-guard/scripts/context_guard.py show-test-hub --root /path/to/project --open
|
|
95
|
+
python3 ~/.agents/skills/context-guard/scripts/context_guard.py serve-test-hub --root /path/to/project --port 8772 --open
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
简单管理测试:
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
python3 ~/.agents/skills/context-guard/scripts/context_guard.py test-hub-list --root /path/to/project
|
|
102
|
+
python3 ~/.agents/skills/context-guard/scripts/context_guard.py test-hub-disable --root /path/to/project --test-id TC-... --reason "暂时不需要每次运行"
|
|
103
|
+
python3 ~/.agents/skills/context-guard/scripts/context_guard.py test-hub-enable --root /path/to/project --test-id TC-...
|
|
104
|
+
python3 ~/.agents/skills/context-guard/scripts/context_guard.py test-hub-set-policy --root /path/to/project --test-id TC-... --run-policy relevant-only --reason "只和编辑器改动相关"
|
|
105
|
+
python3 ~/.agents/skills/context-guard/scripts/context_guard.py test-hub-remove --root /path/to/project --test-id TC-...
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## 常用方式
|
|
109
|
+
|
|
110
|
+
让 Codex 启用并维护 context:
|
|
111
|
+
|
|
112
|
+
```text
|
|
113
|
+
Use $context-guard to maintain this task context.
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
展示当前路线图:
|
|
117
|
+
|
|
118
|
+
```text
|
|
119
|
+
Use $context-guard to show the roadmap.
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
初始化项目 context:
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
python3 ~/.agents/skills/context-guard/scripts/context_guard.py init --root /path/to/project
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
设置记录语言:
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
python3 ~/.agents/skills/context-guard/scripts/context_guard.py set-language --root /path/to/project --language 中文
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
生成路线图:
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
python3 ~/.agents/skills/context-guard/scripts/context_guard.py show-roadmap --root /path/to/project
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
也可以用 npm CLI 作为轻量封装:
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
npx context-guard show-roadmap --root /path/to/project
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
创建支线任务:
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
python3 ~/.agents/skills/context-guard/scripts/context_guard.py create-branch-task \
|
|
150
|
+
--root /path/to/project \
|
|
151
|
+
--title "支线任务标题" \
|
|
152
|
+
--branch "支线名称" \
|
|
153
|
+
--parent-node NODE-YYYYMMDD-001
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
记录路线图节点:
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
python3 ~/.agents/skills/context-guard/scripts/context_guard.py checkpoint-roadmap-node \
|
|
160
|
+
--root /path/to/project \
|
|
161
|
+
--title "给 Codex 看的源标题" \
|
|
162
|
+
--display-title "给用户看的短标题" \
|
|
163
|
+
--user-request "用户实际提出的问题" \
|
|
164
|
+
--progress-summary "当前进展" \
|
|
165
|
+
--method-summary "采取的方法" \
|
|
166
|
+
--branch Main \
|
|
167
|
+
--level major \
|
|
168
|
+
--outcome "结果"
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## 主要文件
|
|
172
|
+
|
|
173
|
+
```text
|
|
174
|
+
.codex/context/
|
|
175
|
+
|-- index.md # 快速索引和当前任务
|
|
176
|
+
|-- roadmap.md # agent 可读路线图
|
|
177
|
+
|-- bad-cases.md # bad case 登记表
|
|
178
|
+
|-- preferences.json # 语言和项目偏好
|
|
179
|
+
|-- roadmap/
|
|
180
|
+
| |-- roadmap.html # 用户查看的路线图
|
|
181
|
+
| |-- roadmap.md # agent 快速读取版
|
|
182
|
+
| `-- roadmap.json # 结构化索引
|
|
183
|
+
|-- tasks/ # 任务级 context
|
|
184
|
+
|-- task-cases/ # 任务导向测试 case
|
|
185
|
+
|-- test-hub/ # 测试注册表、最近结果和失败证据
|
|
186
|
+
`-- bad-case-tests/ # 可复用 bad case 检查脚本
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
## 使用原则
|
|
190
|
+
|
|
191
|
+
- 路线图只记录关键进展,不记录每个小动作。
|
|
192
|
+
- 用户看的标题要像人话,不要像实现日志。
|
|
193
|
+
- bad case 要能帮助未来避免复发。
|
|
194
|
+
- 测试设计权属于人类;Codex 可以执行已确认检查,或提出待确认草案。
|
|
195
|
+
- 用户确认的测试默认是 `every-dev-completion`;只有用户要求时,Codex 才能改成其他运行频率。
|
|
196
|
+
- 已确认的自动化测试应进入 `.codex/context/test-hub/registry.json`,由 `dev-complete` 统一调度。
|
|
197
|
+
- 测试中台保持简单:一个注册表、一个 `dev-complete` runner、一个最近结果、一个轻量 HTML 控制台和几个管理命令。
|
|
198
|
+
- 测试链路优先复用已有命令、脚本、截图或人工检查。
|
|
199
|
+
- 不要为了每个 bad case 都新写脚本。
|
|
200
|
+
- 前端或 HTML 改动结束前,应实际查看页面或截图,确认没有明显视觉错误。
|
|
201
|
+
- 任何新的长期测试 case 都先写简短草案,让用户确认后再变成 active 测试。
|
|
202
|
+
|
|
203
|
+
详细行为规则见 [`skills/context-guard/SKILL.md`](skills/context-guard/SKILL.md)。
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
|
|
4
|
+
const fs = require("fs");
|
|
5
|
+
const os = require("os");
|
|
6
|
+
const path = require("path");
|
|
7
|
+
const { spawnSync } = require("child_process");
|
|
8
|
+
|
|
9
|
+
const packageRoot = path.resolve(__dirname, "..");
|
|
10
|
+
const sourceSkillDir = path.join(packageRoot, "skills", "context-guard");
|
|
11
|
+
const sourceHooksPath = path.join(packageRoot, "hooks.json");
|
|
12
|
+
const pythonScript = path.join(sourceSkillDir, "scripts", "context_guard.py");
|
|
13
|
+
|
|
14
|
+
function usage() {
|
|
15
|
+
console.log(`Context Guard Skill
|
|
16
|
+
|
|
17
|
+
Usage:
|
|
18
|
+
context-guard install [--target <dir>] [--with-hooks] [--hooks-target <file>]
|
|
19
|
+
context-guard path
|
|
20
|
+
context-guard <context_guard.py command> [args...]
|
|
21
|
+
|
|
22
|
+
Examples:
|
|
23
|
+
npx context-guard install
|
|
24
|
+
npx context-guard install --with-hooks
|
|
25
|
+
npx context-guard show-roadmap --root /path/to/project
|
|
26
|
+
`);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function fail(message) {
|
|
30
|
+
console.error(`[context-guard-skill] ${message}`);
|
|
31
|
+
process.exit(1);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function expandHome(inputPath) {
|
|
35
|
+
if (!inputPath) return inputPath;
|
|
36
|
+
if (inputPath === "~") return os.homedir();
|
|
37
|
+
if (inputPath.startsWith("~/")) return path.join(os.homedir(), inputPath.slice(2));
|
|
38
|
+
return inputPath;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function defaultSkillTarget() {
|
|
42
|
+
if (process.env.CONTEXT_GUARD_SKILL_TARGET) {
|
|
43
|
+
return path.resolve(expandHome(process.env.CONTEXT_GUARD_SKILL_TARGET));
|
|
44
|
+
}
|
|
45
|
+
const agentsHome = process.env.AGENTS_HOME || path.join(os.homedir(), ".agents");
|
|
46
|
+
return path.join(agentsHome, "skills", "context-guard");
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function defaultHooksTarget() {
|
|
50
|
+
if (process.env.CONTEXT_GUARD_HOOKS_TARGET) {
|
|
51
|
+
return path.resolve(expandHome(process.env.CONTEXT_GUARD_HOOKS_TARGET));
|
|
52
|
+
}
|
|
53
|
+
const codexHome = process.env.CODEX_HOME || path.join(os.homedir(), ".codex");
|
|
54
|
+
return path.join(codexHome, "hooks.json");
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function parseInstallArgs(args) {
|
|
58
|
+
const options = {
|
|
59
|
+
target: defaultSkillTarget(),
|
|
60
|
+
withHooks: false,
|
|
61
|
+
hooksTarget: defaultHooksTarget(),
|
|
62
|
+
dryRun: false
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
66
|
+
const arg = args[i];
|
|
67
|
+
if (arg === "--target") {
|
|
68
|
+
const value = args[++i];
|
|
69
|
+
if (!value) fail("--target requires a directory");
|
|
70
|
+
options.target = path.resolve(expandHome(value));
|
|
71
|
+
} else if (arg === "--with-hooks" || arg === "--hooks") {
|
|
72
|
+
options.withHooks = true;
|
|
73
|
+
} else if (arg === "--hooks-target") {
|
|
74
|
+
const value = args[++i];
|
|
75
|
+
if (!value) fail("--hooks-target requires a file path");
|
|
76
|
+
options.hooksTarget = path.resolve(expandHome(value));
|
|
77
|
+
} else if (arg === "--dry-run") {
|
|
78
|
+
options.dryRun = true;
|
|
79
|
+
} else if (arg === "-h" || arg === "--help") {
|
|
80
|
+
usage();
|
|
81
|
+
process.exit(0);
|
|
82
|
+
} else {
|
|
83
|
+
fail(`unknown install option: ${arg}`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return options;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function copySkill(target, dryRun) {
|
|
90
|
+
if (!fs.existsSync(path.join(sourceSkillDir, "SKILL.md"))) {
|
|
91
|
+
fail(`source skill folder is missing: ${sourceSkillDir}`);
|
|
92
|
+
}
|
|
93
|
+
if (dryRun) {
|
|
94
|
+
console.log(`[context-guard-skill] would install skill to ${target}`);
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
fs.rmSync(target, { recursive: true, force: true });
|
|
98
|
+
fs.mkdirSync(path.dirname(target), { recursive: true });
|
|
99
|
+
fs.cpSync(sourceSkillDir, target, { recursive: true });
|
|
100
|
+
console.log(`[context-guard-skill] installed skill: ${target}`);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function rewriteHookCommands(hooksConfig, skillTarget) {
|
|
104
|
+
const hookScript = path.join(skillTarget, "scripts", "context_guard_hook.py");
|
|
105
|
+
const encodedHookScript = JSON.stringify(hookScript);
|
|
106
|
+
const next = JSON.parse(JSON.stringify(hooksConfig));
|
|
107
|
+
for (const groups of Object.values(next.hooks || {})) {
|
|
108
|
+
for (const group of groups || []) {
|
|
109
|
+
for (const hook of group.hooks || []) {
|
|
110
|
+
if (hook.type === "command" && typeof hook.command === "string" && hook.command.includes("context_guard_hook.py")) {
|
|
111
|
+
hook.command = `python3 ${encodedHookScript} ${hook.command.split(" ").pop()}`;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return next;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function mergeHooks(existing, incoming) {
|
|
120
|
+
const merged = existing && typeof existing === "object" ? existing : {};
|
|
121
|
+
merged.hooks = merged.hooks && typeof merged.hooks === "object" ? merged.hooks : {};
|
|
122
|
+
for (const [event, groups] of Object.entries(incoming.hooks || {})) {
|
|
123
|
+
const current = Array.isArray(merged.hooks[event]) ? merged.hooks[event] : [];
|
|
124
|
+
const withoutOldContextGuard = current.filter((group) => {
|
|
125
|
+
const hooks = Array.isArray(group && group.hooks) ? group.hooks : [];
|
|
126
|
+
return !hooks.some((hook) => String(hook.command || "").includes("context_guard_hook.py"));
|
|
127
|
+
});
|
|
128
|
+
merged.hooks[event] = withoutOldContextGuard.concat(groups);
|
|
129
|
+
}
|
|
130
|
+
return merged;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function installHooks(skillTarget, hooksTarget, dryRun) {
|
|
134
|
+
if (!fs.existsSync(sourceHooksPath)) {
|
|
135
|
+
fail(`source hooks file is missing: ${sourceHooksPath}`);
|
|
136
|
+
}
|
|
137
|
+
const rawIncoming = JSON.parse(fs.readFileSync(sourceHooksPath, "utf8"));
|
|
138
|
+
const incoming = rewriteHookCommands(rawIncoming, skillTarget);
|
|
139
|
+
let existing = {};
|
|
140
|
+
if (fs.existsSync(hooksTarget)) {
|
|
141
|
+
existing = JSON.parse(fs.readFileSync(hooksTarget, "utf8"));
|
|
142
|
+
}
|
|
143
|
+
const merged = mergeHooks(existing, incoming);
|
|
144
|
+
if (dryRun) {
|
|
145
|
+
console.log(`[context-guard-skill] would install hooks to ${hooksTarget}`);
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
fs.mkdirSync(path.dirname(hooksTarget), { recursive: true });
|
|
149
|
+
if (fs.existsSync(hooksTarget)) {
|
|
150
|
+
const backupPath = `${hooksTarget}.bak-${new Date().toISOString().replace(/[:.]/g, "-")}`;
|
|
151
|
+
fs.copyFileSync(hooksTarget, backupPath);
|
|
152
|
+
console.log(`[context-guard-skill] backed up hooks: ${backupPath}`);
|
|
153
|
+
}
|
|
154
|
+
fs.writeFileSync(hooksTarget, `${JSON.stringify(merged, null, 2)}\n`);
|
|
155
|
+
console.log(`[context-guard-skill] installed hooks: ${hooksTarget}`);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function install(args) {
|
|
159
|
+
const options = parseInstallArgs(args);
|
|
160
|
+
copySkill(options.target, options.dryRun);
|
|
161
|
+
if (options.withHooks) {
|
|
162
|
+
installHooks(options.target, options.hooksTarget, options.dryRun);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function runPython(args) {
|
|
167
|
+
if (!fs.existsSync(pythonScript)) {
|
|
168
|
+
fail(`context_guard.py is missing: ${pythonScript}`);
|
|
169
|
+
}
|
|
170
|
+
const result = spawnSync("python3", [pythonScript, ...args], { stdio: "inherit" });
|
|
171
|
+
if (result.error) fail(result.error.message);
|
|
172
|
+
process.exit(result.status === null ? 1 : result.status);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
const [command, ...rest] = process.argv.slice(2);
|
|
176
|
+
|
|
177
|
+
if (!command || command === "-h" || command === "--help" || command === "help") {
|
|
178
|
+
usage();
|
|
179
|
+
} else if (command === "install") {
|
|
180
|
+
install(rest);
|
|
181
|
+
} else if (command === "path") {
|
|
182
|
+
console.log(sourceSkillDir);
|
|
183
|
+
} else {
|
|
184
|
+
runPython([command, ...rest]);
|
|
185
|
+
}
|
package/hooks.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"hooks": {
|
|
3
|
+
"SessionStart": [
|
|
4
|
+
{
|
|
5
|
+
"matcher": "startup|resume|clear|compact",
|
|
6
|
+
"hooks": [
|
|
7
|
+
{
|
|
8
|
+
"type": "command",
|
|
9
|
+
"command": "python3 ./scripts/context_guard_hook.py session-start",
|
|
10
|
+
"timeout": 10,
|
|
11
|
+
"statusMessage": "Initializing context folder"
|
|
12
|
+
}
|
|
13
|
+
]
|
|
14
|
+
}
|
|
15
|
+
],
|
|
16
|
+
"UserPromptSubmit": [
|
|
17
|
+
{
|
|
18
|
+
"hooks": [
|
|
19
|
+
{
|
|
20
|
+
"type": "command",
|
|
21
|
+
"command": "python3 ./scripts/context_guard_hook.py user-prompt-submit",
|
|
22
|
+
"timeout": 10,
|
|
23
|
+
"statusMessage": "Checking context intake"
|
|
24
|
+
}
|
|
25
|
+
]
|
|
26
|
+
}
|
|
27
|
+
],
|
|
28
|
+
"Stop": [
|
|
29
|
+
{
|
|
30
|
+
"hooks": [
|
|
31
|
+
{
|
|
32
|
+
"type": "command",
|
|
33
|
+
"command": "python3 ./scripts/context_guard_hook.py stop",
|
|
34
|
+
"timeout": 10,
|
|
35
|
+
"statusMessage": "Checking context checkpoint"
|
|
36
|
+
}
|
|
37
|
+
]
|
|
38
|
+
}
|
|
39
|
+
]
|
|
40
|
+
}
|
|
41
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@michelj/context-guard",
|
|
3
|
+
"version": "0.4.0",
|
|
4
|
+
"description": "Install and run the Context Guard Codex skill.",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "git+ssh://git@github.com/Michel-Johnson/Context-Guard-Skill.git"
|
|
8
|
+
},
|
|
9
|
+
"publishConfig": {
|
|
10
|
+
"access": "public",
|
|
11
|
+
"registry": "https://registry.npmjs.org/"
|
|
12
|
+
},
|
|
13
|
+
"bin": {
|
|
14
|
+
"context-guard-skill": "bin/context-guard-skill.js",
|
|
15
|
+
"context-guard": "bin/context-guard-skill.js"
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"README.md",
|
|
19
|
+
"README.zh-CN.md",
|
|
20
|
+
"hooks.json",
|
|
21
|
+
"bin/",
|
|
22
|
+
"skills/context-guard/"
|
|
23
|
+
],
|
|
24
|
+
"scripts": {
|
|
25
|
+
"test": "bash tests/npm-install-smoke.sh && python3 -m py_compile skills/context-guard/scripts/context_guard.py skills/context-guard/scripts/context_guard_hook.py"
|
|
26
|
+
},
|
|
27
|
+
"engines": {
|
|
28
|
+
"node": ">=18"
|
|
29
|
+
}
|
|
30
|
+
}
|