openclawmp 1.0.3 → 1.0.5
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 +121 -97
- package/bin/openclawmp.js +3 -0
- package/lib/api.js +4 -0
- package/lib/commands/create-comment.js +130 -0
- package/lib/commands/help.js +3 -0
- package/lib/commands/install.js +6 -5
- package/lib/config.js +83 -1
- package/lib/help.js +7 -1
- package/lib/utils.js +2 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# 🐟 openclawmp
|
|
2
2
|
|
|
3
|
-
**OpenClaw Marketplace CLI** —
|
|
3
|
+
**OpenClaw Marketplace CLI** — 面向 OpenClaw Marketplace 的命令行工具。
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
用于在终端中完成资产搜索、用户搜索、详情查看、评论、安装、卸载、列表查看和发布等常用操作。当前支持的资产类型包括 `skill`、`experience`、`plugin`、`trigger`、`channel`。
|
|
6
6
|
|
|
7
7
|
## 安装
|
|
8
8
|
|
|
@@ -10,7 +10,7 @@ A command-line client for the [OpenClaw Marketplace](https://openclawmp.stepfun.
|
|
|
10
10
|
npm install -g openclawmp
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
运行要求:Node.js `>=18.0.0`。项目使用 Node 内置 `fetch`,无额外运行时依赖。
|
|
14
14
|
|
|
15
15
|
## 快速开始
|
|
16
16
|
|
|
@@ -18,13 +18,13 @@ npm install -g openclawmp
|
|
|
18
18
|
# 写入本地 token
|
|
19
19
|
openclawmp oauth <your-token>
|
|
20
20
|
|
|
21
|
+
# 查看本地登录状态
|
|
22
|
+
openclawmp login
|
|
23
|
+
|
|
21
24
|
# 搜索市场资产
|
|
22
25
|
openclawmp search 天气
|
|
23
26
|
|
|
24
|
-
#
|
|
25
|
-
openclawmp users 张三
|
|
26
|
-
|
|
27
|
-
# 根据 assetId 查看资产详情
|
|
27
|
+
# 查看资产详情
|
|
28
28
|
openclawmp info 6c476a36955a4270a3fa303beeeed5ee
|
|
29
29
|
|
|
30
30
|
# 安装资产
|
|
@@ -40,150 +40,174 @@ openclawmp uninstall skill/demo-skill
|
|
|
40
40
|
openclawmp publish ./my-asset --yes
|
|
41
41
|
```
|
|
42
42
|
|
|
43
|
-
##
|
|
44
|
-
|
|
45
|
-
- `search`:搜索市场资产,按类型、作者、安装量、标签和简介格式化输出。
|
|
46
|
-
- `users`:搜索用户,默认展示前 10 条,并显示总结果数与下一页游标。
|
|
47
|
-
- `oauth`:将 token 写入本地凭证文件。
|
|
48
|
-
- `info`:根据 `assetId` 查看资产详情与版本信息。
|
|
49
|
-
- `install`:根据 `assetId` 和可选 `semver` 下载归档并安装到本地 OpenClaw 目录。
|
|
50
|
-
- `uninstall`:删除本地安装目录,并清理对应锁文件记录。
|
|
51
|
-
- `list`:扫描本地已安装资产,结合 lockfile 和安装元数据展示结果。
|
|
52
|
-
- `publish`:打包本地目录并上传发布,串联 `createUpload`、`signUploadPartUrl`、`completeUpload`、`createAssetSemver`。
|
|
43
|
+
## 命令概览
|
|
53
44
|
|
|
54
|
-
|
|
45
|
+
| 命令 | 说明 |
|
|
46
|
+
| --- | --- |
|
|
47
|
+
| `login` | 查看当前本地 token 状态和凭证文件位置。 |
|
|
48
|
+
| `oauth` | 将 token 写入本地凭证文件。 |
|
|
49
|
+
| `search` | 按关键词搜索市场资产,并展示类型、作者、安装量、标签和简介等信息。 |
|
|
50
|
+
| `users` | 按关键词搜索用户,默认展示前 10 条,并显示总结果数与下一页游标。 |
|
|
51
|
+
| `info` | 根据 `assetId` 查看资产详情和版本信息。 |
|
|
52
|
+
| `createComment` | 给指定资产发送文本评论;当前用法为 `openclawmp createComment <assetId> <content>`,需要默认本地 token。 |
|
|
53
|
+
| `install` | 根据 `type/assetId` 和可选版本号下载并安装资产到本地目录。 |
|
|
54
|
+
| `list` | 扫描本地已安装资产,并结合锁文件和安装元数据展示结果。 |
|
|
55
|
+
| `uninstall` | 删除本地安装目录,并清理对应锁文件记录。 |
|
|
56
|
+
| `publish` | 校验、打包并发布本地资产目录或归档。 |
|
|
55
57
|
|
|
56
|
-
|
|
57
|
-
- `experience`
|
|
58
|
-
- `plugin`
|
|
59
|
-
- `trigger`
|
|
60
|
-
- `channel`
|
|
61
|
-
|
|
62
|
-
## 运行要求
|
|
63
|
-
|
|
64
|
-
- Node.js `>=18.0.0`
|
|
65
|
-
- 零运行时依赖
|
|
58
|
+
> 查看某个命令的完整参数:`openclawmp help <command>` 或 `openclawmp <command> --help`。
|
|
66
59
|
|
|
67
60
|
## 凭证
|
|
68
61
|
|
|
69
|
-
|
|
62
|
+
默认凭证文件:
|
|
70
63
|
|
|
71
|
-
- macOS / Linux
|
|
72
|
-
- Windows
|
|
64
|
+
- macOS / Linux:`~/.openclaw/hub-credentials.json`
|
|
65
|
+
- Windows:`%USERPROFILE%\.openclaw\hub-credentials.json`
|
|
73
66
|
|
|
74
|
-
|
|
67
|
+
文件最少需要包含:
|
|
75
68
|
|
|
76
69
|
```json
|
|
77
70
|
{
|
|
78
|
-
|
|
71
|
+
"token": "your-credential-token"
|
|
79
72
|
}
|
|
80
73
|
```
|
|
81
74
|
|
|
82
|
-
|
|
75
|
+
写入或查看凭证:
|
|
83
76
|
|
|
84
77
|
```bash
|
|
85
78
|
openclawmp oauth <your-token>
|
|
79
|
+
openclawmp login
|
|
86
80
|
```
|
|
87
81
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
- `Authorization: Bearer <credential token>`:受保护接口必需;`search` 可匿名调用
|
|
91
|
-
- `X-Request-ID`:自动生成,也可通过 `--request-id` 显式指定
|
|
92
|
-
- `Cli-Version`:自动带当前 package 版本
|
|
82
|
+
需要登录态的命令会读取本地 token;部分命令也支持通过 `--token-file <path>` 指定其他凭证文件,具体以命令帮助为准。
|
|
93
83
|
|
|
94
84
|
## 常用示例
|
|
95
85
|
|
|
96
|
-
|
|
97
|
-
npm install -g openclawmp
|
|
98
|
-
openclawmp oauth <your-token>
|
|
99
|
-
openclawmp publish /path/to/asset
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
示例:
|
|
86
|
+
### 搜索资产和用户
|
|
103
87
|
|
|
104
88
|
```bash
|
|
105
|
-
|
|
89
|
+
openclawmp search 天气 --page-size 10
|
|
90
|
+
openclawmp search "stock realtime" --page-size 10
|
|
91
|
+
openclawmp users openclawmp.cc
|
|
92
|
+
openclawmp users 窦窦 --page-size 20
|
|
106
93
|
```
|
|
107
94
|
|
|
108
|
-
|
|
109
|
-
{
|
|
110
|
-
"assetType": "skill",
|
|
111
|
-
"name": "my-skill",
|
|
112
|
-
"displayName": "My Skill",
|
|
113
|
-
"semver": "1.0.0",
|
|
114
|
-
"category": "productivity",
|
|
115
|
-
"tags": ["agent", "automation"]
|
|
116
|
-
}
|
|
117
|
-
```
|
|
95
|
+
### 查看资产详情
|
|
118
96
|
|
|
119
97
|
```bash
|
|
120
|
-
openclawmp
|
|
98
|
+
openclawmp info 6c476a36955a4270a3fa303beeeed5ee
|
|
121
99
|
```
|
|
122
100
|
|
|
123
|
-
|
|
101
|
+
### 发送资产评论
|
|
124
102
|
|
|
125
103
|
```bash
|
|
126
|
-
openclawmp
|
|
104
|
+
openclawmp createComment 8ec77f07430644bc3a848235d5c8d911 "这个资产很有帮助"
|
|
127
105
|
```
|
|
128
106
|
|
|
129
|
-
|
|
107
|
+
### 安装资产
|
|
130
108
|
|
|
131
109
|
```bash
|
|
132
|
-
openclawmp
|
|
110
|
+
openclawmp install skill/7c19dc4c3244418096f1dcb59c93f795
|
|
111
|
+
openclawmp install skill/7c19dc4c3244418096f1dcb59c93f795@1.0.3
|
|
112
|
+
openclawmp install skill/7c19dc4c3244418096f1dcb59c93f795 --version 1.0.3
|
|
133
113
|
```
|
|
134
114
|
|
|
135
|
-
|
|
115
|
+
默认安装根会优先跟随当前 OpenClaw / StepClaw state dir:
|
|
136
116
|
|
|
137
|
-
|
|
117
|
+
1. `OPENCLAWMP_INSTALL_ROOT`
|
|
118
|
+
2. `OPENCLAW_STATE_DIR` 或 `STEPCLAW_STATE_DIR`
|
|
119
|
+
3. `~/.stepclaw/stepclaw-install-state.json` 中记录的 state dir
|
|
120
|
+
4. 检测到 `~/.stepclaw` 时使用该目录
|
|
121
|
+
5. 否则回退到 `~/.openclaw`
|
|
138
122
|
|
|
139
|
-
|
|
140
|
-
openclawmp publish ./my-skill --dry-run
|
|
141
|
-
```
|
|
123
|
+
不同资产类型的默认子目录:
|
|
142
124
|
|
|
143
|
-
|
|
125
|
+
| 类型 | 默认子目录 |
|
|
126
|
+
| --- | --- |
|
|
127
|
+
| `skill` | `skills` |
|
|
128
|
+
| `plugin` / `channel` | `extensions` |
|
|
129
|
+
| `trigger` | `triggers` |
|
|
130
|
+
| `experience` | `experiences` |
|
|
144
131
|
|
|
145
|
-
|
|
146
|
-
openclawmp install skill/7c19dc4c3244418096f1dcb59c93f795
|
|
147
|
-
openclawmp install skill/7c19dc4c3244418096f1dcb59c93f795@1.0.3
|
|
148
|
-
```
|
|
132
|
+
也可以通过 `--target-dir <path>` 显式指定安装根目录。
|
|
149
133
|
|
|
150
|
-
|
|
134
|
+
### 列出和卸载本地资产
|
|
151
135
|
|
|
152
136
|
```bash
|
|
137
|
+
openclawmp list
|
|
138
|
+
openclawmp list --type skill
|
|
153
139
|
openclawmp uninstall skill/7c19dc4c3244418096f1dcb59c93f795
|
|
154
140
|
openclawmp uninstall skill/demo-skill
|
|
141
|
+
openclawmp uninstall skill/@author/name
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### 发布资产
|
|
145
|
+
|
|
146
|
+
发布目录或归档中必须包含 `.metadata.json`:
|
|
147
|
+
|
|
148
|
+
```json
|
|
149
|
+
{
|
|
150
|
+
"assetType": "skill",
|
|
151
|
+
"name": "my-skill",
|
|
152
|
+
"displayName": "My Skill",
|
|
153
|
+
"semver": "1.0.0",
|
|
154
|
+
"category": "productivity",
|
|
155
|
+
"tags": ["agent", "automation"],
|
|
156
|
+
"description": "A short description"
|
|
157
|
+
}
|
|
155
158
|
```
|
|
156
159
|
|
|
157
|
-
|
|
160
|
+
发布示例:
|
|
158
161
|
|
|
159
162
|
```bash
|
|
160
|
-
openclawmp
|
|
161
|
-
openclawmp
|
|
163
|
+
openclawmp publish ./my-skill --yes
|
|
164
|
+
openclawmp publish ./my-skill --asset-id s-123456 --yes
|
|
165
|
+
openclawmp publish ./my-skill --dry-run
|
|
162
166
|
```
|
|
163
167
|
|
|
164
|
-
|
|
168
|
+
如果目录根部存在 `.assetid`,发布时会自动作为目标资产 ID 使用;也可通过 `--asset-id <id>` 显式指定。
|
|
169
|
+
|
|
170
|
+
`--dry-run` 只做本地校验和打包,不提交发布。
|
|
171
|
+
|
|
172
|
+
## 发布 Metadata 规则
|
|
173
|
+
|
|
174
|
+
- `publish` 只读取发布目录或归档里的 `.metadata.json`。
|
|
175
|
+
- `.metadata.json` 必须包含 `assetType`、`name`、`displayName`、`semver`。
|
|
176
|
+
- `assetType` 支持:`skill`、`experience`、`plugin`、`trigger`、`channel`。
|
|
177
|
+
- `semver` 必须是严格的 `x.y.z` 纯数字格式,例如 `1.2.3`。
|
|
178
|
+
- 可选字段:`assetId`、`category`、`tags`、`description`、`longDescription`。
|
|
179
|
+
- 不再从 `README.md`、`package.json`、`openclaw.plugin.json`、`SKILL.md` 自动推断发布 metadata。
|
|
180
|
+
- 不再通过 CLI 参数补录 `assetType`、`name`、`displayName`、`semver`。
|
|
181
|
+
- `assetId` 可写在 `.metadata.json`,也可以通过 `--asset-id` 或目录根部 `.assetid` 传入。
|
|
182
|
+
- 默认不打印请求细节;加 `--verbose` 会额外输出调试信息。
|
|
183
|
+
|
|
184
|
+
## 发布打包规则
|
|
185
|
+
|
|
186
|
+
- 目录发布会默认跳过 `.git`、`node_modules`、`__MACOSX`、`.DS_Store`、`Thumbs.db`。
|
|
187
|
+
- 根目录可通过 `.openclawmpignore` 补充忽略规则,也会读取根目录 `.gitignore` / `.npmignore` 的常见规则。
|
|
188
|
+
- 子路径遇到无权限读取的目录或文件时会自动跳过;使用 `--verbose` 可查看具体跳过项。
|
|
165
189
|
|
|
166
|
-
|
|
190
|
+
## 常用参数
|
|
167
191
|
|
|
168
|
-
|
|
169
|
-
- `oauth`
|
|
170
|
-
- `search`
|
|
171
|
-
- `users`
|
|
172
|
-
- `info`
|
|
173
|
-
- `install`
|
|
174
|
-
- `uninstall`
|
|
175
|
-
- `list`
|
|
192
|
+
不同命令支持的参数略有差异,请以 `--help` 输出为准。常见参数包括:
|
|
176
193
|
|
|
177
|
-
|
|
194
|
+
| 参数 | 说明 |
|
|
195
|
+
| --- | --- |
|
|
196
|
+
| `--base-url <url>` | 指定服务基地址。 |
|
|
197
|
+
| `--token-file <path>` | 指定本地凭证文件。 |
|
|
198
|
+
| `--request-id <id>` | 指定请求追踪 ID。 |
|
|
199
|
+
| `--page-size <number>` | 指定搜索分页大小。 |
|
|
200
|
+
| `--page-token <token>` | 指定下一页游标。 |
|
|
201
|
+
| `--verbose` | 输出更多调试信息。 |
|
|
202
|
+
| `-h, --help` | 查看帮助。 |
|
|
203
|
+
| `-v, --version` | 查看版本。 |
|
|
178
204
|
|
|
179
|
-
|
|
205
|
+
服务基地址优先级:
|
|
180
206
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
- `--yes, -y`
|
|
189
|
-
- `--verbose`
|
|
207
|
+
1. `--base-url`
|
|
208
|
+
2. `OPENCLAWMP_API_BASE_URL`
|
|
209
|
+
3. `OPENCLAWMP_BASE_URL`
|
|
210
|
+
4. `API_BASE_URL`
|
|
211
|
+
5. `NEXT_PUBLIC_API_BASE_URL`
|
|
212
|
+
6. 仓库根目录 `.env.local` / `.env` / `.env.prod`
|
|
213
|
+
7. `https://openclawmp.stepfun.com`
|
package/bin/openclawmp.js
CHANGED
|
@@ -27,6 +27,9 @@ const COMMAND_LOADERS = {
|
|
|
27
27
|
users: function loadUsers() {
|
|
28
28
|
return require("../lib/commands/users");
|
|
29
29
|
},
|
|
30
|
+
createComment: function loadCreateComment() {
|
|
31
|
+
return require("../lib/commands/create-comment");
|
|
32
|
+
},
|
|
30
33
|
info: function loadInfo() {
|
|
31
34
|
return require("../lib/commands/info");
|
|
32
35
|
},
|
package/lib/api.js
CHANGED
|
@@ -11,6 +11,7 @@ const {
|
|
|
11
11
|
|
|
12
12
|
const CATALOG_SERVICE = "step.seafood.catalog.CatalogService";
|
|
13
13
|
const IDENTITY_SERVICE = "step.seafood.identity.IdentityService";
|
|
14
|
+
const ENGAGEMENT_SERVICE = "step.seafood.engagement.EngagementService";
|
|
14
15
|
|
|
15
16
|
class ApiError extends Error {
|
|
16
17
|
constructor(message, details) {
|
|
@@ -245,6 +246,9 @@ function createCatalogClient(options) {
|
|
|
245
246
|
searchUsers: function searchUsers(body, extra) {
|
|
246
247
|
return unaryForService(IDENTITY_SERVICE, "SearchUsers", body, extra);
|
|
247
248
|
},
|
|
249
|
+
createComment: function createComment(body, extra) {
|
|
250
|
+
return unaryForService(ENGAGEMENT_SERVICE, "CreateComment", body, extra);
|
|
251
|
+
},
|
|
248
252
|
listUserAssets: function listUserAssets(body, extra) {
|
|
249
253
|
return unary("ListUserAssets", body, extra);
|
|
250
254
|
},
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const { parseOptions } = require("../cli-parser");
|
|
4
|
+
const { CLI_NAME } = require("../cli-text");
|
|
5
|
+
const { createCatalogClient } = require("../api");
|
|
6
|
+
const { loadHubCredentials } = require("../credentials");
|
|
7
|
+
const { defaultCredentialsPath, resolveConnectBaseUrl } = require("../config");
|
|
8
|
+
const { generateRequestId, trimOrUndefined } = require("../utils");
|
|
9
|
+
|
|
10
|
+
function printHelp() {
|
|
11
|
+
console.log(CLI_NAME + " createComment");
|
|
12
|
+
console.log("");
|
|
13
|
+
console.log("用法:");
|
|
14
|
+
console.log(" " + CLI_NAME + " createComment <assetId> <content>");
|
|
15
|
+
console.log("");
|
|
16
|
+
console.log("说明:");
|
|
17
|
+
console.log(" 调用 step.seafood.engagement.EngagementService/CreateComment 发送文本评论。");
|
|
18
|
+
console.log(" 命令只支持最简单的 assetId + 评论内容用法。");
|
|
19
|
+
console.log(" baseUrl 和 token 读取方式与 publish 命令一致。");
|
|
20
|
+
console.log("");
|
|
21
|
+
console.log("示例:");
|
|
22
|
+
console.log(" " + CLI_NAME + " createComment 8ec77f07430644bc3a848235d5c8d911 \"agrent\"");
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function firstText(values) {
|
|
26
|
+
return values.find(function findValue(value) {
|
|
27
|
+
return typeof value === "string" && value.trim();
|
|
28
|
+
}) || "";
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function parseArguments(positionals) {
|
|
32
|
+
const args = Array.isArray(positionals) ? positionals : [];
|
|
33
|
+
const assetId = trimOrUndefined(args[0]) || "";
|
|
34
|
+
const content = args.slice(1).join(" ").trim();
|
|
35
|
+
|
|
36
|
+
if (!assetId) {
|
|
37
|
+
throw new Error("createComment 命令缺少 assetId");
|
|
38
|
+
}
|
|
39
|
+
if (/\s/u.test(assetId) || assetId.includes("/")) {
|
|
40
|
+
throw new Error("createComment 命令的 assetId 格式不正确");
|
|
41
|
+
}
|
|
42
|
+
if (!content) {
|
|
43
|
+
throw new Error("createComment 命令缺少评论内容");
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return {
|
|
47
|
+
assetId,
|
|
48
|
+
content
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function buildCreateCommentRequest(assetId, content) {
|
|
53
|
+
return {
|
|
54
|
+
assetId,
|
|
55
|
+
contentSegments: [
|
|
56
|
+
{
|
|
57
|
+
type: "COMMENT_CONTENT_TYPE_TEXT",
|
|
58
|
+
text: content
|
|
59
|
+
}
|
|
60
|
+
]
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function resolveCommentId(data) {
|
|
65
|
+
if (!data || typeof data !== "object") {
|
|
66
|
+
return "";
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return firstText([
|
|
70
|
+
data.commentId,
|
|
71
|
+
data.id,
|
|
72
|
+
data.comment && data.comment.commentId,
|
|
73
|
+
data.comment && data.comment.id
|
|
74
|
+
]);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function loadCommentCredentials() {
|
|
78
|
+
try {
|
|
79
|
+
return loadHubCredentials();
|
|
80
|
+
} catch {
|
|
81
|
+
throw new Error(
|
|
82
|
+
[
|
|
83
|
+
"未检测到可用于发送评论的登录态。",
|
|
84
|
+
"请先通过 " + CLI_NAME + " oauth <token> 写入 token,或手动写入 " + defaultCredentialsPath() + "。"
|
|
85
|
+
].join("\n")
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
async function run(context) {
|
|
91
|
+
const parsed = parseOptions(context.argv, {});
|
|
92
|
+
const args = parseArguments(parsed.positionals);
|
|
93
|
+
const loadedCredentials = loadCommentCredentials();
|
|
94
|
+
const requestId = generateRequestId();
|
|
95
|
+
const client = createCatalogClient({
|
|
96
|
+
baseUrl: resolveConnectBaseUrl(),
|
|
97
|
+
token: loadedCredentials.credentials.token,
|
|
98
|
+
cliVersion: context.cliVersion,
|
|
99
|
+
requestId
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
const response = await client.createComment(
|
|
103
|
+
buildCreateCommentRequest(args.assetId, args.content)
|
|
104
|
+
);
|
|
105
|
+
const data = response.data || {};
|
|
106
|
+
const commentId = resolveCommentId(data);
|
|
107
|
+
|
|
108
|
+
console.log("");
|
|
109
|
+
console.log("评论发送成功");
|
|
110
|
+
console.log("- assetId: " + args.assetId);
|
|
111
|
+
if (commentId) {
|
|
112
|
+
console.log("- commentId: " + commentId);
|
|
113
|
+
}
|
|
114
|
+
console.log("- 内容: " + args.content);
|
|
115
|
+
|
|
116
|
+
return {
|
|
117
|
+
assetId: args.assetId,
|
|
118
|
+
content: args.content,
|
|
119
|
+
commentId,
|
|
120
|
+
data,
|
|
121
|
+
requestId: response.requestId
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
module.exports = {
|
|
126
|
+
buildCreateCommentRequest,
|
|
127
|
+
parseArguments,
|
|
128
|
+
printHelp,
|
|
129
|
+
run
|
|
130
|
+
};
|
package/lib/commands/help.js
CHANGED
package/lib/commands/install.js
CHANGED
|
@@ -33,11 +33,12 @@ function printHelp() {
|
|
|
33
33
|
console.log(" install 需要本地 token,默认读取 ~/.openclaw/hub-credentials.json");
|
|
34
34
|
console.log(" 可通过 --token-file <path> 指定其他凭证文件");
|
|
35
35
|
console.log(" 默认安装目录:");
|
|
36
|
-
console.log("
|
|
37
|
-
console.log("
|
|
38
|
-
console.log("
|
|
39
|
-
console.log("
|
|
40
|
-
console.log("
|
|
36
|
+
console.log(" 优先跟随当前 OpenClaw/StepClaw state dir(OPENCLAW_STATE_DIR、STEPCLAW_STATE_DIR 或 ~/.stepclaw)");
|
|
37
|
+
console.log(" 未检测到 StepClaw 时回退到 ~/.openclaw");
|
|
38
|
+
console.log(" skill -> <state-dir>/skills 或 ~/.openclaw/skills");
|
|
39
|
+
console.log(" plugin/channel -> <state-dir>/extensions 或 ~/.openclaw/extensions");
|
|
40
|
+
console.log(" trigger -> <state-dir>/triggers 或 ~/.openclaw/triggers");
|
|
41
|
+
console.log(" experience -> <state-dir>/experiences 或 ~/.openclaw/experiences");
|
|
41
42
|
console.log("");
|
|
42
43
|
console.log("示例:");
|
|
43
44
|
console.log(" " + buildInstallCommand("skill", "7c19dc4c3244418096f1dcb59c93f795"));
|
package/lib/config.js
CHANGED
|
@@ -17,6 +17,12 @@ const INSTALL_ROOT_BY_TYPE = {
|
|
|
17
17
|
experience: ["experiences"],
|
|
18
18
|
template: ["templates"],
|
|
19
19
|
};
|
|
20
|
+
const OPENCLAWMP_INSTALL_ROOT_ENV = "OPENCLAWMP_INSTALL_ROOT";
|
|
21
|
+
const OPENCLAW_STATE_DIR_ENV = "OPENCLAW_STATE_DIR";
|
|
22
|
+
const STEPCLAW_STATE_DIR_ENV = "STEPCLAW_STATE_DIR";
|
|
23
|
+
const STEPCLAW_STATE_DIR_NAME = ".stepclaw";
|
|
24
|
+
const STEPCLAW_INSTALL_STATE_FILE = "stepclaw-install-state.json";
|
|
25
|
+
const STEPCLAW_RUNTIME_STATE_FILE = "stepclaw-state.json";
|
|
20
26
|
|
|
21
27
|
function parseEnvFile(content) {
|
|
22
28
|
const result = {};
|
|
@@ -68,6 +74,26 @@ function firstDefined(values) {
|
|
|
68
74
|
});
|
|
69
75
|
}
|
|
70
76
|
|
|
77
|
+
function trimString(value) {
|
|
78
|
+
return typeof value === "string" ? value.trim() : "";
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function expandHomePath(value) {
|
|
82
|
+
const trimmed = trimString(value);
|
|
83
|
+
if (trimmed === "~") {
|
|
84
|
+
return os.homedir();
|
|
85
|
+
}
|
|
86
|
+
if (trimmed.startsWith("~/") || trimmed.startsWith("~\\")) {
|
|
87
|
+
return path.join(os.homedir(), trimmed.slice(2));
|
|
88
|
+
}
|
|
89
|
+
return trimmed;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function resolvePathValue(value) {
|
|
93
|
+
const expanded = expandHomePath(value);
|
|
94
|
+
return expanded ? path.resolve(expanded) : "";
|
|
95
|
+
}
|
|
96
|
+
|
|
71
97
|
function normalizeBaseUrl(value) {
|
|
72
98
|
return String(value)
|
|
73
99
|
.trim()
|
|
@@ -100,6 +126,53 @@ function getOpenClawHome() {
|
|
|
100
126
|
return path.join(os.homedir(), ".openclaw");
|
|
101
127
|
}
|
|
102
128
|
|
|
129
|
+
function getDefaultStepClawStateDir() {
|
|
130
|
+
return path.join(os.homedir(), STEPCLAW_STATE_DIR_NAME);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function readJsonFileIfExists(filePath) {
|
|
134
|
+
try {
|
|
135
|
+
return JSON.parse(fs.readFileSync(filePath, "utf8"));
|
|
136
|
+
} catch (error) {
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function looksLikeStepClawStateDir(stateDir) {
|
|
142
|
+
return (
|
|
143
|
+
fs.existsSync(path.join(stateDir, "openclaw.json")) ||
|
|
144
|
+
fs.existsSync(path.join(stateDir, STEPCLAW_INSTALL_STATE_FILE)) ||
|
|
145
|
+
fs.existsSync(
|
|
146
|
+
path.join(stateDir, "runtime", STEPCLAW_RUNTIME_STATE_FILE),
|
|
147
|
+
)
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function resolveStepClawStateDir() {
|
|
152
|
+
const envStateDir = firstDefined([
|
|
153
|
+
process.env[OPENCLAW_STATE_DIR_ENV],
|
|
154
|
+
process.env[STEPCLAW_STATE_DIR_ENV],
|
|
155
|
+
]);
|
|
156
|
+
if (envStateDir) {
|
|
157
|
+
return resolvePathValue(envStateDir);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const defaultStateDir = getDefaultStepClawStateDir();
|
|
161
|
+
const presence = readJsonFileIfExists(
|
|
162
|
+
path.join(defaultStateDir, STEPCLAW_INSTALL_STATE_FILE),
|
|
163
|
+
);
|
|
164
|
+
const redirectedStateDir = trimString(presence && presence.stateDir);
|
|
165
|
+
if (redirectedStateDir) {
|
|
166
|
+
return resolvePathValue(redirectedStateDir);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (looksLikeStepClawStateDir(defaultStateDir)) {
|
|
170
|
+
return defaultStateDir;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
return "";
|
|
174
|
+
}
|
|
175
|
+
|
|
103
176
|
function defaultCredentialsPath() {
|
|
104
177
|
return path.join(getOpenClawHome(), "hub-credentials.json");
|
|
105
178
|
}
|
|
@@ -109,7 +182,14 @@ function getLockfilePath() {
|
|
|
109
182
|
}
|
|
110
183
|
|
|
111
184
|
function getManagedAssetsRoot() {
|
|
112
|
-
|
|
185
|
+
const explicitInstallRoot = firstDefined([
|
|
186
|
+
process.env[OPENCLAWMP_INSTALL_ROOT_ENV],
|
|
187
|
+
]);
|
|
188
|
+
if (explicitInstallRoot) {
|
|
189
|
+
return resolvePathValue(explicitInstallRoot);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
return resolveStepClawStateDir() || getOpenClawHome();
|
|
113
193
|
}
|
|
114
194
|
|
|
115
195
|
function getInstallRoot(assetType) {
|
|
@@ -126,6 +206,8 @@ module.exports = {
|
|
|
126
206
|
resolveApiBaseUrl,
|
|
127
207
|
resolveConnectBaseUrl,
|
|
128
208
|
getOpenClawHome,
|
|
209
|
+
getDefaultStepClawStateDir,
|
|
210
|
+
resolveStepClawStateDir,
|
|
129
211
|
defaultCredentialsPath,
|
|
130
212
|
getLockfilePath,
|
|
131
213
|
getManagedAssetsRoot,
|
package/lib/help.js
CHANGED
|
@@ -33,6 +33,11 @@ const COMMAND_SECTIONS = [
|
|
|
33
33
|
description: "搜索用户",
|
|
34
34
|
usage: CLI_NAME + " users <keyword> [options]"
|
|
35
35
|
},
|
|
36
|
+
{
|
|
37
|
+
name: "createComment",
|
|
38
|
+
description: "发送资产评论",
|
|
39
|
+
usage: CLI_NAME + " createComment <assetId> <content>"
|
|
40
|
+
},
|
|
36
41
|
{
|
|
37
42
|
name: "info",
|
|
38
43
|
description: "查看某个资产的详细信息",
|
|
@@ -63,7 +68,7 @@ function printGlobalHelp() {
|
|
|
63
68
|
console.log("");
|
|
64
69
|
console.log("命令:");
|
|
65
70
|
COMMAND_SECTIONS.forEach(function eachSection(section) {
|
|
66
|
-
const paddedName = (section.name + "
|
|
71
|
+
const paddedName = (section.name + " ").slice(0, 15);
|
|
67
72
|
console.log(" " + paddedName + section.description);
|
|
68
73
|
});
|
|
69
74
|
console.log("");
|
|
@@ -82,6 +87,7 @@ function printGlobalHelp() {
|
|
|
82
87
|
console.log(" " + CLI_NAME + " publish ./my-asset --yes");
|
|
83
88
|
console.log(" " + CLI_NAME + " search 天气");
|
|
84
89
|
console.log(" " + CLI_NAME + " users openclawmp.cc");
|
|
90
|
+
console.log(" " + CLI_NAME + " createComment 8ec77f07430644bc3a848235d5c8d911 \"agrent\"");
|
|
85
91
|
console.log(" " + CLI_NAME + " info 6c476a36955a4270a3fa303beeeed5ee");
|
|
86
92
|
console.log(" " + buildInstallCommand("skill", "7c19dc4c3244418096f1dcb59c93f795"));
|
|
87
93
|
console.log(" " + buildInstallCommand("skill", "7c19dc4c3244418096f1dcb59c93f795", "1.0.3"));
|
package/lib/utils.js
CHANGED