diff --git a/benchmark/apps/cli/src/exercises.ts b/benchmark/apps/cli/src/exercises.ts index 8f2aabff0d..31693e28da 100644 --- a/benchmark/apps/cli/src/exercises.ts +++ b/benchmark/apps/cli/src/exercises.ts @@ -3,18 +3,18 @@ import * as fs from "fs" import { filesystem } from "gluegun" -import { type Language, languages } from "@benchmark/types" +import { type ExerciseLanguage, exerciseLanguages } from "@benchmark/types" import { exercisesPath } from "./paths.js" -let exercisesByLanguage: Record | null = null +let exercisesByLanguage: Record | null = null export const getExercises = () => { if (exercisesByLanguage !== null) { return exercisesByLanguage } - const getLanguageExercises = (language: Language) => + const getLanguageExercises = (language: ExerciseLanguage) => fs.existsSync(path.resolve(exercisesPath, language)) ? filesystem .subdirectories(path.resolve(exercisesPath, language)) @@ -22,9 +22,9 @@ export const getExercises = () => { .filter((exercise) => !exercise.startsWith(".")) : [] - exercisesByLanguage = languages.reduce( + exercisesByLanguage = exerciseLanguages.reduce( (collect, language) => ({ ...collect, [language]: getLanguageExercises(language) }), - {} as Record, + {} as Record, ) return exercisesByLanguage diff --git a/benchmark/apps/cli/src/index.ts b/benchmark/apps/cli/src/index.ts index 583cfea2af..26e7cacb29 100644 --- a/benchmark/apps/cli/src/index.ts +++ b/benchmark/apps/cli/src/index.ts @@ -7,14 +7,14 @@ import { build, filesystem, GluegunPrompt, GluegunToolbox } from "gluegun" import { runTests } from "@vscode/test-electron" import { execa, parseCommandString } from "execa" -import { type Language, languages, IpcOrigin, IpcMessageType, TaskEventName } from "@benchmark/types" +import { type ExerciseLanguage, exerciseLanguages, IpcOrigin, IpcMessageType, TaskEventName } from "@benchmark/types" import { type Run, findRun, createRun, finishRun, createTask, Task, getTasks, updateTask } from "@benchmark/db" import { IpcServer } from "@benchmark/ipc" import { __dirname, extensionDevelopmentPath, extensionTestsPath, exercisesPath } from "./paths.js" import { getExercises } from "./exercises.js" -const testCommands: Record = { +const testCommands: Record = { cpp: { commands: ["cmake -G 'Unix\\ Makefiles' -DEXERCISM_RUN_ALL_TESTS=1 ..", "make"], cwd: "build" }, // timeout 15s bash -c "cd '$dir' && mkdir -p build && cd build && cmake -G 'Unix Makefiles' -DEXERCISM_RUN_ALL_TESTS=1 .. >/dev/null 2>&1 && make >/dev/null 2>&1" go: { commands: ["go test"] }, // timeout 15s bash -c "cd '$dir' && go test > /dev/null 2>&1" java: { commands: ["./gradlew test"] }, // timeout --foreground 15s bash -c "cd '$dir' && ./gradlew test > /dev/null 2>&1" @@ -28,7 +28,7 @@ const run = async (toolbox: GluegunToolbox) => { let { language, exercise } = config - if (![undefined, ...languages, "all"].includes(language)) { + if (![undefined, ...exerciseLanguages, "all"].includes(language)) { throw new Error(`Language is invalid: ${language}`) } @@ -49,15 +49,15 @@ const run = async (toolbox: GluegunToolbox) => { }) if (language === "all") { - for (const language of languages) { - const exercises = getExercises()[language as Language] + for (const language of exerciseLanguages) { + const exercises = getExercises()[language as ExerciseLanguage] await pMap(exercises, (exercise) => createTask({ runId: run.id, language, exercise }), { concurrency: 10, }) } } else if (exercise === "all") { - const exercises = getExercises()[language as Language] + const exercises = getExercises()[language as ExerciseLanguage] await pMap(exercises, (exercise) => createTask({ runId: run.id, language, exercise }), { concurrency: 10 }) } else { language = language || (await askLanguage(prompt)) @@ -166,17 +166,17 @@ const runExercise = async ({ run, task }: { run: Run; task: Task }) => { } const askLanguage = async (prompt: GluegunPrompt) => { - const { language } = await prompt.ask<{ language: Language }>({ + const { language } = await prompt.ask<{ language: ExerciseLanguage }>({ type: "select", name: "language", message: "Which language?", - choices: [...languages], + choices: [...exerciseLanguages], }) return language } -const askExercise = async (prompt: GluegunPrompt, language: Language) => { +const askExercise = async (prompt: GluegunPrompt, language: ExerciseLanguage) => { const exercises = filesystem.subdirectories(path.join(exercisesPath, language)) if (exercises.length === 0) { diff --git a/benchmark/apps/web/src/lib/server/exercises.ts b/benchmark/apps/web/src/lib/server/exercises.ts index b32cab1d92..f545827360 100644 --- a/benchmark/apps/web/src/lib/server/exercises.ts +++ b/benchmark/apps/web/src/lib/server/exercises.ts @@ -4,7 +4,7 @@ import * as fs from "fs/promises" import * as path from "path" import { fileURLToPath } from "url" -import { Language, languages } from "@benchmark/types" +import { ExerciseLanguage, exerciseLanguages } from "@benchmark/types" const __dirname = path.dirname(fileURLToPath(import.meta.url)) @@ -24,7 +24,7 @@ const EXERCISES_BASE_PATH = path.resolve(__dirname, "../../../../../../../exerci export const getExercises = async () => { const result = await Promise.all( - languages.map(async (language) => { + exerciseLanguages.map(async (language) => { const languagePath = path.join(EXERCISES_BASE_PATH, language) const exercises = await listDirectories(languagePath) return exercises.map((exercise) => `${language}/${exercise}`) @@ -34,5 +34,5 @@ export const getExercises = async () => { return result.flat() } -export const getExercisesForLanguage = async (language: Language) => +export const getExercisesForLanguage = async (language: ExerciseLanguage) => listDirectories(path.join(EXERCISES_BASE_PATH, language)) diff --git a/benchmark/apps/web/src/lib/server/runs.ts b/benchmark/apps/web/src/lib/server/runs.ts index aa0bfe832e..68ff4f49ff 100644 --- a/benchmark/apps/web/src/lib/server/runs.ts +++ b/benchmark/apps/web/src/lib/server/runs.ts @@ -7,7 +7,7 @@ import os from "os" import { revalidatePath } from "next/cache" import pMap from "p-map" -import { Language, languages } from "@benchmark/types" +import { ExerciseLanguage, exerciseLanguages } from "@benchmark/types" import * as db from "@benchmark/db" import { CreateRun } from "@/lib/schemas" @@ -27,10 +27,10 @@ export async function createRun({ suite, exercises = [], ...values }: CreateRun) throw new Error("Invalid exercise path: " + path) } - await db.createTask({ ...values, runId: run.id, language: language as Language, exercise }) + await db.createTask({ ...values, runId: run.id, language: language as ExerciseLanguage, exercise }) } } else { - for (const language of languages) { + for (const language of exerciseLanguages) { const exercises = await getExercisesForLanguage(language) await pMap(exercises, (exercise) => db.createTask({ ...values, runId: run.id, language, exercise }), { diff --git a/benchmark/packages/db/src/queries/tasks.ts b/benchmark/packages/db/src/queries/tasks.ts index a32e92bf51..caa386675a 100644 --- a/benchmark/packages/db/src/queries/tasks.ts +++ b/benchmark/packages/db/src/queries/tasks.ts @@ -1,6 +1,6 @@ import { and, eq } from "drizzle-orm" -import type { Language } from "@benchmark/types" +import type { ExerciseLanguage } from "@benchmark/types" import { RecordNotFoundError, RecordNotCreatedError } from "./errors.js" import type { InsertTask, UpdateTask } from "../schema.js" @@ -49,7 +49,7 @@ export const updateTask = async (id: number, values: UpdateTask) => { } type GetTask = { runId: number - language: Language + language: ExerciseLanguage exercise: string } diff --git a/benchmark/packages/db/src/schema.ts b/benchmark/packages/db/src/schema.ts index c23d994e13..a1f3f15542 100644 --- a/benchmark/packages/db/src/schema.ts +++ b/benchmark/packages/db/src/schema.ts @@ -3,7 +3,7 @@ import { relations } from "drizzle-orm" import { createInsertSchema } from "drizzle-zod" import { z } from "zod" -import { languages } from "@benchmark/types" +import { exerciseLanguages } from "@benchmark/types" /** * runs @@ -45,7 +45,7 @@ export const tasks = sqliteTable( .references(() => runs.id) .notNull(), taskMetricsId: integer({ mode: "number" }).references(() => taskMetrics.id), - language: text({ enum: languages }).notNull(), + language: text({ enum: exerciseLanguages }).notNull(), exercise: text().notNull(), passed: integer({ mode: "boolean" }), startedAt: integer({ mode: "timestamp" }), diff --git a/benchmark/packages/types/src/exercises.ts b/benchmark/packages/types/src/exercises.ts new file mode 100644 index 0000000000..7eacbbadb1 --- /dev/null +++ b/benchmark/packages/types/src/exercises.ts @@ -0,0 +1,10 @@ +/** + * ExerciseLanguage + */ + +export const exerciseLanguages = ["cpp", "go", "java", "javascript", "python", "rust"] as const + +export type ExerciseLanguage = (typeof exerciseLanguages)[number] + +export const isExerciseLanguage = (value: string): value is ExerciseLanguage => + exerciseLanguages.includes(value as ExerciseLanguage) diff --git a/benchmark/packages/types/src/index.ts b/benchmark/packages/types/src/index.ts index 184b5a43cf..a7fd18bc57 100644 --- a/benchmark/packages/types/src/index.ts +++ b/benchmark/packages/types/src/index.ts @@ -1,125 +1,3 @@ -import { z } from "zod" - -/** - * Language - */ - -export const languages = ["cpp", "go", "java", "javascript", "python", "rust"] as const - -export type Language = (typeof languages)[number] - -export const isLanguage = (value: string): value is Language => languages.includes(value as Language) - -/** - * TaskEvent - */ - -export enum TaskEventName { - Connect = "Connect", - TaskStarted = "TaskStarted", - Message = "Message", - TaskTokenUsageUpdated = "TaskTokenUsageUpdated", - TaskFinished = "TaskFinished", -} - -export const taskEventSchema = z.discriminatedUnion("eventName", [ - z.object({ - eventName: z.literal(TaskEventName.Connect), - data: z.object({ task: z.object({ id: z.number() }) }), - }), - z.object({ - eventName: z.literal(TaskEventName.TaskStarted), - data: z.object({ task: z.object({ id: z.number() }) }), - }), - z.object({ - eventName: z.literal(TaskEventName.Message), - data: z.object({ - task: z.object({ id: z.number() }), - message: z.object({ - taskId: z.string(), - action: z.enum(["created", "updated"]), - message: z.object({ - // See ClineMessage. - ts: z.number(), - type: z.enum(["ask", "say"]), - ask: z.string().optional(), - say: z.string().optional(), - partial: z.boolean().optional(), - text: z.string().optional(), - reasoning: z.string().optional(), - }), - }), - }), - }), - z.object({ - eventName: z.literal(TaskEventName.TaskTokenUsageUpdated), - data: z.object({ - task: z.object({ id: z.number() }), - usage: z.object({}), - }), - }), - z.object({ - eventName: z.literal(TaskEventName.TaskFinished), - data: z.object({ task: z.object({ id: z.number() }), taskMetrics: z.unknown() }), - }), -]) - -export type TaskEvent = z.infer - -/** - * TaskCommand - */ - -export enum TaskCommandName { - StartNewTask = "StartNewTask", -} - -export const taskCommandSchema = z.discriminatedUnion("commandName", [ - z.object({ - commandName: z.literal(TaskCommandName.StartNewTask), - data: z.object({ - text: z.string(), - images: z.array(z.string()).optional(), - }), - }), -]) - -export type TaskCommand = z.infer - -/** - * IpcMessage - */ - -export enum IpcMessageType { - Ack = "Ack", - TaskCommand = "TaskCommand", - TaskEvent = "TaskEvent", -} - -export enum IpcOrigin { - Client = "client", - Server = "server", - Relay = "relay", -} - -export const ipcMessageSchema = z.discriminatedUnion("type", [ - z.object({ - type: z.literal(IpcMessageType.Ack), - origin: z.literal(IpcOrigin.Server), - data: z.object({ clientId: z.string() }), - }), - z.object({ - type: z.literal(IpcMessageType.TaskCommand), - origin: z.literal(IpcOrigin.Client), - clientId: z.string(), - data: taskCommandSchema, - }), - z.object({ - type: z.literal(IpcMessageType.TaskEvent), - origin: z.union([z.literal(IpcOrigin.Server), z.literal(IpcOrigin.Relay)]), - relayClientId: z.string().optional(), - data: taskEventSchema, - }), -]) - -export type IpcMessage = z.infer +export * from "./exercises.js" +export * from "./ipc.js" +export * from "./roo-code.js" diff --git a/benchmark/packages/types/src/ipc.ts b/benchmark/packages/types/src/ipc.ts new file mode 100644 index 0000000000..a744e7454d --- /dev/null +++ b/benchmark/packages/types/src/ipc.ts @@ -0,0 +1,115 @@ +import { z } from "zod" + +/** + * TaskEvent + */ + +export enum TaskEventName { + Connect = "Connect", + TaskStarted = "TaskStarted", + Message = "Message", + TaskTokenUsageUpdated = "TaskTokenUsageUpdated", + TaskFinished = "TaskFinished", +} + +export const taskEventSchema = z.discriminatedUnion("eventName", [ + z.object({ + eventName: z.literal(TaskEventName.Connect), + data: z.object({ task: z.object({ id: z.number() }) }), + }), + z.object({ + eventName: z.literal(TaskEventName.TaskStarted), + data: z.object({ task: z.object({ id: z.number() }) }), + }), + z.object({ + eventName: z.literal(TaskEventName.Message), + data: z.object({ + task: z.object({ id: z.number() }), + message: z.object({ + taskId: z.string(), + action: z.enum(["created", "updated"]), + message: z.object({ + // See ClineMessage. + ts: z.number(), + type: z.enum(["ask", "say"]), + ask: z.string().optional(), + say: z.string().optional(), + partial: z.boolean().optional(), + text: z.string().optional(), + reasoning: z.string().optional(), + }), + }), + }), + }), + z.object({ + eventName: z.literal(TaskEventName.TaskTokenUsageUpdated), + data: z.object({ + task: z.object({ id: z.number() }), + usage: z.object({}), + }), + }), + z.object({ + eventName: z.literal(TaskEventName.TaskFinished), + data: z.object({ task: z.object({ id: z.number() }), taskMetrics: z.unknown() }), + }), +]) + +export type TaskEvent = z.infer + +/** + * TaskCommand + */ + +export enum TaskCommandName { + StartNewTask = "StartNewTask", +} + +export const taskCommandSchema = z.discriminatedUnion("commandName", [ + z.object({ + commandName: z.literal(TaskCommandName.StartNewTask), + data: z.object({ + text: z.string(), + images: z.array(z.string()).optional(), + }), + }), +]) + +export type TaskCommand = z.infer + +/** + * IpcMessage + */ + +export enum IpcMessageType { + Ack = "Ack", + TaskCommand = "TaskCommand", + TaskEvent = "TaskEvent", +} + +export enum IpcOrigin { + Client = "client", + Server = "server", + Relay = "relay", +} + +export const ipcMessageSchema = z.discriminatedUnion("type", [ + z.object({ + type: z.literal(IpcMessageType.Ack), + origin: z.literal(IpcOrigin.Server), + data: z.object({ clientId: z.string() }), + }), + z.object({ + type: z.literal(IpcMessageType.TaskCommand), + origin: z.literal(IpcOrigin.Client), + clientId: z.string(), + data: taskCommandSchema, + }), + z.object({ + type: z.literal(IpcMessageType.TaskEvent), + origin: z.union([z.literal(IpcOrigin.Server), z.literal(IpcOrigin.Relay)]), + relayClientId: z.string().optional(), + data: taskEventSchema, + }), +]) + +export type IpcMessage = z.infer diff --git a/benchmark/packages/types/src/roo-code.ts b/benchmark/packages/types/src/roo-code.ts new file mode 100644 index 0000000000..9817b189bd --- /dev/null +++ b/benchmark/packages/types/src/roo-code.ts @@ -0,0 +1,259 @@ +/* eslint-disable @typescript-eslint/no-unused-vars */ + +import { z } from "zod" + +/** + * ProviderName + */ + +const providerNames = [ + "anthropic", + "glama", + "openrouter", + "bedrock", + "vertex", + "openai", + "ollama", + "vscode-lm", + "lmstudio", + "gemini", + "openai-native", + "mistral", + "deepseek", + "unbound", + "requesty", + "human-relay", + "fake-ai", +] as const + +export type ProviderName = (typeof providerNames)[number] + +/** + * ToolGroup + */ + +export const toolGroups = ["read", "edit", "browser", "command", "mcp", "modes"] as const + +export type ToolGroup = (typeof toolGroups)[number] + +/** + * CheckpointStorage + */ + +export const checkpointStorages = ["task", "workspace"] as const + +export type CheckpointStorage = (typeof checkpointStorages)[number] + +/** + * Language + */ + +const languages = [ + "ca", + "de", + "en", + "es", + "fr", + "hi", + "it", + "ja", + "ko", + "pl", + "pt-BR", + "tr", + "vi", + "zh-CN", + "zh-TW", +] as const + +export type Language = (typeof languages)[number] + +/** + * TelemetrySetting + */ + +export const telemetrySettings = ["unset", "enabled", "disabled"] as const + +export type TelemetrySetting = (typeof telemetrySettings)[number] + +/** + * ModelInfo + */ + +const modelInfoSchema = z.object({ + maxTokens: z.number().optional(), + contextWindow: z.number(), + supportsImages: z.boolean().optional(), + supportsComputerUse: z.boolean().optional(), + supportsPromptCache: z.boolean(), + inputPrice: z.number().optional(), + outputPrice: z.number().optional(), + cacheWritesPrice: z.number().optional(), + cacheReadsPrice: z.number().optional(), + description: z.string().optional(), + reasoningEffort: z.enum(["low", "medium", "high"]).optional(), + thinking: z.boolean().optional(), +}) + +export type ModelInfo = z.infer + +/** + * ApiConfigMeta + */ + +const apiConfigMetaSchema = z.object({ + id: z.string(), + name: z.string(), + apiProvider: z.enum(providerNames).optional(), +}) + +export type ApiConfigMeta = z.infer + +/** + * HistoryItem + */ + +const historyItemSchema = z.object({ + id: z.string(), + number: z.number(), + ts: z.number(), + task: z.string(), + tokensIn: z.number(), + tokensOut: z.number(), + cacheWrites: z.number().optional(), + cacheReads: z.number().optional(), + totalCost: z.number(), + size: z.number().optional(), +}) + +export type HistoryItem = z.infer + +/** + * GroupEntry + */ + +const groupEntrySchema = z.union([ + z.enum(toolGroups), + z + .tuple([ + z.enum(toolGroups), + z.object({ + fileRegex: z.string().optional(), + description: z.string().optional(), + }), + ]) + .readonly(), +]) + +export type GroupEntry = z.infer + +/** + * ModeConfig + */ + +const modeConfigSchema = z.object({ + slug: z.string(), + name: z.string(), + roleDefinition: z.string(), + customInstructions: z.string().optional(), + groups: z.array(groupEntrySchema).readonly(), + source: z.enum(["global", "project"]).optional(), +}) + +export type ModeConfig = z.infer + +/** + * ExperimentId + */ + +const experimentsSchema = z.object({ + experimentalDiffStrategy: z.boolean(), + search_and_replace: z.boolean(), + insert_content: z.boolean(), + powerSteering: z.boolean(), + multi_search_and_replace: z.boolean(), +}) + +export type Experiments = z.infer + +/** + * GlobalSettings + */ + +export const globalSettingsSchema = z.object({ + currentApiConfigName: z.string().optional(), + listApiConfigMeta: z.array(apiConfigMetaSchema).optional(), + pinnedApiConfigs: z.record(z.string(), z.boolean()).optional(), + + lastShownAnnouncementId: z.string().optional(), + customInstructions: z.string().optional(), + taskHistory: z.array(historyItemSchema).optional(), + + autoApprovalEnabled: z.boolean().optional(), + alwaysAllowReadOnly: z.boolean().optional(), + alwaysAllowReadOnlyOutsideWorkspace: z.boolean().optional(), + alwaysAllowWrite: z.boolean().optional(), + alwaysAllowWriteOutsideWorkspace: z.boolean().optional(), + writeDelayMs: z.number().optional(), + alwaysAllowBrowser: z.boolean().optional(), + alwaysApproveResubmit: z.boolean().optional(), + requestDelaySeconds: z.number().optional(), + alwaysAllowMcp: z.boolean().optional(), + alwaysAllowModeSwitch: z.boolean().optional(), + alwaysAllowSubtasks: z.boolean().optional(), + alwaysAllowExecute: z.boolean().optional(), + allowedCommands: z.array(z.string()).optional(), + + browserToolEnabled: z.boolean().optional(), + browserViewportSize: z.string().optional(), + screenshotQuality: z.number().optional(), + remoteBrowserEnabled: z.boolean().optional(), + remoteBrowserHost: z.string().optional(), + + enableCheckpoints: z.boolean().optional(), + checkpointStorage: z.enum(checkpointStorages).optional(), + + ttsEnabled: z.boolean().optional(), + ttsSpeed: z.number().optional(), + soundEnabled: z.boolean().optional(), + soundVolume: z.number().optional(), + + maxOpenTabsContext: z.number().optional(), + maxWorkspaceFiles: z.number().optional(), + showRooIgnoredFiles: z.boolean().optional(), + maxReadFileLine: z.number().optional(), + + terminalOutputLineLimit: z.number().optional(), + terminalShellIntegrationTimeout: z.number().optional(), + + rateLimitSeconds: z.number().optional(), + diffEnabled: z.boolean().optional(), + fuzzyMatchThreshold: z.number().optional(), + experiments: experimentsSchema.optional(), + + language: z.enum(languages).optional(), + + telemetrySetting: z.enum(telemetrySettings).optional(), + + mcpEnabled: z.boolean().optional(), + enableMcpServerCreation: z.boolean().optional(), + + mode: z.string().optional(), + modeApiConfigs: z.record(z.string(), z.string()).optional(), + customModes: z.array(modeConfigSchema).optional(), + customModePrompts: z + .record( + z.string(), + z + .object({ + roleDefinition: z.string().optional(), + customInstructions: z.string().optional(), + }) + .optional(), + ) + .optional(), + customSupportPrompts: z.record(z.string(), z.string().optional()).optional(), + enhancementApiConfigId: z.string().optional(), +}) + +export type GlobalSettings = z.infer diff --git a/package.json b/package.json index 993b3b20f9..ba63bd2e46 100644 --- a/package.json +++ b/package.json @@ -73,9 +73,11 @@ "views": { "roo-cline-ActivityBar": [ { - "type": "webview", "id": "roo-cline.SidebarProvider", - "name": "" + "type": "webview", + "name": "Roo Code", + "icon": "$(rocket)", + "contextualTitle": "Roo Code!" } ] },