Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 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
91 changes: 91 additions & 0 deletions scripts/link-packages.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
#!/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)

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