@cat-kit/agent-context 1.1.4 → 1.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/README.md +259 -54
  2. package/dist/cli.js +1 -2
  3. package/dist/commands/done.js +1 -2
  4. package/dist/commands/install.js +1 -2
  5. package/dist/commands/printer.js +1 -2
  6. package/dist/commands/status.js +1 -2
  7. package/dist/commands/sync.js +1 -2
  8. package/dist/commands/validate.js +1 -2
  9. package/dist/content/actions.js +20 -14
  10. package/dist/content/index.js +13 -4
  11. package/dist/context/archiver.js +1 -2
  12. package/dist/context/reader.js +1 -2
  13. package/dist/context/validator.js +1 -2
  14. package/dist/runner.js +2 -3
  15. package/dist/stats.html +1 -1
  16. package/dist/tools.js +1 -2
  17. package/package.json +1 -5
  18. package/src/cli.ts +2 -8
  19. package/src/commands/done.ts +1 -3
  20. package/src/commands/install.ts +6 -1
  21. package/src/commands/sync.ts +1 -1
  22. package/src/content/actions.ts +30 -20
  23. package/src/content/index.ts +12 -2
  24. package/src/context/reader.ts +5 -13
  25. package/src/context/validator.ts +9 -3
  26. package/src/runner.ts +13 -11
  27. package/src/types.ts +1 -4
  28. package/dist/cli.js.map +0 -1
  29. package/dist/commands/done.js.map +0 -1
  30. package/dist/commands/install.js.map +0 -1
  31. package/dist/commands/printer.js.map +0 -1
  32. package/dist/commands/status.js.map +0 -1
  33. package/dist/commands/sync.js.map +0 -1
  34. package/dist/commands/validate.js.map +0 -1
  35. package/dist/content/actions.js.map +0 -1
  36. package/dist/content/index.js.map +0 -1
  37. package/dist/context/archiver.js.map +0 -1
  38. package/dist/context/reader.js.map +0 -1
  39. package/dist/context/validator.js.map +0 -1
  40. package/dist/runner.js.map +0 -1
  41. package/dist/tools.js.map +0 -1
package/README.md CHANGED
@@ -1,19 +1,41 @@
1
1
  # Agent Context
2
2
 
3
- `@cat-kit/agent-context` 为主流 AI 编程助手安装统一的 `agent-context` Skill,让同一套计划生命周期协议在不同工具里保持一致。
3
+ `@cat-kit/agent-context` 用来给 AI 编程助手安装统一的 `ac-workflow` Skill,让不同工具都按同一套 `.agent-context/` 协议管理任务。
4
4
 
5
- ## 它解决什么问题
5
+ 它解决的不是“如何生成代码”,而是“如何让 AI 在多轮协作里始终知道当前计划、下一步动作和什么时候该归档”。
6
6
 
7
- 旧版 AI 工具通常依赖命令文件或 workflow 目录来驱动任务流程,但现在主流产品都在转向 Skills。
8
- 如果你同时使用 Claude、Codex、Cursor、Antigravity、GitHub Copilot,就需要为不同工具分别维护同一套计划规则,内容容易漂移。
7
+ ## 核心模型
9
8
 
10
- `agent-context` v2 只维护一个核心 Skill,负责统一以下生命周期:
9
+ `agent-context` 由两部分组成:
10
+
11
+ - CLI:负责安装、同步、校验和归档
12
+ - Skill:负责在对话里识别 `init / plan / replan / implement / patch / rush / done` 这些动作
13
+
14
+ 安装 Skill 后,AI 会围绕项目根目录的 `.agent-context/` 目录工作:
15
+
16
+ ```text
17
+ .agent-context/
18
+ ├── plan-{N}/ # 当前计划(最多一个)
19
+ │ ├── plan.md
20
+ │ └── patch-{N}.md
21
+ ├── preparing/ # 待执行计划队列
22
+ │ └── plan-{N}/
23
+ └── done/ # 已归档计划
24
+ └── plan-{N}-{YYYYMMDD}/
25
+ ```
26
+
27
+ 生命周期如下:
11
28
 
12
29
  ```text
13
30
  init -> plan -> replan -> implement -> patch -> done
31
+ └-> rush -> done
14
32
  ```
15
33
 
16
- Skill 内部会约束 `.agent-context/` 目录、计划编号、`plan.md` 模板、实施验证和归档规则,用户不再需要依赖 `/ac-init` 这类命令触发。
34
+ 其中:
35
+
36
+ - `plan / replan / rush / patch` 需要你给出明确任务描述
37
+ - `implement` 不接受额外描述,只执行当前计划
38
+ - `done` 最终由 `agent-context done` 归档当前已执行计划
17
39
 
18
40
  ## 安装
19
41
 
@@ -23,86 +45,269 @@ Skill 内部会约束 `.agent-context/` 目录、计划编号、`plan.md` 模板
23
45
  npm install -g @cat-kit/agent-context
24
46
  ```
25
47
 
26
- ## 快速开始
27
-
28
- 在项目根目录执行:
48
+ 在项目根目录安装 Skill:
29
49
 
30
50
  ```bash
31
51
  agent-context install
32
52
  ```
33
53
 
34
- 交互式选择目标工具后,CLI 会在对应的 Skills 目录下安装统一的 `agent-context` Skill。
54
+ 也可以指定工具:
35
55
 
36
- 安装完成后,你可以直接向 AI 助手表达自然语言意图,例如:
56
+ ```bash
57
+ agent-context install --tools claude,codex,cursor
58
+ ```
37
59
 
38
- - “初始化这个项目的 agent context”
39
- - “为这个需求出一个计划”
40
- - “重做当前计划”
41
- - “按当前计划开始实现”
42
- - “给当前计划补一个 patch”
43
- - “当前计划已经真正完成,归档它”
60
+ 安装完成后,CLI 会在对应目录生成 Skill 文件,例如:
44
61
 
45
- ## 支持的工具
62
+ - Codex: `.codex/skills/agent-context/`
63
+ - Claude: `.claude/skills/agent-context/`
64
+ - Cursor: `.cursor/skills/agent-context/`
46
65
 
47
- | 工具 | Skill 目录 |
48
- | --- | --- |
49
- | Claude | `.claude/skills/agent-context/` |
50
- | Codex | `.codex/skills/agent-context/` |
51
- | Cursor | `.cursor/skills/agent-context/` |
52
- | Antigravity | `.agent/skills/agent-context/` |
53
- | GitHub Copilot | `.github/skills/agent-context/` |
66
+ ## 快速开始
67
+
68
+ 最常见的用法只有三步:
69
+
70
+ 1. 在项目里执行 `agent-context install`
71
+ 2. 把生成的 Skill 文件和 `.agent-context/` 一起纳入版本管理
72
+ 3. 直接在对话里对 AI 说出动作意图
73
+
74
+ 例如:
75
+
76
+ - `初始化这个项目的 agent context`
77
+ - `为“增加导出 Excel 功能”出一个计划`
78
+ - `按当前计划开始实现`
79
+ - `当前计划已经做完,归档它`
80
+
81
+ ## Action 参考
82
+
83
+ 下面的 action 不是 CLI 子命令,而是你对 AI 说的话。AI 安装 Skill 后,会把这些话映射到固定协议。
84
+
85
+ | Action | 何时使用 | 当前状态要求 | 结果 |
86
+ | ------ | -------- | ------------ | ---- |
87
+ | `init` | 项目还没建立好协作约定,或者 `AGENTS.md` 不完整 | 无 | 生成或补全 `AGENTS.md`,新项目可继续进入计划 |
88
+ | `plan` | 新需求需要正式拆分步骤 | 当前没有冲突中的已执行计划 | 创建 `plan.md`,必要时拆成当前计划 + preparing 队列 |
89
+ | `replan` | 计划还没实施,但拆分方式或技术路线要改 | 目标计划必须仍是 `未执行` | 重写计划结构,保留单当前计划模型 |
90
+ | `implement` | 计划已经明确,开始真正落地 | 当前计划存在且状态为 `未执行` | 实施全部步骤,验证通过后把计划改为 `已执行` |
91
+ | `patch` | 已执行计划上出现 Bug、遗漏项或增量需求 | 当前计划必须是 `已执行` | 执行修补,生成 `patch-{N}.md`,更新影响范围 |
92
+ | `rush` | 任务范围很清晰,不想先单独经历 plan 再 implement | 当前不能存在未实施计划 | 直接创建单计划并立刻实施 |
93
+ | `done` | 当前计划已经真正完成,需要收尾归档 | 当前计划必须是 `已执行` | 把当前计划移入 `done/`,必要时晋升下一个 preparing 计划 |
94
+
95
+ ### `init`
96
+
97
+ 适合两种场景:
98
+
99
+ - 新项目刚开始,没有统一协作规则
100
+ - 老项目已有代码,但缺少高质量 `AGENTS.md`
101
+
102
+ 你可以这样说:
103
+
104
+ ```text
105
+ 初始化这个项目的 agent context,技术栈是 Bun + TypeScript,测试用 Vitest
106
+ ```
107
+
108
+ AI 会先判断这是新项目还是旧项目,再决定是创建还是补全 `AGENTS.md`。如果项目信息不足,`init` 应该先提问,而不是直接猜。
109
+
110
+ ### `plan`
111
+
112
+ 适合“要做一件事,但还没开始改代码”的阶段。
113
+
114
+ 你可以这样说:
115
+
116
+ ```text
117
+ 为“给 http 客户端补一个重试插件”出计划
118
+ ```
119
+
120
+ `plan` 的重点不是生成一段漂亮的说明,而是产出一个后续可执行的 `plan.md`。如果任务很大,AI 应该拆成“当前计划 + preparing 队列”;如果任务很小,就只建一个计划。
121
+
122
+ ### `replan`
123
+
124
+ 只在“计划还没实施”时使用。它解决的是“原计划思路不对”,不是“代码写完后还想改一点”。
125
+
126
+ 你可以这样说:
127
+
128
+ ```text
129
+ 重做当前计划,不要引入新依赖,保持 core 零依赖
130
+ ```
131
+
132
+ 如果当前计划已经执行过,再要求修改方案,就不应该走 `replan`,而应该走 `patch`。
133
+
134
+ ### `implement`
135
+
136
+ 适合“计划已经定了,现在开始按计划干活”的阶段。
137
+
138
+ 你可以这样说:
139
+
140
+ ```text
141
+ 按当前计划开始实现
142
+ ```
143
+
144
+ `implement` 不接受附加需求。它只做一件事:读取当前 `plan.md`,逐步实施、验证、回写状态。如果执行中发现阻塞,AI 应该报告,而不是私自跳过步骤。
145
+
146
+ ### `patch`
147
+
148
+ 适合在“当前计划已经执行完成”之后做增量修补。
149
+
150
+ 你可以这样说:
151
+
152
+ ```text
153
+ 给当前计划补一个 patch,修复流式读取时空行被跳过的问题
154
+ ```
155
+
156
+ `patch` 会保留原计划,把新增修补记录写入 `patch-{N}.md`。如果你只是发现实现里还有一个小问题,不需要新开计划,优先用 `patch`。
157
+
158
+ ### `rush`
159
+
160
+ 适合边界清楚、工作量可控的任务,比如:
161
+
162
+ - 修一份文档
163
+ - 改一个很明确的测试
164
+ - 补一个小型脚本
54
165
 
55
- ## 生成产物
166
+ 你可以这样说:
56
167
 
57
- `agent-context` 会按工具生成对应官方支持的 Skill 产物:
168
+ ```text
169
+ rush 一下,把 agent-context 文档里的 action 解释补完整
170
+ ```
171
+
172
+ `rush` 的本质是“跳过单独确认计划内容”,但不是跳过计划本身。AI 仍然需要创建 `plan.md`,只是创建后直接实施。
173
+
174
+ ### `done`
175
+
176
+ 适合真正收尾时使用,不适合把“暂时先停一下”伪装成完成。
177
+
178
+ 你可以这样说:
179
+
180
+ ```text
181
+ 当前计划已经真正完成,归档它
182
+ ```
183
+
184
+ 归档后,当前计划会进入 `.agent-context/done/`。如果 `preparing/` 里还有下一个计划,它会被晋升为新的当前计划。
185
+
186
+ ## 具体协作场景
187
+
188
+ 下面是几条更具体、可直接复用的协作方式。
189
+
190
+ ### 场景 1:从零开始做一个新功能
191
+
192
+ 适用情况:需求还没拆解,涉及多个文件或多个步骤。
193
+
194
+ 推荐流程:
195
+
196
+ 1. `为“新增 xx 功能”出计划`
197
+ 2. 查看 AI 生成的 `plan.md`
198
+ 3. `按当前计划开始实现`
199
+ 4. 如果上线前又补了一个小需求:`给当前计划补一个 patch,...`
200
+ 5. 确认全部完成:`当前计划已经真正完成,归档它`
201
+
202
+ ### 场景 2:方案还没落地,但技术路线要改
203
+
204
+ 适用情况:计划还是 `未执行`,只是发现拆分不合理或路线变了。
205
+
206
+ 推荐指令:
207
+
208
+ ```text
209
+ 重做当前计划,保留目标不变,但改成不引入三方依赖的方案
210
+ ```
211
+
212
+ 这时应该用 `replan`,而不是让 AI 一边改计划一边偷偷改代码。
213
+
214
+ ### 场景 3:代码已经写完,但需要修一个增量问题
215
+
216
+ 适用情况:当前计划状态已经是 `已执行`。
217
+
218
+ 推荐指令:
219
+
220
+ ```text
221
+ 给当前计划补一个 patch,修复 Windows 路径兼容问题
222
+ ```
223
+
224
+ 这时继续走 `plan` 或 `rush` 都会破坏上下文连续性。正确做法是保留主计划,用 `patch` 记录增量修改。
225
+
226
+ ### 场景 4:任务非常明确,不想多轮沟通
227
+
228
+ 适用情况:工作边界清晰,几乎不需要额外澄清。
229
+
230
+ 推荐指令:
58
231
 
59
- | 工具 | 产物 |
60
- | --- | --- |
61
- | Claude | `SKILL.md`,包含 `name`、`description`、`argument-hint` frontmatter |
62
- | Codex | `SKILL.md` + `agents/openai.yaml` |
63
- | Cursor | `SKILL.md` |
64
- | Antigravity | `SKILL.md` |
65
- | GitHub Copilot | `SKILL.md`,包含 `name`、`description`、`license` frontmatter |
232
+ ```text
233
+ rush 一下,把 README 里的命令表更新为最新版本
234
+ ```
235
+
236
+ `rush` 很适合这种“知道要改什么,也知道验收标准”的任务,但不适合目标模糊的大需求。
66
237
 
67
- ## 命令参考
238
+ ## CLI 命令参考
239
+
240
+ CLI 只负责文件安装、同步和状态管理,不负责替代 action。
68
241
 
69
242
  ### `agent-context install`
70
243
 
71
- 安装 `agent-context` Skill。
244
+ 安装 Skill 文件。
72
245
 
73
246
  ```bash
74
- # 交互式选择工具
75
247
  agent-context install
76
-
77
- # 指定工具
78
- agent-context install --tools claude,codex,cursor
79
-
80
- # 仅检查将产生哪些变更
248
+ agent-context install --tools codex,claude
81
249
  agent-context install --check --tools copilot
250
+ agent-context install --yes
82
251
  ```
83
252
 
84
253
  ### `agent-context sync`
85
254
 
86
- 同步已经安装的 `agent-context` Skill。适用于升级 `@cat-kit/agent-context` 版本后更新 Skill 内容。
255
+ 当你升级了 `@cat-kit/agent-context` 版本后,用它把项目中的 Skill 内容同步到最新协议。
87
256
 
88
257
  ```bash
89
- # 同步当前已安装工具
90
258
  agent-context sync
259
+ agent-context sync --tools cursor,codex
260
+ agent-context sync --check
261
+ ```
91
262
 
92
- # 同步指定工具
93
- agent-context sync --tools claude,cursor
263
+ ### `agent-context validate`
94
264
 
95
- # 仅检查是否有待同步内容
96
- agent-context sync --check
265
+ 校验 `.agent-context/` 是否符合协议,例如:
266
+
267
+ - 当前计划是否唯一
268
+ - `plan.md` 是否存在
269
+ - 状态字段是否合法
270
+
271
+ ```bash
272
+ agent-context validate
97
273
  ```
98
274
 
99
- ### 通用选项
275
+ ### `agent-context status`
276
+
277
+ 查看当前计划、preparing 队列和归档数量。
278
+
279
+ ```bash
280
+ agent-context status
281
+ ```
282
+
283
+ ### `agent-context done`
284
+
285
+ 归档当前已执行计划。
286
+
287
+ ```bash
288
+ agent-context done
289
+ agent-context done --yes
290
+ ```
291
+
292
+ ## 通用选项
293
+
294
+ | 选项 | 适用命令 | 说明 |
295
+ | ---- | -------- | ---- |
296
+ | `--tools <tools>` | `install` / `sync` | 指定目标工具,逗号分隔 |
297
+ | `--check` | `install` / `sync` | 只检查是否有变更,不写文件 |
298
+ | `--yes` | `install` / `done` | 跳过交互确认;`install` 会优先复用已安装工具 |
299
+
300
+ ## 支持的工具
301
+
302
+ | 工具 | Skill 目录 |
303
+ | ---- | ---------- |
304
+ | Claude | `.claude/skills/agent-context/` |
305
+ | Codex | `.codex/skills/agent-context/` |
306
+ | Cursor | `.cursor/skills/agent-context/` |
307
+ | Antigravity | `.agent/skills/agent-context/` |
308
+ | GitHub Copilot | `.github/skills/agent-context/` |
100
309
 
101
- | 选项 | 说明 |
102
- | --- | --- |
103
- | `--tools <tools>` | 指定目标工具,逗号分隔 |
104
- | `--check` | 仅检查,不写入文件 |
105
- | `--yes` | 仅 `install` 支持;非交互模式下优先复用已安装工具,否则安装全部工具 |
310
+ 其中 Codex 会额外生成 `agents/openai.yaml` 元数据文件,其余工具只生成 Skill 内容本身。
106
311
 
107
312
  ## License
108
313
 
package/dist/cli.js CHANGED
@@ -1,3 +1,2 @@
1
1
  #!/usr/bin/env node
2
- import{doneCommand as e}from"./commands/done.js";import{installCommand as t}from"./commands/install.js";import{statusCommand as n}from"./commands/status.js";import{syncCommand as r}from"./commands/sync.js";import{validateCommand as i}from"./commands/validate.js";import{readFileSync as a}from"node:fs";import{Command as o}from"commander";const s=JSON.parse(a(new URL(`../package.json`,import.meta.url),`utf8`)),c=typeof s.version==`string`?s.version:`0.0.0`,l=new o;l.name(`agent-context`).description(`Agent Context Skills 安装工具`).version(c),l.command(`install`).description(`安装 ac-workflow Skill`).option(`--tools <tools>`,`指定目标工具,逗号分隔:claude,codex,cursor,antigravity,copilot`).option(`--yes`,`非交互模式:优先复用已安装工具,否则安装全部工具`).option(`--check`,`仅检查是否存在待更新内容,不写入文件`).action(t),l.command(`sync`).description(`同步已安装的 ac-workflow Skill`).option(`--tools <tools>`,`指定目标工具,逗号分隔:claude,codex,cursor,antigravity,copilot`).option(`--check`,`仅检查是否存在待更新内容,不写入文件`).action(r),l.command(`validate`).description(`校验 .agent-context 目录结构`).action(i),l.command(`status`).description(`查看当前 agent-context 状态`).action(n),l.command(`done`).description(`归档当前已执行计划`).option(`--yes`,`跳过确认,直接归档`).action(e),l.parseAsync().catch(e=>{let t=e instanceof Error?e.message:String(e);console.error(`\n❌ ${t}`),process.exitCode=1});export{};
3
- //# sourceMappingURL=cli.js.map
2
+ import{doneCommand as e}from"./commands/done.js";import{installCommand as t}from"./commands/install.js";import{statusCommand as n}from"./commands/status.js";import{syncCommand as r}from"./commands/sync.js";import{validateCommand as i}from"./commands/validate.js";import{readFileSync as a}from"node:fs";import{Command as o}from"commander";const s=JSON.parse(a(new URL(`../package.json`,import.meta.url),`utf8`)),c=typeof s.version==`string`?s.version:`0.0.0`,l=new o;l.name(`agent-context`).description(`Agent Context Skills 安装工具`).version(c),l.command(`install`).description(`安装 ac-workflow Skill`).option(`--tools <tools>`,`指定目标工具,逗号分隔:claude,codex,cursor,antigravity,copilot`).option(`--yes`,`非交互模式:优先复用已安装工具,否则安装全部工具`).option(`--check`,`仅检查是否存在待更新内容,不写入文件`).action(t),l.command(`sync`).description(`同步已安装的 ac-workflow Skill`).option(`--tools <tools>`,`指定目标工具,逗号分隔:claude,codex,cursor,antigravity,copilot`).option(`--check`,`仅检查是否存在待更新内容,不写入文件`).action(r),l.command(`validate`).description(`校验 .agent-context 目录结构`).action(i),l.command(`status`).description(`查看当前 agent-context 状态`).action(n),l.command(`done`).description(`归档当前已执行计划`).option(`--yes`,`跳过确认,直接归档`).action(e),l.parseAsync().catch(e=>{let t=e instanceof Error?e.message:String(e);console.error(`\n❌ ${t}`),process.exitCode=1});export{};
@@ -1,2 +1 @@
1
- import{readRawContext as e}from"../context/reader.js";import{validate as t}from"../context/validator.js";import{archive as n}from"../context/archiver.js";import{basename as r}from"node:path";import{confirm as i}from"@inquirer/prompts";async function a(a){let{snapshot:o,currentPlanCount:s}=await e(process.cwd()),c=t(o,s);if(!c.valid){for(let e of c.errors)console.log(`❌ ${e}`);process.exitCode=1;return}if(!o||!o.currentPlan){console.log(`❌ 无当前计划`),process.exitCode=1;return}if(o.currentPlan.status!==`已执行`){console.log(`❌ 当前计划 plan-${o.currentPlan.number} 尚未执行,无法归档。`),process.exitCode=1;return}if(!a.yes&&!await i({message:`确认归档 plan-${o.currentPlan.number}?`})){console.log(`已取消`);return}let l=await n(o),u=r(l.archivedTo);console.log(`✅ 已归档: plan-${o.currentPlan.number} → done/${u}`),l.promoted!==null&&console.log(`📋 已晋升: plan-${l.promoted} 为新的当前计划`),l.remainingPreparing>0?console.log(`📋 待执行队列剩余 ${l.remainingPreparing} 个计划`):l.promoted===null&&console.log(`ℹ 无更多待执行计划`)}export{a as doneCommand};
2
- //# sourceMappingURL=done.js.map
1
+ import{readRawContext as e}from"../context/reader.js";import{validate as t}from"../context/validator.js";import{archive as n}from"../context/archiver.js";import{basename as r}from"node:path";import{confirm as i}from"@inquirer/prompts";async function a(a){let{snapshot:o,currentPlanCount:s}=await e(process.cwd()),c=t(o,s);if(!c.valid){for(let e of c.errors)console.log(`❌ ${e}`);process.exitCode=1;return}if(!o||!o.currentPlan){console.log(`❌ 无当前计划`),process.exitCode=1;return}if(o.currentPlan.status!==`已执行`){console.log(`❌ 当前计划 plan-${o.currentPlan.number} 尚未执行,无法归档。`),process.exitCode=1;return}if(!a.yes&&!await i({message:`确认归档 plan-${o.currentPlan.number}?`})){console.log(`已取消`);return}let l=await n(o),u=r(l.archivedTo);console.log(`✅ 已归档: plan-${o.currentPlan.number} → done/${u}`),l.promoted!==null&&console.log(`📋 已晋升: plan-${l.promoted} 为新的当前计划`),l.remainingPreparing>0?console.log(`📋 待执行队列剩余 ${l.remainingPreparing} 个计划`):l.promoted===null&&console.log(`ℹ 无更多待执行计划`)}export{a as doneCommand};
@@ -1,2 +1 @@
1
- import{DEFAULT_TOOL_ORDER as e,detectConfiguredToolIds as t,getToolChoices as n,parseToolIds as r}from"../tools.js";import{runInstall as i}from"../runner.js";import{printCheckResult as a,printRunSummary as o}from"./printer.js";import{checkbox as s}from"@inquirer/prompts";async function c(e={}){let t=process.cwd(),n=await l(t,e),r=e.check??!1,s=await i({cwd:t,tools:n,check:r});if(r){a(s,t),s.changed.length>0&&(process.exitCode=1);return}o(s,t)}async function l(i,a){let o=a.tools;if(!o||o.trim().length===0){let r=t(i);return a.yes?r.length>0?r:[...e]:s({message:`请选择要安装 ac-workflow Skill 的工具(可多选):`,choices:n().map(e=>({name:e.name,value:e.id,checked:r.includes(e.id)})),required:!0})}return r(o)}export{c as installCommand};
2
- //# sourceMappingURL=install.js.map
1
+ import{DEFAULT_TOOL_ORDER as e,detectConfiguredToolIds as t,getToolChoices as n,parseToolIds as r}from"../tools.js";import{runInstall as i}from"../runner.js";import{printCheckResult as a,printRunSummary as o}from"./printer.js";import{checkbox as s}from"@inquirer/prompts";async function c(e={}){let t=process.cwd(),n=await l(t,e),r=e.check??!1,s=await i({cwd:t,tools:n,check:r});if(r){a(s,t),s.changed.length>0&&(process.exitCode=1);return}o(s,t)}async function l(i,a){let o=a.tools;if(!o||o.trim().length===0){let r=t(i);return a.yes?r.length>0?r:[...e]:s({message:`请选择要安装 ac-workflow Skill 的工具(可多选):`,choices:n().map(e=>({name:e.name,value:e.id,checked:r.includes(e.id)})),required:!0})}return r(o)}export{c as installCommand};
@@ -1,4 +1,3 @@
1
1
  import{relative as e}from"node:path";function t(t,n){if(console.log(`\n✅ ac-workflow ${t.mode} 完成`),t.created.length>0){console.log(`\n新增 ${t.created.length} 个文件:`);for(let r of t.created)console.log(`- ${e(n,r)}`)}if(t.updated.length>0){console.log(`\n更新 ${t.updated.length} 个文件:`);for(let r of t.updated)console.log(`- ${e(n,r)}`)}t.unchanged.length>0&&console.log(`\n无变更 ${t.unchanged.length} 个文件`)}function n(t,n){if(t.changed.length===0){console.log(`
2
2
  ✅ 检查通过:无需更新`);return}console.log(`
3
- ❌ 检查失败:以下文件需要更新`);for(let r of t.changed)console.log(`- ${e(n,r)}`)}export{n as printCheckResult,t as printRunSummary};
4
- //# sourceMappingURL=printer.js.map
3
+ ❌ 检查失败:以下文件需要更新`);for(let r of t.changed)console.log(`- ${e(n,r)}`)}export{n as printCheckResult,t as printRunSummary};
@@ -1,2 +1 @@
1
- import{readRawContext as e}from"../context/reader.js";import{validate as t}from"../context/validator.js";async function n(){let{snapshot:n,currentPlanCount:r}=await e(process.cwd()),i=t(n,r);if(!i.valid){for(let e of i.errors)console.log(`❌ ${e}`);process.exitCode=1;return}if(i.context===null){console.log(`ℹ 无活跃上下文`);return}let a=i.context,o=a.currentPlan?`plan-${a.currentPlan.number} (${a.currentPlan.status})`:`无`,s=a.preparing.length>0?a.preparing.map(e=>`plan-${e.number}`).join(`, `):`无`;console.log(``),console.log(`Agent Context Status`),console.log(`────────────────────`),console.log(`当前计划: ${o}`),console.log(`待执行队列: ${s}`),console.log(`已归档: ${a.done.length} 个`)}export{n as statusCommand};
2
- //# sourceMappingURL=status.js.map
1
+ import{readRawContext as e}from"../context/reader.js";import{validate as t}from"../context/validator.js";async function n(){let{snapshot:n,currentPlanCount:r}=await e(process.cwd()),i=t(n,r);if(!i.valid){for(let e of i.errors)console.log(`❌ ${e}`);process.exitCode=1;return}if(i.context===null){console.log(`ℹ 无活跃上下文`);return}let a=i.context,o=a.currentPlan?`plan-${a.currentPlan.number} (${a.currentPlan.status})`:`无`,s=a.preparing.length>0?a.preparing.map(e=>`plan-${e.number}`).join(`, `):`无`;console.log(``),console.log(`Agent Context Status`),console.log(`────────────────────`),console.log(`当前计划: ${o}`),console.log(`待执行队列: ${s}`),console.log(`已归档: ${a.done.length} 个`)}export{n as statusCommand};
@@ -1,2 +1 @@
1
- import{detectConfiguredToolIds as e,parseToolIds as t}from"../tools.js";import{runSync as n}from"../runner.js";import{printCheckResult as r,printRunSummary as i}from"./printer.js";async function a(e={}){let t=process.cwd(),a=o(t,e.tools),s=e.check??!1,c=await n({cwd:t,tools:a,check:s});if(s){r(c,t),c.changed.length>0&&(process.exitCode=1);return}i(c,t)}function o(n,r){if(!r||r.trim().length===0){let t=e(n);if(t.length>0)return t;throw Error(`未检测到已安装的 Skill,请先执行 install 或通过 --tools 显式指定工具`)}return t(r)}export{a as syncCommand};
2
- //# sourceMappingURL=sync.js.map
1
+ import{detectConfiguredToolIds as e,parseToolIds as t}from"../tools.js";import{runSync as n}from"../runner.js";import{printCheckResult as r,printRunSummary as i}from"./printer.js";async function a(e={}){let t=process.cwd(),a=o(t,e.tools),s=e.check??!1,c=await n({cwd:t,tools:a,check:s});if(s){r(c,t),c.changed.length>0&&(process.exitCode=1);return}i(c,t)}function o(n,r){if(!r||r.trim().length===0){let t=e(n);if(t.length>0)return t;throw Error(`未检测到已安装的 Skill,请先执行 install 或通过 --tools 显式指定工具`)}return t(r)}export{a as syncCommand};
@@ -1,2 +1 @@
1
- import{readRawContext as e}from"../context/reader.js";import{validate as t}from"../context/validator.js";async function n(){let{snapshot:n,currentPlanCount:r}=await e(process.cwd()),i=t(n,r);if(i.context===null){console.log(`⚠️ 无 .agent-context 目录`);return}if(i.valid){console.log(`✅ 校验通过`);let e=i.context,t=e.currentPlan?`plan-${e.currentPlan.number} (${e.currentPlan.status})`:`无`;console.log(` 当前计划: ${t}`),console.log(` 待执行: ${e.preparing.length} 个`),console.log(` 已归档: ${e.done.length} 个`);return}for(let e of i.errors)console.log(`❌ ${e}`);process.exitCode=1}export{n as validateCommand};
2
- //# sourceMappingURL=validate.js.map
1
+ import{readRawContext as e}from"../context/reader.js";import{validate as t}from"../context/validator.js";async function n(){let{snapshot:n,currentPlanCount:r}=await e(process.cwd()),i=t(n,r);if(i.context===null){console.log(`⚠️ 无 .agent-context 目录`);return}if(i.valid){console.log(`✅ 校验通过`);let e=i.context,t=e.currentPlan?`plan-${e.currentPlan.number} (${e.currentPlan.status})`:`无`;console.log(` 当前计划: ${t}`),console.log(` 待执行: ${e.preparing.length} 个`),console.log(` 已归档: ${e.done.length} 个`);return}for(let e of i.errors)console.log(`❌ ${e}`);process.exitCode=1}export{n as validateCommand};
@@ -41,7 +41,9 @@ const e=[`init`,`plan`,`replan`,`implement`,`patch`,`rush`],t={init:n,plan:r,rep
41
41
 
42
42
  - 运行 \`agent-context validate\`,不通过则中止并报告错误。
43
43
  - 描述为空 → 拒绝执行。
44
- - 存在未归档的已执行当前计划 → 拒绝执行,提示先运行 \`agent-context done\` 归档。
44
+ - 存在未归档的已执行当前计划 → 判断新需求与当前计划的关联性:
45
+ - 相关联或用户本意是修补 → 拒绝执行,提示改用 patch。
46
+ - 完全无关 → 拒绝执行,提示先运行 \`agent-context done\` 归档后再创建新计划。
45
47
  - 存在多个当前计划 → 拒绝执行,提示恢复单活跃状态。
46
48
 
47
49
  ## 执行步骤
@@ -110,7 +112,7 @@ const e=[`init`,`plan`,`replan`,`implement`,`patch`,`rush`],t={init:n,plan:r,rep
110
112
  3. 生成新的拆分方案,保持「单当前计划 + 若干 preparing 计划」结构。
111
113
  4. 新增计划编号:全局 max(N)+1 递增分配;未改动计划保持原编号。
112
114
  5. 更新目录结构,确保每个新计划的 \`plan.md\` 遵循标准模板。
113
- `}function a(){return"# implement\n\n实施当前计划 `.agent-context/plan-{number}/plan.md` 中的全部步骤,通过验证循环后将状态更新为「已执行」。\n\n不接受额外描述。\n\n## 前置检查\n\n- 运行 `agent-context validate`,不通过则中止并报告错误。\n- 带描述 → 拒绝执行。\n- 当前计划不存在 → 拒绝执行,提示先创建计划。\n- 当前计划状态为 `已执行` → 拒绝执行,提示使用 patch 修补或运行 `agent-context done` 归档。\n- `## 目标` 或 `## 内容` 为空 → 拒绝执行,提示补充。\n- 存在多个当前计划 → 拒绝执行,提示恢复单活跃状态。\n- 仅操作当前计划,不直接操作 `preparing/` 中的计划。\n- 遇到阻塞问题应向用户报告,不可静默跳过。\n\n## 执行步骤\n\n1. 读取当前计划 `plan.md`,理解 `## 目标` 与 `## 内容`。\n2. 依据 `## 内容` 中的步骤逐项实施。\n3. **验证循环**(全部通过前不可进入步骤 4):\n a. 逐项对照 `## 内容` 确认每个步骤已实施。\n b. 运行项目验证:类型检查 测试。\n c. 若存在失败项 修复后回到 a 重新验证。\n d. 全部通过 进入步骤 4。\n4. 更新 `plan.md` 状态行:`> 状态: 未执行` → `> 状态: 已执行`。\n5. 更新 `## 影响范围`,记录所有变更文件。\n"}function o(){return`# patch
115
+ `}function a(){return"# implement\n\n实施当前计划 `.agent-context/plan-{number}/plan.md` 中的全部步骤,通过验证循环后将状态更新为「已执行」。\n\n不接受额外描述。\n\n## 前置检查\n\n- 运行 `agent-context validate`,不通过则中止并报告错误。\n- 带描述 → 拒绝执行。\n- 当前计划不存在 → 拒绝执行,提示先创建计划。\n- 当前计划状态为 `已执行` → 拒绝执行,提示使用 patch 修补或运行 `agent-context done` 归档。\n- `## 目标` 或 `## 内容` 为空 → 拒绝执行,提示补充。\n- 存在多个当前计划 → 拒绝执行,提示恢复单活跃状态。\n- 仅操作当前计划,不直接操作 `preparing/` 中的计划。\n- 遇到阻塞问题应向用户报告,不可静默跳过。\n\n## 执行步骤\n\n1. **读取计划**:读取当前 `plan.md`,理解 `## 目标` 与 `## 内容`。\n2. **实施变更**:依据 `## 内容` 的步骤逐项实施。\n3. **验证循环(WHILE 循环检查)**:\n - **3.1 检查对照**:对照 `## 内容`,确保每个步骤均已实施完毕,无遗漏。\n - **3.2 运行验证**:\n - **IF** (编码任务) **THEN**:必须运行代码检查(Lint/Typecheck)与相关测试命令。\n - **ELSE IF** (非编码任务,如纯文档修改或项目规划) **THEN**:无需运行外部命令,仅凭逻辑和视觉排版审阅是否符合验收标准。\n - **3.3 结果判断**:\n - **IF** (存在未通过的验证报错、未完成项或遗漏项) **THEN**:修复发现的问题,然后 **GOTO 3.1**(重新检查)。\n - **ELSE IF** (验证全部通过 或 非编码任务验收合格) **THEN**:退出验证循环,即 **GOTO 4** 继续执行。\n4. **更新状态**:将 `plan.md` 的状态行修改为 `> 状态: 已执行`。\n5. **记录范围**:更新 `## 影响范围`,详细记录本次变动的具体文件路径。`.agent-context/` 目录下的文件不计入影响范围。\n"}function o(){return`# patch
114
116
 
115
117
  基于当前已执行计划创建增量补丁,修复问题或追加变更。
116
118
 
@@ -133,7 +135,7 @@ const e=[`init`,`plan`,`replan`,`implement`,`patch`,`rush`],t={init:n,plan:r,rep
133
135
  4. 创建 \`patch-{number}.md\`(编号:扫描当前计划目录已有补丁取 max+1),遵循下方模板。
134
136
  5. 回写 \`plan.md\`:
135
137
  - \`## 历史补丁\`:追加 \`- patch-{number}: {补丁名称}\`,按编号去重。
136
- - \`## 影响范围\`:合并本次变更路径,按路径去重。
138
+ - \`## 影响范围\`:合并本次变更路径,按路径去重。\`.agent-context/\` 目录下的文件不计入影响范围。
137
139
 
138
140
  ## patch.md 模板
139
141
 
@@ -160,18 +162,22 @@ const e=[`init`,`plan`,`replan`,`implement`,`patch`,`rush`],t={init:n,plan:r,rep
160
162
 
161
163
  - 运行 \`agent-context validate\`,不通过则中止并报告错误。
162
164
  - 描述为空 → 拒绝执行。
163
- - 存在未归档的已执行当前计划 → 拒绝执行,提示先运行 \`agent-context done\` 归档。
165
+ - 存在未归档的已执行当前计划 → 判断新需求与当前计划的关联性:
166
+ - 相关联或用户本意是修补 → 拒绝执行,提示改用 patch。
167
+ - 完全无关 → 拒绝执行,提示先运行 \`agent-context done\` 归档后再创建新计划。
164
168
  - 存在未实施的当前计划 → 拒绝执行,提示先 implement 或 replan。
165
169
 
166
170
  ## 执行步骤
167
171
 
168
- 1. plan 协议创建单计划(不拆分,不进入 preparing 队列)。
169
- 2. 无需用户确认计划内容,直接进入 implement 流程。
170
- 3. 按 implement 协议执行全部步骤,包括验证循环:
171
- a. 逐项对照 \`## 内容\` 确认每个步骤已实施。
172
- b. 运行项目验证:类型检查 → 测试。
173
- c. 若存在失败项 修复后重新验证。
174
- d. 全部通过 进入步骤 4。
175
- 4. 更新 \`plan.md\` 状态行为 \`已执行\`,更新 \`## 影响范围\`。
176
- `}export{e as ACTION_NAMES,t as ACTION_RENDERERS};
177
- //# sourceMappingURL=actions.js.map
172
+ > rush = plan + implement 的连续执行,下方仅列出差异点,未提及的步骤按原协议执行。
173
+
174
+ ### 阶段一:plan(差异)
175
+
176
+ - 跳过「需求澄清」步骤——rush 要求描述本身已足够明确。
177
+ - 强制单计划,不拆分,不进入 preparing 队列。
178
+ - 完成 plan 后**不等待用户确认**,直接进入阶段二。
179
+
180
+ ### 阶段二:implement
181
+
182
+ - 按 \`implement\` 协议**完整执行**(读取计划 → 实施变更 → 验证循环 → 更新状态与影响范围),无任何裁剪。
183
+ `}export{e as ACTION_NAMES,t as ACTION_RENDERERS};
@@ -1,7 +1,14 @@
1
1
  import{ACTION_NAMES as e,ACTION_RENDERERS as t}from"./actions.js";function n(n){let i=[{relativePath:`SKILL.md`,body:r(n)},...e.map(e=>({relativePath:`actions/${e}.md`,body:t[e]()}))];return n.metadataFiles.includes(`openai`)&&i.push({relativePath:`agents/openai.yaml`,body:a()}),{files:i}}function r(e){return`${i(e)}
2
2
  # Agent Context
3
3
 
4
- 管理项目中的 \`.agent-context/\` 计划生命周期。匹配用户意图后,读取对应协议文件(相对于本文件所在目录)严格执行。
4
+ 管理项目中的 \`.agent-context/\` 计划生命周期。匹配用户意图后,**必须先读取对应协议文件的完整内容**,再严格按协议步骤逐项执行。
5
+
6
+ ## 执行纪律
7
+
8
+ - **协议先行**:匹配到动作后,必须先读取对应 \`actions/*.md\` 协议文件的完整内容,再逐步执行。禁止凭记忆、摘要或猜测跳过协议步骤。
9
+ - **前置检查必做**:所有动作(done 除外)均包含「前置检查」,必须逐条执行,不可跳过。包括运行 \`agent-context validate\`。
10
+ - **禁止直接改动**:在 plan / rush 创建计划之前,不得直接修改项目代码文件。任何代码变更必须在已创建计划(implement)或已创建补丁(patch)的上下文中进行。
11
+ - **顺序执行**:协议步骤必须按编号顺序逐项执行,不可跳步、合并或并行。
5
12
 
6
13
  ## 意图匹配
7
14
 
@@ -15,7 +22,9 @@ import{ACTION_NAMES as e,ACTION_RENDERERS as t}from"./actions.js";function n(n){
15
22
  | 无活跃计划时快速出计划并实施 | rush | \`actions/rush.md\` |
16
23
  | 任务彻底完成、归档当前计划 | done | 运行 \`agent-context done\` |
17
24
 
18
- > **消歧**:存在已执行的当前计划时,用户提出任何变更需求 → 一律走 **patch**,禁止走 plan / rush。
25
+ > **消歧**:存在已执行的当前计划时,用户提出变更需求:
26
+ > - 需求与当前计划**相关联**或用户本意是修补当前计划 → 走 **patch**。
27
+ > - 需求与当前计划**完全无关** → 拒绝执行,提示先运行 \`agent-context done\` 归档当前计划后再创建新计划。
19
28
 
20
29
  ## 全局约束
21
30
 
@@ -23,6 +32,7 @@ import{ACTION_NAMES as e,ACTION_RENDERERS as t}from"./actions.js";function n(n){
23
32
  - 任意时刻最多一个当前计划:\`.agent-context/plan-{number}\`。
24
33
  - 多个当前计划 → 拒绝执行,提示恢复单活跃状态。
25
34
  - 计划编号全局递增,不复用。补丁编号在单计划目录内递增,不复用。
35
+ - 影响范围(\`## 影响范围\`)不得包含 \`.agent-context/\` 目录下的文件。
26
36
 
27
37
  ## 目录结构
28
38
 
@@ -46,5 +56,4 @@ import{ACTION_NAMES as e,ACTION_RENDERERS as t}from"./actions.js";function n(n){
46
56
 
47
57
  policy:
48
58
  allow_implicit_invocation: true
49
- `}export{n as renderSkillArtifacts};
50
- //# sourceMappingURL=index.js.map
59
+ `}export{n as renderSkillArtifacts};
@@ -1,2 +1 @@
1
- import{join as e}from"node:path";import{mkdir as t,rename as n}from"node:fs/promises";async function r(r){if(!r.currentPlan)throw Error(`无当前计划`);if(r.currentPlan.status!==`已执行`)throw Error(`当前计划尚未执行`);let a=`plan-${r.currentPlan.number}-${i()}`,o=e(r.root,`done`),s=e(o,a);await t(o,{recursive:!0}),await n(r.currentPlan.dir,s);let c=null,l=r.preparing[0];if(l){let t=e(r.root,`plan-${l.number}`);await n(l.dir,t),c=l.number}return{archivedTo:s,promoted:c,remainingPreparing:r.preparing.length-(c===null?0:1)}}function i(){let e=new Date;return`${String(e.getFullYear())}${String(e.getMonth()+1).padStart(2,`0`)}${String(e.getDate()).padStart(2,`0`)}`}export{r as archive};
2
- //# sourceMappingURL=archiver.js.map
1
+ import{join as e}from"node:path";import{mkdir as t,rename as n}from"node:fs/promises";async function r(r){if(!r.currentPlan)throw Error(`无当前计划`);if(r.currentPlan.status!==`已执行`)throw Error(`当前计划尚未执行`);let a=`plan-${r.currentPlan.number}-${i()}`,o=e(r.root,`done`),s=e(o,a);await t(o,{recursive:!0}),await n(r.currentPlan.dir,s);let c=null,l=r.preparing[0];if(l){let t=e(r.root,`plan-${l.number}`);await n(l.dir,t),c=l.number}return{archivedTo:s,promoted:c,remainingPreparing:r.preparing.length-(c===null?0:1)}}function i(){let e=new Date;return`${String(e.getFullYear())}${String(e.getMonth()+1).padStart(2,`0`)}${String(e.getDate()).padStart(2,`0`)}`}export{r as archive};
@@ -1,2 +1 @@
1
- import{existsSync as e}from"node:fs";import{join as t}from"node:path";import{readFile as n,readdir as r}from"node:fs/promises";const i=/^plan-(\d+)$/,a=/^plan-(\d+)(?:-\d{8})?$/,o=/^>\s*状态:\s*(未执行|已执行)$/m,s=/^>?[ \t]*状态[::].*$/m;async function c(n){let r=t(n,`.agent-context`);if(!e(r))return{snapshot:null,currentPlanCount:0};let i=await u(r),a=await u(t(r,`preparing`)),o=await d(t(r,`done`));return{snapshot:{root:r,currentPlan:i[0]??null,preparing:a,done:o},currentPlanCount:i.length}}async function l(r){let i=t(r,`plan.md`);if(!e(i))return`未执行`;let a=await n(i,`utf-8`),c=a.match(o);return c?c[1]:s.test(a)?`未知`:`未执行`}async function u(n){if(!e(n))return[];let a=await r(n,{withFileTypes:!0}),o=[];for(let e of a){if(!e.isDirectory())continue;let r=e.name.match(i);if(!r?.[1])continue;let a=parseInt(r[1],10),s=t(n,e.name),c=await l(s);o.push({number:a,status:c,dir:s})}return o.sort((e,t)=>e.number-t.number)}async function d(n){if(!e(n))return[];let i=await r(n,{withFileTypes:!0}),o=[];for(let e of i){if(!e.isDirectory())continue;let r=e.name.match(a);r?.[1]&&o.push({number:parseInt(r[1],10),dir:t(n,e.name)})}return o.sort((e,t)=>e.number-t.number)}export{c as readRawContext};
2
- //# sourceMappingURL=reader.js.map
1
+ import{existsSync as e}from"node:fs";import{join as t}from"node:path";import{readFile as n,readdir as r}from"node:fs/promises";const i=/^plan-(\d+)$/,a=/^plan-(\d+)(?:-\d{8})?$/,o=/^>\s*状态:\s*(未执行|已执行)$/m,s=/^>?[ \t]*状态[::].*$/m;async function c(n){let r=t(n,`.agent-context`);if(!e(r))return{snapshot:null,currentPlanCount:0};let i=await u(r),a=await u(t(r,`preparing`)),o=await d(t(r,`done`));return{snapshot:{root:r,currentPlan:i[0]??null,preparing:a,done:o},currentPlanCount:i.length}}async function l(r){let i=t(r,`plan.md`);if(!e(i))return`未执行`;let a=await n(i,`utf-8`),c=a.match(o);return c?c[1]:s.test(a)?`未知`:`未执行`}async function u(n){if(!e(n))return[];let a=await r(n,{withFileTypes:!0}),o=[];for(let e of a){if(!e.isDirectory())continue;let r=e.name.match(i);if(!r?.[1])continue;let a=parseInt(r[1],10),s=t(n,e.name),c=await l(s);o.push({number:a,status:c,dir:s})}return o.sort((e,t)=>e.number-t.number)}async function d(n){if(!e(n))return[];let i=await r(n,{withFileTypes:!0}),o=[];for(let e of i){if(!e.isDirectory())continue;let r=e.name.match(a);r?.[1]&&o.push({number:parseInt(r[1],10),dir:t(n,e.name)})}return o.sort((e,t)=>e.number-t.number)}export{c as readRawContext};
@@ -1,2 +1 @@
1
- import{existsSync as e}from"node:fs";import{join as t}from"node:path";function n(n,r){if(n===null)return{valid:!0,errors:[],context:null};let i=[];r>1&&i.push(`存在 ${r} 个当前计划,应最多 1 个。`),n.currentPlan&&(e(t(n.currentPlan.dir,`plan.md`))||i.push(`当前计划 plan-${n.currentPlan.number} 缺少 plan.md。`),n.currentPlan.status===`未知`&&i.push(`当前计划 plan-${n.currentPlan.number} 的状态格式严重不符合要求,请严格按照 "> 状态: 已执行" 或 "> 状态: 未执行" 的格式书写,禁止添加 emoji 或其他额外字符。`));for(let e of n.preparing)e.status===`未知`&&i.push(`待执行计划 plan-${e.number} 的状态格式严重不符合要求,请严格按照 "> 状态: 已执行" 或 "> 状态: 未执行" 的格式书写。`);let a=[];for(let e of n.done)a.push(e.number);n.currentPlan&&a.push(n.currentPlan.number);for(let e of n.preparing)a.push(e.number);let o=new Set,s=new Set;for(let e of a)o.has(e)&&s.add(e),o.add(e);if(s.size>0){let e=[...s].sort((e,t)=>e-t).join(`, `);i.push(`计划编号冲突: ${e}。`)}a.sort((e,t)=>e-t);for(let e=0;e<a.length;e++)if(a[e]!==e+1){i.push(`计划序列不连续或未从 1 开始。预期出现编号 ${e+1},实际遇到编号 ${a[e]} (要求必须是从 1 开始顺序查询)。`);break}return{valid:i.length===0,errors:i,context:n}}export{n as validate};
2
- //# sourceMappingURL=validator.js.map
1
+ import{existsSync as e}from"node:fs";import{join as t}from"node:path";function n(n,r){if(n===null)return{valid:!0,errors:[],context:null};let i=[];r>1&&i.push(`存在 ${r} 个当前计划,应最多 1 个。`),n.currentPlan&&(e(t(n.currentPlan.dir,`plan.md`))||i.push(`当前计划 plan-${n.currentPlan.number} 缺少 plan.md。`),n.currentPlan.status===`未知`&&i.push(`当前计划 plan-${n.currentPlan.number} 的状态格式严重不符合要求,请严格按照 "> 状态: 已执行" 或 "> 状态: 未执行" 的格式书写,禁止添加 emoji 或其他额外字符。`));for(let e of n.preparing)e.status===`未知`&&i.push(`待执行计划 plan-${e.number} 的状态格式严重不符合要求,请严格按照 "> 状态: 已执行" 或 "> 状态: 未执行" 的格式书写。`);let a=[];for(let e of n.done)a.push(e.number);n.currentPlan&&a.push(n.currentPlan.number);for(let e of n.preparing)a.push(e.number);let o=new Set,s=new Set;for(let e of a)o.has(e)&&s.add(e),o.add(e);if(s.size>0){let e=[...s].sort((e,t)=>e-t).join(`, `);i.push(`计划编号冲突: ${e}。`)}a.sort((e,t)=>e-t);for(let e=0;e<a.length;e++)if(a[e]!==e+1){i.push(`计划序列不连续或未从 1 开始。预期出现编号 ${e+1},实际遇到编号 ${a[e]} (要求必须是从 1 开始顺序查询)。`);break}return{valid:i.length===0,errors:i,context:n}}export{n as validate};
package/dist/runner.js CHANGED
@@ -1,3 +1,2 @@
1
- import{resolveSkillPaths as e,resolveToolTargets as t}from"./tools.js";import{renderSkillArtifacts as n}from"./content/index.js";import{existsSync as r}from"node:fs";import{dirname as i,resolve as a}from"node:path";import{mkdir as o,readFile as s,writeFile as c}from"node:fs/promises";async function l(e={}){return d(`install`,e)}async function u(e={}){return d(`sync`,e)}async function d(e,n){let r=n.cwd??process.cwd(),i=t(_(n.tools)).flatMap(e=>f(e,r)),a=n.check??!1;return{...await m(i,a),mode:e,check:a}}function f(t,r){let i=n(t),a=e(t,r);return i.files.map(e=>({path:p(a,e.relativePath),body:e.body}))}function p(e,t){return t===`SKILL.md`?e.skillFile:a(e.skillDir,t)}async function m(e,t){let n={created:[],updated:[],unchanged:[],changed:[]};for(let a of e){let e=r(a.path),s=await h(a,e);if(!s.changed){n.unchanged.push(a.path);continue}t||(await o(i(a.path),{recursive:!0}),await c(a.path,s.content,`utf-8`)),n.changed.push(a.path),e?n.updated.push(a.path):n.created.push(a.path)}return n}async function h(e,t){let n=g(e.body);return t?{content:n,changed:await s(e.path,`utf-8`)!==n}:{content:n,changed:!0}}function g(e){return e.endsWith(`
2
- `)?e:`${e}\n`}function _(e){if(!(!e||e.length===0))return[...new Set(e)]}export{l as runInstall,u as runSync};
3
- //# sourceMappingURL=runner.js.map
1
+ import{renderSkillArtifacts as e}from"./content/index.js";import{resolveSkillPaths as t,resolveToolTargets as n}from"./tools.js";import{existsSync as r}from"node:fs";import{dirname as i,resolve as a}from"node:path";import{mkdir as o,readFile as s,writeFile as c}from"node:fs/promises";async function l(e={}){return d(`install`,e)}async function u(e={}){return d(`sync`,e)}async function d(e,t){let r=t.cwd??process.cwd(),i=n(_(t.tools)).flatMap(e=>f(e,r)),a=t.check??!1;return{...await m(i,a),mode:e,check:a}}function f(n,r){let i=e(n),a=t(n,r);return i.files.map(e=>({path:p(a,e.relativePath),body:e.body}))}function p(e,t){return t===`SKILL.md`?e.skillFile:a(e.skillDir,t)}async function m(e,t){let n={created:[],updated:[],unchanged:[],changed:[]};for(let a of e){let e=r(a.path),s=await h(a,e);if(!s.changed){n.unchanged.push(a.path);continue}t||(await o(i(a.path),{recursive:!0}),await c(a.path,s.content,`utf-8`)),n.changed.push(a.path),e?n.updated.push(a.path):n.created.push(a.path)}return n}async function h(e,t){let n=g(e.body);return t?{content:n,changed:await s(e.path,`utf-8`)!==n}:{content:n,changed:!0}}function g(e){return e.endsWith(`
2
+ `)?e:`${e}\n`}function _(e){if(!(!e||e.length===0))return[...new Set(e)]}export{l as runInstall,u as runSync};
package/dist/stats.html CHANGED
@@ -4930,7 +4930,7 @@ var drawChart = (function (exports) {
4930
4930
  </script>
4931
4931
  <script>
4932
4932
  /*<!--*/
4933
- const data = {"version":2,"tree":{"name":"root","children":[{"name":"cli.d.ts","children":[{"name":"home/whj/codes/cat-kit/packages/agent-context/src/cli.d.ts","uid":"04e2242d-1"}]},{"name":"cli.js","children":[{"name":"home/whj/codes/cat-kit/packages/agent-context/src/cli.ts","uid":"04e2242d-3"}]},{"name":"commands/done.js","children":[{"name":"home/whj/codes/cat-kit/packages/agent-context/src/commands/done.ts","uid":"04e2242d-5"}]},{"name":"commands/install.js","children":[{"name":"home/whj/codes/cat-kit/packages/agent-context/src/commands/install.ts","uid":"04e2242d-7"}]},{"name":"commands/printer.js","children":[{"name":"home/whj/codes/cat-kit/packages/agent-context/src/commands/printer.ts","uid":"04e2242d-9"}]},{"name":"commands/status.js","children":[{"name":"home/whj/codes/cat-kit/packages/agent-context/src/commands/status.ts","uid":"04e2242d-11"}]},{"name":"commands/sync.js","children":[{"name":"home/whj/codes/cat-kit/packages/agent-context/src/commands/sync.ts","uid":"04e2242d-13"}]},{"name":"commands/validate.js","children":[{"name":"home/whj/codes/cat-kit/packages/agent-context/src/commands/validate.ts","uid":"04e2242d-15"}]},{"name":"content/actions.js","children":[{"name":"home/whj/codes/cat-kit/packages/agent-context/src/content/actions.ts","uid":"04e2242d-17"}]},{"name":"content/index.js","children":[{"name":"home/whj/codes/cat-kit/packages/agent-context/src/content/index.ts","uid":"04e2242d-19"}]},{"name":"context/archiver.js","children":[{"name":"home/whj/codes/cat-kit/packages/agent-context/src/context/archiver.ts","uid":"04e2242d-21"}]},{"name":"context/reader.js","children":[{"name":"home/whj/codes/cat-kit/packages/agent-context/src/context/reader.ts","uid":"04e2242d-23"}]},{"name":"context/validator.js","children":[{"name":"home/whj/codes/cat-kit/packages/agent-context/src/context/validator.ts","uid":"04e2242d-25"}]},{"name":"runner.js","children":[{"name":"home/whj/codes/cat-kit/packages/agent-context/src/runner.ts","uid":"04e2242d-27"}]},{"name":"tools.js","children":[{"name":"home/whj/codes/cat-kit/packages/agent-context/src/tools.ts","uid":"04e2242d-29"}]}],"isRoot":true},"nodeParts":{"04e2242d-1":{"renderedLength":0,"gzipLength":0,"brotliLength":0,"metaUid":"04e2242d-0"},"04e2242d-3":{"renderedLength":1518,"gzipLength":0,"brotliLength":0,"metaUid":"04e2242d-2"},"04e2242d-5":{"renderedLength":1349,"gzipLength":0,"brotliLength":0,"metaUid":"04e2242d-4"},"04e2242d-7":{"renderedLength":985,"gzipLength":0,"brotliLength":0,"metaUid":"04e2242d-6"},"04e2242d-9":{"renderedLength":909,"gzipLength":0,"brotliLength":0,"metaUid":"04e2242d-8"},"04e2242d-11":{"renderedLength":946,"gzipLength":0,"brotliLength":0,"metaUid":"04e2242d-10"},"04e2242d-13":{"renderedLength":745,"gzipLength":0,"brotliLength":0,"metaUid":"04e2242d-12"},"04e2242d-15":{"renderedLength":763,"gzipLength":0,"brotliLength":0,"metaUid":"04e2242d-14"},"04e2242d-17":{"renderedLength":8872,"gzipLength":0,"brotliLength":0,"metaUid":"04e2242d-16"},"04e2242d-19":{"renderedLength":3024,"gzipLength":0,"brotliLength":0,"metaUid":"04e2242d-18"},"04e2242d-21":{"renderedLength":1012,"gzipLength":0,"brotliLength":0,"metaUid":"04e2242d-20"},"04e2242d-23":{"renderedLength":2081,"gzipLength":0,"brotliLength":0,"metaUid":"04e2242d-22"},"04e2242d-25":{"renderedLength":1905,"gzipLength":0,"brotliLength":0,"metaUid":"04e2242d-24"},"04e2242d-27":{"renderedLength":2037,"gzipLength":0,"brotliLength":0,"metaUid":"04e2242d-26"},"04e2242d-29":{"renderedLength":2174,"gzipLength":0,"brotliLength":0,"metaUid":"04e2242d-28"}},"nodeMetas":{"04e2242d-0":{"id":"/home/whj/codes/cat-kit/packages/agent-context/src/cli.d.ts","moduleParts":{"cli.d.ts":"04e2242d-1"},"imported":[],"importedBy":[],"isEntry":true},"04e2242d-2":{"id":"/home/whj/codes/cat-kit/packages/agent-context/src/cli.ts","moduleParts":{"cli.js":"04e2242d-3"},"imported":[{"uid":"04e2242d-30"},{"uid":"04e2242d-31"},{"uid":"04e2242d-4"},{"uid":"04e2242d-6"},{"uid":"04e2242d-10"},{"uid":"04e2242d-12"},{"uid":"04e2242d-14"}],"importedBy":[],"isEntry":true},"04e2242d-4":{"id":"/home/whj/codes/cat-kit/packages/agent-context/src/commands/done.ts","moduleParts":{"commands/done.js":"04e2242d-5"},"imported":[{"uid":"04e2242d-32"},{"uid":"04e2242d-33"},{"uid":"04e2242d-34"}],"importedBy":[{"uid":"04e2242d-2"}]},"04e2242d-6":{"id":"/home/whj/codes/cat-kit/packages/agent-context/src/commands/install.ts","moduleParts":{"commands/install.js":"04e2242d-7"},"imported":[{"uid":"04e2242d-33"},{"uid":"04e2242d-26"},{"uid":"04e2242d-28"},{"uid":"04e2242d-8"}],"importedBy":[{"uid":"04e2242d-2"}]},"04e2242d-8":{"id":"/home/whj/codes/cat-kit/packages/agent-context/src/commands/printer.ts","moduleParts":{"commands/printer.js":"04e2242d-9"},"imported":[{"uid":"04e2242d-32"}],"importedBy":[{"uid":"04e2242d-6"},{"uid":"04e2242d-12"}]},"04e2242d-10":{"id":"/home/whj/codes/cat-kit/packages/agent-context/src/commands/status.ts","moduleParts":{"commands/status.js":"04e2242d-11"},"imported":[{"uid":"04e2242d-34"}],"importedBy":[{"uid":"04e2242d-2"}]},"04e2242d-12":{"id":"/home/whj/codes/cat-kit/packages/agent-context/src/commands/sync.ts","moduleParts":{"commands/sync.js":"04e2242d-13"},"imported":[{"uid":"04e2242d-28"},{"uid":"04e2242d-26"},{"uid":"04e2242d-8"}],"importedBy":[{"uid":"04e2242d-2"}]},"04e2242d-14":{"id":"/home/whj/codes/cat-kit/packages/agent-context/src/commands/validate.ts","moduleParts":{"commands/validate.js":"04e2242d-15"},"imported":[{"uid":"04e2242d-34"}],"importedBy":[{"uid":"04e2242d-2"}]},"04e2242d-16":{"id":"/home/whj/codes/cat-kit/packages/agent-context/src/content/actions.ts","moduleParts":{"content/actions.js":"04e2242d-17"},"imported":[],"importedBy":[{"uid":"04e2242d-18"}]},"04e2242d-18":{"id":"/home/whj/codes/cat-kit/packages/agent-context/src/content/index.ts","moduleParts":{"content/index.js":"04e2242d-19"},"imported":[{"uid":"04e2242d-16"}],"importedBy":[{"uid":"04e2242d-26"}]},"04e2242d-20":{"id":"/home/whj/codes/cat-kit/packages/agent-context/src/context/archiver.ts","moduleParts":{"context/archiver.js":"04e2242d-21"},"imported":[{"uid":"04e2242d-35"},{"uid":"04e2242d-32"}],"importedBy":[{"uid":"04e2242d-34"}]},"04e2242d-22":{"id":"/home/whj/codes/cat-kit/packages/agent-context/src/context/reader.ts","moduleParts":{"context/reader.js":"04e2242d-23"},"imported":[{"uid":"04e2242d-35"},{"uid":"04e2242d-30"},{"uid":"04e2242d-32"}],"importedBy":[{"uid":"04e2242d-34"}]},"04e2242d-24":{"id":"/home/whj/codes/cat-kit/packages/agent-context/src/context/validator.ts","moduleParts":{"context/validator.js":"04e2242d-25"},"imported":[{"uid":"04e2242d-30"},{"uid":"04e2242d-32"}],"importedBy":[{"uid":"04e2242d-34"}]},"04e2242d-26":{"id":"/home/whj/codes/cat-kit/packages/agent-context/src/runner.ts","moduleParts":{"runner.js":"04e2242d-27"},"imported":[{"uid":"04e2242d-32"},{"uid":"04e2242d-30"},{"uid":"04e2242d-35"},{"uid":"04e2242d-28"},{"uid":"04e2242d-18"}],"importedBy":[{"uid":"04e2242d-6"},{"uid":"04e2242d-12"}]},"04e2242d-28":{"id":"/home/whj/codes/cat-kit/packages/agent-context/src/tools.ts","moduleParts":{"tools.js":"04e2242d-29"},"imported":[{"uid":"04e2242d-30"},{"uid":"04e2242d-32"}],"importedBy":[{"uid":"04e2242d-6"},{"uid":"04e2242d-12"},{"uid":"04e2242d-26"}]},"04e2242d-30":{"id":"node:fs","moduleParts":{},"imported":[],"importedBy":[{"uid":"04e2242d-2"},{"uid":"04e2242d-26"},{"uid":"04e2242d-28"},{"uid":"04e2242d-22"},{"uid":"04e2242d-24"}]},"04e2242d-31":{"id":"commander","moduleParts":{},"imported":[],"importedBy":[{"uid":"04e2242d-2"}]},"04e2242d-32":{"id":"node:path","moduleParts":{},"imported":[],"importedBy":[{"uid":"04e2242d-4"},{"uid":"04e2242d-26"},{"uid":"04e2242d-28"},{"uid":"04e2242d-8"},{"uid":"04e2242d-22"},{"uid":"04e2242d-24"},{"uid":"04e2242d-20"}]},"04e2242d-33":{"id":"@inquirer/prompts","moduleParts":{},"imported":[],"importedBy":[{"uid":"04e2242d-4"},{"uid":"04e2242d-6"}]},"04e2242d-34":{"id":"/home/whj/codes/cat-kit/packages/agent-context/src/context/index.ts","moduleParts":{},"imported":[{"uid":"04e2242d-22"},{"uid":"04e2242d-24"},{"uid":"04e2242d-20"}],"importedBy":[{"uid":"04e2242d-4"},{"uid":"04e2242d-10"},{"uid":"04e2242d-14"}]},"04e2242d-35":{"id":"node:fs/promises","moduleParts":{},"imported":[],"importedBy":[{"uid":"04e2242d-26"},{"uid":"04e2242d-22"},{"uid":"04e2242d-20"}]}},"env":{"rollup":"4.23.0"},"options":{"gzip":false,"brotli":false,"sourcemap":false}};
4933
+ const data = {"version":2,"tree":{"name":"root","children":[{"name":"cli.d.ts","children":[{"name":"home/whj/codes/cat-kit/packages/agent-context/src/cli.d.ts","uid":"993aa054-1"}]},{"name":"cli.js","children":[{"name":"home/whj/codes/cat-kit/packages/agent-context/src/cli.ts","uid":"993aa054-3"}]},{"name":"commands/done.js","children":[{"name":"home/whj/codes/cat-kit/packages/agent-context/src/commands/done.ts","uid":"993aa054-5"}]},{"name":"commands/install.js","children":[{"name":"home/whj/codes/cat-kit/packages/agent-context/src/commands/install.ts","uid":"993aa054-7"}]},{"name":"commands/printer.js","children":[{"name":"home/whj/codes/cat-kit/packages/agent-context/src/commands/printer.ts","uid":"993aa054-9"}]},{"name":"commands/status.js","children":[{"name":"home/whj/codes/cat-kit/packages/agent-context/src/commands/status.ts","uid":"993aa054-11"}]},{"name":"commands/sync.js","children":[{"name":"home/whj/codes/cat-kit/packages/agent-context/src/commands/sync.ts","uid":"993aa054-13"}]},{"name":"commands/validate.js","children":[{"name":"home/whj/codes/cat-kit/packages/agent-context/src/commands/validate.ts","uid":"993aa054-15"}]},{"name":"content/actions.js","children":[{"name":"home/whj/codes/cat-kit/packages/agent-context/src/content/actions.ts","uid":"993aa054-17"}]},{"name":"content/index.js","children":[{"name":"home/whj/codes/cat-kit/packages/agent-context/src/content/index.ts","uid":"993aa054-19"}]},{"name":"context/archiver.js","children":[{"name":"home/whj/codes/cat-kit/packages/agent-context/src/context/archiver.ts","uid":"993aa054-21"}]},{"name":"context/reader.js","children":[{"name":"home/whj/codes/cat-kit/packages/agent-context/src/context/reader.ts","uid":"993aa054-23"}]},{"name":"context/validator.js","children":[{"name":"home/whj/codes/cat-kit/packages/agent-context/src/context/validator.ts","uid":"993aa054-25"}]},{"name":"runner.js","children":[{"name":"home/whj/codes/cat-kit/packages/agent-context/src/runner.ts","uid":"993aa054-27"}]},{"name":"tools.js","children":[{"name":"home/whj/codes/cat-kit/packages/agent-context/src/tools.ts","uid":"993aa054-29"}]}],"isRoot":true},"nodeParts":{"993aa054-1":{"renderedLength":0,"gzipLength":0,"brotliLength":0,"metaUid":"993aa054-0"},"993aa054-3":{"renderedLength":1518,"gzipLength":0,"brotliLength":0,"metaUid":"993aa054-2"},"993aa054-5":{"renderedLength":1349,"gzipLength":0,"brotliLength":0,"metaUid":"993aa054-4"},"993aa054-7":{"renderedLength":985,"gzipLength":0,"brotliLength":0,"metaUid":"993aa054-6"},"993aa054-9":{"renderedLength":909,"gzipLength":0,"brotliLength":0,"metaUid":"993aa054-8"},"993aa054-11":{"renderedLength":946,"gzipLength":0,"brotliLength":0,"metaUid":"993aa054-10"},"993aa054-13":{"renderedLength":745,"gzipLength":0,"brotliLength":0,"metaUid":"993aa054-12"},"993aa054-15":{"renderedLength":763,"gzipLength":0,"brotliLength":0,"metaUid":"993aa054-14"},"993aa054-17":{"renderedLength":9909,"gzipLength":0,"brotliLength":0,"metaUid":"993aa054-16"},"993aa054-19":{"renderedLength":4006,"gzipLength":0,"brotliLength":0,"metaUid":"993aa054-18"},"993aa054-21":{"renderedLength":1012,"gzipLength":0,"brotliLength":0,"metaUid":"993aa054-20"},"993aa054-23":{"renderedLength":2081,"gzipLength":0,"brotliLength":0,"metaUid":"993aa054-22"},"993aa054-25":{"renderedLength":1905,"gzipLength":0,"brotliLength":0,"metaUid":"993aa054-24"},"993aa054-27":{"renderedLength":2037,"gzipLength":0,"brotliLength":0,"metaUid":"993aa054-26"},"993aa054-29":{"renderedLength":2174,"gzipLength":0,"brotliLength":0,"metaUid":"993aa054-28"}},"nodeMetas":{"993aa054-0":{"id":"/home/whj/codes/cat-kit/packages/agent-context/src/cli.d.ts","moduleParts":{"cli.d.ts":"993aa054-1"},"imported":[],"importedBy":[],"isEntry":true},"993aa054-2":{"id":"/home/whj/codes/cat-kit/packages/agent-context/src/cli.ts","moduleParts":{"cli.js":"993aa054-3"},"imported":[{"uid":"993aa054-30"},{"uid":"993aa054-31"},{"uid":"993aa054-4"},{"uid":"993aa054-6"},{"uid":"993aa054-10"},{"uid":"993aa054-12"},{"uid":"993aa054-14"}],"importedBy":[],"isEntry":true},"993aa054-4":{"id":"/home/whj/codes/cat-kit/packages/agent-context/src/commands/done.ts","moduleParts":{"commands/done.js":"993aa054-5"},"imported":[{"uid":"993aa054-32"},{"uid":"993aa054-33"},{"uid":"993aa054-34"}],"importedBy":[{"uid":"993aa054-2"}]},"993aa054-6":{"id":"/home/whj/codes/cat-kit/packages/agent-context/src/commands/install.ts","moduleParts":{"commands/install.js":"993aa054-7"},"imported":[{"uid":"993aa054-33"},{"uid":"993aa054-26"},{"uid":"993aa054-28"},{"uid":"993aa054-8"}],"importedBy":[{"uid":"993aa054-2"}]},"993aa054-8":{"id":"/home/whj/codes/cat-kit/packages/agent-context/src/commands/printer.ts","moduleParts":{"commands/printer.js":"993aa054-9"},"imported":[{"uid":"993aa054-32"}],"importedBy":[{"uid":"993aa054-6"},{"uid":"993aa054-12"}]},"993aa054-10":{"id":"/home/whj/codes/cat-kit/packages/agent-context/src/commands/status.ts","moduleParts":{"commands/status.js":"993aa054-11"},"imported":[{"uid":"993aa054-34"}],"importedBy":[{"uid":"993aa054-2"}]},"993aa054-12":{"id":"/home/whj/codes/cat-kit/packages/agent-context/src/commands/sync.ts","moduleParts":{"commands/sync.js":"993aa054-13"},"imported":[{"uid":"993aa054-26"},{"uid":"993aa054-28"},{"uid":"993aa054-8"}],"importedBy":[{"uid":"993aa054-2"}]},"993aa054-14":{"id":"/home/whj/codes/cat-kit/packages/agent-context/src/commands/validate.ts","moduleParts":{"commands/validate.js":"993aa054-15"},"imported":[{"uid":"993aa054-34"}],"importedBy":[{"uid":"993aa054-2"}]},"993aa054-16":{"id":"/home/whj/codes/cat-kit/packages/agent-context/src/content/actions.ts","moduleParts":{"content/actions.js":"993aa054-17"},"imported":[],"importedBy":[{"uid":"993aa054-18"}]},"993aa054-18":{"id":"/home/whj/codes/cat-kit/packages/agent-context/src/content/index.ts","moduleParts":{"content/index.js":"993aa054-19"},"imported":[{"uid":"993aa054-16"}],"importedBy":[{"uid":"993aa054-26"}]},"993aa054-20":{"id":"/home/whj/codes/cat-kit/packages/agent-context/src/context/archiver.ts","moduleParts":{"context/archiver.js":"993aa054-21"},"imported":[{"uid":"993aa054-35"},{"uid":"993aa054-32"}],"importedBy":[{"uid":"993aa054-34"}]},"993aa054-22":{"id":"/home/whj/codes/cat-kit/packages/agent-context/src/context/reader.ts","moduleParts":{"context/reader.js":"993aa054-23"},"imported":[{"uid":"993aa054-30"},{"uid":"993aa054-35"},{"uid":"993aa054-32"}],"importedBy":[{"uid":"993aa054-34"}]},"993aa054-24":{"id":"/home/whj/codes/cat-kit/packages/agent-context/src/context/validator.ts","moduleParts":{"context/validator.js":"993aa054-25"},"imported":[{"uid":"993aa054-30"},{"uid":"993aa054-32"}],"importedBy":[{"uid":"993aa054-34"}]},"993aa054-26":{"id":"/home/whj/codes/cat-kit/packages/agent-context/src/runner.ts","moduleParts":{"runner.js":"993aa054-27"},"imported":[{"uid":"993aa054-30"},{"uid":"993aa054-35"},{"uid":"993aa054-32"},{"uid":"993aa054-18"},{"uid":"993aa054-28"}],"importedBy":[{"uid":"993aa054-6"},{"uid":"993aa054-12"}]},"993aa054-28":{"id":"/home/whj/codes/cat-kit/packages/agent-context/src/tools.ts","moduleParts":{"tools.js":"993aa054-29"},"imported":[{"uid":"993aa054-30"},{"uid":"993aa054-32"}],"importedBy":[{"uid":"993aa054-6"},{"uid":"993aa054-12"},{"uid":"993aa054-26"}]},"993aa054-30":{"id":"node:fs","moduleParts":{},"imported":[],"importedBy":[{"uid":"993aa054-2"},{"uid":"993aa054-26"},{"uid":"993aa054-28"},{"uid":"993aa054-22"},{"uid":"993aa054-24"}]},"993aa054-31":{"id":"commander","moduleParts":{},"imported":[],"importedBy":[{"uid":"993aa054-2"}]},"993aa054-32":{"id":"node:path","moduleParts":{},"imported":[],"importedBy":[{"uid":"993aa054-4"},{"uid":"993aa054-26"},{"uid":"993aa054-28"},{"uid":"993aa054-8"},{"uid":"993aa054-22"},{"uid":"993aa054-24"},{"uid":"993aa054-20"}]},"993aa054-33":{"id":"@inquirer/prompts","moduleParts":{},"imported":[],"importedBy":[{"uid":"993aa054-4"},{"uid":"993aa054-6"}]},"993aa054-34":{"id":"/home/whj/codes/cat-kit/packages/agent-context/src/context/index.ts","moduleParts":{},"imported":[{"uid":"993aa054-22"},{"uid":"993aa054-24"},{"uid":"993aa054-20"}],"importedBy":[{"uid":"993aa054-4"},{"uid":"993aa054-10"},{"uid":"993aa054-14"}]},"993aa054-35":{"id":"node:fs/promises","moduleParts":{},"imported":[],"importedBy":[{"uid":"993aa054-26"},{"uid":"993aa054-22"},{"uid":"993aa054-20"}]}},"env":{"rollup":"4.23.0"},"options":{"gzip":false,"brotli":false,"sourcemap":false}};
4934
4934
 
4935
4935
  const run = () => {
4936
4936
  const width = window.innerWidth;
package/dist/tools.js CHANGED
@@ -1,2 +1 @@
1
- import{existsSync as e}from"node:fs";import{resolve as t}from"node:path";const n={claude:{id:`claude`,name:`Claude Code`,skillRootDir:`.claude/skills`,frontmatterProfile:`claude`,metadataFiles:[]},codex:{id:`codex`,name:`Codex`,skillRootDir:`.codex/skills`,frontmatterProfile:`standard`,metadataFiles:[`openai`]},cursor:{id:`cursor`,name:`Cursor`,skillRootDir:`.cursor/skills`,frontmatterProfile:`standard`,metadataFiles:[]},antigravity:{id:`antigravity`,name:`Antigravity`,skillRootDir:`.agent/skills`,frontmatterProfile:`standard`,metadataFiles:[]},copilot:{id:`copilot`,name:`GitHub Copilot`,skillRootDir:`.github/skills`,frontmatterProfile:`copilot`,metadataFiles:[]}},r=[`claude`,`codex`,`cursor`,`antigravity`,`copilot`];function i(){return r.map(e=>({id:e,name:n[e].name}))}function a(e){let t=e.split(`,`).map(e=>e.trim().toLowerCase()).filter(Boolean);if(t.length===0)return[...r];let n=[];for(let e of t){if(!l(e))throw Error(`不支持的工具标识: ${e}。可选值: ${r.join(`, `)}`);n.includes(e)||n.push(e)}return n}function o(e){return(e&&e.length>0?e:r).map(e=>({...n[e]}))}function s(t){return r.filter(r=>{let i=n[r];return e(c(i,t).skillFile)})}function c(e,n){let r=t(n,e.skillRootDir,`ac-workflow`);return{skillDir:r,skillFile:t(r,`SKILL.md`),openaiMetadataFile:t(r,`agents/openai.yaml`)}}function l(e){return Object.hasOwn(n,e)}export{r as DEFAULT_TOOL_ORDER,s as detectConfiguredToolIds,i as getToolChoices,a as parseToolIds,c as resolveSkillPaths,o as resolveToolTargets};
2
- //# sourceMappingURL=tools.js.map
1
+ import{existsSync as e}from"node:fs";import{resolve as t}from"node:path";const n={claude:{id:`claude`,name:`Claude Code`,skillRootDir:`.claude/skills`,frontmatterProfile:`claude`,metadataFiles:[]},codex:{id:`codex`,name:`Codex`,skillRootDir:`.codex/skills`,frontmatterProfile:`standard`,metadataFiles:[`openai`]},cursor:{id:`cursor`,name:`Cursor`,skillRootDir:`.cursor/skills`,frontmatterProfile:`standard`,metadataFiles:[]},antigravity:{id:`antigravity`,name:`Antigravity`,skillRootDir:`.agent/skills`,frontmatterProfile:`standard`,metadataFiles:[]},copilot:{id:`copilot`,name:`GitHub Copilot`,skillRootDir:`.github/skills`,frontmatterProfile:`copilot`,metadataFiles:[]}},r=[`claude`,`codex`,`cursor`,`antigravity`,`copilot`];function i(){return r.map(e=>({id:e,name:n[e].name}))}function a(e){let t=e.split(`,`).map(e=>e.trim().toLowerCase()).filter(Boolean);if(t.length===0)return[...r];let n=[];for(let e of t){if(!l(e))throw Error(`不支持的工具标识: ${e}。可选值: ${r.join(`, `)}`);n.includes(e)||n.push(e)}return n}function o(e){return(e&&e.length>0?e:r).map(e=>({...n[e]}))}function s(t){return r.filter(r=>{let i=n[r];return e(c(i,t).skillFile)})}function c(e,n){let r=t(n,e.skillRootDir,`ac-workflow`);return{skillDir:r,skillFile:t(r,`SKILL.md`),openaiMetadataFile:t(r,`agents/openai.yaml`)}}function l(e){return Object.hasOwn(n,e)}export{r as DEFAULT_TOOL_ORDER,s as detectConfiguredToolIds,i as getToolChoices,a as parseToolIds,c as resolveSkillPaths,o as resolveToolTargets};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cat-kit/agent-context",
3
- "version": "1.1.4",
3
+ "version": "1.1.6",
4
4
  "description": "代理上下文管理工具",
5
5
  "bin": {
6
6
  "agent-context": "./dist/cli.js"
@@ -11,10 +11,6 @@
11
11
  "README.md"
12
12
  ],
13
13
  "type": "module",
14
- "scripts": {
15
- "build": "tsc -p tsconfig.json",
16
- "clean": "rm -rf dist node_modules/.cache/.tsbuildinfo"
17
- },
18
14
  "dependencies": {
19
15
  "@inquirer/prompts": "^8.3.0",
20
16
  "commander": "^14.0.3"
package/src/cli.ts CHANGED
@@ -34,15 +34,9 @@ program
34
34
  .option('--check', '仅检查是否存在待更新内容,不写入文件')
35
35
  .action(syncCommand)
36
36
 
37
- program
38
- .command('validate')
39
- .description('校验 .agent-context 目录结构')
40
- .action(validateCommand)
37
+ program.command('validate').description('校验 .agent-context 目录结构').action(validateCommand)
41
38
 
42
- program
43
- .command('status')
44
- .description('查看当前 agent-context 状态')
45
- .action(statusCommand)
39
+ program.command('status').description('查看当前 agent-context 状态').action(statusCommand)
46
40
 
47
41
  program
48
42
  .command('done')
@@ -29,9 +29,7 @@ export async function doneCommand(options: { yes?: boolean }): Promise<void> {
29
29
  }
30
30
 
31
31
  if (!options.yes) {
32
- const confirmed = await confirm({
33
- message: `确认归档 plan-${snapshot.currentPlan.number}?`
34
- })
32
+ const confirmed = await confirm({ message: `确认归档 plan-${snapshot.currentPlan.number}?` })
35
33
  if (!confirmed) {
36
34
  console.log('已取消') // eslint-disable-line no-console
37
35
  return
@@ -1,7 +1,12 @@
1
1
  import { checkbox } from '@inquirer/prompts'
2
2
 
3
3
  import { runInstall } from '../runner.js'
4
- import { DEFAULT_TOOL_ORDER, detectConfiguredToolIds, getToolChoices, parseToolIds } from '../tools.js'
4
+ import {
5
+ DEFAULT_TOOL_ORDER,
6
+ detectConfiguredToolIds,
7
+ getToolChoices,
8
+ parseToolIds
9
+ } from '../tools.js'
5
10
  import type { ToolId } from '../types.js'
6
11
  import { printCheckResult, printRunSummary } from './printer.js'
7
12
 
@@ -1,6 +1,6 @@
1
+ import { runSync } from '../runner.js'
1
2
  import { detectConfiguredToolIds, parseToolIds } from '../tools.js'
2
3
  import type { ToolId } from '../types.js'
3
- import { runSync } from '../runner.js'
4
4
  import { printCheckResult, printRunSummary } from './printer.js'
5
5
 
6
6
  export interface SyncCommandOptions {
@@ -58,7 +58,9 @@ function renderPlan(): string {
58
58
 
59
59
  - 运行 \`agent-context validate\`,不通过则中止并报告错误。
60
60
  - 描述为空 → 拒绝执行。
61
- - 存在未归档的已执行当前计划 → 拒绝执行,提示先运行 \`agent-context done\` 归档。
61
+ - 存在未归档的已执行当前计划 → 判断新需求与当前计划的关联性:
62
+ - 相关联或用户本意是修补 → 拒绝执行,提示改用 patch。
63
+ - 完全无关 → 拒绝执行,提示先运行 \`agent-context done\` 归档后再创建新计划。
62
64
  - 存在多个当前计划 → 拒绝执行,提示恢复单活跃状态。
63
65
 
64
66
  ## 执行步骤
@@ -154,15 +156,18 @@ function renderImplement(): string {
154
156
 
155
157
  ## 执行步骤
156
158
 
157
- 1. 读取当前计划 \`plan.md\`,理解 \`## 目标\` 与 \`## 内容\`。
158
- 2. 依据 \`## 内容\` 中的步骤逐项实施。
159
- 3. **验证循环**(全部通过前不可进入步骤 4):
160
- a. 逐项对照 \`## 内容\` 确认每个步骤已实施。
161
- b. 运行项目验证:类型检查 → 测试。
162
- c. 若存在失败项 修复后回到 a 重新验证。
163
- d. 全部通过 进入步骤 4。
164
- 4. 更新 \`plan.md\` 状态行:\`> 状态: 未执行\` → \`> 状态: 已执行\`。
165
- 5. 更新 \`## 影响范围\`,记录所有变更文件。
159
+ 1. **读取计划**:读取当前 \`plan.md\`,理解 \`## 目标\` 与 \`## 内容\`。
160
+ 2. **实施变更**:依据 \`## 内容\` 的步骤逐项实施。
161
+ 3. **验证循环(WHILE 循环检查)**:
162
+ - **3.1 检查对照**:对照 \`## 内容\`,确保每个步骤均已实施完毕,无遗漏。
163
+ - **3.2 运行验证**:
164
+ - **IF** (编码任务) **THEN**:必须运行代码检查(Lint/Typecheck)与相关测试命令。
165
+ - **ELSE IF** (非编码任务,如纯文档修改或项目规划) **THEN**:无需运行外部命令,仅凭逻辑和视觉排版审阅是否符合验收标准。
166
+ - **3.3 结果判断**:
167
+ - **IF** (存在未通过的验证报错、未完成项或遗漏项) **THEN**:修复发现的问题,然后 **GOTO 3.1**(重新检查)。
168
+ - **ELSE IF** (验证全部通过 或 非编码任务验收合格) **THEN**:退出验证循环,即 **GOTO 4** 继续执行。
169
+ 4. **更新状态**:将 \`plan.md\` 的状态行修改为 \`> 状态: 已执行\`。
170
+ 5. **记录范围**:更新 \`## 影响范围\`,详细记录本次变动的具体文件路径。\`.agent-context/\` 目录下的文件不计入影响范围。
166
171
  `
167
172
  }
168
173
 
@@ -190,7 +195,7 @@ function renderPatch(): string {
190
195
  4. 创建 \`patch-{number}.md\`(编号:扫描当前计划目录已有补丁取 max+1),遵循下方模板。
191
196
  5. 回写 \`plan.md\`:
192
197
  - \`## 历史补丁\`:追加 \`- patch-{number}: {补丁名称}\`,按编号去重。
193
- - \`## 影响范围\`:合并本次变更路径,按路径去重。
198
+ - \`## 影响范围\`:合并本次变更路径,按路径去重。\`.agent-context/\` 目录下的文件不计入影响范围。
194
199
 
195
200
  ## patch.md 模板
196
201
 
@@ -221,18 +226,23 @@ function renderRush(): string {
221
226
 
222
227
  - 运行 \`agent-context validate\`,不通过则中止并报告错误。
223
228
  - 描述为空 → 拒绝执行。
224
- - 存在未归档的已执行当前计划 → 拒绝执行,提示先运行 \`agent-context done\` 归档。
229
+ - 存在未归档的已执行当前计划 → 判断新需求与当前计划的关联性:
230
+ - 相关联或用户本意是修补 → 拒绝执行,提示改用 patch。
231
+ - 完全无关 → 拒绝执行,提示先运行 \`agent-context done\` 归档后再创建新计划。
225
232
  - 存在未实施的当前计划 → 拒绝执行,提示先 implement 或 replan。
226
233
 
227
234
  ## 执行步骤
228
235
 
229
- 1. plan 协议创建单计划(不拆分,不进入 preparing 队列)。
230
- 2. 无需用户确认计划内容,直接进入 implement 流程。
231
- 3. 按 implement 协议执行全部步骤,包括验证循环:
232
- a. 逐项对照 \`## 内容\` 确认每个步骤已实施。
233
- b. 运行项目验证:类型检查 → 测试。
234
- c. 若存在失败项 修复后重新验证。
235
- d. 全部通过 进入步骤 4。
236
- 4. 更新 \`plan.md\` 状态行为 \`已执行\`,更新 \`## 影响范围\`。
236
+ > rush = plan + implement 的连续执行,下方仅列出差异点,未提及的步骤按原协议执行。
237
+
238
+ ### 阶段一:plan(差异)
239
+
240
+ - 跳过「需求澄清」步骤——rush 要求描述本身已足够明确。
241
+ - 强制单计划,不拆分,不进入 preparing 队列。
242
+ - 完成 plan 后**不等待用户确认**,直接进入阶段二。
243
+
244
+ ### 阶段二:implement
245
+
246
+ - 按 \`implement\` 协议**完整执行**(读取计划 → 实施变更 → 验证循环 → 更新状态与影响范围),无任何裁剪。
237
247
  `
238
248
  }
@@ -27,7 +27,14 @@ function renderNavigator(target: ToolTarget): string {
27
27
  return `${renderFrontmatter(target)}
28
28
  # Agent Context
29
29
 
30
- 管理项目中的 \`.agent-context/\` 计划生命周期。匹配用户意图后,读取对应协议文件(相对于本文件所在目录)严格执行。
30
+ 管理项目中的 \`.agent-context/\` 计划生命周期。匹配用户意图后,**必须先读取对应协议文件的完整内容**,再严格按协议步骤逐项执行。
31
+
32
+ ## 执行纪律
33
+
34
+ - **协议先行**:匹配到动作后,必须先读取对应 \`actions/*.md\` 协议文件的完整内容,再逐步执行。禁止凭记忆、摘要或猜测跳过协议步骤。
35
+ - **前置检查必做**:所有动作(done 除外)均包含「前置检查」,必须逐条执行,不可跳过。包括运行 \`agent-context validate\`。
36
+ - **禁止直接改动**:在 plan / rush 创建计划之前,不得直接修改项目代码文件。任何代码变更必须在已创建计划(implement)或已创建补丁(patch)的上下文中进行。
37
+ - **顺序执行**:协议步骤必须按编号顺序逐项执行,不可跳步、合并或并行。
31
38
 
32
39
  ## 意图匹配
33
40
 
@@ -41,7 +48,9 @@ function renderNavigator(target: ToolTarget): string {
41
48
  | 无活跃计划时快速出计划并实施 | rush | \`actions/rush.md\` |
42
49
  | 任务彻底完成、归档当前计划 | done | 运行 \`agent-context done\` |
43
50
 
44
- > **消歧**:存在已执行的当前计划时,用户提出任何变更需求 → 一律走 **patch**,禁止走 plan / rush。
51
+ > **消歧**:存在已执行的当前计划时,用户提出变更需求:
52
+ > - 需求与当前计划**相关联**或用户本意是修补当前计划 → 走 **patch**。
53
+ > - 需求与当前计划**完全无关** → 拒绝执行,提示先运行 \`agent-context done\` 归档当前计划后再创建新计划。
45
54
 
46
55
  ## 全局约束
47
56
 
@@ -49,6 +58,7 @@ function renderNavigator(target: ToolTarget): string {
49
58
  - 任意时刻最多一个当前计划:\`.agent-context/plan-{number}\`。
50
59
  - 多个当前计划 → 拒绝执行,提示恢复单活跃状态。
51
60
  - 计划编号全局递增,不复用。补丁编号在单计划目录内递增,不复用。
61
+ - 影响范围(\`## 影响范围\`)不得包含 \`.agent-context/\` 目录下的文件。
52
62
 
53
63
  ## 目录结构
54
64
 
@@ -1,5 +1,5 @@
1
- import { readdir, readFile } from 'node:fs/promises'
2
1
  import { existsSync } from 'node:fs'
2
+ import { readdir, readFile } from 'node:fs/promises'
3
3
  import { join } from 'node:path'
4
4
 
5
5
  import type { ContextSnapshot, PlanInfo, PlanStatus } from '../types.js'
@@ -29,12 +29,7 @@ export async function readRawContext(
29
29
  const preparing = await readPlanDirs(join(root, 'preparing'))
30
30
  const done = await readDonePlans(join(root, 'done'))
31
31
 
32
- const snapshot: ContextSnapshot = {
33
- root,
34
- currentPlan: currentPlans[0] ?? null,
35
- preparing,
36
- done
37
- }
32
+ const snapshot: ContextSnapshot = { root, currentPlan: currentPlans[0] ?? null, preparing, done }
38
33
 
39
34
  return { snapshot, currentPlanCount: currentPlans.length }
40
35
  }
@@ -47,7 +42,7 @@ export async function readPlanStatus(planDir: string): Promise<PlanStatus> {
47
42
  }
48
43
 
49
44
  const content = await readFile(planFile, 'utf-8')
50
-
45
+
51
46
  const exactMatch = content.match(EXACT_STATUS_RE)
52
47
  if (exactMatch) {
53
48
  return exactMatch[1] as PlanStatus
@@ -85,15 +80,12 @@ async function readDonePlans(parentDir: string): Promise<Pick<PlanInfo, 'number'
85
80
  if (!existsSync(parentDir)) return []
86
81
  const entries = await readdir(parentDir, { withFileTypes: true })
87
82
  const plans: Pick<PlanInfo, 'number' | 'dir'>[] = []
88
-
83
+
89
84
  for (const entry of entries) {
90
85
  if (!entry.isDirectory()) continue
91
86
  const match = entry.name.match(DONE_DIR_RE)
92
87
  if (!match?.[1]) continue
93
- plans.push({
94
- number: parseInt(match[1], 10),
95
- dir: join(parentDir, entry.name)
96
- })
88
+ plans.push({ number: parseInt(match[1], 10), dir: join(parentDir, entry.name) })
97
89
  }
98
90
 
99
91
  return plans.sort((a, b) => a.number - b.number)
@@ -24,13 +24,17 @@ export function validate(
24
24
  }
25
25
 
26
26
  if (snapshot.currentPlan.status === '未知') {
27
- errors.push(`当前计划 plan-${snapshot.currentPlan.number} 的状态格式严重不符合要求,请严格按照 "> 状态: 已执行" 或 "> 状态: 未执行" 的格式书写,禁止添加 emoji 或其他额外字符。`)
27
+ errors.push(
28
+ `当前计划 plan-${snapshot.currentPlan.number} 的状态格式严重不符合要求,请严格按照 "> 状态: 已执行" 或 "> 状态: 未执行" 的格式书写,禁止添加 emoji 或其他额外字符。`
29
+ )
28
30
  }
29
31
  }
30
32
 
31
33
  for (const p of snapshot.preparing) {
32
34
  if (p.status === '未知') {
33
- errors.push(`待执行计划 plan-${p.number} 的状态格式严重不符合要求,请严格按照 "> 状态: 已执行" 或 "> 状态: 未执行" 的格式书写。`)
35
+ errors.push(
36
+ `待执行计划 plan-${p.number} 的状态格式严重不符合要求,请严格按照 "> 状态: 已执行" 或 "> 状态: 未执行" 的格式书写。`
37
+ )
34
38
  }
35
39
  }
36
40
 
@@ -54,7 +58,9 @@ export function validate(
54
58
  allNumbers.sort((a, b) => a - b)
55
59
  for (let i = 0; i < allNumbers.length; i++) {
56
60
  if (allNumbers[i] !== i + 1) {
57
- errors.push(`计划序列不连续或未从 1 开始。预期出现编号 ${i + 1},实际遇到编号 ${allNumbers[i]} (要求必须是从 1 开始顺序查询)。`)
61
+ errors.push(
62
+ `计划序列不连续或未从 1 开始。预期出现编号 ${i + 1},实际遇到编号 ${allNumbers[i]} (要求必须是从 1 开始顺序查询)。`
63
+ )
58
64
  break
59
65
  }
60
66
  }
package/src/runner.ts CHANGED
@@ -1,11 +1,18 @@
1
- import { resolve, dirname } from 'node:path'
2
1
  import { existsSync } from 'node:fs'
3
2
  import { mkdir, readFile, writeFile } from 'node:fs/promises'
3
+ import { resolve, dirname } from 'node:path'
4
4
 
5
+ import { renderSkillArtifacts } from './content/index.js'
5
6
  import type { SkillPaths } from './tools.js'
6
7
  import { resolveToolTargets, resolveSkillPaths } from './tools.js'
7
- import { renderSkillArtifacts } from './content/index.js'
8
- import type { ApplyMutationResult, FileMutation, RunOptions, RunResult, ToolId, ToolTarget } from './types.js'
8
+ import type {
9
+ ApplyMutationResult,
10
+ FileMutation,
11
+ RunOptions,
12
+ RunResult,
13
+ ToolId,
14
+ ToolTarget
15
+ } from './types.js'
9
16
 
10
17
  export async function runInstall(options: RunOptions = {}): Promise<RunResult> {
11
18
  return run('install', options)
@@ -22,7 +29,7 @@ async function run(mode: 'install' | 'sync', options: RunOptions): Promise<RunRe
22
29
  const tools = dedup(options.tools)
23
30
  const targets = resolveToolTargets(tools)
24
31
 
25
- const mutations: FileMutation[] = targets.flatMap(target => buildMutations(target, cwd))
32
+ const mutations: FileMutation[] = targets.flatMap((target) => buildMutations(target, cwd))
26
33
 
27
34
  const check = options.check ?? false
28
35
  const result = await applyMutations(mutations, check)
@@ -36,7 +43,7 @@ function buildMutations(target: ToolTarget, cwd: string): FileMutation[] {
36
43
  const artifacts = renderSkillArtifacts(target)
37
44
  const paths = resolveSkillPaths(target, cwd)
38
45
 
39
- return artifacts.files.map(file => ({
46
+ return artifacts.files.map((file) => ({
40
47
  path: resolveArtifactPath(paths, file.relativePath),
41
48
  body: file.body
42
49
  }))
@@ -56,12 +63,7 @@ async function applyMutations(
56
63
  mutations: FileMutation[],
57
64
  check: boolean
58
65
  ): Promise<ApplyMutationResult> {
59
- const result: ApplyMutationResult = {
60
- created: [],
61
- updated: [],
62
- unchanged: [],
63
- changed: []
64
- }
66
+ const result: ApplyMutationResult = { created: [], updated: [], unchanged: [], changed: [] }
65
67
 
66
68
  for (const mutation of mutations) {
67
69
  const fileExists = existsSync(mutation.path)
package/src/types.ts CHANGED
@@ -12,10 +12,7 @@ export interface ToolTarget {
12
12
  }
13
13
 
14
14
  export interface SkillArtifacts {
15
- files: Array<{
16
- relativePath: string
17
- body: string
18
- }>
15
+ files: Array<{ relativePath: string; body: string }>
19
16
  }
20
17
 
21
18
  export interface FileMutation {
package/dist/cli.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"cli.js","names":[],"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { readFileSync } from 'node:fs'\n\nimport { Command } from 'commander'\n\nimport { doneCommand } from './commands/done.js'\nimport { installCommand } from './commands/install.js'\nimport { statusCommand } from './commands/status.js'\nimport { syncCommand } from './commands/sync.js'\nimport { validateCommand } from './commands/validate.js'\n\nconst packageJson = JSON.parse(\n readFileSync(new URL('../package.json', import.meta.url), 'utf8')\n) as { version?: string }\nconst packageVersion = typeof packageJson.version === 'string' ? packageJson.version : '0.0.0'\n\nconst program = new Command()\n\nprogram.name('agent-context').description('Agent Context Skills 安装工具').version(packageVersion)\n\nprogram\n .command('install')\n .description('安装 ac-workflow Skill')\n .option('--tools <tools>', '指定目标工具,逗号分隔:claude,codex,cursor,antigravity,copilot')\n .option('--yes', '非交互模式:优先复用已安装工具,否则安装全部工具')\n .option('--check', '仅检查是否存在待更新内容,不写入文件')\n .action(installCommand)\n\nprogram\n .command('sync')\n .description('同步已安装的 ac-workflow Skill')\n .option('--tools <tools>', '指定目标工具,逗号分隔:claude,codex,cursor,antigravity,copilot')\n .option('--check', '仅检查是否存在待更新内容,不写入文件')\n .action(syncCommand)\n\nprogram\n .command('validate')\n .description('校验 .agent-context 目录结构')\n .action(validateCommand)\n\nprogram\n .command('status')\n .description('查看当前 agent-context 状态')\n .action(statusCommand)\n\nprogram\n .command('done')\n .description('归档当前已执行计划')\n .option('--yes', '跳过确认,直接归档')\n .action(doneCommand)\n\nprogram.parseAsync().catch((error: unknown) => {\n const message = error instanceof Error ? error.message : String(error)\n console.error(`\\n❌ ${message}`) // eslint-disable-line no-console\n process.exitCode = 1\n})\n"],"mappings":";kVAYA,MAAM,EAAc,KAAK,MACvB,EAAa,IAAI,IAAI,kBAAmB,OAAO,KAAK,IAAI,CAAE,OAAO,CAClE,CACK,EAAiB,OAAO,EAAY,SAAY,SAAW,EAAY,QAAU,QAEjF,EAAU,IAAI,EAEpB,EAAQ,KAAK,gBAAgB,CAAC,YAAY,4BAA4B,CAAC,QAAQ,EAAe,CAE9F,EACG,QAAQ,UAAU,CAClB,YAAY,uBAAuB,CACnC,OAAO,kBAAmB,sDAAsD,CAChF,OAAO,QAAS,2BAA2B,CAC3C,OAAO,UAAW,qBAAqB,CACvC,OAAO,EAAe,CAEzB,EACG,QAAQ,OAAO,CACf,YAAY,2BAA2B,CACvC,OAAO,kBAAmB,sDAAsD,CAChF,OAAO,UAAW,qBAAqB,CACvC,OAAO,EAAY,CAEtB,EACG,QAAQ,WAAW,CACnB,YAAY,yBAAyB,CACrC,OAAO,EAAgB,CAE1B,EACG,QAAQ,SAAS,CACjB,YAAY,wBAAwB,CACpC,OAAO,EAAc,CAExB,EACG,QAAQ,OAAO,CACf,YAAY,YAAY,CACxB,OAAO,QAAS,YAAY,CAC5B,OAAO,EAAY,CAEtB,EAAQ,YAAY,CAAC,MAAO,GAAmB,CAC7C,IAAM,EAAU,aAAiB,MAAQ,EAAM,QAAU,OAAO,EAAM,CACtE,QAAQ,MAAM,OAAO,IAAU,CAC/B,QAAQ,SAAW,GACnB"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"done.js","names":[],"sources":["../../src/commands/done.ts"],"sourcesContent":["import { basename } from 'node:path'\n\nimport { confirm } from '@inquirer/prompts'\n\nimport { archive, readRawContext, validate } from '../context/index.js'\n\nexport async function doneCommand(options: { yes?: boolean }): Promise<void> {\n const { snapshot, currentPlanCount } = await readRawContext(process.cwd())\n const result = validate(snapshot, currentPlanCount)\n\n if (!result.valid) {\n for (const error of result.errors) {\n console.log(`❌ ${error}`) // eslint-disable-line no-console\n }\n process.exitCode = 1\n return\n }\n\n if (!snapshot || !snapshot.currentPlan) {\n console.log('❌ 无当前计划') // eslint-disable-line no-console\n process.exitCode = 1\n return\n }\n\n if (snapshot.currentPlan.status !== '已执行') {\n console.log(`❌ 当前计划 plan-${snapshot.currentPlan.number} 尚未执行,无法归档。`) // eslint-disable-line no-console\n process.exitCode = 1\n return\n }\n\n if (!options.yes) {\n const confirmed = await confirm({\n message: `确认归档 plan-${snapshot.currentPlan.number}?`\n })\n if (!confirmed) {\n console.log('已取消') // eslint-disable-line no-console\n return\n }\n }\n\n const archiveResult = await archive(snapshot)\n const archiveName = basename(archiveResult.archivedTo)\n\n console.log(`✅ 已归档: plan-${snapshot.currentPlan.number} → done/${archiveName}`) // eslint-disable-line no-console\n\n if (archiveResult.promoted !== null) {\n console.log(`📋 已晋升: plan-${archiveResult.promoted} 为新的当前计划`) // eslint-disable-line no-console\n }\n\n if (archiveResult.remainingPreparing > 0) {\n console.log(`📋 待执行队列剩余 ${archiveResult.remainingPreparing} 个计划`) // eslint-disable-line no-console\n } else if (archiveResult.promoted === null) {\n console.log('ℹ 无更多待执行计划') // eslint-disable-line no-console\n }\n}\n"],"mappings":"2OAMA,eAAsB,EAAY,EAA2C,CAC3E,GAAM,CAAE,WAAU,oBAAqB,MAAM,EAAe,QAAQ,KAAK,CAAC,CACpE,EAAS,EAAS,EAAU,EAAiB,CAEnD,GAAI,CAAC,EAAO,MAAO,CACjB,IAAK,IAAM,KAAS,EAAO,OACzB,QAAQ,IAAI,KAAK,IAAQ,CAE3B,QAAQ,SAAW,EACnB,OAGF,GAAI,CAAC,GAAY,CAAC,EAAS,YAAa,CACtC,QAAQ,IAAI,UAAU,CACtB,QAAQ,SAAW,EACnB,OAGF,GAAI,EAAS,YAAY,SAAW,MAAO,CACzC,QAAQ,IAAI,eAAe,EAAS,YAAY,OAAO,aAAa,CACpE,QAAQ,SAAW,EACnB,OAGF,GAAI,CAAC,EAAQ,KAIP,CAHc,MAAM,EAAQ,CAC9B,QAAS,aAAa,EAAS,YAAY,OAAO,GACnD,CAAC,CACc,CACd,QAAQ,IAAI,MAAM,CAClB,OAIJ,IAAM,EAAgB,MAAM,EAAQ,EAAS,CACvC,EAAc,EAAS,EAAc,WAAW,CAEtD,QAAQ,IAAI,eAAe,EAAS,YAAY,OAAO,UAAU,IAAc,CAE3E,EAAc,WAAa,MAC7B,QAAQ,IAAI,gBAAgB,EAAc,SAAS,UAAU,CAG3D,EAAc,mBAAqB,EACrC,QAAQ,IAAI,cAAc,EAAc,mBAAmB,MAAM,CACxD,EAAc,WAAa,MACpC,QAAQ,IAAI,aAAa"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"install.js","names":[],"sources":["../../src/commands/install.ts"],"sourcesContent":["import { checkbox } from '@inquirer/prompts'\n\nimport { runInstall } from '../runner.js'\nimport { DEFAULT_TOOL_ORDER, detectConfiguredToolIds, getToolChoices, parseToolIds } from '../tools.js'\nimport type { ToolId } from '../types.js'\nimport { printCheckResult, printRunSummary } from './printer.js'\n\nexport interface InstallCommandOptions {\n tools?: string\n check?: boolean\n yes?: boolean\n}\n\nexport async function installCommand(options: InstallCommandOptions = {}): Promise<void> {\n const cwd = process.cwd()\n const tools = await resolveTools(cwd, options)\n const check = options.check ?? false\n const result = await runInstall({ cwd, tools, check })\n\n if (check) {\n printCheckResult(result, cwd)\n if (result.changed.length > 0) {\n process.exitCode = 1\n }\n return\n }\n\n printRunSummary(result, cwd)\n}\n\nasync function resolveTools(\n cwd: string,\n options: InstallCommandOptions\n): Promise<ToolId[] | undefined> {\n const raw = options.tools\n\n if (!raw || raw.trim().length === 0) {\n const configuredTools = detectConfiguredToolIds(cwd)\n\n if (options.yes) {\n return configuredTools.length > 0 ? configuredTools : [...DEFAULT_TOOL_ORDER]\n }\n\n return checkbox<ToolId>({\n message: '请选择要安装 ac-workflow Skill 的工具(可多选):',\n choices: getToolChoices().map((tool) => ({\n name: tool.name,\n value: tool.id,\n checked: configuredTools.includes(tool.id)\n })),\n required: true\n })\n }\n\n return parseToolIds(raw)\n}\n"],"mappings":"gRAaA,eAAsB,EAAe,EAAiC,EAAE,CAAiB,CACvF,IAAM,EAAM,QAAQ,KAAK,CACnB,EAAQ,MAAM,EAAa,EAAK,EAAQ,CACxC,EAAQ,EAAQ,OAAS,GACzB,EAAS,MAAM,EAAW,CAAE,MAAK,QAAO,QAAO,CAAC,CAEtD,GAAI,EAAO,CACT,EAAiB,EAAQ,EAAI,CACzB,EAAO,QAAQ,OAAS,IAC1B,QAAQ,SAAW,GAErB,OAGF,EAAgB,EAAQ,EAAI,CAG9B,eAAe,EACb,EACA,EAC+B,CAC/B,IAAM,EAAM,EAAQ,MAEpB,GAAI,CAAC,GAAO,EAAI,MAAM,CAAC,SAAW,EAAG,CACnC,IAAM,EAAkB,EAAwB,EAAI,CAMpD,OAJI,EAAQ,IACH,EAAgB,OAAS,EAAI,EAAkB,CAAC,GAAG,EAAmB,CAGxE,EAAiB,CACtB,QAAS,qCACT,QAAS,GAAgB,CAAC,IAAK,IAAU,CACvC,KAAM,EAAK,KACX,MAAO,EAAK,GACZ,QAAS,EAAgB,SAAS,EAAK,GAAG,CAC3C,EAAE,CACH,SAAU,GACX,CAAC,CAGJ,OAAO,EAAa,EAAI"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"printer.js","names":[],"sources":["../../src/commands/printer.ts"],"sourcesContent":["import { relative } from 'node:path'\n\nimport type { RunResult } from '../types.js'\n\nexport function printRunSummary(result: RunResult, cwd: string): void {\n console.log(`\\n✅ ac-workflow ${result.mode} 完成`) // eslint-disable-line no-console\n\n if (result.created.length > 0) {\n console.log(`\\n新增 ${result.created.length} 个文件:`) // eslint-disable-line no-console\n for (const filePath of result.created) {\n console.log(`- ${relative(cwd, filePath)}`) // eslint-disable-line no-console\n }\n }\n\n if (result.updated.length > 0) {\n console.log(`\\n更新 ${result.updated.length} 个文件:`) // eslint-disable-line no-console\n for (const filePath of result.updated) {\n console.log(`- ${relative(cwd, filePath)}`) // eslint-disable-line no-console\n }\n }\n\n if (result.unchanged.length > 0) {\n console.log(`\\n无变更 ${result.unchanged.length} 个文件`) // eslint-disable-line no-console\n }\n}\n\nexport function printCheckResult(result: RunResult, cwd: string): void {\n if (result.changed.length === 0) {\n console.log('\\n✅ 检查通过:无需更新') // eslint-disable-line no-console\n return\n }\n\n console.log('\\n❌ 检查失败:以下文件需要更新') // eslint-disable-line no-console\n for (const filePath of result.changed) {\n console.log(`- ${relative(cwd, filePath)}`) // eslint-disable-line no-console\n }\n}\n"],"mappings":"qCAIA,SAAgB,EAAgB,EAAmB,EAAmB,CAGpE,GAFA,QAAQ,IAAI,mBAAmB,EAAO,KAAK,KAAK,CAE5C,EAAO,QAAQ,OAAS,EAAG,CAC7B,QAAQ,IAAI,QAAQ,EAAO,QAAQ,OAAO,OAAO,CACjD,IAAK,IAAM,KAAY,EAAO,QAC5B,QAAQ,IAAI,KAAK,EAAS,EAAK,EAAS,GAAG,CAI/C,GAAI,EAAO,QAAQ,OAAS,EAAG,CAC7B,QAAQ,IAAI,QAAQ,EAAO,QAAQ,OAAO,OAAO,CACjD,IAAK,IAAM,KAAY,EAAO,QAC5B,QAAQ,IAAI,KAAK,EAAS,EAAK,EAAS,GAAG,CAI3C,EAAO,UAAU,OAAS,GAC5B,QAAQ,IAAI,SAAS,EAAO,UAAU,OAAO,MAAM,CAIvD,SAAgB,EAAiB,EAAmB,EAAmB,CACrE,GAAI,EAAO,QAAQ,SAAW,EAAG,CAC/B,QAAQ,IAAI;aAAgB,CAC5B,OAGF,QAAQ,IAAI;iBAAoB,CAChC,IAAK,IAAM,KAAY,EAAO,QAC5B,QAAQ,IAAI,KAAK,EAAS,EAAK,EAAS,GAAG"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"status.js","names":[],"sources":["../../src/commands/status.ts"],"sourcesContent":["import { readRawContext, validate } from '../context/index.js'\n\nexport async function statusCommand(): Promise<void> {\n const { snapshot, currentPlanCount } = await readRawContext(process.cwd())\n const result = validate(snapshot, currentPlanCount)\n\n if (!result.valid) {\n for (const error of result.errors) {\n console.log(`❌ ${error}`) // eslint-disable-line no-console\n }\n process.exitCode = 1\n return\n }\n\n if (result.context === null) {\n console.log('ℹ 无活跃上下文') // eslint-disable-line no-console\n return\n }\n\n const ctx = result.context\n const current = ctx.currentPlan\n ? `plan-${ctx.currentPlan.number} (${ctx.currentPlan.status})`\n : '无'\n const preparing =\n ctx.preparing.length > 0 ? ctx.preparing.map((p) => `plan-${p.number}`).join(', ') : '无'\n\n console.log('')\n console.log('Agent Context Status')\n console.log('────────────────────')\n console.log(`当前计划: ${current}`)\n console.log(`待执行队列: ${preparing}`)\n console.log(`已归档: ${ctx.done.length} 个`)\n}\n"],"mappings":"yGAEA,eAAsB,GAA+B,CACnD,GAAM,CAAE,WAAU,oBAAqB,MAAM,EAAe,QAAQ,KAAK,CAAC,CACpE,EAAS,EAAS,EAAU,EAAiB,CAEnD,GAAI,CAAC,EAAO,MAAO,CACjB,IAAK,IAAM,KAAS,EAAO,OACzB,QAAQ,IAAI,KAAK,IAAQ,CAE3B,QAAQ,SAAW,EACnB,OAGF,GAAI,EAAO,UAAY,KAAM,CAC3B,QAAQ,IAAI,WAAW,CACvB,OAGF,IAAM,EAAM,EAAO,QACb,EAAU,EAAI,YAChB,QAAQ,EAAI,YAAY,OAAO,IAAI,EAAI,YAAY,OAAO,GAC1D,IACE,EACJ,EAAI,UAAU,OAAS,EAAI,EAAI,UAAU,IAAK,GAAM,QAAQ,EAAE,SAAS,CAAC,KAAK,KAAK,CAAG,IAEvF,QAAQ,IAAI,GAAG,CACf,QAAQ,IAAI,uBAAuB,CACnC,QAAQ,IAAI,uBAAuB,CACnC,QAAQ,IAAI,UAAU,IAAU,CAChC,QAAQ,IAAI,UAAU,IAAY,CAClC,QAAQ,IAAI,WAAW,EAAI,KAAK,OAAO,IAAI"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"sync.js","names":[],"sources":["../../src/commands/sync.ts"],"sourcesContent":["import { detectConfiguredToolIds, parseToolIds } from '../tools.js'\nimport type { ToolId } from '../types.js'\nimport { runSync } from '../runner.js'\nimport { printCheckResult, printRunSummary } from './printer.js'\n\nexport interface SyncCommandOptions {\n tools?: string\n check?: boolean\n}\n\nexport async function syncCommand(options: SyncCommandOptions = {}): Promise<void> {\n const cwd = process.cwd()\n const tools = resolveTools(cwd, options.tools)\n const check = options.check ?? false\n const result = await runSync({ cwd, tools, check })\n\n if (check) {\n printCheckResult(result, cwd)\n if (result.changed.length > 0) {\n process.exitCode = 1\n }\n return\n }\n\n printRunSummary(result, cwd)\n}\n\nfunction resolveTools(cwd: string, raw?: string): ToolId[] | undefined {\n if (!raw || raw.trim().length === 0) {\n const configuredTools = detectConfiguredToolIds(cwd)\n\n if (configuredTools.length > 0) {\n return configuredTools\n }\n\n throw new Error('未检测到已安装的 Skill,请先执行 install 或通过 --tools 显式指定工具')\n }\n\n return parseToolIds(raw)\n}\n"],"mappings":"oLAUA,eAAsB,EAAY,EAA8B,EAAE,CAAiB,CACjF,IAAM,EAAM,QAAQ,KAAK,CACnB,EAAQ,EAAa,EAAK,EAAQ,MAAM,CACxC,EAAQ,EAAQ,OAAS,GACzB,EAAS,MAAM,EAAQ,CAAE,MAAK,QAAO,QAAO,CAAC,CAEnD,GAAI,EAAO,CACT,EAAiB,EAAQ,EAAI,CACzB,EAAO,QAAQ,OAAS,IAC1B,QAAQ,SAAW,GAErB,OAGF,EAAgB,EAAQ,EAAI,CAG9B,SAAS,EAAa,EAAa,EAAoC,CACrE,GAAI,CAAC,GAAO,EAAI,MAAM,CAAC,SAAW,EAAG,CACnC,IAAM,EAAkB,EAAwB,EAAI,CAEpD,GAAI,EAAgB,OAAS,EAC3B,OAAO,EAGT,MAAU,MAAM,iDAAiD,CAGnE,OAAO,EAAa,EAAI"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"validate.js","names":[],"sources":["../../src/commands/validate.ts"],"sourcesContent":["import { readRawContext, validate } from '../context/index.js'\n\nexport async function validateCommand(): Promise<void> {\n const { snapshot, currentPlanCount } = await readRawContext(process.cwd())\n const result = validate(snapshot, currentPlanCount)\n\n if (result.context === null) {\n console.log('⚠️ 无 .agent-context 目录')\n return\n }\n\n if (result.valid) {\n console.log('✅ 校验通过')\n const ctx = result.context\n const current = ctx.currentPlan\n ? `plan-${ctx.currentPlan.number} (${ctx.currentPlan.status})`\n : '无'\n console.log(` 当前计划: ${current}`)\n console.log(` 待执行: ${ctx.preparing.length} 个`)\n console.log(` 已归档: ${ctx.done.length} 个`)\n return\n }\n\n for (const error of result.errors) {\n console.log(`❌ ${error}`)\n }\n process.exitCode = 1\n}\n"],"mappings":"yGAEA,eAAsB,GAAiC,CACrD,GAAM,CAAE,WAAU,oBAAqB,MAAM,EAAe,QAAQ,KAAK,CAAC,CACpE,EAAS,EAAS,EAAU,EAAiB,CAEnD,GAAI,EAAO,UAAY,KAAM,CAC3B,QAAQ,IAAI,yBAAyB,CACrC,OAGF,GAAI,EAAO,MAAO,CAChB,QAAQ,IAAI,SAAS,CACrB,IAAM,EAAM,EAAO,QACb,EAAU,EAAI,YAChB,QAAQ,EAAI,YAAY,OAAO,IAAI,EAAI,YAAY,OAAO,GAC1D,IACJ,QAAQ,IAAI,WAAW,IAAU,CACjC,QAAQ,IAAI,UAAU,EAAI,UAAU,OAAO,IAAI,CAC/C,QAAQ,IAAI,UAAU,EAAI,KAAK,OAAO,IAAI,CAC1C,OAGF,IAAK,IAAM,KAAS,EAAO,OACzB,QAAQ,IAAI,KAAK,IAAQ,CAE3B,QAAQ,SAAW"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"actions.js","names":[],"sources":["../../src/content/actions.ts"],"sourcesContent":["export const ACTION_NAMES = ['init', 'plan', 'replan', 'implement', 'patch', 'rush'] as const\ntype ActionName = (typeof ACTION_NAMES)[number]\n\nexport const ACTION_RENDERERS: Record<ActionName, () => string> = {\n init: renderInit,\n plan: renderPlan,\n replan: renderReplan,\n implement: renderImplement,\n patch: renderPatch,\n rush: renderRush\n}\n\nfunction renderInit(): string {\n return `# init\n\n初始化项目的 Agent Context 上下文。根据新旧项目类型处理 \\`AGENTS.md\\`,新项目会自动进入计划创建流程。\n\n可附带描述参数,用于补充项目背景、技术栈、特殊约束。\n\n## 执行步骤\n\n1. **判断项目类型**:检测根目录是否存在有效代码文件和目录结构。\n - 新项目:无实质代码,或用户明确说明是新项目。\n - 旧项目:已有代码、配置文件和目录结构。\n - 无法判断 → 向用户提问澄清,不可假设。\n\n2. **处理 AGENTS.md**:\n - 新项目:\n 1. 通过提问澄清以下要点(已从描述中获取的可跳过):项目目标与核心功能、技术栈与版本、代码规范与工具链(lint/formatter/测试)、目录结构偏好。\n 2. 生成高质量 \\`AGENTS.md\\`(须满足下方质量标准,不满足则重新优化直至满足)。\n 3. 继续执行 plan 创建初始计划。\n - 旧项目:\n 1. 若不存在 \\`AGENTS.md\\`:通过提问与代码阅读收集信息后生成。\n 2. 若已存在 \\`AGENTS.md\\`:按质量标准评估,不足时增补优化。\n 3. 默认不创建计划(除非用户明确要求)。\n\n3. **输出反馈**:向用户报告项目类型判定结果、AGENTS.md 处理结果、是否需要后续计划。\n\n## 高质量 AGENTS.md 标准\n\n- 常用命令与约束前置,降低代理执行歧义。\n- 明确列出目录结构(至少到第二层)。\n- 明确标注技术栈及版本。\n- 明确代码风格约束(命名规范、格式化工具、lint 配置)。\n- 内容精简,无冗余段落或模板化填充。\n- 大型单体仓库按子包拆分维护本地 \\`AGENTS.md\\`。\n`\n}\n\nfunction renderPlan(): string {\n return `# plan\n\n创建新的执行计划,写入 \\`.agent-context/plan-{number}/plan.md\\`。按复杂度可拆分为多个计划,维护「单当前计划 + preparing 队列」结构。\n\n必须附带计划描述。\n\n## 前置检查\n\n- 运行 \\`agent-context validate\\`,不通过则中止并报告错误。\n- 描述为空 → 拒绝执行。\n- 存在未归档的已执行当前计划 → 拒绝执行,提示先运行 \\`agent-context done\\` 归档。\n- 存在多个当前计划 → 拒绝执行,提示恢复单活跃状态。\n\n## 执行步骤\n\n1. **需求澄清**(存在以下任一歧义时必须提问,否则跳到步骤 2):\n - 范围边界不清:无法判定影响哪些文件或模块。\n - 存在显著不同的技术路径需用户决策。\n - 验收标准不明确:无法判断何时算\"完成\"。\n2. 按复杂度决定单计划或多计划拆分。\n3. 多计划拆分时:最小编号进入 \\`.agent-context/\\` 作为当前计划,其余进入 \\`.agent-context/preparing/\\`。单计划直接创建。\n4. 每个计划创建 \\`plan.md\\`,遵循下方模板。\n5. **自检**(不通过则修改后重新检查):\n - 每个步骤可独立执行且有明确完成标准。\n - 不存在过度拆分或拆分不足。\n - 影响范围可预估。\n\n## plan.md 模板\n\n\\`\\`\\`markdown\n# {计划名称}\n\n> 状态: 未执行\n\n## 目标\n\n{明确的目标描述}\n\n## 内容\n\n{详细的实施步骤}\n\n## 影响范围\n\n## 历史补丁\n\\`\\`\\`\n\n- 状态行唯一,仅允许 \\`未执行\\` 或 \\`已执行\\`。\n- \\`## 目标\\` 与 \\`## 内容\\` 不可为空。\n- \\`## 影响范围\\` 与 \\`## 历史补丁\\` 创建时留空,后续由 implement 和 patch 写入。\n`\n}\n\nfunction renderReplan(): string {\n return `# replan\n\n重新规划已有的未实施计划,保持「单当前计划 + preparing 队列」结构不变。\n\n必须附带重规划描述。\n\n## 前置检查\n\n- 运行 \\`agent-context validate\\`,不通过则中止并报告错误。\n- 描述为空 → 拒绝执行。\n- 无未实施计划 → 拒绝执行,提示使用 plan 创建。\n- 存在多个当前计划 → 拒绝执行,提示恢复单活跃状态。\n- 目标计划编号不存在 → 拒绝执行,列出可选编号。\n- 目标计划已执行 → 拒绝执行,提示使用 patch。\n\n## 作用域\n\n- 默认作用域:\\`.agent-context/preparing/\\` 中全部未实施计划。\n- 可通过描述指定仅重规划部分计划(如\"重规划 plan-3 和 plan-5\")。\n- 当前计划为 \\`已执行\\` → 禁止重写,仅允许重规划 \\`preparing/\\` 队列。\n- 当前计划为 \\`未执行\\` 且用户明确要求 → 可纳入重规划范围。\n\n## 执行步骤\n\n1. 解析描述,确定重规划目标范围。\n2. 读取目标计划 \\`plan.md\\`,理解现有意图。\n3. 生成新的拆分方案,保持「单当前计划 + 若干 preparing 计划」结构。\n4. 新增计划编号:全局 max(N)+1 递增分配;未改动计划保持原编号。\n5. 更新目录结构,确保每个新计划的 \\`plan.md\\` 遵循标准模板。\n`\n}\n\nfunction renderImplement(): string {\n return `# implement\n\n实施当前计划 \\`.agent-context/plan-{number}/plan.md\\` 中的全部步骤,通过验证循环后将状态更新为「已执行」。\n\n不接受额外描述。\n\n## 前置检查\n\n- 运行 \\`agent-context validate\\`,不通过则中止并报告错误。\n- 带描述 → 拒绝执行。\n- 当前计划不存在 → 拒绝执行,提示先创建计划。\n- 当前计划状态为 \\`已执行\\` → 拒绝执行,提示使用 patch 修补或运行 \\`agent-context done\\` 归档。\n- \\`## 目标\\` 或 \\`## 内容\\` 为空 → 拒绝执行,提示补充。\n- 存在多个当前计划 → 拒绝执行,提示恢复单活跃状态。\n- 仅操作当前计划,不直接操作 \\`preparing/\\` 中的计划。\n- 遇到阻塞问题应向用户报告,不可静默跳过。\n\n## 执行步骤\n\n1. 读取当前计划 \\`plan.md\\`,理解 \\`## 目标\\` 与 \\`## 内容\\`。\n2. 依据 \\`## 内容\\` 中的步骤逐项实施。\n3. **验证循环**(全部通过前不可进入步骤 4):\n a. 逐项对照 \\`## 内容\\` 确认每个步骤已实施。\n b. 运行项目验证:类型检查 → 测试。\n c. 若存在失败项 → 修复后回到 a 重新验证。\n d. 全部通过 → 进入步骤 4。\n4. 更新 \\`plan.md\\` 状态行:\\`> 状态: 未执行\\` → \\`> 状态: 已执行\\`。\n5. 更新 \\`## 影响范围\\`,记录所有变更文件。\n`\n}\n\nfunction renderPatch(): string {\n return `# patch\n\n基于当前已执行计划创建增量补丁,修复问题或追加变更。\n\n必须附带补丁描述。\n\n## 前置检查\n\n- 运行 \\`agent-context validate\\`,不通过则中止并报告错误。\n- 描述为空 → 拒绝执行。\n- 当前计划不存在 → 拒绝执行,提示先创建计划。\n- 当前计划状态为 \\`未执行\\` → 拒绝执行,提示先实施。\n- 存在多个当前计划 → 拒绝执行,提示恢复单活跃状态。\n- 补丁不改变计划状态,完成后保持 \\`已执行\\`。\n\n## 执行步骤\n\n1. 阅读 \\`plan.md\\` 与已有 \\`patch-{number}.md\\`,了解上下文与历史,避免重复修复。\n2. 根据描述执行补丁所需的代码变更。\n3. 完成必要验证(测试、类型检查等)。\n4. 创建 \\`patch-{number}.md\\`(编号:扫描当前计划目录已有补丁取 max+1),遵循下方模板。\n5. 回写 \\`plan.md\\`:\n - \\`## 历史补丁\\`:追加 \\`- patch-{number}: {补丁名称}\\`,按编号去重。\n - \\`## 影响范围\\`:合并本次变更路径,按路径去重。\n\n## patch.md 模板\n\n\\`\\`\\`markdown\n# {补丁名称}\n\n## 补丁内容\n\n{修改了什么、为什么修改}\n\n## 影响范围\n\n- 新增文件: \\`/path/to/file\\`\n- 修改文件: \\`/path/to/file\\`\n- 删除文件: \\`/path/to/file\\`\n\\`\\`\\`\n`\n}\n\nfunction renderRush(): string {\n return `# rush\n\n快速通道:创建计划并立即实施,适合范围明确、无需多轮规划的任务。\n\n必须附带任务描述。\n\n## 前置检查\n\n- 运行 \\`agent-context validate\\`,不通过则中止并报告错误。\n- 描述为空 → 拒绝执行。\n- 存在未归档的已执行当前计划 → 拒绝执行,提示先运行 \\`agent-context done\\` 归档。\n- 存在未实施的当前计划 → 拒绝执行,提示先 implement 或 replan。\n\n## 执行步骤\n\n1. 按 plan 协议创建单计划(不拆分,不进入 preparing 队列)。\n2. 无需用户确认计划内容,直接进入 implement 流程。\n3. 按 implement 协议执行全部步骤,包括验证循环:\n a. 逐项对照 \\`## 内容\\` 确认每个步骤已实施。\n b. 运行项目验证:类型检查 → 测试。\n c. 若存在失败项 → 修复后重新验证。\n d. 全部通过 → 进入步骤 4。\n4. 更新 \\`plan.md\\` 状态行为 \\`已执行\\`,更新 \\`## 影响范围\\`。\n`\n}\n"],"mappings":"AAAA,MAAa,EAAe,CAAC,OAAQ,OAAQ,SAAU,YAAa,QAAS,OAAO,CAGvE,EAAqD,CAChE,KAAM,EACN,KAAM,EACN,OAAQ,EACR,UAAW,EACX,MAAO,EACP,KAAM,EACP,CAED,SAAS,GAAqB,CAC5B,MAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAoCT,SAAS,GAAqB,CAC5B,MAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAqDT,SAAS,GAAuB,CAC9B,MAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAgCT,SAAS,GAA0B,CACjC,MAAO,irBA+BT,SAAS,GAAsB,CAC7B,MAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA2CT,SAAS,GAAqB,CAC5B,MAAO"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../src/content/index.ts"],"sourcesContent":["import type { SkillArtifacts, ToolTarget } from '../types.js'\nimport { ACTION_NAMES, ACTION_RENDERERS } from './actions.js'\n\nconst SKILL_NAME = 'ac-workflow'\nconst SKILL_DESCRIPTION =\n '管理 .agent-context 计划生命周期,按 init、plan、replan、implement、patch、rush、done 协议推进任务。'\n\nexport function renderSkillArtifacts(target: ToolTarget): SkillArtifacts {\n const files: SkillArtifacts['files'] = [\n { relativePath: 'SKILL.md', body: renderNavigator(target) },\n ...ACTION_NAMES.map((name) => ({\n relativePath: `actions/${name}.md`,\n body: ACTION_RENDERERS[name]()\n }))\n ]\n\n if (target.metadataFiles.includes('openai')) {\n files.push({ relativePath: 'agents/openai.yaml', body: renderOpenAIMetadata() })\n }\n\n return { files }\n}\n\n// ── Navigator ────────────────────────────────────────\n\nfunction renderNavigator(target: ToolTarget): string {\n return `${renderFrontmatter(target)}\n# Agent Context\n\n管理项目中的 \\`.agent-context/\\` 计划生命周期。匹配用户意图后,读取对应协议文件(相对于本文件所在目录)严格执行。\n\n## 意图匹配\n\n| 用户意图 | 动作 | 协议文件 |\n|----------|------|----------|\n| 初始化项目上下文、补全 AGENTS | init | \\`actions/init.md\\` |\n| 给需求出计划、拆分任务 | plan | \\`actions/plan.md\\` |\n| 重做计划、调整方案 | replan | \\`actions/replan.md\\` |\n| 按计划开始做、实现当前计划 | implement | \\`actions/implement.md\\` |\n| 实施后不满意、追加需求、修补问题 | patch | \\`actions/patch.md\\` |\n| 无活跃计划时快速出计划并实施 | rush | \\`actions/rush.md\\` |\n| 任务彻底完成、归档当前计划 | done | 运行 \\`agent-context done\\` |\n\n> **消歧**:存在已执行的当前计划时,用户提出任何变更需求 → 一律走 **patch**,禁止走 plan / rush。\n\n## 全局约束\n\n- 状态机两态:\\`未执行\\`、\\`已执行\\`。\n- 任意时刻最多一个当前计划:\\`.agent-context/plan-{number}\\`。\n- 多个当前计划 → 拒绝执行,提示恢复单活跃状态。\n- 计划编号全局递增,不复用。补丁编号在单计划目录内递增,不复用。\n\n## 目录结构\n\n\\`\\`\\`text\n.agent-context/\n├── plan-{N}/ # 当前计划(最多一个)\n│ ├── plan.md\n│ └── patch-{N}.md\n├── preparing/ # 待执行计划队列\n│ └── plan-{N}/\n└── done/ # 已归档计划\n └── plan-{N}-{YYYYMMDD}/\n\\`\\`\\`\n\n编号规则:扫描全部 \\`plan-N\\` 目录取 \\`max(N)+1\\`。\n`\n}\n\n// ── Frontmatter & Metadata ──────────────────────────\n\nfunction renderFrontmatter(target: ToolTarget): string {\n const lines = ['---', `name: ${SKILL_NAME}`, `description: ${SKILL_DESCRIPTION}`]\n\n if (target.frontmatterProfile === 'claude') {\n lines.push('argument-hint: [request]')\n }\n\n if (target.frontmatterProfile === 'copilot') {\n lines.push('license: MIT')\n }\n\n lines.push('---', '')\n return `${lines.join('\\n')}\\n`\n}\n\nfunction renderOpenAIMetadata(): string {\n return `interface:\n display_name: \"Agent Context Workflow\"\n short_description: \"统一管理 .agent-context 计划生命周期\"\n default_prompt: \"Use $ac-workflow to manage the current task through init, plan, replan, implement, patch, rush, or done.\"\n\npolicy:\n allow_implicit_invocation: true\n`\n}\n"],"mappings":"kEAOA,SAAgB,EAAqB,EAAoC,CACvE,IAAM,EAAiC,CACrC,CAAE,aAAc,WAAY,KAAM,EAAgB,EAAO,CAAE,CAC3D,GAAG,EAAa,IAAK,IAAU,CAC7B,aAAc,WAAW,EAAK,KAC9B,KAAM,EAAiB,IAAO,CAC/B,EAAE,CACJ,CAMD,OAJI,EAAO,cAAc,SAAS,SAAS,EACzC,EAAM,KAAK,CAAE,aAAc,qBAAsB,KAAM,GAAsB,CAAE,CAAC,CAG3E,CAAE,QAAO,CAKlB,SAAS,EAAgB,EAA4B,CACnD,MAAO,GAAG,EAAkB,EAAO,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA6CtC,SAAS,EAAkB,EAA4B,CACrD,IAAM,EAAQ,CAAC,MAAO,oBAAuB,6FAAoC,CAWjF,OATI,EAAO,qBAAuB,UAChC,EAAM,KAAK,2BAA2B,CAGpC,EAAO,qBAAuB,WAChC,EAAM,KAAK,eAAe,CAG5B,EAAM,KAAK,MAAO,GAAG,CACd,GAAG,EAAM,KAAK;EAAK,CAAC,IAG7B,SAAS,GAA+B,CACtC,MAAO"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"archiver.js","names":[],"sources":["../../src/context/archiver.ts"],"sourcesContent":["import { rename, mkdir } from 'node:fs/promises'\nimport { join } from 'node:path'\n\nimport type { ArchiveResult, ContextSnapshot } from '../types.js'\n\nexport async function archive(context: ContextSnapshot): Promise<ArchiveResult> {\n if (!context.currentPlan) {\n throw new Error('无当前计划')\n }\n\n if (context.currentPlan.status !== '已执行') {\n throw new Error('当前计划尚未执行')\n }\n\n const archiveName = `plan-${context.currentPlan.number}-${formatDate()}`\n const doneDir = join(context.root, 'done')\n const archivedTo = join(doneDir, archiveName)\n\n await mkdir(doneDir, { recursive: true })\n await rename(context.currentPlan.dir, archivedTo)\n\n let promoted: number | null = null\n const first = context.preparing[0]\n if (first) {\n const targetDir = join(context.root, `plan-${first.number}`)\n await rename(first.dir, targetDir)\n promoted = first.number\n }\n\n return {\n archivedTo,\n promoted,\n remainingPreparing: context.preparing.length - (promoted !== null ? 1 : 0)\n }\n}\n\n// ── Helpers ──────────────────────────────────────────\n\nfunction formatDate(): string {\n const d = new Date()\n const y = String(d.getFullYear())\n const m = String(d.getMonth() + 1).padStart(2, '0')\n const day = String(d.getDate()).padStart(2, '0')\n return `${y}${m}${day}`\n}\n"],"mappings":"sFAKA,eAAsB,EAAQ,EAAkD,CAC9E,GAAI,CAAC,EAAQ,YACX,MAAU,MAAM,QAAQ,CAG1B,GAAI,EAAQ,YAAY,SAAW,MACjC,MAAU,MAAM,WAAW,CAG7B,IAAM,EAAc,QAAQ,EAAQ,YAAY,OAAO,GAAG,GAAY,GAChE,EAAU,EAAK,EAAQ,KAAM,OAAO,CACpC,EAAa,EAAK,EAAS,EAAY,CAE7C,MAAM,EAAM,EAAS,CAAE,UAAW,GAAM,CAAC,CACzC,MAAM,EAAO,EAAQ,YAAY,IAAK,EAAW,CAEjD,IAAI,EAA0B,KACxB,EAAQ,EAAQ,UAAU,GAChC,GAAI,EAAO,CACT,IAAM,EAAY,EAAK,EAAQ,KAAM,QAAQ,EAAM,SAAS,CAC5D,MAAM,EAAO,EAAM,IAAK,EAAU,CAClC,EAAW,EAAM,OAGnB,MAAO,CACL,aACA,WACA,mBAAoB,EAAQ,UAAU,QAAU,IAAa,KAAW,EAAJ,GACrE,CAKH,SAAS,GAAqB,CAC5B,IAAM,EAAI,IAAI,KAId,MAAO,GAHG,OAAO,EAAE,aAAa,CAAC,GACvB,OAAO,EAAE,UAAU,CAAG,EAAE,CAAC,SAAS,EAAG,IAAI,GACvC,OAAO,EAAE,SAAS,CAAC,CAAC,SAAS,EAAG,IAAI"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"reader.js","names":[],"sources":["../../src/context/reader.ts"],"sourcesContent":["import { readdir, readFile } from 'node:fs/promises'\nimport { existsSync } from 'node:fs'\nimport { join } from 'node:path'\n\nimport type { ContextSnapshot, PlanInfo, PlanStatus } from '../types.js'\n\nconst PLAN_DIR_RE = /^plan-(\\d+)$/\nconst DONE_DIR_RE = /^plan-(\\d+)(?:-\\d{8})?$/\nconst EXACT_STATUS_RE = /^>\\s*状态:\\s*(未执行|已执行)$/m\nconst LOOSE_STATUS_RE = /^>?[ \\t]*状态[::].*$/m\n\n// ── Public API ───────────────────────────────────────\n\nexport async function readContext(cwd: string): Promise<ContextSnapshot | null> {\n const { snapshot } = await readRawContext(cwd)\n return snapshot\n}\n\nexport async function readRawContext(\n cwd: string\n): Promise<{ snapshot: ContextSnapshot | null; currentPlanCount: number }> {\n const root = join(cwd, '.agent-context')\n\n if (!existsSync(root)) {\n return { snapshot: null, currentPlanCount: 0 }\n }\n\n const currentPlans = await readPlanDirs(root)\n const preparing = await readPlanDirs(join(root, 'preparing'))\n const done = await readDonePlans(join(root, 'done'))\n\n const snapshot: ContextSnapshot = {\n root,\n currentPlan: currentPlans[0] ?? null,\n preparing,\n done\n }\n\n return { snapshot, currentPlanCount: currentPlans.length }\n}\n\nexport async function readPlanStatus(planDir: string): Promise<PlanStatus> {\n const planFile = join(planDir, 'plan.md')\n\n if (!existsSync(planFile)) {\n return '未执行'\n }\n\n const content = await readFile(planFile, 'utf-8')\n \n const exactMatch = content.match(EXACT_STATUS_RE)\n if (exactMatch) {\n return exactMatch[1] as PlanStatus\n }\n\n if (LOOSE_STATUS_RE.test(content)) {\n return '未知'\n }\n\n return '未执行'\n}\n\n// ── Helpers ──────────────────────────────────────────\n\nasync function readPlanDirs(parentDir: string): Promise<PlanInfo[]> {\n if (!existsSync(parentDir)) return []\n\n const entries = await readdir(parentDir, { withFileTypes: true })\n const plans: PlanInfo[] = []\n\n for (const entry of entries) {\n if (!entry.isDirectory()) continue\n const match = entry.name.match(PLAN_DIR_RE)\n if (!match?.[1]) continue\n const number = parseInt(match[1], 10)\n const dir = join(parentDir, entry.name)\n const status = await readPlanStatus(dir)\n plans.push({ number, status, dir })\n }\n\n return plans.sort((a, b) => a.number - b.number)\n}\n\nasync function readDonePlans(parentDir: string): Promise<Pick<PlanInfo, 'number' | 'dir'>[]> {\n if (!existsSync(parentDir)) return []\n const entries = await readdir(parentDir, { withFileTypes: true })\n const plans: Pick<PlanInfo, 'number' | 'dir'>[] = []\n \n for (const entry of entries) {\n if (!entry.isDirectory()) continue\n const match = entry.name.match(DONE_DIR_RE)\n if (!match?.[1]) continue\n plans.push({\n number: parseInt(match[1], 10),\n dir: join(parentDir, entry.name)\n })\n }\n\n return plans.sort((a, b) => a.number - b.number)\n}\n"],"mappings":"+HAMA,MAAM,EAAc,eACd,EAAc,0BACd,EAAkB,yBAClB,EAAkB,sBASxB,eAAsB,EACpB,EACyE,CACzE,IAAM,EAAO,EAAK,EAAK,iBAAiB,CAExC,GAAI,CAAC,EAAW,EAAK,CACnB,MAAO,CAAE,SAAU,KAAM,iBAAkB,EAAG,CAGhD,IAAM,EAAe,MAAM,EAAa,EAAK,CACvC,EAAY,MAAM,EAAa,EAAK,EAAM,YAAY,CAAC,CACvD,EAAO,MAAM,EAAc,EAAK,EAAM,OAAO,CAAC,CASpD,MAAO,CAAE,SAPyB,CAChC,OACA,YAAa,EAAa,IAAM,KAChC,YACA,OACD,CAEkB,iBAAkB,EAAa,OAAQ,CAG5D,eAAsB,EAAe,EAAsC,CACzE,IAAM,EAAW,EAAK,EAAS,UAAU,CAEzC,GAAI,CAAC,EAAW,EAAS,CACvB,MAAO,MAGT,IAAM,EAAU,MAAM,EAAS,EAAU,QAAQ,CAE3C,EAAa,EAAQ,MAAM,EAAgB,CASjD,OARI,EACK,EAAW,GAGhB,EAAgB,KAAK,EAAQ,CACxB,KAGF,MAKT,eAAe,EAAa,EAAwC,CAClE,GAAI,CAAC,EAAW,EAAU,CAAE,MAAO,EAAE,CAErC,IAAM,EAAU,MAAM,EAAQ,EAAW,CAAE,cAAe,GAAM,CAAC,CAC3D,EAAoB,EAAE,CAE5B,IAAK,IAAM,KAAS,EAAS,CAC3B,GAAI,CAAC,EAAM,aAAa,CAAE,SAC1B,IAAM,EAAQ,EAAM,KAAK,MAAM,EAAY,CAC3C,GAAI,CAAC,IAAQ,GAAI,SACjB,IAAM,EAAS,SAAS,EAAM,GAAI,GAAG,CAC/B,EAAM,EAAK,EAAW,EAAM,KAAK,CACjC,EAAS,MAAM,EAAe,EAAI,CACxC,EAAM,KAAK,CAAE,SAAQ,SAAQ,MAAK,CAAC,CAGrC,OAAO,EAAM,MAAM,EAAG,IAAM,EAAE,OAAS,EAAE,OAAO,CAGlD,eAAe,EAAc,EAAgE,CAC3F,GAAI,CAAC,EAAW,EAAU,CAAE,MAAO,EAAE,CACrC,IAAM,EAAU,MAAM,EAAQ,EAAW,CAAE,cAAe,GAAM,CAAC,CAC3D,EAA4C,EAAE,CAEpD,IAAK,IAAM,KAAS,EAAS,CAC3B,GAAI,CAAC,EAAM,aAAa,CAAE,SAC1B,IAAM,EAAQ,EAAM,KAAK,MAAM,EAAY,CACtC,IAAQ,IACb,EAAM,KAAK,CACT,OAAQ,SAAS,EAAM,GAAI,GAAG,CAC9B,IAAK,EAAK,EAAW,EAAM,KAAK,CACjC,CAAC,CAGJ,OAAO,EAAM,MAAM,EAAG,IAAM,EAAE,OAAS,EAAE,OAAO"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"validator.js","names":[],"sources":["../../src/context/validator.ts"],"sourcesContent":["import { existsSync } from 'node:fs'\nimport { join } from 'node:path'\n\nimport type { ContextSnapshot, ValidateResult } from '../types.js'\n\nexport function validate(\n snapshot: ContextSnapshot | null,\n currentPlanCount: number\n): ValidateResult {\n if (snapshot === null) {\n return { valid: true, errors: [], context: null }\n }\n\n const errors: string[] = []\n\n if (currentPlanCount > 1) {\n errors.push(`存在 ${currentPlanCount} 个当前计划,应最多 1 个。`)\n }\n\n if (snapshot.currentPlan) {\n const planMd = join(snapshot.currentPlan.dir, 'plan.md')\n if (!existsSync(planMd)) {\n errors.push(`当前计划 plan-${snapshot.currentPlan.number} 缺少 plan.md。`)\n }\n\n if (snapshot.currentPlan.status === '未知') {\n errors.push(`当前计划 plan-${snapshot.currentPlan.number} 的状态格式严重不符合要求,请严格按照 \"> 状态: 已执行\" 或 \"> 状态: 未执行\" 的格式书写,禁止添加 emoji 或其他额外字符。`)\n }\n }\n\n for (const p of snapshot.preparing) {\n if (p.status === '未知') {\n errors.push(`待执行计划 plan-${p.number} 的状态格式严重不符合要求,请严格按照 \"> 状态: 已执行\" 或 \"> 状态: 未执行\" 的格式书写。`)\n }\n }\n\n const allNumbers: number[] = []\n for (const d of snapshot.done) allNumbers.push(d.number)\n if (snapshot.currentPlan) allNumbers.push(snapshot.currentPlan.number)\n for (const p of snapshot.preparing) allNumbers.push(p.number)\n\n const seen = new Set<number>()\n const duplicates = new Set<number>()\n for (const n of allNumbers) {\n if (seen.has(n)) duplicates.add(n)\n seen.add(n)\n }\n\n if (duplicates.size > 0) {\n const nums = [...duplicates].sort((a, b) => a - b).join(', ')\n errors.push(`计划编号冲突: ${nums}。`)\n }\n\n allNumbers.sort((a, b) => a - b)\n for (let i = 0; i < allNumbers.length; i++) {\n if (allNumbers[i] !== i + 1) {\n errors.push(`计划序列不连续或未从 1 开始。预期出现编号 ${i + 1},实际遇到编号 ${allNumbers[i]} (要求必须是从 1 开始顺序查询)。`)\n break\n }\n }\n\n return { valid: errors.length === 0, errors, context: snapshot }\n}\n"],"mappings":"sEAKA,SAAgB,EACd,EACA,EACgB,CAChB,GAAI,IAAa,KACf,MAAO,CAAE,MAAO,GAAM,OAAQ,EAAE,CAAE,QAAS,KAAM,CAGnD,IAAM,EAAmB,EAAE,CAEvB,EAAmB,GACrB,EAAO,KAAK,MAAM,EAAiB,iBAAiB,CAGlD,EAAS,cAEN,EADU,EAAK,EAAS,YAAY,IAAK,UAAU,CACjC,EACrB,EAAO,KAAK,aAAa,EAAS,YAAY,OAAO,cAAc,CAGjE,EAAS,YAAY,SAAW,MAClC,EAAO,KAAK,aAAa,EAAS,YAAY,OAAO,yEAAyE,EAIlI,IAAK,IAAM,KAAK,EAAS,UACnB,EAAE,SAAW,MACf,EAAO,KAAK,cAAc,EAAE,OAAO,sDAAsD,CAI7F,IAAM,EAAuB,EAAE,CAC/B,IAAK,IAAM,KAAK,EAAS,KAAM,EAAW,KAAK,EAAE,OAAO,CACpD,EAAS,aAAa,EAAW,KAAK,EAAS,YAAY,OAAO,CACtE,IAAK,IAAM,KAAK,EAAS,UAAW,EAAW,KAAK,EAAE,OAAO,CAE7D,IAAM,EAAO,IAAI,IACX,EAAa,IAAI,IACvB,IAAK,IAAM,KAAK,EACV,EAAK,IAAI,EAAE,EAAE,EAAW,IAAI,EAAE,CAClC,EAAK,IAAI,EAAE,CAGb,GAAI,EAAW,KAAO,EAAG,CACvB,IAAM,EAAO,CAAC,GAAG,EAAW,CAAC,MAAM,EAAG,IAAM,EAAI,EAAE,CAAC,KAAK,KAAK,CAC7D,EAAO,KAAK,WAAW,EAAK,GAAG,CAGjC,EAAW,MAAM,EAAG,IAAM,EAAI,EAAE,CAChC,IAAK,IAAI,EAAI,EAAG,EAAI,EAAW,OAAQ,IACrC,GAAI,EAAW,KAAO,EAAI,EAAG,CAC3B,EAAO,KAAK,0BAA0B,EAAI,EAAE,UAAU,EAAW,GAAG,qBAAqB,CACzF,MAIJ,MAAO,CAAE,MAAO,EAAO,SAAW,EAAG,SAAQ,QAAS,EAAU"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"runner.js","names":[],"sources":["../src/runner.ts"],"sourcesContent":["import { resolve, dirname } from 'node:path'\nimport { existsSync } from 'node:fs'\nimport { mkdir, readFile, writeFile } from 'node:fs/promises'\n\nimport type { SkillPaths } from './tools.js'\nimport { resolveToolTargets, resolveSkillPaths } from './tools.js'\nimport { renderSkillArtifacts } from './content/index.js'\nimport type { ApplyMutationResult, FileMutation, RunOptions, RunResult, ToolId, ToolTarget } from './types.js'\n\nexport async function runInstall(options: RunOptions = {}): Promise<RunResult> {\n return run('install', options)\n}\n\nexport async function runSync(options: RunOptions = {}): Promise<RunResult> {\n return run('sync', options)\n}\n\n// ── Orchestration ───────────────────────────────────\n\nasync function run(mode: 'install' | 'sync', options: RunOptions): Promise<RunResult> {\n const cwd = options.cwd ?? process.cwd()\n const tools = dedup(options.tools)\n const targets = resolveToolTargets(tools)\n\n const mutations: FileMutation[] = targets.flatMap(target => buildMutations(target, cwd))\n\n const check = options.check ?? false\n const result = await applyMutations(mutations, check)\n\n return { ...result, mode, check }\n}\n\n// ── Mutation building ───────────────────────────────\n\nfunction buildMutations(target: ToolTarget, cwd: string): FileMutation[] {\n const artifacts = renderSkillArtifacts(target)\n const paths = resolveSkillPaths(target, cwd)\n\n return artifacts.files.map(file => ({\n path: resolveArtifactPath(paths, file.relativePath),\n body: file.body\n }))\n}\n\nfunction resolveArtifactPath(paths: SkillPaths, relativePath: string): string {\n if (relativePath === 'SKILL.md') {\n return paths.skillFile\n }\n\n return resolve(paths.skillDir, relativePath)\n}\n\n// ── Mutation application ────────────────────────────\n\nasync function applyMutations(\n mutations: FileMutation[],\n check: boolean\n): Promise<ApplyMutationResult> {\n const result: ApplyMutationResult = {\n created: [],\n updated: [],\n unchanged: [],\n changed: []\n }\n\n for (const mutation of mutations) {\n const fileExists = existsSync(mutation.path)\n const next = await resolveNextContent(mutation, fileExists)\n\n if (!next.changed) {\n result.unchanged.push(mutation.path)\n continue\n }\n\n if (!check) {\n await mkdir(dirname(mutation.path), { recursive: true })\n await writeFile(mutation.path, next.content, 'utf-8')\n }\n\n result.changed.push(mutation.path)\n\n if (fileExists) {\n result.updated.push(mutation.path)\n } else {\n result.created.push(mutation.path)\n }\n }\n\n return result\n}\n\nasync function resolveNextContent(\n mutation: FileMutation,\n fileExists: boolean\n): Promise<{ content: string; changed: boolean }> {\n const content = normalizeTrailingNewline(mutation.body)\n\n if (!fileExists) {\n return { content, changed: true }\n }\n\n const current = await readFile(mutation.path, 'utf-8')\n return { content, changed: current !== content }\n}\n\nfunction normalizeTrailingNewline(content: string): string {\n return content.endsWith('\\n') ? content : `${content}\\n`\n}\n\nfunction dedup(tools?: ToolId[]): ToolId[] | undefined {\n if (!tools || tools.length === 0) return undefined\n return [...new Set(tools)]\n}\n"],"mappings":"6RASA,eAAsB,EAAW,EAAsB,EAAE,CAAsB,CAC7E,OAAO,EAAI,UAAW,EAAQ,CAGhC,eAAsB,EAAQ,EAAsB,EAAE,CAAsB,CAC1E,OAAO,EAAI,OAAQ,EAAQ,CAK7B,eAAe,EAAI,EAA0B,EAAyC,CACpF,IAAM,EAAM,EAAQ,KAAO,QAAQ,KAAK,CAIlC,EAFU,EADF,EAAM,EAAQ,MAAM,CACO,CAEC,QAAQ,GAAU,EAAe,EAAQ,EAAI,CAAC,CAElF,EAAQ,EAAQ,OAAS,GAG/B,MAAO,CAAE,GAFM,MAAM,EAAe,EAAW,EAAM,CAEjC,OAAM,QAAO,CAKnC,SAAS,EAAe,EAAoB,EAA6B,CACvE,IAAM,EAAY,EAAqB,EAAO,CACxC,EAAQ,EAAkB,EAAQ,EAAI,CAE5C,OAAO,EAAU,MAAM,IAAI,IAAS,CAClC,KAAM,EAAoB,EAAO,EAAK,aAAa,CACnD,KAAM,EAAK,KACZ,EAAE,CAGL,SAAS,EAAoB,EAAmB,EAA8B,CAK5E,OAJI,IAAiB,WACZ,EAAM,UAGR,EAAQ,EAAM,SAAU,EAAa,CAK9C,eAAe,EACb,EACA,EAC8B,CAC9B,IAAM,EAA8B,CAClC,QAAS,EAAE,CACX,QAAS,EAAE,CACX,UAAW,EAAE,CACb,QAAS,EAAE,CACZ,CAED,IAAK,IAAM,KAAY,EAAW,CAChC,IAAM,EAAa,EAAW,EAAS,KAAK,CACtC,EAAO,MAAM,EAAmB,EAAU,EAAW,CAE3D,GAAI,CAAC,EAAK,QAAS,CACjB,EAAO,UAAU,KAAK,EAAS,KAAK,CACpC,SAGG,IACH,MAAM,EAAM,EAAQ,EAAS,KAAK,CAAE,CAAE,UAAW,GAAM,CAAC,CACxD,MAAM,EAAU,EAAS,KAAM,EAAK,QAAS,QAAQ,EAGvD,EAAO,QAAQ,KAAK,EAAS,KAAK,CAE9B,EACF,EAAO,QAAQ,KAAK,EAAS,KAAK,CAElC,EAAO,QAAQ,KAAK,EAAS,KAAK,CAItC,OAAO,EAGT,eAAe,EACb,EACA,EACgD,CAChD,IAAM,EAAU,EAAyB,EAAS,KAAK,CAOvD,OALK,EAKE,CAAE,UAAS,QADF,MAAM,EAAS,EAAS,KAAM,QAAQ,GACf,EAAS,CAJvC,CAAE,UAAS,QAAS,GAAM,CAOrC,SAAS,EAAyB,EAAyB,CACzD,OAAO,EAAQ,SAAS;EAAK,CAAG,EAAU,GAAG,EAAQ,IAGvD,SAAS,EAAM,EAAwC,CACjD,MAAC,GAAS,EAAM,SAAW,GAC/B,MAAO,CAAC,GAAG,IAAI,IAAI,EAAM,CAAC"}
package/dist/tools.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"tools.js","names":[],"sources":["../src/tools.ts"],"sourcesContent":["import { existsSync } from 'node:fs'\nimport { resolve } from 'node:path'\n\nimport type { ToolId, ToolTarget } from './types.js'\n\nconst SKILL_FILE_NAME = 'SKILL.md'\nconst SKILL_NAME = 'ac-workflow'\n\nconst TOOL_TARGET_MAP: Record<ToolId, ToolTarget> = {\n claude: {\n id: 'claude',\n name: 'Claude Code',\n skillRootDir: '.claude/skills',\n frontmatterProfile: 'claude',\n metadataFiles: []\n },\n codex: {\n id: 'codex',\n name: 'Codex',\n skillRootDir: '.codex/skills',\n frontmatterProfile: 'standard',\n metadataFiles: ['openai']\n },\n cursor: {\n id: 'cursor',\n name: 'Cursor',\n skillRootDir: '.cursor/skills',\n frontmatterProfile: 'standard',\n metadataFiles: []\n },\n antigravity: {\n id: 'antigravity',\n name: 'Antigravity',\n skillRootDir: '.agent/skills',\n frontmatterProfile: 'standard',\n metadataFiles: []\n },\n copilot: {\n id: 'copilot',\n name: 'GitHub Copilot',\n skillRootDir: '.github/skills',\n frontmatterProfile: 'copilot',\n metadataFiles: []\n }\n}\n\nexport const DEFAULT_TOOL_ORDER: ToolId[] = ['claude', 'codex', 'cursor', 'antigravity', 'copilot']\n\nexport interface ToolChoice {\n id: ToolId\n name: string\n}\n\nexport function getToolChoices(): ToolChoice[] {\n return DEFAULT_TOOL_ORDER.map((id) => ({ id, name: TOOL_TARGET_MAP[id].name }))\n}\n\nexport function parseToolIds(toolsText: string): ToolId[] {\n const parsed = toolsText\n .split(',')\n .map((item) => item.trim().toLowerCase())\n .filter(Boolean)\n\n if (parsed.length === 0) {\n return [...DEFAULT_TOOL_ORDER]\n }\n\n const uniqueIds: ToolId[] = []\n\n for (const value of parsed) {\n if (!isToolId(value)) {\n throw new Error(`不支持的工具标识: ${value}。可选值: ${DEFAULT_TOOL_ORDER.join(', ')}`)\n }\n\n if (!uniqueIds.includes(value)) {\n uniqueIds.push(value)\n }\n }\n\n return uniqueIds\n}\n\nexport function resolveToolTargets(tools?: ToolId[]): ToolTarget[] {\n const selected = tools && tools.length > 0 ? tools : DEFAULT_TOOL_ORDER\n return selected.map((id) => ({ ...TOOL_TARGET_MAP[id] }))\n}\n\nexport function detectConfiguredToolIds(cwd: string): ToolId[] {\n return DEFAULT_TOOL_ORDER.filter((toolId) => {\n const target = TOOL_TARGET_MAP[toolId]\n return existsSync(resolveSkillPaths(target, cwd).skillFile)\n })\n}\n\n// ── Skill 路径解析 ───────────────────────────────────\n\nexport interface SkillPaths {\n skillDir: string\n skillFile: string\n openaiMetadataFile: string\n}\n\nexport function resolveSkillPaths(target: ToolTarget, cwd: string): SkillPaths {\n const skillDir = resolve(cwd, target.skillRootDir, SKILL_NAME)\n return {\n skillDir,\n skillFile: resolve(skillDir, SKILL_FILE_NAME),\n openaiMetadataFile: resolve(skillDir, 'agents/openai.yaml')\n }\n}\n\nfunction isToolId(value: string): value is ToolId {\n return Object.hasOwn(TOOL_TARGET_MAP, value)\n}\n"],"mappings":"yEAKA,MAGM,EAA8C,CAClD,OAAQ,CACN,GAAI,SACJ,KAAM,cACN,aAAc,iBACd,mBAAoB,SACpB,cAAe,EAAE,CAClB,CACD,MAAO,CACL,GAAI,QACJ,KAAM,QACN,aAAc,gBACd,mBAAoB,WACpB,cAAe,CAAC,SAAS,CAC1B,CACD,OAAQ,CACN,GAAI,SACJ,KAAM,SACN,aAAc,iBACd,mBAAoB,WACpB,cAAe,EAAE,CAClB,CACD,YAAa,CACX,GAAI,cACJ,KAAM,cACN,aAAc,gBACd,mBAAoB,WACpB,cAAe,EAAE,CAClB,CACD,QAAS,CACP,GAAI,UACJ,KAAM,iBACN,aAAc,iBACd,mBAAoB,UACpB,cAAe,EAAE,CAClB,CACF,CAEY,EAA+B,CAAC,SAAU,QAAS,SAAU,cAAe,UAAU,CAOnG,SAAgB,GAA+B,CAC7C,OAAO,EAAmB,IAAK,IAAQ,CAAE,KAAI,KAAM,EAAgB,GAAI,KAAM,EAAE,CAGjF,SAAgB,EAAa,EAA6B,CACxD,IAAM,EAAS,EACZ,MAAM,IAAI,CACV,IAAK,GAAS,EAAK,MAAM,CAAC,aAAa,CAAC,CACxC,OAAO,QAAQ,CAElB,GAAI,EAAO,SAAW,EACpB,MAAO,CAAC,GAAG,EAAmB,CAGhC,IAAM,EAAsB,EAAE,CAE9B,IAAK,IAAM,KAAS,EAAQ,CAC1B,GAAI,CAAC,EAAS,EAAM,CAClB,MAAU,MAAM,aAAa,EAAM,QAAQ,EAAmB,KAAK,KAAK,GAAG,CAGxE,EAAU,SAAS,EAAM,EAC5B,EAAU,KAAK,EAAM,CAIzB,OAAO,EAGT,SAAgB,EAAmB,EAAgC,CAEjE,OADiB,GAAS,EAAM,OAAS,EAAI,EAAQ,GACrC,IAAK,IAAQ,CAAE,GAAG,EAAgB,GAAK,EAAE,CAG3D,SAAgB,EAAwB,EAAuB,CAC7D,OAAO,EAAmB,OAAQ,GAAW,CAC3C,IAAM,EAAS,EAAgB,GAC/B,OAAO,EAAW,EAAkB,EAAQ,EAAI,CAAC,UAAU,EAC3D,CAWJ,SAAgB,EAAkB,EAAoB,EAAyB,CAC7E,IAAM,EAAW,EAAQ,EAAK,EAAO,aAAc,cAAW,CAC9D,MAAO,CACL,WACA,UAAW,EAAQ,EAAU,WAAgB,CAC7C,mBAAoB,EAAQ,EAAU,qBAAqB,CAC5D,CAGH,SAAS,EAAS,EAAgC,CAChD,OAAO,OAAO,OAAO,EAAiB,EAAM"}