@mediaio/cli 0.1.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 +220 -0
- package/bin/mediaio.js +2 -0
- package/bin/run.js +51 -0
- package/install.js +104 -0
- package/package.json +37 -0
package/README.md
ADDED
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
# media-plugin-cli
|
|
2
|
+
|
|
3
|
+
Media.io CLI 的 npm 安装与启动层。该包本身不实现 Media.io API,而是在
|
|
4
|
+
`postinstall` 阶段下载与当前操作系统、CPU 架构匹配的 `media-plugin-bin` Go
|
|
5
|
+
binary,并通过 JavaScript launcher 透传参数、标准输入输出、signal 和退出码。
|
|
6
|
+
|
|
7
|
+
整体技术方案参考:
|
|
8
|
+
`media-plugin-docs/architecture/MCP、CLI与Agent插件技术方案-v2.md`。
|
|
9
|
+
|
|
10
|
+
> 正式发布包名为 `@mediaio/cli`。安装、排障和发布均以 `package.json.name` 为准。
|
|
11
|
+
|
|
12
|
+
## 架构位置
|
|
13
|
+
|
|
14
|
+
```text
|
|
15
|
+
npm install -g @mediaio/cli
|
|
16
|
+
↓ postinstall
|
|
17
|
+
install.js 下载 vendor/mediaio(Windows 为 vendor/mediaio.exe)
|
|
18
|
+
↓
|
|
19
|
+
mediaio 命令 → bin/mediaio.js → bin/run.js → Go binary
|
|
20
|
+
↓
|
|
21
|
+
Media.io 公网 API
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
`media-plugin-main` 中的 Agent Skills 可以复用这套 CLI/binary 基座;本仓库不包含
|
|
25
|
+
Skills、MCP 服务或 Media.io API client 实现。
|
|
26
|
+
|
|
27
|
+
## 环境要求
|
|
28
|
+
|
|
29
|
+
- Node.js 14 或更高版本。
|
|
30
|
+
- npm、pnpm、Yarn 或 Bun;安装器会记录检测到的包管理器。
|
|
31
|
+
- 系统提供 `tar` 命令。当前安装器使用 `tar` 解压 binary,Windows 环境也必须可用。
|
|
32
|
+
- 能访问当前配置的 GitHub Release 下载地址。
|
|
33
|
+
|
|
34
|
+
## 安装
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
npm install -g @mediaio/cli
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
安装完成后:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
mediaio --help
|
|
44
|
+
mediaio auth login
|
|
45
|
+
mediaio generate list
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
CLI 只提供 `mediaio` 命令,不提供缩写别名。命令、binary、Release asset 和安装目录
|
|
49
|
+
均使用完整的 `mediaio` 名称。
|
|
50
|
+
|
|
51
|
+
## postinstall 做了什么
|
|
52
|
+
|
|
53
|
+
`npm install` 会执行:
|
|
54
|
+
|
|
55
|
+
```text
|
|
56
|
+
node install.js
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
当前安装流程:
|
|
60
|
+
|
|
61
|
+
1. 将 Node 平台映射为 binary 平台名:`darwin`、`linux`、`windows`。
|
|
62
|
+
2. 将 Node 架构映射为 Go 架构名:`x64 → amd64`、`arm64 → arm64`。
|
|
63
|
+
3. 读取 npm 包版本作为 binary 版本。
|
|
64
|
+
4. 下载对应的 `.tar.gz` Release asset。
|
|
65
|
+
5. 从压缩包根目录提取 `mediaio` 或 `mediaio.exe` 到 `vendor/`。
|
|
66
|
+
6. Unix 平台为 binary 增加可执行权限。
|
|
67
|
+
7. 写入 `vendor/install.json`,记录安装方式、包管理器、包名和版本。
|
|
68
|
+
|
|
69
|
+
当前下载规则:
|
|
70
|
+
|
|
71
|
+
```text
|
|
72
|
+
https://github.com/media-io/cli/releases/download/v<version>/mediaio_<version>_<os>_<arch>.tar.gz
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
例如 npm 包版本为 `1.0.3`、运行环境为 Apple Silicon macOS 时,会下载:
|
|
76
|
+
|
|
77
|
+
```text
|
|
78
|
+
https://github.com/media-io/cli/releases/download/v1.0.3/mediaio_1.0.3_darwin_arm64.tar.gz
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
archive 根目录必须直接包含 `mediaio`;Windows archive 必须直接包含 `mediaio.exe`。
|
|
82
|
+
|
|
83
|
+
## launcher 行为
|
|
84
|
+
|
|
85
|
+
`bin/run.js` 启动 `vendor/mediaio` 或 `vendor/mediaio.exe`,并执行以下透传:
|
|
86
|
+
|
|
87
|
+
- 原样传递 CLI 参数。
|
|
88
|
+
- `stdin`、`stdout`、`stderr` 使用 `inherit`。
|
|
89
|
+
- 子进程被 signal 终止时,将 signal 传递给当前 Node 进程。
|
|
90
|
+
- 正常退出时返回 Go binary 的 exit code。
|
|
91
|
+
- 向 binary 注入 `mediaio_INSTALL_METHOD=npm`。
|
|
92
|
+
- 向 binary 注入 `mediaio_PACKAGE_MANAGER=<npm|pnpm|yarn|bun>`。
|
|
93
|
+
|
|
94
|
+
## 本地开发
|
|
95
|
+
|
|
96
|
+
只检查 JavaScript 语法,不触发 binary 下载:
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
node --check install.js
|
|
100
|
+
node --check bin/mediaio.js
|
|
101
|
+
node --check bin/run.js
|
|
102
|
+
npm pack --dry-run
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
使用相邻的 `media-plugin-bin` 本地构建产物联调:
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
# 先在 ../media-plugin-bin 中构建
|
|
109
|
+
cd ../media-plugin-bin
|
|
110
|
+
mkdir -p dist
|
|
111
|
+
go build -trimpath -o dist/mediaio .
|
|
112
|
+
|
|
113
|
+
# 回到本仓库,跳过 postinstall 并放入本地 binary
|
|
114
|
+
cd ../media-plugin-cli
|
|
115
|
+
npm install --ignore-scripts
|
|
116
|
+
mkdir -p vendor
|
|
117
|
+
cp ../media-plugin-bin/dist/mediaio vendor/mediaio
|
|
118
|
+
chmod +x vendor/mediaio
|
|
119
|
+
|
|
120
|
+
node bin/mediaio.js --help
|
|
121
|
+
node bin/mediaio.js generate list
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Windows 请复制 `mediaio.exe`:
|
|
125
|
+
|
|
126
|
+
```powershell
|
|
127
|
+
New-Item -ItemType Directory -Force vendor
|
|
128
|
+
Copy-Item ..\media-plugin-bin\dist\mediaio.exe vendor\mediaio.exe
|
|
129
|
+
node bin\mediaio.js --help
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## 发布
|
|
133
|
+
|
|
134
|
+
npm 包与 Go binary 当前使用同一个版本号,必须成套发布。
|
|
135
|
+
|
|
136
|
+
1. 在 `media-plugin-bin` 中完成测试和多平台构建。
|
|
137
|
+
2. 创建 `v<version>` Release,并上传对应的 binary archives。
|
|
138
|
+
3. 确认每个 archive 的名称和根目录文件符合安装器约定。
|
|
139
|
+
4. 将本仓库 `package.json.version` 设置为相同版本。
|
|
140
|
+
5. 检查 npm 包内容并发布。
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
npm pack --dry-run
|
|
144
|
+
npm pack
|
|
145
|
+
npm publish --access public
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
发布后应在干净环境验证:
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
npm install -g @mediaio/cli@<version>
|
|
152
|
+
mediaio --help
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
v2 方案首期 binary matrix 为:
|
|
156
|
+
|
|
157
|
+
```text
|
|
158
|
+
darwin/amd64
|
|
159
|
+
darwin/arm64
|
|
160
|
+
linux/amd64
|
|
161
|
+
linux/arm64
|
|
162
|
+
windows/amd64
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
注意:当前 `package.json` 的 `os` 与 `cpu` 字段、`install.js` 的映射逻辑也会允许
|
|
166
|
+
`windows/arm64` 进入安装流程。正式发布前必须二选一:提供
|
|
167
|
+
`mediaio_<version>_windows_arm64.tar.gz`,或收紧安装器/包元数据,避免用户安装后得到 404。
|
|
168
|
+
|
|
169
|
+
## 排障
|
|
170
|
+
|
|
171
|
+
### binary 不存在
|
|
172
|
+
|
|
173
|
+
如果看到 `binary not found at .../vendor/mediaio`,说明 `postinstall` 未执行或执行失败。
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
npm uninstall -g @mediaio/cli
|
|
177
|
+
npm install -g @mediaio/cli
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
使用 `npm install --ignore-scripts` 安装时不会下载 binary;当前版本尚未提供独立的
|
|
181
|
+
`mediaio install` 修复命令。
|
|
182
|
+
|
|
183
|
+
### 下载返回 404
|
|
184
|
+
|
|
185
|
+
检查以下三项是否完全一致:
|
|
186
|
+
|
|
187
|
+
- `package.json.version`;
|
|
188
|
+
- GitHub Release tag `v<version>`;
|
|
189
|
+
- asset 名称 `mediaio_<version>_<os>_<arch>.tar.gz`。
|
|
190
|
+
|
|
191
|
+
### 解压失败
|
|
192
|
+
|
|
193
|
+
确认系统存在 `tar`,并确认 archive 根目录直接包含 `mediaio` 或 `mediaio.exe`。
|
|
194
|
+
|
|
195
|
+
### 平台不支持
|
|
196
|
+
|
|
197
|
+
当前安装器只识别:
|
|
198
|
+
|
|
199
|
+
```text
|
|
200
|
+
darwin | linux | windows
|
|
201
|
+
amd64 | arm64
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
Node 报告的其他 `process.platform` 或 `process.arch` 会直接终止安装。
|
|
205
|
+
|
|
206
|
+
## 当前实现与 v2 目标的差异
|
|
207
|
+
|
|
208
|
+
| 领域 | 当前实现 | v2 目标 |
|
|
209
|
+
|---|---|---|
|
|
210
|
+
| npm 包名 | `@mediaio/cli` | `@mediaio/cli` |
|
|
211
|
+
| 命令入口 | 仅 `mediaio` | 仅 `mediaio`,不提供缩写别名 |
|
|
212
|
+
| 版本锁定 | npm version 直接拼接下载 URL | 独立 binary manifest 固定精确版本 |
|
|
213
|
+
| 完整性校验 | 尚无 checksum/signature 校验 | SHA-256、签名和 binary version 校验 |
|
|
214
|
+
| 下载安全 | 直接写目标 tarball,未配置 timeout | 随机临时文件、timeout、原子安装和统一清理 |
|
|
215
|
+
| 平台识别 | OS/CPU;未识别 libc | Linux 明确 glibc/musl 策略 |
|
|
216
|
+
| 安装修复 | 重新安装 npm 包 | 显式 install/repair/upgrade/offline 入口 |
|
|
217
|
+
| metadata | 写入 `install.json`,launcher 损坏时降级 | metadata 与 binary 原子安装,损坏时明确失败 |
|
|
218
|
+
|
|
219
|
+
这些目标完成前,README 和发布说明应明确当前能力边界,不能声称安装器已经验证
|
|
220
|
+
checksum、签名或 binary version。
|
package/bin/mediaio.js
ADDED
package/bin/run.js
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
const { spawn } = require("child_process");
|
|
2
|
+
const path = require("path");
|
|
3
|
+
const fs = require("fs");
|
|
4
|
+
|
|
5
|
+
function detectPackageManager() {
|
|
6
|
+
const ua = process.env.npm_config_user_agent || "";
|
|
7
|
+
if (ua.startsWith("pnpm/")) return "pnpm";
|
|
8
|
+
if (ua.startsWith("yarn/")) return "yarn";
|
|
9
|
+
if (ua.startsWith("bun/")) return "bun";
|
|
10
|
+
return "";
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function readInstallMetadata(vendorDir) {
|
|
14
|
+
try {
|
|
15
|
+
return JSON.parse(fs.readFileSync(path.join(vendorDir, "install.json"), "utf8"));
|
|
16
|
+
} catch (_) {
|
|
17
|
+
return {};
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
module.exports = function run() {
|
|
22
|
+
const binName = process.platform === "win32" ? "mediaio.exe" : "mediaio";
|
|
23
|
+
const vendorDir = path.join(__dirname, "..", "vendor");
|
|
24
|
+
const bin = path.join(vendorDir, binName);
|
|
25
|
+
if (!fs.existsSync(bin)) {
|
|
26
|
+
console.error(
|
|
27
|
+
"@mediaio/cli: binary not found at " +
|
|
28
|
+
bin +
|
|
29
|
+
". Reinstall: npm i -g @mediaio/cli"
|
|
30
|
+
);
|
|
31
|
+
process.exit(1);
|
|
32
|
+
}
|
|
33
|
+
const metadata = readInstallMetadata(vendorDir);
|
|
34
|
+
const child = spawn(bin, process.argv.slice(2), {
|
|
35
|
+
stdio: "inherit",
|
|
36
|
+
env: {
|
|
37
|
+
...process.env,
|
|
38
|
+
mediaio_INSTALL_METHOD: "npm",
|
|
39
|
+
mediaio_PACKAGE_MANAGER:
|
|
40
|
+
metadata.package_manager || detectPackageManager() || "npm",
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
child.on("exit", (code, signal) => {
|
|
44
|
+
if (signal) process.kill(process.pid, signal);
|
|
45
|
+
else process.exit(code ?? 0);
|
|
46
|
+
});
|
|
47
|
+
child.on("error", (err) => {
|
|
48
|
+
console.error("@mediaio/cli: failed to exec —", err.message);
|
|
49
|
+
process.exit(1);
|
|
50
|
+
});
|
|
51
|
+
};
|
package/install.js
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
const fs = require("fs");
|
|
3
|
+
const path = require("path");
|
|
4
|
+
const https = require("https");
|
|
5
|
+
const { execFileSync } = require("child_process");
|
|
6
|
+
|
|
7
|
+
const pkg = require("./package.json");
|
|
8
|
+
const VERSION = pkg.version;
|
|
9
|
+
|
|
10
|
+
const PLATFORM_MAP = { darwin: "darwin", linux: "linux", win32: "windows" };
|
|
11
|
+
const ARCH_MAP = { x64: "amd64", arm64: "arm64" };
|
|
12
|
+
|
|
13
|
+
const platform = PLATFORM_MAP[process.platform];
|
|
14
|
+
const arch = ARCH_MAP[process.arch];
|
|
15
|
+
|
|
16
|
+
if (!platform || !arch) {
|
|
17
|
+
console.error(
|
|
18
|
+
`@mediaio/cli: unsupported platform ${process.platform}/${process.arch}`
|
|
19
|
+
);
|
|
20
|
+
console.error("Supported: darwin|linux|windows × x64|arm64");
|
|
21
|
+
process.exit(1);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const binName = platform === "windows" ? "mediaio.exe" : "mediaio";
|
|
25
|
+
const tarball = `mediaio_${VERSION}_${platform}_${arch}.tar.gz`;
|
|
26
|
+
const url = `https://github.com/media-io/cli/releases/download/v${VERSION}/${tarball}`;
|
|
27
|
+
|
|
28
|
+
const vendorDir = path.join(__dirname, "vendor");
|
|
29
|
+
fs.mkdirSync(vendorDir, { recursive: true });
|
|
30
|
+
const tarballPath = path.join(vendorDir, tarball);
|
|
31
|
+
const metadataPath = path.join(vendorDir, "install.json");
|
|
32
|
+
|
|
33
|
+
function detectPackageManager() {
|
|
34
|
+
const ua = process.env.npm_config_user_agent || "";
|
|
35
|
+
if (ua.startsWith("pnpm/")) return "pnpm";
|
|
36
|
+
if (ua.startsWith("yarn/")) return "yarn";
|
|
37
|
+
if (ua.startsWith("bun/")) return "bun";
|
|
38
|
+
return "npm";
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function download(targetUrl, dest, redirects = 0) {
|
|
42
|
+
return new Promise((resolve, reject) => {
|
|
43
|
+
if (redirects > 5) return reject(new Error("too many redirects"));
|
|
44
|
+
const file = fs.createWriteStream(dest);
|
|
45
|
+
https
|
|
46
|
+
.get(targetUrl, (res) => {
|
|
47
|
+
if (
|
|
48
|
+
res.statusCode >= 300 &&
|
|
49
|
+
res.statusCode < 400 &&
|
|
50
|
+
res.headers.location
|
|
51
|
+
) {
|
|
52
|
+
file.close();
|
|
53
|
+
fs.unlinkSync(dest);
|
|
54
|
+
return resolve(download(res.headers.location, dest, redirects + 1));
|
|
55
|
+
}
|
|
56
|
+
if (res.statusCode !== 200) {
|
|
57
|
+
file.close();
|
|
58
|
+
try {
|
|
59
|
+
fs.unlinkSync(dest);
|
|
60
|
+
} catch (_) {}
|
|
61
|
+
return reject(new Error(`HTTP ${res.statusCode} for ${targetUrl}`));
|
|
62
|
+
}
|
|
63
|
+
res.pipe(file);
|
|
64
|
+
file.on("finish", () => file.close(() => resolve()));
|
|
65
|
+
})
|
|
66
|
+
.on("error", (err) => {
|
|
67
|
+
try {
|
|
68
|
+
fs.unlinkSync(dest);
|
|
69
|
+
} catch (_) {}
|
|
70
|
+
reject(err);
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
(async () => {
|
|
76
|
+
console.log(`@mediaio/cli: downloading ${url}`);
|
|
77
|
+
await download(url, tarballPath);
|
|
78
|
+
console.log(`downloaded ${url}`);
|
|
79
|
+
// pipe via stdin: bsdtar on Windows misparses "-f" paths under "@scope" dirs as user@host remote syntax
|
|
80
|
+
execFileSync("tar", ["-xz", "-C", vendorDir, binName], {
|
|
81
|
+
input: fs.readFileSync(tarballPath),
|
|
82
|
+
});
|
|
83
|
+
if (platform !== "windows") {
|
|
84
|
+
fs.chmodSync(path.join(vendorDir, binName), 0o755);
|
|
85
|
+
}
|
|
86
|
+
fs.writeFileSync(
|
|
87
|
+
metadataPath,
|
|
88
|
+
JSON.stringify(
|
|
89
|
+
{
|
|
90
|
+
install_method: "npm",
|
|
91
|
+
package_manager: detectPackageManager(),
|
|
92
|
+
package_name: pkg.name,
|
|
93
|
+
version: VERSION,
|
|
94
|
+
},
|
|
95
|
+
null,
|
|
96
|
+
2
|
|
97
|
+
) + "\n"
|
|
98
|
+
);
|
|
99
|
+
fs.unlinkSync(tarballPath);
|
|
100
|
+
console.log("@mediaio/cli: installed");
|
|
101
|
+
})().catch((err) => {
|
|
102
|
+
console.error("@mediaio/cli: install failed —", err.message);
|
|
103
|
+
process.exit(1);
|
|
104
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@mediaio/cli",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "mediaio AI CLI — generate images and videos from the terminal.",
|
|
5
|
+
"bin": {
|
|
6
|
+
"mediaio": "bin/mediaio.js"
|
|
7
|
+
},
|
|
8
|
+
"scripts": {
|
|
9
|
+
"postinstall": "node install.js"
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
"bin/",
|
|
13
|
+
"install.js",
|
|
14
|
+
"README.md"
|
|
15
|
+
],
|
|
16
|
+
"engines": {
|
|
17
|
+
"node": ">=14"
|
|
18
|
+
},
|
|
19
|
+
"license": "MIT",
|
|
20
|
+
"homepage": "https://media.io",
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "git+https://github.com/media-io/cli.git"
|
|
24
|
+
},
|
|
25
|
+
"os": [
|
|
26
|
+
"darwin",
|
|
27
|
+
"linux",
|
|
28
|
+
"win32"
|
|
29
|
+
],
|
|
30
|
+
"cpu": [
|
|
31
|
+
"x64",
|
|
32
|
+
"arm64"
|
|
33
|
+
],
|
|
34
|
+
"publishConfig": {
|
|
35
|
+
"access": "public"
|
|
36
|
+
}
|
|
37
|
+
}
|