@mearl/setup 2.6.0 → 2.7.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 CHANGED
@@ -17,6 +17,10 @@ npx @mearl/setup agentbay
17
17
  无交互环境可使用 `--stdin` 或 `--key-file <path>`。为避免 Key 进入 shell history 和
18
18
  进程参数,不接受把 Key 直接写在命令行中。
19
19
 
20
+ Qoder Cloud Agent 仅在常规云连接失败、Mearl Skill 进入 Qoder 异常接管分支时使用
21
+ `npx @mearl/setup qoder --yes` 生成一次性配对指令。它不安装额外隧道,也不会把 Qoder
22
+ PAT 写入配对 URL;正常安装和连接流程无需执行该命令。
23
+
20
24
  ## 行为
21
25
 
22
26
  - `install` 可以省略;直接执行 `npx @mearl/setup` 等同于 `npx @mearl/setup install`。
@@ -33,6 +37,8 @@ npx @mearl/setup agentbay
33
37
  - local/cloud 共用一份 `@mearl/client`;组合安装只处理一次,卸载单个环境时若另一个环境仍在使用则保留。
34
38
  - 从 2.5.x 更新 cloud 环境时会先卸载旧 `@mearl/cloud-client`,避免它遗留的 `mearl` bin 与统一 client 冲突。
35
39
  - local/cloud 共用的全局 mearl skill 通过 `ali-skills` 的 JSON 清单定位,只处理一次。
40
+ - 安装始终通过 `ali-skills add` 写入最新的全局 mearl skill,并关联当前检测到的 Agent;
41
+ 可用 `--skip-skill` 跳过。
36
42
  - 卸载一个环境但另一个仍依赖全局 mearl skill 时会保留 skill。
37
43
  - `--mcp` 的客户端配置和清理由 `@mearl/mcp-server` 自己的命令完成。
38
44
 
@@ -67,13 +73,13 @@ npx @mearl/setup
67
73
  npx @mearl/setup install
68
74
 
69
75
  # Agent / CI 无交互安装
70
- npx @mearl/setup install --yes
76
+ npx @mearl/setup --yes
71
77
 
72
78
  # 安装云端 Agent 环境
73
- npx @mearl/setup install --cloud
79
+ npx @mearl/setup --cloud
74
80
 
75
81
  # 同一台机器同时作为本地浏览器宿主和云端 Agent
76
- npx @mearl/setup install --local --cloud
82
+ npx @mearl/setup --local --cloud
77
83
 
78
84
  # 自动更新当前 PATH 中检测到的全部 Mearl 环境
79
85
  npx @mearl/setup update
package/dist/aliSkills.js CHANGED
@@ -163,15 +163,7 @@ export async function runGlobalMearlSkillOperation(operation, options = {}) {
163
163
  return null;
164
164
  }
165
165
  };
166
- const paths = await listMearlPaths();
167
- if (!paths)
168
- return false;
169
166
  if (operation === 'install') {
170
- if (paths.length > 0) {
171
- writeLine('Skill: already installed:');
172
- paths.forEach(skillPath => writeLine(` ${skillPath}`));
173
- return true;
174
- }
175
167
  const installed = await run(['add', 'trip/mearl', '--skill', 'mearl', '--global', ...(options.yes ? ['--yes'] : [])], false);
176
168
  if (!installed)
177
169
  return false;
@@ -187,6 +179,9 @@ export async function runGlobalMearlSkillOperation(operation, options = {}) {
187
179
  writeLine('Skill: installed.');
188
180
  return true;
189
181
  }
182
+ const paths = await listMearlPaths();
183
+ if (!paths)
184
+ return false;
190
185
  if (paths.length === 0) {
191
186
  writeLine('Skill: no tracked global mearl skill found; skipped.');
192
187
  return true;
package/dist/bin.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/bin.js ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ import { main } from './cli.js';
3
+ process.exitCode = await main();
package/dist/cli.d.ts CHANGED
@@ -2,12 +2,13 @@
2
2
  import { configureAgentBayApiKey, promptAgentBayApiKey, readAgentBayApiKeyFile, readAgentBayApiKeyStdin } from './agentBay.js';
3
3
  import { type MearlLifecycleOperation } from './lifecycle.js';
4
4
  import type { MearlProfile } from './profiles.js';
5
+ import { createQoderPairingInfo } from './qoder.js';
5
6
  export declare const SETUP_VERSION: string;
6
7
  interface ParsedArgs {
7
8
  agentBayKeyFile?: string;
8
9
  agentBayReadStdin: boolean;
9
10
  help: boolean;
10
- operation?: MearlLifecycleOperation | 'agentbay';
11
+ operation?: MearlLifecycleOperation | 'agentbay' | 'qoder';
11
12
  profiles?: MearlProfile[];
12
13
  skipSkill: boolean;
13
14
  targetLine?: string;
@@ -19,6 +20,7 @@ export interface SetupCliDependencies {
19
20
  promptAgentBayKey?: typeof promptAgentBayApiKey;
20
21
  readAgentBayKeyFile?: typeof readAgentBayApiKeyFile;
21
22
  readAgentBayKeyStdin?: typeof readAgentBayApiKeyStdin;
23
+ createQoderPairing?: typeof createQoderPairingInfo;
22
24
  }
23
25
  export declare function parseSetupArgs(argv: string[]): ParsedArgs;
24
26
  export declare function main(argv?: string[], interactiveTerminal?: boolean, dependencies?: SetupCliDependencies): Promise<number>;
package/dist/cli.js CHANGED
@@ -1,9 +1,8 @@
1
1
  #!/usr/bin/env node
2
- import path from 'node:path';
3
2
  import { createRequire } from 'node:module';
4
- import { fileURLToPath } from 'node:url';
5
3
  import { configureAgentBayApiKey, promptAgentBayApiKey, readAgentBayApiKeyFile, readAgentBayApiKeyStdin, } from './agentBay.js';
6
4
  import { runMearlLifecycle } from './lifecycle.js';
5
+ import { createQoderPairingInfo, formatQoderPairingOutput } from './qoder.js';
7
6
  import { isMearlReleaseLine } from './version.js';
8
7
  const require = createRequire(import.meta.url);
9
8
  export const SETUP_VERSION = require('../package.json').version;
@@ -54,6 +53,20 @@ export function parseSetupArgs(argv) {
54
53
  }
55
54
  throw new Error('Usage: npx @mearl/setup agentbay [--stdin | --key-file <path>]. API keys are not accepted as command-line arguments.');
56
55
  }
56
+ if (operation === 'qoder') {
57
+ const options = argv.slice(1);
58
+ const allowed = new Set(['--yes', '-y', '--non-interactive']);
59
+ if (options.some(option => !allowed.has(option))) {
60
+ throw new Error('Usage: npx @mearl/setup qoder [--yes]');
61
+ }
62
+ return {
63
+ agentBayReadStdin: false,
64
+ help: false,
65
+ operation,
66
+ skipSkill: false,
67
+ yes: options.length > 0,
68
+ };
69
+ }
57
70
  if (operation !== 'install' && operation !== 'update' && operation !== 'uninstall') {
58
71
  throw new Error(`Unknown operation: ${operation}`);
59
72
  }
@@ -112,12 +125,14 @@ Usage:
112
125
  npx @mearl/setup [install] [--local] [--cloud] [--mcp] [--yes]
113
126
  npx @mearl/setup <update|uninstall> [--local] [--cloud] [--mcp] [--yes]
114
127
  npx @mearl/setup agentbay [--stdin | --key-file <path>]
128
+ npx @mearl/setup qoder [--yes]
115
129
 
116
130
  Behavior:
117
131
  install Default command; defaults to --local when no environment is specified
118
132
  update Auto-detects installed environments from the current PATH
119
133
  uninstall Auto-detects installed environments and asks for confirmation
120
134
  agentbay Save or update AGENTBAY_KEY without changing other Mearl settings
135
+ qoder Create a Qoder client-side tool pairing request for troubleshooting
121
136
 
122
137
  Options:
123
138
  --local Manage @mearl/native-host and @mearl/client
@@ -139,11 +154,11 @@ Examples:
139
154
  npx @mearl/setup
140
155
  npx @mearl/setup --yes
141
156
  npx @mearl/setup install
142
- npx @mearl/setup install --yes
143
- npx @mearl/setup install --cloud
144
- npx @mearl/setup install --local --cloud
157
+ npx @mearl/setup --cloud
158
+ npx @mearl/setup --local --cloud
145
159
  npx @mearl/setup update
146
160
  npx @mearl/setup agentbay
161
+ npx @mearl/setup qoder --yes
147
162
  npx @mearl/setup update --local --target-line 2.3.x --skip-skill
148
163
  npx @mearl/setup uninstall --local`;
149
164
  if (toError)
@@ -194,6 +209,17 @@ export async function main(argv = process.argv.slice(2), interactiveTerminal = p
194
209
  return 1;
195
210
  }
196
211
  }
212
+ if (parsed.operation === 'qoder') {
213
+ try {
214
+ const pairing = (dependencies.createQoderPairing ?? createQoderPairingInfo)();
215
+ console.log(formatQoderPairingOutput(pairing));
216
+ return 0;
217
+ }
218
+ catch (error) {
219
+ console.error(error instanceof Error ? error.message : String(error));
220
+ return 1;
221
+ }
222
+ }
197
223
  if (!interactiveTerminal && !parsed.yes && parsed.operation !== 'update') {
198
224
  console.error('Non-interactive input detected. Re-run with --yes or --non-interactive.');
199
225
  return 2;
@@ -213,7 +239,3 @@ export async function main(argv = process.argv.slice(2), interactiveTerminal = p
213
239
  return 1;
214
240
  }
215
241
  }
216
- const currentFile = fileURLToPath(import.meta.url);
217
- if (process.argv[1] && path.resolve(process.argv[1]) === currentFile) {
218
- process.exitCode = await main();
219
- }
package/dist/index.d.ts CHANGED
@@ -1,6 +1,8 @@
1
1
  export { buildGlobalPackageCommand, detectGlobalPackage, resolveInvokingPackageManager, resolvePackageManagerInstallation, } from './packageManager.js';
2
2
  export { configureAgentBayApiKey, promptAgentBayApiKey, readAgentBayApiKeyFile, readAgentBayApiKeyStdin, } from './agentBay.js';
3
3
  export type { AgentBayConfigurationOptions, AgentBayConfigurationResult, AgentBaySecretInput, AgentBaySecretOutput, } from './agentBay.js';
4
+ export { createQoderPairingInfo, formatQoderPairingOutput } from './qoder.js';
5
+ export type { QoderPairingInfo, QoderPairingOptions } from './qoder.js';
4
6
  export type { DetectedGlobalPackage, GlobalPackageCommand, GlobalPackageManager, PackageManagerInstallation, PackageOperation, PackageDetectionOptions, } from './packageManager.js';
5
7
  export { runMearlLifecycle } from './lifecycle.js';
6
8
  export type { MearlLifecycleDependencies, MearlLifecycleOperation, MearlLifecycleOptions, } from './lifecycle.js';
package/dist/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  export { buildGlobalPackageCommand, detectGlobalPackage, resolveInvokingPackageManager, resolvePackageManagerInstallation, } from './packageManager.js';
2
2
  export { configureAgentBayApiKey, promptAgentBayApiKey, readAgentBayApiKeyFile, readAgentBayApiKeyStdin, } from './agentBay.js';
3
+ export { createQoderPairingInfo, formatQoderPairingOutput } from './qoder.js';
3
4
  export { runMearlLifecycle } from './lifecycle.js';
4
5
  export { MEARL_PROFILES, detectMearlProfiles } from './profiles.js';
5
6
  export { MEARL_NATIVE_HOST_NAMES, resolveNativeHostDirectory, uninstallNativeHostArtifacts, } from './nativeHost.js';
package/dist/lifecycle.js CHANGED
@@ -150,7 +150,7 @@ export async function runMearlLifecycle(options, dependencies = {}) {
150
150
  writeLine('No installed Mearl environment was detected on the current PATH.');
151
151
  if (options.operation === 'uninstall')
152
152
  return true;
153
- writeLine('Run: npx @mearl/setup install');
153
+ writeLine('Run: npx @mearl/setup');
154
154
  return false;
155
155
  }
156
156
  if (options.operation === 'update') {
@@ -0,0 +1,18 @@
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
+ /** Create a short-lived correlation handle without embedding Qoder credentials in the URL. */
17
+ export declare function createQoderPairingInfo(options?: QoderPairingOptions): QoderPairingInfo;
18
+ export declare function formatQoderPairingOutput(info: QoderPairingInfo): string;
package/dist/qoder.js ADDED
@@ -0,0 +1,32 @@
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 "${info.connectorUrl}"`;
23
+ return `[Qoder] Mearl local-browser pairing is ready.
24
+
25
+ Show the user this command and ask them to run it on the computer that owns the browser:
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 reads QODER_PERSONAL_ACCESS_TOKEN from the local environment. Never add the PAT to the pairing URL.`;
32
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mearl/setup",
3
- "version": "2.6.0",
3
+ "version": "2.7.0",
4
4
  "description": "One-shot environment setup and configuration for Mearl",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -30,13 +30,17 @@
30
30
  "types": "./dist/agentBay.d.ts",
31
31
  "import": "./dist/agentBay.js"
32
32
  },
33
+ "./qoder": {
34
+ "types": "./dist/qoder.d.ts",
35
+ "import": "./dist/qoder.js"
36
+ },
33
37
  "./version": {
34
38
  "types": "./dist/version.d.ts",
35
39
  "import": "./dist/version.js"
36
40
  }
37
41
  },
38
42
  "bin": {
39
- "mearl-setup": "./dist/cli.js"
43
+ "mearl-setup": "./dist/bin.js"
40
44
  },
41
45
  "files": [
42
46
  "dist",
@@ -58,7 +62,7 @@
58
62
  "typescript": "^5.8.3"
59
63
  },
60
64
  "scripts": {
61
- "build": "rm -rf dist/ && tsc && chmod +x dist/cli.js",
65
+ "build": "rm -rf dist/ && tsc && chmod +x dist/bin.js",
62
66
  "dev": "tsc --watch",
63
67
  "typecheck": "tsc --noEmit",
64
68
  "test": "vitest run"