@cat-kit/agent-context 1.1.6 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +1 -1
- package/dist/commands/init.js +1 -0
- package/dist/commands/status.js +1 -1
- package/dist/commands/validate.js +1 -1
- package/dist/content/actions.js +5 -5
- package/dist/content/index.js +12 -9
- package/dist/context/reader.js +1 -1
- package/dist/context/scope.js +5 -0
- package/dist/stats.html +1 -1
- package/package.json +1 -1
- package/src/cli.ts +8 -0
- package/src/commands/init.ts +43 -0
- package/src/commands/status.ts +1 -0
- package/src/commands/validate.ts +1 -0
- package/src/content/actions.ts +5 -5
- package/src/content/index.ts +12 -9
- package/src/context/index.ts +1 -0
- package/src/context/reader.ts +13 -3
- package/src/context/scope.ts +70 -0
- package/src/types.ts +1 -0
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{initCommand as t}from"./commands/init.js";import{installCommand as n}from"./commands/install.js";import{statusCommand as r}from"./commands/status.js";import{syncCommand as i}from"./commands/sync.js";import{validateCommand as a}from"./commands/validate.js";import{readFileSync as o}from"node:fs";import{Command as s}from"commander";const c=JSON.parse(o(new URL(`../package.json`,import.meta.url),`utf8`)),l=typeof c.version==`string`?c.version:`0.0.0`,u=new s;u.name(`agent-context`).description(`Agent Context Skills 安装工具`).version(l),u.command(`install`).description(`安装 ac-workflow Skill`).option(`--tools <tools>`,`指定目标工具,逗号分隔:claude,codex,cursor,antigravity,copilot`).option(`--yes`,`非交互模式:优先复用已安装工具,否则安装全部工具`).option(`--check`,`仅检查是否存在待更新内容,不写入文件`).action(n),u.command(`sync`).description(`同步已安装的 ac-workflow Skill`).option(`--tools <tools>`,`指定目标工具,逗号分隔:claude,codex,cursor,antigravity,copilot`).option(`--check`,`仅检查是否存在待更新内容,不写入文件`).action(i),u.command(`init`).description(`初始化 SCOPE(从 git user.name 自动获取或手动指定)`).option(`--scope <name>`,`手动指定 SCOPE 名称`).option(`--yes`,`非交互模式:自动覆盖已存在的 SCOPE`).action(t),u.command(`validate`).description(`校验 .agent-context 目录结构`).action(a),u.command(`status`).description(`查看当前 agent-context 状态`).action(r),u.command(`done`).description(`归档当前已执行计划`).option(`--yes`,`跳过确认,直接归档`).action(e),u.parseAsync().catch(e=>{let t=e instanceof Error?e.message:String(e);console.error(`\n❌ ${t}`),process.exitCode=1});export{};
|
|
@@ -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/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};
|
|
@@ -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
|
@@ -33,7 +33,7 @@ const e=[`init`,`plan`,`replan`,`implement`,`patch`,`rush`],t={init:n,plan:r,rep
|
|
|
33
33
|
- 大型单体仓库按子包拆分维护本地 \`AGENTS.md\`。
|
|
34
34
|
`}function r(){return`# plan
|
|
35
35
|
|
|
36
|
-
创建新的执行计划,写入 \`.agent-context/plan-{number}/plan.md\`。按复杂度可拆分为多个计划,维护「单当前计划 + preparing 队列」结构。
|
|
36
|
+
创建新的执行计划,写入 \`.agent-context/{scope}/plan-{number}/plan.md\`。按复杂度可拆分为多个计划,维护「单当前计划 + preparing 队列」结构。
|
|
37
37
|
|
|
38
38
|
必须附带计划描述。
|
|
39
39
|
|
|
@@ -53,7 +53,7 @@ const e=[`init`,`plan`,`replan`,`implement`,`patch`,`rush`],t={init:n,plan:r,rep
|
|
|
53
53
|
- 存在显著不同的技术路径需用户决策。
|
|
54
54
|
- 验收标准不明确:无法判断何时算"完成"。
|
|
55
55
|
2. 按复杂度决定单计划或多计划拆分。
|
|
56
|
-
3. 多计划拆分时:最小编号进入 \`.agent-context/\` 作为当前计划,其余进入 \`.agent-context/preparing/\`。单计划直接创建。
|
|
56
|
+
3. 多计划拆分时:最小编号进入 \`.agent-context/{scope}/\` 作为当前计划,其余进入 \`.agent-context/{scope}/preparing/\`。单计划直接创建。
|
|
57
57
|
4. 每个计划创建 \`plan.md\`,遵循下方模板。
|
|
58
58
|
5. **自检**(不通过则修改后重新检查):
|
|
59
59
|
- 每个步骤可独立执行且有明确完成标准。
|
|
@@ -100,9 +100,9 @@ const e=[`init`,`plan`,`replan`,`implement`,`patch`,`rush`],t={init:n,plan:r,rep
|
|
|
100
100
|
|
|
101
101
|
## 作用域
|
|
102
102
|
|
|
103
|
-
- 默认作用域:\`.agent-context/preparing/\` 中全部未实施计划。
|
|
103
|
+
- 默认作用域:\`.agent-context/{scope}/preparing/\` 中全部未实施计划。
|
|
104
104
|
- 可通过描述指定仅重规划部分计划(如"重规划 plan-3 和 plan-5")。
|
|
105
|
-
- 当前计划为 \`已执行\` → 禁止重写,仅允许重规划 \`preparing/\` 队列。
|
|
105
|
+
- 当前计划为 \`已执行\` → 禁止重写,仅允许重规划 \`{scope}/preparing/\` 队列。
|
|
106
106
|
- 当前计划为 \`未执行\` 且用户明确要求 → 可纳入重规划范围。
|
|
107
107
|
|
|
108
108
|
## 执行步骤
|
|
@@ -112,7 +112,7 @@ const e=[`init`,`plan`,`replan`,`implement`,`patch`,`rush`],t={init:n,plan:r,rep
|
|
|
112
112
|
3. 生成新的拆分方案,保持「单当前计划 + 若干 preparing 计划」结构。
|
|
113
113
|
4. 新增计划编号:全局 max(N)+1 递增分配;未改动计划保持原编号。
|
|
114
114
|
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
|
|
115
|
+
`}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
116
|
|
|
117
117
|
基于当前已执行计划创建增量补丁,修复问题或追加变更。
|
|
118
118
|
|
package/dist/content/index.js
CHANGED
|
@@ -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,16 +38,19 @@ 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
|
-
|
|
53
|
+
编号规则:在当前 scope 内扫描全部 \`plan-N\` 目录取 \`max(N)+1\`。
|
|
51
54
|
`}function i(e){let t=[`---`,`name: ac-workflow`,`description: 管理 .agent-context 计划生命周期,按 init、plan、replan、implement、patch、rush、done 协议推进任务。`];return e.frontmatterProfile===`claude`&&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"
|
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(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 d(o),c=await d(n(o,`preparing`)),l=await f(n(o,`done`));return{snapshot:{root:o,scope:a,currentPlan:s[0]??null,preparing:c,done:l},currentPlanCount:s.length}}async function u(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 d(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 u(s);o.push({number:i,status:c,dir:s})}return o.sort((e,t)=>e.number-t.number)}async function f(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 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":"
|
|
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":"5218ad55-1"}]},{"name":"cli.js","children":[{"name":"home/whj/codes/cat-kit/packages/agent-context/src/cli.ts","uid":"5218ad55-3"}]},{"name":"commands/done.js","children":[{"name":"home/whj/codes/cat-kit/packages/agent-context/src/commands/done.ts","uid":"5218ad55-5"}]},{"name":"commands/init.js","children":[{"name":"home/whj/codes/cat-kit/packages/agent-context/src/commands/init.ts","uid":"5218ad55-7"}]},{"name":"commands/install.js","children":[{"name":"home/whj/codes/cat-kit/packages/agent-context/src/commands/install.ts","uid":"5218ad55-9"}]},{"name":"commands/printer.js","children":[{"name":"home/whj/codes/cat-kit/packages/agent-context/src/commands/printer.ts","uid":"5218ad55-11"}]},{"name":"commands/status.js","children":[{"name":"home/whj/codes/cat-kit/packages/agent-context/src/commands/status.ts","uid":"5218ad55-13"}]},{"name":"commands/sync.js","children":[{"name":"home/whj/codes/cat-kit/packages/agent-context/src/commands/sync.ts","uid":"5218ad55-15"}]},{"name":"commands/validate.js","children":[{"name":"home/whj/codes/cat-kit/packages/agent-context/src/commands/validate.ts","uid":"5218ad55-17"}]},{"name":"content/actions.js","children":[{"name":"home/whj/codes/cat-kit/packages/agent-context/src/content/actions.ts","uid":"5218ad55-19"}]},{"name":"content/index.js","children":[{"name":"home/whj/codes/cat-kit/packages/agent-context/src/content/index.ts","uid":"5218ad55-21"}]},{"name":"context/archiver.js","children":[{"name":"home/whj/codes/cat-kit/packages/agent-context/src/context/archiver.ts","uid":"5218ad55-23"}]},{"name":"context/reader.js","children":[{"name":"home/whj/codes/cat-kit/packages/agent-context/src/context/reader.ts","uid":"5218ad55-25"}]},{"name":"context/scope.js","children":[{"name":"home/whj/codes/cat-kit/packages/agent-context/src/context/scope.ts","uid":"5218ad55-27"}]},{"name":"context/validator.js","children":[{"name":"home/whj/codes/cat-kit/packages/agent-context/src/context/validator.ts","uid":"5218ad55-29"}]},{"name":"runner.js","children":[{"name":"home/whj/codes/cat-kit/packages/agent-context/src/runner.ts","uid":"5218ad55-31"}]},{"name":"tools.js","children":[{"name":"home/whj/codes/cat-kit/packages/agent-context/src/tools.ts","uid":"5218ad55-33"}]}],"isRoot":true},"nodeParts":{"5218ad55-1":{"renderedLength":0,"gzipLength":0,"brotliLength":0,"metaUid":"5218ad55-0"},"5218ad55-3":{"renderedLength":1767,"gzipLength":0,"brotliLength":0,"metaUid":"5218ad55-2"},"5218ad55-5":{"renderedLength":1349,"gzipLength":0,"brotliLength":0,"metaUid":"5218ad55-4"},"5218ad55-7":{"renderedLength":718,"gzipLength":0,"brotliLength":0,"metaUid":"5218ad55-6"},"5218ad55-9":{"renderedLength":985,"gzipLength":0,"brotliLength":0,"metaUid":"5218ad55-8"},"5218ad55-11":{"renderedLength":909,"gzipLength":0,"brotliLength":0,"metaUid":"5218ad55-10"},"5218ad55-13":{"renderedLength":993,"gzipLength":0,"brotliLength":0,"metaUid":"5218ad55-12"},"5218ad55-15":{"renderedLength":745,"gzipLength":0,"brotliLength":0,"metaUid":"5218ad55-14"},"5218ad55-17":{"renderedLength":813,"gzipLength":0,"brotliLength":0,"metaUid":"5218ad55-16"},"5218ad55-19":{"renderedLength":9957,"gzipLength":0,"brotliLength":0,"metaUid":"5218ad55-18"},"5218ad55-21":{"renderedLength":4203,"gzipLength":0,"brotliLength":0,"metaUid":"5218ad55-20"},"5218ad55-23":{"renderedLength":1012,"gzipLength":0,"brotliLength":0,"metaUid":"5218ad55-22"},"5218ad55-25":{"renderedLength":2173,"gzipLength":0,"brotliLength":0,"metaUid":"5218ad55-24"},"5218ad55-27":{"renderedLength":1479,"gzipLength":0,"brotliLength":0,"metaUid":"5218ad55-26"},"5218ad55-29":{"renderedLength":1905,"gzipLength":0,"brotliLength":0,"metaUid":"5218ad55-28"},"5218ad55-31":{"renderedLength":2037,"gzipLength":0,"brotliLength":0,"metaUid":"5218ad55-30"},"5218ad55-33":{"renderedLength":2174,"gzipLength":0,"brotliLength":0,"metaUid":"5218ad55-32"}},"nodeMetas":{"5218ad55-0":{"id":"/home/whj/codes/cat-kit/packages/agent-context/src/cli.d.ts","moduleParts":{"cli.d.ts":"5218ad55-1"},"imported":[],"importedBy":[],"isEntry":true},"5218ad55-2":{"id":"/home/whj/codes/cat-kit/packages/agent-context/src/cli.ts","moduleParts":{"cli.js":"5218ad55-3"},"imported":[{"uid":"5218ad55-34"},{"uid":"5218ad55-35"},{"uid":"5218ad55-4"},{"uid":"5218ad55-6"},{"uid":"5218ad55-8"},{"uid":"5218ad55-12"},{"uid":"5218ad55-14"},{"uid":"5218ad55-16"}],"importedBy":[],"isEntry":true},"5218ad55-4":{"id":"/home/whj/codes/cat-kit/packages/agent-context/src/commands/done.ts","moduleParts":{"commands/done.js":"5218ad55-5"},"imported":[{"uid":"5218ad55-36"},{"uid":"5218ad55-37"},{"uid":"5218ad55-38"}],"importedBy":[{"uid":"5218ad55-2"}]},"5218ad55-6":{"id":"/home/whj/codes/cat-kit/packages/agent-context/src/commands/init.ts","moduleParts":{"commands/init.js":"5218ad55-7"},"imported":[{"uid":"5218ad55-34"},{"uid":"5218ad55-39"},{"uid":"5218ad55-36"},{"uid":"5218ad55-37"},{"uid":"5218ad55-26"}],"importedBy":[{"uid":"5218ad55-2"}]},"5218ad55-8":{"id":"/home/whj/codes/cat-kit/packages/agent-context/src/commands/install.ts","moduleParts":{"commands/install.js":"5218ad55-9"},"imported":[{"uid":"5218ad55-37"},{"uid":"5218ad55-30"},{"uid":"5218ad55-32"},{"uid":"5218ad55-10"}],"importedBy":[{"uid":"5218ad55-2"}]},"5218ad55-10":{"id":"/home/whj/codes/cat-kit/packages/agent-context/src/commands/printer.ts","moduleParts":{"commands/printer.js":"5218ad55-11"},"imported":[{"uid":"5218ad55-36"}],"importedBy":[{"uid":"5218ad55-8"},{"uid":"5218ad55-14"}]},"5218ad55-12":{"id":"/home/whj/codes/cat-kit/packages/agent-context/src/commands/status.ts","moduleParts":{"commands/status.js":"5218ad55-13"},"imported":[{"uid":"5218ad55-38"}],"importedBy":[{"uid":"5218ad55-2"}]},"5218ad55-14":{"id":"/home/whj/codes/cat-kit/packages/agent-context/src/commands/sync.ts","moduleParts":{"commands/sync.js":"5218ad55-15"},"imported":[{"uid":"5218ad55-30"},{"uid":"5218ad55-32"},{"uid":"5218ad55-10"}],"importedBy":[{"uid":"5218ad55-2"}]},"5218ad55-16":{"id":"/home/whj/codes/cat-kit/packages/agent-context/src/commands/validate.ts","moduleParts":{"commands/validate.js":"5218ad55-17"},"imported":[{"uid":"5218ad55-38"}],"importedBy":[{"uid":"5218ad55-2"}]},"5218ad55-18":{"id":"/home/whj/codes/cat-kit/packages/agent-context/src/content/actions.ts","moduleParts":{"content/actions.js":"5218ad55-19"},"imported":[],"importedBy":[{"uid":"5218ad55-20"}]},"5218ad55-20":{"id":"/home/whj/codes/cat-kit/packages/agent-context/src/content/index.ts","moduleParts":{"content/index.js":"5218ad55-21"},"imported":[{"uid":"5218ad55-18"}],"importedBy":[{"uid":"5218ad55-30"}]},"5218ad55-22":{"id":"/home/whj/codes/cat-kit/packages/agent-context/src/context/archiver.ts","moduleParts":{"context/archiver.js":"5218ad55-23"},"imported":[{"uid":"5218ad55-39"},{"uid":"5218ad55-36"}],"importedBy":[{"uid":"5218ad55-38"}]},"5218ad55-24":{"id":"/home/whj/codes/cat-kit/packages/agent-context/src/context/reader.ts","moduleParts":{"context/reader.js":"5218ad55-25"},"imported":[{"uid":"5218ad55-34"},{"uid":"5218ad55-39"},{"uid":"5218ad55-36"},{"uid":"5218ad55-26"}],"importedBy":[{"uid":"5218ad55-38"}]},"5218ad55-26":{"id":"/home/whj/codes/cat-kit/packages/agent-context/src/context/scope.ts","moduleParts":{"context/scope.js":"5218ad55-27"},"imported":[{"uid":"5218ad55-34"},{"uid":"5218ad55-39"},{"uid":"5218ad55-36"},{"uid":"5218ad55-40"}],"importedBy":[{"uid":"5218ad55-6"},{"uid":"5218ad55-38"},{"uid":"5218ad55-24"}]},"5218ad55-28":{"id":"/home/whj/codes/cat-kit/packages/agent-context/src/context/validator.ts","moduleParts":{"context/validator.js":"5218ad55-29"},"imported":[{"uid":"5218ad55-34"},{"uid":"5218ad55-36"}],"importedBy":[{"uid":"5218ad55-38"}]},"5218ad55-30":{"id":"/home/whj/codes/cat-kit/packages/agent-context/src/runner.ts","moduleParts":{"runner.js":"5218ad55-31"},"imported":[{"uid":"5218ad55-34"},{"uid":"5218ad55-39"},{"uid":"5218ad55-36"},{"uid":"5218ad55-20"},{"uid":"5218ad55-32"}],"importedBy":[{"uid":"5218ad55-8"},{"uid":"5218ad55-14"}]},"5218ad55-32":{"id":"/home/whj/codes/cat-kit/packages/agent-context/src/tools.ts","moduleParts":{"tools.js":"5218ad55-33"},"imported":[{"uid":"5218ad55-34"},{"uid":"5218ad55-36"}],"importedBy":[{"uid":"5218ad55-8"},{"uid":"5218ad55-14"},{"uid":"5218ad55-30"}]},"5218ad55-34":{"id":"node:fs","moduleParts":{},"imported":[],"importedBy":[{"uid":"5218ad55-2"},{"uid":"5218ad55-6"},{"uid":"5218ad55-26"},{"uid":"5218ad55-30"},{"uid":"5218ad55-32"},{"uid":"5218ad55-24"},{"uid":"5218ad55-28"}]},"5218ad55-35":{"id":"commander","moduleParts":{},"imported":[],"importedBy":[{"uid":"5218ad55-2"}]},"5218ad55-36":{"id":"node:path","moduleParts":{},"imported":[],"importedBy":[{"uid":"5218ad55-4"},{"uid":"5218ad55-6"},{"uid":"5218ad55-26"},{"uid":"5218ad55-30"},{"uid":"5218ad55-32"},{"uid":"5218ad55-10"},{"uid":"5218ad55-24"},{"uid":"5218ad55-28"},{"uid":"5218ad55-22"}]},"5218ad55-37":{"id":"@inquirer/prompts","moduleParts":{},"imported":[],"importedBy":[{"uid":"5218ad55-4"},{"uid":"5218ad55-6"},{"uid":"5218ad55-8"}]},"5218ad55-38":{"id":"/home/whj/codes/cat-kit/packages/agent-context/src/context/index.ts","moduleParts":{},"imported":[{"uid":"5218ad55-24"},{"uid":"5218ad55-28"},{"uid":"5218ad55-22"},{"uid":"5218ad55-26"}],"importedBy":[{"uid":"5218ad55-4"},{"uid":"5218ad55-12"},{"uid":"5218ad55-16"}]},"5218ad55-39":{"id":"node:fs/promises","moduleParts":{},"imported":[],"importedBy":[{"uid":"5218ad55-6"},{"uid":"5218ad55-26"},{"uid":"5218ad55-30"},{"uid":"5218ad55-24"},{"uid":"5218ad55-22"}]},"5218ad55-40":{"id":"node:child_process","moduleParts":{},"imported":[],"importedBy":[{"uid":"5218ad55-26"}]}},"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
package/src/cli.ts
CHANGED
|
@@ -5,6 +5,7 @@ import { readFileSync } from 'node:fs'
|
|
|
5
5
|
import { Command } from 'commander'
|
|
6
6
|
|
|
7
7
|
import { doneCommand } from './commands/done.js'
|
|
8
|
+
import { initCommand } from './commands/init.js'
|
|
8
9
|
import { installCommand } from './commands/install.js'
|
|
9
10
|
import { statusCommand } from './commands/status.js'
|
|
10
11
|
import { syncCommand } from './commands/sync.js'
|
|
@@ -34,6 +35,13 @@ program
|
|
|
34
35
|
.option('--check', '仅检查是否存在待更新内容,不写入文件')
|
|
35
36
|
.action(syncCommand)
|
|
36
37
|
|
|
38
|
+
program
|
|
39
|
+
.command('init')
|
|
40
|
+
.description('初始化 SCOPE(从 git user.name 自动获取或手动指定)')
|
|
41
|
+
.option('--scope <name>', '手动指定 SCOPE 名称')
|
|
42
|
+
.option('--yes', '非交互模式:自动覆盖已存在的 SCOPE')
|
|
43
|
+
.action(initCommand)
|
|
44
|
+
|
|
37
45
|
program.command('validate').description('校验 .agent-context 目录结构').action(validateCommand)
|
|
38
46
|
|
|
39
47
|
program.command('status').description('查看当前 agent-context 状态').action(statusCommand)
|
|
@@ -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/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/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
|
@@ -50,7 +50,7 @@ function renderInit(): string {
|
|
|
50
50
|
function renderPlan(): string {
|
|
51
51
|
return `# plan
|
|
52
52
|
|
|
53
|
-
创建新的执行计划,写入 \`.agent-context/plan-{number}/plan.md\`。按复杂度可拆分为多个计划,维护「单当前计划 + preparing 队列」结构。
|
|
53
|
+
创建新的执行计划,写入 \`.agent-context/{scope}/plan-{number}/plan.md\`。按复杂度可拆分为多个计划,维护「单当前计划 + preparing 队列」结构。
|
|
54
54
|
|
|
55
55
|
必须附带计划描述。
|
|
56
56
|
|
|
@@ -70,7 +70,7 @@ function renderPlan(): string {
|
|
|
70
70
|
- 存在显著不同的技术路径需用户决策。
|
|
71
71
|
- 验收标准不明确:无法判断何时算"完成"。
|
|
72
72
|
2. 按复杂度决定单计划或多计划拆分。
|
|
73
|
-
3. 多计划拆分时:最小编号进入 \`.agent-context/\` 作为当前计划,其余进入 \`.agent-context/preparing/\`。单计划直接创建。
|
|
73
|
+
3. 多计划拆分时:最小编号进入 \`.agent-context/{scope}/\` 作为当前计划,其余进入 \`.agent-context/{scope}/preparing/\`。单计划直接创建。
|
|
74
74
|
4. 每个计划创建 \`plan.md\`,遵循下方模板。
|
|
75
75
|
5. **自检**(不通过则修改后重新检查):
|
|
76
76
|
- 每个步骤可独立执行且有明确完成标准。
|
|
@@ -121,9 +121,9 @@ function renderReplan(): string {
|
|
|
121
121
|
|
|
122
122
|
## 作用域
|
|
123
123
|
|
|
124
|
-
- 默认作用域:\`.agent-context/preparing/\` 中全部未实施计划。
|
|
124
|
+
- 默认作用域:\`.agent-context/{scope}/preparing/\` 中全部未实施计划。
|
|
125
125
|
- 可通过描述指定仅重规划部分计划(如"重规划 plan-3 和 plan-5")。
|
|
126
|
-
- 当前计划为 \`已执行\` → 禁止重写,仅允许重规划 \`preparing/\` 队列。
|
|
126
|
+
- 当前计划为 \`已执行\` → 禁止重写,仅允许重规划 \`{scope}/preparing/\` 队列。
|
|
127
127
|
- 当前计划为 \`未执行\` 且用户明确要求 → 可纳入重规划范围。
|
|
128
128
|
|
|
129
129
|
## 执行步骤
|
|
@@ -139,7 +139,7 @@ function renderReplan(): string {
|
|
|
139
139
|
function renderImplement(): string {
|
|
140
140
|
return `# implement
|
|
141
141
|
|
|
142
|
-
实施当前计划 \`.agent-context/plan-{number}/plan.md\` 中的全部步骤,通过验证循环后将状态更新为「已执行」。
|
|
142
|
+
实施当前计划 \`.agent-context/{scope}/plan-{number}/plan.md\` 中的全部步骤,通过验证循环后将状态更新为「已执行」。
|
|
143
143
|
|
|
144
144
|
不接受额外描述。
|
|
145
145
|
|
package/src/content/index.ts
CHANGED
|
@@ -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
|
|
package/src/context/index.ts
CHANGED
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 { existsSync } from 'node:fs'
|
|
2
|
+
import { readFile, writeFile, mkdir } from 'node:fs/promises'
|
|
3
|
+
import { join } from 'node:path'
|
|
4
|
+
import { execSync } from 'node:child_process'
|
|
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
|
+
}
|