From 5cc2c27e7b0cb978dd913728e4156f1ec79543c1 Mon Sep 17 00:00:00 2001 From: Gen Zhang Date: Sun, 15 Feb 2026 19:53:22 +0000 Subject: [PATCH] feat(release): ship esbuild bundle in npm package The npm registry publish path ships unbundled dist/ plus full node_modules/ (44,835 files), causing ~1-2 minute cold starts on Windows due to Defender real-time scanning. The GitHub registry path already ships a single-file bundle with zero dependencies. Apply the same bundle transformation to the npm publish path: - Add scripts/prepare-npm-release.js that rewrites the CLI package.json to ship bundle/ instead of dist/, removes all dependencies, and adds optionalDependencies for native modules (node-pty, keytar) so platform-specific features keep working. - Add a "Prepare bundled CLI for npm release" step in the publish action, conditioned on non-GitHub registry URLs. Result: npm package drops from 44,835 files to ~129 files (6.8 MB). Closes #19169 --- .github/actions/publish-release/action.yml | 7 ++ scripts/prepare-npm-release.js | 84 ++++++++++++++++++++++ 2 files changed, 91 insertions(+) create mode 100644 scripts/prepare-npm-release.js diff --git a/.github/actions/publish-release/action.yml b/.github/actions/publish-release/action.yml index 5c74524ddb..9ee9fd5e9a 100644 --- a/.github/actions/publish-release/action.yml +++ b/.github/actions/publish-release/action.yml @@ -181,6 +181,13 @@ runs: --workspace="${{ inputs.a2a-package-name }}" \ --save-exact + - name: '📦 Prepare bundled CLI for npm release' + if: "inputs.npm-registry-url != 'https://npm.pkg.github.com/'" + working-directory: '${{ inputs.working-directory }}' + shell: 'bash' + run: | + node ${{ github.workspace }}/scripts/prepare-npm-release.js + - name: 'Get CLI Token' uses: './.github/actions/npm-auth-token' id: 'cli-token' diff --git a/scripts/prepare-npm-release.js b/scripts/prepare-npm-release.js new file mode 100644 index 0000000000..3ce6e03481 --- /dev/null +++ b/scripts/prepare-npm-release.js @@ -0,0 +1,84 @@ +/** + * @license + * Copyright 2025 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import fs from 'node:fs'; +import path from 'node:path'; + +const rootDir = process.cwd(); + +function readJson(filePath) { + return JSON.parse(fs.readFileSync(path.resolve(rootDir, filePath), 'utf-8')); +} + +function writeJson(filePath, data) { + fs.writeFileSync( + path.resolve(rootDir, filePath), + JSON.stringify(data, null, 2), + ); +} + +// Copy bundle directory into packages/cli +const sourceBundleDir = path.resolve(rootDir, 'bundle'); +const destBundleDir = path.resolve(rootDir, 'packages/cli/bundle'); + +if (fs.existsSync(sourceBundleDir)) { + fs.rmSync(destBundleDir, { recursive: true, force: true }); + fs.cpSync(sourceBundleDir, destBundleDir, { recursive: true }); + console.log('Copied bundle/ directory to packages/cli/'); +} else { + console.error( + 'Error: bundle/ directory not found at project root. Please run `npm run bundle` first.', + ); + process.exit(1); +} + +// Read native module versions from root package.json +const rootPkg = readJson('package.json'); +const rootOptional = rootPkg.optionalDependencies || {}; + +const nativeModules = [ + '@lydell/node-pty', + '@lydell/node-pty-darwin-arm64', + '@lydell/node-pty-darwin-x64', + '@lydell/node-pty-linux-x64', + '@lydell/node-pty-win32-arm64', + '@lydell/node-pty-win32-x64', + 'keytar', + 'node-pty', +]; + +const optionalDependencies = {}; +for (const mod of nativeModules) { + if (rootOptional[mod]) { + optionalDependencies[mod] = rootOptional[mod]; + } +} + +// Update @google/gemini-cli package.json for bundled npm release +const cliPkgPath = 'packages/cli/package.json'; +const cliPkg = readJson(cliPkgPath); + +cliPkg.files = ['bundle/']; +cliPkg.bin = { + gemini: 'bundle/gemini.js', +}; + +delete cliPkg.dependencies; +delete cliPkg.devDependencies; +delete cliPkg.scripts; +delete cliPkg.main; +delete cliPkg.config; + +cliPkg.optionalDependencies = optionalDependencies; + +writeJson(cliPkgPath, cliPkg); + +console.log('Updated packages/cli/package.json for bundled npm release.'); +console.log( + 'optionalDependencies:', + JSON.stringify(optionalDependencies, null, 2), +); +console.log('Successfully prepared packages for npm release.');