/* eslint-env node */ const fs = require("fs") const path = require("path") const { execSync } = require("child_process") const readline = require("readline") const PACKAGE_NAME = "@roo-code/types" const BRANCH_NAME = "roo-code-types-v" const rootDir = path.join(__dirname, "..") const npmDir = path.join(rootDir, "npm") const monorepoPackagePath = path.join(rootDir, "package.json") const npmMetadataPath = path.join(npmDir, "package.metadata.json") const npmPackagePath = path.join(npmDir, "package.json") const args = process.argv.slice(2) const publishOnly = args.includes("--publish-only") async function confirmPublish() { const rl = readline.createInterface({ input: process.stdin, output: process.stdout, }) return new Promise((resolve) => { rl.question("\n⚠️ Are you sure you want to publish to npm? (y/n): ", (answer) => { rl.close() resolve(answer.toLowerCase() === "y") }) }) } function updatePackageVersion(filePath, version) { try { const packageContent = JSON.parse(fs.readFileSync(filePath, "utf8")) const oldVersion = packageContent.version packageContent.version = version fs.writeFileSync(filePath, JSON.stringify(packageContent, null, 2) + "\n") try { execSync(`npx prettier --write "${filePath}"`, { stdio: "pipe" }) console.log(`✨ Formatted ${path.basename(filePath)} with prettier`) } catch (prettierError) { console.warn(`⚠️ Could not format with prettier:`, prettierError.message) } const fileName = path.basename(filePath) console.log(`✅ Updated ${fileName} version: ${oldVersion} → ${version}`) return oldVersion } catch (error) { throw new Error(`Failed to update version in ${path.basename(filePath)}: ${error.message}`) } } function syncVersionToMetadata(version) { console.log(" 📝 Syncing version to package.metadata.json...") updatePackageVersion(npmMetadataPath, version) } function commitVersionChanges(version) { try { console.log(" 📝 Committing version changes to git...") try { const status = execSync("git status --porcelain", { encoding: "utf8" }) const relevantChanges = status.split("\n").filter((line) => line.includes("packages/types/npm/package")) if (relevantChanges.length === 0) { console.log(" ⚠️ No version changes to commit") return } } catch (error) { console.warn(" ⚠️ Could not check git status:", error.message) } execSync("git add .", { stdio: "pipe" }) const commitMessage = `chore: bump version to v${version}` execSync(`git commit -m "${commitMessage}"`, { stdio: "pipe" }) console.log(` ✅ Committed: ${commitMessage}`) } catch (error) { console.warn(" ⚠️ Could not commit version changes:", error.message) console.log(" You may need to commit these changes manually.") } } function checkGitHubCLI() { try { execSync("gh --version", { stdio: "pipe" }) execSync("gh auth status", { stdio: "pipe" }) return true } catch (_error) { return false } } function createPullRequest(branchName, baseBranch, version) { try { console.log(` 🔄 Creating pull request...`) if (!checkGitHubCLI()) { console.warn(" ⚠️ GitHub CLI not found or not authenticated") console.log(" Install gh CLI and run: gh auth login") console.log(" Then manually create PR with: gh pr create") return } const title = `Release: v${version}` const body = `## 🚀 Release v${version} This PR contains the version bump for the SDK release v${version}. ### Changes - Bumped version from previous to v${version} - Published to npm as ${PACKAGE_NAME}@${version} ### Checklist - [x] Version bumped - [x] Package published to npm - [ ] Changelog updated (if applicable) - [ ] Documentation updated (if applicable) --- *This PR was automatically created by the npm publish script.*` try { // Create the pull request const prUrl = execSync( `gh pr create --base "${baseBranch}" --head "${branchName}" --title "${title}" --body "${body}"`, { encoding: "utf8", stdio: "pipe" }, ).trim() console.log(` ✅ Pull request created: ${prUrl}`) } catch (error) { if (error.message.includes("already exists")) { console.log(" ℹ️ Pull request already exists for this branch") } else { throw error } } } catch (error) { console.error(" ❌ Failed to create pull request:", error.message) console.log(" You can manually create a PR with:") console.log(` gh pr create --base "${baseBranch}" --head "${branchName}"`) } } function createVersionBranchAndCommit(version) { try { const branchName = `${BRANCH_NAME}${version}` console.log(` 🌿 Creating version branch: ${branchName}...`) let currentBranch try { currentBranch = execSync("git rev-parse --abbrev-ref HEAD", { encoding: "utf8", }).trim() } catch (_error) { console.warn(" ⚠️ Could not determine current branch") currentBranch = "main" } execSync(`git checkout -b ${branchName}`, { stdio: "pipe" }) console.log(` ✅ Created branch: ${branchName}`) commitVersionChanges(version) execSync(`git push --set-upstream origin ${branchName}`, { stdio: "pipe" }) console.log(` ✅ Pushed branch to origin with upstream tracking`) createPullRequest(branchName, currentBranch, version) if (currentBranch) { execSync(`git checkout ${currentBranch}`, { stdio: "pipe" }) console.log(` ✅ Returned to branch: ${currentBranch}`) } console.log(` 🎯 Version branch created with commits: ${branchName}`) } catch (error) { console.error(" ❌ Failed to create version branch:", error.message) console.log(" You may need to create the branch manually.") } } function generateNpmPackage() { try { console.log(" 📖 Reading monorepo package.json...") const monorepoPackageContent = fs.readFileSync(monorepoPackagePath, "utf8") const monorepoPackage = JSON.parse(monorepoPackageContent) console.log(" 📖 Reading npm package metadata...") const npmMetadataContent = fs.readFileSync(npmMetadataPath, "utf8") const npmMetadata = JSON.parse(npmMetadataContent) console.log(" 🔨 Generating npm package.json...") const npmPackage = { ...npmMetadata, dependencies: monorepoPackage.dependencies || {}, main: "./dist/index.cjs", module: "./dist/index.js", types: "./dist/index.d.ts", exports: { ".": { types: "./dist/index.d.ts", import: "./dist/index.js", require: { types: "./dist/index.d.cts", default: "./dist/index.cjs", }, }, }, files: ["dist"], } const outputContent = JSON.stringify(npmPackage, null, 2) + "\n" fs.writeFileSync(npmPackagePath, outputContent) console.log(" ✅ npm/package.json generated successfully") console.log(` 📦 Package name: ${npmPackage.name}`) console.log(` 📌 Version: ${npmPackage.version}`) console.log(` 📚 Dependencies: ${Object.keys(npmPackage.dependencies).length}`) } catch (error) { throw new Error(`Failed to generate npm package.json: ${error.message}`) } } async function publish() { try { console.log("\n🚀 NPM PUBLISH WORKFLOW") if (publishOnly) { console.log("📌 Mode: Publish only (no git operations)") } console.log("=".repeat(60)) console.log("\n📦 Step 1: Generating npm package.json...") generateNpmPackage() const npmPackage = JSON.parse(fs.readFileSync(npmPackagePath, "utf8")) const originalVersion = npmPackage.version // Save original version console.log(`\n📌 Current version: ${npmPackage.version}`) console.log(`📦 Package name: ${npmPackage.name}`) console.log("\n📈 Step 2: Bumping version (minor)...") try { execSync("npm version minor --no-git-tag-version", { cwd: npmDir, stdio: "inherit", }) } catch (error) { console.error("❌ Failed to bump version:", error.message) throw error } const updatedPackage = JSON.parse(fs.readFileSync(npmPackagePath, "utf8")) console.log(`✅ New version: ${updatedPackage.version}`) console.log("\n🔨 Step 3: Building production bundle...") console.log(" This may take a moment...") try { execSync("NODE_ENV=production pnpm tsup --outDir npm/dist", { cwd: rootDir, stdio: "inherit", }) console.log("✅ Production build complete") } catch (error) { console.error("❌ Build failed:", error.message) throw error } console.log("\n" + "=".repeat(60)) console.log("📋 PUBLISH SUMMARY:") console.log(` Package: ${updatedPackage.name}`) console.log(` Version: ${updatedPackage.version}`) console.log(` Registry: ${updatedPackage.publishConfig?.registry || "https://registry.npmjs.org/"}`) console.log(` Access: ${updatedPackage.publishConfig?.access || "public"}`) console.log("=".repeat(60)) const confirmed = await confirmPublish() if (!confirmed) { console.log("\n❌ Publishing cancelled by user") console.log("🔙 Reverting version change...") try { updatePackageVersion(npmPackagePath, originalVersion) } catch (revertError) { console.error("⚠️ Could not revert version:", revertError.message) console.log(` You may need to manually change version back to ${originalVersion}`) } process.exit(0) } console.log("\n💾 Step 4: Syncing version to metadata...") syncVersionToMetadata(updatedPackage.version) console.log("\n🚀 Step 5: Publishing to npm...") try { execSync("npm publish", { cwd: npmDir, stdio: "inherit", }) } catch (error) { console.error("❌ Publish failed:", error.message) console.error("💡 The package was built but not published.") console.error(" You can try publishing manually from the npm directory.") throw error } if (!publishOnly) { console.log("\n🌿 Step 6: Creating version branch, committing, and opening PR...") createVersionBranchAndCommit(updatedPackage.version) } else { console.log("\n📝 Step 6: Skipping version branch creation (--publish-only mode)") } console.log("\n" + "=".repeat(60)) console.log("✅ Successfully published to npm!") console.log(`🎉 ${updatedPackage.name}@${updatedPackage.version} is now live`) console.log(`📦 View at: https://www.npmjs.com/package/${updatedPackage.name}`) if (!publishOnly) { console.log(`🌿 Version branch: ${BRANCH_NAME}${updatedPackage.version}`) } console.log("=".repeat(60) + "\n") } catch (error) { console.error("\n❌ Error during publish process:", error.message) console.error("\n💡 Troubleshooting tips:") console.error(" 1. Ensure you are logged in to npm: npm whoami") console.error(" 2. Check your npm permissions for this package") console.error(" 3. Verify the package name is not already taken") console.error(" 4. Make sure all dependencies are installed: pnpm install") process.exit(1) } } async function main() { await publish() } main().catch((error) => { console.error("Unexpected error:", error) process.exit(1) })