@ultime/codecraft 1.2.1 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +13 -0
- package/README.md +15 -35
- package/VERSION +1 -1
- package/adapters/README.md +1 -1
- package/docs/07-ai-prompts.md +7 -5
- package/evals/golden-tasks.md +3 -5
- package/package.json +3 -3
- package/src/cli.mjs +1 -97
- package/src/install.mjs +0 -102
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.4.0 - 2026-10-27
|
|
4
|
+
|
|
5
|
+
- 仓库改为 `skills/codecraft` 标准集合布局,可被 `skills` CLI 直接发现。
|
|
6
|
+
- 移除 `codecraft install`、agent 注册表与自定义 agent;安装改由 `npx skills add ultime-space/skills --skill codecraft` 或 `skills-npm` 负责。
|
|
7
|
+
- 发布 workflow、README、适配器与评测路径同步到集合布局。
|
|
8
|
+
|
|
9
|
+
## 1.3.0 - 2026-10-27
|
|
10
|
+
|
|
11
|
+
- 新增 agent 注册表:内置 generic / claude / cursor / trae / trae-cn,`--list-agents` 查看项目 / 全局路径与检测结果。
|
|
12
|
+
- 支持项目级 `codecraft.agents.json` 与用户级 `~/.codecraft/agents.json` 自定义 agent(project / global / markers),项目级覆盖用户级。
|
|
13
|
+
- `auto` 按注册表检测所有匹配的 agent,不优先任何一家;重复目标的 agent 自动合并,避免重复复制。
|
|
14
|
+
- 仍保留 `--dest` 作为临时目录逃生口。
|
|
15
|
+
|
|
3
16
|
## 1.2.1 - 2026-10-27
|
|
4
17
|
|
|
5
18
|
- 修复 pack 自动判定:识别 Nuxt 2 的 `pages/`、Nuxt 3 的 `app/`、uni-app 的 `manifest.json + pages.json`、Taro / uni-app 依赖,以及 workspace 内的嵌套应用。
|
package/README.md
CHANGED
|
@@ -43,44 +43,33 @@
|
|
|
43
43
|
|
|
44
44
|
## 安装
|
|
45
45
|
|
|
46
|
-
### 方式 A:
|
|
46
|
+
### 方式 A:skills CLI(推荐)
|
|
47
47
|
|
|
48
48
|
```bash
|
|
49
|
-
|
|
50
|
-
npx skills-npm setup
|
|
49
|
+
npx skills add ultime-space/skills --skill codecraft
|
|
51
50
|
```
|
|
52
51
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
### 方式 B:Codecraft 自带安装器(单次,无额外依赖)
|
|
56
|
-
|
|
57
|
-
```bash
|
|
58
|
-
npx @ultime/codecraft install
|
|
59
|
-
```
|
|
52
|
+
不传 `-a` 时,CLI 会检测本机 agent 并让你多选;`-g` 装到用户目录,`-a` 指定 agent。agent 支持由 `skills` CLI 维护,本 skill 不枚举。
|
|
60
53
|
|
|
61
|
-
|
|
54
|
+
### 方式 B:npm + skills-npm(多项目 / 团队)
|
|
62
55
|
|
|
63
56
|
```bash
|
|
64
|
-
|
|
65
|
-
npx
|
|
66
|
-
npx @ultime/codecraft install --global --agent trae-cn # Trae CN 的全局目录
|
|
67
|
-
npx @ultime/codecraft install --global --dest .trae-cn/skills # 自定义目录
|
|
68
|
-
npx @ultime/codecraft install --dry-run # 只看计划
|
|
69
|
-
npx @ultime/codecraft install --force # 覆盖已有目录
|
|
57
|
+
npm i -D @ultime/codecraft skills-npm
|
|
58
|
+
npx skills-npm setup
|
|
70
59
|
```
|
|
71
60
|
|
|
72
|
-
|
|
61
|
+
之后每次 `npm install` 都会把 `node_modules/@ultime/codecraft` 里的 skill 同步到 agent 目录:`.agents/skills/codecraft`,以及检测到的 agent 目录。需要 Node.js >= 22.20(`skills-npm` 的要求)。
|
|
73
62
|
|
|
74
63
|
### 方式 C:手动指针
|
|
75
64
|
|
|
76
65
|
不复制文件,只在项目规则里留一行:
|
|
77
66
|
|
|
78
|
-
-
|
|
67
|
+
- 通用:`AGENTS.md`
|
|
79
68
|
- Claude:`CLAUDE.md` 或 `~/.claude/CLAUDE.md`
|
|
80
|
-
-
|
|
69
|
+
- Trae:`.trae/rules/codecraft.md`
|
|
81
70
|
|
|
82
71
|
```md
|
|
83
|
-
代码任务先读 <Codecraft
|
|
72
|
+
代码任务先读 <Codecraft 仓库路径>/skills/codecraft/adapters/trae/SKILL.md
|
|
84
73
|
```
|
|
85
74
|
|
|
86
75
|
平台入口:
|
|
@@ -88,8 +77,8 @@ npx @ultime/codecraft install --force # 覆盖已有目录
|
|
|
88
77
|
| 平台 | 入口文件 |
|
|
89
78
|
|---|---|
|
|
90
79
|
| 通用(读 `AGENTS.md`) | [`adapters/generic/AGENTS.md`](./adapters/generic/AGENTS.md) |
|
|
91
|
-
| Trae | [`adapters/trae/SKILL.md`](./adapters/trae/SKILL.md) |
|
|
92
80
|
| Claude | [`adapters/claude/SKILL.md`](./adapters/claude/SKILL.md) |
|
|
81
|
+
| Trae | [`adapters/trae/SKILL.md`](./adapters/trae/SKILL.md) |
|
|
93
82
|
|
|
94
83
|
## 第一次使用
|
|
95
84
|
|
|
@@ -136,7 +125,6 @@ codecraft <command> [options]
|
|
|
136
125
|
| `audit` | 内置规则 + `codecraft.config.json` 里的 gates,出只读报告 |
|
|
137
126
|
| `plan` | 把 findings 转成只读升级计划;默认不跑 gates |
|
|
138
127
|
| `init` | 生成 app / library 骨架;默认 dry-run |
|
|
139
|
-
| `install` | 把 skill 安装到 agent skills 目录;默认写入,`--dry-run` 只看计划 |
|
|
140
128
|
| `version` | 输出版本号 |
|
|
141
129
|
|
|
142
130
|
### 常用
|
|
@@ -151,9 +139,6 @@ codecraft audit --config codecraft.config.json --fail-fast
|
|
|
151
139
|
codecraft plan --root . --with-gates
|
|
152
140
|
codecraft init --root . --name demo # dry-run
|
|
153
141
|
codecraft init --root . --name demo --apply # 写盘
|
|
154
|
-
codecraft install # 自动检测并安装
|
|
155
|
-
codecraft install --agent trae,claude --force
|
|
156
|
-
codecraft install --dry-run
|
|
157
142
|
```
|
|
158
143
|
|
|
159
144
|
### 参数
|
|
@@ -171,18 +156,13 @@ codecraft install --dry-run
|
|
|
171
156
|
| `--with-gates` | — | 关 | `plan` 执行 gates |
|
|
172
157
|
| `--name <name>` | 字符串 | — | `init` 的 app / package 名称;`--apply` 时必填 |
|
|
173
158
|
| `--apply` | — | 关 | `init` 写盘;已存在路径跳过,不覆盖 |
|
|
174
|
-
| `--agent <list>` | `auto` / `claude` / `trae` / `cursor` / `generic` | `auto` | `install` 目标,可逗号分隔 |
|
|
175
|
-
| `--global` | — | 关 | `install` 写入用户目录 |
|
|
176
|
-
| `--dest <path>` | 目录 | — | `install` 的显式目标 |
|
|
177
|
-
| `--force` | — | 关 | `install` 覆盖已有 codecraft 目录 |
|
|
178
|
-
| `--dry-run` | — | 关 | `install` 只输出计划,不写盘 |
|
|
179
159
|
|
|
180
160
|
### 退出码
|
|
181
161
|
|
|
182
162
|
| 码 | 含义 |
|
|
183
163
|
|---|---|
|
|
184
164
|
| `0` | 通过;warning 不阻断 |
|
|
185
|
-
| `1` | 有 error findings
|
|
165
|
+
| `1` | 有 error findings,或有 gate 失败 |
|
|
186
166
|
| `2` | 用法错误、root 不存在、配置非法 |
|
|
187
167
|
|
|
188
168
|
### 输出
|
|
@@ -247,7 +227,7 @@ docs/ 宪法、族卡、AI 契约、风格总图、模式、架构、AI
|
|
|
247
227
|
scenarios/ 新项目 / 旧项目审计 / 只出报告 / 重构评审
|
|
248
228
|
adapters/ generic / Trae / Claude 手动指针
|
|
249
229
|
prompts/ 输出格式
|
|
250
|
-
src/ + bin/ CLI
|
|
230
|
+
src/ + bin/ CLI(check / audit / plan / init)
|
|
251
231
|
tests/ node:test 用例
|
|
252
232
|
templates/ init --apply 的 app / library 骨架
|
|
253
233
|
evals/ golden tasks(人工回归)
|
|
@@ -263,13 +243,13 @@ ROADMAP.md 后续版本计划与交接说明
|
|
|
263
243
|
- 不按「感觉重要」升 major;`2.0` 不设时间表。
|
|
264
244
|
- 规则 ID `A1–A21` 稳定;增删规则属于 minor 以上的变更。
|
|
265
245
|
- 报告始终携带版本号;跨版本对比以 JSON 为准。
|
|
266
|
-
- 后续计划:[ROADMAP.md](https://github.com/ultime-space/skills/blob/main/codecraft/ROADMAP.md)。
|
|
246
|
+
- 后续计划:[ROADMAP.md](https://github.com/ultime-space/skills/blob/main/skills/codecraft/ROADMAP.md)。
|
|
267
247
|
|
|
268
248
|
## FAQ
|
|
269
249
|
|
|
270
250
|
- **静态检查误报怎么办?** 在 `codecraft.config.json` 的 `ignore` 里登记 `rule` + `file` + `reason`,必要时加 `expires`;不要直接删规则。
|
|
271
251
|
- **`Files: 0` 是什么意思?** 没有扫到源文件,命令会输出警告并以 2 退出;用 `--pack app|library` 指定正确类型,或检查 `--root`。
|
|
272
|
-
-
|
|
252
|
+
- **怎么装到指定 agent?** `npx skills add ultime-space/skills --skill codecraft`;交互选 agent,或用 `-a <agent>` 非交互。安装路径由 `skills` CLI 维护,本 skill 不枚举。
|
|
273
253
|
- **`check` / `audit` / `plan` 有什么区别?** `check` 只跑内置规则;`audit` 额外跑 config 里的 gates;`plan` 只读,把 findings 转成计划,默认不跑 gates。
|
|
274
254
|
- **为什么不自动跑 typecheck / test?** 门禁由项目提供,Codecraft 只编排,避免第二套实现。
|
|
275
255
|
- **monorepo 为什么被判成 app / library?** 有 `pages/`、`app/`、`manifest.json + pages.json`、Taro / uni-app 依赖或嵌套应用时按 `app`;有 `packages/` 或 `src/` 时按 `library`;仍不确定就显式传 `--pack`。
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
1.
|
|
1
|
+
1.4.0
|
package/adapters/README.md
CHANGED
|
@@ -9,6 +9,6 @@ Core 是 `docs/` + `scenarios/` + `scripts/`;adapters 只做入口,不复制
|
|
|
9
9
|
|
|
10
10
|
规则:adapter 只写“读什么、按什么流程、输出什么”,规则正文留在 `docs/`。
|
|
11
11
|
|
|
12
|
-
包根的 [`SKILL.md`](../SKILL.md) 是标准 agent skill 入口(`skills
|
|
12
|
+
包根的 [`SKILL.md`](../SKILL.md) 是标准 agent skill 入口(`skills add` / `skills-npm` 使用);本目录的平台文件用于手动指针接入。两者二选一,不要同时维护两套正文。
|
|
13
13
|
|
|
14
14
|
使用者提示词(怎么对 AI 说):[`../docs/07-ai-prompts.md`](../docs/07-ai-prompts.md)。
|
package/docs/07-ai-prompts.md
CHANGED
|
@@ -10,9 +10,11 @@
|
|
|
10
10
|
最快的方式:
|
|
11
11
|
|
|
12
12
|
```bash
|
|
13
|
-
npx
|
|
13
|
+
npx skills add ultime-space/skills --skill codecraft
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
+
交互选择 agent;非交互用 `-a <agent>`,全局加 `-g`。
|
|
17
|
+
|
|
16
18
|
或走 npm 同步:
|
|
17
19
|
|
|
18
20
|
```bash
|
|
@@ -24,12 +26,12 @@ npx skills-npm setup
|
|
|
24
26
|
|
|
25
27
|
也可以手动在 agent 入口里留一条指针,不要复制规则:
|
|
26
28
|
|
|
27
|
-
- Trae:项目 `.trae/rules/codecraft.md`
|
|
28
|
-
- Claude:`CLAUDE.md`
|
|
29
29
|
- 通用:`AGENTS.md`
|
|
30
|
+
- Claude:`CLAUDE.md`
|
|
31
|
+
- Trae:项目 `.trae/rules/codecraft.md`
|
|
30
32
|
|
|
31
33
|
```md
|
|
32
|
-
代码任务先读 <Codecraft 仓库路径>/codecraft/adapters/<平台>/...
|
|
34
|
+
代码任务先读 <Codecraft 仓库路径>/skills/codecraft/adapters/<平台>/...
|
|
33
35
|
```
|
|
34
36
|
|
|
35
37
|
平台对应:Trae → `adapters/trae/SKILL.md`,Claude → `adapters/claude/SKILL.md`,其他 → `adapters/generic/AGENTS.md`。
|
|
@@ -39,7 +41,7 @@ npx skills-npm setup
|
|
|
39
41
|
任何任务都可以先用这段,再补场景:
|
|
40
42
|
|
|
41
43
|
```text
|
|
42
|
-
使用 Codecraft(<Codecraft 仓库路径>/codecraft)。
|
|
44
|
+
使用 Codecraft(<Codecraft 仓库路径>/skills/codecraft)。
|
|
43
45
|
模式:Audit / Plan / Apply。
|
|
44
46
|
范围:<目录 / 包 / 文件 / diff>。
|
|
45
47
|
任务:<一句话>。
|
package/evals/golden-tasks.md
CHANGED
|
@@ -109,12 +109,10 @@
|
|
|
109
109
|
- 期望:命中 A21;只报文件与行号,不回显密钥;提示轮换。
|
|
110
110
|
- 失败信号:漏报;把密钥原文打印到报告;把普通变量名误报为密钥。
|
|
111
111
|
|
|
112
|
-
## 16.
|
|
112
|
+
## 16. 安装(已移出本 skill)
|
|
113
113
|
|
|
114
|
-
-
|
|
115
|
-
-
|
|
116
|
-
- 期望:生成 `.agents/skills/codecraft/SKILL.md`、`docs/`、`scenarios/`、`prompts/`;第二次 skip;`--force` 覆盖。
|
|
117
|
-
- 失败信号:复制到错误目录;覆盖用户已有内容;`SKILL.md` 引用断链。
|
|
114
|
+
- 安装由 `skills` CLI 负责:`npx skills add ultime-space/skills --skill codecraft`。
|
|
115
|
+
- 不在 Codecraft 规则评估范围内;本文件不再评估安装器行为。
|
|
118
116
|
|
|
119
117
|
## 评分
|
|
120
118
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ultime/codecraft",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "面向 JS/TS 的代码规范与架构设计(前端默认,Node 后端可复用结构规则),作为可安装的 skill 包。",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
@@ -18,9 +18,9 @@
|
|
|
18
18
|
"repository": {
|
|
19
19
|
"type": "git",
|
|
20
20
|
"url": "git+https://github.com/ultime-space/skills.git",
|
|
21
|
-
"directory": "codecraft"
|
|
21
|
+
"directory": "skills/codecraft"
|
|
22
22
|
},
|
|
23
|
-
"homepage": "https://github.com/ultime-space/skills/tree/main/codecraft",
|
|
23
|
+
"homepage": "https://github.com/ultime-space/skills/tree/main/skills/codecraft",
|
|
24
24
|
"bugs": {
|
|
25
25
|
"url": "https://github.com/ultime-space/skills/issues"
|
|
26
26
|
},
|
package/src/cli.mjs
CHANGED
|
@@ -5,7 +5,6 @@ import { loadConfig, runGates } from './gates.mjs'
|
|
|
5
5
|
import { buildPlan, summarizePlan } from './plan.mjs'
|
|
6
6
|
import { applyInitPlan, buildInitPlan } from './init.mjs'
|
|
7
7
|
import { applyIgnores } from './ignore.mjs'
|
|
8
|
-
import { applyInstallPlan, buildInstallPlan, parseAgents } from './install.mjs'
|
|
9
8
|
|
|
10
9
|
const PACKAGE = JSON.parse(fs.readFileSync(new URL('../package.json', import.meta.url), 'utf8'))
|
|
11
10
|
const VERSION = PACKAGE.version
|
|
@@ -17,18 +16,12 @@ Commands:
|
|
|
17
16
|
audit check + configured gates; read-only report
|
|
18
17
|
plan Read-only upgrade plan from findings
|
|
19
18
|
init Scaffold an app or package (dry-run unless --apply)
|
|
20
|
-
install Install the skill into agent skills directories
|
|
21
19
|
version Print version
|
|
22
20
|
|
|
23
21
|
Options:
|
|
24
22
|
--root <path> Project root (default: cwd)
|
|
25
23
|
--pack app|library|design-system|auto Rule pack (default: auto)
|
|
26
24
|
--config <path> Config file (default: codecraft.config.json)
|
|
27
|
-
--agent auto|generic|claude|cursor|trae|trae-cn Install target, comma-separated (default: auto)
|
|
28
|
-
--global Install into the home directory
|
|
29
|
-
--dest <path> Explicit destination (relative to root / home), e.g. .trae-cn/skills
|
|
30
|
-
--force Replace an existing codecraft skill directory
|
|
31
|
-
--dry-run Show the install plan without writing
|
|
32
25
|
--no-gates Skip gates in audit / plan
|
|
33
26
|
--with-gates Run configured gates in plan
|
|
34
27
|
--fail-fast Stop gates after the first failure
|
|
@@ -59,7 +52,7 @@ export function main(argv) {
|
|
|
59
52
|
}
|
|
60
53
|
|
|
61
54
|
const command = args.command || 'check'
|
|
62
|
-
if (!['check', 'audit', 'plan', 'init'
|
|
55
|
+
if (!['check', 'audit', 'plan', 'init'].includes(command)) {
|
|
63
56
|
console.error(`codecraft: unknown command "${command}"\n next: run codecraft --help`)
|
|
64
57
|
return 2
|
|
65
58
|
}
|
|
@@ -70,42 +63,6 @@ export function main(argv) {
|
|
|
70
63
|
return 2
|
|
71
64
|
}
|
|
72
65
|
|
|
73
|
-
if (command === 'install') {
|
|
74
|
-
let agents
|
|
75
|
-
try {
|
|
76
|
-
agents = parseAgents(args.agent)
|
|
77
|
-
} catch (error) {
|
|
78
|
-
console.error(`codecraft: ${error.message}`)
|
|
79
|
-
return 2
|
|
80
|
-
}
|
|
81
|
-
try {
|
|
82
|
-
const plan = buildInstallPlan(root, { agents, global: args.global, dest: args.dest })
|
|
83
|
-
const applied = args.dryRun ? null : applyInstallPlan(plan, { force: args.force })
|
|
84
|
-
const meta = {
|
|
85
|
-
version: VERSION,
|
|
86
|
-
mode: 'install',
|
|
87
|
-
root,
|
|
88
|
-
scope: args.global ? 'global' : 'project',
|
|
89
|
-
agent: args.agent,
|
|
90
|
-
dest: args.dest || null,
|
|
91
|
-
dryRun: args.dryRun,
|
|
92
|
-
targets: plan.length,
|
|
93
|
-
created: applied?.created.length ?? 0,
|
|
94
|
-
replaced: applied?.replaced.length ?? 0,
|
|
95
|
-
skipped: applied?.skipped.length ?? 0,
|
|
96
|
-
}
|
|
97
|
-
if (args.format === 'json') {
|
|
98
|
-
console.log(JSON.stringify({ ...meta, plan, applied }, null, 2))
|
|
99
|
-
} else {
|
|
100
|
-
console.log(formatInstall(meta, plan, applied))
|
|
101
|
-
}
|
|
102
|
-
return plan.length ? 0 : 1
|
|
103
|
-
} catch (error) {
|
|
104
|
-
console.error(`codecraft: ${error.message}`)
|
|
105
|
-
return 1
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
|
|
109
66
|
let config
|
|
110
67
|
try {
|
|
111
68
|
config = loadConfig(root, args.config)
|
|
@@ -243,11 +200,6 @@ function parseArgs(argv) {
|
|
|
243
200
|
failFast: false,
|
|
244
201
|
name: '',
|
|
245
202
|
apply: false,
|
|
246
|
-
agent: 'auto',
|
|
247
|
-
global: false,
|
|
248
|
-
dest: '',
|
|
249
|
-
force: false,
|
|
250
|
-
dryRun: false,
|
|
251
203
|
format: 'md',
|
|
252
204
|
severity: 'warn',
|
|
253
205
|
ci: false,
|
|
@@ -264,12 +216,7 @@ function parseArgs(argv) {
|
|
|
264
216
|
else if (arg === '--with-gates') args.withGates = true
|
|
265
217
|
else if (arg === '--fail-fast') args.failFast = true
|
|
266
218
|
else if (arg === '--apply') args.apply = true
|
|
267
|
-
else if (arg === '--global') args.global = true
|
|
268
|
-
else if (arg === '--force') args.force = true
|
|
269
|
-
else if (arg === '--dry-run') args.dryRun = true
|
|
270
219
|
else if (arg === '--name') args.name = argv[++i] ?? ''
|
|
271
|
-
else if (arg === '--agent') args.agent = argv[++i] ?? 'auto'
|
|
272
|
-
else if (arg === '--dest') args.dest = argv[++i] ?? ''
|
|
273
220
|
else if (arg === '--root') args.root = argv[++i] ?? '.'
|
|
274
221
|
else if (arg === '--pack') args.pack = argv[++i] ?? 'auto'
|
|
275
222
|
else if (arg === '--config') args.config = argv[++i] ?? ''
|
|
@@ -501,49 +448,6 @@ function formatInit(meta, plan, applied) {
|
|
|
501
448
|
return lines.filter((line, index) => !(line === '' && lines[index - 1] === '')).join('\n')
|
|
502
449
|
}
|
|
503
450
|
|
|
504
|
-
function formatInstall(meta, plan, applied) {
|
|
505
|
-
const lines = [
|
|
506
|
-
'# Codecraft Install',
|
|
507
|
-
'',
|
|
508
|
-
`- Version: ${meta.version}`,
|
|
509
|
-
`- Mode: install`,
|
|
510
|
-
`- Scope: ${meta.scope}`,
|
|
511
|
-
`- Agent: ${meta.agent}`,
|
|
512
|
-
`- Root: ${meta.root}`,
|
|
513
|
-
`- Dest: ${meta.dest ?? '(auto)'}`,
|
|
514
|
-
`- Dry run: ${meta.dryRun}`,
|
|
515
|
-
`- Targets: ${meta.targets}`,
|
|
516
|
-
]
|
|
517
|
-
|
|
518
|
-
if (applied) {
|
|
519
|
-
lines.push(
|
|
520
|
-
`- Created: ${meta.created}`,
|
|
521
|
-
`- Replaced: ${meta.replaced}`,
|
|
522
|
-
`- Skipped: ${meta.skipped}`,
|
|
523
|
-
)
|
|
524
|
-
}
|
|
525
|
-
|
|
526
|
-
if (!plan.length) {
|
|
527
|
-
lines.push('', '未找到可安装的目标;请用 `--agent` 指定,或先创建 agent 配置目录。')
|
|
528
|
-
} else {
|
|
529
|
-
lines.push('', '## Plan', '', '| Agent | Target | Action |', '|---|---|---|')
|
|
530
|
-
for (const entry of plan) {
|
|
531
|
-
lines.push(`| ${entry.agent} | ${entry.target} | ${entry.action} |`)
|
|
532
|
-
}
|
|
533
|
-
}
|
|
534
|
-
|
|
535
|
-
lines.push(
|
|
536
|
-
'',
|
|
537
|
-
'## Next',
|
|
538
|
-
'',
|
|
539
|
-
meta.dryRun
|
|
540
|
-
? '- Re-run without `--dry-run` to write the skill.'
|
|
541
|
-
: '- Restart the agent or reload skills;然后说:`用 Codecraft 审计本项目,只读,不改文件。`',
|
|
542
|
-
)
|
|
543
|
-
|
|
544
|
-
return lines.join('\n')
|
|
545
|
-
}
|
|
546
|
-
|
|
547
451
|
function header(meta) {
|
|
548
452
|
return [
|
|
549
453
|
`# Codecraft ${title(meta.mode)}`,
|
package/src/install.mjs
DELETED
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
import fs from 'node:fs'
|
|
2
|
-
import os from 'node:os'
|
|
3
|
-
import path from 'node:path'
|
|
4
|
-
import { fileURLToPath } from 'node:url'
|
|
5
|
-
|
|
6
|
-
const PACKAGE_ROOT = fileURLToPath(new URL('..', import.meta.url))
|
|
7
|
-
const SKILL_FILES = ['SKILL.md']
|
|
8
|
-
const SKILL_DIRS = ['docs', 'scenarios', 'prompts']
|
|
9
|
-
|
|
10
|
-
const AGENT_DIRS = {
|
|
11
|
-
generic: '.agents/skills',
|
|
12
|
-
claude: '.claude/skills',
|
|
13
|
-
cursor: '.cursor/skills',
|
|
14
|
-
trae: '.trae/skills',
|
|
15
|
-
'trae-cn': '.trae-cn/skills',
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
const AGENT_MARKERS = {
|
|
19
|
-
generic: ['.agents'],
|
|
20
|
-
claude: ['.claude', 'CLAUDE.md'],
|
|
21
|
-
cursor: ['.cursor'],
|
|
22
|
-
trae: ['.trae'],
|
|
23
|
-
'trae-cn': ['.trae-cn'],
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export const AGENTS = Object.keys(AGENT_DIRS)
|
|
27
|
-
|
|
28
|
-
export function parseAgents(value) {
|
|
29
|
-
if (!value || value === 'auto') return []
|
|
30
|
-
const agents = [...new Set(value.split(',').map((item) => item.trim()).filter(Boolean))]
|
|
31
|
-
const invalid = agents.filter((agent) => !AGENTS.includes(agent))
|
|
32
|
-
if (invalid.length) {
|
|
33
|
-
throw new Error(`unknown agent: ${invalid.join(', ')}(可选:auto, ${AGENTS.join(', ')})`)
|
|
34
|
-
}
|
|
35
|
-
return agents
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export function buildInstallPlan(root, options = {}) {
|
|
39
|
-
const base = options.global ? os.homedir() : path.resolve(root)
|
|
40
|
-
const explicit = options.agents ?? []
|
|
41
|
-
const invalid = explicit.filter((agent) => !AGENTS.includes(agent))
|
|
42
|
-
if (invalid.length) {
|
|
43
|
-
throw new Error(`unknown agent: ${invalid.join(', ')}(可选:${AGENTS.join(', ')})`)
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
const agents = explicit.length ? explicit : detectAgents(base, options.global)
|
|
47
|
-
const destinations = options.dest
|
|
48
|
-
? [{ agent: 'custom', dir: path.resolve(base, options.dest) }]
|
|
49
|
-
: agents.map((agent) => ({ agent, dir: path.join(base, AGENT_DIRS[agent]) }))
|
|
50
|
-
|
|
51
|
-
assertSource()
|
|
52
|
-
|
|
53
|
-
return destinations.map(({ agent, dir }) => {
|
|
54
|
-
const target = path.join(dir, 'codecraft')
|
|
55
|
-
const exists = fs.existsSync(target)
|
|
56
|
-
return { agent, target, exists, action: exists ? 'exists' : 'create' }
|
|
57
|
-
})
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
export function applyInstallPlan(plan, options = {}) {
|
|
61
|
-
const created = []
|
|
62
|
-
const skipped = []
|
|
63
|
-
const replaced = []
|
|
64
|
-
|
|
65
|
-
for (const entry of plan) {
|
|
66
|
-
if (entry.exists && !options.force) {
|
|
67
|
-
skipped.push(entry.target)
|
|
68
|
-
continue
|
|
69
|
-
}
|
|
70
|
-
if (entry.exists) {
|
|
71
|
-
fs.rmSync(entry.target, { recursive: true, force: true })
|
|
72
|
-
replaced.push(entry.target)
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
fs.mkdirSync(entry.target, { recursive: true })
|
|
76
|
-
for (const file of SKILL_FILES) {
|
|
77
|
-
fs.copyFileSync(path.join(PACKAGE_ROOT, file), path.join(entry.target, file))
|
|
78
|
-
}
|
|
79
|
-
for (const dir of SKILL_DIRS) {
|
|
80
|
-
fs.cpSync(path.join(PACKAGE_ROOT, dir), path.join(entry.target, dir), { recursive: true })
|
|
81
|
-
}
|
|
82
|
-
created.push(entry.target)
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
return { created, skipped, replaced }
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
function detectAgents(base, global) {
|
|
89
|
-
const found = AGENTS.filter((agent) =>
|
|
90
|
-
AGENT_MARKERS[agent].some((marker) => fs.existsSync(path.join(base, marker))),
|
|
91
|
-
)
|
|
92
|
-
if (global) return found.length ? found : ['generic']
|
|
93
|
-
return [...new Set([...found, 'generic'])]
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
function assertSource() {
|
|
97
|
-
for (const file of SKILL_FILES) {
|
|
98
|
-
if (!fs.existsSync(path.join(PACKAGE_ROOT, file))) {
|
|
99
|
-
throw new Error(`skill source is incomplete: missing ${file}`)
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
}
|