Add cli types (#11781)

This commit is contained in:
Chris Estreich 2026-02-26 22:06:55 -08:00 committed by GitHub
parent 50c8101754
commit b55409c0b0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 291 additions and 62 deletions

View file

@ -156,7 +156,7 @@ export class JsonEventEmitter {
emitControl(event: {
subtype: "ack" | "done" | "error"
requestId?: string
command?: string
command?: JsonEvent["command"]
taskId?: string
content?: string
success?: boolean

View file

@ -1,7 +1,12 @@
import { createInterface } from "readline"
import { randomUUID } from "crypto"
import type { RooCodeSettings } from "@roo-code/types"
import {
rooCliCommandNames,
type RooCliCommandName,
type RooCliInputCommand,
type RooCliStartCommand,
} from "@roo-code/types"
import { isRecord } from "@/lib/utils/guards.js"
@ -12,20 +17,15 @@ import type { JsonEventEmitter } from "@/agent/json-event-emitter.js"
// Types
// ---------------------------------------------------------------------------
export type StdinStreamCommandName = "start" | "message" | "cancel" | "ping" | "shutdown"
export type StdinStreamCommandName = RooCliCommandName
export type StdinStreamCommand =
| { command: "start"; requestId: string; prompt: string; configuration?: RooCodeSettings }
| { command: "message"; requestId: string; prompt: string }
| { command: "cancel"; requestId: string }
| { command: "ping"; requestId: string }
| { command: "shutdown"; requestId: string }
export type StdinStreamCommand = RooCliInputCommand
// ---------------------------------------------------------------------------
// Parsing
// ---------------------------------------------------------------------------
export const VALID_STDIN_COMMANDS = new Set<StdinStreamCommandName>(["start", "message", "cancel", "ping", "shutdown"])
export const VALID_STDIN_COMMANDS = new Set<StdinStreamCommandName>(rooCliCommandNames)
export function parseStdinStreamCommand(line: string, lineNumber: number): StdinStreamCommand {
let parsed: unknown
@ -67,7 +67,12 @@ export function parseStdinStreamCommand(line: string, lineNumber: number): Stdin
}
if (command === "start" && isRecord(parsed.configuration)) {
return { command, requestId, prompt: promptRaw, configuration: parsed.configuration as RooCodeSettings }
return {
command,
requestId,
prompt: promptRaw,
configuration: parsed.configuration as RooCliStartCommand["configuration"],
}
}
return { command, requestId, prompt: promptRaw }

View file

@ -1,3 +1,15 @@
import {
rooCliOutputFormats,
type RooCliCost,
type RooCliEventType,
type RooCliFinalOutput,
type RooCliOutputFormat,
type RooCliQueueItem,
type RooCliStreamEvent,
type RooCliToolResult,
type RooCliToolUse,
} from "@roo-code/types"
/**
* JSON Event Types for Structured CLI Output
*
@ -14,9 +26,9 @@
/**
* Output format options for the CLI.
*/
export const OUTPUT_FORMATS = ["text", "json", "stream-json"] as const
export const OUTPUT_FORMATS = rooCliOutputFormats
export type OutputFormat = (typeof OUTPUT_FORMATS)[number]
export type OutputFormat = RooCliOutputFormat
export function isValidOutputFormat(format: string): format is OutputFormat {
return (OUTPUT_FORMATS as readonly string[]).includes(format)
@ -25,66 +37,24 @@ export function isValidOutputFormat(format: string): format is OutputFormat {
/**
* Event type discriminators for JSON output.
*/
export type JsonEventType =
| "system" // System messages (init, ready, shutdown)
| "control" // Transport/control protocol events
| "queue" // Message queue telemetry from extension state
| "assistant" // Assistant text messages
| "user" // User messages (echoed input)
| "tool_use" // Tool invocations (file ops, commands, browser, MCP)
| "tool_result" // Results from tool execution
| "thinking" // Reasoning/thinking content
| "error" // Errors
| "result" // Final task result
export type JsonEventType = RooCliEventType
export interface JsonEventQueueItem {
/** Queue item id generated by MessageQueueService */
id: string
/** Queued text prompt preview */
text?: string
/** Number of attached images in the queued message */
imageCount?: number
/** Queue insertion/update timestamp (ms epoch) */
timestamp?: number
}
export type JsonEventQueueItem = RooCliQueueItem
/**
* Tool use information for tool_use events.
*/
export interface JsonEventToolUse {
/** Tool name (e.g., "read_file", "write_to_file", "execute_command") */
name: string
/** Tool input parameters */
input?: Record<string, unknown>
}
export type JsonEventToolUse = RooCliToolUse
/**
* Tool result information for tool_result events.
*/
export interface JsonEventToolResult {
/** Tool name that produced this result */
name: string
/** Tool output (for successful execution) */
output?: string
/** Error message (for failed execution) */
error?: string
}
export type JsonEventToolResult = RooCliToolResult
/**
* Cost and token usage information.
*/
export interface JsonEventCost {
/** Total cost in USD */
totalCost?: number
/** Input tokens used */
inputTokens?: number
/** Output tokens generated */
outputTokens?: number
/** Cache write tokens */
cacheWrites?: number
/** Cache read tokens */
cacheReads?: number
}
export type JsonEventCost = RooCliCost
/**
* Base JSON event structure.
@ -94,7 +64,7 @@ export interface JsonEventCost {
* - Each delta includes `id` for easy correlation
* - Final message has `done: true`
*/
export interface JsonEvent {
export type JsonEvent = RooCliStreamEvent & {
/** Event type discriminator */
type: JsonEventType
/** Protocol schema version (included on system.init) */
@ -137,7 +107,7 @@ export interface JsonEvent {
* Final JSON output for "json" mode (single object at end).
* Contains the result and accumulated messages.
*/
export interface JsonFinalOutput {
export type JsonFinalOutput = RooCliFinalOutput & {
/** Final result type */
type: "result"
/** Whether the task succeeded */

View file

@ -0,0 +1,80 @@
import {
rooCliControlEventSchema,
rooCliFinalOutputSchema,
rooCliInputCommandSchema,
rooCliStreamEventSchema,
} from "../cli.js"
describe("CLI types", () => {
describe("rooCliInputCommandSchema", () => {
it("validates a start command", () => {
const result = rooCliInputCommandSchema.safeParse({
command: "start",
requestId: "req-1",
prompt: "hello",
configuration: {},
})
expect(result.success).toBe(true)
})
it("rejects a message command without prompt", () => {
const result = rooCliInputCommandSchema.safeParse({
command: "message",
requestId: "req-2",
})
expect(result.success).toBe(false)
})
})
describe("rooCliControlEventSchema", () => {
it("validates a control done event", () => {
const result = rooCliControlEventSchema.safeParse({
type: "control",
subtype: "done",
requestId: "req-3",
command: "start",
success: true,
code: "task_completed",
})
expect(result.success).toBe(true)
})
it("rejects control event without requestId", () => {
const result = rooCliControlEventSchema.safeParse({
type: "control",
subtype: "ack",
})
expect(result.success).toBe(false)
})
})
describe("rooCliStreamEventSchema", () => {
it("accepts passthrough fields for forward compatibility", () => {
const result = rooCliStreamEventSchema.safeParse({
type: "assistant",
id: 42,
content: "partial",
customField: "future",
})
expect(result.success).toBe(true)
})
})
describe("rooCliFinalOutputSchema", () => {
it("validates final json output shape", () => {
const result = rooCliFinalOutputSchema.safeParse({
type: "result",
success: true,
content: "done",
events: [],
})
expect(result.success).toBe(true)
})
})
})

173
packages/types/src/cli.ts Normal file
View file

@ -0,0 +1,173 @@
import { z } from "zod"
import { rooCodeSettingsSchema } from "./global-settings.js"
/**
* Roo CLI stdin commands
*/
export const rooCliCommandNames = ["start", "message", "cancel", "ping", "shutdown"] as const
export const rooCliCommandNameSchema = z.enum(rooCliCommandNames)
export type RooCliCommandName = z.infer<typeof rooCliCommandNameSchema>
export const rooCliCommandBaseSchema = z.object({
command: rooCliCommandNameSchema,
requestId: z.string().min(1),
})
export type RooCliCommandBase = z.infer<typeof rooCliCommandBaseSchema>
export const rooCliStartCommandSchema = rooCliCommandBaseSchema.extend({
command: z.literal("start"),
prompt: z.string(),
configuration: rooCodeSettingsSchema.optional(),
})
export type RooCliStartCommand = z.infer<typeof rooCliStartCommandSchema>
export const rooCliMessageCommandSchema = rooCliCommandBaseSchema.extend({
command: z.literal("message"),
prompt: z.string(),
})
export type RooCliMessageCommand = z.infer<typeof rooCliMessageCommandSchema>
export const rooCliCancelCommandSchema = rooCliCommandBaseSchema.extend({
command: z.literal("cancel"),
})
export type RooCliCancelCommand = z.infer<typeof rooCliCancelCommandSchema>
export const rooCliPingCommandSchema = rooCliCommandBaseSchema.extend({
command: z.literal("ping"),
})
export type RooCliPingCommand = z.infer<typeof rooCliPingCommandSchema>
export const rooCliShutdownCommandSchema = rooCliCommandBaseSchema.extend({
command: z.literal("shutdown"),
})
export type RooCliShutdownCommand = z.infer<typeof rooCliShutdownCommandSchema>
export const rooCliInputCommandSchema = z.discriminatedUnion("command", [
rooCliStartCommandSchema,
rooCliMessageCommandSchema,
rooCliCancelCommandSchema,
rooCliPingCommandSchema,
rooCliShutdownCommandSchema,
])
export type RooCliInputCommand = z.infer<typeof rooCliInputCommandSchema>
/**
* Roo CLI stream-json output
*/
export const rooCliOutputFormats = ["text", "json", "stream-json"] as const
export const rooCliOutputFormatSchema = z.enum(rooCliOutputFormats)
export type RooCliOutputFormat = z.infer<typeof rooCliOutputFormatSchema>
export const rooCliEventTypes = [
"system",
"control",
"queue",
"assistant",
"user",
"tool_use",
"tool_result",
"thinking",
"error",
"result",
] as const
export const rooCliEventTypeSchema = z.enum(rooCliEventTypes)
export type RooCliEventType = z.infer<typeof rooCliEventTypeSchema>
export const rooCliControlSubtypes = ["ack", "done", "error"] as const
export const rooCliControlSubtypeSchema = z.enum(rooCliControlSubtypes)
export type RooCliControlSubtype = z.infer<typeof rooCliControlSubtypeSchema>
export const rooCliQueueItemSchema = z.object({
id: z.string().min(1),
text: z.string().optional(),
imageCount: z.number().optional(),
timestamp: z.number().optional(),
})
export type RooCliQueueItem = z.infer<typeof rooCliQueueItemSchema>
export const rooCliToolUseSchema = z.object({
name: z.string(),
input: z.record(z.unknown()).optional(),
})
export type RooCliToolUse = z.infer<typeof rooCliToolUseSchema>
export const rooCliToolResultSchema = z.object({
name: z.string(),
output: z.string().optional(),
error: z.string().optional(),
})
export type RooCliToolResult = z.infer<typeof rooCliToolResultSchema>
export const rooCliCostSchema = z.object({
totalCost: z.number().optional(),
inputTokens: z.number().optional(),
outputTokens: z.number().optional(),
cacheWrites: z.number().optional(),
cacheReads: z.number().optional(),
})
export type RooCliCost = z.infer<typeof rooCliCostSchema>
export const rooCliStreamEventSchema = z
.object({
type: rooCliEventTypeSchema.optional(),
subtype: z.string().optional(),
requestId: z.string().optional(),
command: rooCliCommandNameSchema.optional(),
taskId: z.string().optional(),
code: z.string().optional(),
content: z.string().optional(),
success: z.boolean().optional(),
id: z.number().optional(),
done: z.boolean().optional(),
queueDepth: z.number().optional(),
queue: z.array(rooCliQueueItemSchema).optional(),
schemaVersion: z.number().optional(),
protocol: z.string().optional(),
capabilities: z.array(z.string()).optional(),
tool_use: rooCliToolUseSchema.optional(),
tool_result: rooCliToolResultSchema.optional(),
cost: rooCliCostSchema.optional(),
})
.passthrough()
export type RooCliStreamEvent = z.infer<typeof rooCliStreamEventSchema>
export const rooCliControlEventSchema = rooCliStreamEventSchema.extend({
type: z.literal("control"),
subtype: rooCliControlSubtypeSchema,
requestId: z.string().min(1),
})
export type RooCliControlEvent = z.infer<typeof rooCliControlEventSchema>
export const rooCliFinalOutputSchema = z.object({
type: z.literal("result"),
success: z.boolean(),
content: z.string().optional(),
cost: rooCliCostSchema.optional(),
events: z.array(rooCliStreamEventSchema),
})
export type RooCliFinalOutput = z.infer<typeof rooCliFinalOutputSchema>

View file

@ -1,4 +1,5 @@
export * from "./api.js"
export * from "./cli.js"
export * from "./cloud.js"
export * from "./codebase-index.js"
export * from "./context-management.js"