@mearl/cloud-server 3.0.0-beta.4 → 3.0.0-beta.7
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 +8 -15
- package/dist/chunks/{chunk-67UWHFX6.js → chunk-LXICEBLN.js} +1 -1
- package/dist/cli.d.ts +2 -1
- package/dist/cli.js +12 -62
- package/dist/index.js +1 -1
- package/dist/mode.d.ts +1 -1
- package/package.json +7 -7
- package/dist/qoder.d.ts +0 -29
package/README.md
CHANGED
|
@@ -7,14 +7,10 @@
|
|
|
7
7
|
推荐通过 setup 安装完整的云端 Agent 环境(cloud-server、统一 client 与 Agent Skill):
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
|
-
npx
|
|
10
|
+
npx @mearl/setup --cloud
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
Qoder
|
|
14
|
-
|
|
15
|
-
```bash
|
|
16
|
-
npx --@mearl:registry=https://registry.npmjs.org @mearl/setup --qoder-cloud --yes
|
|
17
|
-
```
|
|
13
|
+
可选连接协议由已安装能力包提供。Qoder 配对见 [`@mearl/plugin-qoder`](../../plugin-qoder/README.md);核心不内置其配对实现。
|
|
18
14
|
|
|
19
15
|
在 Docker 或自定义进程托管等只需要 Server 包的场景,可单独安装 `@mearl/cloud-server`。
|
|
20
16
|
|
|
@@ -24,8 +20,7 @@ npx --@mearl:registry=https://registry.npmjs.org @mearl/setup --qoder-cloud --ye
|
|
|
24
20
|
|
|
25
21
|
Server **默认以后台守护进程方式运行**,启动后立即返回,并打印本地机器需要执行的连接命令。
|
|
26
22
|
POSIX 环境下后台进程会进入独立 session,可在启动命令结束后继续运行。
|
|
27
|
-
|
|
28
|
-
pair/connector 信息后退出,不监听端口或创建守护进程。
|
|
23
|
+
其他 cloud mode 通过已安装的 `cloud.server.<id>` 加载,未安装时明确失败。
|
|
29
24
|
|
|
30
25
|
```bash
|
|
31
26
|
mearl-cloud-server [command] [options]
|
|
@@ -75,7 +70,7 @@ mearl-cloud-server --foreground
|
|
|
75
70
|
[CloudServer] Logs: ~/.mearl/cloud-server.log
|
|
76
71
|
|
|
77
72
|
Connect from your local machine:
|
|
78
|
-
npx
|
|
73
|
+
npx @mearl/cloud-connector start "ws://10.0.1.100:8080/ws?token=xxx"
|
|
79
74
|
```
|
|
80
75
|
|
|
81
76
|
部署在反向代理或沙箱中时,由部署宿主或 preset 安装器通过 `MEARL_CLOUD_PUBLIC_URL` 提供外部入口,可使用 `{port}` 占位符。核心不探测组织专属沙箱变量或内部端口映射接口;相关自动发现由独立能力包处理。当前阶段尚未接通这些内部适配,内部产品仍保留原实现。
|
|
@@ -85,7 +80,7 @@ mearl-cloud-server --foreground
|
|
|
85
80
|
运行时文件位于 `~/.mearl/`:
|
|
86
81
|
|
|
87
82
|
- `cloud-server.json` - 连接配置(含 server URL、pid、端口等),统一 `@mearl/client` 自动读取
|
|
88
|
-
- `cloud-server-mode.json` - setup
|
|
83
|
+
- `cloud-server-mode.json` - setup 为可选 cloud mode 写入的标识;普通 `--cloud` 会删除它
|
|
89
84
|
- `cloud-server.log` - 后台进程日志(`logs` 子命令读取,或 `tail -f` 跟踪);超过 5MB 会在下次启动时滚动为 `cloud-server.log.1`
|
|
90
85
|
|
|
91
86
|
> 守护进程的启停、状态、日志滚动等生命周期逻辑由共享包 [`@mearl/daemon-core`](../../daemon-core) 提供(与 cloud-connector 复用同一套实现)。
|
|
@@ -126,9 +121,7 @@ console.log(stats);
|
|
|
126
121
|
await server.stop();
|
|
127
122
|
```
|
|
128
123
|
|
|
129
|
-
|
|
130
|
-
Client-Side `mearl` 工具、Session API 和本地 connector 转发,不会连接一个本地
|
|
131
|
-
cloud-server 端口。
|
|
124
|
+
可选 mode 的握手和转发由对应能力包负责。
|
|
132
125
|
|
|
133
126
|
## 架构
|
|
134
127
|
|
|
@@ -233,7 +226,7 @@ WantedBy=multi-user.target
|
|
|
233
226
|
|
|
234
227
|
```dockerfile
|
|
235
228
|
FROM node:20-alpine
|
|
236
|
-
RUN npm
|
|
229
|
+
RUN npm install -g @mearl/cloud-server
|
|
237
230
|
EXPOSE 8080
|
|
238
231
|
CMD ["mearl-cloud-server", "--foreground", "--token", "your-token"]
|
|
239
232
|
```
|
|
@@ -241,7 +234,7 @@ CMD ["mearl-cloud-server", "--foreground", "--token", "your-token"]
|
|
|
241
234
|
### 使用 PM2
|
|
242
235
|
|
|
243
236
|
```bash
|
|
244
|
-
pm2 start mearl-cloud-server --name
|
|
237
|
+
pm2 start mearl-cloud-server --name mearl-cloud-server -- --foreground --port 8080 --token your-token
|
|
245
238
|
```
|
|
246
239
|
|
|
247
240
|
## 注意事项
|
|
@@ -28,7 +28,7 @@ function resolveCloudPublicEndpoint(port, env = process.env) {
|
|
|
28
28
|
}
|
|
29
29
|
function formatConnectorCommand(url) {
|
|
30
30
|
const argument = /[$`"\\\r\n]/.test(url) ? "'" + url.replaceAll("'", "'\\''") + "'" : `"${url}"`;
|
|
31
|
-
return `npx
|
|
31
|
+
return `npx @mearl/cloud-connector start ${argument}`;
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
// src/index.ts
|
package/dist/cli.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { CloudServerOptions } from './index.js';
|
|
2
|
-
|
|
2
|
+
type CloudServerCommand = 'start' | 'stop' | 'restart' | 'status' | 'logs';
|
|
3
3
|
export interface ParsedCloudServerArgs {
|
|
4
4
|
command: CloudServerCommand;
|
|
5
5
|
daemonArgs: string[];
|
|
@@ -10,3 +10,4 @@ export interface ParsedCloudServerArgs {
|
|
|
10
10
|
}
|
|
11
11
|
export declare function parseCloudServerArgs(argv: string[]): ParsedCloudServerArgs;
|
|
12
12
|
export declare function main(argv?: string[]): Promise<number>;
|
|
13
|
+
export {};
|
package/dist/cli.js
CHANGED
|
@@ -5,9 +5,10 @@ import {
|
|
|
5
5
|
LOG_FILE,
|
|
6
6
|
MODE_FILE,
|
|
7
7
|
formatConnectorCommand
|
|
8
|
-
} from "./chunks/chunk-
|
|
8
|
+
} from "./chunks/chunk-LXICEBLN.js";
|
|
9
9
|
|
|
10
10
|
// src/cli.ts
|
|
11
|
+
import { capabilityDirectory } from "@mearl/daemon-core/page-runtimes";
|
|
11
12
|
import { Command, CommanderError, InvalidArgumentError } from "commander";
|
|
12
13
|
|
|
13
14
|
// src/daemon.ts
|
|
@@ -82,7 +83,7 @@ import { mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
|
82
83
|
import { dirname } from "node:path";
|
|
83
84
|
var CLOUD_SERVER_MODE_ENV = "MEARL_CLOUD_MODE";
|
|
84
85
|
function isCloudServerMode(value) {
|
|
85
|
-
return value === "
|
|
86
|
+
return typeof value === "string" && /^[a-z][a-z0-9-]{0,63}$/.test(value);
|
|
86
87
|
}
|
|
87
88
|
function readStoredMode(storage) {
|
|
88
89
|
const modeFile = storage.modeFile ?? MODE_FILE;
|
|
@@ -112,72 +113,18 @@ function resolveCloudServerMode(env = process.env, storage = {}) {
|
|
|
112
113
|
const requested = env[CLOUD_SERVER_MODE_ENV];
|
|
113
114
|
if (requested !== void 0) {
|
|
114
115
|
if (!isCloudServerMode(requested)) {
|
|
115
|
-
throw new Error(`${CLOUD_SERVER_MODE_ENV} must be
|
|
116
|
+
throw new Error(`${CLOUD_SERVER_MODE_ENV} must be a valid installed cloud mode ID`);
|
|
116
117
|
}
|
|
117
|
-
if (requested
|
|
118
|
+
if (requested !== "websocket") writeStoredMode(requested, storage);
|
|
118
119
|
else clearStoredMode(storage);
|
|
119
120
|
return requested;
|
|
120
121
|
}
|
|
121
122
|
return readStoredMode(storage) ?? "websocket";
|
|
122
123
|
}
|
|
123
124
|
|
|
124
|
-
// src/qoder.ts
|
|
125
|
-
import { randomBytes } from "node:crypto";
|
|
126
|
-
function createQoderPairingInfo(options = {}) {
|
|
127
|
-
const pairingCode = (options.createCode ?? (() => randomBytes(24).toString("base64url")))();
|
|
128
|
-
if (!/^[A-Za-z0-9_-]{16,128}$/.test(pairingCode)) {
|
|
129
|
-
throw new Error("Qoder pairing code must be 16-128 URL-safe characters");
|
|
130
|
-
}
|
|
131
|
-
const createdAt = (options.now ?? Date.now)();
|
|
132
|
-
if (!Number.isSafeInteger(createdAt) || createdAt < 1e12 || createdAt > 9999999999999) {
|
|
133
|
-
throw new Error("Qoder pairing timestamp must be a 13-digit epoch millisecond value");
|
|
134
|
-
}
|
|
135
|
-
return {
|
|
136
|
-
pairingCode,
|
|
137
|
-
createdAt,
|
|
138
|
-
connectorUrl: `qoder://pair/${pairingCode}?created=${createdAt}`,
|
|
139
|
-
toolInput: { action: "pair", payload: { code: pairingCode } }
|
|
140
|
-
};
|
|
141
|
-
}
|
|
142
|
-
function formatQoderPairingOutput(info) {
|
|
143
|
-
const connectorCommand = `npx --@mearl:registry=https://registry.npmjs.org @mearl/cloud-connector start "${info.connectorUrl}"`;
|
|
144
|
-
return `[CloudServer] Qoder pairing mode is ready.
|
|
145
|
-
|
|
146
|
-
Connect from your local machine:
|
|
147
|
-
${connectorCommand}
|
|
148
|
-
|
|
149
|
-
Then immediately invoke the Qoder client-side custom tool named "mearl" with this input:
|
|
150
|
-
${JSON.stringify(info.toolInput)}
|
|
151
|
-
|
|
152
|
-
The connector resolves QODER_PERSONAL_ACCESS_TOKEN from the local environment, ~/.mearl/.env, or supported local credential storage. Never add the PAT to the pairing URL.`;
|
|
153
|
-
}
|
|
154
|
-
async function runQoderCloudServerCommand(command, dependencies) {
|
|
155
|
-
const writeLine = dependencies.writeLine ?? console.log;
|
|
156
|
-
switch (command) {
|
|
157
|
-
case "start":
|
|
158
|
-
case "restart":
|
|
159
|
-
if (dependencies.isServerRunning()) await dependencies.stopServer();
|
|
160
|
-
writeLine(
|
|
161
|
-
formatQoderPairingOutput(
|
|
162
|
-
(dependencies.createPairing ?? (() => createQoderPairingInfo()))()
|
|
163
|
-
)
|
|
164
|
-
);
|
|
165
|
-
break;
|
|
166
|
-
case "status":
|
|
167
|
-
dependencies.printStatus();
|
|
168
|
-
writeLine("[CloudServer] Mode: qoder pairing (no listening service)");
|
|
169
|
-
break;
|
|
170
|
-
case "stop":
|
|
171
|
-
await dependencies.stopServer();
|
|
172
|
-
break;
|
|
173
|
-
case "logs":
|
|
174
|
-
dependencies.printLogs();
|
|
175
|
-
break;
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
|
|
179
125
|
// src/cli.ts
|
|
180
|
-
|
|
126
|
+
import { NodeCapabilityRegistry } from "@mearl/daemon-core/capabilities";
|
|
127
|
+
var CLOUD_SERVER_VERSION = true ? "3.0.0-beta.7" : "unknown";
|
|
181
128
|
var COMMANDS = ["start", "stop", "restart", "status", "logs"];
|
|
182
129
|
var START_OPTION_NAMES = /* @__PURE__ */ new Set([
|
|
183
130
|
"foreground",
|
|
@@ -322,8 +269,11 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
322
269
|
return 0;
|
|
323
270
|
}
|
|
324
271
|
const mode = resolveCloudServerMode();
|
|
325
|
-
if (mode
|
|
326
|
-
|
|
272
|
+
if (mode !== "websocket") {
|
|
273
|
+
const hook = `cloud.server.${mode}`;
|
|
274
|
+
const registry = new NodeCapabilityRegistry({ version: CLOUD_SERVER_VERSION }, capabilityDirectory(), { hooks: [hook] });
|
|
275
|
+
await registry.refresh();
|
|
276
|
+
await registry.require(hook)(parsed.command, {
|
|
327
277
|
isServerRunning: isDaemonRunning,
|
|
328
278
|
stopServer: stopDaemon,
|
|
329
279
|
printStatus: statusDaemon,
|
package/dist/index.js
CHANGED
package/dist/mode.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mearl/cloud-server",
|
|
3
|
-
"version": "3.0.0-beta.
|
|
3
|
+
"version": "3.0.0-beta.7",
|
|
4
4
|
"description": "Cloud WebSocket server for Mearl — bridges cloud agents to local connectors",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
7
|
-
"node": ">=
|
|
7
|
+
"node": ">=20.18.0"
|
|
8
8
|
},
|
|
9
9
|
"main": "dist/index.js",
|
|
10
10
|
"types": "dist/index.d.ts",
|
|
@@ -33,11 +33,11 @@
|
|
|
33
33
|
"registry": "https://registry.npmjs.org"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"commander": "^
|
|
36
|
+
"commander": "^14.0.3",
|
|
37
37
|
"ws": "^8.18.0",
|
|
38
|
-
"@mearl/
|
|
39
|
-
"@mearl/
|
|
40
|
-
"@mearl/
|
|
38
|
+
"@mearl/client": "3.0.0-beta.7",
|
|
39
|
+
"@mearl/cloud-types": "3.0.0-beta.7",
|
|
40
|
+
"@mearl/daemon-core": "3.0.0-beta.7"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"@types/node": "^24.9.1",
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
},
|
|
48
48
|
"repository": {
|
|
49
49
|
"type": "git",
|
|
50
|
-
"url": "git+https://github.com/
|
|
50
|
+
"url": "git+https://github.com/mearlhq/mearl.git",
|
|
51
51
|
"directory": "packages/cloud/cloud-server"
|
|
52
52
|
},
|
|
53
53
|
"scripts": {
|
package/dist/qoder.d.ts
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
export interface QoderPairingInfo {
|
|
2
|
-
pairingCode: string;
|
|
3
|
-
createdAt: number;
|
|
4
|
-
connectorUrl: string;
|
|
5
|
-
toolInput: {
|
|
6
|
-
action: 'pair';
|
|
7
|
-
payload: {
|
|
8
|
-
code: string;
|
|
9
|
-
};
|
|
10
|
-
};
|
|
11
|
-
}
|
|
12
|
-
export interface QoderPairingOptions {
|
|
13
|
-
now?: () => number;
|
|
14
|
-
createCode?: () => string;
|
|
15
|
-
}
|
|
16
|
-
export type CloudServerCommand = 'start' | 'stop' | 'restart' | 'status' | 'logs';
|
|
17
|
-
interface QoderCloudServerDependencies {
|
|
18
|
-
createPairing?: () => QoderPairingInfo;
|
|
19
|
-
isServerRunning: () => boolean;
|
|
20
|
-
printLogs: () => void;
|
|
21
|
-
printStatus: () => void;
|
|
22
|
-
stopServer: () => Promise<void>;
|
|
23
|
-
writeLine?: (message: string) => void;
|
|
24
|
-
}
|
|
25
|
-
/** Create a short-lived correlation handle without embedding Qoder credentials in the URL. */
|
|
26
|
-
export declare function createQoderPairingInfo(options?: QoderPairingOptions): QoderPairingInfo;
|
|
27
|
-
export declare function formatQoderPairingOutput(info: QoderPairingInfo): string;
|
|
28
|
-
export declare function runQoderCloudServerCommand(command: CloudServerCommand, dependencies: QoderCloudServerDependencies): Promise<void>;
|
|
29
|
-
export {};
|