qwen-code/scripts/sync-computer-use-schemas.ts
顾盼 53d3d7f6ff
feat(computer-use): use @qwen-code/open-computer-use fork (signed + notarized) (#4726)
* feat(computer-use): point built-in MCP at @qwen-code/open-computer-use@0.2.2

Switch the deferred Computer Use MCP server from upstream
`open-computer-use` to the QwenLM fork `@qwen-code/open-computer-use`,
published to npm (signed + notarized, pinned at 0.2.2).

- constants.ts: add PINNED_OPEN_COMPUTER_USE_PACKAGE_NAME
  (@qwen-code/open-computer-use); pin 0.2.2;
  resolveComputerUsePackageSpec() composes name@version.
- sync-computer-use-schemas.ts: default to the scoped package + 0.2.2.
- schemas.ts: header refresh — tool surface is unchanged across
  0.2.0→0.2.2, so the hardcoded 9-tool schemas need no content change.
- Test/doc sample specs updated to the scoped name. permission-detector
  tests keep `open-computer-use doctor` — only the npm package is scoped;
  the installed CLI binary is still named `open-computer-use`.

* feat(computer-use): point built-in MCP at @qwen-code/open-computer-use@0.2.3

Switch the deferred Computer Use MCP server from upstream
`open-computer-use` to the QwenLM fork `@qwen-code/open-computer-use`,
published to npm (signed + notarized, pinned at 0.2.3).

0.2.3 includes the screenshot env-var controls (OPEN_COMPUTER_USE_IMAGE_*),
the window-free `permission-status` command, and the minScale-clamp fix
(small MAX_DIMENSION now downsamples to the minScale floor instead of
falling back to the full-size original).

- constants.ts: add PINNED_OPEN_COMPUTER_USE_PACKAGE_NAME
  (@qwen-code/open-computer-use); pin 0.2.3;
  resolveComputerUsePackageSpec() composes name@version.
- sync-computer-use-schemas.ts: default to the scoped package + 0.2.3.
- schemas.ts: header refresh — 0.2.0→0.2.3 changes don't alter the MCP
  tool surface, so the hardcoded 9-tool schemas are unchanged.
- Test/doc sample specs use the scoped name. permission-detector tests
  keep `open-computer-use doctor` — only the npm package is scoped; the
  installed CLI binary is still named `open-computer-use`.
2026-06-03 19:13:39 +08:00

107 lines
3.2 KiB
TypeScript
Executable file

#!/usr/bin/env tsx
/**
* Regenerate packages/core/src/tools/computer-use/schemas.ts from a
* live @qwen-code/open-computer-use MCP server.
*
* Usage:
* npx tsx scripts/sync-computer-use-schemas.ts [packageSpec]
*
* The default is the currently-pinned package + version from
* `packages/core/src/tools/computer-use/constants.ts`
* (PINNED_OPEN_COMPUTER_USE_PACKAGE_NAME / _VERSION). Running with no
* args verifies the current pin is still in sync; pass an explicit spec
* (e.g. `@qwen-code/open-computer-use@0.2.1`) to upgrade.
*
* Bumping the pin is a 4-step procedure documented in constants.ts —
* read that JSDoc first.
*/
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
import { writeFile } from 'node:fs/promises';
import { resolve } from 'node:path';
// Keep in sync with PINNED_OPEN_COMPUTER_USE_PACKAGE_NAME /
// PINNED_OPEN_COMPUTER_USE_VERSION in
// packages/core/src/tools/computer-use/constants.ts. Duplicated as
// literals here because importing TypeScript from `scripts/` into the
// package tree adds tooling complexity for a two-string lookup.
const DEFAULT_PACKAGE_NAME = '@qwen-code/open-computer-use';
const DEFAULT_PINNED_VERSION = '0.2.3';
async function main(): Promise<void> {
const packageSpec =
process.argv[2] ?? `${DEFAULT_PACKAGE_NAME}@${DEFAULT_PINNED_VERSION}`;
const transport = new StdioClientTransport({
command: 'npx',
args: ['-y', packageSpec, 'mcp'],
});
const client = new Client(
{ name: 'qwen-code-schema-sync', version: '1.0.0' },
{ capabilities: {} },
);
await client.connect(transport);
const result = await client.listTools();
await client.close();
if (result.tools.length !== 9) {
process.stderr.write(
`WARNING: upstream returned ${result.tools.length} tools, expected 9. Continuing anyway.\n`,
);
}
const schemas: Record<
string,
{ description: string; parameterSchema: unknown }
> = {};
for (const tool of result.tools) {
schemas[tool.name] = {
description: tool.description ?? '',
parameterSchema: tool.inputSchema ?? { type: 'object', properties: {} },
};
}
const out = `/**
* @license
* Copyright 2025 Qwen Team
* SPDX-License-Identifier: Apache-2.0
*/
/**
* Hardcoded schemas for the upstream open-computer-use tools.
*
* Pinned to upstream: ${packageSpec}
* Regenerated by scripts/sync-computer-use-schemas.ts — do not hand-edit.
*/
export interface ComputerUseToolSchema {
description: string;
parameterSchema: Record<string, unknown>;
}
export const COMPUTER_USE_TOOL_NAMES = ${JSON.stringify(
result.tools.map((t) => t.name),
null,
2,
)} as const;
export type ComputerUseToolName = (typeof COMPUTER_USE_TOOL_NAMES)[number];
export const COMPUTER_USE_SCHEMAS: Record<ComputerUseToolName, ComputerUseToolSchema> = ${JSON.stringify(
schemas,
null,
2,
)};
`;
const target = resolve('packages/core/src/tools/computer-use/schemas.ts');
await writeFile(target, out, 'utf8');
process.stdout.write(`Wrote ${result.tools.length} schemas to ${target}\n`);
}
main().catch((err) => {
process.stderr.write(`Schema sync failed: ${err}\n`);
process.exit(1);
});