openclawmp 0.1.6 → 1.0.0-alpha.0
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 +135 -117
- package/bin/openclawmp.js +63 -65
- package/lib/api.js +203 -228
- package/lib/archive.js +831 -228
- package/lib/asset-types.js +90 -0
- package/lib/cli-parser.js +125 -52
- package/lib/commands/help.js +63 -0
- package/lib/commands/info.js +341 -41
- package/lib/commands/install.js +289 -174
- package/lib/commands/list.js +284 -25
- package/lib/commands/login.js +75 -28
- package/lib/commands/publish.js +719 -476
- package/lib/commands/search.js +200 -33
- package/lib/commands/uninstall.js +258 -37
- package/lib/config.js +100 -158
- package/lib/credentials.js +38 -0
- package/lib/help.js +76 -57
- package/lib/install-metadata.js +106 -0
- package/lib/lockfile.js +73 -0
- package/lib/metadata.js +1007 -0
- package/lib/publish-flow.js +378 -0
- package/lib/update-notifier.js +340 -0
- package/lib/utils.js +361 -0
- package/package.json +17 -20
- package/lib/auth.js +0 -42
- package/lib/commands/comment.js +0 -137
- package/lib/commands/delete-account.js +0 -44
- package/lib/commands/issue.js +0 -157
- package/lib/commands/star.js +0 -67
- package/lib/commands/unbind.js +0 -37
- package/lib/commands/whoami.js +0 -48
- package/lib/ui.js +0 -103
package/README.md
CHANGED
|
@@ -4,176 +4,194 @@
|
|
|
4
4
|
|
|
5
5
|
A command-line client for the [OpenClaw Marketplace](https://openclawmp.cc), allowing you to search, install, publish, and manage agent assets (skills, plugins, triggers, channels, and more).
|
|
6
6
|
|
|
7
|
-
##
|
|
7
|
+
## 安装
|
|
8
8
|
|
|
9
9
|
```bash
|
|
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
|
|
|
17
17
|
```bash
|
|
18
|
-
#
|
|
19
|
-
openclawmp search
|
|
18
|
+
# 搜索市场资产
|
|
19
|
+
openclawmp search 天气
|
|
20
20
|
|
|
21
|
-
#
|
|
22
|
-
openclawmp
|
|
21
|
+
# 查看资产详情
|
|
22
|
+
openclawmp info 7c19dc4c3244418096f1dcb59c93f795
|
|
23
23
|
|
|
24
|
-
#
|
|
24
|
+
# 安装资产
|
|
25
|
+
openclawmp install skill/7c19dc4c3244418096f1dcb59c93f795
|
|
26
|
+
|
|
27
|
+
# 安装指定版本
|
|
28
|
+
openclawmp install skill/7c19dc4c3244418096f1dcb59c93f795@1.0.3
|
|
29
|
+
|
|
30
|
+
# 列出本地已安装资产
|
|
25
31
|
openclawmp list
|
|
26
32
|
|
|
27
|
-
#
|
|
28
|
-
openclawmp
|
|
33
|
+
# 卸载本地资产
|
|
34
|
+
openclawmp uninstall skill/demo-skill
|
|
29
35
|
|
|
30
|
-
#
|
|
31
|
-
openclawmp publish ./my-skill
|
|
36
|
+
# 发布本地资产
|
|
37
|
+
openclawmp publish ./my-skill --type skill --version 1.0.0 --yes
|
|
32
38
|
```
|
|
33
39
|
|
|
34
|
-
##
|
|
40
|
+
## 功能概览
|
|
35
41
|
|
|
36
|
-
|
|
42
|
+
- `search`:搜索市场资产,按类型、作者、安装量、标签和简介格式化输出。
|
|
43
|
+
- `info`:查看资产详情与版本信息。
|
|
44
|
+
- `install`:根据 `assetId` 和可选 `semver` 下载归档并安装到本地 OpenClaw 目录。
|
|
45
|
+
- `uninstall`:删除本地安装目录,并清理对应锁文件记录。
|
|
46
|
+
- `list`:扫描本地已安装资产,结合 lockfile 和安装元数据展示结果。
|
|
47
|
+
- `publish`:打包本地目录并上传发布,串联 `createUpload`、`signUploadPartUrl`、`completeUpload`、`createAssetSemver`。
|
|
37
48
|
|
|
38
|
-
|
|
49
|
+
## 支持的资产类型
|
|
39
50
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
51
|
+
- `skill`
|
|
52
|
+
- `experience`
|
|
53
|
+
- `plugin`
|
|
54
|
+
- `trigger`
|
|
55
|
+
- `channel`
|
|
44
56
|
|
|
45
|
-
|
|
57
|
+
## 运行要求
|
|
46
58
|
|
|
47
|
-
|
|
59
|
+
- Node.js `>=18.0.0`
|
|
60
|
+
- 零运行时依赖
|
|
48
61
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
openclawmp install skill/@cybernova/web-search
|
|
62
|
+
## 凭证
|
|
63
|
+
|
|
64
|
+
默认读取:
|
|
53
65
|
|
|
54
|
-
|
|
55
|
-
|
|
66
|
+
- macOS / Linux: `~/.openclaw/hub-credentials.json`
|
|
67
|
+
- Windows: `%USERPROFILE%\\.openclaw\\hub-credentials.json`
|
|
56
68
|
|
|
57
|
-
|
|
58
|
-
|
|
69
|
+
文件最少需要:
|
|
70
|
+
|
|
71
|
+
```json
|
|
72
|
+
{
|
|
73
|
+
"token": "your-credential-token"
|
|
74
|
+
}
|
|
59
75
|
```
|
|
60
76
|
|
|
61
|
-
|
|
77
|
+
请求头约定:
|
|
62
78
|
|
|
63
|
-
|
|
79
|
+
- `Authorization: Bearer <credential token>`:受保护接口必需;`search` 可匿名调用
|
|
80
|
+
- `X-Request-ID`:自动生成,也可通过 `--request-id` 显式指定
|
|
81
|
+
- `Cli-Version`:自动带当前 package 版本
|
|
64
82
|
|
|
65
|
-
|
|
83
|
+
## 常用示例
|
|
66
84
|
|
|
67
85
|
```bash
|
|
68
|
-
openclawmp
|
|
86
|
+
npm install -g openclawmp
|
|
87
|
+
openclawmp publish /path/to/asset
|
|
69
88
|
```
|
|
70
89
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
Remove an installed asset.
|
|
90
|
+
示例:
|
|
74
91
|
|
|
75
92
|
```bash
|
|
76
|
-
openclawmp
|
|
77
|
-
|
|
93
|
+
openclawmp publish ./my-skill \
|
|
94
|
+
--type skill \
|
|
95
|
+
--category productivity \
|
|
96
|
+
--tags agent,automation \
|
|
97
|
+
--version 1.0.0 \
|
|
98
|
+
--yes
|
|
78
99
|
```
|
|
79
100
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
View detailed information about an asset from the registry.
|
|
101
|
+
更新已有资产版本:
|
|
83
102
|
|
|
84
103
|
```bash
|
|
85
|
-
openclawmp
|
|
86
|
-
openclawmp info trigger/fs-event-trigger
|
|
104
|
+
openclawmp publish ./my-skill --version 1.0.1 --yes
|
|
87
105
|
```
|
|
88
106
|
|
|
89
|
-
|
|
107
|
+
如果目录根部已存在 `.assetid`,会自动把该值透传为 `assetId`;也可显式传入 `--asset-id <id>`。
|
|
90
108
|
|
|
91
|
-
|
|
109
|
+
只做本地校验和打包:
|
|
92
110
|
|
|
93
111
|
```bash
|
|
94
|
-
|
|
95
|
-
openclawmp publish
|
|
96
|
-
|
|
97
|
-
# Publish a specific directory
|
|
98
|
-
openclawmp publish ./my-skill
|
|
99
|
-
|
|
100
|
-
# Skip confirmation prompt
|
|
101
|
-
openclawmp publish ./my-skill --yes
|
|
112
|
+
openclawmp publish ./my-skill --dry-run
|
|
102
113
|
```
|
|
103
114
|
|
|
104
|
-
|
|
105
|
-
1. `SKILL.md` frontmatter (for skills)
|
|
106
|
-
2. `openclaw.plugin.json` (for plugins/channels)
|
|
107
|
-
3. `package.json` (fallback)
|
|
108
|
-
4. `README.md` (fallback)
|
|
109
|
-
|
|
110
|
-
### `openclawmp login`
|
|
111
|
-
|
|
112
|
-
Show device authorization information. Your OpenClaw device identity is used for publishing.
|
|
115
|
+
安装示例:
|
|
113
116
|
|
|
114
117
|
```bash
|
|
115
|
-
openclawmp
|
|
118
|
+
openclawmp install skill/7c19dc4c3244418096f1dcb59c93f795
|
|
119
|
+
openclawmp install skill/7c19dc4c3244418096f1dcb59c93f795@1.0.3
|
|
116
120
|
```
|
|
117
121
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
Show current user/device info and configuration status.
|
|
122
|
+
卸载示例:
|
|
121
123
|
|
|
122
124
|
```bash
|
|
123
|
-
openclawmp
|
|
125
|
+
openclawmp uninstall skill/7c19dc4c3244418096f1dcb59c93f795
|
|
126
|
+
openclawmp uninstall skill/demo-skill
|
|
124
127
|
```
|
|
125
128
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
| Option | Description |
|
|
129
|
-
|--------|-------------|
|
|
130
|
-
| `--api <url>` | Override the API base URL |
|
|
131
|
-
| `--version`, `-v` | Show version |
|
|
132
|
-
| `--help`, `-h` | Show help |
|
|
133
|
-
|
|
134
|
-
## Environment Variables
|
|
135
|
-
|
|
136
|
-
| Variable | Description |
|
|
137
|
-
|----------|-------------|
|
|
138
|
-
| `OPENCLAWMP_API` | Override the default API base URL (`https://openclawmp.cc`) |
|
|
139
|
-
| `OPENCLAW_STATE_DIR` | Override the OpenClaw state directory (default: `~/.openclaw`) |
|
|
140
|
-
| `NO_COLOR` | Disable colored output |
|
|
141
|
-
|
|
142
|
-
## Configuration
|
|
143
|
-
|
|
144
|
-
Configuration files are stored in `~/.openclawmp/`:
|
|
145
|
-
|
|
146
|
-
- `auth.json` — Authentication token
|
|
147
|
-
|
|
148
|
-
Install metadata is tracked in `~/.openclaw/seafood-lock.json` (shared with the OpenClaw ecosystem).
|
|
149
|
-
|
|
150
|
-
## Asset Types
|
|
151
|
-
|
|
152
|
-
| Type | Icon | Description |
|
|
153
|
-
|------|------|-------------|
|
|
154
|
-
| `skill` | 🧩 | Agent skills and capabilities |
|
|
155
|
-
| `config` | ⚙️ | Configuration presets |
|
|
156
|
-
| `plugin` | 🔌 | Gateway plugins |
|
|
157
|
-
| `trigger` | ⚡ | Event triggers |
|
|
158
|
-
| `channel` | 📡 | Communication channels |
|
|
159
|
-
| `template` | 📋 | Project templates |
|
|
160
|
-
|
|
161
|
-
## Development
|
|
129
|
+
搜索示例:
|
|
162
130
|
|
|
163
131
|
```bash
|
|
164
|
-
|
|
165
|
-
git clone https://github.com/openclaw/openclawmp.git
|
|
166
|
-
cd openclawmp
|
|
167
|
-
|
|
168
|
-
# Run directly
|
|
169
|
-
node bin/openclawmp.js --help
|
|
170
|
-
node bin/openclawmp.js search weather
|
|
171
|
-
|
|
172
|
-
# Link globally for testing
|
|
173
|
-
npm link
|
|
174
|
-
openclawmp --help
|
|
132
|
+
openclawmp search 天气 --page-size 10
|
|
175
133
|
```
|
|
176
134
|
|
|
177
|
-
##
|
|
178
|
-
|
|
179
|
-
|
|
135
|
+
## 命令结构
|
|
136
|
+
|
|
137
|
+
入口采用懒加载:
|
|
138
|
+
|
|
139
|
+
- `publish`
|
|
140
|
+
- `search`
|
|
141
|
+
- `install`
|
|
142
|
+
- `uninstall`
|
|
143
|
+
- `list`
|
|
144
|
+
|
|
145
|
+
其中当前可用的是 `publish`、`search`、`install`、`uninstall`、`list`。
|
|
146
|
+
|
|
147
|
+
## 发布命令参数
|
|
148
|
+
|
|
149
|
+
- `--type <skill|experience|plugin|trigger|channel>`
|
|
150
|
+
- `--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
|
+
- `--base-url <url>`
|
|
160
|
+
- `--token-file <path>`
|
|
161
|
+
- `--part-size-mb <number>`
|
|
162
|
+
- `--ttl-seconds <number>`
|
|
163
|
+
- `--request-id <id>`
|
|
164
|
+
- `--dry-run`
|
|
165
|
+
- `--yes, -y`
|
|
166
|
+
- `--verbose`
|
|
167
|
+
|
|
168
|
+
## 目录发布打包规则
|
|
169
|
+
|
|
170
|
+
- 目录发布会默认跳过 `.git`、`node_modules`、`__MACOSX`、`.DS_Store`、`Thumbs.db`
|
|
171
|
+
- 根目录可通过 `.openclawmpignore` 补充忽略规则,也会读取根目录 `.gitignore` / `.npmignore` 的常见规则
|
|
172
|
+
- 子路径遇到无权限读取的目录或文件时会自动跳过;使用 `--verbose` 可查看具体跳过项
|
|
173
|
+
|
|
174
|
+
## Metadata 提取规则
|
|
175
|
+
|
|
176
|
+
- 优先级:CLI 显式参数 > `.metadata.json` > `README.md` > `package.json` > `openclaw.plugin.json` > `SKILL.md`
|
|
177
|
+
- `.metadata.json` 存在时会优先使用,适合显式固定 `type`、`name`、`displayName`、`description`、`version`、`category`、`tags`、`longDescription`
|
|
178
|
+
- `SKILL.md` 的 `name`、`display-name`、`description`、`version`、`tags` 只从 frontmatter(`---` 到 `---`)提取,不会把正文内容混进 `description`
|
|
179
|
+
- `README.md` 支持 YAML frontmatter 和前置 `key: value` 形式字段提取 `name`、`display-name`、`description`、`version`、`type`、`category`、`tags`
|
|
180
|
+
- `trigger` / `experience` 会把 README 标题后的第一段作为描述兜底
|
|
181
|
+
- 发布必填规则:`assetType`、`name`、`displayName`、`semver`
|
|
182
|
+
- `version` 必须是严格的 `x.x.x` 形式,例如 `1.2.1`、`1.1.10`
|
|
183
|
+
- `assetId` 为可选字段;有就透传,没有就省略,由后端判断是新建还是已有资产发新版
|
|
184
|
+
- `objectId` 由上传完成后自动生成,登录态始终必需
|
|
185
|
+
- 调用发布接口前会打印 `CreateAssetSemver` 请求预览;真正发网请求前会打印对应 request body
|
|
186
|
+
|
|
187
|
+
## 默认配置来源
|
|
188
|
+
|
|
189
|
+
`baseUrl` 优先级:
|
|
190
|
+
|
|
191
|
+
1. `--base-url`
|
|
192
|
+
2. `OPENCLAWMP_API_BASE_URL`
|
|
193
|
+
3. `OPENCLAWMP_BASE_URL`
|
|
194
|
+
4. `API_BASE_URL`
|
|
195
|
+
5. `NEXT_PUBLIC_API_BASE_URL`
|
|
196
|
+
6. 仓库根目录 `.env.local` / `.env` / `.env.prod`
|
|
197
|
+
7. `https://seafood.c.stepfun-inc.net`
|
package/bin/openclawmp.js
CHANGED
|
@@ -1,85 +1,83 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
// ============================================================================
|
|
3
|
-
// 🐟 OpenClaw Marketplace CLI (openclawmp)
|
|
4
|
-
//
|
|
5
|
-
// Pure Node.js rewrite of seafood-market.sh
|
|
6
|
-
// Zero external runtime dependencies
|
|
7
|
-
// ============================================================================
|
|
8
2
|
|
|
9
|
-
|
|
3
|
+
const path = require("node:path");
|
|
10
4
|
|
|
11
|
-
const
|
|
12
|
-
const
|
|
13
|
-
const {
|
|
14
|
-
const {
|
|
5
|
+
const pkg = require(path.join(__dirname, "..", "package.json"));
|
|
6
|
+
const { parseCommandLine } = require("../lib/cli-parser");
|
|
7
|
+
const { printGlobalHelp } = require("../lib/help");
|
|
8
|
+
const { maybeNotifyAboutUpdates } = require("../lib/update-notifier");
|
|
9
|
+
const { formatUserFacingError } = require("../lib/utils");
|
|
15
10
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
11
|
+
const COMMAND_LOADERS = {
|
|
12
|
+
help: function loadHelp() {
|
|
13
|
+
return require("../lib/commands/help");
|
|
14
|
+
},
|
|
15
|
+
login: function loadLogin() {
|
|
16
|
+
return require("../lib/commands/login");
|
|
17
|
+
},
|
|
18
|
+
publish: function loadPublish() {
|
|
19
|
+
return require("../lib/commands/publish");
|
|
20
|
+
},
|
|
21
|
+
search: function loadSearch() {
|
|
22
|
+
return require("../lib/commands/search");
|
|
23
|
+
},
|
|
24
|
+
info: function loadInfo() {
|
|
25
|
+
return require("../lib/commands/info");
|
|
26
|
+
},
|
|
27
|
+
install: function loadInstall() {
|
|
28
|
+
return require("../lib/commands/install");
|
|
29
|
+
},
|
|
30
|
+
uninstall: function loadUninstall() {
|
|
31
|
+
return require("../lib/commands/uninstall");
|
|
32
|
+
},
|
|
33
|
+
list: function loadList() {
|
|
34
|
+
return require("../lib/commands/list");
|
|
35
|
+
}
|
|
37
36
|
};
|
|
38
37
|
|
|
39
38
|
async function main() {
|
|
40
|
-
const
|
|
39
|
+
const parsed = parseCommandLine(process.argv.slice(2));
|
|
41
40
|
|
|
42
|
-
|
|
43
|
-
if (flags.version || flags.v) {
|
|
44
|
-
const pkg = require(path.join(__dirname, '..', 'package.json'));
|
|
41
|
+
if (parsed.version) {
|
|
45
42
|
console.log(pkg.version);
|
|
46
|
-
|
|
43
|
+
return;
|
|
47
44
|
}
|
|
48
45
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
process.exit(0);
|
|
46
|
+
if (!parsed.command) {
|
|
47
|
+
printGlobalHelp();
|
|
48
|
+
return;
|
|
53
49
|
}
|
|
54
50
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
const ui = require(path.join(libDir, 'ui.js'));
|
|
59
|
-
ui.err(`Unknown command: ${command}`);
|
|
60
|
-
console.log('');
|
|
61
|
-
printHelp();
|
|
62
|
-
process.exit(1);
|
|
51
|
+
const loadCommand = COMMAND_LOADERS[parsed.command];
|
|
52
|
+
if (!loadCommand) {
|
|
53
|
+
throw new Error("未知命令: " + parsed.command);
|
|
63
54
|
}
|
|
64
55
|
|
|
65
|
-
|
|
66
|
-
if (flags.api || process.env.OPENCLAWMP_API) {
|
|
67
|
-
const config = require(path.join(libDir, 'config.js'));
|
|
68
|
-
config.setApiBase(flags.api || process.env.OPENCLAWMP_API);
|
|
69
|
-
}
|
|
56
|
+
const commandModule = loadCommand();
|
|
70
57
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
const ui = require(path.join(libDir, 'ui.js'));
|
|
76
|
-
if (e.code === 'ENOTFOUND' || e.code === 'ECONNREFUSED') {
|
|
77
|
-
ui.err(`Cannot reach API server. Check your connection or use --api to set a custom endpoint.`);
|
|
78
|
-
} else {
|
|
79
|
-
ui.err(e.message || String(e));
|
|
58
|
+
if (parsed.help) {
|
|
59
|
+
if (typeof commandModule.printHelp === "function") {
|
|
60
|
+
commandModule.printHelp();
|
|
61
|
+
return;
|
|
80
62
|
}
|
|
81
|
-
|
|
63
|
+
printGlobalHelp();
|
|
64
|
+
return;
|
|
82
65
|
}
|
|
66
|
+
|
|
67
|
+
await commandModule.run({
|
|
68
|
+
argv: parsed.argv,
|
|
69
|
+
command: parsed.command,
|
|
70
|
+
cliVersion: pkg.version
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
await maybeNotifyAboutUpdates({
|
|
74
|
+
command: parsed.command,
|
|
75
|
+
packageName: pkg.name,
|
|
76
|
+
currentVersion: pkg.version
|
|
77
|
+
});
|
|
83
78
|
}
|
|
84
79
|
|
|
85
|
-
main()
|
|
80
|
+
main().catch(function onError(error) {
|
|
81
|
+
console.error(formatUserFacingError(error, { title: "执行失败" }));
|
|
82
|
+
process.exitCode = 1;
|
|
83
|
+
});
|