openclawmp 1.0.0-alpha.0 → 1.0.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +37 -30
- package/lib/api.js +1 -1
- package/lib/archive.js +1 -1
- package/lib/cli-text.js +34 -0
- package/lib/commands/info.js +25 -153
- package/lib/commands/install.js +39 -16
- package/lib/commands/list.js +3 -2
- package/lib/commands/login.js +3 -2
- package/lib/commands/publish.js +34 -447
- package/lib/commands/search.js +6 -5
- package/lib/commands/uninstall.js +4 -3
- package/lib/help.js +20 -18
- package/lib/metadata.js +64 -82
- package/lib/publish-flow.js +6 -13
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -18,8 +18,8 @@ npm install -g openclawmp
|
|
|
18
18
|
# 搜索市场资产
|
|
19
19
|
openclawmp search 天气
|
|
20
20
|
|
|
21
|
-
# 查看资产详情
|
|
22
|
-
openclawmp info
|
|
21
|
+
# 根据 assetId 查看资产详情
|
|
22
|
+
openclawmp info 6c476a36955a4270a3fa303beeeed5ee
|
|
23
23
|
|
|
24
24
|
# 安装资产
|
|
25
25
|
openclawmp install skill/7c19dc4c3244418096f1dcb59c93f795
|
|
@@ -34,13 +34,13 @@ openclawmp list
|
|
|
34
34
|
openclawmp uninstall skill/demo-skill
|
|
35
35
|
|
|
36
36
|
# 发布本地资产
|
|
37
|
-
openclawmp publish ./my-
|
|
37
|
+
openclawmp publish ./my-asset --yes
|
|
38
38
|
```
|
|
39
39
|
|
|
40
40
|
## 功能概览
|
|
41
41
|
|
|
42
42
|
- `search`:搜索市场资产,按类型、作者、安装量、标签和简介格式化输出。
|
|
43
|
-
- `info
|
|
43
|
+
- `info`:根据 `assetId` 查看资产详情与版本信息。
|
|
44
44
|
- `install`:根据 `assetId` 和可选 `semver` 下载归档并安装到本地 OpenClaw 目录。
|
|
45
45
|
- `uninstall`:删除本地安装目录,并清理对应锁文件记录。
|
|
46
46
|
- `list`:扫描本地已安装资产,结合 lockfile 和安装元数据展示结果。
|
|
@@ -90,18 +90,34 @@ openclawmp publish /path/to/asset
|
|
|
90
90
|
示例:
|
|
91
91
|
|
|
92
92
|
```bash
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
93
|
+
cat .metadata.json
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
```json
|
|
97
|
+
{
|
|
98
|
+
"assetType": "skill",
|
|
99
|
+
"name": "my-skill",
|
|
100
|
+
"displayName": "My Skill",
|
|
101
|
+
"semver": "1.0.0",
|
|
102
|
+
"category": "productivity",
|
|
103
|
+
"tags": ["agent", "automation"]
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
openclawmp publish ./my-skill --yes
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
查看资产详情:
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
openclawmp info 6c476a36955a4270a3fa303beeeed5ee
|
|
99
115
|
```
|
|
100
116
|
|
|
101
117
|
更新已有资产版本:
|
|
102
118
|
|
|
103
119
|
```bash
|
|
104
|
-
openclawmp publish ./my-skill --
|
|
120
|
+
openclawmp publish ./my-skill --asset-id s-123456 --yes
|
|
105
121
|
```
|
|
106
122
|
|
|
107
123
|
如果目录根部已存在 `.assetid`,会自动把该值透传为 `assetId`;也可显式传入 `--asset-id <id>`。
|
|
@@ -138,24 +154,16 @@ openclawmp search 天气 --page-size 10
|
|
|
138
154
|
|
|
139
155
|
- `publish`
|
|
140
156
|
- `search`
|
|
157
|
+
- `info`
|
|
141
158
|
- `install`
|
|
142
159
|
- `uninstall`
|
|
143
160
|
- `list`
|
|
144
161
|
|
|
145
|
-
其中当前可用的是 `publish`、`search`、`install`、`uninstall`、`list`。
|
|
162
|
+
其中当前可用的是 `publish`、`search`、`info`、`install`、`uninstall`、`list`。
|
|
146
163
|
|
|
147
164
|
## 发布命令参数
|
|
148
165
|
|
|
149
|
-
- `--type <skill|experience|plugin|trigger|channel>`
|
|
150
166
|
- `--asset-id <id>`:未传时会尝试读取目录根部 `.assetid`
|
|
151
|
-
- `--name <slug>`
|
|
152
|
-
- `--display-name <name>`
|
|
153
|
-
- `--description <text>`
|
|
154
|
-
- `--version <semver>`
|
|
155
|
-
- `--category <category>`
|
|
156
|
-
- `--tags <a,b,c>`
|
|
157
|
-
- `--tag <value>`:可重复
|
|
158
|
-
- `--long-description <text>`
|
|
159
167
|
- `--base-url <url>`
|
|
160
168
|
- `--token-file <path>`
|
|
161
169
|
- `--part-size-mb <number>`
|
|
@@ -171,16 +179,15 @@ openclawmp search 天气 --page-size 10
|
|
|
171
179
|
- 根目录可通过 `.openclawmpignore` 补充忽略规则,也会读取根目录 `.gitignore` / `.npmignore` 的常见规则
|
|
172
180
|
- 子路径遇到无权限读取的目录或文件时会自动跳过;使用 `--verbose` 可查看具体跳过项
|
|
173
181
|
|
|
174
|
-
## Metadata
|
|
182
|
+
## Publish Metadata
|
|
175
183
|
|
|
176
|
-
-
|
|
177
|
-
- `.metadata.json`
|
|
178
|
-
- `
|
|
179
|
-
-
|
|
180
|
-
-
|
|
181
|
-
-
|
|
182
|
-
- `
|
|
183
|
-
- `assetId` 为可选字段;有就透传,没有就省略,由后端判断是新建还是已有资产发新版
|
|
184
|
+
- `publish` 只读取发布目录或归档里的 `.metadata.json`
|
|
185
|
+
- `.metadata.json` 必须包含 `assetType`、`name`、`displayName`、`semver`
|
|
186
|
+
- `semver` 必须是严格的 `x.y.z` 纯数字格式,例如 `1.2.3`
|
|
187
|
+
- 可选字段:`assetId`、`category`、`tags`、`description`、`longDescription`
|
|
188
|
+
- 不再从 `README.md`、`package.json`、`openclaw.plugin.json`、`SKILL.md` 自动推断发布 metadata
|
|
189
|
+
- 不再通过 CLI 参数补录 `assetType`、`name`、`displayName`、`semver`
|
|
190
|
+
- `assetId` 可写在 `.metadata.json`,也可以通过 `--asset-id` 或目录根部 `.assetid` 透传
|
|
184
191
|
- `objectId` 由上传完成后自动生成,登录态始终必需
|
|
185
192
|
- 调用发布接口前会打印 `CreateAssetSemver` 请求预览;真正发网请求前会打印对应 request body
|
|
186
193
|
|
package/lib/api.js
CHANGED
|
@@ -115,7 +115,7 @@ function createCatalogClient(options) {
|
|
|
115
115
|
"Connect-Protocol-Version": "1",
|
|
116
116
|
"Content-Type": "application/json",
|
|
117
117
|
"Accept": "application/json",
|
|
118
|
-
"User-Agent": "
|
|
118
|
+
"User-Agent": "openclawmp/" + (options.cliVersion || "dev")
|
|
119
119
|
};
|
|
120
120
|
|
|
121
121
|
if (options.token) {
|
package/lib/archive.js
CHANGED
|
@@ -879,7 +879,7 @@ async function preparePackage(inputPath) {
|
|
|
879
879
|
const inspected = await inspectPublishInput(inputPath);
|
|
880
880
|
|
|
881
881
|
if (inspected.isDirectory) {
|
|
882
|
-
const tempDir = await fsp.mkdtemp(path.join(os.tmpdir(), "
|
|
882
|
+
const tempDir = await fsp.mkdtemp(path.join(os.tmpdir(), "openclawmp-cli-"));
|
|
883
883
|
const packagePath = path.join(tempDir, inspected.packageFileName);
|
|
884
884
|
await createTarGzFromEntries(inspected.entries, packagePath);
|
|
885
885
|
const packageStat = await fsp.stat(packagePath);
|
package/lib/cli-text.js
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const CLI_NAME = "openclawmp";
|
|
4
|
+
|
|
5
|
+
function buildInstallSpecifier(assetType, assetId, semver) {
|
|
6
|
+
const normalizedAssetType = String(assetType || "").trim();
|
|
7
|
+
const normalizedAssetId = String(assetId || "").trim();
|
|
8
|
+
const normalizedSemver = String(semver || "").trim();
|
|
9
|
+
|
|
10
|
+
if (!normalizedAssetType || !normalizedAssetId) {
|
|
11
|
+
return "";
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return (
|
|
15
|
+
normalizedAssetType +
|
|
16
|
+
"/" +
|
|
17
|
+
normalizedAssetId +
|
|
18
|
+
(normalizedSemver ? "@" + normalizedSemver : "")
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function buildInstallCommand(assetType, assetId, semver) {
|
|
23
|
+
const specifier = buildInstallSpecifier(assetType, assetId, semver);
|
|
24
|
+
if (!specifier) {
|
|
25
|
+
return "";
|
|
26
|
+
}
|
|
27
|
+
return CLI_NAME + " install " + specifier;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
module.exports = {
|
|
31
|
+
CLI_NAME,
|
|
32
|
+
buildInstallSpecifier,
|
|
33
|
+
buildInstallCommand
|
|
34
|
+
};
|
package/lib/commands/info.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
const { parseOptions } = require("../cli-parser");
|
|
4
|
+
const { CLI_NAME } = require("../cli-text");
|
|
4
5
|
const { createCatalogClient } = require("../api");
|
|
5
|
-
const { fromCatalogAssetType
|
|
6
|
+
const { fromCatalogAssetType } = require("../asset-types");
|
|
6
7
|
const { resolveConnectBaseUrl } = require("../config");
|
|
7
8
|
const { generateRequestId, humanize } = require("../utils");
|
|
8
9
|
|
|
@@ -15,10 +16,13 @@ const TYPE_ICONS = {
|
|
|
15
16
|
};
|
|
16
17
|
|
|
17
18
|
function printHelp() {
|
|
18
|
-
console.log("
|
|
19
|
+
console.log(CLI_NAME + " info");
|
|
19
20
|
console.log("");
|
|
20
21
|
console.log("用法:");
|
|
21
|
-
console.log("
|
|
22
|
+
console.log(" " + CLI_NAME + " info <assetId> [options]");
|
|
23
|
+
console.log("");
|
|
24
|
+
console.log("示例:");
|
|
25
|
+
console.log(" " + CLI_NAME + " info 6c476a36955a4270a3fa303beeeed5ee");
|
|
22
26
|
console.log("");
|
|
23
27
|
console.log("参数:");
|
|
24
28
|
console.log(" --base-url <url> API 基地址");
|
|
@@ -33,57 +37,28 @@ function pickFirstText(values) {
|
|
|
33
37
|
}) || "";
|
|
34
38
|
}
|
|
35
39
|
|
|
36
|
-
function
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
.toLowerCase()
|
|
40
|
-
.replace(/\s+/g, " ");
|
|
41
|
-
}
|
|
40
|
+
function parseAssetId(positionals) {
|
|
41
|
+
const args = Array.isArray(positionals) ? positionals.filter(Boolean) : [];
|
|
42
|
+
const usageExample = CLI_NAME + " info 6c476a36955a4270a3fa303beeeed5ee";
|
|
42
43
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
if (!text) {
|
|
46
|
-
throw new Error("info 命令缺少资产标识");
|
|
44
|
+
if (args.length === 0) {
|
|
45
|
+
throw new Error("info 命令缺少 assetId");
|
|
47
46
|
}
|
|
48
47
|
|
|
49
|
-
if (
|
|
50
|
-
|
|
51
|
-
kind: "assetId",
|
|
52
|
-
assetId: text
|
|
53
|
-
};
|
|
48
|
+
if (args.length !== 1) {
|
|
49
|
+
throw new Error("info 命令只支持 <assetId> 用法,例如: " + usageExample);
|
|
54
50
|
}
|
|
55
51
|
|
|
56
|
-
|
|
57
|
-
if (
|
|
58
|
-
|
|
59
|
-
if (!assetType) {
|
|
60
|
-
throw new Error("未知资产类型: " + match[1]);
|
|
61
|
-
}
|
|
62
|
-
return {
|
|
63
|
-
kind: "typedAuthorName",
|
|
64
|
-
assetType,
|
|
65
|
-
authorId: match[2],
|
|
66
|
-
query: match[3].trim()
|
|
67
|
-
};
|
|
52
|
+
const assetId = String(args[0] || "").trim();
|
|
53
|
+
if (!assetId) {
|
|
54
|
+
throw new Error("info 命令缺少 assetId");
|
|
68
55
|
}
|
|
69
56
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
const assetType = normalizeLocalAssetType(match[1]);
|
|
73
|
-
if (!assetType) {
|
|
74
|
-
throw new Error("未知资产类型: " + match[1]);
|
|
75
|
-
}
|
|
76
|
-
return {
|
|
77
|
-
kind: "typedName",
|
|
78
|
-
assetType,
|
|
79
|
-
query: match[2].trim()
|
|
80
|
-
};
|
|
57
|
+
if (/\s/u.test(assetId) || assetId.includes("/")) {
|
|
58
|
+
throw new Error("info 命令只支持 <assetId> 用法,例如: " + usageExample);
|
|
81
59
|
}
|
|
82
60
|
|
|
83
|
-
return
|
|
84
|
-
kind: "query",
|
|
85
|
-
query: text
|
|
86
|
-
};
|
|
61
|
+
return assetId;
|
|
87
62
|
}
|
|
88
63
|
|
|
89
64
|
function formatTypeLabel(assetType) {
|
|
@@ -156,100 +131,6 @@ function normalizeTimestamp(value) {
|
|
|
156
131
|
return "";
|
|
157
132
|
}
|
|
158
133
|
|
|
159
|
-
async function listAllUserAssets(client, authorId, assetType) {
|
|
160
|
-
const items = [];
|
|
161
|
-
let pageToken = "";
|
|
162
|
-
|
|
163
|
-
do {
|
|
164
|
-
const response = await client.listUserAssets({
|
|
165
|
-
userId: authorId,
|
|
166
|
-
assetType: toCatalogAssetType(assetType),
|
|
167
|
-
pageSize: 100,
|
|
168
|
-
pageToken
|
|
169
|
-
});
|
|
170
|
-
|
|
171
|
-
const pageItems = Array.isArray(response.data.items) ? response.data.items : [];
|
|
172
|
-
items.push.apply(items, pageItems);
|
|
173
|
-
pageToken = response.data.nextPageToken || "";
|
|
174
|
-
} while (pageToken);
|
|
175
|
-
|
|
176
|
-
return items;
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
function buildAmbiguousError(items) {
|
|
180
|
-
return (
|
|
181
|
-
"匹配到多个资产,请改用更精确的 assetId 或 type/@author/name。候选项: " +
|
|
182
|
-
items
|
|
183
|
-
.map(function mapItem(item) {
|
|
184
|
-
return (
|
|
185
|
-
(item.displayName || item.name || item.assetId) +
|
|
186
|
-
" [" +
|
|
187
|
-
(item.assetId || "") +
|
|
188
|
-
"] @" +
|
|
189
|
-
(item.ownerUserId || "unknown")
|
|
190
|
-
);
|
|
191
|
-
})
|
|
192
|
-
.join(", ")
|
|
193
|
-
);
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
function pickAssetFromItems(items, requestedName) {
|
|
197
|
-
const normalizedRequested = normalizeName(requestedName);
|
|
198
|
-
const exactMatches = items.filter(function filterItem(item) {
|
|
199
|
-
return (
|
|
200
|
-
item &&
|
|
201
|
-
(normalizeName(item.name) === normalizedRequested ||
|
|
202
|
-
normalizeName(item.displayName) === normalizedRequested)
|
|
203
|
-
);
|
|
204
|
-
});
|
|
205
|
-
|
|
206
|
-
if (exactMatches.length === 1) {
|
|
207
|
-
return exactMatches[0];
|
|
208
|
-
}
|
|
209
|
-
if (exactMatches.length > 1) {
|
|
210
|
-
throw new Error(buildAmbiguousError(exactMatches));
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
const fuzzyMatches = items.filter(function filterItem(item) {
|
|
214
|
-
return (
|
|
215
|
-
item &&
|
|
216
|
-
(normalizeName(item.name).includes(normalizedRequested) ||
|
|
217
|
-
normalizeName(item.displayName).includes(normalizedRequested))
|
|
218
|
-
);
|
|
219
|
-
});
|
|
220
|
-
|
|
221
|
-
if (fuzzyMatches.length === 1) {
|
|
222
|
-
return fuzzyMatches[0];
|
|
223
|
-
}
|
|
224
|
-
if (fuzzyMatches.length > 1) {
|
|
225
|
-
throw new Error(buildAmbiguousError(fuzzyMatches));
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
throw new Error("未找到资产: " + requestedName);
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
async function resolveAssetSummary(client, reference) {
|
|
232
|
-
if (reference.kind === "assetId") {
|
|
233
|
-
return {
|
|
234
|
-
assetId: reference.assetId
|
|
235
|
-
};
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
if (reference.kind === "typedAuthorName") {
|
|
239
|
-
const items = await listAllUserAssets(client, reference.authorId, reference.assetType);
|
|
240
|
-
return pickAssetFromItems(items, reference.query);
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
const response = await client.searchAssets({
|
|
244
|
-
query: reference.query,
|
|
245
|
-
assetType: reference.assetType ? toCatalogAssetType(reference.assetType) : 0,
|
|
246
|
-
pageSize: 50,
|
|
247
|
-
pageToken: ""
|
|
248
|
-
});
|
|
249
|
-
const items = Array.isArray(response.data.items) ? response.data.items : [];
|
|
250
|
-
return pickAssetFromItems(items, reference.query);
|
|
251
|
-
}
|
|
252
|
-
|
|
253
134
|
function printAssetInfo(detail, summary, semvers, verbose) {
|
|
254
135
|
const localAssetType = fromCatalogAssetType(detail.assetType);
|
|
255
136
|
const title = pickFirstText([detail.displayName, detail.name, detail.assetId]) || "(未命名资产)";
|
|
@@ -309,10 +190,7 @@ async function run(context) {
|
|
|
309
190
|
verbose: { type: "boolean" }
|
|
310
191
|
});
|
|
311
192
|
|
|
312
|
-
const
|
|
313
|
-
if (!rawReference) {
|
|
314
|
-
throw new Error("info 命令缺少资产标识");
|
|
315
|
-
}
|
|
193
|
+
const assetId = parseAssetId(parsed.positionals);
|
|
316
194
|
|
|
317
195
|
const requestId = parsed.options["request-id"] || generateRequestId();
|
|
318
196
|
const client = createCatalogClient({
|
|
@@ -321,13 +199,6 @@ async function run(context) {
|
|
|
321
199
|
requestId
|
|
322
200
|
});
|
|
323
201
|
|
|
324
|
-
const reference = parseAssetReference(rawReference);
|
|
325
|
-
const summary = await resolveAssetSummary(client, reference);
|
|
326
|
-
const assetId = summary.assetId;
|
|
327
|
-
if (!assetId) {
|
|
328
|
-
throw new Error("未能解析 assetId: " + rawReference);
|
|
329
|
-
}
|
|
330
|
-
|
|
331
202
|
const assetResponse = await client.getAsset({
|
|
332
203
|
assetId
|
|
333
204
|
});
|
|
@@ -340,13 +211,14 @@ async function run(context) {
|
|
|
340
211
|
const semvers = Array.isArray(semverResponse.data.items)
|
|
341
212
|
? semverResponse.data.items
|
|
342
213
|
: [];
|
|
214
|
+
const asset = assetResponse.data || {};
|
|
343
215
|
|
|
344
|
-
printAssetInfo(
|
|
216
|
+
printAssetInfo(asset, asset, semvers, Boolean(parsed.options.verbose));
|
|
345
217
|
|
|
346
218
|
return {
|
|
347
|
-
asset
|
|
219
|
+
asset,
|
|
348
220
|
semvers,
|
|
349
|
-
summary
|
|
221
|
+
summary: asset
|
|
350
222
|
};
|
|
351
223
|
}
|
|
352
224
|
|
package/lib/commands/install.js
CHANGED
|
@@ -4,8 +4,9 @@ const fs = require("node:fs/promises");
|
|
|
4
4
|
const os = require("node:os");
|
|
5
5
|
const path = require("node:path");
|
|
6
6
|
|
|
7
|
-
const { fromCatalogAssetType, normalizeLocalAssetType } = require("../asset-types");
|
|
7
|
+
const { VALID_ASSET_TYPES, fromCatalogAssetType, normalizeLocalAssetType } = require("../asset-types");
|
|
8
8
|
const { parseOptions } = require("../cli-parser");
|
|
9
|
+
const { CLI_NAME, buildInstallCommand } = require("../cli-text");
|
|
9
10
|
const { createCatalogClient } = require("../api");
|
|
10
11
|
const { resolveConnectBaseUrl, getInstallRoot } = require("../config");
|
|
11
12
|
const { loadHubCredentials } = require("../credentials");
|
|
@@ -22,21 +23,32 @@ const {
|
|
|
22
23
|
} = require("../utils");
|
|
23
24
|
|
|
24
25
|
function printHelp() {
|
|
25
|
-
console.log("
|
|
26
|
+
console.log(CLI_NAME + " install");
|
|
26
27
|
console.log("");
|
|
27
28
|
console.log("用法:");
|
|
28
|
-
console.log("
|
|
29
|
+
console.log(" " + CLI_NAME + " install <type>/<assetId>[@<semver>] [options]");
|
|
30
|
+
console.log("");
|
|
31
|
+
console.log("说明:");
|
|
32
|
+
console.log(" type 支持: " + VALID_ASSET_TYPES.join(", "));
|
|
33
|
+
console.log(" install 需要本地 token,默认读取 ~/.openclaw/hub-credentials.json");
|
|
34
|
+
console.log(" 可通过 --token-file <path> 指定其他凭证文件");
|
|
35
|
+
console.log(" 默认安装目录:");
|
|
36
|
+
console.log(" skill -> ~/.openclaw/skills");
|
|
37
|
+
console.log(" plugin -> ~/.openclaw/extensions");
|
|
38
|
+
console.log(" channel -> ~/.openclaw/extensions");
|
|
39
|
+
console.log(" trigger -> ~/.openclaw/triggers");
|
|
40
|
+
console.log(" experience -> ~/.openclaw/experiences");
|
|
29
41
|
console.log("");
|
|
30
42
|
console.log("示例:");
|
|
31
|
-
console.log("
|
|
32
|
-
console.log("
|
|
43
|
+
console.log(" " + buildInstallCommand("skill", "7c19dc4c3244418096f1dcb59c93f795"));
|
|
44
|
+
console.log(" " + buildInstallCommand("skill", "7c19dc4c3244418096f1dcb59c93f795", "1.0.3"));
|
|
33
45
|
console.log("");
|
|
34
46
|
console.log("参数:");
|
|
35
47
|
console.log(" --version <semver> 安装指定版本(也可写在 <assetId>@<semver>)");
|
|
36
48
|
console.log(" --base-url <url> API 基地址");
|
|
37
49
|
console.log(" --token-file <path> 本地命令行令牌文件");
|
|
38
50
|
console.log(" --request-id <id> 手动指定 X-Request-ID");
|
|
39
|
-
console.log(" --target-dir <path>
|
|
51
|
+
console.log(" --target-dir <path> 自定义安装根目录,最终会安装到 <target-dir>/<asset-name>");
|
|
40
52
|
console.log(" --verbose 输出更多上下文");
|
|
41
53
|
console.log(" -h, --help 查看帮助");
|
|
42
54
|
}
|
|
@@ -116,6 +128,18 @@ function resolveAssetTypeFromDetail(assetDetail) {
|
|
|
116
128
|
);
|
|
117
129
|
}
|
|
118
130
|
|
|
131
|
+
function buildReversionDownloadUrlRequest(assetId, semver) {
|
|
132
|
+
const request = {
|
|
133
|
+
assetId
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
if (semver && semver.reversionId) {
|
|
137
|
+
request.reversionId = semver.reversionId;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return request;
|
|
141
|
+
}
|
|
142
|
+
|
|
119
143
|
async function downloadBuffer(url) {
|
|
120
144
|
printTerminalOperationNotice("下载归档文件", [url]);
|
|
121
145
|
|
|
@@ -252,14 +276,11 @@ async function run(context) {
|
|
|
252
276
|
assetId: assetDetail.assetId || specifier.assetId,
|
|
253
277
|
latestSemver: assetDetail.latestSemver || ""
|
|
254
278
|
}, requestedVersion);
|
|
279
|
+
const resolvedAssetId = assetDetail.assetId || specifier.assetId;
|
|
255
280
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
const downloadInfo = await client.getReversionDownloadUrl({
|
|
261
|
-
reversionId: semver.reversionId
|
|
262
|
-
});
|
|
281
|
+
const downloadInfo = await client.getReversionDownloadUrl(
|
|
282
|
+
buildReversionDownloadUrlRequest(resolvedAssetId, semver)
|
|
283
|
+
);
|
|
263
284
|
|
|
264
285
|
const downloadUrl = downloadInfo.data.downloadUrl;
|
|
265
286
|
if (!downloadUrl) {
|
|
@@ -267,9 +288,11 @@ async function run(context) {
|
|
|
267
288
|
}
|
|
268
289
|
|
|
269
290
|
if (parsed.options.verbose) {
|
|
270
|
-
console.log("资产ID: " +
|
|
291
|
+
console.log("资产ID: " + resolvedAssetId);
|
|
271
292
|
console.log("下载版本: " + semver.semver);
|
|
272
|
-
|
|
293
|
+
if (semver.reversionId) {
|
|
294
|
+
console.log("reversionId: " + semver.reversionId);
|
|
295
|
+
}
|
|
273
296
|
console.log("downloadUrl: " + downloadUrl);
|
|
274
297
|
}
|
|
275
298
|
|
|
@@ -288,7 +311,6 @@ async function run(context) {
|
|
|
288
311
|
await installDownloadedArchive(downloaded.buffer, targetDir, fileNameHint);
|
|
289
312
|
await writeInstallMetadata(targetDir, assetDetail);
|
|
290
313
|
|
|
291
|
-
const resolvedAssetId = assetDetail.assetId || specifier.assetId;
|
|
292
314
|
const lockKey = specifier.assetType + "/" + resolvedAssetId;
|
|
293
315
|
await upsertInstalledAsset({
|
|
294
316
|
key: lockKey,
|
|
@@ -311,6 +333,7 @@ async function run(context) {
|
|
|
311
333
|
}
|
|
312
334
|
|
|
313
335
|
module.exports = {
|
|
336
|
+
buildReversionDownloadUrlRequest,
|
|
314
337
|
parseAssetSpecifier,
|
|
315
338
|
printHelp,
|
|
316
339
|
resolveRequestedVersion,
|
package/lib/commands/list.js
CHANGED
|
@@ -4,6 +4,7 @@ const fs = require("node:fs/promises");
|
|
|
4
4
|
const path = require("node:path");
|
|
5
5
|
|
|
6
6
|
const { parseOptions } = require("../cli-parser");
|
|
7
|
+
const { CLI_NAME } = require("../cli-text");
|
|
7
8
|
const { VALID_ASSET_TYPES, normalizeLocalAssetType } = require("../asset-types");
|
|
8
9
|
const { getInstallRoot } = require("../config");
|
|
9
10
|
const { normalizeInstallMetadata, readInstallMetadata } = require("../install-metadata");
|
|
@@ -20,10 +21,10 @@ const TYPE_ICONS = {
|
|
|
20
21
|
};
|
|
21
22
|
|
|
22
23
|
function printHelp() {
|
|
23
|
-
console.log("
|
|
24
|
+
console.log(CLI_NAME + " list");
|
|
24
25
|
console.log("");
|
|
25
26
|
console.log("用法:");
|
|
26
|
-
console.log("
|
|
27
|
+
console.log(" " + CLI_NAME + " list [options]");
|
|
27
28
|
console.log("");
|
|
28
29
|
console.log("参数:");
|
|
29
30
|
console.log(" --type <type> skill | experience | plugin | trigger | channel");
|
package/lib/commands/login.js
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
+
const { CLI_NAME } = require("../cli-text");
|
|
3
4
|
const { defaultCredentialsPath } = require("../config");
|
|
4
5
|
const { loadHubCredentials } = require("../credentials");
|
|
5
6
|
const { parseOptions } = require("../cli-parser");
|
|
6
7
|
|
|
7
8
|
function printHelp() {
|
|
8
|
-
console.log("
|
|
9
|
+
console.log(CLI_NAME + " login");
|
|
9
10
|
console.log("");
|
|
10
11
|
console.log("用法:");
|
|
11
|
-
console.log("
|
|
12
|
+
console.log(" " + CLI_NAME + " login [options]");
|
|
12
13
|
console.log("");
|
|
13
14
|
console.log("参数:");
|
|
14
15
|
console.log(" --token-file <path> 指定本地凭证文件路径");
|