Skip to content

Commit e9a7733

Browse files
committed
feat(computer-use): replace built-in tools with bundled skill
1 parent 717ad10 commit e9a7733

52 files changed

Lines changed: 1121 additions & 5842 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/.size-baseline

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
3480 audio-capture-prebuilds.yml
1717
9023 auto-minimize-spam.yml
1818
4638 build-and-publish-image.yml
19-
42519 cd-cua-driver.yml
19+
49610 cd-cua-driver.yml
2020
2076 cd-mobile-mcp.yml
2121
69782 ci.yml
2222
1482 codeql.yml
@@ -55,7 +55,6 @@
5555
6777 serve-ab-publish.yml
5656
17013 serve-ab.yml
5757
2641 stale.yml
58-
8653 sync-cua-driver-to-oss.yml
5958
10920 sync-desktop-to-oss.yml
6059
10018 sync-live-host-to-oss.yml
6160
10138 sync-release-to-oss.yml

.github/workflows/cd-cua-driver.yml

Lines changed: 173 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,15 @@ name: 'CD: Qwen CUA Driver'
1111
# imported cert (no DEVELOPER_NAME secret needed).
1212
# Windows ships UNSIGNED (matches upstream — no EV cert).
1313
#
14-
# Artifact convention (matches the qwen-code computer-use downloader):
14+
# Artifact convention used by the @qwen-code/cua-sdk native installer:
1515
# macOS : cua-driver-rs-<v>-darwin-{arm64,x86_64,universal}.tar.gz
1616
# (each contains the Qwen binary, SDK payload, and signed
1717
# QwenCuaDriver.app) + *-binary.tar.gz (runtime + SDK payload)
1818
# Linux : cua-driver-rs-<v>-linux-{x86_64,arm64}.tar.gz + *-binary.tar.gz
1919
# Windows: cua-driver-rs-<v>-windows-{x86_64,arm64}.zip + *-binary.zip
20-
# npm : one platform-neutral @qwen-code/cua-sdk package. Its postinstall
21-
# downloads and verifies the matching *-binary archive above.
20+
# npm : @qwen-code/cua-sdk downloads and verifies the matching *-binary
21+
# archive above. @qwen-code/node-repl-mcp is independently
22+
# versioned and ships from the same verified workflow.
2223
on:
2324
push:
2425
tags: ['cua-driver-rs-v*']
@@ -37,11 +38,18 @@ on:
3738
default: true
3839
dry_run:
3940
description:
40-
'Build all release assets and clean-install the npm package without
41+
'Build release assets and clean-install both npm packages without
4142
creating a GitHub Release, npm version, tag, or installer sync PR.'
4243
required: false
4344
type: 'boolean'
4445
default: true
46+
node_repl_only:
47+
description:
48+
'Only verify/publish @qwen-code/node-repl-mcp; do not build or release
49+
cua-driver assets.'
50+
required: false
51+
type: 'boolean'
52+
default: false
4553
permissions:
4654
contents: 'write'
4755
jobs:
@@ -50,6 +58,7 @@ jobs:
5058
runs-on: 'ubuntu-latest'
5159
outputs:
5260
version: '${{ steps.release.outputs.version }}'
61+
node_repl_version: '${{ steps.release.outputs.node_repl_version }}'
5362
steps:
5463
- uses: 'actions/checkout@v4'
5564
with:
@@ -82,11 +91,22 @@ jobs:
8291
exit 1
8392
fi
8493
94+
NODE_REPL_NAME=$(node -p "require('./packages/node-repl/package.json').name")
95+
NODE_REPL_VERSION=$(node -p "require('./packages/node-repl/package.json').version")
96+
if [[ "$NODE_REPL_NAME" != "@qwen-code/node-repl-mcp" ]]; then
97+
echo "::error::Expected @qwen-code/node-repl-mcp, found $NODE_REPL_NAME"
98+
exit 1
99+
fi
100+
if [[ ! "$NODE_REPL_VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$ ]]; then
101+
echo "::error::Invalid Node REPL package version $NODE_REPL_VERSION"
102+
exit 1
103+
fi
104+
85105
if [[ "${{ github.event_name }}" == "workflow_dispatch" && "${{ inputs.dry_run }}" != "true" && "$GITHUB_REF" != "refs/heads/main" ]]; then
86106
echo "::error::A production dispatch must run from protected main"
87107
exit 1
88108
fi
89-
if [[ "${{ github.event_name }}" == "workflow_dispatch" && "${{ inputs.dry_run }}" != "true" && "${{ inputs.notarize }}" != "true" ]]; then
109+
if [[ "${{ github.event_name }}" == "workflow_dispatch" && "${{ inputs.dry_run }}" != "true" && "${{ inputs.node_repl_only }}" != "true" && "${{ inputs.notarize }}" != "true" ]]; then
90110
echo "::error::A production dispatch must enable macOS codesigning and notarization"
91111
exit 1
92112
fi
@@ -98,8 +118,15 @@ jobs:
98118
fi
99119
fi
100120
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
121+
echo "node_repl_version=$NODE_REPL_VERSION" >> "$GITHUB_OUTPUT"
101122
- uses: 'dtolnay/rust-toolchain@1.97.1'
123+
if:
124+
"github.event_name != 'workflow_dispatch' || inputs.node_repl_only ==
125+
false"
102126
- name: 'Test model payload filtering'
127+
if:
128+
"github.event_name != 'workflow_dispatch' || inputs.node_repl_only ==
129+
false"
103130
working-directory: 'packages/cua-driver/rust'
104131
run: 'cargo test -p cua-driver-core --locked model_payload'
105132

@@ -110,6 +137,8 @@ jobs:
110137
build-linux:
111138
name: 'linux-${{ matrix.arch }}'
112139
needs: ['validate-version']
140+
if: "github.event_name != 'workflow_dispatch' || inputs.node_repl_only ==
141+
false"
113142
runs-on: '${{ matrix.runner }}'
114143
strategy:
115144
fail-fast: false
@@ -200,6 +229,8 @@ jobs:
200229
build-windows:
201230
name: 'windows-${{ matrix.arch }}'
202231
needs: ['validate-version']
232+
if: "github.event_name != 'workflow_dispatch' || inputs.node_repl_only ==
233+
false"
203234
runs-on: 'windows-latest'
204235
strategy:
205236
fail-fast: false
@@ -279,6 +310,8 @@ jobs:
279310
build-macos:
280311
name: 'macos-universal'
281312
needs: ['validate-version']
313+
if: "github.event_name != 'workflow_dispatch' || inputs.node_repl_only ==
314+
false"
282315
runs-on: 'macos-26'
283316
env:
284317
# Sign+notarize on tag push (real release); on manual dispatch honor the
@@ -513,7 +546,7 @@ jobs:
513546
done
514547
515548
verify-sdk-package:
516-
name: 'single npm package dry-run'
549+
name: '@qwen-code/cua-sdk package dry-run'
517550
needs: ['validate-version', 'build-linux', 'verify-release-artifacts']
518551
runs-on: 'ubuntu-latest'
519552
permissions:
@@ -578,6 +611,46 @@ jobs:
578611
if-no-files-found: 'error'
579612
retention-days: 7
580613

614+
verify-node-repl-package:
615+
name: '@qwen-code/node-repl-mcp package dry-run'
616+
needs: ['validate-version']
617+
runs-on: 'ubuntu-latest'
618+
permissions:
619+
contents: 'read'
620+
steps:
621+
- uses: 'actions/checkout@v4'
622+
- uses: 'actions/setup-node@v4'
623+
with:
624+
node-version: '22'
625+
cache: 'npm'
626+
cache-dependency-path: 'package-lock.json'
627+
registry-url: 'https://registry.npmjs.org'
628+
scope: '@qwen-code'
629+
- name: 'Install npm 11'
630+
run: 'npm install --global npm@11.19.0'
631+
- name: 'Install workspace dependencies'
632+
run: 'npm ci --ignore-scripts --no-audit --no-fund --progress=false'
633+
- name: 'Test standalone Node REPL package'
634+
working-directory: 'packages/node-repl'
635+
run: |
636+
npm run build
637+
npm run typecheck
638+
npm test
639+
npm run smoke
640+
npm run smoke:mcp
641+
npm run smoke:lifecycle
642+
- name: 'Pack, publish-dry-run, and clean-install Node REPL tarball'
643+
run: |
644+
node packages/node-repl/scripts/verify-package.mjs \
645+
--output-dir "${RUNNER_TEMP}/node-repl-package"
646+
- uses: 'actions/upload-artifact@v4'
647+
with:
648+
name: 'node-repl-mcp-npm-${{
649+
needs.validate-version.outputs.node_repl_version }}'
650+
path: '${{ runner.temp }}/node-repl-package/*.tgz'
651+
if-no-files-found: 'error'
652+
retention-days: 7
653+
581654
# ── Release ──────────────────────────────────────────────────────────────
582655
release:
583656
name: 'Create GitHub Release'
@@ -588,13 +661,15 @@ jobs:
588661
'build-macos',
589662
'verify-release-artifacts',
590663
'verify-sdk-package',
664+
'verify-node-repl-package',
591665
]
592666
runs-on: 'ubuntu-latest'
593667
outputs:
594668
version: '${{ steps.version.outputs.version }}'
595669
if:
596670
"startsWith(github.ref, 'refs/tags/cua-driver-rs-v') || (github.event_name
597-
== 'workflow_dispatch' && inputs.dry_run == false)"
671+
== 'workflow_dispatch' && inputs.dry_run == false &&
672+
inputs.node_repl_only == false)"
598673
steps:
599674
- uses: 'actions/checkout@v4'
600675
- uses: 'actions/download-artifact@v4'
@@ -691,9 +766,10 @@ jobs:
691766
- **macOS**: codesigned + notarized universal binary + `QwenCuaDriver.app`
692767
- **Linux**: unsigned (x86_64 + arm64, glibc 2.31 floor)
693768
- **Windows**: unsigned (x86_64 + arm64)
694-
- **Node.js**: the same workflow publishes the single
695-
`@qwen-code/cua-sdk` npm package after a clean install against
696-
these release assets
769+
- **Node.js**: the same workflow publishes `@qwen-code/cua-sdk`
770+
after a clean install against these release assets and publishes
771+
the independently versioned `@qwen-code/node-repl-mcp` package
772+
after its MCP protocol smoke tests
697773
698774
Enable relative coordinates: `CUA_DRIVER_RS_COORDINATE_SPACE=1`
699775
(default `0` = off; optional `CUA_DRIVER_RS_COORDINATE_SCALE=1000`).
@@ -706,7 +782,8 @@ jobs:
706782
needs: ['validate-version', 'verify-sdk-package', 'release']
707783
if:
708784
"startsWith(github.ref, 'refs/tags/cua-driver-rs-v') || (github.event_name
709-
== 'workflow_dispatch' && inputs.dry_run == false)"
785+
== 'workflow_dispatch' && inputs.dry_run == false &&
786+
inputs.node_repl_only == false)"
710787
runs-on: 'ubuntu-latest'
711788
environment:
712789
name: 'production-release'
@@ -827,9 +904,93 @@ jobs:
827904
echo '::error::Published npm version did not become visible'
828905
exit 1
829906
907+
publish-node-repl:
908+
name: 'Publish @qwen-code/node-repl-mcp'
909+
needs: ['validate-version', 'verify-node-repl-package', 'release']
910+
if: "always() && needs.validate-version.result == 'success' &&
911+
needs.verify-node-repl-package.result == 'success' &&
912+
(needs.release.result == 'success' || (github.event_name ==
913+
'workflow_dispatch' && inputs.node_repl_only == true)) &&
914+
(startsWith(github.ref, 'refs/tags/cua-driver-rs-v') ||
915+
(github.event_name == 'workflow_dispatch' && inputs.dry_run == false))"
916+
runs-on: 'ubuntu-latest'
917+
environment:
918+
name: 'production-release'
919+
url: 'https://www.npmjs.com/package/@qwen-code/node-repl-mcp/v/${{
920+
needs.validate-version.outputs.node_repl_version }}'
921+
permissions:
922+
contents: 'read'
923+
id-token: 'write'
924+
steps:
925+
- uses: 'actions/setup-node@v4'
926+
with:
927+
node-version: '22'
928+
registry-url: 'https://registry.npmjs.org'
929+
scope: '@qwen-code'
930+
- name: 'Install npm 11'
931+
run: 'npm install --global npm@11.19.0'
932+
- uses: 'actions/download-artifact@v4'
933+
with:
934+
name: 'node-repl-mcp-npm-${{
935+
needs.validate-version.outputs.node_repl_version }}'
936+
path: '${{ runner.temp }}/node-repl-package'
937+
- name: 'Require npm publishing token'
938+
env:
939+
NODE_AUTH_TOKEN: '${{ secrets.NPM_TOKEN }}'
940+
run: |
941+
if [[ -z "$NODE_AUTH_TOKEN" ]]; then
942+
echo '::error::production-release NPM_TOKEN is required for the first @qwen-code/node-repl-mcp publication'
943+
exit 1
944+
fi
945+
- name: 'Publish immutable Node REPL tarball'
946+
env:
947+
NODE_AUTH_TOKEN: '${{ secrets.NPM_TOKEN }}'
948+
VERSION: '${{ needs.validate-version.outputs.node_repl_version }}'
949+
run: |
950+
set -euo pipefail
951+
TARBALL=$(find "${RUNNER_TEMP}/node-repl-package" -type f -name '*.tgz' -print -quit)
952+
if [[ -z "$TARBALL" ]]; then
953+
echo '::error::Packed @qwen-code/node-repl-mcp tarball is missing'
954+
exit 1
955+
fi
956+
LOCAL_INTEGRITY="sha512-$(openssl dgst -sha512 -binary "$TARBALL" | openssl base64 -A)"
957+
REMOTE_INTEGRITY=$(npm view "@qwen-code/node-repl-mcp@${VERSION}" dist.integrity 2>/dev/null || true)
958+
if [[ -n "$REMOTE_INTEGRITY" ]]; then
959+
if [[ "$REMOTE_INTEGRITY" != "$LOCAL_INTEGRITY" ]]; then
960+
echo "::error::@qwen-code/node-repl-mcp@${VERSION} already exists with different integrity"
961+
exit 1
962+
fi
963+
echo "@qwen-code/node-repl-mcp@${VERSION} already contains this exact tarball"
964+
exit 0
965+
fi
966+
NPM_TAG=latest
967+
[[ "$VERSION" == *-* ]] && NPM_TAG=next
968+
npm publish "$TARBALL" --provenance --access public --tag "$NPM_TAG"
969+
- name: 'Verify npm registry integrity'
970+
env:
971+
VERSION: '${{ needs.validate-version.outputs.node_repl_version }}'
972+
run: |
973+
set -euo pipefail
974+
TARBALL=$(find "${RUNNER_TEMP}/node-repl-package" -type f -name '*.tgz' -print -quit)
975+
LOCAL_INTEGRITY="sha512-$(openssl dgst -sha512 -binary "$TARBALL" | openssl base64 -A)"
976+
for attempt in {1..20}; do
977+
REMOTE_INTEGRITY=$(npm view "@qwen-code/node-repl-mcp@${VERSION}" dist.integrity 2>/dev/null || true)
978+
if [[ "$REMOTE_INTEGRITY" == "$LOCAL_INTEGRITY" ]]; then
979+
echo "Verified npm registry integrity on attempt $attempt"
980+
exit 0
981+
fi
982+
if [[ -n "$REMOTE_INTEGRITY" ]]; then
983+
echo '::error::Published npm artifact integrity does not match the verified tarball'
984+
exit 1
985+
fi
986+
sleep 10
987+
done
988+
echo '::error::Published npm version did not become visible'
989+
exit 1
990+
830991
sync-installer-version:
831992
name: 'Sync installer version to main'
832-
needs: ['release', 'publish-sdk']
993+
needs: ['release', 'publish-sdk', 'publish-node-repl']
833994
runs-on: 'ubuntu-latest'
834995
permissions:
835996
contents: 'write'

0 commit comments

Comments
 (0)