Task metadata (#7092)

This commit is contained in:
Chris Estreich 2025-08-14 00:14:17 -10:00 committed by GitHub
parent dcbb7a673f
commit c56b95bc60
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 912 additions and 292 deletions

View file

@ -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"
},

2
packages/types/.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
dist
npm/package.json

View file

@ -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",
},
},
]

View file

@ -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"]
}

View file

@ -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"
}

View file

@ -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)
})

View file

@ -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<typeof taskMetadataSchema>
export interface TaskLike {
readonly taskId: string
readonly rootTask?: TaskLike
readonly blockingAsk?: BlockingAsk
readonly metadata: TaskMetadata
on<K extends keyof TaskEvents>(event: K, listener: (...args: TaskEvents[K]) => void | Promise<void>): this
off<K extends keyof TaskEvents>(event: K, listener: (...args: TaskEvents[K]) => void | Promise<void>): this

View file

@ -4,6 +4,6 @@
"types": ["vitest/globals"],
"outDir": "dist"
},
"include": ["src"],
"include": ["src", "scripts", "*.config.ts"],
"exclude": ["node_modules"]
}

187
pnpm-lock.yaml generated
View file

@ -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:

View file

@ -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,
})
}

340
scripts/link-packages.ts Normal file
View file

@ -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<string, string>
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<string, string>
}
const npmMetadataContent = fs.readFileSync(npmMetadataPath, "utf8")
const npmMetadata = JSON.parse(npmMetadataContent) as Partial<NpmPackage>
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()

View file

@ -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<TaskEvents> 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<TaskEvents> 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<TaskEvents> 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<TaskEvents> implements TaskLike {
private async startTask(task?: string, images?: string[]): Promise<void> {
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<TaskEvents> 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)

View file

@ -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<string> {
// 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()
}
}

View file

@ -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()

View file

@ -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",

8
tsconfig.json Normal file
View file

@ -0,0 +1,8 @@
{
"extends": "@roo-code/config-typescript/base.json",
"compilerOptions": {
"types": ["node"]
},
"exclude": ["node_modules"],
"include": ["scripts/*.ts"]
}