openclawmp 1.0.2 → 1.0.4
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 +9 -1
- package/bin/openclawmp.js +3 -0
- package/lib/api.js +10 -2
- package/lib/commands/help.js +3 -0
- package/lib/commands/install.js +6 -5
- package/lib/commands/users.js +247 -0
- package/lib/config.js +81 -1
- package/lib/help.js +6 -0
- package/lib/utils.js +2 -0
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -21,6 +21,9 @@ openclawmp oauth <your-token>
|
|
|
21
21
|
# 搜索市场资产
|
|
22
22
|
openclawmp search 天气
|
|
23
23
|
|
|
24
|
+
# 搜索用户
|
|
25
|
+
openclawmp users 张三
|
|
26
|
+
|
|
24
27
|
# 根据 assetId 查看资产详情
|
|
25
28
|
openclawmp info 6c476a36955a4270a3fa303beeeed5ee
|
|
26
29
|
|
|
@@ -40,6 +43,7 @@ openclawmp publish ./my-asset --yes
|
|
|
40
43
|
## 功能概览
|
|
41
44
|
|
|
42
45
|
- `search`:搜索市场资产,按类型、作者、安装量、标签和简介格式化输出。
|
|
46
|
+
- `users`:搜索用户,默认展示前 10 条,并显示总结果数与下一页游标。
|
|
43
47
|
- `oauth`:将 token 写入本地凭证文件。
|
|
44
48
|
- `info`:根据 `assetId` 查看资产详情与版本信息。
|
|
45
49
|
- `install`:根据 `assetId` 和可选 `semver` 下载归档并安装到本地 OpenClaw 目录。
|
|
@@ -143,6 +147,8 @@ openclawmp install skill/7c19dc4c3244418096f1dcb59c93f795
|
|
|
143
147
|
openclawmp install skill/7c19dc4c3244418096f1dcb59c93f795@1.0.3
|
|
144
148
|
```
|
|
145
149
|
|
|
150
|
+
默认安装根会优先跟随当前 OpenClaw/StepClaw state dir(`OPENCLAW_STATE_DIR`、`STEPCLAW_STATE_DIR` 或 `~/.stepclaw/stepclaw-install-state.json`),未检测到 StepClaw 时回退到 `~/.openclaw`。也可通过 `--target-dir <path>` 显式指定安装根。
|
|
151
|
+
|
|
146
152
|
卸载示例:
|
|
147
153
|
|
|
148
154
|
```bash
|
|
@@ -154,6 +160,7 @@ openclawmp uninstall skill/demo-skill
|
|
|
154
160
|
|
|
155
161
|
```bash
|
|
156
162
|
openclawmp search 天气 --page-size 10
|
|
163
|
+
openclawmp users openclawmp.cc
|
|
157
164
|
```
|
|
158
165
|
|
|
159
166
|
## 命令结构
|
|
@@ -163,12 +170,13 @@ openclawmp search 天气 --page-size 10
|
|
|
163
170
|
- `publish`
|
|
164
171
|
- `oauth`
|
|
165
172
|
- `search`
|
|
173
|
+
- `users`
|
|
166
174
|
- `info`
|
|
167
175
|
- `install`
|
|
168
176
|
- `uninstall`
|
|
169
177
|
- `list`
|
|
170
178
|
|
|
171
|
-
其中当前可用的是 `publish`、`oauth`、`search`、`info`、`install`、`uninstall`、`list`。
|
|
179
|
+
其中当前可用的是 `publish`、`oauth`、`search`、`users`、`info`、`install`、`uninstall`、`list`。
|
|
172
180
|
|
|
173
181
|
## 发布命令参数
|
|
174
182
|
|
package/bin/openclawmp.js
CHANGED
|
@@ -24,6 +24,9 @@ const COMMAND_LOADERS = {
|
|
|
24
24
|
search: function loadSearch() {
|
|
25
25
|
return require("../lib/commands/search");
|
|
26
26
|
},
|
|
27
|
+
users: function loadUsers() {
|
|
28
|
+
return require("../lib/commands/users");
|
|
29
|
+
},
|
|
27
30
|
info: function loadInfo() {
|
|
28
31
|
return require("../lib/commands/info");
|
|
29
32
|
},
|
package/lib/api.js
CHANGED
|
@@ -10,6 +10,7 @@ const {
|
|
|
10
10
|
} = require("./utils");
|
|
11
11
|
|
|
12
12
|
const CATALOG_SERVICE = "step.seafood.catalog.CatalogService";
|
|
13
|
+
const IDENTITY_SERVICE = "step.seafood.identity.IdentityService";
|
|
13
14
|
|
|
14
15
|
class ApiError extends Error {
|
|
15
16
|
constructor(message, details) {
|
|
@@ -136,10 +137,10 @@ function createCatalogClient(options) {
|
|
|
136
137
|
const defaultRequestId = normalizeRequestId(options.requestId) || generateRequestId();
|
|
137
138
|
const verbose = Boolean(options.verbose);
|
|
138
139
|
|
|
139
|
-
async function
|
|
140
|
+
async function unaryForService(serviceName, methodName, body, extra) {
|
|
140
141
|
const requestId = normalizeRequestId((extra && extra.requestId) || defaultRequestId);
|
|
141
142
|
const operationName = humanizeApiMethodName(methodName) || methodName || "接口调用";
|
|
142
|
-
const requestUrl = String(buildServiceUrl(options.baseUrl,
|
|
143
|
+
const requestUrl = String(buildServiceUrl(options.baseUrl, serviceName, methodName));
|
|
143
144
|
const requestBody = JSON.stringify(body || {}, jsonReplacer);
|
|
144
145
|
const headers = {
|
|
145
146
|
"Connect-Protocol-Version": "1",
|
|
@@ -233,10 +234,17 @@ function createCatalogClient(options) {
|
|
|
233
234
|
};
|
|
234
235
|
}
|
|
235
236
|
|
|
237
|
+
async function unary(methodName, body, extra) {
|
|
238
|
+
return unaryForService(CATALOG_SERVICE, methodName, body, extra);
|
|
239
|
+
}
|
|
240
|
+
|
|
236
241
|
return {
|
|
237
242
|
searchAssets: function searchAssets(body, extra) {
|
|
238
243
|
return unary("SearchAssets", body, extra);
|
|
239
244
|
},
|
|
245
|
+
searchUsers: function searchUsers(body, extra) {
|
|
246
|
+
return unaryForService(IDENTITY_SERVICE, "SearchUsers", body, extra);
|
|
247
|
+
},
|
|
240
248
|
listUserAssets: function listUserAssets(body, extra) {
|
|
241
249
|
return unary("ListUserAssets", body, extra);
|
|
242
250
|
},
|
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"));
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const { parseOptions } = require("../cli-parser");
|
|
4
|
+
const { createCatalogClient } = require("../api");
|
|
5
|
+
const { CLI_NAME } = require("../cli-text");
|
|
6
|
+
const { resolveApiBaseUrl, resolveConnectBaseUrl } = require("../config");
|
|
7
|
+
const { generateRequestId } = require("../utils");
|
|
8
|
+
|
|
9
|
+
const DEFAULT_PAGE_SIZE = 10;
|
|
10
|
+
const DEFAULT_SORT_BY = "SEARCH_USERS_SORT_BY_BEST_MATCH";
|
|
11
|
+
|
|
12
|
+
function printHelp() {
|
|
13
|
+
console.log(CLI_NAME + " users");
|
|
14
|
+
console.log("");
|
|
15
|
+
console.log("用法:");
|
|
16
|
+
console.log(" " + CLI_NAME + " users <keyword> [options]");
|
|
17
|
+
console.log("");
|
|
18
|
+
console.log("参数:");
|
|
19
|
+
console.log(" --page-size <number> 每页条数,默认 10");
|
|
20
|
+
console.log(" --page-token <token> 分页游标");
|
|
21
|
+
console.log(" --request-id <id> 手动指定 X-Request-ID");
|
|
22
|
+
console.log(" --verbose 输出更多上下文");
|
|
23
|
+
console.log(" -h, --help 查看帮助");
|
|
24
|
+
console.log("");
|
|
25
|
+
console.log("示例:");
|
|
26
|
+
console.log(" " + CLI_NAME + " users openclawmp.cc");
|
|
27
|
+
console.log(" " + CLI_NAME + " users 窦窦 --page-size 20");
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function pickFirstText(values) {
|
|
31
|
+
return values.find(function findValue(value) {
|
|
32
|
+
return typeof value === "string" && value.trim();
|
|
33
|
+
}) || "";
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function pickFirstScalar(values) {
|
|
37
|
+
return values.find(function findValue(value) {
|
|
38
|
+
if (typeof value === "string") {
|
|
39
|
+
return value.trim();
|
|
40
|
+
}
|
|
41
|
+
return typeof value === "number" && Number.isFinite(value);
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function normalizePageSize(value) {
|
|
46
|
+
if (value === undefined) {
|
|
47
|
+
return DEFAULT_PAGE_SIZE;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (!Number.isInteger(value) || value <= 0) {
|
|
51
|
+
throw new Error("--page-size 需要是大于 0 的整数");
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return value;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function formatCount(value) {
|
|
58
|
+
const numeric = Number(value);
|
|
59
|
+
if (Number.isFinite(numeric)) {
|
|
60
|
+
return numeric.toLocaleString("zh-CN");
|
|
61
|
+
}
|
|
62
|
+
return String(value || "0");
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function resolveItems(data) {
|
|
66
|
+
if (Array.isArray(data.items)) {
|
|
67
|
+
return data.items;
|
|
68
|
+
}
|
|
69
|
+
if (Array.isArray(data.users)) {
|
|
70
|
+
return data.users;
|
|
71
|
+
}
|
|
72
|
+
return [];
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function resolveTotalSize(data, items) {
|
|
76
|
+
const total = pickFirstScalar([
|
|
77
|
+
data.totalSize,
|
|
78
|
+
data.total_size,
|
|
79
|
+
data.totalCount,
|
|
80
|
+
data.total_count,
|
|
81
|
+
data.total,
|
|
82
|
+
data.count
|
|
83
|
+
]);
|
|
84
|
+
if (total !== undefined) {
|
|
85
|
+
return String(total);
|
|
86
|
+
}
|
|
87
|
+
return String(items.length);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function resolveNextPageToken(data) {
|
|
91
|
+
return pickFirstText([data.nextPageToken, data.next_page_token]);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function resolveUser(item) {
|
|
95
|
+
if (!item || typeof item !== "object") {
|
|
96
|
+
return {};
|
|
97
|
+
}
|
|
98
|
+
if (item.user && typeof item.user === "object") {
|
|
99
|
+
return item.user;
|
|
100
|
+
}
|
|
101
|
+
if (item.profile && typeof item.profile === "object") {
|
|
102
|
+
return item.profile;
|
|
103
|
+
}
|
|
104
|
+
return item;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function resolveDisplayName(user) {
|
|
108
|
+
return pickFirstText([
|
|
109
|
+
user.displayName,
|
|
110
|
+
user.name,
|
|
111
|
+
user.nickname,
|
|
112
|
+
user.userId
|
|
113
|
+
]) || "(未命名用户)";
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function formatDescription(user) {
|
|
117
|
+
const raw = pickFirstText([
|
|
118
|
+
user.introduction,
|
|
119
|
+
user.description,
|
|
120
|
+
user.bio,
|
|
121
|
+
user.summary
|
|
122
|
+
]);
|
|
123
|
+
const singleLine = raw.replace(/\s+/g, " ").trim();
|
|
124
|
+
if (!singleLine) {
|
|
125
|
+
return "(无描述)";
|
|
126
|
+
}
|
|
127
|
+
if (singleLine.length <= 120) {
|
|
128
|
+
return singleLine;
|
|
129
|
+
}
|
|
130
|
+
return singleLine.slice(0, 117) + "...";
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function buildHomepageUrl(user, siteBaseUrl) {
|
|
134
|
+
const explicitUrl = pickFirstText([
|
|
135
|
+
user.homepageUrl,
|
|
136
|
+
user.homePageUrl,
|
|
137
|
+
user.profileUrl,
|
|
138
|
+
user.publicProfileUrl,
|
|
139
|
+
user.url,
|
|
140
|
+
user.link
|
|
141
|
+
]);
|
|
142
|
+
if (explicitUrl) {
|
|
143
|
+
return String(new URL(explicitUrl, String(siteBaseUrl).replace(/\/+$/u, "") + "/"));
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const userId = pickFirstText([user.userId, user.uid, user.id]);
|
|
147
|
+
if (!userId) {
|
|
148
|
+
return "(无主页链接)";
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return String(siteBaseUrl).replace(/\/+$/u, "") + "/user/" + encodeURIComponent(userId);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function printUserSearchResult(item, index, siteBaseUrl) {
|
|
155
|
+
const user = resolveUser(item);
|
|
156
|
+
|
|
157
|
+
console.log(index + ". " + resolveDisplayName(user));
|
|
158
|
+
console.log(" 描述: " + formatDescription(user));
|
|
159
|
+
console.log(" 主页: " + buildHomepageUrl(user, siteBaseUrl));
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
async function run(context) {
|
|
163
|
+
const parsed = parseOptions(context.argv, {
|
|
164
|
+
"page-size": { type: "number" },
|
|
165
|
+
"page-token": { type: "string" },
|
|
166
|
+
"request-id": { type: "string" },
|
|
167
|
+
verbose: { type: "boolean" }
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
const query = parsed.positionals.join(" ").trim();
|
|
171
|
+
if (!query) {
|
|
172
|
+
throw new Error("users 命令缺少关键词");
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
const pageSize = normalizePageSize(parsed.options["page-size"]);
|
|
176
|
+
const requestId = parsed.options["request-id"] || generateRequestId();
|
|
177
|
+
const apiBaseUrl = resolveApiBaseUrl();
|
|
178
|
+
const client = createCatalogClient({
|
|
179
|
+
baseUrl: resolveConnectBaseUrl(),
|
|
180
|
+
cliVersion: context.cliVersion,
|
|
181
|
+
requestId,
|
|
182
|
+
verbose: Boolean(parsed.options.verbose)
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
const response = await client.searchUsers({
|
|
186
|
+
query,
|
|
187
|
+
sortBy: DEFAULT_SORT_BY,
|
|
188
|
+
pageSize,
|
|
189
|
+
pageToken: parsed.options["page-token"] || ""
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
const items = resolveItems(response.data);
|
|
193
|
+
const totalSize = resolveTotalSize(response.data, items);
|
|
194
|
+
const nextPageToken = resolveNextPageToken(response.data);
|
|
195
|
+
|
|
196
|
+
if (parsed.options.verbose) {
|
|
197
|
+
console.log("request-id: " + response.requestId);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
if (items.length === 0) {
|
|
201
|
+
if (Number(totalSize) > 0) {
|
|
202
|
+
console.log("当前页没有可展示的用户结果。");
|
|
203
|
+
} else {
|
|
204
|
+
console.log("没有找到与 \"" + query + "\" 相关的用户。");
|
|
205
|
+
}
|
|
206
|
+
console.log("总结果数: " + formatCount(totalSize));
|
|
207
|
+
|
|
208
|
+
return {
|
|
209
|
+
items: [],
|
|
210
|
+
nextPageToken,
|
|
211
|
+
totalSize
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
console.log("用户搜索结果:共 " + formatCount(totalSize) + " 项,本页 " + items.length + " 项");
|
|
216
|
+
console.log("");
|
|
217
|
+
|
|
218
|
+
items.forEach(function eachItem(item, index) {
|
|
219
|
+
printUserSearchResult(item, index + 1, apiBaseUrl);
|
|
220
|
+
if (index < items.length - 1) {
|
|
221
|
+
console.log("");
|
|
222
|
+
}
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
if (nextPageToken) {
|
|
226
|
+
let nextPageCommand = " " + CLI_NAME + " users " + JSON.stringify(query);
|
|
227
|
+
if (pageSize !== DEFAULT_PAGE_SIZE) {
|
|
228
|
+
nextPageCommand += " --page-size " + pageSize;
|
|
229
|
+
}
|
|
230
|
+
nextPageCommand += " --page-token " + nextPageToken;
|
|
231
|
+
|
|
232
|
+
console.log("");
|
|
233
|
+
console.log("下一页:");
|
|
234
|
+
console.log(nextPageCommand);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
return {
|
|
238
|
+
items,
|
|
239
|
+
nextPageToken,
|
|
240
|
+
totalSize
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
module.exports = {
|
|
245
|
+
printHelp,
|
|
246
|
+
run
|
|
247
|
+
};
|
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,51 @@ 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(path.join(stateDir, "runtime", STEPCLAW_RUNTIME_STATE_FILE))
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function resolveStepClawStateDir() {
|
|
150
|
+
const envStateDir = firstDefined([
|
|
151
|
+
process.env[OPENCLAW_STATE_DIR_ENV],
|
|
152
|
+
process.env[STEPCLAW_STATE_DIR_ENV],
|
|
153
|
+
]);
|
|
154
|
+
if (envStateDir) {
|
|
155
|
+
return resolvePathValue(envStateDir);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const defaultStateDir = getDefaultStepClawStateDir();
|
|
159
|
+
const presence = readJsonFileIfExists(
|
|
160
|
+
path.join(defaultStateDir, STEPCLAW_INSTALL_STATE_FILE)
|
|
161
|
+
);
|
|
162
|
+
const redirectedStateDir = trimString(presence && presence.stateDir);
|
|
163
|
+
if (redirectedStateDir) {
|
|
164
|
+
return resolvePathValue(redirectedStateDir);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if (looksLikeStepClawStateDir(defaultStateDir)) {
|
|
168
|
+
return defaultStateDir;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return "";
|
|
172
|
+
}
|
|
173
|
+
|
|
103
174
|
function defaultCredentialsPath() {
|
|
104
175
|
return path.join(getOpenClawHome(), "hub-credentials.json");
|
|
105
176
|
}
|
|
@@ -109,7 +180,14 @@ function getLockfilePath() {
|
|
|
109
180
|
}
|
|
110
181
|
|
|
111
182
|
function getManagedAssetsRoot() {
|
|
112
|
-
|
|
183
|
+
const explicitInstallRoot = firstDefined([
|
|
184
|
+
process.env[OPENCLAWMP_INSTALL_ROOT_ENV],
|
|
185
|
+
]);
|
|
186
|
+
if (explicitInstallRoot) {
|
|
187
|
+
return resolvePathValue(explicitInstallRoot);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
return resolveStepClawStateDir() || getOpenClawHome();
|
|
113
191
|
}
|
|
114
192
|
|
|
115
193
|
function getInstallRoot(assetType) {
|
|
@@ -126,6 +204,8 @@ module.exports = {
|
|
|
126
204
|
resolveApiBaseUrl,
|
|
127
205
|
resolveConnectBaseUrl,
|
|
128
206
|
getOpenClawHome,
|
|
207
|
+
getDefaultStepClawStateDir,
|
|
208
|
+
resolveStepClawStateDir,
|
|
129
209
|
defaultCredentialsPath,
|
|
130
210
|
getLockfilePath,
|
|
131
211
|
getManagedAssetsRoot,
|
package/lib/help.js
CHANGED
|
@@ -28,6 +28,11 @@ const COMMAND_SECTIONS = [
|
|
|
28
28
|
description: "搜索市场资产",
|
|
29
29
|
usage: CLI_NAME + " search <query> [options]"
|
|
30
30
|
},
|
|
31
|
+
{
|
|
32
|
+
name: "users",
|
|
33
|
+
description: "搜索用户",
|
|
34
|
+
usage: CLI_NAME + " users <keyword> [options]"
|
|
35
|
+
},
|
|
31
36
|
{
|
|
32
37
|
name: "info",
|
|
33
38
|
description: "查看某个资产的详细信息",
|
|
@@ -76,6 +81,7 @@ function printGlobalHelp() {
|
|
|
76
81
|
console.log(" " + CLI_NAME + " oauth <your-token>");
|
|
77
82
|
console.log(" " + CLI_NAME + " publish ./my-asset --yes");
|
|
78
83
|
console.log(" " + CLI_NAME + " search 天气");
|
|
84
|
+
console.log(" " + CLI_NAME + " users openclawmp.cc");
|
|
79
85
|
console.log(" " + CLI_NAME + " info 6c476a36955a4270a3fa303beeeed5ee");
|
|
80
86
|
console.log(" " + buildInstallCommand("skill", "7c19dc4c3244418096f1dcb59c93f795"));
|
|
81
87
|
console.log(" " + buildInstallCommand("skill", "7c19dc4c3244418096f1dcb59c93f795", "1.0.3"));
|
package/lib/utils.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "openclawmp",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.4",
|
|
4
4
|
"description": "OpenClaw Marketplace CLI client",
|
|
5
5
|
"bin": {
|
|
6
6
|
"openclawmp": "bin/openclawmp.js"
|
|
@@ -15,7 +15,8 @@
|
|
|
15
15
|
},
|
|
16
16
|
"scripts": {
|
|
17
17
|
"start": "node bin/openclawmp.js",
|
|
18
|
-
"publish:dry-run": "node bin/openclawmp.js publish . --dry-run"
|
|
18
|
+
"publish:dry-run": "node bin/openclawmp.js publish . --dry-run",
|
|
19
|
+
"pack:local": "npm pack"
|
|
19
20
|
},
|
|
20
21
|
"directories": {
|
|
21
22
|
"lib": "lib",
|