@cat-kit/agent-context 1.1.6 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +74 -27
- package/dist/cli.js +1 -1
- package/dist/commands/done.js +1 -1
- package/dist/commands/index-cmd.js +1 -0
- package/dist/commands/init.js +1 -0
- package/dist/commands/install.js +1 -1
- package/dist/commands/status.js +1 -1
- package/dist/commands/sync.js +1 -1
- package/dist/commands/validate.js +1 -1
- package/dist/content/actions.js +27 -11
- package/dist/content/index.js +14 -11
- package/dist/context/indexer.js +3 -0
- package/dist/context/reader.js +1 -1
- package/dist/context/scope.js +5 -0
- package/dist/stats.html +1 -1
- package/package.json +3 -3
- package/src/cli.ts +11 -0
- package/src/commands/done.ts +7 -1
- package/src/commands/index-cmd.ts +26 -0
- package/src/commands/init.ts +43 -0
- package/src/commands/install.ts +1 -1
- package/src/commands/status.ts +1 -0
- package/src/commands/sync.ts +1 -1
- package/src/commands/validate.ts +1 -0
- package/src/content/actions.ts +27 -11
- package/src/content/index.ts +14 -11
- package/src/context/index.ts +2 -0
- package/src/context/indexer.ts +52 -0
- package/src/context/reader.ts +13 -3
- package/src/context/scope.ts +70 -0
- package/src/types.ts +1 -0
package/README.md
CHANGED
|
@@ -15,13 +15,17 @@
|
|
|
15
15
|
|
|
16
16
|
```text
|
|
17
17
|
.agent-context/
|
|
18
|
-
├──
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
├──
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
└──
|
|
18
|
+
├── .env # SCOPE 配置(SCOPE=<name>)
|
|
19
|
+
├── .gitignore
|
|
20
|
+
└── {scope}/ # 作用域目录(按协作者隔离)
|
|
21
|
+
├── index.md # 计划索引(自动生成)
|
|
22
|
+
├── plan-{N}/ # 当前计划(最多一个)
|
|
23
|
+
│ ├── plan.md
|
|
24
|
+
│ └── patch-{N}.md
|
|
25
|
+
├── preparing/ # 待执行计划队列
|
|
26
|
+
│ └── plan-{N}/
|
|
27
|
+
└── done/ # 已归档计划
|
|
28
|
+
└── plan-{N}-{YYYYMMDD}/
|
|
25
29
|
```
|
|
26
30
|
|
|
27
31
|
生命周期如下:
|
|
@@ -82,15 +86,15 @@ agent-context install --tools claude,codex,cursor
|
|
|
82
86
|
|
|
83
87
|
下面的 action 不是 CLI 子命令,而是你对 AI 说的话。AI 安装 Skill 后,会把这些话映射到固定协议。
|
|
84
88
|
|
|
85
|
-
| Action
|
|
86
|
-
|
|
|
87
|
-
| `init`
|
|
88
|
-
| `plan`
|
|
89
|
-
| `replan`
|
|
90
|
-
| `implement` | 计划已经明确,开始真正落地
|
|
91
|
-
| `patch`
|
|
92
|
-
| `rush`
|
|
93
|
-
| `done`
|
|
89
|
+
| Action | 何时使用 | 当前状态要求 | 结果 |
|
|
90
|
+
| ----------- | ------------------------------------------------ | ----------------------------- | ------------------------------------------------------- |
|
|
91
|
+
| `init` | 项目还没建立好协作约定,或者 `AGENTS.md` 不完整 | 无 | 生成或补全 `AGENTS.md`,新项目可继续进入计划 |
|
|
92
|
+
| `plan` | 新需求需要正式拆分步骤 | 当前没有冲突中的已执行计划 | 创建 `plan.md`,必要时拆成当前计划 + preparing 队列 |
|
|
93
|
+
| `replan` | 计划还没实施,但拆分方式或技术路线要改 | 目标计划必须仍是 `未执行` | 重写计划结构,保留单当前计划模型 |
|
|
94
|
+
| `implement` | 计划已经明确,开始真正落地 | 当前计划存在且状态为 `未执行` | 实施全部步骤,验证通过后把计划改为 `已执行` |
|
|
95
|
+
| `patch` | 已执行计划上出现 Bug、遗漏项或增量需求 | 当前计划必须是 `已执行` | 执行修补,生成 `patch-{N}.md`,更新影响范围 |
|
|
96
|
+
| `rush` | 任务范围很清晰,不想先单独经历 plan 再 implement | 当前不能存在未实施计划 | 直接创建单计划并立刻实施 |
|
|
97
|
+
| `done` | 当前计划已经真正完成,需要收尾归档 | 当前计划必须是 `已执行` | 把当前计划移入 `done/`,必要时晋升下一个 preparing 计划 |
|
|
94
98
|
|
|
95
99
|
### `init`
|
|
96
100
|
|
|
@@ -235,10 +239,42 @@ rush 一下,把 README 里的命令表更新为最新版本
|
|
|
235
239
|
|
|
236
240
|
`rush` 很适合这种“知道要改什么,也知道验收标准”的任务,但不适合目标模糊的大需求。
|
|
237
241
|
|
|
242
|
+
## 多人协作
|
|
243
|
+
|
|
244
|
+
`agent-context` 通过 SCOPE 机制支持多人在同一项目中独立管理计划:
|
|
245
|
+
|
|
246
|
+
- 每位协作者拥有独立的作用域目录(`{scope}/`),互不干扰
|
|
247
|
+
- SCOPE 名称自动取自 git 配置的 `user.name`
|
|
248
|
+
- 计划编号在各 SCOPE 内独立递增
|
|
249
|
+
- 首次使用时运行 `agent-context init` 初始化作用域
|
|
250
|
+
|
|
251
|
+
```text
|
|
252
|
+
.agent-context/
|
|
253
|
+
├── alice/ # Alice 的计划
|
|
254
|
+
│ ├── index.md
|
|
255
|
+
│ ├── plan-1/
|
|
256
|
+
│ └── done/
|
|
257
|
+
├── bob/ # Bob 的计划
|
|
258
|
+
│ ├── index.md
|
|
259
|
+
│ ├── plan-3/
|
|
260
|
+
│ └── done/
|
|
261
|
+
└── .env # 当前用户的 SCOPE
|
|
262
|
+
```
|
|
263
|
+
|
|
238
264
|
## CLI 命令参考
|
|
239
265
|
|
|
240
266
|
CLI 只负责文件安装、同步和状态管理,不负责替代 action。
|
|
241
267
|
|
|
268
|
+
### `agent-context init`
|
|
269
|
+
|
|
270
|
+
初始化作用域。首次在项目中使用时运行,会自动检测 git `user.name` 作为 SCOPE 名称,并创建必要的目录结构。
|
|
271
|
+
|
|
272
|
+
```bash
|
|
273
|
+
agent-context init
|
|
274
|
+
agent-context init --scope alice
|
|
275
|
+
agent-context init --yes
|
|
276
|
+
```
|
|
277
|
+
|
|
242
278
|
### `agent-context install`
|
|
243
279
|
|
|
244
280
|
安装 Skill 文件。
|
|
@@ -289,22 +325,33 @@ agent-context done
|
|
|
289
325
|
agent-context done --yes
|
|
290
326
|
```
|
|
291
327
|
|
|
328
|
+
### `agent-context index`
|
|
329
|
+
|
|
330
|
+
生成或更新当前 SCOPE 的计划索引文件 `.agent-context/{scope}/index.md`。索引按 done、当前计划、preparing 分类,每项为 `- [x/ ] [标题](相对路径)` 格式。
|
|
331
|
+
|
|
332
|
+
归档计划时(`done`)会自动调用,也可手动运行:
|
|
333
|
+
|
|
334
|
+
```bash
|
|
335
|
+
agent-context index
|
|
336
|
+
```
|
|
337
|
+
|
|
292
338
|
## 通用选项
|
|
293
339
|
|
|
294
|
-
| 选项
|
|
295
|
-
|
|
|
296
|
-
| `--tools <tools>` | `install` / `sync`
|
|
297
|
-
| `--check`
|
|
298
|
-
| `--yes`
|
|
340
|
+
| 选项 | 适用命令 | 说明 |
|
|
341
|
+
| ----------------- | --------------------------- | -------------------------------------------- |
|
|
342
|
+
| `--tools <tools>` | `install` / `sync` | 指定目标工具,逗号分隔 |
|
|
343
|
+
| `--check` | `install` / `sync` | 只检查是否有变更,不写文件 |
|
|
344
|
+
| `--yes` | `install` / `init` / `done` | 跳过交互确认;`install` 会优先复用已安装工具 |
|
|
345
|
+
| `--scope <name>` | `init` | 手动指定 SCOPE 名称,不使用 git user.name |
|
|
299
346
|
|
|
300
347
|
## 支持的工具
|
|
301
348
|
|
|
302
|
-
| 工具
|
|
303
|
-
|
|
|
304
|
-
| Claude
|
|
305
|
-
| Codex
|
|
306
|
-
| Cursor
|
|
307
|
-
| Antigravity
|
|
349
|
+
| 工具 | Skill 目录 |
|
|
350
|
+
| -------------- | ------------------------------- |
|
|
351
|
+
| Claude | `.claude/skills/agent-context/` |
|
|
352
|
+
| Codex | `.codex/skills/agent-context/` |
|
|
353
|
+
| Cursor | `.cursor/skills/agent-context/` |
|
|
354
|
+
| Antigravity | `.agent/skills/agent-context/` |
|
|
308
355
|
| GitHub Copilot | `.github/skills/agent-context/` |
|
|
309
356
|
|
|
310
357
|
其中 Codex 会额外生成 `agents/openai.yaml` 元数据文件,其余工具只生成 Skill 内容本身。
|
package/dist/cli.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{doneCommand as e}from"./commands/done.js";import{
|
|
2
|
+
import{doneCommand as e}from"./commands/done.js";import{indexCommand as t}from"./commands/index-cmd.js";import{initCommand as n}from"./commands/init.js";import{installCommand as r}from"./commands/install.js";import{statusCommand as i}from"./commands/status.js";import{syncCommand as a}from"./commands/sync.js";import{validateCommand as o}from"./commands/validate.js";import{readFileSync as s}from"node:fs";import{Command as c}from"commander";const l=JSON.parse(s(new URL(`../package.json`,import.meta.url),`utf8`)),u=typeof l.version==`string`?l.version:`0.0.0`,d=new c;d.name(`agent-context`).description(`Agent Context Skills 安装工具`).version(u),d.command(`install`).description(`安装 ac-workflow Skill`).option(`--tools <tools>`,`指定目标工具,逗号分隔:claude,codex,cursor,antigravity,copilot`).option(`--yes`,`非交互模式:优先复用已安装工具,否则安装全部工具`).option(`--check`,`仅检查是否存在待更新内容,不写入文件`).action(r),d.command(`sync`).description(`同步已安装的 ac-workflow Skill`).option(`--tools <tools>`,`指定目标工具,逗号分隔:claude,codex,cursor,antigravity,copilot`).option(`--check`,`仅检查是否存在待更新内容,不写入文件`).action(a),d.command(`init`).description(`初始化 SCOPE(从 git user.name 自动获取或手动指定)`).option(`--scope <name>`,`手动指定 SCOPE 名称`).option(`--yes`,`非交互模式:自动覆盖已存在的 SCOPE`).action(n),d.command(`validate`).description(`校验 .agent-context 目录结构`).action(o),d.command(`status`).description(`查看当前 agent-context 状态`).action(i),d.command(`done`).description(`归档当前已执行计划`).option(`--yes`,`跳过确认,直接归档`).action(e),d.command(`index`).description(`生成或更新计划索引文件`).action(t),d.parseAsync().catch(e=>{let t=e instanceof Error?e.message:String(e);console.error(`\n❌ ${t}`),process.exitCode=1});export{};
|
package/dist/commands/done.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{readRawContext as
|
|
1
|
+
import{readContext as e,readRawContext as t}from"../context/reader.js";import{validate as n}from"../context/validator.js";import{archive as r}from"../context/archiver.js";import{generateIndex as i}from"../context/indexer.js";import{basename as a}from"node:path";import{confirm as o}from"@inquirer/prompts";async function s(s){let{snapshot:c,currentPlanCount:l}=await t(process.cwd()),u=n(c,l);if(!u.valid){for(let e of u.errors)console.log(`❌ ${e}`);process.exitCode=1;return}if(!c||!c.currentPlan){console.log(`❌ 无当前计划`),process.exitCode=1;return}if(c.currentPlan.status!==`已执行`){console.log(`❌ 当前计划 plan-${c.currentPlan.number} 尚未执行,无法归档。`),process.exitCode=1;return}if(!s.yes&&!await o({message:`确认归档 plan-${c.currentPlan.number}?`})){console.log(`已取消`);return}let d=await r(c),f=a(d.archivedTo);console.log(`✅ 已归档: plan-${c.currentPlan.number} → done/${f}`),d.promoted!==null&&console.log(`📋 已晋升: plan-${d.promoted} 为新的当前计划`),d.remainingPreparing>0?console.log(`📋 待执行队列剩余 ${d.remainingPreparing} 个计划`):d.promoted===null&&console.log(`ℹ 无更多待执行计划`);let p=await e(process.cwd());p&&(await i(p),console.log(`📇 已更新索引`))}export{s as doneCommand};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{readRawContext as e}from"../context/reader.js";import{validate as t}from"../context/validator.js";import{generateIndex as n}from"../context/indexer.js";import{relative as r}from"node:path";async function i(){let i=process.cwd(),{snapshot:a,currentPlanCount:o}=await e(i),s=t(a,o);if(!s.valid){for(let e of s.errors)console.log(`❌ ${e}`);process.exitCode=1;return}if(!a){console.log(`❌ 未找到 .agent-context 目录`),process.exitCode=1;return}let c=await n(a);console.log(`✅ 已生成索引: ${r(i,c.path)}(${c.entries} 个计划)`)}export{i as indexCommand};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{initScope as e}from"../context/scope.js";import{existsSync as t}from"node:fs";import{join as n}from"node:path";import{confirm as r}from"@inquirer/prompts";import{mkdir as i,readFile as a}from"node:fs/promises";async function o(o={}){let s=n(process.cwd(),`.agent-context`);await i(s,{recursive:!0});let c=n(s,`.env`);if(t(c)){let e=(await a(c,`utf-8`)).match(/^SCOPE=(.+)$/m)?.[1]?.trim();if(e&&(console.log(`当前 SCOPE: ${e}`),!o.yes&&!await r({message:`是否覆盖当前 SCOPE?`}))){console.log(`已取消`);return}}let l=await e(s,o.scope);console.log(`✅ SCOPE 已设置: ${l}`),console.log(` 目录: .agent-context/${l}/`)}export{o as initCommand};
|
package/dist/commands/install.js
CHANGED
|
@@ -1 +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
|
|
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,check:r,...n?{tools:n}:{}});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};
|
package/dist/commands/status.js
CHANGED
|
@@ -1 +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};
|
|
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(`当前作用域: ${a.scope}`),console.log(`当前计划: ${o}`),console.log(`待执行队列: ${s}`),console.log(`已归档: ${a.done.length} 个`)}export{n as statusCommand};
|
package/dist/commands/sync.js
CHANGED
|
@@ -1 +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
|
|
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,check:s,...a?{tools:a}:{}});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 +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
|
|
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;console.log(` 当前作用域: ${e.scope}`);let 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};
|
package/dist/content/actions.js
CHANGED
|
@@ -4,6 +4,13 @@ const e=[`init`,`plan`,`replan`,`implement`,`patch`,`rush`],t={init:n,plan:r,rep
|
|
|
4
4
|
|
|
5
5
|
可附带描述参数,用于补充项目背景、技术栈、特殊约束。
|
|
6
6
|
|
|
7
|
+
## 前置检查
|
|
8
|
+
|
|
9
|
+
- 若已存在 \`.agent-context/\`:运行 \`agent-context validate\`,不通过则中止并报告错误。
|
|
10
|
+
- 若 \`.agent-context/\` 不存在:确认这是首次初始化场景;若目录残缺或状态异常,向用户报告,不可继续假设。
|
|
11
|
+
- 新项目缺少关键决策信息时,必须主动提问或确认,不可直接生成 \`AGENTS.md\` 或进入 plan。
|
|
12
|
+
- 遇到阻塞问题应向用户报告,不可静默跳过。
|
|
13
|
+
|
|
7
14
|
## 执行步骤
|
|
8
15
|
|
|
9
16
|
1. **判断项目类型**:检测根目录是否存在有效代码文件和目录结构。
|
|
@@ -13,11 +20,16 @@ const e=[`init`,`plan`,`replan`,`implement`,`patch`,`rush`],t={init:n,plan:r,rep
|
|
|
13
20
|
|
|
14
21
|
2. **处理 AGENTS.md**:
|
|
15
22
|
- 新项目:
|
|
16
|
-
1.
|
|
17
|
-
|
|
18
|
-
|
|
23
|
+
1. 先收集或确认以下信息,其中前两类属于**必须主动确认**的决策项,即使描述已部分涵盖也不能整体跳过;可基于描述用确认式问题补问,而不是完全重问。
|
|
24
|
+
- 必须主动确认:技术栈与版本(语言、运行时、框架、构建/测试工具等)
|
|
25
|
+
- 必须主动确认:架构偏好(目录结构、分层模式、关键框架或方案选型)
|
|
26
|
+
- 可基于描述补充:项目目标与核心功能
|
|
27
|
+
- 可基于描述补充:代码规范与工具链细节(lint、formatter、测试约定等)
|
|
28
|
+
2. 对高价值决策类问题必须在计划前澄清,例如:是否使用 monorepo、前后端如何拆分、采用哪个框架与测试工具。
|
|
29
|
+
3. 生成高质量 \`AGENTS.md\`(须满足下方质量标准,不满足则重新优化直至满足)。
|
|
30
|
+
4. 继续执行 plan 创建初始计划。
|
|
19
31
|
- 旧项目:
|
|
20
|
-
1. 若不存在 \`AGENTS.md
|
|
32
|
+
1. 若不存在 \`AGENTS.md\`:优先通过代码与配置读取收集信息;仅对无法可靠判断的内容提问后生成。
|
|
21
33
|
2. 若已存在 \`AGENTS.md\`:按质量标准评估,不足时增补优化。
|
|
22
34
|
3. 默认不创建计划(除非用户明确要求)。
|
|
23
35
|
|
|
@@ -33,7 +45,7 @@ const e=[`init`,`plan`,`replan`,`implement`,`patch`,`rush`],t={init:n,plan:r,rep
|
|
|
33
45
|
- 大型单体仓库按子包拆分维护本地 \`AGENTS.md\`。
|
|
34
46
|
`}function r(){return`# plan
|
|
35
47
|
|
|
36
|
-
创建新的执行计划,写入 \`.agent-context/plan-{number}/plan.md\`。按复杂度可拆分为多个计划,维护「单当前计划 + preparing 队列」结构。
|
|
48
|
+
创建新的执行计划,写入 \`.agent-context/{scope}/plan-{number}/plan.md\`。按复杂度可拆分为多个计划,维护「单当前计划 + preparing 队列」结构。
|
|
37
49
|
|
|
38
50
|
必须附带计划描述。
|
|
39
51
|
|
|
@@ -53,7 +65,7 @@ const e=[`init`,`plan`,`replan`,`implement`,`patch`,`rush`],t={init:n,plan:r,rep
|
|
|
53
65
|
- 存在显著不同的技术路径需用户决策。
|
|
54
66
|
- 验收标准不明确:无法判断何时算"完成"。
|
|
55
67
|
2. 按复杂度决定单计划或多计划拆分。
|
|
56
|
-
3. 多计划拆分时:最小编号进入 \`.agent-context/\` 作为当前计划,其余进入 \`.agent-context/preparing/\`。单计划直接创建。
|
|
68
|
+
3. 多计划拆分时:最小编号进入 \`.agent-context/{scope}/\` 作为当前计划,其余进入 \`.agent-context/{scope}/preparing/\`。单计划直接创建。
|
|
57
69
|
4. 每个计划创建 \`plan.md\`,遵循下方模板。
|
|
58
70
|
5. **自检**(不通过则修改后重新检查):
|
|
59
71
|
- 每个步骤可独立执行且有明确完成标准。
|
|
@@ -100,9 +112,9 @@ const e=[`init`,`plan`,`replan`,`implement`,`patch`,`rush`],t={init:n,plan:r,rep
|
|
|
100
112
|
|
|
101
113
|
## 作用域
|
|
102
114
|
|
|
103
|
-
- 默认作用域:\`.agent-context/preparing/\` 中全部未实施计划。
|
|
115
|
+
- 默认作用域:\`.agent-context/{scope}/preparing/\` 中全部未实施计划。
|
|
104
116
|
- 可通过描述指定仅重规划部分计划(如"重规划 plan-3 和 plan-5")。
|
|
105
|
-
- 当前计划为 \`已执行\` → 禁止重写,仅允许重规划 \`preparing/\` 队列。
|
|
117
|
+
- 当前计划为 \`已执行\` → 禁止重写,仅允许重规划 \`{scope}/preparing/\` 队列。
|
|
106
118
|
- 当前计划为 \`未执行\` 且用户明确要求 → 可纳入重规划范围。
|
|
107
119
|
|
|
108
120
|
## 执行步骤
|
|
@@ -112,7 +124,7 @@ const e=[`init`,`plan`,`replan`,`implement`,`patch`,`rush`],t={init:n,plan:r,rep
|
|
|
112
124
|
3. 生成新的拆分方案,保持「单当前计划 + 若干 preparing 计划」结构。
|
|
113
125
|
4. 新增计划编号:全局 max(N)+1 递增分配;未改动计划保持原编号。
|
|
114
126
|
5. 更新目录结构,确保每个新计划的 \`plan.md\` 遵循标准模板。
|
|
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
|
|
127
|
+
`}function a(){return"# implement\n\n实施当前计划 `.agent-context/{scope}/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
|
|
116
128
|
|
|
117
129
|
基于当前已执行计划创建增量补丁,修复问题或追加变更。
|
|
118
130
|
|
|
@@ -125,13 +137,16 @@ const e=[`init`,`plan`,`replan`,`implement`,`patch`,`rush`],t={init:n,plan:r,rep
|
|
|
125
137
|
- 当前计划不存在 → 拒绝执行,提示先创建计划。
|
|
126
138
|
- 当前计划状态为 \`未执行\` → 拒绝执行,提示先实施。
|
|
127
139
|
- 存在多个当前计划 → 拒绝执行,提示恢复单活跃状态。
|
|
140
|
+
- 补丁需求与当前计划完全无关 → 拒绝执行,提示先运行 \`agent-context done\` 归档后再创建新计划。
|
|
128
141
|
- 补丁不改变计划状态,完成后保持 \`已执行\`。
|
|
129
142
|
|
|
130
143
|
## 执行步骤
|
|
131
144
|
|
|
132
145
|
1. 阅读 \`plan.md\` 与已有 \`patch-{number}.md\`,了解上下文与历史,避免重复修复。
|
|
133
146
|
2. 根据描述执行补丁所需的代码变更。
|
|
134
|
-
3.
|
|
147
|
+
3. 完成验证:
|
|
148
|
+
- **IF** (编码任务) **THEN**:运行相关测试,以及必要的 Lint/Typecheck。
|
|
149
|
+
- **ELSE IF** (非编码任务,如纯文档修改) **THEN**:仅凭逻辑与排版审阅确认验收通过。
|
|
135
150
|
4. 创建 \`patch-{number}.md\`(编号:扫描当前计划目录已有补丁取 max+1),遵循下方模板。
|
|
136
151
|
5. 回写 \`plan.md\`:
|
|
137
152
|
- \`## 历史补丁\`:追加 \`- patch-{number}: {补丁名称}\`,按编号去重。
|
|
@@ -162,6 +177,7 @@ const e=[`init`,`plan`,`replan`,`implement`,`patch`,`rush`],t={init:n,plan:r,rep
|
|
|
162
177
|
|
|
163
178
|
- 运行 \`agent-context validate\`,不通过则中止并报告错误。
|
|
164
179
|
- 描述为空 → 拒绝执行。
|
|
180
|
+
- 描述仍存在范围边界、技术路径或验收标准歧义 → 拒绝执行,提示改用 \`plan\`。
|
|
165
181
|
- 存在未归档的已执行当前计划 → 判断新需求与当前计划的关联性:
|
|
166
182
|
- 相关联或用户本意是修补 → 拒绝执行,提示改用 patch。
|
|
167
183
|
- 完全无关 → 拒绝执行,提示先运行 \`agent-context done\` 归档后再创建新计划。
|
|
@@ -173,7 +189,7 @@ const e=[`init`,`plan`,`replan`,`implement`,`patch`,`rush`],t={init:n,plan:r,rep
|
|
|
173
189
|
|
|
174
190
|
### 阶段一:plan(差异)
|
|
175
191
|
|
|
176
|
-
-
|
|
192
|
+
- 仅在描述本身已足够明确时跳过「需求澄清」步骤;否则不得继续 rush。
|
|
177
193
|
- 强制单计划,不拆分,不进入 preparing 队列。
|
|
178
194
|
- 完成 plan 后**不等待用户确认**,直接进入阶段二。
|
|
179
195
|
|
package/dist/content/index.js
CHANGED
|
@@ -6,7 +6,7 @@ import{ACTION_NAMES as e,ACTION_RENDERERS as t}from"./actions.js";function n(n){
|
|
|
6
6
|
## 执行纪律
|
|
7
7
|
|
|
8
8
|
- **协议先行**:匹配到动作后,必须先读取对应 \`actions/*.md\` 协议文件的完整内容,再逐步执行。禁止凭记忆、摘要或猜测跳过协议步骤。
|
|
9
|
-
- **前置检查必做**:所有动作(done
|
|
9
|
+
- **前置检查必做**:所有动作(done 除外)均包含「前置检查」,必须逐条执行,不可跳过。凡协议写明需运行 \`agent-context validate\` 时必须执行;\`init\` 在首次初始化且 \`.agent-context/\` 尚不存在时,先确认初始化场景成立,再按协议继续。
|
|
10
10
|
- **禁止直接改动**:在 plan / rush 创建计划之前,不得直接修改项目代码文件。任何代码变更必须在已创建计划(implement)或已创建补丁(patch)的上下文中进行。
|
|
11
11
|
- **顺序执行**:协议步骤必须按编号顺序逐项执行,不可跳步、合并或并行。
|
|
12
12
|
|
|
@@ -29,7 +29,7 @@ import{ACTION_NAMES as e,ACTION_RENDERERS as t}from"./actions.js";function n(n){
|
|
|
29
29
|
## 全局约束
|
|
30
30
|
|
|
31
31
|
- 状态机两态:\`未执行\`、\`已执行\`。
|
|
32
|
-
- 任意时刻最多一个当前计划:\`.agent-context/plan-{number}\`。
|
|
32
|
+
- 任意时刻最多一个当前计划:\`.agent-context/{scope}/plan-{number}\`。
|
|
33
33
|
- 多个当前计划 → 拒绝执行,提示恢复单活跃状态。
|
|
34
34
|
- 计划编号全局递增,不复用。补丁编号在单计划目录内递增,不复用。
|
|
35
35
|
- 影响范围(\`## 影响范围\`)不得包含 \`.agent-context/\` 目录下的文件。
|
|
@@ -38,17 +38,20 @@ import{ACTION_NAMES as e,ACTION_RENDERERS as t}from"./actions.js";function n(n){
|
|
|
38
38
|
|
|
39
39
|
\`\`\`text
|
|
40
40
|
.agent-context/
|
|
41
|
-
├──
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
├──
|
|
45
|
-
│
|
|
46
|
-
└──
|
|
47
|
-
|
|
41
|
+
├── .env # SCOPE 配置(SCOPE=<name>)
|
|
42
|
+
├── .gitignore
|
|
43
|
+
└── {scope}/ # 作用域目录(按协作者隔离)
|
|
44
|
+
├── plan-{N}/ # 当前计划(最多一个)
|
|
45
|
+
│ ├── plan.md
|
|
46
|
+
│ └── patch-{N}.md
|
|
47
|
+
├── preparing/ # 待执行计划队列
|
|
48
|
+
│ └── plan-{N}/
|
|
49
|
+
└── done/ # 已归档计划
|
|
50
|
+
└── plan-{N}-{YYYYMMDD}/
|
|
48
51
|
\`\`\`
|
|
49
52
|
|
|
50
|
-
|
|
51
|
-
`}function i(e){let t=[`---`,`name: ac-workflow`,`description: 管理 .agent-context 计划生命周期,按 init、plan、replan、implement、patch、rush、done 协议推进任务。`];return e.frontmatterProfile
|
|
53
|
+
编号规则:在当前 scope 内扫描全部 \`plan-N\` 目录取 \`max(N)+1\`。
|
|
54
|
+
`}function i(e){let t=[`---`,`name: ac-workflow`,`description: 管理 .agent-context 计划生命周期,按 init、plan、replan、implement、patch、rush、done 协议推进任务。`];return e.frontmatterProfile!==`copilot`&&t.push(`argument-hint: [request]`),e.frontmatterProfile===`copilot`&&t.push(`license: MIT`),t.push(`---`,``),`${t.join(`
|
|
52
55
|
`)}\n`}function a(){return`interface:
|
|
53
56
|
display_name: "Agent Context Workflow"
|
|
54
57
|
short_description: "统一管理 .agent-context 计划生命周期"
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import{existsSync as e}from"node:fs";import{join as t,relative as n}from"node:path";import{readFile as r,writeFile as i}from"node:fs/promises";const a=/^#\s+(.+)$/m;async function o(e){let r=[];for(let t of e.done){let i=await s(t.dir),a=`./${n(e.root,t.dir)}/plan.md`;r.push(`- [x] [${i}](${a})`)}if(e.currentPlan){let t=await s(e.currentPlan.dir),i=`./${n(e.root,e.currentPlan.dir)}/plan.md`,a=e.currentPlan.status===`已执行`?`x`:` `;r.push(`- [${a}] [${t}](${i})`)}for(let t of e.preparing){let i=await s(t.dir),a=`./${n(e.root,t.dir)}/plan.md`;r.push(`- [ ] [${i}](${a})`)}let a=t(e.root,`index.md`);return await i(a,r.join(`
|
|
2
|
+
`)+`
|
|
3
|
+
`,`utf-8`),{path:a,entries:r.length}}async function s(n){let i=t(n,`plan.md`);return e(i)?(await r(i,`utf-8`)).match(a)?.[1]?.trim()??`plan-${n.split(`/`).pop()??`unknown`}`:`plan-${n.split(`/`).pop()??`unknown`}`}export{o as generateIndex};
|
package/dist/context/reader.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{resolveScope as e}from"./scope.js";import{existsSync as t}from"node:fs";import{join as n}from"node:path";import{readFile as r,readdir as i}from"node:fs/promises";const a=/^plan-(\d+)$/,o=/^plan-(\d+)(?:-\d{8})?$/,s=/^>\s*状态:\s*(未执行|已执行)$/m,c=/^>?[ \t]*状态[::].*$/m;async function l(e){let{snapshot:t}=await u(e);return t}async function u(r){let i=n(r,`.agent-context`);if(!t(i))return{snapshot:null,currentPlanCount:0};let a=await e(i),o=n(i,a),s=await f(o),c=await f(n(o,`preparing`)),l=await p(n(o,`done`));return{snapshot:{root:o,scope:a,currentPlan:s[0]??null,preparing:c,done:l},currentPlanCount:s.length}}async function d(e){let i=n(e,`plan.md`);if(!t(i))return`未执行`;let a=await r(i,`utf-8`),o=a.match(s);return o?o[1]:c.test(a)?`未知`:`未执行`}async function f(e){if(!t(e))return[];let r=await i(e,{withFileTypes:!0}),o=[];for(let t of r){if(!t.isDirectory())continue;let r=t.name.match(a);if(!r?.[1])continue;let i=parseInt(r[1],10),s=n(e,t.name),c=await d(s);o.push({number:i,status:c,dir:s})}return o.sort((e,t)=>e.number-t.number)}async function p(e){if(!t(e))return[];let r=await i(e,{withFileTypes:!0}),a=[];for(let t of r){if(!t.isDirectory())continue;let r=t.name.match(o);r?.[1]&&a.push({number:parseInt(r[1],10),dir:n(e,t.name)})}return a.sort((e,t)=>e.number-t.number)}export{l as readContext,u as readRawContext};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import{existsSync as e}from"node:fs";import{join as t}from"node:path";import{mkdir as n,readFile as r,writeFile as i}from"node:fs/promises";import{execSync as a}from"node:child_process";async function o(n){let i=t(n,`.env`);if(e(i)){let e=(await r(i,`utf-8`)).match(/^SCOPE=(.+)$/m);if(e?.[1])return e[1].trim()}return s(n)}async function s(e,r){let o;if(r)o=c(r);else{let e;try{e=a(`git config user.name`,{encoding:`utf-8`}).trim()}catch{throw Error(`未找到 git user.name,请先运行 git config user.name <name>`)}if(!e)throw Error(`未找到 git user.name,请先运行 git config user.name <name>`);o=c(e)}return await i(t(e,`.env`),`SCOPE=${o}\n`,`utf-8`),await l(e),await n(t(e,o),{recursive:!0}),o}function c(e){return e.toLowerCase().replace(/[^a-z0-9]/g,`-`).replace(/^-+|-+$/g,``).replace(/-{2,}/g,`-`)}async function l(n){let a=t(n,`.gitignore`);if(e(a)){let e=await r(a,`utf-8`);e.split(`
|
|
2
|
+
`).some(e=>e.trim()===`.env`)||await i(a,e.trimEnd()+`
|
|
3
|
+
.env
|
|
4
|
+
`,`utf-8`)}else await i(a,`.env
|
|
5
|
+
`,`utf-8`)}export{s as initScope,o as resolveScope};
|
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":"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}};
|
|
4933
|
+
const data = {"version":2,"tree":{"name":"root","children":[{"name":"cli.d.ts","children":[{"name":"Users/whj/Codes/cat-kit/packages/agent-context/src/cli.d.ts","uid":"2800e162-1"}]},{"name":"cli.js","children":[{"name":"Users/whj/Codes/cat-kit/packages/agent-context/src/cli.ts","uid":"2800e162-3"}]},{"name":"commands/done.js","children":[{"name":"Users/whj/Codes/cat-kit/packages/agent-context/src/commands/done.ts","uid":"2800e162-5"}]},{"name":"commands/index-cmd.js","children":[{"name":"Users/whj/Codes/cat-kit/packages/agent-context/src/commands/index-cmd.ts","uid":"2800e162-7"}]},{"name":"commands/init.js","children":[{"name":"Users/whj/Codes/cat-kit/packages/agent-context/src/commands/init.ts","uid":"2800e162-9"}]},{"name":"commands/install.js","children":[{"name":"Users/whj/Codes/cat-kit/packages/agent-context/src/commands/install.ts","uid":"2800e162-11"}]},{"name":"commands/printer.js","children":[{"name":"Users/whj/Codes/cat-kit/packages/agent-context/src/commands/printer.ts","uid":"2800e162-13"}]},{"name":"commands/status.js","children":[{"name":"Users/whj/Codes/cat-kit/packages/agent-context/src/commands/status.ts","uid":"2800e162-15"}]},{"name":"commands/sync.js","children":[{"name":"Users/whj/Codes/cat-kit/packages/agent-context/src/commands/sync.ts","uid":"2800e162-17"}]},{"name":"commands/validate.js","children":[{"name":"Users/whj/Codes/cat-kit/packages/agent-context/src/commands/validate.ts","uid":"2800e162-19"}]},{"name":"content/actions.js","children":[{"name":"Users/whj/Codes/cat-kit/packages/agent-context/src/content/actions.ts","uid":"2800e162-21"}]},{"name":"content/index.js","children":[{"name":"Users/whj/Codes/cat-kit/packages/agent-context/src/content/index.ts","uid":"2800e162-23"}]},{"name":"context/archiver.js","children":[{"name":"Users/whj/Codes/cat-kit/packages/agent-context/src/context/archiver.ts","uid":"2800e162-25"}]},{"name":"context/indexer.js","children":[{"name":"Users/whj/Codes/cat-kit/packages/agent-context/src/context/indexer.ts","uid":"2800e162-27"}]},{"name":"context/reader.js","children":[{"name":"Users/whj/Codes/cat-kit/packages/agent-context/src/context/reader.ts","uid":"2800e162-29"}]},{"name":"context/scope.js","children":[{"name":"Users/whj/Codes/cat-kit/packages/agent-context/src/context/scope.ts","uid":"2800e162-31"}]},{"name":"context/validator.js","children":[{"name":"Users/whj/Codes/cat-kit/packages/agent-context/src/context/validator.ts","uid":"2800e162-33"}]},{"name":"runner.js","children":[{"name":"Users/whj/Codes/cat-kit/packages/agent-context/src/runner.ts","uid":"2800e162-35"}]},{"name":"tools.js","children":[{"name":"Users/whj/Codes/cat-kit/packages/agent-context/src/tools.ts","uid":"2800e162-37"}]}],"isRoot":true},"nodeParts":{"2800e162-1":{"renderedLength":0,"gzipLength":0,"brotliLength":0,"metaUid":"2800e162-0"},"2800e162-3":{"renderedLength":1863,"gzipLength":0,"brotliLength":0,"metaUid":"2800e162-2"},"2800e162-5":{"renderedLength":1508,"gzipLength":0,"brotliLength":0,"metaUid":"2800e162-4"},"2800e162-7":{"renderedLength":629,"gzipLength":0,"brotliLength":0,"metaUid":"2800e162-6"},"2800e162-9":{"renderedLength":718,"gzipLength":0,"brotliLength":0,"metaUid":"2800e162-8"},"2800e162-11":{"renderedLength":1005,"gzipLength":0,"brotliLength":0,"metaUid":"2800e162-10"},"2800e162-13":{"renderedLength":909,"gzipLength":0,"brotliLength":0,"metaUid":"2800e162-12"},"2800e162-15":{"renderedLength":993,"gzipLength":0,"brotliLength":0,"metaUid":"2800e162-14"},"2800e162-17":{"renderedLength":765,"gzipLength":0,"brotliLength":0,"metaUid":"2800e162-16"},"2800e162-19":{"renderedLength":813,"gzipLength":0,"brotliLength":0,"metaUid":"2800e162-18"},"2800e162-21":{"renderedLength":11445,"gzipLength":0,"brotliLength":0,"metaUid":"2800e162-20"},"2800e162-23":{"renderedLength":4355,"gzipLength":0,"brotliLength":0,"metaUid":"2800e162-22"},"2800e162-25":{"renderedLength":1012,"gzipLength":0,"brotliLength":0,"metaUid":"2800e162-24"},"2800e162-27":{"renderedLength":1274,"gzipLength":0,"brotliLength":0,"metaUid":"2800e162-26"},"2800e162-29":{"renderedLength":2276,"gzipLength":0,"brotliLength":0,"metaUid":"2800e162-28"},"2800e162-31":{"renderedLength":1479,"gzipLength":0,"brotliLength":0,"metaUid":"2800e162-30"},"2800e162-33":{"renderedLength":1905,"gzipLength":0,"brotliLength":0,"metaUid":"2800e162-32"},"2800e162-35":{"renderedLength":2037,"gzipLength":0,"brotliLength":0,"metaUid":"2800e162-34"},"2800e162-37":{"renderedLength":2174,"gzipLength":0,"brotliLength":0,"metaUid":"2800e162-36"}},"nodeMetas":{"2800e162-0":{"id":"/Users/whj/Codes/cat-kit/packages/agent-context/src/cli.d.ts","moduleParts":{"cli.d.ts":"2800e162-1"},"imported":[],"importedBy":[],"isEntry":true},"2800e162-2":{"id":"/Users/whj/Codes/cat-kit/packages/agent-context/src/cli.ts","moduleParts":{"cli.js":"2800e162-3"},"imported":[{"uid":"2800e162-38"},{"uid":"2800e162-39"},{"uid":"2800e162-4"},{"uid":"2800e162-6"},{"uid":"2800e162-8"},{"uid":"2800e162-10"},{"uid":"2800e162-14"},{"uid":"2800e162-16"},{"uid":"2800e162-18"}],"importedBy":[],"isEntry":true},"2800e162-4":{"id":"/Users/whj/Codes/cat-kit/packages/agent-context/src/commands/done.ts","moduleParts":{"commands/done.js":"2800e162-5"},"imported":[{"uid":"2800e162-40"},{"uid":"2800e162-41"},{"uid":"2800e162-42"}],"importedBy":[{"uid":"2800e162-2"}]},"2800e162-6":{"id":"/Users/whj/Codes/cat-kit/packages/agent-context/src/commands/index-cmd.ts","moduleParts":{"commands/index-cmd.js":"2800e162-7"},"imported":[{"uid":"2800e162-40"},{"uid":"2800e162-42"}],"importedBy":[{"uid":"2800e162-2"}]},"2800e162-8":{"id":"/Users/whj/Codes/cat-kit/packages/agent-context/src/commands/init.ts","moduleParts":{"commands/init.js":"2800e162-9"},"imported":[{"uid":"2800e162-38"},{"uid":"2800e162-43"},{"uid":"2800e162-40"},{"uid":"2800e162-41"},{"uid":"2800e162-30"}],"importedBy":[{"uid":"2800e162-2"}]},"2800e162-10":{"id":"/Users/whj/Codes/cat-kit/packages/agent-context/src/commands/install.ts","moduleParts":{"commands/install.js":"2800e162-11"},"imported":[{"uid":"2800e162-41"},{"uid":"2800e162-34"},{"uid":"2800e162-36"},{"uid":"2800e162-12"}],"importedBy":[{"uid":"2800e162-2"}]},"2800e162-12":{"id":"/Users/whj/Codes/cat-kit/packages/agent-context/src/commands/printer.ts","moduleParts":{"commands/printer.js":"2800e162-13"},"imported":[{"uid":"2800e162-40"}],"importedBy":[{"uid":"2800e162-10"},{"uid":"2800e162-16"}]},"2800e162-14":{"id":"/Users/whj/Codes/cat-kit/packages/agent-context/src/commands/status.ts","moduleParts":{"commands/status.js":"2800e162-15"},"imported":[{"uid":"2800e162-42"}],"importedBy":[{"uid":"2800e162-2"}]},"2800e162-16":{"id":"/Users/whj/Codes/cat-kit/packages/agent-context/src/commands/sync.ts","moduleParts":{"commands/sync.js":"2800e162-17"},"imported":[{"uid":"2800e162-34"},{"uid":"2800e162-36"},{"uid":"2800e162-12"}],"importedBy":[{"uid":"2800e162-2"}]},"2800e162-18":{"id":"/Users/whj/Codes/cat-kit/packages/agent-context/src/commands/validate.ts","moduleParts":{"commands/validate.js":"2800e162-19"},"imported":[{"uid":"2800e162-42"}],"importedBy":[{"uid":"2800e162-2"}]},"2800e162-20":{"id":"/Users/whj/Codes/cat-kit/packages/agent-context/src/content/actions.ts","moduleParts":{"content/actions.js":"2800e162-21"},"imported":[],"importedBy":[{"uid":"2800e162-22"}]},"2800e162-22":{"id":"/Users/whj/Codes/cat-kit/packages/agent-context/src/content/index.ts","moduleParts":{"content/index.js":"2800e162-23"},"imported":[{"uid":"2800e162-20"}],"importedBy":[{"uid":"2800e162-34"}]},"2800e162-24":{"id":"/Users/whj/Codes/cat-kit/packages/agent-context/src/context/archiver.ts","moduleParts":{"context/archiver.js":"2800e162-25"},"imported":[{"uid":"2800e162-43"},{"uid":"2800e162-40"}],"importedBy":[{"uid":"2800e162-42"}]},"2800e162-26":{"id":"/Users/whj/Codes/cat-kit/packages/agent-context/src/context/indexer.ts","moduleParts":{"context/indexer.js":"2800e162-27"},"imported":[{"uid":"2800e162-38"},{"uid":"2800e162-43"},{"uid":"2800e162-40"}],"importedBy":[{"uid":"2800e162-42"}]},"2800e162-28":{"id":"/Users/whj/Codes/cat-kit/packages/agent-context/src/context/reader.ts","moduleParts":{"context/reader.js":"2800e162-29"},"imported":[{"uid":"2800e162-38"},{"uid":"2800e162-43"},{"uid":"2800e162-40"},{"uid":"2800e162-30"}],"importedBy":[{"uid":"2800e162-42"}]},"2800e162-30":{"id":"/Users/whj/Codes/cat-kit/packages/agent-context/src/context/scope.ts","moduleParts":{"context/scope.js":"2800e162-31"},"imported":[{"uid":"2800e162-44"},{"uid":"2800e162-38"},{"uid":"2800e162-43"},{"uid":"2800e162-40"}],"importedBy":[{"uid":"2800e162-8"},{"uid":"2800e162-42"},{"uid":"2800e162-28"}]},"2800e162-32":{"id":"/Users/whj/Codes/cat-kit/packages/agent-context/src/context/validator.ts","moduleParts":{"context/validator.js":"2800e162-33"},"imported":[{"uid":"2800e162-38"},{"uid":"2800e162-40"}],"importedBy":[{"uid":"2800e162-42"}]},"2800e162-34":{"id":"/Users/whj/Codes/cat-kit/packages/agent-context/src/runner.ts","moduleParts":{"runner.js":"2800e162-35"},"imported":[{"uid":"2800e162-38"},{"uid":"2800e162-43"},{"uid":"2800e162-40"},{"uid":"2800e162-22"},{"uid":"2800e162-36"}],"importedBy":[{"uid":"2800e162-10"},{"uid":"2800e162-16"}]},"2800e162-36":{"id":"/Users/whj/Codes/cat-kit/packages/agent-context/src/tools.ts","moduleParts":{"tools.js":"2800e162-37"},"imported":[{"uid":"2800e162-38"},{"uid":"2800e162-40"}],"importedBy":[{"uid":"2800e162-10"},{"uid":"2800e162-16"},{"uid":"2800e162-34"}]},"2800e162-38":{"id":"node:fs","moduleParts":{},"imported":[],"importedBy":[{"uid":"2800e162-2"},{"uid":"2800e162-8"},{"uid":"2800e162-30"},{"uid":"2800e162-34"},{"uid":"2800e162-36"},{"uid":"2800e162-28"},{"uid":"2800e162-32"},{"uid":"2800e162-26"}]},"2800e162-39":{"id":"commander","moduleParts":{},"imported":[],"importedBy":[{"uid":"2800e162-2"}]},"2800e162-40":{"id":"node:path","moduleParts":{},"imported":[],"importedBy":[{"uid":"2800e162-4"},{"uid":"2800e162-6"},{"uid":"2800e162-8"},{"uid":"2800e162-30"},{"uid":"2800e162-34"},{"uid":"2800e162-36"},{"uid":"2800e162-12"},{"uid":"2800e162-28"},{"uid":"2800e162-32"},{"uid":"2800e162-24"},{"uid":"2800e162-26"}]},"2800e162-41":{"id":"@inquirer/prompts","moduleParts":{},"imported":[],"importedBy":[{"uid":"2800e162-4"},{"uid":"2800e162-8"},{"uid":"2800e162-10"}]},"2800e162-42":{"id":"/Users/whj/Codes/cat-kit/packages/agent-context/src/context/index.ts","moduleParts":{},"imported":[{"uid":"2800e162-28"},{"uid":"2800e162-32"},{"uid":"2800e162-24"},{"uid":"2800e162-26"},{"uid":"2800e162-30"}],"importedBy":[{"uid":"2800e162-4"},{"uid":"2800e162-6"},{"uid":"2800e162-14"},{"uid":"2800e162-18"}]},"2800e162-43":{"id":"node:fs/promises","moduleParts":{},"imported":[],"importedBy":[{"uid":"2800e162-8"},{"uid":"2800e162-30"},{"uid":"2800e162-34"},{"uid":"2800e162-28"},{"uid":"2800e162-24"},{"uid":"2800e162-26"}]},"2800e162-44":{"id":"node:child_process","moduleParts":{},"imported":[],"importedBy":[{"uid":"2800e162-30"}]}},"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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cat-kit/agent-context",
|
|
3
|
-
"version": "1.1
|
|
3
|
+
"version": "1.2.1",
|
|
4
4
|
"description": "代理上下文管理工具",
|
|
5
5
|
"bin": {
|
|
6
6
|
"agent-context": "./dist/cli.js"
|
|
@@ -12,11 +12,11 @@
|
|
|
12
12
|
],
|
|
13
13
|
"type": "module",
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"@inquirer/prompts": "^8.3.
|
|
15
|
+
"@inquirer/prompts": "^8.3.2",
|
|
16
16
|
"commander": "^14.0.3"
|
|
17
17
|
},
|
|
18
18
|
"devDependencies": {
|
|
19
|
-
"@cat-kit/tsconfig": "
|
|
19
|
+
"@cat-kit/tsconfig": "2.0.0",
|
|
20
20
|
"@types/node": "^24.12.0"
|
|
21
21
|
}
|
|
22
22
|
}
|
package/src/cli.ts
CHANGED
|
@@ -5,6 +5,8 @@ import { readFileSync } from 'node:fs'
|
|
|
5
5
|
import { Command } from 'commander'
|
|
6
6
|
|
|
7
7
|
import { doneCommand } from './commands/done.js'
|
|
8
|
+
import { indexCommand } from './commands/index-cmd.js'
|
|
9
|
+
import { initCommand } from './commands/init.js'
|
|
8
10
|
import { installCommand } from './commands/install.js'
|
|
9
11
|
import { statusCommand } from './commands/status.js'
|
|
10
12
|
import { syncCommand } from './commands/sync.js'
|
|
@@ -34,6 +36,13 @@ program
|
|
|
34
36
|
.option('--check', '仅检查是否存在待更新内容,不写入文件')
|
|
35
37
|
.action(syncCommand)
|
|
36
38
|
|
|
39
|
+
program
|
|
40
|
+
.command('init')
|
|
41
|
+
.description('初始化 SCOPE(从 git user.name 自动获取或手动指定)')
|
|
42
|
+
.option('--scope <name>', '手动指定 SCOPE 名称')
|
|
43
|
+
.option('--yes', '非交互模式:自动覆盖已存在的 SCOPE')
|
|
44
|
+
.action(initCommand)
|
|
45
|
+
|
|
37
46
|
program.command('validate').description('校验 .agent-context 目录结构').action(validateCommand)
|
|
38
47
|
|
|
39
48
|
program.command('status').description('查看当前 agent-context 状态').action(statusCommand)
|
|
@@ -44,6 +53,8 @@ program
|
|
|
44
53
|
.option('--yes', '跳过确认,直接归档')
|
|
45
54
|
.action(doneCommand)
|
|
46
55
|
|
|
56
|
+
program.command('index').description('生成或更新计划索引文件').action(indexCommand)
|
|
57
|
+
|
|
47
58
|
program.parseAsync().catch((error: unknown) => {
|
|
48
59
|
const message = error instanceof Error ? error.message : String(error)
|
|
49
60
|
console.error(`\n❌ ${message}`) // eslint-disable-line no-console
|
package/src/commands/done.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { basename } from 'node:path'
|
|
|
2
2
|
|
|
3
3
|
import { confirm } from '@inquirer/prompts'
|
|
4
4
|
|
|
5
|
-
import { archive, readRawContext, validate } from '../context/index.js'
|
|
5
|
+
import { archive, generateIndex, readContext, readRawContext, validate } from '../context/index.js'
|
|
6
6
|
|
|
7
7
|
export async function doneCommand(options: { yes?: boolean }): Promise<void> {
|
|
8
8
|
const { snapshot, currentPlanCount } = await readRawContext(process.cwd())
|
|
@@ -50,4 +50,10 @@ export async function doneCommand(options: { yes?: boolean }): Promise<void> {
|
|
|
50
50
|
} else if (archiveResult.promoted === null) {
|
|
51
51
|
console.log('ℹ 无更多待执行计划') // eslint-disable-line no-console
|
|
52
52
|
}
|
|
53
|
+
|
|
54
|
+
const freshSnapshot = await readContext(process.cwd())
|
|
55
|
+
if (freshSnapshot) {
|
|
56
|
+
await generateIndex(freshSnapshot)
|
|
57
|
+
console.log('📇 已更新索引') // eslint-disable-line no-console
|
|
58
|
+
}
|
|
53
59
|
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { relative } from 'node:path'
|
|
2
|
+
|
|
3
|
+
import { readRawContext, validate, generateIndex } from '../context/index.js'
|
|
4
|
+
|
|
5
|
+
export async function indexCommand(): Promise<void> {
|
|
6
|
+
const cwd = process.cwd()
|
|
7
|
+
const { snapshot, currentPlanCount } = await readRawContext(cwd)
|
|
8
|
+
const result = validate(snapshot, currentPlanCount)
|
|
9
|
+
|
|
10
|
+
if (!result.valid) {
|
|
11
|
+
for (const error of result.errors) {
|
|
12
|
+
console.log(`❌ ${error}`) // eslint-disable-line no-console
|
|
13
|
+
}
|
|
14
|
+
process.exitCode = 1
|
|
15
|
+
return
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
if (!snapshot) {
|
|
19
|
+
console.log('❌ 未找到 .agent-context 目录') // eslint-disable-line no-console
|
|
20
|
+
process.exitCode = 1
|
|
21
|
+
return
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const indexResult = await generateIndex(snapshot)
|
|
25
|
+
console.log(`✅ 已生成索引: ${relative(cwd, indexResult.path)}(${indexResult.entries} 个计划)`) // eslint-disable-line no-console
|
|
26
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs'
|
|
2
|
+
import { readFile, mkdir } from 'node:fs/promises'
|
|
3
|
+
import { join } from 'node:path'
|
|
4
|
+
|
|
5
|
+
import { confirm } from '@inquirer/prompts'
|
|
6
|
+
|
|
7
|
+
import { initScope } from '../context/scope.js'
|
|
8
|
+
|
|
9
|
+
export interface InitCommandOptions {
|
|
10
|
+
scope?: string
|
|
11
|
+
yes?: boolean
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export async function initCommand(options: InitCommandOptions = {}): Promise<void> {
|
|
15
|
+
const cwd = process.cwd()
|
|
16
|
+
const acRoot = join(cwd, '.agent-context')
|
|
17
|
+
|
|
18
|
+
await mkdir(acRoot, { recursive: true })
|
|
19
|
+
|
|
20
|
+
const envPath = join(acRoot, '.env')
|
|
21
|
+
|
|
22
|
+
if (existsSync(envPath)) {
|
|
23
|
+
const content = await readFile(envPath, 'utf-8')
|
|
24
|
+
const match = content.match(/^SCOPE=(.+)$/m)
|
|
25
|
+
const existing = match?.[1]?.trim()
|
|
26
|
+
|
|
27
|
+
if (existing) {
|
|
28
|
+
console.log(`当前 SCOPE: ${existing}`) // eslint-disable-line no-console
|
|
29
|
+
|
|
30
|
+
if (!options.yes) {
|
|
31
|
+
const overwrite = await confirm({ message: '是否覆盖当前 SCOPE?' })
|
|
32
|
+
if (!overwrite) {
|
|
33
|
+
console.log('已取消') // eslint-disable-line no-console
|
|
34
|
+
return
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const scope = await initScope(acRoot, options.scope)
|
|
41
|
+
console.log(`✅ SCOPE 已设置: ${scope}`) // eslint-disable-line no-console
|
|
42
|
+
console.log(` 目录: .agent-context/${scope}/`) // eslint-disable-line no-console
|
|
43
|
+
}
|
package/src/commands/install.ts
CHANGED
|
@@ -20,7 +20,7 @@ export async function installCommand(options: InstallCommandOptions = {}): Promi
|
|
|
20
20
|
const cwd = process.cwd()
|
|
21
21
|
const tools = await resolveTools(cwd, options)
|
|
22
22
|
const check = options.check ?? false
|
|
23
|
-
const result = await runInstall({ cwd,
|
|
23
|
+
const result = await runInstall({ cwd, check, ...(tools ? { tools } : {}) })
|
|
24
24
|
|
|
25
25
|
if (check) {
|
|
26
26
|
printCheckResult(result, cwd)
|
package/src/commands/status.ts
CHANGED
|
@@ -27,6 +27,7 @@ export async function statusCommand(): Promise<void> {
|
|
|
27
27
|
console.log('')
|
|
28
28
|
console.log('Agent Context Status')
|
|
29
29
|
console.log('────────────────────')
|
|
30
|
+
console.log(`当前作用域: ${ctx.scope}`)
|
|
30
31
|
console.log(`当前计划: ${current}`)
|
|
31
32
|
console.log(`待执行队列: ${preparing}`)
|
|
32
33
|
console.log(`已归档: ${ctx.done.length} 个`)
|
package/src/commands/sync.ts
CHANGED
|
@@ -12,7 +12,7 @@ export async function syncCommand(options: SyncCommandOptions = {}): Promise<voi
|
|
|
12
12
|
const cwd = process.cwd()
|
|
13
13
|
const tools = resolveTools(cwd, options.tools)
|
|
14
14
|
const check = options.check ?? false
|
|
15
|
-
const result = await runSync({ cwd,
|
|
15
|
+
const result = await runSync({ cwd, check, ...(tools ? { tools } : {}) })
|
|
16
16
|
|
|
17
17
|
if (check) {
|
|
18
18
|
printCheckResult(result, cwd)
|
package/src/commands/validate.ts
CHANGED
|
@@ -12,6 +12,7 @@ export async function validateCommand(): Promise<void> {
|
|
|
12
12
|
if (result.valid) {
|
|
13
13
|
console.log('✅ 校验通过')
|
|
14
14
|
const ctx = result.context
|
|
15
|
+
console.log(` 当前作用域: ${ctx.scope}`)
|
|
15
16
|
const current = ctx.currentPlan
|
|
16
17
|
? `plan-${ctx.currentPlan.number} (${ctx.currentPlan.status})`
|
|
17
18
|
: '无'
|
package/src/content/actions.ts
CHANGED
|
@@ -17,6 +17,13 @@ function renderInit(): string {
|
|
|
17
17
|
|
|
18
18
|
可附带描述参数,用于补充项目背景、技术栈、特殊约束。
|
|
19
19
|
|
|
20
|
+
## 前置检查
|
|
21
|
+
|
|
22
|
+
- 若已存在 \`.agent-context/\`:运行 \`agent-context validate\`,不通过则中止并报告错误。
|
|
23
|
+
- 若 \`.agent-context/\` 不存在:确认这是首次初始化场景;若目录残缺或状态异常,向用户报告,不可继续假设。
|
|
24
|
+
- 新项目缺少关键决策信息时,必须主动提问或确认,不可直接生成 \`AGENTS.md\` 或进入 plan。
|
|
25
|
+
- 遇到阻塞问题应向用户报告,不可静默跳过。
|
|
26
|
+
|
|
20
27
|
## 执行步骤
|
|
21
28
|
|
|
22
29
|
1. **判断项目类型**:检测根目录是否存在有效代码文件和目录结构。
|
|
@@ -26,11 +33,16 @@ function renderInit(): string {
|
|
|
26
33
|
|
|
27
34
|
2. **处理 AGENTS.md**:
|
|
28
35
|
- 新项目:
|
|
29
|
-
1.
|
|
30
|
-
|
|
31
|
-
|
|
36
|
+
1. 先收集或确认以下信息,其中前两类属于**必须主动确认**的决策项,即使描述已部分涵盖也不能整体跳过;可基于描述用确认式问题补问,而不是完全重问。
|
|
37
|
+
- 必须主动确认:技术栈与版本(语言、运行时、框架、构建/测试工具等)
|
|
38
|
+
- 必须主动确认:架构偏好(目录结构、分层模式、关键框架或方案选型)
|
|
39
|
+
- 可基于描述补充:项目目标与核心功能
|
|
40
|
+
- 可基于描述补充:代码规范与工具链细节(lint、formatter、测试约定等)
|
|
41
|
+
2. 对高价值决策类问题必须在计划前澄清,例如:是否使用 monorepo、前后端如何拆分、采用哪个框架与测试工具。
|
|
42
|
+
3. 生成高质量 \`AGENTS.md\`(须满足下方质量标准,不满足则重新优化直至满足)。
|
|
43
|
+
4. 继续执行 plan 创建初始计划。
|
|
32
44
|
- 旧项目:
|
|
33
|
-
1. 若不存在 \`AGENTS.md
|
|
45
|
+
1. 若不存在 \`AGENTS.md\`:优先通过代码与配置读取收集信息;仅对无法可靠判断的内容提问后生成。
|
|
34
46
|
2. 若已存在 \`AGENTS.md\`:按质量标准评估,不足时增补优化。
|
|
35
47
|
3. 默认不创建计划(除非用户明确要求)。
|
|
36
48
|
|
|
@@ -50,7 +62,7 @@ function renderInit(): string {
|
|
|
50
62
|
function renderPlan(): string {
|
|
51
63
|
return `# plan
|
|
52
64
|
|
|
53
|
-
创建新的执行计划,写入 \`.agent-context/plan-{number}/plan.md\`。按复杂度可拆分为多个计划,维护「单当前计划 + preparing 队列」结构。
|
|
65
|
+
创建新的执行计划,写入 \`.agent-context/{scope}/plan-{number}/plan.md\`。按复杂度可拆分为多个计划,维护「单当前计划 + preparing 队列」结构。
|
|
54
66
|
|
|
55
67
|
必须附带计划描述。
|
|
56
68
|
|
|
@@ -70,7 +82,7 @@ function renderPlan(): string {
|
|
|
70
82
|
- 存在显著不同的技术路径需用户决策。
|
|
71
83
|
- 验收标准不明确:无法判断何时算"完成"。
|
|
72
84
|
2. 按复杂度决定单计划或多计划拆分。
|
|
73
|
-
3. 多计划拆分时:最小编号进入 \`.agent-context/\` 作为当前计划,其余进入 \`.agent-context/preparing/\`。单计划直接创建。
|
|
85
|
+
3. 多计划拆分时:最小编号进入 \`.agent-context/{scope}/\` 作为当前计划,其余进入 \`.agent-context/{scope}/preparing/\`。单计划直接创建。
|
|
74
86
|
4. 每个计划创建 \`plan.md\`,遵循下方模板。
|
|
75
87
|
5. **自检**(不通过则修改后重新检查):
|
|
76
88
|
- 每个步骤可独立执行且有明确完成标准。
|
|
@@ -121,9 +133,9 @@ function renderReplan(): string {
|
|
|
121
133
|
|
|
122
134
|
## 作用域
|
|
123
135
|
|
|
124
|
-
- 默认作用域:\`.agent-context/preparing/\` 中全部未实施计划。
|
|
136
|
+
- 默认作用域:\`.agent-context/{scope}/preparing/\` 中全部未实施计划。
|
|
125
137
|
- 可通过描述指定仅重规划部分计划(如"重规划 plan-3 和 plan-5")。
|
|
126
|
-
- 当前计划为 \`已执行\` → 禁止重写,仅允许重规划 \`preparing/\` 队列。
|
|
138
|
+
- 当前计划为 \`已执行\` → 禁止重写,仅允许重规划 \`{scope}/preparing/\` 队列。
|
|
127
139
|
- 当前计划为 \`未执行\` 且用户明确要求 → 可纳入重规划范围。
|
|
128
140
|
|
|
129
141
|
## 执行步骤
|
|
@@ -139,7 +151,7 @@ function renderReplan(): string {
|
|
|
139
151
|
function renderImplement(): string {
|
|
140
152
|
return `# implement
|
|
141
153
|
|
|
142
|
-
实施当前计划 \`.agent-context/plan-{number}/plan.md\` 中的全部步骤,通过验证循环后将状态更新为「已执行」。
|
|
154
|
+
实施当前计划 \`.agent-context/{scope}/plan-{number}/plan.md\` 中的全部步骤,通过验证循环后将状态更新为「已执行」。
|
|
143
155
|
|
|
144
156
|
不接受额外描述。
|
|
145
157
|
|
|
@@ -185,13 +197,16 @@ function renderPatch(): string {
|
|
|
185
197
|
- 当前计划不存在 → 拒绝执行,提示先创建计划。
|
|
186
198
|
- 当前计划状态为 \`未执行\` → 拒绝执行,提示先实施。
|
|
187
199
|
- 存在多个当前计划 → 拒绝执行,提示恢复单活跃状态。
|
|
200
|
+
- 补丁需求与当前计划完全无关 → 拒绝执行,提示先运行 \`agent-context done\` 归档后再创建新计划。
|
|
188
201
|
- 补丁不改变计划状态,完成后保持 \`已执行\`。
|
|
189
202
|
|
|
190
203
|
## 执行步骤
|
|
191
204
|
|
|
192
205
|
1. 阅读 \`plan.md\` 与已有 \`patch-{number}.md\`,了解上下文与历史,避免重复修复。
|
|
193
206
|
2. 根据描述执行补丁所需的代码变更。
|
|
194
|
-
3.
|
|
207
|
+
3. 完成验证:
|
|
208
|
+
- **IF** (编码任务) **THEN**:运行相关测试,以及必要的 Lint/Typecheck。
|
|
209
|
+
- **ELSE IF** (非编码任务,如纯文档修改) **THEN**:仅凭逻辑与排版审阅确认验收通过。
|
|
195
210
|
4. 创建 \`patch-{number}.md\`(编号:扫描当前计划目录已有补丁取 max+1),遵循下方模板。
|
|
196
211
|
5. 回写 \`plan.md\`:
|
|
197
212
|
- \`## 历史补丁\`:追加 \`- patch-{number}: {补丁名称}\`,按编号去重。
|
|
@@ -226,6 +241,7 @@ function renderRush(): string {
|
|
|
226
241
|
|
|
227
242
|
- 运行 \`agent-context validate\`,不通过则中止并报告错误。
|
|
228
243
|
- 描述为空 → 拒绝执行。
|
|
244
|
+
- 描述仍存在范围边界、技术路径或验收标准歧义 → 拒绝执行,提示改用 \`plan\`。
|
|
229
245
|
- 存在未归档的已执行当前计划 → 判断新需求与当前计划的关联性:
|
|
230
246
|
- 相关联或用户本意是修补 → 拒绝执行,提示改用 patch。
|
|
231
247
|
- 完全无关 → 拒绝执行,提示先运行 \`agent-context done\` 归档后再创建新计划。
|
|
@@ -237,7 +253,7 @@ function renderRush(): string {
|
|
|
237
253
|
|
|
238
254
|
### 阶段一:plan(差异)
|
|
239
255
|
|
|
240
|
-
-
|
|
256
|
+
- 仅在描述本身已足够明确时跳过「需求澄清」步骤;否则不得继续 rush。
|
|
241
257
|
- 强制单计划,不拆分,不进入 preparing 队列。
|
|
242
258
|
- 完成 plan 后**不等待用户确认**,直接进入阶段二。
|
|
243
259
|
|
package/src/content/index.ts
CHANGED
|
@@ -32,7 +32,7 @@ function renderNavigator(target: ToolTarget): string {
|
|
|
32
32
|
## 执行纪律
|
|
33
33
|
|
|
34
34
|
- **协议先行**:匹配到动作后,必须先读取对应 \`actions/*.md\` 协议文件的完整内容,再逐步执行。禁止凭记忆、摘要或猜测跳过协议步骤。
|
|
35
|
-
- **前置检查必做**:所有动作(done
|
|
35
|
+
- **前置检查必做**:所有动作(done 除外)均包含「前置检查」,必须逐条执行,不可跳过。凡协议写明需运行 \`agent-context validate\` 时必须执行;\`init\` 在首次初始化且 \`.agent-context/\` 尚不存在时,先确认初始化场景成立,再按协议继续。
|
|
36
36
|
- **禁止直接改动**:在 plan / rush 创建计划之前,不得直接修改项目代码文件。任何代码变更必须在已创建计划(implement)或已创建补丁(patch)的上下文中进行。
|
|
37
37
|
- **顺序执行**:协议步骤必须按编号顺序逐项执行,不可跳步、合并或并行。
|
|
38
38
|
|
|
@@ -55,7 +55,7 @@ function renderNavigator(target: ToolTarget): string {
|
|
|
55
55
|
## 全局约束
|
|
56
56
|
|
|
57
57
|
- 状态机两态:\`未执行\`、\`已执行\`。
|
|
58
|
-
- 任意时刻最多一个当前计划:\`.agent-context/plan-{number}\`。
|
|
58
|
+
- 任意时刻最多一个当前计划:\`.agent-context/{scope}/plan-{number}\`。
|
|
59
59
|
- 多个当前计划 → 拒绝执行,提示恢复单活跃状态。
|
|
60
60
|
- 计划编号全局递增,不复用。补丁编号在单计划目录内递增,不复用。
|
|
61
61
|
- 影响范围(\`## 影响范围\`)不得包含 \`.agent-context/\` 目录下的文件。
|
|
@@ -64,16 +64,19 @@ function renderNavigator(target: ToolTarget): string {
|
|
|
64
64
|
|
|
65
65
|
\`\`\`text
|
|
66
66
|
.agent-context/
|
|
67
|
-
├──
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
├──
|
|
71
|
-
│
|
|
72
|
-
└──
|
|
73
|
-
|
|
67
|
+
├── .env # SCOPE 配置(SCOPE=<name>)
|
|
68
|
+
├── .gitignore
|
|
69
|
+
└── {scope}/ # 作用域目录(按协作者隔离)
|
|
70
|
+
├── plan-{N}/ # 当前计划(最多一个)
|
|
71
|
+
│ ├── plan.md
|
|
72
|
+
│ └── patch-{N}.md
|
|
73
|
+
├── preparing/ # 待执行计划队列
|
|
74
|
+
│ └── plan-{N}/
|
|
75
|
+
└── done/ # 已归档计划
|
|
76
|
+
└── plan-{N}-{YYYYMMDD}/
|
|
74
77
|
\`\`\`
|
|
75
78
|
|
|
76
|
-
|
|
79
|
+
编号规则:在当前 scope 内扫描全部 \`plan-N\` 目录取 \`max(N)+1\`。
|
|
77
80
|
`
|
|
78
81
|
}
|
|
79
82
|
|
|
@@ -82,7 +85,7 @@ function renderNavigator(target: ToolTarget): string {
|
|
|
82
85
|
function renderFrontmatter(target: ToolTarget): string {
|
|
83
86
|
const lines = ['---', `name: ${SKILL_NAME}`, `description: ${SKILL_DESCRIPTION}`]
|
|
84
87
|
|
|
85
|
-
if (target.frontmatterProfile
|
|
88
|
+
if (target.frontmatterProfile !== 'copilot') {
|
|
86
89
|
lines.push('argument-hint: [request]')
|
|
87
90
|
}
|
|
88
91
|
|
package/src/context/index.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
export { readContext, readRawContext, readPlanStatus } from './reader.js'
|
|
2
2
|
export { validate } from './validator.js'
|
|
3
3
|
export { archive } from './archiver.js'
|
|
4
|
+
export { generateIndex } from './indexer.js'
|
|
5
|
+
export { resolveScope, initScope, normalizeScope } from './scope.js'
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs'
|
|
2
|
+
import { readFile, writeFile } from 'node:fs/promises'
|
|
3
|
+
import { join, relative } from 'node:path'
|
|
4
|
+
|
|
5
|
+
import type { ContextSnapshot } from '../types.js'
|
|
6
|
+
|
|
7
|
+
const H1_RE = /^#\s+(.+)$/m
|
|
8
|
+
|
|
9
|
+
export interface IndexResult {
|
|
10
|
+
path: string
|
|
11
|
+
entries: number
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export async function generateIndex(context: ContextSnapshot): Promise<IndexResult> {
|
|
15
|
+
const lines: string[] = []
|
|
16
|
+
|
|
17
|
+
for (const plan of context.done) {
|
|
18
|
+
const title = await extractTitle(plan.dir)
|
|
19
|
+
const rel = `./${relative(context.root, plan.dir)}/plan.md`
|
|
20
|
+
lines.push(`- [x] [${title}](${rel})`)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (context.currentPlan) {
|
|
24
|
+
const title = await extractTitle(context.currentPlan.dir)
|
|
25
|
+
const rel = `./${relative(context.root, context.currentPlan.dir)}/plan.md`
|
|
26
|
+
const check = context.currentPlan.status === '已执行' ? 'x' : ' '
|
|
27
|
+
lines.push(`- [${check}] [${title}](${rel})`)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
for (const plan of context.preparing) {
|
|
31
|
+
const title = await extractTitle(plan.dir)
|
|
32
|
+
const rel = `./${relative(context.root, plan.dir)}/plan.md`
|
|
33
|
+
lines.push(`- [ ] [${title}](${rel})`)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const indexPath = join(context.root, 'index.md')
|
|
37
|
+
await writeFile(indexPath, lines.join('\n') + '\n', 'utf-8')
|
|
38
|
+
|
|
39
|
+
return { path: indexPath, entries: lines.length }
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async function extractTitle(planDir: string): Promise<string> {
|
|
43
|
+
const planFile = join(planDir, 'plan.md')
|
|
44
|
+
|
|
45
|
+
if (!existsSync(planFile)) {
|
|
46
|
+
return `plan-${planDir.split('/').pop() ?? 'unknown'}`
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const content = await readFile(planFile, 'utf-8')
|
|
50
|
+
const match = content.match(H1_RE)
|
|
51
|
+
return match?.[1]?.trim() ?? `plan-${planDir.split('/').pop() ?? 'unknown'}`
|
|
52
|
+
}
|
package/src/context/reader.ts
CHANGED
|
@@ -3,6 +3,7 @@ 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'
|
|
6
|
+
import { resolveScope } from './scope.js'
|
|
6
7
|
|
|
7
8
|
const PLAN_DIR_RE = /^plan-(\d+)$/
|
|
8
9
|
const DONE_DIR_RE = /^plan-(\d+)(?:-\d{8})?$/
|
|
@@ -19,17 +20,26 @@ export async function readContext(cwd: string): Promise<ContextSnapshot | null>
|
|
|
19
20
|
export async function readRawContext(
|
|
20
21
|
cwd: string
|
|
21
22
|
): Promise<{ snapshot: ContextSnapshot | null; currentPlanCount: number }> {
|
|
22
|
-
const
|
|
23
|
+
const acRoot = join(cwd, '.agent-context')
|
|
23
24
|
|
|
24
|
-
if (!existsSync(
|
|
25
|
+
if (!existsSync(acRoot)) {
|
|
25
26
|
return { snapshot: null, currentPlanCount: 0 }
|
|
26
27
|
}
|
|
27
28
|
|
|
29
|
+
const scope = await resolveScope(acRoot)
|
|
30
|
+
const root = join(acRoot, scope)
|
|
31
|
+
|
|
28
32
|
const currentPlans = await readPlanDirs(root)
|
|
29
33
|
const preparing = await readPlanDirs(join(root, 'preparing'))
|
|
30
34
|
const done = await readDonePlans(join(root, 'done'))
|
|
31
35
|
|
|
32
|
-
const snapshot: ContextSnapshot = {
|
|
36
|
+
const snapshot: ContextSnapshot = {
|
|
37
|
+
root,
|
|
38
|
+
scope,
|
|
39
|
+
currentPlan: currentPlans[0] ?? null,
|
|
40
|
+
preparing,
|
|
41
|
+
done
|
|
42
|
+
}
|
|
33
43
|
|
|
34
44
|
return { snapshot, currentPlanCount: currentPlans.length }
|
|
35
45
|
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { execSync } from 'node:child_process'
|
|
2
|
+
import { existsSync } from 'node:fs'
|
|
3
|
+
import { readFile, writeFile, mkdir } from 'node:fs/promises'
|
|
4
|
+
import { join } from 'node:path'
|
|
5
|
+
|
|
6
|
+
export async function resolveScope(acRoot: string): Promise<string> {
|
|
7
|
+
const envPath = join(acRoot, '.env')
|
|
8
|
+
|
|
9
|
+
if (existsSync(envPath)) {
|
|
10
|
+
const content = await readFile(envPath, 'utf-8')
|
|
11
|
+
const match = content.match(/^SCOPE=(.+)$/m)
|
|
12
|
+
if (match?.[1]) {
|
|
13
|
+
return match[1].trim()
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return initScope(acRoot)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export async function initScope(acRoot: string, manualScope?: string): Promise<string> {
|
|
21
|
+
let scope: string
|
|
22
|
+
|
|
23
|
+
if (manualScope) {
|
|
24
|
+
scope = normalizeScope(manualScope)
|
|
25
|
+
} else {
|
|
26
|
+
let userName: string
|
|
27
|
+
try {
|
|
28
|
+
userName = execSync('git config user.name', { encoding: 'utf-8' }).trim()
|
|
29
|
+
} catch {
|
|
30
|
+
throw new Error('未找到 git user.name,请先运行 git config user.name <name>')
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (!userName) {
|
|
34
|
+
throw new Error('未找到 git user.name,请先运行 git config user.name <name>')
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
scope = normalizeScope(userName)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const envPath = join(acRoot, '.env')
|
|
41
|
+
await writeFile(envPath, `SCOPE=${scope}\n`, 'utf-8')
|
|
42
|
+
|
|
43
|
+
await ensureGitignoreHasEnv(acRoot)
|
|
44
|
+
|
|
45
|
+
const scopeDir = join(acRoot, scope)
|
|
46
|
+
await mkdir(scopeDir, { recursive: true })
|
|
47
|
+
|
|
48
|
+
return scope
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function normalizeScope(name: string): string {
|
|
52
|
+
return name
|
|
53
|
+
.toLowerCase()
|
|
54
|
+
.replace(/[^a-z0-9]/g, '-')
|
|
55
|
+
.replace(/^-+|-+$/g, '')
|
|
56
|
+
.replace(/-{2,}/g, '-')
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async function ensureGitignoreHasEnv(acRoot: string): Promise<void> {
|
|
60
|
+
const gitignorePath = join(acRoot, '.gitignore')
|
|
61
|
+
|
|
62
|
+
if (existsSync(gitignorePath)) {
|
|
63
|
+
const content = await readFile(gitignorePath, 'utf-8')
|
|
64
|
+
if (!content.split('\n').some((line) => line.trim() === '.env')) {
|
|
65
|
+
await writeFile(gitignorePath, content.trimEnd() + '\n.env\n', 'utf-8')
|
|
66
|
+
}
|
|
67
|
+
} else {
|
|
68
|
+
await writeFile(gitignorePath, '.env\n', 'utf-8')
|
|
69
|
+
}
|
|
70
|
+
}
|