@cli-skill/cli 0.0.1-beta.20260402075508 → 0.0.1-beta.20260402142556
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 +58 -21
- package/package.json +3 -4
- package/skill/SKILL.md +48 -29
- package/skill/references/core.md +14 -6
- package/src/app.ts +2 -2
- package/src/build.ts +55 -27
- package/src/bun.ts +32 -2
- package/src/commands/config.ts +33 -4
- package/src/commands/create.ts +2 -0
- package/src/commands/install.ts +8 -10
- package/src/commands/list.ts +17 -22
- package/src/commands/skill.ts +56 -147
- package/src/commands/uninstall.ts +13 -5
- package/src/project.ts +7 -8
- package/src/registry.ts +192 -191
- package/test/registry.test.ts +74 -0
package/README.md
CHANGED
|
@@ -2,13 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
`@cli-skill/cli` 是 `cli-skill` 的平台命令行入口。
|
|
4
4
|
|
|
5
|
-
它不是某一个具体 skill 的运行时,而是整个 skill
|
|
5
|
+
它不是某一个具体 skill 的运行时,而是整个 skill 生命周期和本地注册表的管理入口。
|
|
6
6
|
|
|
7
7
|
## 主要职责
|
|
8
8
|
|
|
9
9
|
- 创建新的 skill 项目
|
|
10
|
-
-
|
|
11
|
-
-
|
|
10
|
+
- 维护本地 skill 注册表
|
|
11
|
+
- 提供当前目录命令和已注册 skill 执行入口
|
|
12
|
+
- 生成 `skill/` 产物
|
|
12
13
|
- 安装和卸载已发布 skill
|
|
13
14
|
- 挂载和取消挂载本地 skill
|
|
14
15
|
- 发布本地 skill
|
|
@@ -21,34 +22,36 @@
|
|
|
21
22
|
```bash
|
|
22
23
|
cli-skill create <skillName> --cli-name <cliName> [--template <templateName>]
|
|
23
24
|
cli-skill list
|
|
25
|
+
cli-skill tools <skillName>
|
|
24
26
|
cli-skill install <skillName> [--packageName <packageName>]
|
|
25
27
|
cli-skill uninstall <packageName>
|
|
26
28
|
cli-skill config get [keyPath]
|
|
27
29
|
cli-skill config set <keyPath> <value>
|
|
30
|
+
cli-skill exec <skillName> <toolName> [rawInput]
|
|
28
31
|
```
|
|
29
32
|
|
|
30
|
-
###
|
|
33
|
+
### 当前目录命令
|
|
31
34
|
|
|
32
35
|
```bash
|
|
33
|
-
cli-skill
|
|
34
|
-
cli-skill
|
|
35
|
-
cli-skill
|
|
36
|
-
cli-skill
|
|
37
|
-
cli-skill
|
|
38
|
-
cli-skill
|
|
39
|
-
cli-skill
|
|
40
|
-
cli-skill
|
|
41
|
-
cli-skill
|
|
36
|
+
cli-skill tools
|
|
37
|
+
cli-skill run <toolName> [rawInput]
|
|
38
|
+
cli-skill config get [keyPath]
|
|
39
|
+
cli-skill config set <keyPath> <value>
|
|
40
|
+
cli-skill config unset <keyPath>
|
|
41
|
+
cli-skill build
|
|
42
|
+
cli-skill mount [targetPath]
|
|
43
|
+
cli-skill unmount [targetPath]
|
|
44
|
+
cli-skill publish [--dry-run] [--tag <tag>]
|
|
42
45
|
```
|
|
43
46
|
|
|
44
47
|
## 典型工作流
|
|
45
48
|
|
|
46
49
|
```bash
|
|
47
50
|
cli-skill create my-skill --cli-name my-skill
|
|
48
|
-
cd
|
|
51
|
+
cd ./my-skill
|
|
49
52
|
bun install
|
|
50
|
-
cli-skill
|
|
51
|
-
cli-skill
|
|
53
|
+
cli-skill build
|
|
54
|
+
cli-skill mount
|
|
52
55
|
```
|
|
53
56
|
|
|
54
57
|
## skill 项目结构
|
|
@@ -68,7 +71,14 @@ cli-skill my-skill mount
|
|
|
68
71
|
- `src/skill/*`
|
|
69
72
|
- 文档模板源目录
|
|
70
73
|
|
|
71
|
-
|
|
74
|
+
模板生成出来的 skill 包会同时依赖:
|
|
75
|
+
|
|
76
|
+
- `@cli-skill/core`
|
|
77
|
+
- 运行 skill
|
|
78
|
+
- `@cli-skill/cli`
|
|
79
|
+
- 在项目目录内调用 `cli-skill build`、`cli-skill mount` 等命令
|
|
80
|
+
|
|
81
|
+
执行 `cli-skill build` 后会生成:
|
|
72
82
|
|
|
73
83
|
- `skill/SKILL.md`
|
|
74
84
|
- `skill/agents/openai.yaml`
|
|
@@ -80,7 +90,7 @@ cli-skill my-skill mount
|
|
|
80
90
|
|
|
81
91
|
## build 输入
|
|
82
92
|
|
|
83
|
-
`cli-skill
|
|
93
|
+
`cli-skill build` 会读取:
|
|
84
94
|
|
|
85
95
|
- `src/index.ts`
|
|
86
96
|
- `src/skill/`
|
|
@@ -97,13 +107,17 @@ cli-skill my-skill mount
|
|
|
97
107
|
|
|
98
108
|
## 安装模型
|
|
99
109
|
|
|
100
|
-
|
|
110
|
+
本地创建的 skill 默认放在当前目录:
|
|
111
|
+
|
|
112
|
+
- `./<skill-name>`
|
|
113
|
+
|
|
114
|
+
已安装 skill 默认放在:
|
|
101
115
|
|
|
102
116
|
- `~/.cli-skill/skills`
|
|
103
117
|
|
|
104
|
-
|
|
118
|
+
本地注册表默认放在:
|
|
105
119
|
|
|
106
|
-
- `~/.cli-skill/
|
|
120
|
+
- `~/.cli-skill/registry.json`
|
|
107
121
|
|
|
108
122
|
默认 agent 目录是:
|
|
109
123
|
|
|
@@ -121,3 +135,26 @@ cli-skill my-skill mount
|
|
|
121
135
|
```bash
|
|
122
136
|
cli-skill install fx --packageName @scope/cli-skill-fx
|
|
123
137
|
```
|
|
138
|
+
|
|
139
|
+
## skill bin 的行为
|
|
140
|
+
|
|
141
|
+
生成出来的 skill 自带一个很薄的 bin。
|
|
142
|
+
|
|
143
|
+
例如:
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
my-skill list
|
|
147
|
+
my-skill open_page '{"url":"https://example.com"}'
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
它适合做:
|
|
151
|
+
|
|
152
|
+
- 查看这个 skill 的 tool 列表
|
|
153
|
+
- 直接执行某个 tool
|
|
154
|
+
|
|
155
|
+
它不承担项目管理命令。以下操作仍然只通过 `cli-skill` 使用:
|
|
156
|
+
|
|
157
|
+
- `build`
|
|
158
|
+
- `mount`
|
|
159
|
+
- `unmount`
|
|
160
|
+
- `publish`
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cli-skill/cli",
|
|
3
|
-
"version": "0.0.1-beta.
|
|
3
|
+
"version": "0.0.1-beta.20260402142556",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./src/index.ts",
|
|
6
6
|
"types": "./src/index.ts",
|
|
@@ -14,13 +14,12 @@
|
|
|
14
14
|
}
|
|
15
15
|
},
|
|
16
16
|
"scripts": {
|
|
17
|
-
"build": "tsc -p tsconfig.json",
|
|
18
17
|
"test": "tsc -p tsconfig.test.json && bun test ./test"
|
|
19
18
|
},
|
|
20
19
|
"dependencies": {
|
|
21
|
-
"@cli-skill/core": "^0.0.1-beta.
|
|
20
|
+
"@cli-skill/core": "^0.0.1-beta.20260402142556",
|
|
22
21
|
"cac": "^6.7.14",
|
|
23
22
|
"lodash": "^4.17.21",
|
|
24
|
-
"zod": "^3.
|
|
23
|
+
"zod": "^4.3.6"
|
|
25
24
|
}
|
|
26
25
|
}
|
package/skill/SKILL.md
CHANGED
|
@@ -23,18 +23,32 @@ description: 当任务涉及 cli skill 的创建、挂载、安装、发布或
|
|
|
23
23
|
|
|
24
24
|
## 工作模型
|
|
25
25
|
|
|
26
|
-
处理 cli skill
|
|
26
|
+
处理 cli skill 时,默认按三类命令来理解:
|
|
27
27
|
|
|
28
28
|
- 平台命令
|
|
29
29
|
- `cli-skill create`
|
|
30
30
|
- `cli-skill list`
|
|
31
|
+
- `cli-skill tools <skill-name>`
|
|
31
32
|
- `cli-skill install`
|
|
32
33
|
- `cli-skill uninstall`
|
|
33
34
|
- `cli-skill config ...`
|
|
34
|
-
-
|
|
35
|
-
- `cli-skill
|
|
35
|
+
- 当前目录命令
|
|
36
|
+
- `cli-skill tools`
|
|
37
|
+
- `cli-skill run`
|
|
38
|
+
- `cli-skill build`
|
|
39
|
+
- `cli-skill mount`
|
|
40
|
+
- `cli-skill publish`
|
|
41
|
+
- 已注册 skill 执行命令
|
|
42
|
+
- `cli-skill exec <skill-name> ...`
|
|
36
43
|
|
|
37
|
-
skill 自己的 bin
|
|
44
|
+
skill 自己的 bin 只是一个转发入口:
|
|
45
|
+
|
|
46
|
+
- `skill-name list`
|
|
47
|
+
- 查看这个 skill 的 tools
|
|
48
|
+
- `skill-name <tool>`
|
|
49
|
+
- 执行这个 skill 的 tool
|
|
50
|
+
|
|
51
|
+
项目级命令仍然通过 `cli-skill` 使用,不通过 skill bin 使用。
|
|
38
52
|
|
|
39
53
|
## 默认流程
|
|
40
54
|
|
|
@@ -42,9 +56,10 @@ skill 自己的 bin 只是一个转发入口,仍然会落到 `cli-skill <skill
|
|
|
42
56
|
|
|
43
57
|
```bash
|
|
44
58
|
cli-skill create <skill-name> --cli-name <cli-name>
|
|
59
|
+
cd ./<skill-name>
|
|
45
60
|
bun install
|
|
46
|
-
cli-skill
|
|
47
|
-
cli-skill
|
|
61
|
+
cli-skill build
|
|
62
|
+
cli-skill mount
|
|
48
63
|
```
|
|
49
64
|
|
|
50
65
|
如果没有提供 `cli-name`,默认令它等于 `skill-name`。
|
|
@@ -66,13 +81,7 @@ cli-skill <skill-name> mount
|
|
|
66
81
|
- `src/skill/*`
|
|
67
82
|
- 文档模板源目录
|
|
68
83
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
```bash
|
|
72
|
-
cli-skill <skill-name> build
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
会生成:
|
|
84
|
+
执行 `cli-skill build` 会生成:
|
|
76
85
|
|
|
77
86
|
- `skill/SKILL.md`
|
|
78
87
|
- `skill/agents/openai.yaml`
|
|
@@ -83,17 +92,19 @@ cli-skill <skill-name> build
|
|
|
83
92
|
| --- | --- |
|
|
84
93
|
| 创建 skill | `cli-skill create <skill-name> --cli-name <cli-name> [--template <templateName>]` |
|
|
85
94
|
| 查看 skill 列表 | `cli-skill list` |
|
|
95
|
+
| 查看已注册 skill 的 tool 列表 | `cli-skill tools <skill-name>` |
|
|
86
96
|
| 安装已发布 skill | `cli-skill install <skill-name>` |
|
|
87
97
|
| 卸载已发布 skill | `cli-skill uninstall <package-name>` |
|
|
88
|
-
| 查看 tool 列表 | `cli-skill
|
|
89
|
-
|
|
|
90
|
-
|
|
|
91
|
-
|
|
|
92
|
-
|
|
|
93
|
-
|
|
|
94
|
-
|
|
|
95
|
-
|
|
|
96
|
-
|
|
|
98
|
+
| 查看 tool 列表 | `cli-skill tools` |
|
|
99
|
+
| 运行当前目录 tool | `cli-skill run <tool-name> [rawInput]` |
|
|
100
|
+
| 运行已注册 skill 的 tool | `cli-skill exec <skill-name> <tool-name> [rawInput]` |
|
|
101
|
+
| 读取当前 skill 配置 | `cli-skill config get [keyPath]` |
|
|
102
|
+
| 写入当前 skill 配置 | `cli-skill config set <keyPath> <value>` |
|
|
103
|
+
| 删除当前 skill 配置 | `cli-skill config unset <keyPath>` |
|
|
104
|
+
| 挂载当前 skill | `cli-skill mount [targetPath]` |
|
|
105
|
+
| 取消挂载当前 skill | `cli-skill unmount [targetPath]` |
|
|
106
|
+
| 构建 skill 产物 | `cli-skill build` |
|
|
107
|
+
| 发布当前 skill | `cli-skill publish [--dry-run] [--tag <tag>]` |
|
|
97
108
|
| 读取全局配置 | `cli-skill config get [keyPath]` |
|
|
98
109
|
| 写入全局配置 | `cli-skill config set <keyPath> <value>` |
|
|
99
110
|
|
|
@@ -106,14 +117,20 @@ cli-skill <skill-name> build
|
|
|
106
117
|
- 注册根目录 `skill/` 到 agent 目录
|
|
107
118
|
- `mount` 不应隐式执行 `install`。
|
|
108
119
|
- `install` / `uninstall` 面向已发布 skill。
|
|
109
|
-
- `publish`
|
|
120
|
+
- `publish` 只针对当前目录的本地 skill。
|
|
121
|
+
- skill bin 只负责:
|
|
122
|
+
- `list`
|
|
123
|
+
- 直接执行 tool
|
|
124
|
+
- `config get/set/unset`
|
|
110
125
|
|
|
111
126
|
默认目录:
|
|
112
127
|
|
|
113
|
-
-
|
|
128
|
+
- 当前目录创建的 skill:
|
|
129
|
+
- `./<skill-name>`
|
|
130
|
+
- 已安装 skill:
|
|
114
131
|
- `~/.cli-skill/skills/<skill-name>`
|
|
115
|
-
-
|
|
116
|
-
- `~/.cli-skill/
|
|
132
|
+
- 本地注册表:
|
|
133
|
+
- `~/.cli-skill/registry.json`
|
|
117
134
|
- agent 默认目录:
|
|
118
135
|
- `~/.agents/skills/<skill-name>`
|
|
119
136
|
|
|
@@ -132,8 +149,9 @@ skill 作用域配置路径:
|
|
|
132
149
|
```bash
|
|
133
150
|
cli-skill config get
|
|
134
151
|
cli-skill config set skillsRoot ~/.cli-skill/skills
|
|
135
|
-
|
|
136
|
-
cli-skill
|
|
152
|
+
cd ./<skill-name>
|
|
153
|
+
cli-skill config get
|
|
154
|
+
cli-skill config set baseUrl https://example.com
|
|
137
155
|
```
|
|
138
156
|
|
|
139
157
|
## 文档规则
|
|
@@ -143,7 +161,7 @@ cli-skill <skill-name> config set baseUrl https://example.com
|
|
|
143
161
|
- tool 或配置变更后,应重新执行:
|
|
144
162
|
|
|
145
163
|
```bash
|
|
146
|
-
cli-skill
|
|
164
|
+
cli-skill build
|
|
147
165
|
```
|
|
148
166
|
|
|
149
167
|
## 不要做的事
|
|
@@ -151,4 +169,5 @@ cli-skill <skill-name> build
|
|
|
151
169
|
- 不要把 `create` 当成“已经可执行”
|
|
152
170
|
- 不要手动改 `~/.agents/skills`
|
|
153
171
|
- 不要把 skill bin 当成独立平台
|
|
172
|
+
- 不要期待 skill bin 提供 `build` / `mount` / `publish`
|
|
154
173
|
- 不要在修改已有 skill 时重新 `create`
|
package/skill/references/core.md
CHANGED
|
@@ -14,11 +14,11 @@
|
|
|
14
14
|
- 真正执行动作的最小单元
|
|
15
15
|
- `skill`
|
|
16
16
|
- 对 tools 的组织与描述
|
|
17
|
-
- `
|
|
17
|
+
- `skill/` 产物
|
|
18
18
|
- 给 agent 使用的 `skill/` 目录
|
|
19
19
|
|
|
20
20
|
源码不是直接写给 agent 的。
|
|
21
|
-
源码先定义 skill 和 tools,然后再由 `build` 生成 agent 真正消费的产物。
|
|
21
|
+
源码先定义 skill 和 tools,然后再由 `cli-skill build` 生成 agent 真正消费的产物。
|
|
22
22
|
|
|
23
23
|
## skill 项目源码结构
|
|
24
24
|
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
执行:
|
|
41
41
|
|
|
42
42
|
```bash
|
|
43
|
-
cli-skill
|
|
43
|
+
cli-skill build
|
|
44
44
|
```
|
|
45
45
|
|
|
46
46
|
之后,根目录会生成:
|
|
@@ -67,6 +67,8 @@ cli-skill <skill-name> build
|
|
|
67
67
|
|
|
68
68
|
也就是说,skill 只做“组织”和“说明”,不直接承担运行时能力注入。
|
|
69
69
|
|
|
70
|
+
命令解析也不在 `core`。`core` 只负责类型、runtime、tool 执行。
|
|
71
|
+
|
|
70
72
|
## `defineTool` 负责什么
|
|
71
73
|
|
|
72
74
|
`defineTool` 才是运行能力的核心。
|
|
@@ -179,11 +181,11 @@ export default defineSkill({
|
|
|
179
181
|
|
|
180
182
|
- `tool` 负责声明自己要 `browserPlugin`
|
|
181
183
|
- `skill` 只负责把它组织起来
|
|
182
|
-
- `build` 再负责生成 `skill/` 产物
|
|
184
|
+
- `cli-skill build` 再负责生成 `skill/` 产物
|
|
183
185
|
|
|
184
186
|
## 文档模板怎么写
|
|
185
187
|
|
|
186
|
-
`src/skill/*` 下的 `.md/.yaml/.yml` 文件会在 build 时做变量替换。
|
|
188
|
+
`src/skill/*` 下的 `.md/.yaml/.yml` 文件会在 `cli-skill build` 时做变量替换。
|
|
187
189
|
|
|
188
190
|
当前常用变量有:
|
|
189
191
|
|
|
@@ -211,13 +213,19 @@ export default defineSkill({
|
|
|
211
213
|
|
|
212
214
|
这也是为什么生成出来的 skill 模板会把 `zod` 放在自己的 `dependencies` 里。
|
|
213
215
|
|
|
216
|
+
生成出来的 skill 模板还会把 `@cli-skill/cli` 放进 `devDependencies`,用于在 skill 项目目录里直接执行:
|
|
217
|
+
|
|
218
|
+
- `cli-skill build`
|
|
219
|
+
- `cli-skill mount`
|
|
220
|
+
- `cli-skill publish`
|
|
221
|
+
|
|
214
222
|
## 什么时候继续往下看
|
|
215
223
|
|
|
216
224
|
如果你需要的是:
|
|
217
225
|
|
|
218
226
|
- 怎么创建 skill
|
|
219
227
|
- 怎么 mount / install / publish
|
|
220
|
-
-
|
|
228
|
+
- 怎么生成 `skill/` 产物
|
|
221
229
|
|
|
222
230
|
优先回到主 skill 文档:
|
|
223
231
|
|
package/src/app.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { registerConfigCommand } from "./commands/config";
|
|
|
3
3
|
import { registerCreateCommand } from "./commands/create";
|
|
4
4
|
import { registerInstallCommand } from "./commands/install";
|
|
5
5
|
import { registerListCommand } from "./commands/list";
|
|
6
|
-
import {
|
|
6
|
+
import { registerSkillCommands } from "./commands/skill";
|
|
7
7
|
import { registerUninstallCommand } from "./commands/uninstall";
|
|
8
8
|
|
|
9
9
|
export function createApp(version: string) {
|
|
@@ -14,7 +14,7 @@ export function createApp(version: string) {
|
|
|
14
14
|
registerListCommand(cli);
|
|
15
15
|
registerInstallCommand(cli);
|
|
16
16
|
registerUninstallCommand(cli);
|
|
17
|
-
|
|
17
|
+
registerSkillCommands(cli);
|
|
18
18
|
|
|
19
19
|
cli.help();
|
|
20
20
|
cli.version(version);
|
package/src/build.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { mkdir, readdir, readFile, stat, writeFile } from "node:fs/promises";
|
|
2
2
|
import path from "node:path";
|
|
3
|
-
import { type
|
|
3
|
+
import { type ZodTypeAny } from "zod";
|
|
4
4
|
import type { SkillDefinition } from "@cli-skill/core";
|
|
5
5
|
|
|
6
6
|
interface FieldInfo {
|
|
@@ -15,27 +15,39 @@ interface DocRow {
|
|
|
15
15
|
notes: string;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
+
type ShapeLike = Record<string, ZodTypeAny>;
|
|
19
|
+
|
|
20
|
+
function getSchemaDef(schema: ZodTypeAny): Record<string, unknown> | undefined {
|
|
21
|
+
return (schema as ZodTypeAny & { _def?: Record<string, unknown>; def?: Record<string, unknown> })._def
|
|
22
|
+
?? (schema as ZodTypeAny & { def?: Record<string, unknown> }).def;
|
|
23
|
+
}
|
|
24
|
+
|
|
18
25
|
function unwrapField(schema: ZodTypeAny): FieldInfo {
|
|
19
26
|
let current = schema;
|
|
20
27
|
let optional = false;
|
|
21
28
|
let defaultValue: unknown;
|
|
22
29
|
|
|
23
30
|
while (true) {
|
|
24
|
-
|
|
31
|
+
const def = getSchemaDef(current);
|
|
32
|
+
const typeName = def?.typeName;
|
|
33
|
+
const type = def?.type;
|
|
34
|
+
|
|
35
|
+
if ((typeName === "ZodOptional" || type === "optional") && def?.innerType) {
|
|
25
36
|
optional = true;
|
|
26
|
-
current =
|
|
37
|
+
current = def.innerType as ZodTypeAny;
|
|
27
38
|
continue;
|
|
28
39
|
}
|
|
29
40
|
|
|
30
|
-
if (
|
|
41
|
+
if ((typeName === "ZodDefault" || type === "default") && def?.innerType) {
|
|
31
42
|
optional = true;
|
|
32
|
-
|
|
33
|
-
|
|
43
|
+
const rawDefault = def.defaultValue;
|
|
44
|
+
defaultValue = typeof rawDefault === "function" ? rawDefault() : rawDefault;
|
|
45
|
+
current = def.innerType as ZodTypeAny;
|
|
34
46
|
continue;
|
|
35
47
|
}
|
|
36
48
|
|
|
37
|
-
if (
|
|
38
|
-
current =
|
|
49
|
+
if ((typeName === "ZodNullable" || type === "nullable") && def?.innerType) {
|
|
50
|
+
current = def.innerType as ZodTypeAny;
|
|
39
51
|
continue;
|
|
40
52
|
}
|
|
41
53
|
|
|
@@ -46,25 +58,30 @@ function unwrapField(schema: ZodTypeAny): FieldInfo {
|
|
|
46
58
|
}
|
|
47
59
|
|
|
48
60
|
function getTypeName(schema: ZodTypeAny): string | undefined {
|
|
49
|
-
|
|
61
|
+
const def = getSchemaDef(schema);
|
|
62
|
+
return (def?.typeName as string | undefined) ?? (def?.type as string | undefined);
|
|
50
63
|
}
|
|
51
64
|
|
|
52
|
-
function getObjectShape(schema: ZodTypeAny):
|
|
53
|
-
|
|
65
|
+
function getObjectShape(schema: ZodTypeAny): ShapeLike | null {
|
|
66
|
+
const typeName = getTypeName(schema);
|
|
67
|
+
if (typeName !== "ZodObject" && typeName !== "object") {
|
|
54
68
|
return null;
|
|
55
69
|
}
|
|
56
70
|
|
|
57
71
|
const objectSchema = schema as ZodTypeAny & {
|
|
58
|
-
_def
|
|
59
|
-
shape?:
|
|
72
|
+
_def?: { shape?: (() => ShapeLike) | ShapeLike };
|
|
73
|
+
def?: { shape?: (() => ShapeLike) | ShapeLike };
|
|
74
|
+
shape?: ShapeLike;
|
|
60
75
|
};
|
|
76
|
+
const def = getSchemaDef(objectSchema);
|
|
77
|
+
const shapeValue = def?.shape as (() => ShapeLike) | ShapeLike | undefined;
|
|
61
78
|
|
|
62
|
-
if (typeof
|
|
63
|
-
return
|
|
79
|
+
if (typeof shapeValue === "function") {
|
|
80
|
+
return shapeValue();
|
|
64
81
|
}
|
|
65
82
|
|
|
66
|
-
if (
|
|
67
|
-
return
|
|
83
|
+
if (shapeValue) {
|
|
84
|
+
return shapeValue;
|
|
68
85
|
}
|
|
69
86
|
|
|
70
87
|
return objectSchema.shape ?? null;
|
|
@@ -87,21 +104,32 @@ function describeType(schema: ZodTypeAny): string {
|
|
|
87
104
|
return "boolean";
|
|
88
105
|
}
|
|
89
106
|
|
|
90
|
-
|
|
91
|
-
|
|
107
|
+
const def = getSchemaDef(base);
|
|
108
|
+
|
|
109
|
+
if (typeName === "ZodLiteral" || typeName === "literal") {
|
|
110
|
+
const values = def?.values;
|
|
111
|
+
if (Array.isArray(values) && values.length === 1) {
|
|
112
|
+
return JSON.stringify(values[0]);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return JSON.stringify(def?.value);
|
|
92
116
|
}
|
|
93
117
|
|
|
94
|
-
if (typeName === "ZodEnum") {
|
|
95
|
-
|
|
96
|
-
|
|
118
|
+
if (typeName === "ZodEnum" || typeName === "enum") {
|
|
119
|
+
const entries = (def?.entries as Record<string, string> | undefined)
|
|
120
|
+
?? ((base as ZodTypeAny & { options?: string[] }).options
|
|
121
|
+
? Object.fromEntries(((base as ZodTypeAny & { options: string[] }).options).map((item) => [item, item]))
|
|
122
|
+
: undefined);
|
|
123
|
+
return Object.values(entries ?? {})
|
|
124
|
+
.map((item) => JSON.stringify(item))
|
|
97
125
|
.join(" | ");
|
|
98
126
|
}
|
|
99
127
|
|
|
100
|
-
if (typeName === "ZodArray") {
|
|
101
|
-
return `array<${describeType(
|
|
128
|
+
if (typeName === "ZodArray" || typeName === "array") {
|
|
129
|
+
return `array<${describeType((def?.type ?? def?.element) as ZodTypeAny)}>`;
|
|
102
130
|
}
|
|
103
131
|
|
|
104
|
-
if (typeName === "ZodObject") {
|
|
132
|
+
if (typeName === "ZodObject" || typeName === "object") {
|
|
105
133
|
return "object";
|
|
106
134
|
}
|
|
107
135
|
|
|
@@ -123,7 +151,7 @@ function describeNotes(schema: ZodTypeAny): string {
|
|
|
123
151
|
return notes.join("; ");
|
|
124
152
|
}
|
|
125
153
|
|
|
126
|
-
function collectShapeRows(shape:
|
|
154
|
+
function collectShapeRows(shape: ShapeLike, prefix = ""): DocRow[] {
|
|
127
155
|
const rows: DocRow[] = [];
|
|
128
156
|
|
|
129
157
|
for (const [key, schema] of Object.entries(shape)) {
|
|
@@ -180,7 +208,7 @@ function renderTable(headers: string[], rows: string[][]): string {
|
|
|
180
208
|
}
|
|
181
209
|
|
|
182
210
|
function renderConfigSection(skill: SkillDefinition): string {
|
|
183
|
-
const rows = collectShapeRows(skill.config).map((row) => [row.path, row.type, row.notes || ""]);
|
|
211
|
+
const rows = collectShapeRows(skill.config as ShapeLike).map((row) => [row.path, row.type, row.notes || ""]);
|
|
184
212
|
return renderTable(["字段", "类型", "说明"], rows.length > 0 ? rows : [["-", "-", "-"]]);
|
|
185
213
|
}
|
|
186
214
|
|
package/src/bun.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { execFile } from "node:child_process";
|
|
1
|
+
import { execFile, spawn } from "node:child_process";
|
|
2
2
|
import { mkdir, rm, writeFile } from "node:fs/promises";
|
|
3
|
+
import os from "node:os";
|
|
3
4
|
import path from "node:path";
|
|
4
5
|
import { promisify } from "node:util";
|
|
5
6
|
|
|
@@ -19,6 +20,33 @@ export async function runBun(
|
|
|
19
20
|
});
|
|
20
21
|
}
|
|
21
22
|
|
|
23
|
+
export async function runBunStreaming(
|
|
24
|
+
args: string[],
|
|
25
|
+
cwd?: string,
|
|
26
|
+
envOverrides?: Record<string, string | undefined>,
|
|
27
|
+
): Promise<void> {
|
|
28
|
+
await new Promise<void>((resolve, reject) => {
|
|
29
|
+
const child = spawn("bun", args, {
|
|
30
|
+
cwd,
|
|
31
|
+
env: {
|
|
32
|
+
...process.env,
|
|
33
|
+
...envOverrides,
|
|
34
|
+
},
|
|
35
|
+
stdio: "inherit",
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
child.on("error", reject);
|
|
39
|
+
child.on("exit", (code, signal) => {
|
|
40
|
+
if (code === 0) {
|
|
41
|
+
resolve();
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
reject(new Error(`bun ${args.join(" ")} failed with code ${code ?? "null"}${signal ? ` signal ${signal}` : ""}`));
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
|
|
22
50
|
export async function runBunx(args: string[], cwd?: string): Promise<string> {
|
|
23
51
|
const { stdout } = await execFileAsync("bunx", args, {
|
|
24
52
|
cwd,
|
|
@@ -36,7 +64,9 @@ export async function runBunAndCapture(args: string[], cwd?: string): Promise<st
|
|
|
36
64
|
}
|
|
37
65
|
|
|
38
66
|
export async function getBunGlobalBinDir(): Promise<string> {
|
|
39
|
-
|
|
67
|
+
const home = process.env.HOME || os.homedir();
|
|
68
|
+
const bunInstall = process.env.BUN_INSTALL || path.join(home, ".bun");
|
|
69
|
+
return path.join(bunInstall, "bin");
|
|
40
70
|
}
|
|
41
71
|
|
|
42
72
|
export async function installPackageToDirectory(packageSpec: string, installDir: string): Promise<void> {
|
package/src/commands/config.ts
CHANGED
|
@@ -6,7 +6,9 @@ import {
|
|
|
6
6
|
parseConfigCliValue,
|
|
7
7
|
saveBrowserSkillCliConfig,
|
|
8
8
|
setConfigValue,
|
|
9
|
+
unsetConfigValue,
|
|
9
10
|
} from "../config";
|
|
11
|
+
import { getCurrentSkillProject } from "../registry";
|
|
10
12
|
|
|
11
13
|
function printConfigValue(value: unknown): void {
|
|
12
14
|
if (typeof value === "string") {
|
|
@@ -25,13 +27,24 @@ function printConfigValue(value: unknown): void {
|
|
|
25
27
|
export function registerConfigCommand(cli: CAC): void {
|
|
26
28
|
cli
|
|
27
29
|
.command("config [...args]", "Manage cli-skill config")
|
|
28
|
-
.usage("config get [keyPath]\n cli-skill config set <keyPath> <value>")
|
|
30
|
+
.usage("config get [keyPath]\n cli-skill config set <keyPath> <value>\n cli-skill config unset <keyPath>")
|
|
29
31
|
.action(async (args: string[] = []) => {
|
|
30
32
|
const [subcommand, keyPath, rawValue] = args;
|
|
33
|
+
let currentSkillName: string | null = null;
|
|
34
|
+
|
|
35
|
+
try {
|
|
36
|
+
currentSkillName = (await getCurrentSkillProject()).skillName;
|
|
37
|
+
} catch {}
|
|
38
|
+
|
|
39
|
+
const scopedKeyPath = currentSkillName && keyPath
|
|
40
|
+
? `skillConfig.${currentSkillName}.${keyPath}`
|
|
41
|
+
: currentSkillName
|
|
42
|
+
? `skillConfig.${currentSkillName}`
|
|
43
|
+
: keyPath;
|
|
31
44
|
|
|
32
45
|
if (subcommand === "get") {
|
|
33
46
|
const currentConfig = await loadBrowserSkillCliConfig();
|
|
34
|
-
const value = getConfigValue(currentConfig,
|
|
47
|
+
const value = getConfigValue(currentConfig, scopedKeyPath);
|
|
35
48
|
printConfigValue(value);
|
|
36
49
|
return;
|
|
37
50
|
}
|
|
@@ -42,12 +55,28 @@ export function registerConfigCommand(cli: CAC): void {
|
|
|
42
55
|
}
|
|
43
56
|
|
|
44
57
|
const currentConfig = await loadBrowserSkillCliConfig();
|
|
45
|
-
const nextConfig = setConfigValue(
|
|
58
|
+
const nextConfig = setConfigValue(
|
|
59
|
+
currentConfig,
|
|
60
|
+
scopedKeyPath!,
|
|
61
|
+
parseConfigCliValue(rawValue),
|
|
62
|
+
);
|
|
63
|
+
await saveBrowserSkillCliConfig(nextConfig);
|
|
64
|
+
console.log(getBrowserSkillConfigPath());
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (subcommand === "unset") {
|
|
69
|
+
if (!keyPath) {
|
|
70
|
+
throw new Error("Usage: cli-skill config unset <keyPath>");
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const currentConfig = await loadBrowserSkillCliConfig();
|
|
74
|
+
const nextConfig = unsetConfigValue(currentConfig, scopedKeyPath!);
|
|
46
75
|
await saveBrowserSkillCliConfig(nextConfig);
|
|
47
76
|
console.log(getBrowserSkillConfigPath());
|
|
48
77
|
return;
|
|
49
78
|
}
|
|
50
79
|
|
|
51
|
-
throw new Error("Usage: cli-skill config get [keyPath] | cli-skill config set <keyPath> <value>");
|
|
80
|
+
throw new Error("Usage: cli-skill config get [keyPath] | cli-skill config set <keyPath> <value> | cli-skill config unset <keyPath>");
|
|
52
81
|
});
|
|
53
82
|
}
|
package/src/commands/create.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { CAC } from "cac";
|
|
2
2
|
import { DEFAULT_TEMPLATE_NAME } from "../constants";
|
|
3
3
|
import { createSkillProject } from "../project";
|
|
4
|
+
import { registerLocalSkillProject } from "../registry";
|
|
4
5
|
|
|
5
6
|
function resolveTemplateName(templateOption?: string): string {
|
|
6
7
|
return templateOption ?? DEFAULT_TEMPLATE_NAME;
|
|
@@ -20,6 +21,7 @@ export function registerCreateCommand(cli: CAC): void {
|
|
|
20
21
|
options.cliName ?? skillName,
|
|
21
22
|
resolveTemplateName(options.template),
|
|
22
23
|
);
|
|
24
|
+
await registerLocalSkillProject(targetDir);
|
|
23
25
|
console.log(targetDir);
|
|
24
26
|
});
|
|
25
27
|
}
|