@mearl/plugin-qoder 0.0.0-stage → 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.
@@ -0,0 +1,4 @@
1
+ export * from './agent.js';
2
+ export * from './connector.js';
3
+ export * from './pairing.js';
4
+ export * from './endpoint.js';
package/dist/index.js ADDED
@@ -0,0 +1,4 @@
1
+ export * from './agent.js';
2
+ export * from './connector.js';
3
+ export * from './pairing.js';
4
+ export * from './endpoint.js';
@@ -0,0 +1,29 @@
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 {};
@@ -0,0 +1,53 @@
1
+ import { randomBytes } from 'node:crypto';
2
+ /** Create a short-lived correlation handle without embedding Qoder credentials in the URL. */
3
+ export function createQoderPairingInfo(options = {}) {
4
+ const pairingCode = (options.createCode ?? (() => randomBytes(24).toString('base64url')))();
5
+ if (!/^[A-Za-z0-9_-]{16,128}$/.test(pairingCode)) {
6
+ throw new Error('Qoder pairing code must be 16-128 URL-safe characters');
7
+ }
8
+ const createdAt = (options.now ?? Date.now)();
9
+ if (!Number.isSafeInteger(createdAt) ||
10
+ createdAt < 1_000_000_000_000 ||
11
+ createdAt > 9_999_999_999_999) {
12
+ throw new Error('Qoder pairing timestamp must be a 13-digit epoch millisecond value');
13
+ }
14
+ return {
15
+ pairingCode,
16
+ createdAt,
17
+ connectorUrl: `qoder://pair/${pairingCode}?created=${createdAt}`,
18
+ toolInput: { action: 'pair', payload: { code: pairingCode } },
19
+ };
20
+ }
21
+ export function formatQoderPairingOutput(info) {
22
+ const connectorCommand = `npx @mearl/cloud-connector start "${info.connectorUrl}"`;
23
+ return `[CloudServer] Qoder pairing mode is ready.
24
+
25
+ Connect from your local machine:
26
+ ${connectorCommand}
27
+
28
+ Then immediately invoke the Qoder client-side custom tool named "mearl" with this input:
29
+ ${JSON.stringify(info.toolInput)}
30
+
31
+ 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.`;
32
+ }
33
+ export async function runQoderCloudServerCommand(command, dependencies) {
34
+ const writeLine = dependencies.writeLine ?? console.log;
35
+ switch (command) {
36
+ case 'start':
37
+ case 'restart':
38
+ if (dependencies.isServerRunning())
39
+ await dependencies.stopServer();
40
+ writeLine(formatQoderPairingOutput((dependencies.createPairing ?? (() => createQoderPairingInfo()))()));
41
+ break;
42
+ case 'status':
43
+ dependencies.printStatus();
44
+ writeLine('[CloudServer] Mode: qoder pairing (no listening service)');
45
+ break;
46
+ case 'stop':
47
+ await dependencies.stopServer();
48
+ break;
49
+ case 'logs':
50
+ dependencies.printLogs();
51
+ break;
52
+ }
53
+ }
@@ -0,0 +1,14 @@
1
+ import { QoderAgentProvider } from './agent.js';
2
+ import { QoderConnector } from './connector.js';
3
+ import { runQoderCloudServerCommand } from './pairing.js';
4
+ /** Factories remain idle until the host selects this installed contribution. */
5
+ export default function createQoderPlugin(): {
6
+ agent: (options: {
7
+ log: (message: string) => void;
8
+ version: string;
9
+ }) => QoderAgentProvider;
10
+ connector: (options: Omit<ConstructorParameters<typeof QoderConnector>[0], "endpoint"> & {
11
+ serverUrl: string;
12
+ }) => QoderConnector;
13
+ server: typeof runQoderCloudServerCommand;
14
+ };
@@ -0,0 +1,12 @@
1
+ import { QoderAgentProvider } from './agent.js';
2
+ import { QoderConnector } from './connector.js';
3
+ import { requireQoderEndpoint } from './endpoint.js';
4
+ import { runQoderCloudServerCommand } from './pairing.js';
5
+ /** Factories remain idle until the host selects this installed contribution. */
6
+ export default function createQoderPlugin() {
7
+ return {
8
+ agent: (options) => new QoderAgentProvider(options.log, options.version),
9
+ connector: (options) => new QoderConnector({ ...options, endpoint: requireQoderEndpoint(options.serverUrl) }),
10
+ server: runQoderCloudServerCommand,
11
+ };
12
+ }
@@ -0,0 +1,50 @@
1
+ # Qoder Cloud Agent 配对模式
2
+
3
+ 当前运行于 Qoder Cloud Agent 时使用本模式;其他远端 Agent 使用 cloud-server / WebSocket 模式。浏览器机器先按本包 README 安装 Qoder 能力,Agent 机器可直接使用本包生成配对信息;两种模式保持相同的 Mearl action 契约。
4
+
5
+ Qoder 模式使用官方 Client-Side 自定义工具和 Session 事件接口,不依赖 Cloudflare Tunnel,也不把 Qoder 沙箱公网入口当作 WebSocket。Agent 按以下顺序处理:
6
+
7
+ 1. 检查当前 Agent 是否已经提供名为 `mearl` 的 Client-Side 自定义工具。若已提供,Agent 直接执行:
8
+
9
+ ```bash
10
+ npx @mearl/plugin-qoder pair
11
+ ```
12
+
13
+ 从输出读取本地 `npx @mearl/cloud-connector start "qoder://pair/..."` 命令和 `pair` 输入。先把本地命令展示给用户,再立即调用 `mearl` 自定义工具提交输出中的 `pair` 输入;该工具调用会暂停,直到用户在浏览器所在机器执行连接命令并完成配对。
14
+
15
+ 2. 配对后,本 Session 的浏览器操作不再在 Qoder 沙箱中执行 `mearl ...` shell 命令。Agent 在内部把 Skill 中相同的 action、payload、browser 和 timeout 映射为 `mearl` 自定义工具调用。对用户仍按正常 Mearl 操作结果交付,不额外暴露协议差异。
16
+
17
+ 3. 如果当前 Agent 没有 `mearl` 自定义工具,先判断 Agent 是否能使用已有 Qoder PAT 和 Agent ID/version 直接读取当前完整 `tools` 数组、追加下方配置并更新 Agent。不得覆盖其他已有工具。若缺少必要权限或信息,再引导用户在 Qoder Agent 配置中添加:
18
+
19
+ ```json
20
+ {
21
+ "type": "custom",
22
+ "name": "mearl",
23
+ "description": "Invoke a Mearl browser action on the user's paired local browser. Use action=pair only with a code generated by @mearl/plugin-qoder pair.",
24
+ "input_schema": {
25
+ "type": "object",
26
+ "additionalProperties": false,
27
+ "properties": {
28
+ "action": { "type": "string" },
29
+ "payload": { "type": "object" },
30
+ "browser": { "type": "string" },
31
+ "timeoutSec": { "type": "number", "minimum": 1 }
32
+ },
33
+ "required": ["action"]
34
+ }
35
+ }
36
+ ```
37
+
38
+ Qoder 工具配置绑定 Agent;修改后只对新 Session 生效。明确提示用户新建 Session,再从正常流程开始;不要在当前 Session 反复重试。
39
+
40
+ 4. 仅当本地报认证缺失、401 或 PAT 过期时,按 connector 错误提示在浏览器所在机器配置 Qoder PAT 并重启 connector。凭据来源和本地配置方式由错误提示提供;不要求用户把 PAT 发给 Agent,不把 PAT 放进命令 URL、聊天消息或日志。用户已主动提供 PAT 并明确要求配置时,可写入受支持来源,但不得复述。
41
+
42
+ 5. `page_screenshot` 结果会优先以 Qoder 图片内容块回传,并保留截图元数据;若接口版本暂不接受图片块,connector 自动退回包含原始 base64 的 JSON 文本,确保截图数据不丢失。
43
+
44
+ ---
45
+
46
+ <a id="common"></a>
47
+
48
+ ## 通用问题
49
+
50
+ <a id="timeout"></a>
package/package.json CHANGED
@@ -1,6 +1,48 @@
1
1
  {
2
2
  "name": "@mearl/plugin-qoder",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "3.0.0-beta.7",
4
+ "description": "Optional Qoder CLI agent and cloud connector capability for Mearl",
5
+ "type": "module",
6
+ "license": "Apache-2.0",
7
+ "main": "dist/index.js",
8
+ "types": "dist/index.d.ts",
9
+ "bin": {
10
+ "mearl-qoder": "dist/cli.js"
11
+ },
12
+ "exports": {
13
+ ".": {
14
+ "types": "./dist/index.d.ts",
15
+ "import": "./dist/index.js"
16
+ }
17
+ },
18
+ "files": [
19
+ "dist",
20
+ "docs",
21
+ "!dist/**/__tests__/**",
22
+ "!dist/**/*.test.d.ts"
23
+ ],
24
+ "engines": {
25
+ "node": ">=20.18.0"
26
+ },
27
+ "dependencies": {
28
+ "@agentclientprotocol/sdk": "^1.2.1",
29
+ "@mearl/agent-runtime": "3.0.0-beta.7",
30
+ "@mearl/client": "3.0.0-beta.7",
31
+ "@mearl/cloud-connector": "3.0.0-beta.7",
32
+ "@mearl/browser-core": "3.0.0-beta.7"
33
+ },
34
+ "devDependencies": {
35
+ "typescript": "^5.8.3",
36
+ "esbuild": "^0.28.2"
37
+ },
38
+ "repository": {
39
+ "type": "git",
40
+ "url": "git+https://github.com/mearlhq/mearl.git",
41
+ "directory": "packages/plugin-qoder"
42
+ },
43
+ "scripts": {
44
+ "build": "rm -rf dist/ && tsc && node build.mjs",
45
+ "typecheck": "tsc --noEmit",
46
+ "test": "vitest run"
47
+ }
6
48
  }