/** * @license * Copyright 2025 Google LLC * SPDX-License-Identifier: Apache-2.0 */ import { execSync } from 'node:child_process'; import { existsSync, readFileSync, readdirSync, writeFileSync } from 'node:fs'; import { join, resolve } from 'node:path'; import { keepManifestLayout } from './keep-manifest-layout.js'; import { INDEPENDENT_PACKAGES } from './release-packages.mjs'; import { getWorkspacePackageJsonPaths } from './workspaces.js'; // A script to handle versioning and ensure all related changes are in a single, atomic commit. function run(command) { console.log(`> ${command}`); execSync(command, { stdio: 'inherit' }); } function readJson(filePath) { return JSON.parse(readFileSync(filePath, 'utf-8')); } function writeJson(filePath, data) { writeFileSync(filePath, JSON.stringify(data, null, 2) + '\n'); } // 1. Get the version from the command line arguments. const versionType = process.argv[2]; if (!versionType) { console.error('Error: No version specified.'); console.error( 'Usage: npm run version (e.g., 1.2.3 or patch|minor|major|prerelease)', ); process.exit(1); } // `pnpm version` re-sorts every manifest it rewrites; snapshot them so the // bump below can be reduced to a version change (see keep-manifest-layout.js). // Enumerate with the workspace globs rather than `git ls-files`: like the // `--no-git-checks` flags below, this script must not require a git work tree. const { workspaces } = readJson('package.json'); const snapshotPaths = [ 'package.json', ...getWorkspacePackageJsonPaths(process.cwd(), workspaces), ]; const originalManifests = new Map( snapshotPaths.map((file) => [file, readFileSync(file, 'utf-8')]), ); // Resolve patch/minor/etc. once, then align all release workspaces to it. run( `corepack pnpm version ${versionType} --no-git-tag-version --allow-same-version --no-git-checks`, ); const rootPackageJsonPath = resolve(process.cwd(), 'package.json'); const newVersion = readJson(rootPackageJsonPath).version; run( `corepack pnpm -r ${INDEPENDENT_PACKAGES.map((name) => `--filter="!${name}"`).join(' ')} version ${newVersion} --no-git-tag-version --allow-same-version --no-git-checks`, ); for (const [file, original] of originalManifests) { const updated = readFileSync(file, 'utf-8'); if (updated !== original) { writeFileSync(file, keepManifestLayout(original, updated)); } } // 5. Keep the published Mem0 Extension manifest aligned with its package. const mem0ManifestPath = resolve( process.cwd(), 'integrations/external-context-mem0/qwen-extension.json', ); const mem0Manifest = readJson(mem0ManifestPath); mem0Manifest.version = newVersion; writeJson(mem0ManifestPath, mem0Manifest); run( 'npx prettier --experimental-cli --write integrations/external-context-mem0/qwen-extension.json', ); // 6. Update the sandboxImageUri in the root package.json const rootPackageJson = readJson(rootPackageJsonPath); if (rootPackageJson.config?.sandboxImageUri) { rootPackageJson.config.sandboxImageUri = rootPackageJson.config.sandboxImageUri.replace(/:.*$/, `:${newVersion}`); console.log(`Updated sandboxImageUri in root to use version ${newVersion}`); writeJson(rootPackageJsonPath, rootPackageJson); } // 7. Update the sandboxImageUri in the cli package.json const cliPackageJsonPath = resolve(process.cwd(), 'packages/cli/package.json'); const cliPackageJson = readJson(cliPackageJsonPath); if (cliPackageJson.config?.sandboxImageUri) { cliPackageJson.config.sandboxImageUri = cliPackageJson.config.sandboxImageUri.replace(/:.*$/, `:${newVersion}`); console.log( `Updated sandboxImageUri in cli package to use version ${newVersion}`, ); writeJson(cliPackageJsonPath, cliPackageJson); } // 8. Pin channel adapters' semver dependency on @qwen-code/channel-base to // the exact new version. A caret range like ^0.21.0 does not match a // prerelease bump (e.g. 0.21.1-preview.0), so npm would replace the workspace // link with the stale registry package and the release build would compile // against outdated types. const channelsDir = resolve(process.cwd(), 'packages/channels'); for (const entry of readdirSync(channelsDir)) { const pkgPath = join(channelsDir, entry, 'package.json'); if (!existsSync(pkgPath)) continue; const pkg = readJson(pkgPath); const dep = pkg.dependencies?.['@qwen-code/channel-base']; if (dep && !dep.startsWith('file:')) { pkg.dependencies['@qwen-code/channel-base'] = newVersion; writeJson(pkgPath, pkg); console.log( `Pinned @qwen-code/channel-base to ${newVersion} in ${pkg.name}`, ); } } console.log(`Successfully bumped versions to v${newVersion}.`);