@mearl/setup
Advanced tools
| #!/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.`; | ||
| } |
@@ -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.'); |
+3
-1
@@ -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; |
+29
-6
| #!/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(); | ||
| } |
+2
-0
| 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'; |
+1
-0
| 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'; |
+7
-3
| { | ||
| "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", |
+6
-0
@@ -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` 自己的命令完成。 |
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
AI-detected potential code anomaly
Supply chain riskAI has identified unusual behaviors that may pose a security risk.
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
80491
4.81%26
18.18%1723
4.55%101
6.32%25
-3.85%