@mearl/setup 2.6.1 → 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
 
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
@@ -143,6 +158,7 @@ Examples:
143
158
  npx @mearl/setup --local --cloud
144
159
  npx @mearl/setup update
145
160
  npx @mearl/setup agentbay
161
+ npx @mearl/setup qoder --yes
146
162
  npx @mearl/setup update --local --target-line 2.3.x --skip-skill
147
163
  npx @mearl/setup uninstall --local`;
148
164
  if (toError)
@@ -193,6 +209,17 @@ export async function main(argv = process.argv.slice(2), interactiveTerminal = p
193
209
  return 1;
194
210
  }
195
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
+ }
196
223
  if (!interactiveTerminal && !parsed.yes && parsed.operation !== 'update') {
197
224
  console.error('Non-interactive input detected. Re-run with --yes or --non-interactive.');
198
225
  return 2;
@@ -212,7 +239,3 @@ export async function main(argv = process.argv.slice(2), interactiveTerminal = p
212
239
  return 1;
213
240
  }
214
241
  }
215
- const currentFile = fileURLToPath(import.meta.url);
216
- if (process.argv[1] && path.resolve(process.argv[1]) === currentFile) {
217
- process.exitCode = await main();
218
- }
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';
@@ -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.1",
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"