@cli-skill/cli 0.0.1-beta.20260402112811 → 0.0.2-beta.20260402145701
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 +31 -0
- package/package.json +3 -3
- package/skill/SKILL.md +15 -1
- package/skill/references/core.md +4 -0
- package/src/build.ts +55 -27
- package/src/commands/skill.ts +6 -10
- package/src/commands/uninstall.ts +13 -1
package/README.md
CHANGED
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
```bash
|
|
23
23
|
cli-skill create <skillName> --cli-name <cliName> [--template <templateName>]
|
|
24
24
|
cli-skill list
|
|
25
|
+
cli-skill tools <skillName>
|
|
25
26
|
cli-skill install <skillName> [--packageName <packageName>]
|
|
26
27
|
cli-skill uninstall <packageName>
|
|
27
28
|
cli-skill config get [keyPath]
|
|
@@ -70,6 +71,13 @@ cli-skill mount
|
|
|
70
71
|
- `src/skill/*`
|
|
71
72
|
- 文档模板源目录
|
|
72
73
|
|
|
74
|
+
模板生成出来的 skill 包会同时依赖:
|
|
75
|
+
|
|
76
|
+
- `@cli-skill/core`
|
|
77
|
+
- 运行 skill
|
|
78
|
+
- `@cli-skill/cli`
|
|
79
|
+
- 在项目目录内调用 `cli-skill build`、`cli-skill mount` 等命令
|
|
80
|
+
|
|
73
81
|
执行 `cli-skill build` 后会生成:
|
|
74
82
|
|
|
75
83
|
- `skill/SKILL.md`
|
|
@@ -127,3 +135,26 @@ cli-skill mount
|
|
|
127
135
|
```bash
|
|
128
136
|
cli-skill install fx --packageName @scope/cli-skill-fx
|
|
129
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.
|
|
3
|
+
"version": "0.0.2-beta.20260402145701",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./src/index.ts",
|
|
6
6
|
"types": "./src/index.ts",
|
|
@@ -17,9 +17,9 @@
|
|
|
17
17
|
"test": "tsc -p tsconfig.test.json && bun test ./test"
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"@cli-skill/core": "^0.0.
|
|
20
|
+
"@cli-skill/core": "^0.0.2-beta.20260402145701",
|
|
21
21
|
"cac": "^6.7.14",
|
|
22
22
|
"lodash": "^4.17.21",
|
|
23
|
-
"zod": "^3.
|
|
23
|
+
"zod": "^4.3.6"
|
|
24
24
|
}
|
|
25
25
|
}
|
package/skill/SKILL.md
CHANGED
|
@@ -28,6 +28,7 @@ description: 当任务涉及 cli skill 的创建、挂载、安装、发布或
|
|
|
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 ...`
|
|
@@ -40,7 +41,14 @@ description: 当任务涉及 cli skill 的创建、挂载、安装、发布或
|
|
|
40
41
|
- 已注册 skill 执行命令
|
|
41
42
|
- `cli-skill exec <skill-name> ...`
|
|
42
43
|
|
|
43
|
-
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 使用。
|
|
44
52
|
|
|
45
53
|
## 默认流程
|
|
46
54
|
|
|
@@ -84,6 +92,7 @@ cli-skill mount
|
|
|
84
92
|
| --- | --- |
|
|
85
93
|
| 创建 skill | `cli-skill create <skill-name> --cli-name <cli-name> [--template <templateName>]` |
|
|
86
94
|
| 查看 skill 列表 | `cli-skill list` |
|
|
95
|
+
| 查看已注册 skill 的 tool 列表 | `cli-skill tools <skill-name>` |
|
|
87
96
|
| 安装已发布 skill | `cli-skill install <skill-name>` |
|
|
88
97
|
| 卸载已发布 skill | `cli-skill uninstall <package-name>` |
|
|
89
98
|
| 查看 tool 列表 | `cli-skill tools` |
|
|
@@ -109,6 +118,10 @@ cli-skill mount
|
|
|
109
118
|
- `mount` 不应隐式执行 `install`。
|
|
110
119
|
- `install` / `uninstall` 面向已发布 skill。
|
|
111
120
|
- `publish` 只针对当前目录的本地 skill。
|
|
121
|
+
- skill bin 只负责:
|
|
122
|
+
- `list`
|
|
123
|
+
- 直接执行 tool
|
|
124
|
+
- `config get/set/unset`
|
|
112
125
|
|
|
113
126
|
默认目录:
|
|
114
127
|
|
|
@@ -156,4 +169,5 @@ cli-skill build
|
|
|
156
169
|
- 不要把 `create` 当成“已经可执行”
|
|
157
170
|
- 不要手动改 `~/.agents/skills`
|
|
158
171
|
- 不要把 skill bin 当成独立平台
|
|
172
|
+
- 不要期待 skill bin 提供 `build` / `mount` / `publish`
|
|
159
173
|
- 不要在修改已有 skill 时重新 `create`
|
package/skill/references/core.md
CHANGED
|
@@ -67,6 +67,8 @@ cli-skill build
|
|
|
67
67
|
|
|
68
68
|
也就是说,skill 只做“组织”和“说明”,不直接承担运行时能力注入。
|
|
69
69
|
|
|
70
|
+
命令解析也不在 `core`。`core` 只负责类型、runtime、tool 执行。
|
|
71
|
+
|
|
70
72
|
## `defineTool` 负责什么
|
|
71
73
|
|
|
72
74
|
`defineTool` 才是运行能力的核心。
|
|
@@ -211,6 +213,8 @@ export default defineSkill({
|
|
|
211
213
|
|
|
212
214
|
这也是为什么生成出来的 skill 模板会把 `zod` 放在自己的 `dependencies` 里。
|
|
213
215
|
|
|
216
|
+
skill 项目默认只依赖 `@cli-skill/core`。平台 CLI 通过全局安装的 `cli-skill` 提供,不会再写进模板依赖里。
|
|
217
|
+
|
|
214
218
|
## 什么时候继续往下看
|
|
215
219
|
|
|
216
220
|
如果你需要的是:
|
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/commands/skill.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { CAC } from "cac";
|
|
2
|
-
import {
|
|
2
|
+
import { listTools, runTool } from "@cli-skill/core";
|
|
3
3
|
import { writeSkillDocsMarkdown } from "../build";
|
|
4
4
|
import { runBunStreaming } from "../bun";
|
|
5
5
|
import { loadSkillDefinition } from "../project";
|
|
@@ -16,16 +16,14 @@ export function registerSkillCommands(cli: CAC): void {
|
|
|
16
16
|
.action(async (skillName: string, toolName: string, rawInput?: string) => {
|
|
17
17
|
const resolved = await resolveRegisteredSkillProject(skillName);
|
|
18
18
|
const skill = await loadSkillDefinition(resolved.projectPath);
|
|
19
|
-
const exitCode = await
|
|
20
|
-
rootDir: resolved.projectPath,
|
|
21
|
-
});
|
|
19
|
+
const exitCode = await runTool(skill, toolName, rawInput, { rootDir: resolved.projectPath });
|
|
22
20
|
process.exitCode = exitCode;
|
|
23
21
|
});
|
|
24
22
|
|
|
25
|
-
cli.command("tools", "List tools in the current cli skill project").action(async () => {
|
|
26
|
-
const resolved = await getCurrentSkillProject();
|
|
23
|
+
cli.command("tools [skillName]", "List tools in the current cli skill project or a registered cli skill").action(async (skillName?: string) => {
|
|
24
|
+
const resolved = skillName ? await resolveRegisteredSkillProject(skillName) : await getCurrentSkillProject();
|
|
27
25
|
const skill = await loadSkillDefinition(resolved.projectPath);
|
|
28
|
-
const exitCode = await
|
|
26
|
+
const exitCode = await listTools(skill, { rootDir: resolved.projectPath });
|
|
29
27
|
process.exitCode = exitCode;
|
|
30
28
|
});
|
|
31
29
|
|
|
@@ -34,9 +32,7 @@ export function registerSkillCommands(cli: CAC): void {
|
|
|
34
32
|
.action(async (toolName: string, rawInput?: string) => {
|
|
35
33
|
const resolved = await getCurrentSkillProject();
|
|
36
34
|
const skill = await loadSkillDefinition(resolved.projectPath);
|
|
37
|
-
const exitCode = await
|
|
38
|
-
rootDir: resolved.projectPath,
|
|
39
|
-
});
|
|
35
|
+
const exitCode = await runTool(skill, toolName, rawInput, { rootDir: resolved.projectPath });
|
|
40
36
|
process.exitCode = exitCode;
|
|
41
37
|
});
|
|
42
38
|
|
|
@@ -3,6 +3,16 @@ import { rm } from "node:fs/promises";
|
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { resolveRegisteredSkillProject, removeRegistryEntry, unregisterProjectBins } from "../registry";
|
|
5
5
|
|
|
6
|
+
function getInstalledSkillRoot(projectPath: string): string {
|
|
7
|
+
const segments = projectPath.split(path.sep);
|
|
8
|
+
const nodeModulesIndex = segments.lastIndexOf("node_modules");
|
|
9
|
+
if (nodeModulesIndex === -1) {
|
|
10
|
+
return projectPath;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
return segments.slice(0, nodeModulesIndex).join(path.sep) || path.sep;
|
|
14
|
+
}
|
|
15
|
+
|
|
6
16
|
export function registerUninstallCommand(cli: CAC): void {
|
|
7
17
|
cli
|
|
8
18
|
.command("uninstall <packageName>", "Uninstall a managed cli skill")
|
|
@@ -13,7 +23,9 @@ export function registerUninstallCommand(cli: CAC): void {
|
|
|
13
23
|
for (const agentPath of resolved.agentPaths) {
|
|
14
24
|
await rm(agentPath, { recursive: true, force: true });
|
|
15
25
|
}
|
|
16
|
-
|
|
26
|
+
if (resolved.source === "installed") {
|
|
27
|
+
await rm(getInstalledSkillRoot(resolved.projectPath), { recursive: true, force: true });
|
|
28
|
+
}
|
|
17
29
|
await removeRegistryEntry(skillName);
|
|
18
30
|
console.log(resolved.projectPath);
|
|
19
31
|
});
|