Sign In

@mearl/setup

Package Overview
Dependencies
Maintainers
2
Versions
9
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@mearl/setup - npm Package Compare versions

Comparing version
2.6.1
to
2.7.0
+2
dist/bin.d.ts
#!/usr/bin/env node
export {};
#!/usr/bin/env node
import { main } from './cli.js';
process.exitCode = await main();
export interface QoderPairingInfo {
pairingCode: string;
createdAt: number;
connectorUrl: string;
toolInput: {
action: 'pair';
payload: {
code: string;
};
};
}
export interface QoderPairingOptions {
now?: () => number;
createCode?: () => string;
}
/** Create a short-lived correlation handle without embedding Qoder credentials in the URL. */
export declare function createQoderPairingInfo(options?: QoderPairingOptions): QoderPairingInfo;
export declare function formatQoderPairingOutput(info: QoderPairingInfo): string;
import { randomBytes } from 'node:crypto';
/** Create a short-lived correlation handle without embedding Qoder credentials in the URL. */
export function createQoderPairingInfo(options = {}) {
const pairingCode = (options.createCode ?? (() => randomBytes(24).toString('base64url')))();
if (!/^[A-Za-z0-9_-]{16,128}$/.test(pairingCode)) {
throw new Error('Qoder pairing code must be 16-128 URL-safe characters');
}
const createdAt = (options.now ?? Date.now)();
if (!Number.isSafeInteger(createdAt) ||
createdAt < 1_000_000_000_000 ||
createdAt > 9_999_999_999_999) {
throw new Error('Qoder pairing timestamp must be a 13-digit epoch millisecond value');
}
return {
pairingCode,
createdAt,
connectorUrl: `qoder://pair/${pairingCode}?created=${createdAt}`,
toolInput: { action: 'pair', payload: { code: pairingCode } },
};
}
export function formatQoderPairingOutput(info) {
const connectorCommand = `npx @mearl/cloud-connector "${info.connectorUrl}"`;
return `[Qoder] Mearl local-browser pairing is ready.
Show the user this command and ask them to run it on the computer that owns the browser:
${connectorCommand}
Then immediately invoke the Qoder client-side custom tool named "mearl" with this input:
${JSON.stringify(info.toolInput)}
The connector reads QODER_PERSONAL_ACCESS_TOKEN from the local environment. Never add the PAT to the pairing URL.`;
}
+3
-8

@@ -166,11 +166,3 @@ import fs from 'node:fs';

};
const paths = await listMearlPaths();
if (!paths)
return false;
if (operation === 'install') {
if (paths.length > 0) {
writeLine('Skill: already installed:');
paths.forEach(skillPath => writeLine(` ${skillPath}`));
return true;
}
const installed = await run(['add', 'trip/mearl', '--skill', 'mearl', '--global', ...(options.yes ? ['--yes'] : [])], false);

@@ -191,2 +183,5 @@ if (!installed)

}
const paths = await listMearlPaths();
if (!paths)
return false;
if (paths.length === 0) {

@@ -193,0 +188,0 @@ writeLine('Skill: no tracked global mearl skill found; skipped.');

@@ -5,2 +5,3 @@ #!/usr/bin/env node

import type { MearlProfile } from './profiles.js';
import { createQoderPairingInfo } from './qoder.js';
export declare const SETUP_VERSION: string;

@@ -11,3 +12,3 @@ interface ParsedArgs {

help: boolean;
operation?: MearlLifecycleOperation | 'agentbay';
operation?: MearlLifecycleOperation | 'agentbay' | 'qoder';
profiles?: MearlProfile[];

@@ -24,2 +25,3 @@ skipSkill: boolean;

readAgentBayKeyStdin?: typeof readAgentBayApiKeyStdin;
createQoderPairing?: typeof createQoderPairingInfo;
}

@@ -26,0 +28,0 @@ export declare function parseSetupArgs(argv: string[]): ParsedArgs;

#!/usr/bin/env node
import path from 'node:path';
import { createRequire } from 'node:module';
import { fileURLToPath } from 'node:url';
import { configureAgentBayApiKey, promptAgentBayApiKey, readAgentBayApiKeyFile, readAgentBayApiKeyStdin, } from './agentBay.js';
import { runMearlLifecycle } from './lifecycle.js';
import { createQoderPairingInfo, formatQoderPairingOutput } from './qoder.js';
import { isMearlReleaseLine } from './version.js';

@@ -57,2 +56,16 @@ const require = createRequire(import.meta.url);

}
if (operation === 'qoder') {
const options = argv.slice(1);
const allowed = new Set(['--yes', '-y', '--non-interactive']);
if (options.some(option => !allowed.has(option))) {
throw new Error('Usage: npx @mearl/setup qoder [--yes]');
}
return {
agentBayReadStdin: false,
help: false,
operation,
skipSkill: false,
yes: options.length > 0,
};
}
if (operation !== 'install' && operation !== 'update' && operation !== 'uninstall') {

@@ -116,2 +129,3 @@ throw new Error(`Unknown operation: ${operation}`);

npx @mearl/setup agentbay [--stdin | --key-file <path>]
npx @mearl/setup qoder [--yes]

@@ -123,2 +137,3 @@ Behavior:

agentbay Save or update AGENTBAY_KEY without changing other Mearl settings
qoder Create a Qoder client-side tool pairing request for troubleshooting

@@ -149,2 +164,3 @@ Options:

npx @mearl/setup agentbay
npx @mearl/setup qoder --yes
npx @mearl/setup update --local --target-line 2.3.x --skip-skill

@@ -200,2 +216,13 @@ npx @mearl/setup uninstall --local`;

}
if (parsed.operation === 'qoder') {
try {
const pairing = (dependencies.createQoderPairing ?? createQoderPairingInfo)();
console.log(formatQoderPairingOutput(pairing));
return 0;
}
catch (error) {
console.error(error instanceof Error ? error.message : String(error));
return 1;
}
}
if (!interactiveTerminal && !parsed.yes && parsed.operation !== 'update') {

@@ -220,5 +247,1 @@ console.error('Non-interactive input detected. Re-run with --yes or --non-interactive.');

}
const currentFile = fileURLToPath(import.meta.url);
if (process.argv[1] && path.resolve(process.argv[1]) === currentFile) {
process.exitCode = await main();
}
export { buildGlobalPackageCommand, detectGlobalPackage, resolveInvokingPackageManager, resolvePackageManagerInstallation, } from './packageManager.js';
export { configureAgentBayApiKey, promptAgentBayApiKey, readAgentBayApiKeyFile, readAgentBayApiKeyStdin, } from './agentBay.js';
export type { AgentBayConfigurationOptions, AgentBayConfigurationResult, AgentBaySecretInput, AgentBaySecretOutput, } from './agentBay.js';
export { createQoderPairingInfo, formatQoderPairingOutput } from './qoder.js';
export type { QoderPairingInfo, QoderPairingOptions } from './qoder.js';
export type { DetectedGlobalPackage, GlobalPackageCommand, GlobalPackageManager, PackageManagerInstallation, PackageOperation, PackageDetectionOptions, } from './packageManager.js';

@@ -5,0 +7,0 @@ export { runMearlLifecycle } from './lifecycle.js';

export { buildGlobalPackageCommand, detectGlobalPackage, resolveInvokingPackageManager, resolvePackageManagerInstallation, } from './packageManager.js';
export { configureAgentBayApiKey, promptAgentBayApiKey, readAgentBayApiKeyFile, readAgentBayApiKeyStdin, } from './agentBay.js';
export { createQoderPairingInfo, formatQoderPairingOutput } from './qoder.js';
export { runMearlLifecycle } from './lifecycle.js';

@@ -4,0 +5,0 @@ export { MEARL_PROFILES, detectMearlProfiles } from './profiles.js';

{
"name": "@mearl/setup",
"version": "2.6.1",
"version": "2.7.0",
"description": "One-shot environment setup and configuration for Mearl",

@@ -33,2 +33,6 @@ "type": "module",

},
"./qoder": {
"types": "./dist/qoder.d.ts",
"import": "./dist/qoder.js"
},
"./version": {

@@ -40,3 +44,3 @@ "types": "./dist/version.d.ts",

"bin": {
"mearl-setup": "./dist/cli.js"
"mearl-setup": "./dist/bin.js"
},

@@ -63,3 +67,3 @@ "files": [

"scripts": {
"build": "rm -rf dist/ && tsc && chmod +x dist/cli.js",
"build": "rm -rf dist/ && tsc && chmod +x dist/bin.js",
"dev": "tsc --watch",

@@ -66,0 +70,0 @@ "typecheck": "tsc --noEmit",

@@ -20,2 +20,6 @@ # @mearl/setup

Qoder Cloud Agent 仅在常规云连接失败、Mearl Skill 进入 Qoder 异常接管分支时使用
`npx @mearl/setup qoder --yes` 生成一次性配对指令。它不安装额外隧道,也不会把 Qoder
PAT 写入配对 URL;正常安装和连接流程无需执行该命令。
## 行为

@@ -37,2 +41,4 @@

- local/cloud 共用的全局 mearl skill 通过 `ali-skills` 的 JSON 清单定位,只处理一次。
- 安装始终通过 `ali-skills add` 写入最新的全局 mearl skill,并关联当前检测到的 Agent;
可用 `--skip-skill` 跳过。
- 卸载一个环境但另一个仍依赖全局 mearl skill 时会保留 skill。

@@ -39,0 +45,0 @@ - `--mcp` 的客户端配置和清理由 `@mearl/mcp-server` 自己的命令完成。