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
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
"clean": "turbo clean --log-order grouped --output-logs new-only && rimraf dist out bin .vite-port .turbo",
"install:vsix": "pnpm install --frozen-lockfile && pnpm clean && pnpm vsix && node scripts/install-vsix.js",
"install:vsix:nightly": "pnpm install --frozen-lockfile && pnpm clean && pnpm vsix:nightly && node scripts/install-vsix.js --nightly",
"serve": "node scripts/serve.js",
"serve:install": "node scripts/serve.js --install-only",
"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",
Expand Down
233 changes: 233 additions & 0 deletions scripts/serve.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,233 @@
/**
* Serve script for Roo Code extension development
*
* This script manages code-server for web-based VS Code testing.
*
* Prerequisites:
* brew install code-server
*
* Usage:
* pnpm serve # Start code-server on port 9080
* pnpm serve -- --port 8080 # Use a custom port
* pnpm serve -- --host 0.0.0.0 # Bind to all interfaces (for Docker/remote access)
* pnpm serve -- --auth none # Disable authentication (password|none)
* pnpm serve:install # Build and install the extension into code-server
*
* Workflow:
* 1. Run `pnpm serve:install` to build and install the extension
* 2. Run `pnpm serve` to start code-server
* 3. After code changes, run `pnpm serve:install` again and reload the window
* (Cmd+Shift+P → "Developer: Reload Window")
*
* Your password is stored in ~/.config/code-server/config.yaml
*/

const { execSync, spawn } = require("child_process")
const fs = require("fs")
const path = require("path")
const os = require("os")

const RESET = "\x1b[0m"
const BOLD = "\x1b[1m"
const GREEN = "\x1b[32m"
const YELLOW = "\x1b[33m"
const CYAN = "\x1b[36m"
const RED = "\x1b[31m"

// Build vsix to a fixed path in temp directory
const VSIX_PATH = path.join(os.tmpdir(), "roo-code-serve.vsix")

// Parse command line flags
const installOnly = process.argv.includes("--install-only")

// Parse --port argument (default: 9080)
const DEFAULT_PORT = 9080
function getPort() {
const portIndex = process.argv.indexOf("--port")
if (portIndex !== -1 && process.argv[portIndex + 1]) {
const port = parseInt(process.argv[portIndex + 1], 10)
if (!isNaN(port) && port > 0 && port < 65536) {
return port
}
}
return DEFAULT_PORT
}
const port = getPort()

// Parse --host argument (default: 127.0.0.1, use 0.0.0.0 for Docker/remote access)
const DEFAULT_HOST = "127.0.0.1"
function getHost() {
const hostIndex = process.argv.indexOf("--host")
if (hostIndex !== -1 && process.argv[hostIndex + 1]) {
return process.argv[hostIndex + 1]
}
return DEFAULT_HOST
}
const host = getHost()

// Parse --auth argument (optional, passed to code-server: "password" or "none")
function getAuth() {
const authIndex = process.argv.indexOf("--auth")
if (authIndex !== -1 && process.argv[authIndex + 1]) {
return process.argv[authIndex + 1]
}
return null
}
const auth = getAuth()

function log(message) {
console.log(`${CYAN}[serve]${RESET} ${message}`)
}

function logSuccess(message) {
console.log(`${GREEN}✓${RESET} ${message}`)
}

function logWarning(message) {
console.log(`${YELLOW}⚠${RESET} ${message}`)
}

function logError(message) {
console.error(`${RED}✗${RESET} ${message}`)
}

function isCodeServerInstalled() {
try {
execSync("which code-server", { stdio: "pipe" })
return true
} catch {
return false
}
}

function ensureUserSettings() {
// code-server stores user data in ~/.local/share/code-server
const userDataDir = path.join(process.env.HOME || process.env.USERPROFILE, ".local", "share", "code-server", "User")
const settingsFile = path.join(userDataDir, "settings.json")

// Create directory if it doesn't exist
if (!fs.existsSync(userDataDir)) {
fs.mkdirSync(userDataDir, { recursive: true })
}

// Read existing settings or start fresh
let settings = {}
if (fs.existsSync(settingsFile)) {
try {
settings = JSON.parse(fs.readFileSync(settingsFile, "utf8"))
} catch {
// If parsing fails, start fresh
}
}

// Set the startup editor to none (disables welcome tab)
settings["workbench.startupEditor"] = "none"

// Hide the secondary sidebar (auxiliary bar)
settings["workbench.auxiliaryBar.visible"] = false

// Disable extension recommendations prompts
settings["extensions.ignoreRecommendations"] = true

fs.writeFileSync(settingsFile, JSON.stringify(settings, null, "\t"))
}

async function main() {
// Check if code-server is installed
log("Checking for code-server...")
if (!isCodeServerInstalled()) {
logError("code-server is not installed")
console.log("\nTo install code-server on macOS:")
console.log(` ${CYAN}brew install code-server${RESET}`)
console.log("\nFor other platforms, see: https://coder.com/docs/code-server/install")
process.exit(1)
}
logSuccess("code-server found")

// If install-only mode, build and install the extension
if (installOnly) {
console.log(`\n${BOLD}🔧 Roo Code - Install Extension${RESET}\n`)

// Build vsix to temp directory
log(`Building vsix to ${VSIX_PATH}...`)
try {
execSync(`pnpm vsix -- --out "${VSIX_PATH}"`, { stdio: "inherit" })
logSuccess("Build complete")
} catch (error) {
logError("Build failed")
process.exit(1)
}

// Install extension into code-server
log("Installing extension into code-server...")
try {
execSync(`code-server --install-extension "${VSIX_PATH}"`, { stdio: "inherit" })
logSuccess("Extension installed")
} catch (error) {
logWarning("Extension installation had warnings (this is usually fine)")
}

// Configure user settings to disable welcome tab
log("Configuring user settings...")
ensureUserSettings()
logSuccess("User settings configured (welcome tab disabled)")

console.log(`\n${GREEN}✓ Extension built and installed.${RESET}`)
console.log(` If code-server is running, reload the window to pick up changes.`)
console.log(` (Cmd+Shift+P → "Developer: Reload Window")\n`)
return
}

// Default: Start code-server
console.log(`\n${BOLD}🚀 Roo Code - code-server Development Server${RESET}\n`)
const cwd = process.cwd()
console.log(`\n${BOLD}Starting code-server...${RESET}`)
console.log(` Working directory: ${cwd}`)
console.log(` URL: ${CYAN}http://${host}:${port}${RESET}`)
if (auth === "none") {
console.log(` Auth: ${YELLOW}disabled${RESET}`)
} else {
console.log(` Password: ${YELLOW}~/.config/code-server/config.yaml${RESET}`)
}
console.log(`\n Press ${BOLD}Ctrl+C${RESET} to stop\n`)

// Spawn code-server with:
// --bind-addr: Address to bind to
// --auth: Authentication type (password or none)
// --disable-workspace-trust: Skip workspace trust prompts
// --disable-getting-started-override: Disable welcome/getting started page
// -e: Ignore last opened directory (start fresh)
const args = ["--bind-addr", `${host}:${port}`]
if (auth) {
args.push("--auth", auth)
}
args.push("--disable-workspace-trust", "--disable-getting-started-override", "-e", cwd)

const codeServer = spawn("code-server", args, {
stdio: "inherit",
cwd: cwd,
})

codeServer.on("error", (err) => {
logError(`Failed to start code-server: ${err.message}`)
process.exit(1)
})

codeServer.on("close", (code) => {
if (code !== 0 && code !== null) {
logError(`code-server exited with code ${code}`)
}
})

// Handle Ctrl+C gracefully
process.on("SIGINT", () => {
console.log("\n")
log("Shutting down code-server...")
codeServer.kill("SIGTERM")
})
}

main().catch((error) => {
logError(error.message)
process.exit(1)
})
Loading