mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-09-06 08:18:39 +00:00
Working
This commit is contained in:
parent
d0e4b887e4
commit
9e91335bf6
8 changed files with 335 additions and 40 deletions
|
|
@ -6,41 +6,5 @@ commands:
|
|||
run: pnpm install
|
||||
timeout: 60
|
||||
|
||||
- name: Build & watch (Terminal 1)
|
||||
run: |
|
||||
# Build all workspace packages first (handles @roo-code/build and other deps)
|
||||
pnpm build || exit $?
|
||||
|
||||
# Enable polling for file watchers (helps with symlinks and macOS issues)
|
||||
export CHOKIDAR_USEPOLLING=true
|
||||
export WATCHPACK_POLLING=true
|
||||
|
||||
# Start watchers (same as .vscode/tasks.json "watch" task, using direct pnpm filters)
|
||||
pnpm --filter @roo-code/vscode-webview dev &
|
||||
pnpm --filter roo-cline watch:bundle &
|
||||
pnpm --filter roo-cline watch:tsc &
|
||||
|
||||
# Wait for all background jobs
|
||||
wait
|
||||
timeout: 0
|
||||
|
||||
- name: Start code-server (Terminal 2)
|
||||
run: |
|
||||
PORT=${PORT:-8443}
|
||||
|
||||
# Install code-server if missing
|
||||
if ! command -v code-server &> /dev/null; then
|
||||
curl -fsSL https://code-server.dev/install.sh | sh
|
||||
fi
|
||||
|
||||
# Symlink extension for live development
|
||||
EXT_DIR="$HOME/.local/share/code-server/extensions"
|
||||
mkdir -p "$EXT_DIR"
|
||||
ln -sfn "$(pwd)/src" "$EXT_DIR/roo-cline"
|
||||
|
||||
# Disable atomic writes so file watchers detect changes properly
|
||||
export DISABLE_ATOMICWRITES=true
|
||||
|
||||
# Launch code-server
|
||||
code-server --auth none --bind-addr 0.0.0.0:${PORT} .
|
||||
timeout: 0
|
||||
- name: Serve
|
||||
run: pnpm serve
|
||||
|
|
@ -23,7 +23,8 @@
|
|||
"changeset:version": "cp CHANGELOG.md src/CHANGELOG.md && changeset version && cp -vf src/CHANGELOG.md .",
|
||||
"knip": "knip --include files",
|
||||
"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",
|
||||
"npm:publish:types": "pnpm --filter @roo-code/types npm:publish"
|
||||
"npm:publish:types": "pnpm --filter @roo-code/types npm:publish",
|
||||
"serve": "bash scripts/serve.sh"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@changesets/cli": "^2.27.10",
|
||||
|
|
|
|||
3
pnpm-lock.yaml
generated
3
pnpm-lock.yaml
generated
|
|
@ -1338,6 +1338,9 @@ importers:
|
|||
'@vitest/ui':
|
||||
specifier: ^3.2.3
|
||||
version: 3.2.4(vitest@3.2.4)
|
||||
chokidar:
|
||||
specifier: ^4.0.1
|
||||
version: 4.0.3
|
||||
identity-obj-proxy:
|
||||
specifier: ^3.0.0
|
||||
version: 3.0.0
|
||||
|
|
|
|||
94
scripts/serve.sh
Executable file
94
scripts/serve.sh
Executable file
|
|
@ -0,0 +1,94 @@
|
|||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
PORT=${PORT:-8443}
|
||||
|
||||
# Install code-server if missing
|
||||
if ! command -v code-server &> /dev/null; then
|
||||
echo "Installing code-server..."
|
||||
curl -fsSL https://code-server.dev/install.sh | sh
|
||||
fi
|
||||
|
||||
# Set up extension symlink for live development
|
||||
EXT_DIR="$HOME/.local/share/code-server/extensions"
|
||||
mkdir -p "$EXT_DIR"
|
||||
ln -sfn "$(pwd)/src" "$EXT_DIR/roo-cline"
|
||||
|
||||
echo "=============================================="
|
||||
echo "Setting up environment variables for watchers"
|
||||
echo "=============================================="
|
||||
|
||||
# Enable polling for file watchers (helps with symlinks and various environments)
|
||||
# Chokidar (used by Vite and now esbuild)
|
||||
export CHOKIDAR_USEPOLLING=true
|
||||
export CHOKIDAR_INTERVAL=1000
|
||||
echo "CHOKIDAR_USEPOLLING=$CHOKIDAR_USEPOLLING"
|
||||
echo "CHOKIDAR_INTERVAL=$CHOKIDAR_INTERVAL"
|
||||
|
||||
# Watchpack (used by webpack)
|
||||
export WATCHPACK_POLLING=true
|
||||
|
||||
# TypeScript watch mode - use polling instead of fs events
|
||||
export TSC_WATCHFILE=UseFsEventsWithFallbackDynamicPolling
|
||||
export TSC_WATCHDIRECTORY=UseFsEventsWithFallbackDynamicPolling
|
||||
|
||||
# Disable atomic writes so file watchers detect changes properly
|
||||
export DISABLE_ATOMICWRITES=true
|
||||
|
||||
# Set development environment (from .vscode/launch.json)
|
||||
export NODE_ENV=development
|
||||
export VSCODE_DEBUG_MODE=true
|
||||
|
||||
# Trap to clean up all background processes on exit
|
||||
cleanup() {
|
||||
echo "Stopping all processes..."
|
||||
jobs -p | xargs -r kill 2>/dev/null
|
||||
}
|
||||
trap cleanup EXIT INT TERM
|
||||
|
||||
# Build all workspace packages first
|
||||
echo ""
|
||||
echo "=============================================="
|
||||
echo "Building workspace packages..."
|
||||
echo "=============================================="
|
||||
pnpm build
|
||||
|
||||
# Start code-server in background FIRST
|
||||
echo ""
|
||||
echo "=============================================="
|
||||
echo "Starting code-server on port $PORT"
|
||||
echo "Extension files are at: $(pwd)/src"
|
||||
echo "Symlinked to: $EXT_DIR/roo-cline"
|
||||
echo "=============================================="
|
||||
code-server --auth none --bind-addr 0.0.0.0:${PORT} . &
|
||||
CODE_SERVER_PID=$!
|
||||
|
||||
# Give code-server a moment to start
|
||||
sleep 2
|
||||
|
||||
# Start watchers with explicit env vars using env command
|
||||
echo ""
|
||||
echo "=============================================="
|
||||
echo "Starting file watchers..."
|
||||
echo "=============================================="
|
||||
|
||||
# Run webview watcher (custom chokidar-based script)
|
||||
env CHOKIDAR_USEPOLLING=true CHOKIDAR_INTERVAL=1000 pnpm --filter @roo-code/vscode-webview dev:watch &
|
||||
|
||||
# Run bundle watcher (custom chokidar-based script)
|
||||
env CHOKIDAR_USEPOLLING=true CHOKIDAR_INTERVAL=1000 pnpm --filter roo-cline watch:bundle &
|
||||
|
||||
# Run tsc watcher
|
||||
env TSC_WATCHFILE=UseFsEventsWithFallbackDynamicPolling pnpm --filter roo-cline watch:tsc &
|
||||
|
||||
echo ""
|
||||
echo "=============================================="
|
||||
echo "All processes started!"
|
||||
echo "code-server running at http://localhost:${PORT}"
|
||||
echo "Watchers are running - file changes should trigger rebuilds"
|
||||
echo "Press Ctrl+C to stop all processes"
|
||||
echo "=============================================="
|
||||
echo ""
|
||||
|
||||
# Wait for all background processes
|
||||
wait
|
||||
117
src/esbuild.mjs
117
src/esbuild.mjs
|
|
@ -4,6 +4,8 @@ import * as path from "path"
|
|||
import { fileURLToPath } from "url"
|
||||
import process from "node:process"
|
||||
import * as console from "node:console"
|
||||
import { setTimeout, clearTimeout } from "node:timers"
|
||||
import chokidar from "chokidar"
|
||||
|
||||
import { copyPaths, copyWasms, copyLocales, setupLocaleWatcher } from "@roo-code/build"
|
||||
|
||||
|
|
@ -121,9 +123,122 @@ async function main() {
|
|||
])
|
||||
|
||||
if (watch) {
|
||||
await Promise.all([extensionCtx.watch(), workerCtx.watch()])
|
||||
// Use chokidar for file watching with polling support
|
||||
// This is more reliable than esbuild's native watcher in environments like code-server
|
||||
const usePolling = process.env.CHOKIDAR_USEPOLLING === "true"
|
||||
const pollInterval = parseInt(process.env.CHOKIDAR_INTERVAL || "1000", 10)
|
||||
|
||||
console.log(`[${name}] ========================================`)
|
||||
console.log(`[${name}] Starting watch mode`)
|
||||
console.log(`[${name}] CHOKIDAR_USEPOLLING: ${process.env.CHOKIDAR_USEPOLLING}`)
|
||||
console.log(`[${name}] Polling enabled: ${usePolling}`)
|
||||
console.log(`[${name}] Poll interval: ${pollInterval}ms`)
|
||||
console.log(`[${name}] Watching directory: ${srcDir}`)
|
||||
console.log(`[${name}] CWD: ${process.cwd()}`)
|
||||
console.log(`[${name}] ========================================`)
|
||||
|
||||
// Initial build
|
||||
await Promise.all([extensionCtx.rebuild(), workerCtx.rebuild()])
|
||||
copyLocales(srcDir, distDir)
|
||||
setupLocaleWatcher(srcDir, distDir)
|
||||
|
||||
// Set up chokidar watcher - watch the srcDir directly
|
||||
console.log(`[${name}] Setting up chokidar watcher...`)
|
||||
console.log(`[${name}] srcDir:`, srcDir)
|
||||
|
||||
// List files to verify they exist
|
||||
const extensionTs = path.join(srcDir, "extension.ts")
|
||||
console.log(`[${name}] extension.ts exists:`, fs.existsSync(extensionTs))
|
||||
|
||||
const watcher = chokidar.watch(srcDir, {
|
||||
ignored: (filePath) => {
|
||||
// Ignore node_modules, dist, and test files
|
||||
const relativePath = path.relative(srcDir, filePath)
|
||||
return relativePath.includes("node_modules") ||
|
||||
relativePath.includes("dist") ||
|
||||
relativePath.endsWith(".spec.ts") ||
|
||||
relativePath.endsWith(".test.ts")
|
||||
},
|
||||
persistent: true,
|
||||
usePolling,
|
||||
interval: pollInterval,
|
||||
ignoreInitial: false, // Count files during initial scan
|
||||
depth: 10,
|
||||
})
|
||||
|
||||
console.log(`[${name}] Watcher created, waiting for ready event...`)
|
||||
|
||||
let rebuildTimeout = null
|
||||
let fileCount = 0
|
||||
let isReady = false
|
||||
|
||||
const triggerRebuild = (eventType, filePath) => {
|
||||
if (!isReady) return
|
||||
|
||||
// Ignore directories that are written to during build
|
||||
const ignoredPaths = [
|
||||
"/dist/", "\\dist\\", "/dist", "\\dist",
|
||||
"/node_modules/", "\\node_modules\\",
|
||||
"/assets/", "\\assets\\",
|
||||
"/webview-ui/", "\\webview-ui\\",
|
||||
]
|
||||
for (const ignored of ignoredPaths) {
|
||||
if (filePath.includes(ignored)) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Only rebuild for .ts, .tsx source files (not .json since those can be copied)
|
||||
const shouldRebuild = (filePath.endsWith(".ts") || filePath.endsWith(".tsx")) &&
|
||||
!filePath.endsWith(".d.ts") && !filePath.endsWith(".spec.ts") && !filePath.endsWith(".test.ts")
|
||||
if (!shouldRebuild) {
|
||||
return
|
||||
}
|
||||
|
||||
// Debounce rebuilds
|
||||
if (rebuildTimeout) {
|
||||
clearTimeout(rebuildTimeout)
|
||||
}
|
||||
rebuildTimeout = setTimeout(async () => {
|
||||
console.log(`[${name}] File ${eventType}: ${path.relative(srcDir, filePath)}`)
|
||||
console.log(`[esbuild-problem-matcher#onStart]`)
|
||||
try {
|
||||
await Promise.all([extensionCtx.rebuild(), workerCtx.rebuild()])
|
||||
console.log(`[esbuild-problem-matcher#onEnd]`)
|
||||
} catch (err) {
|
||||
console.error(`[${name}] Rebuild failed:`, err.message)
|
||||
console.log(`[esbuild-problem-matcher#onEnd]`)
|
||||
}
|
||||
}, 200)
|
||||
}
|
||||
|
||||
watcher.on("change", (p) => triggerRebuild("changed", p))
|
||||
watcher.on("add", (p) => {
|
||||
if (!isReady && (p.endsWith(".ts") || p.endsWith(".tsx") || p.endsWith(".json"))) {
|
||||
fileCount++
|
||||
}
|
||||
triggerRebuild("added", p)
|
||||
})
|
||||
watcher.on("unlink", (p) => triggerRebuild("deleted", p))
|
||||
watcher.on("error", (err) => console.error(`[${name}] Watcher error:`, err))
|
||||
watcher.on("ready", () => {
|
||||
isReady = true
|
||||
console.log(`[${name}] ========================================`)
|
||||
console.log(`[${name}] Watcher ready!`)
|
||||
console.log(`[${name}] Watching ${fileCount} files`)
|
||||
console.log(`[${name}] Listening for changes...`)
|
||||
console.log(`[${name}] ========================================`)
|
||||
})
|
||||
|
||||
// Also add a raw event listener to see ALL events
|
||||
watcher.on("raw", (event, rawPath, details) => {
|
||||
if (process.env.DEBUG_WATCHER === "true") {
|
||||
console.log(`[${name}] Raw event:`, event, rawPath)
|
||||
}
|
||||
})
|
||||
|
||||
// Keep the process running
|
||||
await new Promise(() => {})
|
||||
} else {
|
||||
await Promise.all([extensionCtx.rebuild(), workerCtx.rebuild()])
|
||||
await Promise.all([extensionCtx.dispose(), workerCtx.dispose()])
|
||||
|
|
|
|||
|
|
@ -347,6 +347,11 @@ export async function activate(context: vscode.ExtensionContext) {
|
|||
// Watch the core files and automatically reload the extension host.
|
||||
if (process.env.NODE_ENV === "development") {
|
||||
const watchPaths = [
|
||||
// Watch compiled output - triggers reload when esbuild finishes a rebuild
|
||||
{ path: path.join(context.extensionPath, "dist"), pattern: "extension.js" },
|
||||
// Also watch webview build output
|
||||
{ path: path.join(context.extensionPath, "webview-ui/build"), pattern: "**/*" },
|
||||
// Watch source files for changes that might not trigger a rebuild
|
||||
{ path: context.extensionPath, pattern: "**/*.ts" },
|
||||
{ path: path.join(context.extensionPath, "../packages/types"), pattern: "**/*.ts" },
|
||||
{ path: path.join(context.extensionPath, "../packages/telemetry"), pattern: "**/*.ts" },
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
"test": "vitest run",
|
||||
"format": "prettier --write src",
|
||||
"dev": "vite",
|
||||
"dev:watch": "node watch.mjs",
|
||||
"build": "tsc -b && vite build",
|
||||
"build:nightly": "tsc -b && vite build --mode nightly",
|
||||
"preview": "vite preview",
|
||||
|
|
@ -86,6 +87,7 @@
|
|||
"devDependencies": {
|
||||
"@roo-code/config-eslint": "workspace:^",
|
||||
"@roo-code/config-typescript": "workspace:^",
|
||||
"chokidar": "^4.0.1",
|
||||
"@testing-library/jest-dom": "^6.6.3",
|
||||
"@testing-library/react": "^16.2.0",
|
||||
"@testing-library/user-event": "^14.6.1",
|
||||
|
|
|
|||
111
webview-ui/watch.mjs
Normal file
111
webview-ui/watch.mjs
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
import chokidar from "chokidar"
|
||||
import { exec } from "child_process"
|
||||
import path from "path"
|
||||
import { fileURLToPath } from "url"
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url)
|
||||
const __dirname = path.dirname(__filename)
|
||||
|
||||
const usePolling = process.env.CHOKIDAR_USEPOLLING === "true"
|
||||
const pollInterval = parseInt(process.env.CHOKIDAR_INTERVAL || "1000", 10)
|
||||
|
||||
console.log(`[webview] ========================================`)
|
||||
console.log(`[webview] Starting watch mode`)
|
||||
console.log(`[webview] Polling: ${usePolling}, Interval: ${pollInterval}ms`)
|
||||
console.log(`[webview] Watching: ${path.join(__dirname, "src")}`)
|
||||
console.log(`[webview] ========================================`)
|
||||
|
||||
let buildInProgress = false
|
||||
let pendingBuild = false
|
||||
|
||||
const runBuild = () => {
|
||||
if (buildInProgress) {
|
||||
pendingBuild = true
|
||||
return
|
||||
}
|
||||
|
||||
buildInProgress = true
|
||||
console.log(`[webview] Building...`)
|
||||
|
||||
exec("pnpm vite build", { cwd: __dirname }, (error, stdout, stderr) => {
|
||||
buildInProgress = false
|
||||
|
||||
if (error) {
|
||||
console.error(`[webview] Build failed:`, error.message)
|
||||
if (stderr) console.error(stderr)
|
||||
} else {
|
||||
console.log(`[webview] Build complete`)
|
||||
}
|
||||
|
||||
if (pendingBuild) {
|
||||
pendingBuild = false
|
||||
runBuild()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const srcDir = path.join(__dirname, "src")
|
||||
console.log(`[webview] srcDir: ${srcDir}`)
|
||||
|
||||
const watcher = chokidar.watch(srcDir, {
|
||||
ignored: (filePath) => {
|
||||
const relativePath = path.relative(srcDir, filePath)
|
||||
return relativePath.includes("node_modules") ||
|
||||
relativePath.endsWith(".spec.ts") ||
|
||||
relativePath.endsWith(".spec.tsx") ||
|
||||
relativePath.endsWith(".test.ts") ||
|
||||
relativePath.endsWith(".test.tsx")
|
||||
},
|
||||
persistent: true,
|
||||
usePolling,
|
||||
interval: pollInterval,
|
||||
ignoreInitial: false, // Count files during initial scan
|
||||
depth: 10,
|
||||
})
|
||||
|
||||
let fileCount = 0
|
||||
let isReady = false
|
||||
|
||||
let debounceTimeout = null
|
||||
watcher.on("change", (filePath) => {
|
||||
if (!isReady) return
|
||||
if (debounceTimeout) clearTimeout(debounceTimeout)
|
||||
debounceTimeout = setTimeout(() => {
|
||||
console.log(`[webview] File changed: ${filePath}`)
|
||||
runBuild()
|
||||
}, 200)
|
||||
})
|
||||
|
||||
watcher.on("add", (filePath) => {
|
||||
if (!isReady) {
|
||||
fileCount++
|
||||
return
|
||||
}
|
||||
if (debounceTimeout) clearTimeout(debounceTimeout)
|
||||
debounceTimeout = setTimeout(() => {
|
||||
console.log(`[webview] File added: ${filePath}`)
|
||||
runBuild()
|
||||
}, 200)
|
||||
})
|
||||
|
||||
watcher.on("unlink", (filePath) => {
|
||||
if (!isReady) return
|
||||
if (debounceTimeout) clearTimeout(debounceTimeout)
|
||||
debounceTimeout = setTimeout(() => {
|
||||
console.log(`[webview] File deleted: ${filePath}`)
|
||||
runBuild()
|
||||
}, 200)
|
||||
})
|
||||
|
||||
watcher.on("ready", () => {
|
||||
isReady = true
|
||||
console.log(`[webview] ========================================`)
|
||||
console.log(`[webview] Watcher ready!`)
|
||||
console.log(`[webview] Watching ${fileCount} files`)
|
||||
console.log(`[webview] Listening for changes...`)
|
||||
console.log(`[webview] ========================================`)
|
||||
})
|
||||
|
||||
watcher.on("error", (error) => {
|
||||
console.error(`[webview] Watcher error:`, error)
|
||||
})
|
||||
Loading…
Add table
Reference in a new issue