From b4881268303df4ab71b76224a350b8a6488cf8cb Mon Sep 17 00:00:00 2001 From: LaZzyMan Date: Tue, 10 Feb 2026 14:38:01 +0800 Subject: [PATCH] feat add multi-platform support --- esbuild.config.js | 7 ++++ packages/cli/package.json | 10 +++++- .../cli/src/ui/utils/clipboardUtils.test.ts | 32 +++++++------------ packages/cli/src/ui/utils/clipboardUtils.ts | 31 ++++++++++++++++-- .../core/src/extension/claude-converter.ts | 2 +- scripts/prepare-package.js | 7 ++++ 6 files changed, 64 insertions(+), 25 deletions(-) diff --git a/esbuild.config.js b/esbuild.config.js index 12ab39d58..2b532b44e 100644 --- a/esbuild.config.js +++ b/esbuild.config.js @@ -33,6 +33,13 @@ const external = [ '@lydell/node-pty-linux-x64', '@lydell/node-pty-win32-arm64', '@lydell/node-pty-win32-x64', + '@teddyzhu/clipboard', + '@teddyzhu/clipboard-darwin-arm64', + '@teddyzhu/clipboard-darwin-x64', + '@teddyzhu/clipboard-linux-x64-gnu', + '@teddyzhu/clipboard-linux-arm64-gnu', + '@teddyzhu/clipboard-win32-x64-msvc', + '@teddyzhu/clipboard-win32-arm64-msvc', ]; esbuild diff --git a/packages/cli/package.json b/packages/cli/package.json index b0155cbb4..4a37c2566 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -41,7 +41,6 @@ "@iarna/toml": "^2.2.5", "@modelcontextprotocol/sdk": "^1.25.1", "@qwen-code/qwen-code-core": "file:../core", - "@teddyzhu/clipboard": "^0.0.5", "@types/update-notifier": "^6.0.8", "ansi-regex": "^6.2.2", "command-exists": "^1.2.9", @@ -96,6 +95,15 @@ "typescript": "^5.3.3", "vitest": "^3.1.1" }, + "optionalDependencies": { + "@teddyzhu/clipboard": "^0.0.5", + "@teddyzhu/clipboard-darwin-arm64": "0.0.5", + "@teddyzhu/clipboard-darwin-x64": "0.0.5", + "@teddyzhu/clipboard-linux-x64-gnu": "0.0.5", + "@teddyzhu/clipboard-linux-arm64-gnu": "0.0.5", + "@teddyzhu/clipboard-win32-x64-msvc": "0.0.5", + "@teddyzhu/clipboard-win32-arm64-msvc": "0.0.5" + }, "engines": { "node": ">=20" } diff --git a/packages/cli/src/ui/utils/clipboardUtils.test.ts b/packages/cli/src/ui/utils/clipboardUtils.test.ts index c7197c5cf..5a190bf48 100644 --- a/packages/cli/src/ui/utils/clipboardUtils.test.ts +++ b/packages/cli/src/ui/utils/clipboardUtils.test.ts @@ -16,6 +16,12 @@ const mockHasFormat = vi.fn(); const mockGetImageData = vi.fn(); vi.mock('@teddyzhu/clipboard', () => ({ + default: { + ClipboardManager: vi.fn().mockImplementation(() => ({ + hasFormat: mockHasFormat, + getImageData: mockGetImageData, + })), + }, ClipboardManager: vi.fn().mockImplementation(() => ({ hasFormat: mockHasFormat, getImageData: mockGetImageData, @@ -53,26 +59,19 @@ describe('clipboardUtils', () => { expect(result).toBe(false); }); - it('should log errors in DEBUG mode', async () => { + it('should return false and not throw when error occurs in DEBUG mode', async () => { const originalEnv = process.env; vi.stubGlobal('process', { ...process, env: { ...originalEnv, DEBUG: '1' }, }); - const consoleErrorSpy = vi - .spyOn(console, 'error') - .mockImplementation(() => {}); mockHasFormat.mockImplementation(() => { throw new Error('Test error'); }); - await clipboardHasImage(); - expect(consoleErrorSpy).toHaveBeenCalledWith( - 'Error checking clipboard for image:', - expect.any(Error), - ); - consoleErrorSpy.mockRestore(); + const result = await clipboardHasImage(); + expect(result).toBe(false); }); }); @@ -101,26 +100,19 @@ describe('clipboardUtils', () => { expect(result).toBe(null); }); - it('should log errors in DEBUG mode', async () => { + it('should return null and not throw when error occurs in DEBUG mode', async () => { const originalEnv = process.env; vi.stubGlobal('process', { ...process, env: { ...originalEnv, DEBUG: '1' }, }); - const consoleErrorSpy = vi - .spyOn(console, 'error') - .mockImplementation(() => {}); mockHasFormat.mockImplementation(() => { throw new Error('Test error'); }); - await saveClipboardImage('/tmp/test'); - expect(consoleErrorSpy).toHaveBeenCalledWith( - 'Error saving clipboard image:', - expect.any(Error), - ); - consoleErrorSpy.mockRestore(); + const result = await saveClipboardImage('/tmp/test'); + expect(result).toBe(null); }); }); diff --git a/packages/cli/src/ui/utils/clipboardUtils.ts b/packages/cli/src/ui/utils/clipboardUtils.ts index 9b21e6303..a28c2a49c 100644 --- a/packages/cli/src/ui/utils/clipboardUtils.ts +++ b/packages/cli/src/ui/utils/clipboardUtils.ts @@ -6,18 +6,41 @@ import * as fs from 'node:fs/promises'; import * as path from 'node:path'; -import { ClipboardManager } from '@teddyzhu/clipboard'; import { createDebugLogger } from '@qwen-code/qwen-code-core'; const debugLogger = createDebugLogger('CLIPBOARD_UTILS'); +// eslint-disable-next-line @typescript-eslint/no-explicit-any +type ClipboardModule = any; + +let cachedClipboardModule: ClipboardModule | null = null; +let clipboardLoadAttempted = false; + +async function getClipboardModule(): Promise { + if (clipboardLoadAttempted) return cachedClipboardModule; + clipboardLoadAttempted = true; + + try { + const modName = '@teddyzhu/clipboard'; + cachedClipboardModule = await import(modName); + return cachedClipboardModule; + } catch (_e) { + debugLogger.error( + 'Failed to load @teddyzhu/clipboard native module. Clipboard image features will be unavailable.', + ); + return null; + } +} + /** * Checks if the system clipboard contains an image * @returns true if clipboard contains an image */ export async function clipboardHasImage(): Promise { try { - const clipboard = new ClipboardManager(); + const mod = await getClipboardModule(); + if (!mod) return false; + const clipboard = new mod.ClipboardManager(); return clipboard.hasFormat('image'); } catch (error) { debugLogger.error('Error checking clipboard for image:', error); @@ -34,7 +57,9 @@ export async function saveClipboardImage( targetDir?: string, ): Promise { try { - const clipboard = new ClipboardManager(); + const mod = await getClipboardModule(); + if (!mod) return null; + const clipboard = new mod.ClipboardManager(); if (!clipboard.hasFormat('image')) { return null; diff --git a/packages/core/src/extension/claude-converter.ts b/packages/core/src/extension/claude-converter.ts index 28835bc87..68da9cfff 100644 --- a/packages/core/src/extension/claude-converter.ts +++ b/packages/core/src/extension/claude-converter.ts @@ -100,7 +100,7 @@ const CLAUDE_TOOLS_MAPPING: Record = { Grep: 'Grep', KillShell: 'None', NotebookEdit: 'None', - Read: ['ReadFile', 'ReadManyFiles'], + Read: 'ReadFile', Skill: 'Skill', Task: 'Task', TodoWrite: 'TodoWrite', diff --git a/scripts/prepare-package.js b/scripts/prepare-package.js index de94e8d81..3ae9d3e08 100644 --- a/scripts/prepare-package.js +++ b/scripts/prepare-package.js @@ -161,6 +161,13 @@ const distPackageJson = { '@lydell/node-pty-linux-x64': '1.1.0', '@lydell/node-pty-win32-arm64': '1.1.0', '@lydell/node-pty-win32-x64': '1.1.0', + '@teddyzhu/clipboard': '0.0.5', + '@teddyzhu/clipboard-darwin-arm64': '0.0.5', + '@teddyzhu/clipboard-darwin-x64': '0.0.5', + '@teddyzhu/clipboard-linux-x64-gnu': '0.0.5', + '@teddyzhu/clipboard-linux-arm64-gnu': '0.0.5', + '@teddyzhu/clipboard-win32-x64-msvc': '0.0.5', + '@teddyzhu/clipboard-win32-arm64-msvc': '0.0.5', }, engines: rootPackageJson.engines, };