Some cleanup

This commit is contained in:
cte 2026-01-11 00:00:44 -08:00
parent 22fa95f692
commit 844de64153
9 changed files with 11 additions and 118 deletions

View file

@ -1,20 +1,13 @@
/**
* Tests for RooCodeAgent
*/
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"
import type * as acp from "@agentclientprotocol/sdk"
import { RooCodeAgent, type RooCodeAgentOptions } from "../agent.js"
// Mock the auth module
vi.mock("@/commands/auth/index.js", () => ({
login: vi.fn().mockResolvedValue({ success: true }),
logout: vi.fn().mockResolvedValue({ success: true }),
status: vi.fn().mockResolvedValue({ authenticated: false }),
}))
// Mock AcpSession
vi.mock("../session.js", () => ({
AcpSession: {
create: vi.fn().mockResolvedValue({
@ -40,7 +33,6 @@ describe("RooCodeAgent", () => {
}
beforeEach(() => {
// Create a mock connection
mockConnection = {
sessionUpdate: vi.fn().mockResolvedValue(undefined),
requestPermission: vi.fn().mockResolvedValue({

View file

@ -1,4 +1,3 @@
import { describe, it, expect, beforeEach } from "vitest"
import { DeltaTracker } from "../delta-tracker.js"
describe("DeltaTracker", () => {

View file

@ -1,11 +1,5 @@
/**
* Tests for AcpSession
*/
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"
import type * as acp from "@agentclientprotocol/sdk"
// Mock the ExtensionHost before importing AcpSession
vi.mock("@/agent/extension-host.js", () => {
const mockClient = {
on: vi.fn().mockReturnThis(),
@ -25,7 +19,6 @@ vi.mock("@/agent/extension-host.js", () => {
}
})
// Import after mocking
import { AcpSession, type AcpSessionOptions } from "../session.js"
import { ExtensionHost } from "@/agent/extension-host.js"
@ -41,7 +34,6 @@ describe("AcpSession", () => {
}
beforeEach(() => {
// Create a mock connection
mockConnection = {
sessionUpdate: vi.fn().mockResolvedValue(undefined),
requestPermission: vi.fn().mockResolvedValue({

View file

@ -1,8 +1,3 @@
/**
* Tests for ACP Message Translator
*/
import { describe, it, expect } from "vitest"
import type { ClineMessage } from "@roo-code/types"
import {

View file

@ -1,10 +1,3 @@
/**
* Tests for UpdateBuffer
*
* Verifies that the buffer correctly batches text chunk updates
* while passing through other updates immediately.
*/
import type * as acp from "@agentclientprotocol/sdk"
import { UpdateBuffer } from "../update-buffer.js"

View file

@ -1,22 +1,2 @@
/**
* ACP (Agent Client Protocol) Integration Module
*
* This module provides ACP support for the Roo Code CLI, allowing ACP-compatible
* clients like Zed to use Roo Code as their AI coding assistant.
*
* Main components:
* - RooCodeAgent: Implements the acp.Agent interface
* - AcpSession: Wraps ExtensionHost for individual sessions
* - Translator: Converts between internal and ACP message formats
* - UpdateBuffer: Batches session updates to reduce message frequency
* - acpLog: File-based logger for debugging (writes to ~/.roo/acp.log)
*
* Note: Commands are executed internally by the extension (like the reference
* implementations gemini-cli and opencode), not through ACP terminals.
*/
export { RooCodeAgent, type RooCodeAgentOptions } from "./agent.js"
export { AcpSession, type AcpSessionOptions } from "./session.js"
export { UpdateBuffer, type UpdateBufferOptions } from "./update-buffer.js"
export { type RooCodeAgentOptions, RooCodeAgent } from "./agent.js"
export { acpLog } from "./logger.js"
export * from "./translator.js"

View file

@ -1,70 +1,30 @@
/**
* ACP Command
*
* Starts the Roo Code CLI in ACP server mode, allowing ACP-compatible clients
* like Zed to use Roo Code as their AI coding assistant.
*
* Usage:
* roo acp [options]
*
* The ACP server communicates over stdin/stdout using the ACP protocol
* (JSON-RPC over newline-delimited JSON).
*/
import { Readable, Writable } from "node:stream"
import path from "node:path"
import { fileURLToPath } from "node:url"
import * as acpSdk from "@agentclientprotocol/sdk"
import { type RooCodeAgentOptions, RooCodeAgent, acpLog } from "@/acp/index.js"
import { DEFAULT_FLAGS } from "@/types/constants.js"
import { type SupportedProvider, DEFAULT_FLAGS } from "@/types/index.js"
import { getDefaultExtensionPath } from "@/lib/utils/extension.js"
// =============================================================================
// Types
// =============================================================================
import { type RooCodeAgentOptions, RooCodeAgent, acpLog } from "@/acp/index.js"
export interface AcpCommandOptions {
/** Path to the extension bundle directory */
extension?: string
/** API provider (anthropic, openai, openrouter, etc.) */
provider?: string
/** Model to use */
provider?: SupportedProvider
model?: string
/** Initial mode (code, architect, ask, debug) */
mode?: string
/** API key */
apiKey?: string
}
// =============================================================================
// ACP Server
// =============================================================================
/**
* Run the ACP server.
*
* This sets up the ACP connection using stdin/stdout and creates a RooCodeAgent
* to handle incoming requests.
*/
export async function runAcpServer(options: AcpCommandOptions): Promise<void> {
acpLog.info("Command", "Starting ACP server")
acpLog.debug("Command", "Options", options)
// Resolve extension path
const __dirname = path.dirname(fileURLToPath(import.meta.url))
const extensionPath = options.extension || getDefaultExtensionPath(__dirname)
if (!extensionPath) {
acpLog.error("Command", "Extension path not found")
console.error("Error: Extension path not found. Use --extension to specify the path.")
process.exit(1)
}
acpLog.info("Command", `Extension path: ${extensionPath}`)
// Create agent options
const agentOptions: RooCodeAgentOptions = {
extensionPath,
provider: options.provider || DEFAULT_FLAGS.provider,
@ -73,24 +33,14 @@ export async function runAcpServer(options: AcpCommandOptions): Promise<void> {
apiKey: options.apiKey || process.env.OPENROUTER_API_KEY,
}
acpLog.debug("Command", "Agent options", {
extensionPath: agentOptions.extensionPath,
provider: agentOptions.provider,
model: agentOptions.model,
mode: agentOptions.mode,
hasApiKey: !!agentOptions.apiKey,
})
// Set up stdio streams for ACP communication
// Note: We write to stdout (agent -> client) and read from stdin (client -> agent)
// Set up stdio streams for ACP communication.
// Note: We write to stdout (agent -> client) and read from stdin (client -> agent).
const stdout = Writable.toWeb(process.stdout) as WritableStream<Uint8Array>
const stdin = Readable.toWeb(process.stdin) as ReadableStream<Uint8Array>
// Create the ACP stream
const stream = acpSdk.ndJsonStream(stdout, stdin)
acpLog.info("Command", "ACP stream created, waiting for connection")
// Create the agent connection
let agent: RooCodeAgent | null = null
const connection = new acpSdk.AgentSideConnection((conn: acpSdk.AgentSideConnection) => {
@ -99,12 +49,13 @@ export async function runAcpServer(options: AcpCommandOptions): Promise<void> {
return agent
}, stream)
// Handle graceful shutdown
const cleanup = async () => {
acpLog.info("Command", "Received shutdown signal, cleaning up")
if (agent) {
await agent.dispose()
}
acpLog.info("Command", "Cleanup complete, exiting")
process.exit(0)
}
@ -112,26 +63,17 @@ export async function runAcpServer(options: AcpCommandOptions): Promise<void> {
process.on("SIGINT", cleanup)
process.on("SIGTERM", cleanup)
// Wait for the connection to close
acpLog.info("Command", "Waiting for connection to close")
await connection.closed
acpLog.info("Command", "Connection closed")
}
// =============================================================================
// Command Action
// =============================================================================
/**
* Action handler for the `roo acp` command.
*/
export async function acp(options: AcpCommandOptions): Promise<void> {
try {
await runAcpServer(options)
} catch (error) {
// Log errors to file and stderr so they don't interfere with ACP protocol
acpLog.error("Command", "Fatal error", error)
console.error("[ACP] Fatal error:", error)
console.error(error)
process.exit(1)
}
}

View file

@ -1,2 +1,3 @@
export * from "./auth/index.js"
export * from "./cli/index.js"
export * from "./acp/index.js"

View file

@ -2,8 +2,7 @@ import { Command } from "commander"
import { DEFAULT_FLAGS } from "@/types/constants.js"
import { VERSION } from "@/lib/utils/version.js"
import { run, login, logout, status } from "@/commands/index.js"
import { acp } from "@/commands/acp/index.js"
import { run, login, logout, status, acp } from "@/commands/index.js"
const program = new Command()