mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-08-28 05:27:24 +00:00
163 lines
5.1 KiB
TypeScript
163 lines
5.1 KiB
TypeScript
/**
|
|
* @roo-code/cli - Command Line Interface for Roo Code
|
|
*/
|
|
|
|
import { Command } from "commander"
|
|
import fs from "fs"
|
|
import path from "path"
|
|
import { fileURLToPath } from "url"
|
|
|
|
import {
|
|
type ProviderName,
|
|
type ReasoningEffortExtended,
|
|
isProviderName,
|
|
reasoningEffortsExtended,
|
|
} from "@roo-code/types"
|
|
import { setLogger } from "@roo-code/vscode-shim"
|
|
|
|
import { ExtensionHost } from "./extension-host.js"
|
|
import { getEnvVarName, getApiKeyFromEnv, getDefaultExtensionPath } from "./utils.js"
|
|
|
|
const DEFAULTS = {
|
|
mode: "code",
|
|
reasoningEffort: "medium" as const,
|
|
model: "anthropic/claude-opus-4.5",
|
|
}
|
|
|
|
const REASONING_EFFORTS = [...reasoningEffortsExtended, "unspecified", "disabled"]
|
|
|
|
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
|
|
|
const program = new Command()
|
|
|
|
program.name("roo").description("Roo Code CLI - Run the Roo Code agent from the command line").version("0.1.0")
|
|
|
|
program
|
|
.argument("<prompt>", "The prompt/task to execute")
|
|
.option("-w, --workspace <path>", "Workspace path to operate in", process.cwd())
|
|
.option("-e, --extension <path>", "Path to the extension bundle directory")
|
|
.option("-v, --verbose", "Enable verbose output (show VSCode and extension logs)", false)
|
|
.option("-d, --debug", "Enable debug output (includes detailed debug information)", false)
|
|
.option("-x, --exit-on-complete", "Exit the process when the task completes (useful for testing)", false)
|
|
.option("-y, --yes", "Auto-approve all prompts (non-interactive mode)", false)
|
|
.option("-k, --api-key <key>", "API key for the LLM provider (defaults to ANTHROPIC_API_KEY env var)")
|
|
.option("-p, --provider <provider>", "API provider (anthropic, openai, openrouter, etc.)", "openrouter")
|
|
.option("-m, --model <model>", "Model to use", DEFAULTS.model)
|
|
.option("-M, --mode <mode>", "Mode to start in (code, architect, ask, debug, etc.)", DEFAULTS.mode)
|
|
.option(
|
|
"-r, --reasoning-effort <effort>",
|
|
"Reasoning effort level (unspecified, disabled, none, minimal, low, medium, high, xhigh)",
|
|
DEFAULTS.reasoningEffort,
|
|
)
|
|
.action(
|
|
async (
|
|
prompt: string,
|
|
options: {
|
|
workspace: string
|
|
extension?: string
|
|
verbose: boolean
|
|
debug: boolean
|
|
exitOnComplete: boolean
|
|
yes: boolean
|
|
apiKey?: string
|
|
provider: ProviderName
|
|
model?: string
|
|
mode?: string
|
|
reasoningEffort?: ReasoningEffortExtended | "unspecified" | "disabled"
|
|
},
|
|
) => {
|
|
// Default is quiet mode - suppress VSCode shim logs unless verbose
|
|
// or debug is specified.
|
|
if (!options.verbose && !options.debug) {
|
|
setLogger({
|
|
info: () => {},
|
|
warn: () => {},
|
|
error: () => {},
|
|
debug: () => {},
|
|
})
|
|
}
|
|
|
|
const extensionPath = options.extension || getDefaultExtensionPath(__dirname)
|
|
const apiKey = options.apiKey || getApiKeyFromEnv(options.provider)
|
|
const workspacePath = path.resolve(options.workspace)
|
|
|
|
if (!apiKey) {
|
|
console.error(
|
|
`[CLI] Error: No API key provided. Use --api-key or set the appropriate environment variable.`,
|
|
)
|
|
console.error(`[CLI] For ${options.provider}, set ${getEnvVarName(options.provider)}`)
|
|
process.exit(1)
|
|
}
|
|
|
|
if (!fs.existsSync(workspacePath)) {
|
|
console.error(`[CLI] Error: Workspace path does not exist: ${workspacePath}`)
|
|
process.exit(1)
|
|
}
|
|
|
|
if (!isProviderName(options.provider)) {
|
|
console.error(`[CLI] Error: Invalid provider: ${options.provider}`)
|
|
process.exit(1)
|
|
}
|
|
|
|
if (options.reasoningEffort && !REASONING_EFFORTS.includes(options.reasoningEffort)) {
|
|
console.error(
|
|
`[CLI] Error: Invalid reasoning effort: ${options.reasoningEffort}, must be one of: ${REASONING_EFFORTS.join(", ")}`,
|
|
)
|
|
process.exit(1)
|
|
}
|
|
|
|
console.log(`[CLI] Mode: ${options.mode || "default"}`)
|
|
console.log(`[CLI] Reasoning Effort: ${options.reasoningEffort || "default"}`)
|
|
console.log(`[CLI] Provider: ${options.provider}`)
|
|
console.log(`[CLI] Model: ${options.model || "default"}`)
|
|
console.log(`[CLI] Workspace: ${workspacePath}`)
|
|
|
|
const host = new ExtensionHost({
|
|
mode: options.mode || DEFAULTS.mode,
|
|
reasoningEffort: options.reasoningEffort === "unspecified" ? undefined : options.reasoningEffort,
|
|
apiProvider: options.provider,
|
|
apiKey,
|
|
model: options.model || DEFAULTS.model,
|
|
workspacePath,
|
|
extensionPath: path.resolve(extensionPath),
|
|
verbose: options.debug,
|
|
quiet: !options.verbose && !options.debug,
|
|
nonInteractive: options.yes,
|
|
})
|
|
|
|
// Handle SIGINT (Ctrl+C)
|
|
process.on("SIGINT", async () => {
|
|
console.log("\n[CLI] Received SIGINT, shutting down...")
|
|
await host.dispose()
|
|
process.exit(130)
|
|
})
|
|
|
|
// Handle SIGTERM
|
|
process.on("SIGTERM", async () => {
|
|
console.log("\n[CLI] Received SIGTERM, shutting down...")
|
|
await host.dispose()
|
|
process.exit(143)
|
|
})
|
|
|
|
try {
|
|
await host.activate()
|
|
await host.runTask(prompt)
|
|
await host.dispose()
|
|
|
|
if (options.exitOnComplete) {
|
|
process.exit(0)
|
|
}
|
|
} catch (error) {
|
|
console.error("[CLI] Error:", error instanceof Error ? error.message : String(error))
|
|
|
|
if (options.debug && error instanceof Error) {
|
|
console.error(error.stack)
|
|
}
|
|
|
|
await host.dispose()
|
|
process.exit(1)
|
|
}
|
|
},
|
|
)
|
|
|
|
program.parse()
|