From c56b95bc6097715e1cbb6d0dffe297021f010c83 Mon Sep 17 00:00:00 2001 From: Chris Estreich Date: Thu, 14 Aug 2025 00:14:17 -1000 Subject: [PATCH] Task metadata (#7092) --- package.json | 10 +- packages/types/.gitignore | 2 + packages/types/eslint.config.mjs | 18 +- .../{package.json => package.metadata.json} | 28 +- packages/types/package.json | 8 +- packages/types/scripts/publish-npm.cjs | 351 ++++++++++++++++++ packages/types/src/task.ts | 11 + packages/types/tsconfig.json | 2 +- pnpm-lock.yaml | 187 +++++++--- scripts/link-packages.js | 158 -------- scripts/link-packages.ts | 340 +++++++++++++++++ src/core/task/Task.ts | 19 +- src/core/webview/ClineProvider.ts | 51 +-- src/extension.ts | 8 +- src/package.json | 3 +- tsconfig.json | 8 + 16 files changed, 912 insertions(+), 292 deletions(-) create mode 100644 packages/types/.gitignore rename packages/types/npm/{package.json => package.metadata.json} (52%) create mode 100644 packages/types/scripts/publish-npm.cjs delete mode 100755 scripts/link-packages.js create mode 100644 scripts/link-packages.ts create mode 100644 tsconfig.json diff --git a/package.json b/package.json index c1ddc68223..cdc8a1abca 100644 --- a/package.json +++ b/package.json @@ -24,15 +24,20 @@ "knip": "knip --include files", "update-contributors": "node scripts/update-contributors.js", "evals": "dotenvx run -f packages/evals/.env.development packages/evals/.env.local -- docker compose -f packages/evals/docker-compose.yml --profile server --profile runner up --build --scale runner=0", - "link-workspace-packages": "node scripts/link-packages.js", - "unlink-workspace-packages": "node scripts/link-packages.js --unlink" + "npm:publish:types": "pnpm --filter @roo-code/types npm:publish", + "link-workspace-packages": "tsx scripts/link-packages.ts", + "unlink-workspace-packages": "tsx scripts/link-packages.ts --unlink" }, "devDependencies": { "@changesets/cli": "^2.27.10", "@dotenvx/dotenvx": "^1.34.0", + "@roo-code/config-typescript": "workspace:^", + "@types/glob": "^9.0.0", + "@types/node": "^24.1.0", "@vscode/vsce": "3.3.2", "esbuild": "^0.25.0", "eslint": "^9.27.0", + "glob": "^11.0.3", "husky": "^9.1.7", "knip": "^5.44.4", "lint-staged": "^16.0.0", @@ -41,6 +46,7 @@ "ovsx": "0.10.4", "prettier": "^3.4.2", "rimraf": "^6.0.1", + "tsx": "^4.19.3", "turbo": "^2.5.3", "typescript": "^5.4.5" }, diff --git a/packages/types/.gitignore b/packages/types/.gitignore new file mode 100644 index 0000000000..ddf5f39ede --- /dev/null +++ b/packages/types/.gitignore @@ -0,0 +1,2 @@ +dist +npm/package.json diff --git a/packages/types/eslint.config.mjs b/packages/types/eslint.config.mjs index 694bf73664..c603a68f12 100644 --- a/packages/types/eslint.config.mjs +++ b/packages/types/eslint.config.mjs @@ -1,4 +1,20 @@ import { config } from "@roo-code/config-eslint/base" +import globals from "globals" /** @type {import("eslint").Linter.Config} */ -export default [...config] +export default [ + ...config, + { + files: ["**/*.cjs"], + languageOptions: { + globals: { + ...globals.node, + ...globals.commonjs, + }, + sourceType: "commonjs", + }, + rules: { + "@typescript-eslint/no-require-imports": "off", + }, + }, +] diff --git a/packages/types/npm/package.json b/packages/types/npm/package.metadata.json similarity index 52% rename from packages/types/npm/package.json rename to packages/types/npm/package.metadata.json index b2be718cf6..391d2acbaa 100644 --- a/packages/types/npm/package.json +++ b/packages/types/npm/package.metadata.json @@ -1,6 +1,6 @@ { "name": "@roo-code/types", - "version": "1.46.0", + "version": "1.48.0", "description": "TypeScript type definitions for Roo Code.", "publishConfig": { "access": "public", @@ -17,28 +17,6 @@ "url": "https://github.com/RooCodeInc/Roo-Code/issues" }, "homepage": "https://roocode.com", - "keywords": [ - "roo", - "roo-code", - "ai" - ], - "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" - ], - "dependencies": { - "zod": "^3.25.61" - } + "keywords": ["roo", "roo-code", "ai"], + "files": ["dist"] } diff --git a/packages/types/package.json b/packages/types/package.json index feda97f289..44fde30b59 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -18,8 +18,9 @@ "check-types": "tsc --noEmit", "test": "vitest run", "build": "tsup", - "npm:publish": "cd npm && npm version minor && cd - && tsup --outDir npm/dist && cd npm && npm publish", - "clean": "rimraf dist npm/dist .turbo" + "build:watch": "tsup --watch --outDir npm/dist --onSuccess 'echo ✅ Types rebuilt to npm/dist'", + "npm:publish": "node scripts/publish-npm.cjs", + "clean": "rimraf dist .turbo" }, "dependencies": { "zod": "^3.25.61" @@ -27,7 +28,8 @@ "devDependencies": { "@roo-code/config-eslint": "workspace:^", "@roo-code/config-typescript": "workspace:^", - "@types/node": "20.x", + "@types/node": "^24.1.0", + "globals": "^16.3.0", "tsup": "^8.3.5", "vitest": "^3.2.3" } diff --git a/packages/types/scripts/publish-npm.cjs b/packages/types/scripts/publish-npm.cjs new file mode 100644 index 0000000000..a82308fdfa --- /dev/null +++ b/packages/types/scripts/publish-npm.cjs @@ -0,0 +1,351 @@ +/* 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/sdk/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) +}) diff --git a/packages/types/src/task.ts b/packages/types/src/task.ts index a4a2f5f0fc..4fe74c6cd4 100644 --- a/packages/types/src/task.ts +++ b/packages/types/src/task.ts @@ -1,3 +1,5 @@ +import { z } from "zod" + import { RooCodeEventName } from "./events.js" import { type ClineMessage, type BlockingAsk, type TokenUsage } from "./message.js" import { type ToolUsage, type ToolName } from "./tool.js" @@ -61,10 +63,19 @@ export type TaskProviderEvents = { * TaskLike */ +export const taskMetadataSchema = z.object({ + taskId: z.string(), + task: z.string().optional(), + images: z.array(z.string()).optional(), +}) + +export type TaskMetadata = z.infer + export interface TaskLike { readonly taskId: string readonly rootTask?: TaskLike readonly blockingAsk?: BlockingAsk + readonly metadata: TaskMetadata on(event: K, listener: (...args: TaskEvents[K]) => void | Promise): this off(event: K, listener: (...args: TaskEvents[K]) => void | Promise): this diff --git a/packages/types/tsconfig.json b/packages/types/tsconfig.json index a66434e570..2a73ee92bb 100644 --- a/packages/types/tsconfig.json +++ b/packages/types/tsconfig.json @@ -4,6 +4,6 @@ "types": ["vitest/globals"], "outDir": "dist" }, - "include": ["src"], + "include": ["src", "scripts", "*.config.ts"], "exclude": ["node_modules"] } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index cc7fd4a06e..43b0cf2951 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -22,6 +22,15 @@ importers: '@dotenvx/dotenvx': specifier: ^1.34.0 version: 1.44.2 + '@roo-code/config-typescript': + specifier: workspace:^ + version: link:packages/config-typescript + '@types/glob': + specifier: ^9.0.0 + version: 9.0.0 + '@types/node': + specifier: ^24.1.0 + version: 24.2.1 '@vscode/vsce': specifier: 3.3.2 version: 3.3.2 @@ -31,12 +40,15 @@ importers: eslint: specifier: ^9.27.0 version: 9.28.0(jiti@2.4.2) + glob: + specifier: ^11.0.3 + version: 11.0.3 husky: specifier: ^9.1.7 version: 9.1.7 knip: specifier: ^5.44.4 - version: 5.60.2(@types/node@22.15.29)(typescript@5.8.3) + version: 5.60.2(@types/node@24.2.1)(typescript@5.8.3) lint-staged: specifier: ^16.0.0 version: 16.1.2 @@ -55,6 +67,9 @@ importers: rimraf: specifier: ^6.0.1 version: 6.0.1 + tsx: + specifier: ^4.19.3 + version: 4.19.4 turbo: specifier: ^2.5.3 version: 2.5.4 @@ -235,7 +250,7 @@ importers: version: 4.1.6 vitest: specifier: ^3.2.3 - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.15.29)(@vitest/ui@3.2.4)(jiti@2.4.2)(jsdom@26.1.0)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0) + version: 3.2.4(@types/debug@4.1.12)(@types/node@24.2.1)(@vitest/ui@3.2.4)(jiti@2.4.2)(jsdom@26.1.0)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0) apps/web-roo-code: dependencies: @@ -521,14 +536,17 @@ importers: specifier: workspace:^ version: link:../config-typescript '@types/node': - specifier: 20.x - version: 20.17.57 + specifier: ^24.1.0 + version: 24.2.1 + globals: + specifier: ^16.3.0 + version: 16.3.0 tsup: specifier: ^8.3.5 version: 8.5.0(jiti@2.4.2)(postcss@8.5.4)(tsx@4.19.4)(typescript@5.8.3)(yaml@2.8.0) vitest: specifier: ^3.2.3 - version: 3.2.4(@types/debug@4.1.12)(@types/node@20.17.57)(@vitest/ui@3.2.4)(jiti@2.4.2)(jsdom@26.1.0)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0) + version: 3.2.4(@types/debug@4.1.12)(@types/node@24.2.1)(@vitest/ui@3.2.4)(jiti@2.4.2)(jsdom@26.1.0)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0) src: dependencies: @@ -563,8 +581,8 @@ importers: specifier: ^1.14.0 version: 1.14.0(typescript@5.8.3) '@roo-code/cloud': - specifier: ^0.13.0 - version: 0.13.0 + specifier: ^0.14.0 + version: 0.14.0 '@roo-code/ipc': specifier: workspace:^ version: link:../packages/ipc @@ -703,6 +721,9 @@ importers: simple-git: specifier: ^3.27.0 version: 3.27.0 + socket.io-client: + specifier: ^4.8.1 + version: 4.8.1 sound-play: specifier: ^1.1.0 version: 1.1.0 @@ -1936,6 +1957,14 @@ packages: '@ioredis/commands@1.3.0': resolution: {integrity: sha512-M/T6Zewn7sDaBQEqIZ8Rb+i9y8qfGmq+5SDFSf9sA2lUZTmdDLVdOiQaeDp+Q4wElZ9HG1GAX5KhDaidp6LQsQ==} + '@isaacs/balanced-match@4.0.1': + resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==} + engines: {node: 20 || >=22} + + '@isaacs/brace-expansion@5.0.0': + resolution: {integrity: sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==} + engines: {node: 20 || >=22} + '@isaacs/cliui@8.0.2': resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} engines: {node: '>=12'} @@ -3065,11 +3094,11 @@ packages: cpu: [x64] os: [win32] - '@roo-code/cloud@0.13.0': - resolution: {integrity: sha512-pIrfMpuHSk3LPMG3SLmsfr/IYvL5x0k0iUXQ51dgZ2fP7TlzWg2erxclNl79O7pRMDYFnA/8YoQTAnv1N8VXnQ==} + '@roo-code/cloud@0.14.0': + resolution: {integrity: sha512-EKFw7sLSJcOpXQDjCMFL4EnE7OH3RhO00joteaysNYNpNe+js6kMFrBZY61rj1tZAXV/943RWeQptG4sSAfPFQ==} - '@roo-code/types@1.45.0': - resolution: {integrity: sha512-+rFJ9HcukDl59X9pI6lgZDtJHtKqHg6BIdS4LG759X+5MV7wvlNb4S+bQ3qKqIlBsQhH17bzIJCfsWZwjwxecw==} + '@roo-code/types@1.48.0': + resolution: {integrity: sha512-DJkA/310sLcs4vM4YLhJhc5A1JFYmdcOt+hRQMUPq+wF02yW9rc7ZZzHNDOOUZL+kk5naUd2nBRxLiJoh6o0Ng==} '@sec-ant/readable-stream@0.4.1': resolution: {integrity: sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==} @@ -3801,6 +3830,10 @@ packages: '@types/glob@8.1.0': resolution: {integrity: sha512-IO+MJPVhoqz+28h1qLAcBEH2+xHMK6MTyHJc7MTnnYb6wsoLR29POVGJ7LycmVXIqyy/4/2ShP5sUwTXuOwb/w==} + '@types/glob@9.0.0': + resolution: {integrity: sha512-00UxlRaIUvYm4R4W9WYkN8/J+kV8fmOQ7okeH6YFtGWFMt3odD45tpG5yA5wnL7HE6lLgjaTW5n14ju2hl2NNA==} + deprecated: This is a stub types definition. glob provides its own type definitions, so you do not need this installed. + '@types/hast@3.0.4': resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} @@ -3871,14 +3904,8 @@ packages: '@types/node@20.17.57': resolution: {integrity: sha512-f3T4y6VU4fVQDKVqJV4Uppy8c1p/sVvS3peyqxyWnzkqXFJLRU7Y1Bl7rMS1Qe9z0v4M6McY0Fp9yBsgHJUsWQ==} - '@types/node@20.19.1': - resolution: {integrity: sha512-jJD50LtlD2dodAEO653i3YF04NWak6jN3ky+Ri3Em3mGR39/glWiboM/IePaRbgwSfqM1TpGXfAg8ohn/4dTgA==} - - '@types/node@20.19.9': - resolution: {integrity: sha512-cuVNgarYWZqxRJDQHEB58GEONhOK79QVR/qYx4S7kcUObQvUwvFnYxJuuHUKm2aieN9X3yZB4LZsuYNU1Qphsw==} - - '@types/node@22.15.29': - resolution: {integrity: sha512-LNdjOkUDlU1RZb8e1kOIUpN1qQUlzGkEtbVNo53vbrwDg5om6oduhm4SiUaPW5ASTXhAiP0jInWG8Qx9fVlOeQ==} + '@types/node@24.2.1': + resolution: {integrity: sha512-DRh5K+ka5eJic8CjH7td8QpYEV6Zo10gfRkjHCO3weqZHWDtAaSTFtl4+VMqOJ4N5jcuhZ9/l+yy8rVgw7BQeQ==} '@types/prop-types@15.7.14': resolution: {integrity: sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ==} @@ -6000,6 +6027,11 @@ packages: engines: {node: 20 || >=22} hasBin: true + glob@11.0.3: + resolution: {integrity: sha512-2Nim7dha1KVkaiF4q6Dj+ngPPMdfvLJEOpZk/jKiUAkqKebpGAWQXAq9z1xu9HKu5lWfqw/FASuccEjyznjPaA==} + engines: {node: 20 || >=22} + hasBin: true + glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} deprecated: Glob versions prior to v9 are no longer supported @@ -6020,6 +6052,10 @@ packages: resolution: {integrity: sha512-aibexHNbb/jiUSObBgpHLj+sIuUmJnYcgXBlrfsiDZ9rt4aF2TFRbyLgZ2iFQuVZ1K5Mx3FVkbKRSgKrbK3K2g==} engines: {node: '>=18'} + globals@16.3.0: + resolution: {integrity: sha512-bqWEnJ1Nt3neqx2q5SFfGS8r/ahumIakg3HcwtNlrVlwXIeNumWn/c7Pn/wKzGhf6SaW6H6uWXLqC30STCMchQ==} + engines: {node: '>=18'} + globalthis@1.0.4: resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} engines: {node: '>= 0.4'} @@ -6571,6 +6607,10 @@ packages: resolution: {integrity: sha512-9DDdhb5j6cpeitCbvLO7n7J4IxnbM6hoF6O1g4HQ5TfhvvKN8ywDM7668ZhMHRqVmxqhps/F6syWK2KcPxYlkw==} engines: {node: 20 || >=22} + jackspeak@4.1.1: + resolution: {integrity: sha512-zptv57P3GpL+O0I7VdMJNBZCu+BPHVQUk55Ft8/QCJjTVxrnJHuVuX/0Bl2A6/+2oyR/ZMEuFKwmzqqZ/U5nPQ==} + engines: {node: 20 || >=22} + jest-diff@29.7.0: resolution: {integrity: sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -7333,6 +7373,10 @@ packages: resolution: {integrity: sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==} engines: {node: 20 || >=22} + minimatch@10.0.3: + resolution: {integrity: sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw==} + engines: {node: 20 || >=22} + minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} @@ -8675,6 +8719,7 @@ packages: source-map@0.8.0-beta.0: resolution: {integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==} engines: {node: '>= 8'} + deprecated: The work that was done in this beta branch won't be included in future versions space-separated-tokens@1.1.5: resolution: {integrity: sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA==} @@ -9249,8 +9294,8 @@ packages: undici-types@6.19.8: resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==} - undici-types@6.21.0: - resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + undici-types@7.10.0: + resolution: {integrity: sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag==} undici@6.21.3: resolution: {integrity: sha512-gBLkYIlEnSp8pFbT64yFgGE6UIB9tAkhukC23PmMDCe5Nd+cRqKxSjw5y54MK2AZMgZfJWMaNE4nYUHgi1XEOw==} @@ -11133,6 +11178,12 @@ snapshots: '@ioredis/commands@1.3.0': {} + '@isaacs/balanced-match@4.0.1': {} + + '@isaacs/brace-expansion@5.0.0': + dependencies: + '@isaacs/balanced-match': 4.0.1 + '@isaacs/cliui@8.0.2': dependencies: string-width: 5.1.2 @@ -11161,7 +11212,7 @@ snapshots: '@jest/schemas': 29.6.3 '@types/istanbul-lib-coverage': 2.0.6 '@types/istanbul-reports': 3.0.4 - '@types/node': 20.17.57 + '@types/node': 24.2.1 '@types/yargs': 17.0.33 chalk: 4.1.2 @@ -12234,9 +12285,9 @@ snapshots: '@rollup/rollup-win32-x64-msvc@4.40.2': optional: true - '@roo-code/cloud@0.13.0': + '@roo-code/cloud@0.14.0': dependencies: - '@roo-code/types': 1.45.0 + '@roo-code/types': 1.48.0 ioredis: 5.6.1 p-wait-for: 5.0.2 socket.io-client: 4.8.1 @@ -12246,7 +12297,7 @@ snapshots: - supports-color - utf-8-validate - '@roo-code/types@1.45.0': + '@roo-code/types@1.48.0': dependencies: zod: 3.25.76 @@ -13159,7 +13210,11 @@ snapshots: '@types/glob@8.1.0': dependencies: '@types/minimatch': 5.1.2 - '@types/node': 20.17.57 + '@types/node': 24.2.1 + + '@types/glob@9.0.0': + dependencies: + glob: 11.0.3 '@types/hast@3.0.4': dependencies: @@ -13212,12 +13267,12 @@ snapshots: '@types/node-fetch@2.6.12': dependencies: - '@types/node': 20.17.57 + '@types/node': 24.2.1 form-data: 4.0.4 '@types/node-ipc@9.2.3': dependencies: - '@types/node': 20.17.57 + '@types/node': 24.2.1 '@types/node@12.20.55': {} @@ -13235,18 +13290,9 @@ snapshots: dependencies: undici-types: 6.19.8 - '@types/node@20.19.1': + '@types/node@24.2.1': dependencies: - undici-types: 6.21.0 - - '@types/node@20.19.9': - dependencies: - undici-types: 6.21.0 - optional: true - - '@types/node@22.15.29': - dependencies: - undici-types: 6.21.0 + undici-types: 7.10.0 '@types/prop-types@15.7.14': {} @@ -13277,11 +13323,11 @@ snapshots: '@types/stream-chain@2.1.0': dependencies: - '@types/node': 20.19.1 + '@types/node': 24.2.1 '@types/stream-json@1.7.8': dependencies: - '@types/node': 20.19.1 + '@types/node': 24.2.1 '@types/stream-chain': 2.1.0 '@types/string-similarity@4.0.2': {} @@ -13307,7 +13353,7 @@ snapshots: '@types/ws@8.18.1': dependencies: - '@types/node': 20.19.9 + '@types/node': 24.2.1 optional: true '@types/yargs-parser@21.0.3': {} @@ -13318,7 +13364,7 @@ snapshots: '@types/yauzl@2.10.3': dependencies: - '@types/node': 20.17.50 + '@types/node': 24.2.1 optional: true '@typescript-eslint/eslint-plugin@8.32.1(@typescript-eslint/parser@8.32.1(eslint@9.27.0(jiti@2.4.2))(typescript@5.8.3))(eslint@9.27.0(jiti@2.4.2))(typescript@5.8.3)': @@ -13443,13 +13489,13 @@ snapshots: optionalDependencies: vite: 6.3.5(@types/node@20.17.57)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0) - '@vitest/mocker@3.2.4(vite@6.3.5(@types/node@22.15.29)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0))': + '@vitest/mocker@3.2.4(vite@6.3.5(@types/node@24.2.1)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0))': dependencies: '@vitest/spy': 3.2.4 estree-walker: 3.0.3 magic-string: 0.30.17 optionalDependencies: - vite: 6.3.5(@types/node@22.15.29)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0) + vite: 6.3.5(@types/node@24.2.1)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0) '@vitest/pretty-format@3.2.4': dependencies: @@ -13480,7 +13526,7 @@ snapshots: sirv: 3.0.1 tinyglobby: 0.2.14 tinyrainbow: 2.0.0 - vitest: 3.2.4(@types/debug@4.1.12)(@types/node@22.15.29)(@vitest/ui@3.2.4)(jiti@2.4.2)(jsdom@26.1.0)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0) + vitest: 3.2.4(@types/debug@4.1.12)(@types/node@24.2.1)(@vitest/ui@3.2.4)(jiti@2.4.2)(jsdom@26.1.0)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0) '@vitest/utils@3.2.4': dependencies: @@ -13561,7 +13607,7 @@ snapshots: cockatiel: 3.2.1 commander: 12.1.0 form-data: 4.0.4 - glob: 11.0.2 + glob: 11.0.3 hosted-git-info: 4.1.0 jsonc-parser: 3.3.1 leven: 3.1.0 @@ -15691,6 +15737,15 @@ snapshots: package-json-from-dist: 1.0.1 path-scurry: 2.0.0 + glob@11.0.3: + dependencies: + foreground-child: 3.3.1 + jackspeak: 4.1.1 + minimatch: 10.0.3 + minipass: 7.1.2 + package-json-from-dist: 1.0.1 + path-scurry: 2.0.0 + glob@7.2.3: dependencies: fs.realpath: 1.0.0 @@ -15708,6 +15763,8 @@ snapshots: globals@16.1.0: {} + globals@16.3.0: {} + globalthis@1.0.4: dependencies: define-properties: 1.2.1 @@ -16297,6 +16354,10 @@ snapshots: dependencies: '@isaacs/cliui': 8.0.2 + jackspeak@4.1.1: + dependencies: + '@isaacs/cliui': 8.0.2 + jest-diff@29.7.0: dependencies: chalk: 4.1.2 @@ -16328,7 +16389,7 @@ snapshots: jest-util@29.7.0: dependencies: '@jest/types': 29.6.3 - '@types/node': 20.17.57 + '@types/node': 24.2.1 chalk: 4.1.2 ci-info: 3.9.0 graceful-fs: 4.2.11 @@ -16488,10 +16549,10 @@ snapshots: kind-of@6.0.3: {} - knip@5.60.2(@types/node@22.15.29)(typescript@5.8.3): + knip@5.60.2(@types/node@24.2.1)(typescript@5.8.3): dependencies: '@nodelib/fs.walk': 1.2.8 - '@types/node': 22.15.29 + '@types/node': 24.2.1 fast-glob: 3.3.3 formatly: 0.2.4 jiti: 2.4.2 @@ -17322,6 +17383,10 @@ snapshots: dependencies: brace-expansion: 4.0.1 + minimatch@10.0.3: + dependencies: + '@isaacs/brace-expansion': 5.0.0 + minimatch@3.1.2: dependencies: brace-expansion: 4.0.1 @@ -18544,7 +18609,7 @@ snapshots: rimraf@6.0.1: dependencies: - glob: 11.0.2 + glob: 11.0.3 package-json-from-dist: 1.0.1 robust-predicates@3.0.2: {} @@ -19531,7 +19596,7 @@ snapshots: undici-types@6.19.8: {} - undici-types@6.21.0: {} + undici-types@7.10.0: {} undici@6.21.3: {} @@ -19806,13 +19871,13 @@ snapshots: - tsx - yaml - vite-node@3.2.4(@types/node@22.15.29)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0): + vite-node@3.2.4(@types/node@24.2.1)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0): dependencies: cac: 6.7.14 debug: 4.4.1(supports-color@8.1.1) es-module-lexer: 1.7.0 pathe: 2.0.3 - vite: 6.3.5(@types/node@22.15.29)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0) + vite: 6.3.5(@types/node@24.2.1)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0) transitivePeerDependencies: - '@types/node' - jiti @@ -19859,7 +19924,7 @@ snapshots: tsx: 4.19.4 yaml: 2.8.0 - vite@6.3.5(@types/node@22.15.29)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0): + vite@6.3.5(@types/node@24.2.1)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0): dependencies: esbuild: 0.25.5 fdir: 6.4.4(picomatch@4.0.2) @@ -19868,7 +19933,7 @@ snapshots: rollup: 4.40.2 tinyglobby: 0.2.13 optionalDependencies: - '@types/node': 22.15.29 + '@types/node': 24.2.1 fsevents: 2.3.3 jiti: 2.4.2 lightningcss: 1.30.1 @@ -19963,11 +20028,11 @@ snapshots: - tsx - yaml - vitest@3.2.4(@types/debug@4.1.12)(@types/node@22.15.29)(@vitest/ui@3.2.4)(jiti@2.4.2)(jsdom@26.1.0)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0): + vitest@3.2.4(@types/debug@4.1.12)(@types/node@24.2.1)(@vitest/ui@3.2.4)(jiti@2.4.2)(jsdom@26.1.0)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0): dependencies: '@types/chai': 5.2.2 '@vitest/expect': 3.2.4 - '@vitest/mocker': 3.2.4(vite@6.3.5(@types/node@22.15.29)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0)) + '@vitest/mocker': 3.2.4(vite@6.3.5(@types/node@24.2.1)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0)) '@vitest/pretty-format': 3.2.4 '@vitest/runner': 3.2.4 '@vitest/snapshot': 3.2.4 @@ -19985,12 +20050,12 @@ snapshots: tinyglobby: 0.2.14 tinypool: 1.1.1 tinyrainbow: 2.0.0 - vite: 6.3.5(@types/node@22.15.29)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0) - vite-node: 3.2.4(@types/node@22.15.29)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0) + vite: 6.3.5(@types/node@24.2.1)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0) + vite-node: 3.2.4(@types/node@24.2.1)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0) why-is-node-running: 2.3.0 optionalDependencies: '@types/debug': 4.1.12 - '@types/node': 22.15.29 + '@types/node': 24.2.1 '@vitest/ui': 3.2.4(vitest@3.2.4) jsdom: 26.1.0 transitivePeerDependencies: diff --git a/scripts/link-packages.js b/scripts/link-packages.js deleted file mode 100755 index 6d8b33f6de..0000000000 --- a/scripts/link-packages.js +++ /dev/null @@ -1,158 +0,0 @@ -#!/usr/bin/env node - -const { spawn, execSync } = require("child_process") -const path = require("path") -const fs = require("fs") - -// Package configuration - Add new packages here as needed. -const config = { - packages: [ - { - name: "@roo-code/cloud", - sourcePath: "../Roo-Code-Cloud/packages/sdk", - targetPath: "src/node_modules/@roo-code/cloud", - npmPath: "npm", - watchCommand: "pnpm build:development:watch", - }, - ], -} - -const args = process.argv.slice(2) -const packageName = args.find((arg) => !arg.startsWith("--")) -const watch = !args.includes("--no-watch") -const unlink = args.includes("--unlink") - -const packages = packageName ? config.packages.filter((p) => p.name === packageName) : config.packages - -if (!packages.length) { - console.error(`Package '${packageName}' not found`) - process.exit(1) -} - -packages.forEach(unlink ? unlinkPackage : linkPackage) - -// After unlinking, restore npm packages with a single pnpm install. -if (unlink && packages.length > 0) { - const srcPath = path.resolve(__dirname, "..", "src") - console.log("\nRestoring npm packages...") - - try { - execSync("pnpm install", { cwd: srcPath, stdio: "inherit" }) - console.log("Successfully restored npm packages") - } catch (error) { - console.error(`Failed to restore packages: ${error.message}`) - console.log("You may need to run 'pnpm install' manually in the src directory") - } -} - -if (!unlink && watch) { - const watchers = packages.filter((pkg) => pkg.watchCommand).map(startWatch) - - if (watchers.length) { - process.on("SIGINT", () => { - console.log("\nStopping...") - watchers.forEach((w) => w.kill()) - process.exit(0) - }) - console.log("\nWatching for changes. Press Ctrl+C to stop.\n") - } -} - -function generateNpmPackageJson(sourcePath, npmPath) { - const npmDir = path.join(sourcePath, npmPath) - const npmPackagePath = path.join(npmDir, "package.json") - const npmMetadataPath = path.join(npmDir, "package.metadata.json") - const monorepoPackagePath = path.join(sourcePath, "package.json") - - if (fs.existsSync(npmPackagePath)) { - console.log(` ✓ npm/package.json already exists`) - return - } - - if (!fs.existsSync(npmMetadataPath)) { - console.log(` ⚠ No package.metadata.json found, skipping npm package.json generation`) - return - } - - try { - console.log(` 📦 Generating npm/package.json...`) - const monorepoPackage = JSON.parse(fs.readFileSync(monorepoPackagePath, "utf8")) - const npmMetadata = JSON.parse(fs.readFileSync(npmMetadataPath, "utf8")) - - const npmPackage = { - ...npmMetadata, - type: "module", - 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"], - } - - fs.writeFileSync(npmPackagePath, JSON.stringify(npmPackage, null, 2) + "\n") - console.log(` ✓ Generated npm/package.json for ${npmPackage.name}`) - } catch (error) { - console.error(` ✗ Failed to generate npm/package.json: ${error.message}`) - } -} - -function linkPackage(pkg) { - const sourcePath = path.resolve(__dirname, "..", pkg.sourcePath) - const targetPath = path.resolve(__dirname, "..", pkg.targetPath) - - if (!fs.existsSync(sourcePath)) { - console.error(`Source not found: ${sourcePath}`) - process.exit(1) - } - - // Install dependencies if needed. - if (!fs.existsSync(path.join(sourcePath, "node_modules"))) { - console.log(`Installing dependencies for ${pkg.name}...`) - - try { - execSync("pnpm install", { cwd: sourcePath, stdio: "inherit" }) - } catch (e) { - execSync("pnpm install --no-frozen-lockfile", { cwd: sourcePath, stdio: "inherit" }) - } - } - - // If npmPath is specified, check if we need to generate package.json. - if (pkg.npmPath) { - generateNpmPackageJson(sourcePath, pkg.npmPath) - } - - // Create symlink. - fs.rmSync(targetPath, { recursive: true, force: true }) - fs.mkdirSync(path.dirname(targetPath), { recursive: true }) - const linkSource = pkg.npmPath ? path.join(sourcePath, pkg.npmPath) : sourcePath - fs.symlinkSync(linkSource, targetPath, "dir") - console.log(`Linked ${pkg.name}`) -} - -function unlinkPackage(pkg) { - const targetPath = path.resolve(__dirname, "..", pkg.targetPath) - if (fs.existsSync(targetPath)) { - fs.rmSync(targetPath, { recursive: true, force: true }) - console.log(`Unlinked ${pkg.name}`) - } -} - -function startWatch(pkg) { - console.log(`Watching ${pkg.name}...`) - const [cmd, ...args] = pkg.watchCommand.split(" ") - return spawn(cmd, args, { - cwd: path.resolve(__dirname, "..", pkg.sourcePath), - stdio: "inherit", - shell: true, - }) -} diff --git a/scripts/link-packages.ts b/scripts/link-packages.ts new file mode 100644 index 0000000000..4d7e4a7c4c --- /dev/null +++ b/scripts/link-packages.ts @@ -0,0 +1,340 @@ +import { spawn, execSync, type ChildProcess } from "child_process" +import * as path from "path" +import * as fs from "fs" +import { fileURLToPath } from "url" +import { glob } from "glob" + +// @ts-expect-error - TS1470: We only run this script with tsx so it will never +// compile to CJS and it's safe to ignore this tsc error. +const __filename = fileURLToPath(import.meta.url) +const __dirname = path.dirname(__filename) + +interface PackageConfig { + readonly name: string + readonly sourcePath: string + readonly targetPaths: readonly string[] + readonly replacePath?: string + readonly npmPath: string + readonly watchCommand?: string + readonly watchOutput?: { + readonly start: string[] + readonly stop: string[] + } +} + +interface Config { + readonly packages: readonly PackageConfig[] +} + +interface WatcherResult { + child: ChildProcess +} + +interface NpmPackage { + name?: string + version?: string + type: "module" + dependencies: Record + main: string + module: string + types: string + exports: { + ".": { + types: string + import: string + require: { + types: string + default: string + } + } + } + files: string[] +} + +const config: Config = { + packages: [ + { + name: "@roo-code/cloud", + sourcePath: "../Roo-Code-Cloud/packages/sdk", + targetPaths: ["src/node_modules/@roo-code/cloud"] as const, + replacePath: "node_modules/.pnpm/@roo-code+cloud*", + npmPath: "npm", + watchCommand: "pnpm build:development:watch", + watchOutput: { + start: ["CLI Building", "CLI Change detected"], + stop: ["DTS ⚡️ Build success"], + }, + }, + ], +} as const + +const args = process.argv.slice(2) +const packageName = args.find((arg) => !arg.startsWith("--")) +const watchMode = !args.includes("--no-watch") +const unlink = args.includes("--unlink") + +const packages: readonly PackageConfig[] = packageName + ? config.packages.filter((p) => p.name === packageName) + : config.packages + +if (!packages.length) { + console.error(`Package '${packageName}' not found`) + process.exit(1) +} + +function pathExists(filePath: string): boolean { + try { + fs.accessSync(filePath) + return true + } catch { + return false + } +} + +function copyRecursiveSync(src: string, dest: string): void { + const exists = pathExists(src) + + if (!exists) { + return + } + + const stats = fs.statSync(src) + const isDirectory = stats.isDirectory() + + if (isDirectory) { + if (!pathExists(dest)) { + fs.mkdirSync(dest, { recursive: true }) + } + + const children = fs.readdirSync(src) + + children.forEach((childItemName) => { + copyRecursiveSync(path.join(src, childItemName), path.join(dest, childItemName)) + }) + } else { + fs.copyFileSync(src, dest) + } +} + +function generateNpmPackageJson(sourcePath: string, npmPath: string): string { + const npmDir = path.join(sourcePath, npmPath) + const npmPackagePath = path.join(npmDir, "package.json") + const npmMetadataPath = path.join(npmDir, "package.metadata.json") + const monorepoPackagePath = path.join(sourcePath, "package.json") + + if (pathExists(npmPackagePath)) { + return npmPackagePath + } + + if (!pathExists(npmMetadataPath)) { + throw new Error(`No package.metadata.json found in ${npmDir}`) + } + + const monorepoPackageContent = fs.readFileSync(monorepoPackagePath, "utf8") + + const monorepoPackage = JSON.parse(monorepoPackageContent) as { + dependencies?: Record + } + + const npmMetadataContent = fs.readFileSync(npmMetadataPath, "utf8") + const npmMetadata = JSON.parse(npmMetadataContent) as Partial + + const npmPackage: NpmPackage = { + ...npmMetadata, + type: "module", + 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"], + } + + fs.writeFileSync(npmPackagePath, JSON.stringify(npmPackage, null, 2) + "\n") + + return npmPackagePath +} + +function linkPackage(pkg: PackageConfig): void { + const sourcePath = path.resolve(__dirname, "..", pkg.sourcePath) + + if (!pathExists(sourcePath)) { + console.error(`❌ Source not found: ${sourcePath}`) + process.exit(1) + } + + generateNpmPackageJson(sourcePath, pkg.npmPath) + + for (const currentTargetPath of pkg.targetPaths) { + const targetPath = path.resolve(__dirname, "..", currentTargetPath) + + if (pathExists(targetPath)) { + fs.rmSync(targetPath, { recursive: true, force: true }) + } + + const parentDir = path.dirname(targetPath) + fs.mkdirSync(parentDir, { recursive: true }) + + const linkSource = pkg.npmPath ? path.join(sourcePath, pkg.npmPath) : sourcePath + copyRecursiveSync(linkSource, targetPath) + } +} + +function unlinkPackage(pkg: PackageConfig): void { + for (const currentTargetPath of pkg.targetPaths) { + const targetPath = path.resolve(__dirname, "..", currentTargetPath) + + if (pathExists(targetPath)) { + fs.rmSync(targetPath, { recursive: true, force: true }) + console.log(`🗑️ Removed ${pkg.name} from ${currentTargetPath}`) + } + } +} + +function startWatch(pkg: PackageConfig): WatcherResult { + if (!pkg.watchCommand) { + throw new Error(`Package ${pkg.name} has no watch command configured`) + } + + const commandParts = pkg.watchCommand.split(" ") + const [cmd, ...args] = commandParts + + if (!cmd) { + throw new Error(`Invalid watch command for ${pkg.name}`) + } + + console.log(`Watching for changes to ${pkg.sourcePath} with ${cmd} ${args.join(" ")}`) + + const child = spawn(cmd, args, { + cwd: path.resolve(__dirname, "..", pkg.sourcePath), + stdio: "pipe", + shell: true, + }) + + let debounceTimer: NodeJS.Timeout | null = null + + const DEBOUNCE_DELAY = 500 + + if (child.stdout) { + child.stdout.on("data", (data: Buffer) => { + const output = data.toString() + + const isStarting = pkg.watchOutput?.start.some((start) => output.includes(start)) + + const isDone = pkg.watchOutput?.stop.some((stop) => output.includes(stop)) + + if (isStarting) { + console.log(`🔨 Building ${pkg.name}...`) + + if (debounceTimer) { + clearTimeout(debounceTimer) + debounceTimer = null + } + } + + if (isDone) { + console.log(`✅ Built ${pkg.name}`) + + if (debounceTimer) { + clearTimeout(debounceTimer) + } + + debounceTimer = setTimeout(() => { + linkPackage(pkg) + + console.log(`📋 Copied ${pkg.name} to ${pkg.targetPaths.length} paths\n`) + + debounceTimer = null + }, DEBOUNCE_DELAY) + } + }) + } + + if (child.stderr) { + child.stderr.on("data", (data: Buffer) => { + console.log(`❌ "${data.toString()}"`) + }) + } + + return { child } +} + +function main(): void { + if (unlink) { + packages.forEach(unlinkPackage) + + console.log("\n📦 Restoring npm packages...") + + try { + execSync("pnpm install", { cwd: __dirname, stdio: "ignore" }) + console.log("✅ npm packages restored") + } catch (error) { + console.error(`❌ Failed to restore packages: ${error instanceof Error ? error.message : String(error)}`) + + console.log(" Run 'pnpm install' manually if needed") + } + } else { + packages.forEach((pkg) => { + linkPackage(pkg) + + if (pkg.replacePath) { + const replacePattern = path.resolve(__dirname, "..", pkg.replacePath) + + try { + const matchedPaths = glob.sync(replacePattern) + + if (matchedPaths.length > 0) { + matchedPaths.forEach((matchedPath: string) => { + if (pathExists(matchedPath)) { + fs.rmSync(matchedPath, { recursive: true, force: true }) + console.log(`🗑️ Removed ${pkg.name} from ${matchedPath}`) + } + }) + } else { + if (pathExists(replacePattern)) { + fs.rmSync(replacePattern, { recursive: true, force: true }) + console.log(`🗑️ Removed ${pkg.name} from ${replacePattern}`) + } + } + } catch (error) { + console.error( + `❌ Error processing replace path: ${error instanceof Error ? error.message : String(error)}`, + ) + } + } + }) + + if (watchMode) { + const packagesWithWatch = packages.filter( + (pkg): pkg is PackageConfig & { watchCommand: string } => pkg.watchCommand !== undefined, + ) + + const watchers = packagesWithWatch.map(startWatch) + + if (watchers.length > 0) { + process.on("SIGINT", () => { + console.log("\n👋 Stopping watchers...") + + watchers.forEach((w) => { + if (w.child) { + w.child.kill() + } + }) + + process.exit(0) + }) + } + } + } +} + +main() diff --git a/src/core/task/Task.ts b/src/core/task/Task.ts index 2103dacb27..659e7772d5 100644 --- a/src/core/task/Task.ts +++ b/src/core/task/Task.ts @@ -11,6 +11,7 @@ import { serializeError } from "serialize-error" import { type TaskLike, + type TaskMetadata, type TaskEvents, type ProviderSettings, type TokenUsage, @@ -32,7 +33,7 @@ import { isBlockingAsk, } from "@roo-code/types" import { TelemetryService } from "@roo-code/telemetry" -import { CloudService, UnifiedBridgeService } from "@roo-code/cloud" +import { CloudService, ExtensionBridgeService } from "@roo-code/cloud" // api import { ApiHandler, ApiHandlerCreateMessageMetadata, buildApiHandler } from "../../api" @@ -122,9 +123,11 @@ export type TaskOptions = { } export class Task extends EventEmitter implements TaskLike { - todoList?: TodoItem[] readonly taskId: string readonly instanceId: string + readonly metadata: TaskMetadata + + todoList?: TodoItem[] readonly rootTask: Task | undefined = undefined readonly parentTask: Task | undefined = undefined @@ -240,7 +243,7 @@ export class Task extends EventEmitter implements TaskLike { // Task Bridge enableTaskBridge: boolean - bridgeService: UnifiedBridgeService | null = null + bridgeService: ExtensionBridgeService | null = null // Streaming isWaitingForFirstChunk = false @@ -285,6 +288,12 @@ export class Task extends EventEmitter implements TaskLike { this.taskId = historyItem ? historyItem.id : crypto.randomUUID() + this.metadata = { + taskId: this.taskId, + task: historyItem ? historyItem.task : task, + images: historyItem ? [] : images, + } + // Normal use-case is usually retry similar history task with new workspace. this.workspacePath = parentTask ? parentTask.workspacePath @@ -981,7 +990,7 @@ export class Task extends EventEmitter implements TaskLike { private async startTask(task?: string, images?: string[]): Promise { if (this.enableTaskBridge) { try { - this.bridgeService = this.bridgeService || UnifiedBridgeService.getInstance() + this.bridgeService = this.bridgeService || ExtensionBridgeService.getInstance() if (this.bridgeService) { await this.bridgeService.subscribeToTask(this) @@ -1046,7 +1055,7 @@ export class Task extends EventEmitter implements TaskLike { private async resumeTaskFromHistory() { if (this.enableTaskBridge) { try { - this.bridgeService = this.bridgeService || UnifiedBridgeService.getInstance() + this.bridgeService = this.bridgeService || ExtensionBridgeService.getInstance() if (this.bridgeService) { await this.bridgeService.subscribeToTask(this) diff --git a/src/core/webview/ClineProvider.ts b/src/core/webview/ClineProvider.ts index 81c0a562c7..6622b29891 100644 --- a/src/core/webview/ClineProvider.ts +++ b/src/core/webview/ClineProvider.ts @@ -560,18 +560,16 @@ export class ClineProvider this.log("Resolving webview view") this.view = webviewView - - // Set panel reference according to webview type const inTabMode = "onDidChangeViewState" in webviewView + if (inTabMode) { - // Tag page type setPanel(webviewView, "tab") } else if ("onDidChangeVisibility" in webviewView) { - // Sidebar Type setPanel(webviewView, "sidebar") } - // Initialize out-of-scope variables that need to receive persistent global state values + // Initialize out-of-scope variables that need to receive persistent + // global state values. this.getState().then( ({ terminalShellIntegrationTimeout = Terminal.defaultShellIntegrationTimeout, @@ -594,18 +592,15 @@ export class ClineProvider }, ) - // Initialize tts enabled state this.getState().then(({ ttsEnabled }) => { setTtsEnabled(ttsEnabled ?? false) }) - // Initialize tts speed state this.getState().then(({ ttsSpeed }) => { setTtsSpeed(ttsSpeed ?? 1) }) webviewView.webview.options = { - // Allow scripts in the webview enableScripts: true, localResourceRoots: [this.contextProxy.extensionUri], } @@ -616,32 +611,31 @@ export class ClineProvider : this.getHtmlContent(webviewView.webview) // Sets up an event listener to listen for messages passed from the webview view context - // and executes code based on the message that is received + // and executes code based on the message that is received. this.setWebviewMessageListener(webviewView.webview) - // Initialize code index status subscription for the current workspace + // Initialize code index status subscription for the current workspace. this.updateCodeIndexStatusSubscription() - // Listen for active editor changes to update code index status for the current workspace + // Listen for active editor changes to update code index status for the + // current workspace. const activeEditorSubscription = vscode.window.onDidChangeActiveTextEditor(() => { - // Update subscription when workspace might have changed + // Update subscription when workspace might have changed. this.updateCodeIndexStatusSubscription() }) this.webviewDisposables.push(activeEditorSubscription) - // Logs show up in bottom panel > Debug Console - //console.log("registering listener") - - // Listen for when the panel becomes visible + // Listen for when the panel becomes visible. // https://github.com/microsoft/vscode-discussions/discussions/840 if ("onDidChangeViewState" in webviewView) { - // WebviewView and WebviewPanel have all the same properties except for this visibility listener - // panel + // WebviewView and WebviewPanel have all the same properties except + // for this visibility listener panel. const viewStateDisposable = webviewView.onDidChangeViewState(() => { if (this.view?.visible) { this.postMessageToWebview({ type: "action", action: "didBecomeVisible" }) } }) + this.webviewDisposables.push(viewStateDisposable) } else if ("onDidChangeVisibility" in webviewView) { // sidebar @@ -650,6 +644,7 @@ export class ClineProvider this.postMessageToWebview({ type: "action", action: "didBecomeVisible" }) } }) + this.webviewDisposables.push(visibilityDisposable) } @@ -838,8 +833,8 @@ export class ClineProvider } private async getHMRHtmlContent(webview: vscode.Webview): Promise { - // Try to read the port from the file - let localPort = "5173" // Default fallback + let localPort = "5173" + try { const fs = require("fs") const path = require("path") @@ -855,7 +850,6 @@ export class ClineProvider } } catch (err) { console.error("[ClineProvider:Vite] Failed to read Vite port file:", err) - // Continue with default port if file reading fails } const localServerUrl = `localhost:${localPort}` @@ -865,7 +859,6 @@ export class ClineProvider await axios.get(`http://${localServerUrl}`) } catch (error) { vscode.window.showErrorMessage(t("common:errors.hmr_not_running")) - return this.getHtmlContent(webview) } @@ -2130,12 +2123,8 @@ export class ClineProvider return true } - /** - * Handle remote control enabled/disabled state changes - * Manages UnifiedBridgeService lifecycle - */ public async handleRemoteControlToggle(enabled: boolean) { - const { CloudService: CloudServiceImport, UnifiedBridgeService } = await import("@roo-code/cloud") + const { CloudService: CloudServiceImport, ExtensionBridgeService } = await import("@roo-code/cloud") const userInfo = CloudServiceImport.instance.getUserInfo() @@ -2146,10 +2135,10 @@ export class ClineProvider return } - await UnifiedBridgeService.handleRemoteControlState( + await ExtensionBridgeService.handleRemoteControlState( userInfo, enabled, - { ...bridgeConfig, provider: this }, + { ...bridgeConfig, provider: this, sessionId: vscode.env.sessionId }, (message: string) => this.log(message), ) @@ -2158,7 +2147,7 @@ export class ClineProvider if (currentTask && !currentTask.bridgeService) { try { - currentTask.bridgeService = UnifiedBridgeService.getInstance() + currentTask.bridgeService = ExtensionBridgeService.getInstance() if (currentTask.bridgeService) { await currentTask.bridgeService.subscribeToTask(currentTask) @@ -2183,7 +2172,7 @@ export class ClineProvider } } - UnifiedBridgeService.resetInstance() + ExtensionBridgeService.resetInstance() } } diff --git a/src/extension.ts b/src/extension.ts index 767e83c42d..6cb6ea4b07 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -12,7 +12,7 @@ try { console.warn("Failed to load environment variables:", e) } -import { CloudService, UnifiedBridgeService } from "@roo-code/cloud" +import { CloudService, ExtensionBridgeService } from "@roo-code/cloud" import { TelemetryService, PostHogTelemetryClient } from "@roo-code/telemetry" import "./utils/path" // Necessary to have access to String.prototype.toPosix. @@ -141,10 +141,10 @@ export async function activate(context: vscode.ExtensionContext) { return } - UnifiedBridgeService.handleRemoteControlState( + ExtensionBridgeService.handleRemoteControlState( userInfo, contextProxy.getValue("remoteControlEnabled"), - { ...bridgeConfig, provider }, + { ...bridgeConfig, provider, sessionId: vscode.env.sessionId }, (message: string) => outputChannel.appendLine(message), ) }) @@ -280,7 +280,7 @@ export async function activate(context: vscode.ExtensionContext) { export async function deactivate() { outputChannel.appendLine(`${Package.name} extension deactivated`) - const bridgeService = UnifiedBridgeService.getInstance() + const bridgeService = ExtensionBridgeService.getInstance() if (bridgeService) { await bridgeService.disconnect() diff --git a/src/package.json b/src/package.json index 9d694b2bbb..14b534288b 100644 --- a/src/package.json +++ b/src/package.json @@ -427,7 +427,7 @@ "@mistralai/mistralai": "^1.3.6", "@modelcontextprotocol/sdk": "^1.9.0", "@qdrant/js-client-rest": "^1.14.0", - "@roo-code/cloud": "^0.13.0", + "@roo-code/cloud": "^0.14.0", "@roo-code/ipc": "workspace:^", "@roo-code/telemetry": "workspace:^", "@roo-code/types": "workspace:^", @@ -474,6 +474,7 @@ "say": "^0.16.0", "serialize-error": "^12.0.0", "simple-git": "^3.27.0", + "socket.io-client": "^4.8.1", "sound-play": "^1.1.0", "stream-json": "^1.8.0", "string-similarity": "^4.0.4", diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000000..44f734c197 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "@roo-code/config-typescript/base.json", + "compilerOptions": { + "types": ["node"] + }, + "exclude": ["node_modules"], + "include": ["scripts/*.ts"] +}