Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@
"changeset:version": "cp CHANGELOG.md src/CHANGELOG.md && changeset version && cp -vf src/CHANGELOG.md .",
"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"
"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"
},
"devDependencies": {
"@changesets/cli": "^2.27.10",
Expand Down
105 changes: 105 additions & 0 deletions scripts/link-packages.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
#!/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 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" })
}
}

// 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,
})
}
48 changes: 37 additions & 11 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -207,28 +207,54 @@ export async function activate(context: vscode.ExtensionContext) {

// Watch the core files and automatically reload the extension host.
if (process.env.NODE_ENV === "development") {
const pattern = "**/*.ts"

const watchPaths = [
{ path: context.extensionPath, name: "extension" },
{ path: path.join(context.extensionPath, "../packages/types"), name: "types" },
{ path: path.join(context.extensionPath, "../packages/telemetry"), name: "telemetry" },
{ path: context.extensionPath, pattern: "**/*.ts" },
{ path: path.join(context.extensionPath, "../packages/types"), pattern: "**/*.ts" },
{ path: path.join(context.extensionPath, "../packages/telemetry"), pattern: "**/*.ts" },
{ path: path.join(context.extensionPath, "node_modules/@roo-code/cloud"), pattern: "**/*" },
]

console.log(
`♻️♻️♻️ Core auto-reloading is ENABLED. Watching for changes in: ${watchPaths.map(({ name }) => name).join(", ")}`,
`♻️♻️♻️ Core auto-reloading: Watching for changes in ${watchPaths.map(({ path }) => path).join(", ")}`,
)

watchPaths.forEach(({ path: watchPath, name }) => {
const watcher = vscode.workspace.createFileSystemWatcher(new vscode.RelativePattern(watchPath, pattern))
// Create a debounced reload function to prevent excessive reloads
let reloadTimeout: NodeJS.Timeout | undefined
const DEBOUNCE_DELAY = 1_000

const debouncedReload = (uri: vscode.Uri) => {
if (reloadTimeout) {
clearTimeout(reloadTimeout)
}

watcher.onDidChange((uri) => {
console.log(`♻️ ${name} file changed: ${uri.fsPath}. Reloading host…`)
console.log(`♻️ ${uri.fsPath} changed; scheduling reload...`)

reloadTimeout = setTimeout(() => {
console.log(`♻️ Reloading host after debounce delay...`)
vscode.commands.executeCommand("workbench.action.reloadWindow")
})
}, DEBOUNCE_DELAY)
}

watchPaths.forEach(({ path: watchPath, pattern }) => {
const relPattern = new vscode.RelativePattern(vscode.Uri.file(watchPath), pattern)
const watcher = vscode.workspace.createFileSystemWatcher(relPattern, false, false, false)

// Listen to all change types to ensure symlinked file updates trigger reloads.
watcher.onDidChange(debouncedReload)
watcher.onDidCreate(debouncedReload)
watcher.onDidDelete(debouncedReload)

context.subscriptions.push(watcher)
})

// Clean up the timeout on deactivation
context.subscriptions.push({
dispose: () => {
if (reloadTimeout) {
clearTimeout(reloadTimeout)
}
},
})
}

return new API(outputChannel, provider, socketPath, enableLogging)
Expand Down
9 changes: 8 additions & 1 deletion src/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,12 @@
"useUnknownInCatchVariables": false
},
"include": ["."],
"exclude": ["node_modules"]
"exclude": ["node_modules"],
"watchOptions": {
"watchFile": "useFsEvents",
"watchDirectory": "useFsEvents",
"fallbackPolling": "dynamicPriority",
"synchronousWatchDirectory": true,
"excludeDirectories": ["**/node_modules", "**/dist", "**/.turbo"]
}
}
Loading