mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-08-28 05:27:24 +00:00
New task slash command
This commit is contained in:
parent
b6f571cadf
commit
e85362fb11
87 changed files with 1142 additions and 861 deletions
|
|
@ -433,24 +433,6 @@ describe("ExtensionHost", () => {
|
|||
|
||||
expect(handleMsgUpdatedSpy).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it("should route action messages to handleActionMessage", () => {
|
||||
const host = createTestHost()
|
||||
const handleActionSpy = spyOnPrivate(host, "handleActionMessage")
|
||||
|
||||
callPrivate(host, "handleExtensionMessage", { type: "action", action: "test" })
|
||||
|
||||
expect(handleActionSpy).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it("should route invoke messages to handleInvokeMessage", () => {
|
||||
const host = createTestHost()
|
||||
const handleInvokeSpy = spyOnPrivate(host, "handleInvokeMessage")
|
||||
|
||||
callPrivate(host, "handleExtensionMessage", { type: "invoke", invoke: "test" })
|
||||
|
||||
expect(handleInvokeSpy).toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
|
||||
describe("handleSayMessage", () => {
|
||||
|
|
|
|||
103
apps/cli/src/__tests__/globalCommands.test.ts
Normal file
103
apps/cli/src/__tests__/globalCommands.test.ts
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
import { describe, it, expect } from "vitest"
|
||||
import {
|
||||
GLOBAL_COMMANDS,
|
||||
getGlobalCommand,
|
||||
getGlobalCommandsForAutocomplete,
|
||||
type GlobalCommand,
|
||||
type GlobalCommandAction,
|
||||
} from "../globalCommands.js"
|
||||
|
||||
describe("globalCommands", () => {
|
||||
describe("GLOBAL_COMMANDS", () => {
|
||||
it("should contain the /new command", () => {
|
||||
const newCommand = GLOBAL_COMMANDS.find((cmd) => cmd.name === "new")
|
||||
expect(newCommand).toBeDefined()
|
||||
expect(newCommand?.action).toBe("clearTask")
|
||||
expect(newCommand?.description).toBe("Start a new task")
|
||||
})
|
||||
|
||||
it("should have valid structure for all commands", () => {
|
||||
for (const cmd of GLOBAL_COMMANDS) {
|
||||
expect(cmd.name).toBeTruthy()
|
||||
expect(typeof cmd.name).toBe("string")
|
||||
expect(cmd.description).toBeTruthy()
|
||||
expect(typeof cmd.description).toBe("string")
|
||||
expect(cmd.action).toBeTruthy()
|
||||
expect(typeof cmd.action).toBe("string")
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe("getGlobalCommand", () => {
|
||||
it("should return the command when found", () => {
|
||||
const cmd = getGlobalCommand("new")
|
||||
expect(cmd).toBeDefined()
|
||||
expect(cmd?.name).toBe("new")
|
||||
expect(cmd?.action).toBe("clearTask")
|
||||
})
|
||||
|
||||
it("should return undefined for unknown commands", () => {
|
||||
const cmd = getGlobalCommand("unknown-command")
|
||||
expect(cmd).toBeUndefined()
|
||||
})
|
||||
|
||||
it("should be case-sensitive", () => {
|
||||
const cmd = getGlobalCommand("NEW")
|
||||
expect(cmd).toBeUndefined()
|
||||
})
|
||||
})
|
||||
|
||||
describe("getGlobalCommandsForAutocomplete", () => {
|
||||
it("should return commands in autocomplete format", () => {
|
||||
const commands = getGlobalCommandsForAutocomplete()
|
||||
expect(commands.length).toBe(GLOBAL_COMMANDS.length)
|
||||
|
||||
for (const cmd of commands) {
|
||||
expect(cmd.name).toBeTruthy()
|
||||
expect(cmd.source).toBe("global")
|
||||
expect(cmd.action).toBeTruthy()
|
||||
}
|
||||
})
|
||||
|
||||
it("should include the /new command with correct format", () => {
|
||||
const commands = getGlobalCommandsForAutocomplete()
|
||||
const newCommand = commands.find((cmd) => cmd.name === "new")
|
||||
|
||||
expect(newCommand).toBeDefined()
|
||||
expect(newCommand?.description).toBe("Start a new task")
|
||||
expect(newCommand?.source).toBe("global")
|
||||
expect(newCommand?.action).toBe("clearTask")
|
||||
})
|
||||
|
||||
it("should not include argumentHint for action commands", () => {
|
||||
const commands = getGlobalCommandsForAutocomplete()
|
||||
// Action commands don't have argument hints
|
||||
for (const cmd of commands) {
|
||||
expect(cmd).not.toHaveProperty("argumentHint")
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe("type safety", () => {
|
||||
it("should have valid GlobalCommandAction types", () => {
|
||||
// This test ensures the type is properly constrained
|
||||
const validActions: GlobalCommandAction[] = ["clearTask"]
|
||||
|
||||
for (const cmd of GLOBAL_COMMANDS) {
|
||||
expect(validActions).toContain(cmd.action)
|
||||
}
|
||||
})
|
||||
|
||||
it("should match GlobalCommand interface", () => {
|
||||
const testCommand: GlobalCommand = {
|
||||
name: "test",
|
||||
description: "Test command",
|
||||
action: "clearTask",
|
||||
}
|
||||
|
||||
expect(testCommand.name).toBe("test")
|
||||
expect(testCommand.description).toBe("Test command")
|
||||
expect(testCommand.action).toBe("clearTask")
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
@ -13,10 +13,11 @@ import { createRequire } from "module"
|
|||
import path from "path"
|
||||
import { fileURLToPath } from "url"
|
||||
import fs from "fs"
|
||||
import os from "os"
|
||||
import readline from "readline"
|
||||
|
||||
import { ProviderName, ReasoningEffortExtended, RooCodeSettings, ExtensionMessage } from "@roo-code/types"
|
||||
import { createVSCodeAPI, setRuntimeConfigValues } from "@roo-code/vscode-shim"
|
||||
import { ProviderName, ReasoningEffortExtended, RooCodeSettings } from "@roo-code/types"
|
||||
|
||||
// Get the CLI package root directory (for finding node_modules/@vscode/ripgrep)
|
||||
// When bundled, import.meta.url points to dist/index.js, so go up to package root
|
||||
|
|
@ -53,6 +54,8 @@ interface WebviewViewProvider {
|
|||
resolveWebviewView?(webviewView: unknown, context: unknown, token: unknown): void | Promise<void>
|
||||
}
|
||||
|
||||
const DEBUG_LOG_PATH = path.join(os.homedir(), ".roo", "cli-debug.log")
|
||||
|
||||
export class ExtensionHost extends EventEmitter {
|
||||
private vscode: ReturnType<typeof createVSCodeAPI> | null = null
|
||||
private extensionModule: ExtensionModule | null = null
|
||||
|
|
@ -61,7 +64,7 @@ export class ExtensionHost extends EventEmitter {
|
|||
private options: ExtensionHostOptions
|
||||
private isWebviewReady = false
|
||||
private pendingMessages: unknown[] = []
|
||||
private messageListener: ((message: unknown) => void) | null = null
|
||||
private messageListener: ((message: ExtensionMessage) => void) | null = null
|
||||
|
||||
private originalConsole: {
|
||||
log: typeof console.log
|
||||
|
|
@ -85,9 +88,6 @@ export class ExtensionHost extends EventEmitter {
|
|||
// Track streamed content by ts for delta computation
|
||||
private streamedContent: Map<number, { text: string; headerShown: boolean }> = new Map()
|
||||
|
||||
// Track message processing for verbose debug output
|
||||
private processedMessageCount = 0
|
||||
|
||||
// Track if we're currently streaming a message (to manage newlines)
|
||||
private currentlyStreamingTs: number | null = null
|
||||
|
||||
|
|
@ -97,28 +97,64 @@ export class ExtensionHost extends EventEmitter {
|
|||
constructor(options: ExtensionHostOptions) {
|
||||
super()
|
||||
this.options = options
|
||||
// Initialize currentMode from options to track mode changes
|
||||
this.currentMode = options.mode || null
|
||||
}
|
||||
|
||||
private log(...args: unknown[]): void {
|
||||
if (this.options.verbose) {
|
||||
// Use original console if available to avoid quiet mode suppression
|
||||
const logFn = this.originalConsole?.log || console.log
|
||||
logFn("[ExtensionHost]", ...args)
|
||||
/**
|
||||
* Write debug log entry to ~/.roo/cli-debug.log
|
||||
* This avoids console output which breaks the TUI.
|
||||
*/
|
||||
private log(message: string, data?: unknown): void {
|
||||
try {
|
||||
const logDir = path.dirname(DEBUG_LOG_PATH)
|
||||
|
||||
if (!fs.existsSync(logDir)) {
|
||||
fs.mkdirSync(logDir, { recursive: true })
|
||||
}
|
||||
|
||||
const timestamp = new Date().toISOString()
|
||||
|
||||
const entry = data
|
||||
? `[${timestamp}] ${message}: ${JSON.stringify(data, null, 2)}\n`
|
||||
: `[${timestamp}] ${message}\n`
|
||||
|
||||
fs.appendFileSync(DEBUG_LOG_PATH, entry)
|
||||
} catch {
|
||||
// NO-OP
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Suppress Node.js warnings (like MaxListenersExceededWarning)
|
||||
* This is called regardless of quiet mode to prevent warnings from interrupting output
|
||||
* Get the shape (keys) of an object for logging
|
||||
*/
|
||||
private getMessageShape(msg: unknown): Record<string, string> {
|
||||
if (!msg || typeof msg !== "object") {
|
||||
return { _type: typeof msg }
|
||||
}
|
||||
|
||||
const shape: Record<string, string> = {}
|
||||
|
||||
for (const [key, value] of Object.entries(msg as Record<string, unknown>)) {
|
||||
if (value === null) {
|
||||
shape[key] = "null"
|
||||
} else if (Array.isArray(value)) {
|
||||
shape[key] = `array[${value.length}]`
|
||||
} else if (typeof value === "object") {
|
||||
shape[key] = `object{${Object.keys(value).join(",")}}`
|
||||
} else {
|
||||
shape[key] = typeof value
|
||||
}
|
||||
}
|
||||
|
||||
return shape
|
||||
}
|
||||
|
||||
private suppressNodeWarnings(): void {
|
||||
// Suppress process warnings (like MaxListenersExceededWarning)
|
||||
// Suppress process warnings (like MaxListenersExceededWarning).
|
||||
this.originalProcessEmitWarning = process.emitWarning
|
||||
process.emitWarning = () => {}
|
||||
|
||||
// Also suppress via the warning event handler
|
||||
// Also suppress via the warning event handler.
|
||||
process.on("warning", () => {})
|
||||
}
|
||||
|
||||
|
|
@ -169,8 +205,6 @@ export class ExtensionHost extends EventEmitter {
|
|||
}
|
||||
|
||||
async activate(): Promise<void> {
|
||||
this.log("Activating extension...")
|
||||
|
||||
// Suppress Node.js warnings (like MaxListenersExceededWarning) before anything else
|
||||
this.suppressNodeWarnings()
|
||||
|
||||
|
|
@ -179,14 +213,13 @@ export class ExtensionHost extends EventEmitter {
|
|||
|
||||
// Verify extension path exists
|
||||
const bundlePath = path.join(this.options.extensionPath, "extension.js")
|
||||
|
||||
if (!fs.existsSync(bundlePath)) {
|
||||
this.restoreConsole()
|
||||
throw new Error(`Extension bundle not found at: ${bundlePath}`)
|
||||
}
|
||||
|
||||
// 1. Create VSCode API mock
|
||||
this.log("Creating VSCode API mock...")
|
||||
this.log("Using appRoot:", CLI_PACKAGE_ROOT)
|
||||
this.vscode = createVSCodeAPI(
|
||||
this.options.extensionPath,
|
||||
this.options.workspacePath,
|
||||
|
|
@ -228,8 +261,6 @@ export class ExtensionHost extends EventEmitter {
|
|||
require: require,
|
||||
} as unknown as NodeJS.Module
|
||||
|
||||
this.log("Loading extension bundle from:", bundlePath)
|
||||
|
||||
// 5. Load extension bundle
|
||||
try {
|
||||
this.extensionModule = require(bundlePath) as ExtensionModule
|
||||
|
|
@ -244,12 +275,9 @@ export class ExtensionHost extends EventEmitter {
|
|||
// 6. Restore module resolution
|
||||
Module._resolveFilename = originalResolve
|
||||
|
||||
this.log("Activating extension...")
|
||||
|
||||
// 7. Activate extension
|
||||
try {
|
||||
this.extensionAPI = await this.extensionModule.activate(this.vscode.context)
|
||||
this.log("Extension activated successfully")
|
||||
} catch (error) {
|
||||
throw new Error(`Failed to activate extension: ${error instanceof Error ? error.message : String(error)}`)
|
||||
}
|
||||
|
|
@ -260,18 +288,13 @@ export class ExtensionHost extends EventEmitter {
|
|||
* This is triggered when the extension registers its sidebar webview provider
|
||||
*/
|
||||
registerWebviewProvider(viewId: string, provider: WebviewViewProvider): void {
|
||||
this.log(`Webview provider registered: ${viewId}`)
|
||||
this.webviewProviders.set(viewId, provider)
|
||||
|
||||
// The WindowAPI will call resolveWebviewView automatically
|
||||
// We don't need to do anything here
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a webview provider is disposed
|
||||
*/
|
||||
unregisterWebviewProvider(viewId: string): void {
|
||||
this.log(`Webview provider unregistered: ${viewId}`)
|
||||
this.webviewProviders.delete(viewId)
|
||||
}
|
||||
|
||||
|
|
@ -288,11 +311,8 @@ export class ExtensionHost extends EventEmitter {
|
|||
* This indicates the webview is ready to receive messages
|
||||
*/
|
||||
markWebviewReady(): void {
|
||||
this.log("Webview marked as ready")
|
||||
this.isWebviewReady = true
|
||||
this.emit("webviewReady")
|
||||
|
||||
// Flush any pending messages
|
||||
this.flushPendingMessages()
|
||||
}
|
||||
|
||||
|
|
@ -301,10 +321,10 @@ export class ExtensionHost extends EventEmitter {
|
|||
*/
|
||||
private flushPendingMessages(): void {
|
||||
if (this.pendingMessages.length > 0) {
|
||||
this.log(`Flushing ${this.pendingMessages.length} pending messages`)
|
||||
for (const message of this.pendingMessages) {
|
||||
this.emit("webviewMessage", message)
|
||||
}
|
||||
|
||||
this.pendingMessages = []
|
||||
}
|
||||
}
|
||||
|
|
@ -314,12 +334,10 @@ export class ExtensionHost extends EventEmitter {
|
|||
*/
|
||||
sendToExtension(message: unknown): void {
|
||||
if (!this.isWebviewReady) {
|
||||
this.log("Queueing message (webview not ready):", message)
|
||||
this.pendingMessages.push(message)
|
||||
return
|
||||
}
|
||||
|
||||
this.log("Sending message to extension:", message)
|
||||
this.emit("webviewMessage", message)
|
||||
}
|
||||
|
||||
|
|
@ -360,6 +378,7 @@ export class ExtensionHost extends EventEmitter {
|
|||
xai: "XAI_API_KEY",
|
||||
groq: "GROQ_API_KEY",
|
||||
}
|
||||
|
||||
const envVar = envVarMap[provider.toLowerCase()] || `${provider.toUpperCase().replace(/-/g, "_")}_API_KEY`
|
||||
return process.env[envVar]
|
||||
}
|
||||
|
|
@ -528,15 +547,8 @@ export class ExtensionHost extends EventEmitter {
|
|||
return config
|
||||
}
|
||||
|
||||
/**
|
||||
* Run a task with the given prompt
|
||||
*/
|
||||
async runTask(prompt: string): Promise<void> {
|
||||
this.log("Running task:", prompt)
|
||||
|
||||
// Wait for webview to be ready
|
||||
if (!this.isWebviewReady) {
|
||||
this.log("Waiting for webview to be ready...")
|
||||
await new Promise<void>((resolve) => {
|
||||
this.once("webviewReady", resolve)
|
||||
})
|
||||
|
|
@ -549,8 +561,6 @@ export class ExtensionHost extends EventEmitter {
|
|||
// In non-interactive mode (-y flag), enable auto-approval for everything
|
||||
// In interactive mode (default), we'll prompt the user for each action
|
||||
if (this.options.nonInteractive) {
|
||||
this.log("Non-interactive mode: enabling auto-approval settings...")
|
||||
|
||||
const settings: RooCodeSettings = {
|
||||
autoApprovalEnabled: true,
|
||||
alwaysAllowReadOnly: true,
|
||||
|
|
@ -572,8 +582,6 @@ export class ExtensionHost extends EventEmitter {
|
|||
this.sendToExtension({ type: "updateSettings", updatedSettings: settings })
|
||||
await new Promise<void>((resolve) => setTimeout(resolve, 100))
|
||||
} else {
|
||||
this.log("Interactive mode: user will be prompted for approvals...")
|
||||
|
||||
const settings: RooCodeSettings = {
|
||||
autoApprovalEnabled: false,
|
||||
}
|
||||
|
|
@ -585,7 +593,6 @@ export class ExtensionHost extends EventEmitter {
|
|||
|
||||
// Always send API configuration - it may include API key from environment variables
|
||||
const apiConfig = this.buildApiConfiguration()
|
||||
this.log("Sending initial API configuration:", JSON.stringify(apiConfig))
|
||||
this.sendToExtension({ type: "updateSettings", updatedSettings: apiConfig })
|
||||
await new Promise<void>((resolve) => setTimeout(resolve, 100))
|
||||
|
||||
|
|
@ -597,52 +604,64 @@ export class ExtensionHost extends EventEmitter {
|
|||
* Set up listener for messages from the extension
|
||||
*/
|
||||
private setupMessageListener(): void {
|
||||
this.messageListener = (message: unknown) => {
|
||||
this.handleExtensionMessage(message)
|
||||
}
|
||||
|
||||
this.messageListener = (message: ExtensionMessage) => this.handleExtensionMessage(message)
|
||||
this.on("extensionWebviewMessage", this.messageListener)
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle messages from the extension
|
||||
*/
|
||||
private handleExtensionMessage(message: unknown): void {
|
||||
const msg = message as Record<string, unknown>
|
||||
private handleExtensionMessage(msg: ExtensionMessage): void {
|
||||
// Log all incoming messages for debugging
|
||||
this.log(`[MSG] type=${msg.type}`, this.getMessageShape(msg))
|
||||
|
||||
if (this.options.verbose) {
|
||||
this.log("Received message from extension:", JSON.stringify(msg, null, 2))
|
||||
// For state messages, log additional details about the state
|
||||
if (msg.type === "state" && msg.state) {
|
||||
const state = msg.state
|
||||
// Extract model ID based on provider (different providers use different fields)
|
||||
const apiConfig = state.apiConfiguration
|
||||
let modelId = apiConfig?.apiModelId
|
||||
|
||||
if (apiConfig?.apiProvider === "openrouter") {
|
||||
modelId = apiConfig?.openRouterModelId
|
||||
} else if (apiConfig?.apiProvider === "openai") {
|
||||
modelId = apiConfig?.openAiModelId
|
||||
} else if (apiConfig?.apiProvider === "ollama") {
|
||||
modelId = apiConfig?.ollamaModelId
|
||||
}
|
||||
|
||||
this.log(`[STATE] mode=${state.mode}, clineMessages=${state.clineMessages?.length || 0}`, {
|
||||
apiProvider: apiConfig?.apiProvider,
|
||||
modelId: modelId,
|
||||
mode: state.mode,
|
||||
cliProvider: this.options.apiProvider,
|
||||
cliModel: this.options.model,
|
||||
})
|
||||
|
||||
// Log any ask messages in the state that might indicate resume
|
||||
if (state.clineMessages) {
|
||||
for (const clineMsg of state.clineMessages) {
|
||||
if (clineMsg?.ask === "resume_task" || clineMsg?.ask === "resume_completed_task") {
|
||||
this.log(`[RESUME DETECTED] ask=${clineMsg.ask}, ts=${clineMsg.ts}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle different message types
|
||||
switch (msg.type) {
|
||||
case "state":
|
||||
this.handleStateMessage(msg)
|
||||
break
|
||||
|
||||
case "messageUpdated":
|
||||
// This is the streaming update - handle individual message updates
|
||||
// This is the streaming update - handle individual message updates.
|
||||
this.handleMessageUpdated(msg)
|
||||
break
|
||||
|
||||
case "action":
|
||||
this.handleActionMessage(msg)
|
||||
break
|
||||
|
||||
case "invoke":
|
||||
this.handleInvokeMessage(msg)
|
||||
break
|
||||
|
||||
case "modes":
|
||||
// Forward modes list to the TUI
|
||||
// Forward modes list to the TUI.
|
||||
this.emit("extensionWebviewMessage", msg)
|
||||
break
|
||||
|
||||
default:
|
||||
// Log unknown message types in verbose mode
|
||||
if (this.options.verbose) {
|
||||
this.log("Unknown message type:", msg.type)
|
||||
}
|
||||
// NO-OP
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -655,6 +674,7 @@ export class ExtensionHost extends EventEmitter {
|
|||
if (this.options.disableOutput) {
|
||||
return
|
||||
}
|
||||
|
||||
const text = args.map((arg) => (typeof arg === "string" ? arg : JSON.stringify(arg))).join(" ")
|
||||
process.stdout.write(text + "\n")
|
||||
}
|
||||
|
|
@ -668,65 +688,113 @@ export class ExtensionHost extends EventEmitter {
|
|||
if (this.options.disableOutput) {
|
||||
return
|
||||
}
|
||||
|
||||
const text = args.map((arg) => (typeof arg === "string" ? arg : JSON.stringify(arg))).join(" ")
|
||||
process.stderr.write(text + "\n")
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle state update messages from the extension
|
||||
* Get the expected model ID from CLI options
|
||||
*/
|
||||
private handleStateMessage(msg: Record<string, unknown>): void {
|
||||
const state = msg.state as Record<string, unknown> | undefined
|
||||
if (!state) return
|
||||
private getExpectedModelId(): string | undefined {
|
||||
return this.options.model
|
||||
}
|
||||
|
||||
// Detect mode changes and re-apply API configuration
|
||||
// This preserves the CLI-provided provider/model settings across mode switches
|
||||
const newMode = state.mode as string | undefined
|
||||
if (this.options.verbose) {
|
||||
this.log(`State update: mode=${newMode}, currentMode=${this.currentMode}`)
|
||||
/**
|
||||
* Get the current model ID from state's apiConfiguration
|
||||
*/
|
||||
private getStateModelId(apiConfig: Record<string, unknown> | undefined): string | undefined {
|
||||
if (!apiConfig) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
const provider = apiConfig.apiProvider as string | undefined
|
||||
switch (provider) {
|
||||
case "openrouter":
|
||||
return apiConfig.openRouterModelId as string | undefined
|
||||
case "openai":
|
||||
return apiConfig.openAiModelId as string | undefined
|
||||
case "ollama":
|
||||
return apiConfig.ollamaModelId as string | undefined
|
||||
case "litellm":
|
||||
return apiConfig.litellmModelId as string | undefined
|
||||
case "lmstudio":
|
||||
return apiConfig.lmStudioModelId as string | undefined
|
||||
case "huggingface":
|
||||
return apiConfig.huggingFaceModelId as string | undefined
|
||||
case "unbound":
|
||||
return apiConfig.unboundModelId as string | undefined
|
||||
case "requesty":
|
||||
return apiConfig.requestyModelId as string | undefined
|
||||
case "deepinfra":
|
||||
return apiConfig.deepInfraModelId as string | undefined
|
||||
case "vercel-ai-gateway":
|
||||
return apiConfig.vercelAiGatewayModelId as string | undefined
|
||||
case "io-intelligence":
|
||||
return apiConfig.ioIntelligenceModelId as string | undefined
|
||||
default:
|
||||
return apiConfig.apiModelId as string | undefined
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle state update messages from the extension.
|
||||
*/
|
||||
private handleStateMessage(msg: ExtensionMessage): void {
|
||||
const state = msg.state
|
||||
|
||||
if (!state) {
|
||||
return
|
||||
}
|
||||
|
||||
// Track current mode for mode switch detection (in tool execution).
|
||||
const newMode = state.mode
|
||||
|
||||
if (newMode && this.currentMode !== null && this.currentMode !== newMode) {
|
||||
const apiConfig = this.buildApiConfiguration()
|
||||
this.log(`Mode changed from ${this.currentMode} to ${newMode}, re-applying API configuration...`)
|
||||
if (this.options.verbose) {
|
||||
this.log(`API config: ${JSON.stringify(apiConfig)}`)
|
||||
}
|
||||
this.sendToExtension({ type: "updateSettings", updatedSettings: apiConfig })
|
||||
this.log(`[MODE CHANGE] from=${this.currentMode} to=${newMode}, re-applying CLI settings`)
|
||||
const updatedSettings = this.buildApiConfiguration()
|
||||
this.sendToExtension({ type: "updateSettings", updatedSettings })
|
||||
}
|
||||
|
||||
if (newMode) {
|
||||
this.currentMode = newMode
|
||||
}
|
||||
|
||||
const clineMessages = state.clineMessages as Array<Record<string, unknown>> | undefined
|
||||
// Detect when the model in state differs from CLI-specified model.
|
||||
// This catches task resume scenarios where the extension loads stored apiConfiguration
|
||||
// which may differ from CLI-provided settings. We re-apply CLI settings proactively.
|
||||
const apiConfig = state.apiConfiguration as Record<string, unknown> | undefined
|
||||
const stateModelId = this.getStateModelId(apiConfig)
|
||||
const expectedModelId = this.getExpectedModelId()
|
||||
|
||||
if (expectedModelId && stateModelId && stateModelId !== expectedModelId) {
|
||||
this.log(`[MODEL MISMATCH] state has ${stateModelId}, CLI expects ${expectedModelId}, re-applying settings`)
|
||||
const updatedSettings = this.buildApiConfiguration()
|
||||
this.sendToExtension({ type: "updateSettings", updatedSettings })
|
||||
}
|
||||
|
||||
const clineMessages = state.clineMessages
|
||||
|
||||
if (clineMessages && clineMessages.length > 0) {
|
||||
// Track message processing for verbose debug output
|
||||
this.processedMessageCount++
|
||||
|
||||
// Verbose: log state update summary
|
||||
if (this.options.verbose) {
|
||||
this.log(`State update #${this.processedMessageCount}: ${clineMessages.length} messages`)
|
||||
}
|
||||
|
||||
// Process all messages to find new or updated ones
|
||||
for (const message of clineMessages) {
|
||||
if (!message) continue
|
||||
|
||||
const ts = message.ts as number | undefined
|
||||
const isPartial = message.partial as boolean | undefined
|
||||
const text = message.text as string
|
||||
const type = message.type as string
|
||||
const say = message.say as string | undefined
|
||||
const ask = message.ask as string | undefined
|
||||
|
||||
if (!ts) continue
|
||||
|
||||
// Handle "say" type messages
|
||||
if (type === "say" && say) {
|
||||
this.handleSayMessage(ts, say, text, isPartial)
|
||||
if (!message) {
|
||||
continue
|
||||
}
|
||||
// Handle "ask" type messages
|
||||
else if (type === "ask" && ask) {
|
||||
|
||||
const ts = message.ts
|
||||
const isPartial = message.partial
|
||||
const text = message.text
|
||||
const type = message.type
|
||||
const say = message.say
|
||||
const ask = message.ask
|
||||
|
||||
if (!ts) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (type === "say" && say && typeof text === "string") {
|
||||
this.handleSayMessage(ts, say, text, isPartial)
|
||||
} else if (type === "ask" && ask && typeof text === "string") {
|
||||
this.handleAskMessage(ts, ask, text, isPartial)
|
||||
}
|
||||
}
|
||||
|
|
@ -737,25 +805,27 @@ export class ExtensionHost extends EventEmitter {
|
|||
* Handle messageUpdated - individual streaming updates for a single message
|
||||
* This is where real-time streaming happens!
|
||||
*/
|
||||
private handleMessageUpdated(msg: Record<string, unknown>): void {
|
||||
const clineMessage = msg.clineMessage as Record<string, unknown> | undefined
|
||||
if (!clineMessage) return
|
||||
private handleMessageUpdated(msg: ExtensionMessage): void {
|
||||
const clineMessage = msg.clineMessage
|
||||
|
||||
const ts = clineMessage.ts as number | undefined
|
||||
const isPartial = clineMessage.partial as boolean | undefined
|
||||
const text = clineMessage.text as string
|
||||
const type = clineMessage.type as string
|
||||
const say = clineMessage.say as string | undefined
|
||||
const ask = clineMessage.ask as string | undefined
|
||||
|
||||
if (!ts) return
|
||||
|
||||
// Handle "say" type messages
|
||||
if (type === "say" && say) {
|
||||
this.handleSayMessage(ts, say, text, isPartial)
|
||||
if (!clineMessage) {
|
||||
return
|
||||
}
|
||||
// Handle "ask" type messages
|
||||
else if (type === "ask" && ask) {
|
||||
|
||||
const ts = clineMessage.ts
|
||||
const isPartial = clineMessage.partial
|
||||
const text = clineMessage.text
|
||||
const type = clineMessage.type
|
||||
const say = clineMessage.say
|
||||
const ask = clineMessage.ask
|
||||
|
||||
if (!ts) {
|
||||
return
|
||||
}
|
||||
|
||||
if (type === "say" && say && typeof text === "string") {
|
||||
this.handleSayMessage(ts, say, text, isPartial)
|
||||
} else if (type === "ask" && ask && typeof text === "string") {
|
||||
this.handleAskMessage(ts, ask, text, isPartial)
|
||||
}
|
||||
}
|
||||
|
|
@ -768,6 +838,7 @@ export class ExtensionHost extends EventEmitter {
|
|||
if (this.options.disableOutput) {
|
||||
return
|
||||
}
|
||||
|
||||
process.stdout.write(text)
|
||||
}
|
||||
|
||||
|
|
@ -823,6 +894,7 @@ export class ExtensionHost extends EventEmitter {
|
|||
} else if (!isPartial && text && !alreadyDisplayedComplete) {
|
||||
// Message complete - ensure all content is output
|
||||
const streamed = this.streamedContent.get(ts)
|
||||
|
||||
if (streamed) {
|
||||
// We were streaming - output any remaining delta and finish
|
||||
if (text.length > streamed.text.length && text.startsWith(streamed.text)) {
|
||||
|
|
@ -834,6 +906,7 @@ export class ExtensionHost extends EventEmitter {
|
|||
// Not streamed yet - output complete message
|
||||
this.output("\n[assistant]", text)
|
||||
}
|
||||
|
||||
this.displayedMessages.set(ts, { text, partial: false })
|
||||
this.streamedContent.set(ts, { text, headerShown: true })
|
||||
}
|
||||
|
|
@ -842,13 +915,13 @@ export class ExtensionHost extends EventEmitter {
|
|||
case "thinking":
|
||||
case "reasoning":
|
||||
// Stream reasoning content in real-time.
|
||||
this.log(`Received ${say} message: partial=${isPartial}, textLength=${text?.length ?? 0}`)
|
||||
if (isPartial && text) {
|
||||
this.streamContent(ts, text, "[reasoning]")
|
||||
this.displayedMessages.set(ts, { text, partial: true })
|
||||
} else if (!isPartial && text && !alreadyDisplayedComplete) {
|
||||
// Reasoning complete - finish the stream.
|
||||
const streamed = this.streamedContent.get(ts)
|
||||
|
||||
if (streamed) {
|
||||
if (text.length > streamed.text.length && text.startsWith(streamed.text)) {
|
||||
const delta = text.slice(streamed.text.length)
|
||||
|
|
@ -858,6 +931,7 @@ export class ExtensionHost extends EventEmitter {
|
|||
} else {
|
||||
this.output("\n[reasoning]", text)
|
||||
}
|
||||
|
||||
this.displayedMessages.set(ts, { text, partial: false })
|
||||
}
|
||||
break
|
||||
|
|
@ -870,11 +944,13 @@ export class ExtensionHost extends EventEmitter {
|
|||
} else if (!isPartial && text && !alreadyDisplayedComplete) {
|
||||
// Command output complete - finish the stream.
|
||||
const streamed = this.streamedContent.get(ts)
|
||||
|
||||
if (streamed) {
|
||||
if (text.length > streamed.text.length && text.startsWith(streamed.text)) {
|
||||
const delta = text.slice(streamed.text.length)
|
||||
this.writeStream(delta)
|
||||
}
|
||||
|
||||
this.finishStream(ts)
|
||||
} else {
|
||||
this.writeStream("\n[command output] ")
|
||||
|
|
@ -907,7 +983,6 @@ export class ExtensionHost extends EventEmitter {
|
|||
break
|
||||
|
||||
case "tool":
|
||||
// Tool usage - show when complete
|
||||
if (text && !alreadyDisplayedComplete) {
|
||||
this.output("\n[tool]", text)
|
||||
this.displayedMessages.set(ts, { text, partial: false })
|
||||
|
|
@ -915,21 +990,10 @@ export class ExtensionHost extends EventEmitter {
|
|||
break
|
||||
|
||||
case "api_req_started":
|
||||
// API request started - log in verbose mode
|
||||
if (this.options.verbose) {
|
||||
this.log(`API request started: ts=${ts}`)
|
||||
}
|
||||
break
|
||||
|
||||
default:
|
||||
// Other say types - show in verbose mode
|
||||
if (this.options.verbose) {
|
||||
this.log(`Unknown say type: ${say}, text length: ${text?.length ?? 0}, partial: ${isPartial}`)
|
||||
if (text && !alreadyDisplayedComplete) {
|
||||
this.output(`\n[${say}]`, text || "")
|
||||
this.displayedMessages.set(ts, { text: text || "", partial: false })
|
||||
}
|
||||
}
|
||||
// NO-OP
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -986,7 +1050,7 @@ export class ExtensionHost extends EventEmitter {
|
|||
case "followup":
|
||||
if (!alreadyDisplayed) {
|
||||
// In non-interactive mode, still prompt the user but with a 10s timeout
|
||||
// that auto-selects the first option if no input is received
|
||||
// that auto-selects the first option if no input is received.
|
||||
this.pendingAsks.add(ts)
|
||||
this.handleFollowupQuestionWithTimeout(ts, text)
|
||||
this.displayedMessages.set(ts, { text, partial: false })
|
||||
|
|
@ -1000,7 +1064,7 @@ export class ExtensionHost extends EventEmitter {
|
|||
}
|
||||
break
|
||||
|
||||
// Note: command_output is handled separately in handleCommandOutputAsk
|
||||
// Note: command_output is handled separately in handleCommandOutputAsk.
|
||||
|
||||
case "tool":
|
||||
if (!alreadyDisplayed && text) {
|
||||
|
|
@ -1008,11 +1072,16 @@ export class ExtensionHost extends EventEmitter {
|
|||
const toolInfo = JSON.parse(text)
|
||||
const toolName = toolInfo.tool || "unknown"
|
||||
this.output(`\n[tool] ${toolName}`)
|
||||
// Display all tool parameters (excluding 'tool' which is the name)
|
||||
|
||||
// Display all tool parameters (excluding 'tool' which is the name).
|
||||
for (const [key, value] of Object.entries(toolInfo)) {
|
||||
if (key === "tool") continue
|
||||
if (key === "tool") {
|
||||
continue
|
||||
}
|
||||
|
||||
// Format the value - truncate long strings
|
||||
let displayValue: string
|
||||
|
||||
if (typeof value === "string") {
|
||||
displayValue = value.length > 200 ? value.substring(0, 200) + "..." : value
|
||||
} else if (typeof value === "object" && value !== null) {
|
||||
|
|
@ -1021,21 +1090,13 @@ export class ExtensionHost extends EventEmitter {
|
|||
} else {
|
||||
displayValue = String(value)
|
||||
}
|
||||
this.output(` ${key}: ${displayValue}`)
|
||||
}
|
||||
|
||||
// Proactively send API config when switchMode tool is detected
|
||||
// This helps preserve provider/model settings across mode switches
|
||||
if (toolName === "switchMode") {
|
||||
this.log("switchMode tool detected, proactively sending API configuration...")
|
||||
this.sendToExtension({
|
||||
type: "updateSettings",
|
||||
updatedSettings: this.buildApiConfiguration(),
|
||||
})
|
||||
this.output(` ${key}: ${displayValue}`)
|
||||
}
|
||||
} catch {
|
||||
this.output("\n[tool]", text)
|
||||
}
|
||||
|
||||
this.displayedMessages.set(ts, { text, partial: false })
|
||||
}
|
||||
break
|
||||
|
|
@ -1394,15 +1455,20 @@ export class ExtensionHost extends EventEmitter {
|
|||
toolInfo = JSON.parse(text) as Record<string, unknown>
|
||||
toolName = (toolInfo.tool as string) || "unknown"
|
||||
} catch {
|
||||
// Use raw text if not JSON
|
||||
// Use raw text if not JSON.
|
||||
}
|
||||
|
||||
this.output(`\n[Tool Request] ${toolName}`)
|
||||
|
||||
// Display all tool parameters (excluding 'tool' which is the name)
|
||||
for (const [key, value] of Object.entries(toolInfo)) {
|
||||
if (key === "tool") continue
|
||||
if (key === "tool") {
|
||||
continue
|
||||
}
|
||||
|
||||
// Format the value - truncate long strings
|
||||
let displayValue: string
|
||||
|
||||
if (typeof value === "string") {
|
||||
displayValue = value.length > 200 ? value.substring(0, 200) + "..." : value
|
||||
} else if (typeof value === "object" && value !== null) {
|
||||
|
|
@ -1411,6 +1477,7 @@ export class ExtensionHost extends EventEmitter {
|
|||
} else {
|
||||
displayValue = String(value)
|
||||
}
|
||||
|
||||
this.output(` ${key}: ${displayValue}`)
|
||||
}
|
||||
|
||||
|
|
@ -1431,7 +1498,10 @@ export class ExtensionHost extends EventEmitter {
|
|||
*/
|
||||
private async handleBrowserApproval(ts: number, text: string): Promise<void> {
|
||||
this.output("\n[browser action request]")
|
||||
if (text) this.output(` Action: ${text}`)
|
||||
|
||||
if (text) {
|
||||
this.output(` Action: ${text}`)
|
||||
}
|
||||
|
||||
try {
|
||||
const approved = await this.promptForYesNo("Allow browser action? (y/n): ")
|
||||
|
|
@ -1440,7 +1510,8 @@ export class ExtensionHost extends EventEmitter {
|
|||
this.output("[Defaulting to: no]")
|
||||
this.sendApprovalResponse(false)
|
||||
}
|
||||
// Note: Don't delete from pendingAsks - see handleFollowupQuestion comment
|
||||
|
||||
// Note: Don't delete from pendingAsks - see handleFollowupQuestion comment.
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1454,19 +1525,26 @@ export class ExtensionHost extends EventEmitter {
|
|||
try {
|
||||
const mcpInfo = JSON.parse(text)
|
||||
serverName = mcpInfo.server_name || "unknown"
|
||||
|
||||
if (mcpInfo.type === "use_mcp_tool") {
|
||||
toolName = mcpInfo.tool_name || ""
|
||||
} else if (mcpInfo.type === "access_mcp_resource") {
|
||||
resourceUri = mcpInfo.uri || ""
|
||||
}
|
||||
} catch {
|
||||
// Use raw text if not JSON
|
||||
// Use raw text if not JSON.
|
||||
}
|
||||
|
||||
this.output("\n[mcp request]")
|
||||
this.output(` Server: ${serverName}`)
|
||||
if (toolName) this.output(` Tool: ${toolName}`)
|
||||
if (resourceUri) this.output(` Resource: ${resourceUri}`)
|
||||
|
||||
if (toolName) {
|
||||
this.output(` Tool: ${toolName}`)
|
||||
}
|
||||
|
||||
if (resourceUri) {
|
||||
this.output(` Resource: ${resourceUri}`)
|
||||
}
|
||||
|
||||
try {
|
||||
const approved = await this.promptForYesNo("Allow MCP access? (y/n): ")
|
||||
|
|
@ -1475,7 +1553,8 @@ export class ExtensionHost extends EventEmitter {
|
|||
this.output("[Defaulting to: no]")
|
||||
this.sendApprovalResponse(false)
|
||||
}
|
||||
// Note: Don't delete from pendingAsks - see handleFollowupQuestion comment
|
||||
|
||||
// Note: Don't delete from pendingAsks - see handleFollowupQuestion comment.
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1501,7 +1580,10 @@ export class ExtensionHost extends EventEmitter {
|
|||
private async handleResumeTask(ts: number, ask: string, text: string): Promise<void> {
|
||||
const isCompleted = ask === "resume_completed_task"
|
||||
this.output(`\n[Resume ${isCompleted ? "Completed " : ""}Task]`)
|
||||
if (text) this.output(` ${text}`)
|
||||
|
||||
if (text) {
|
||||
this.output(` ${text}`)
|
||||
}
|
||||
|
||||
try {
|
||||
const resume = await this.promptForYesNo("Continue with this task? (y/n): ")
|
||||
|
|
@ -1510,7 +1592,8 @@ export class ExtensionHost extends EventEmitter {
|
|||
this.output("[Defaulting to: no]")
|
||||
this.sendApprovalResponse(false)
|
||||
}
|
||||
// Note: Don't delete from pendingAsks - see handleFollowupQuestion comment
|
||||
|
||||
// Note: Don't delete from pendingAsks - see handleFollowupQuestion comment.
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1518,7 +1601,10 @@ export class ExtensionHost extends EventEmitter {
|
|||
*/
|
||||
private async handleGenericApproval(ts: number, ask: string, text: string): Promise<void> {
|
||||
this.output(`\n[${ask}]`)
|
||||
if (text) this.output(` ${text}`)
|
||||
|
||||
if (text) {
|
||||
this.output(` ${text}`)
|
||||
}
|
||||
|
||||
try {
|
||||
const approved = await this.promptForYesNo("Approve? (y/n): ")
|
||||
|
|
@ -1527,7 +1613,8 @@ export class ExtensionHost extends EventEmitter {
|
|||
this.output("[Defaulting to: no]")
|
||||
this.sendApprovalResponse(false)
|
||||
}
|
||||
// Note: Don't delete from pendingAsks - see handleFollowupQuestion comment
|
||||
|
||||
// Note: Don't delete from pendingAsks - see handleFollowupQuestion comment.
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1546,18 +1633,21 @@ export class ExtensionHost extends EventEmitter {
|
|||
// Message complete - output any remaining content and send approval
|
||||
if (text && !alreadyDisplayedComplete) {
|
||||
const streamed = this.streamedContent.get(ts)
|
||||
|
||||
if (streamed) {
|
||||
// We were streaming - output any remaining delta and finish.
|
||||
if (text.length > streamed.text.length && text.startsWith(streamed.text)) {
|
||||
const delta = text.slice(streamed.text.length)
|
||||
this.writeStream(delta)
|
||||
}
|
||||
|
||||
this.finishStream(ts)
|
||||
} else {
|
||||
this.writeStream("\n[command output] ")
|
||||
this.writeStream(text)
|
||||
this.writeStream("\n")
|
||||
}
|
||||
|
||||
this.displayedMessages.set(ts, { text, partial: false })
|
||||
this.streamedContent.set(ts, { text, headerShown: true })
|
||||
}
|
||||
|
|
@ -1629,11 +1719,7 @@ export class ExtensionHost extends EventEmitter {
|
|||
* Send a followup response (text answer) to the extension
|
||||
*/
|
||||
private sendFollowupResponse(text: string): void {
|
||||
this.sendToExtension({
|
||||
type: "askResponse",
|
||||
askResponse: "messageResponse",
|
||||
text,
|
||||
})
|
||||
this.sendToExtension({ type: "askResponse", askResponse: "messageResponse", text })
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1646,28 +1732,6 @@ export class ExtensionHost extends EventEmitter {
|
|||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle action messages
|
||||
*/
|
||||
private handleActionMessage(msg: Record<string, unknown>): void {
|
||||
const action = msg.action as string
|
||||
|
||||
if (this.options.verbose) {
|
||||
this.log("Action:", action)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle invoke messages
|
||||
*/
|
||||
private handleInvokeMessage(msg: Record<string, unknown>): void {
|
||||
const invoke = msg.invoke as string
|
||||
|
||||
if (this.options.verbose) {
|
||||
this.log("Invoke:", invoke)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for the task to complete
|
||||
*/
|
||||
|
|
@ -1710,8 +1774,6 @@ export class ExtensionHost extends EventEmitter {
|
|||
* Clean up resources
|
||||
*/
|
||||
async dispose(): Promise<void> {
|
||||
this.log("Disposing extension host...")
|
||||
|
||||
// Clear pending asks
|
||||
this.pendingAsks.clear()
|
||||
|
||||
|
|
@ -1731,8 +1793,8 @@ export class ExtensionHost extends EventEmitter {
|
|||
if (this.extensionModule?.deactivate) {
|
||||
try {
|
||||
await this.extensionModule.deactivate()
|
||||
} catch (error) {
|
||||
this.log("Error deactivating extension:", error)
|
||||
} catch (_error) {
|
||||
// NO-OP
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1748,7 +1810,5 @@ export class ExtensionHost extends EventEmitter {
|
|||
|
||||
// Restore console if it was suppressed
|
||||
this.restoreConsole()
|
||||
|
||||
this.log("Extension host disposed")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
62
apps/cli/src/globalCommands.ts
Normal file
62
apps/cli/src/globalCommands.ts
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
/**
|
||||
* CLI-specific global slash commands
|
||||
*
|
||||
* These commands are handled entirely within the CLI and trigger actions
|
||||
* by sending messages to the extension host. They are separate from the
|
||||
* extension's built-in commands which expand into prompt content.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Action types that can be triggered by global commands.
|
||||
* Each action corresponds to a message type sent to the extension host.
|
||||
*/
|
||||
export type GlobalCommandAction = "clearTask"
|
||||
|
||||
/**
|
||||
* Definition of a CLI global command
|
||||
*/
|
||||
export interface GlobalCommand {
|
||||
/** Command name (without the leading /) */
|
||||
name: string
|
||||
/** Description shown in the autocomplete picker */
|
||||
description: string
|
||||
/** Action to trigger when the command is executed */
|
||||
action: GlobalCommandAction
|
||||
}
|
||||
|
||||
/**
|
||||
* CLI-specific global slash commands
|
||||
* These commands trigger actions rather than expanding into prompt content.
|
||||
*/
|
||||
export const GLOBAL_COMMANDS: GlobalCommand[] = [
|
||||
{
|
||||
name: "new",
|
||||
description: "Start a new task",
|
||||
action: "clearTask",
|
||||
},
|
||||
]
|
||||
|
||||
/**
|
||||
* Get a global command by name
|
||||
*/
|
||||
export function getGlobalCommand(name: string): GlobalCommand | undefined {
|
||||
return GLOBAL_COMMANDS.find((cmd) => cmd.name === name)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get global commands formatted for autocomplete
|
||||
* Returns commands in the SlashCommandResult format expected by the autocomplete trigger
|
||||
*/
|
||||
export function getGlobalCommandsForAutocomplete(): Array<{
|
||||
name: string
|
||||
description?: string
|
||||
source: "global" | "project" | "built-in"
|
||||
action?: string
|
||||
}> {
|
||||
return GLOBAL_COMMANDS.map((cmd) => ({
|
||||
name: cmd.name,
|
||||
description: cmd.description,
|
||||
source: "global" as const,
|
||||
action: cmd.action,
|
||||
}))
|
||||
}
|
||||
|
|
@ -44,6 +44,7 @@ import type {
|
|||
SlashCommandResult,
|
||||
ModeResult,
|
||||
} from "./types.js"
|
||||
import { getGlobalCommand, getGlobalCommandsForAutocomplete } from "../globalCommands.js"
|
||||
|
||||
// Layout constants
|
||||
const PICKER_HEIGHT = 10 // Max height for picker when open
|
||||
|
|
@ -333,7 +334,13 @@ function AppInner({
|
|||
})
|
||||
|
||||
const slashCommandTrigger = createSlashCommandTrigger({
|
||||
getCommands: () => allSlashCommandsRef.current.map(toSlashCommandResult),
|
||||
getCommands: () => {
|
||||
// Merge CLI global commands with extension commands
|
||||
const extensionCommands = allSlashCommandsRef.current.map(toSlashCommandResult)
|
||||
const globalCommands = getGlobalCommandsForAutocomplete().map(toSlashCommandResult)
|
||||
// Global commands appear first, then extension commands
|
||||
return [...globalCommands, ...extensionCommands]
|
||||
},
|
||||
})
|
||||
|
||||
const modeTrigger = createModeTrigger({
|
||||
|
|
@ -815,7 +822,6 @@ function AppInner({
|
|||
}
|
||||
}, []) // Run once on mount
|
||||
|
||||
// Handle user input submission
|
||||
const handleSubmit = useCallback(
|
||||
async (text: string) => {
|
||||
if (!hostRef.current || !text.trim()) {
|
||||
|
|
@ -828,18 +834,34 @@ function AppInner({
|
|||
return
|
||||
}
|
||||
|
||||
// Check for CLI global action commands (e.g., /new).
|
||||
if (trimmedText.startsWith("/")) {
|
||||
const commandMatch = trimmedText.match(/^\/(\w+)(?:\s|$)/)
|
||||
|
||||
if (commandMatch && commandMatch[1]) {
|
||||
const globalCommand = getGlobalCommand(commandMatch[1])
|
||||
|
||||
if (globalCommand?.action === "clearTask") {
|
||||
// Reset CLI state and send clearTask to extension.
|
||||
useCLIStore.getState().reset()
|
||||
// Reset component-level refs to avoid stale message tracking.
|
||||
seenMessageIds.current.clear()
|
||||
firstTextMessageSkipped.current = false
|
||||
hostRef.current.sendToExtension({ type: "clearTask" })
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pendingAsk) {
|
||||
addMessage({
|
||||
id: randomUUID(),
|
||||
role: "user",
|
||||
content: trimmedText,
|
||||
})
|
||||
addMessage({ id: randomUUID(), role: "user", content: trimmedText })
|
||||
|
||||
hostRef.current.sendToExtension({
|
||||
type: "askResponse",
|
||||
askResponse: "messageResponse",
|
||||
text: trimmedText,
|
||||
})
|
||||
|
||||
setPendingAsk(null)
|
||||
setShowCustomInput(false)
|
||||
isTransitioningToCustomInput.current = false
|
||||
|
|
@ -847,12 +869,7 @@ function AppInner({
|
|||
} else if (!hasStartedTask) {
|
||||
setHasStartedTask(true)
|
||||
setLoading(true)
|
||||
|
||||
addMessage({
|
||||
id: randomUUID(),
|
||||
role: "user",
|
||||
content: trimmedText,
|
||||
})
|
||||
addMessage({ id: randomUUID(), role: "user", content: trimmedText })
|
||||
|
||||
try {
|
||||
await hostRef.current.runTask(trimmedText)
|
||||
|
|
@ -864,13 +881,9 @@ function AppInner({
|
|||
if (isComplete) {
|
||||
setComplete(false)
|
||||
}
|
||||
setLoading(true)
|
||||
|
||||
addMessage({
|
||||
id: randomUUID(),
|
||||
role: "user",
|
||||
content: trimmedText,
|
||||
})
|
||||
setLoading(true)
|
||||
addMessage({ id: randomUUID(), role: "user", content: trimmedText })
|
||||
|
||||
hostRef.current.sendToExtension({
|
||||
type: "askResponse",
|
||||
|
|
@ -894,24 +907,22 @@ function AppInner({
|
|||
|
||||
// Handle approval (Y key)
|
||||
const handleApprove = useCallback(() => {
|
||||
if (!hostRef.current) return
|
||||
if (!hostRef.current) {
|
||||
return
|
||||
}
|
||||
|
||||
hostRef.current.sendToExtension({
|
||||
type: "askResponse",
|
||||
askResponse: "yesButtonClicked",
|
||||
})
|
||||
hostRef.current.sendToExtension({ type: "askResponse", askResponse: "yesButtonClicked" })
|
||||
setPendingAsk(null)
|
||||
setLoading(true)
|
||||
}, [setPendingAsk, setLoading])
|
||||
|
||||
// Handle rejection (N key)
|
||||
const handleReject = useCallback(() => {
|
||||
if (!hostRef.current) return
|
||||
if (!hostRef.current) {
|
||||
return
|
||||
}
|
||||
|
||||
hostRef.current.sendToExtension({
|
||||
type: "askResponse",
|
||||
askResponse: "noButtonClicked",
|
||||
})
|
||||
hostRef.current.sendToExtension({ type: "askResponse", askResponse: "noButtonClicked" })
|
||||
setPendingAsk(null)
|
||||
setLoading(true)
|
||||
}, [setPendingAsk, setLoading])
|
||||
|
|
@ -920,6 +931,7 @@ function AppInner({
|
|||
useInput((input) => {
|
||||
if (pendingAsk && pendingAsk.type !== "followup") {
|
||||
const lower = input.toLowerCase()
|
||||
|
||||
if (lower === "y") {
|
||||
handleApprove()
|
||||
} else if (lower === "n") {
|
||||
|
|
@ -930,9 +942,7 @@ function AppInner({
|
|||
|
||||
// Handle picker state changes from AutocompleteInput
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const handlePickerStateChange = useCallback((state: AutocompletePickerState<any>) => {
|
||||
setPickerState(state)
|
||||
}, [])
|
||||
const handlePickerStateChange = useCallback((state: AutocompletePickerState<any>) => setPickerState(state), [])
|
||||
|
||||
// Handle item selection from external PickerSelect
|
||||
const handlePickerSelect = useCallback(
|
||||
|
|
@ -941,13 +951,12 @@ function AppInner({
|
|||
// Check if this is a mode selection
|
||||
if (pickerState.activeTrigger?.id === "mode" && item && typeof item === "object" && "slug" in item) {
|
||||
const modeItem = item as ModeItem
|
||||
|
||||
// Send mode change message to extension
|
||||
if (hostRef.current) {
|
||||
hostRef.current.sendToExtension({
|
||||
type: "switchMode",
|
||||
mode: modeItem.slug,
|
||||
})
|
||||
hostRef.current.sendToExtension({ type: "switchMode", mode: modeItem.slug })
|
||||
}
|
||||
|
||||
// Close the picker
|
||||
autocompleteRef.current?.closePicker()
|
||||
followupAutocompleteRef.current?.closePicker()
|
||||
|
|
@ -1379,13 +1388,20 @@ function parseMarkdownChecklist(markdown: string): TodoItem[] {
|
|||
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
const line = lines[i]
|
||||
if (!line) continue
|
||||
|
||||
if (!line) {
|
||||
continue
|
||||
}
|
||||
|
||||
const trimmedLine = line.trim()
|
||||
if (!trimmedLine) continue
|
||||
|
||||
if (!trimmedLine) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Match markdown checkbox patterns
|
||||
const checkboxMatch = trimmedLine.match(/^\[([x\-\s])\]\s*(.+)$/i)
|
||||
|
||||
if (checkboxMatch) {
|
||||
const statusChar = checkboxMatch[1] ?? " "
|
||||
const content = checkboxMatch[2] ?? ""
|
||||
|
|
@ -1397,11 +1413,7 @@ function parseMarkdownChecklist(markdown: string): TodoItem[] {
|
|||
status = "in_progress"
|
||||
}
|
||||
|
||||
todos.push({
|
||||
id: `todo-${i}`,
|
||||
content: content.trim(),
|
||||
status,
|
||||
})
|
||||
todos.push({ id: `todo-${i}`, content: content.trim(), status })
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,8 @@ export interface SlashCommandResult extends AutocompleteItem {
|
|||
argumentHint?: string
|
||||
/** Source of the command */
|
||||
source: "global" | "project" | "built-in"
|
||||
/** Action to trigger for CLI global commands (only present for action commands) */
|
||||
action?: string
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -92,8 +94,15 @@ export function createSlashCommandTrigger(config: SlashCommandTriggerConfig): Au
|
|||
},
|
||||
|
||||
renderItem: (item: SlashCommandResult, isSelected: boolean) => {
|
||||
// Source indicator icons
|
||||
const sourceIcon = item.source === "built-in" ? "⚡" : item.source === "project" ? "📁" : "🌐"
|
||||
// Source indicator icons:
|
||||
// ⚙️ for action commands (CLI global), ⚡ built-in, 📁 project, 🌐 global (content)
|
||||
const sourceIcon = item.action
|
||||
? "⚙️"
|
||||
: item.source === "built-in"
|
||||
? "⚡"
|
||||
: item.source === "project"
|
||||
? "📁"
|
||||
: "🌐"
|
||||
|
||||
return (
|
||||
<Box paddingLeft={2}>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
import type { ClineAsk, ClineSay, TodoItem } from "@roo-code/types"
|
||||
|
||||
import type { GlobalCommandAction } from "../globalCommands.js"
|
||||
|
||||
// Re-export TodoItem for convenience
|
||||
export type { TodoItem }
|
||||
|
||||
|
|
@ -86,6 +88,8 @@ export interface SlashCommandResult {
|
|||
description?: string
|
||||
argumentHint?: string
|
||||
source: "global" | "project" | "built-in"
|
||||
/** Action to trigger for CLI global commands (e.g., clearTask for /new) */
|
||||
action?: GlobalCommandAction
|
||||
}
|
||||
|
||||
export interface ModeResult {
|
||||
|
|
|
|||
13
packages/types/src/git.ts
Normal file
13
packages/types/src/git.ts
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
export interface GitRepositoryInfo {
|
||||
repositoryUrl?: string
|
||||
repositoryName?: string
|
||||
defaultBranch?: string
|
||||
}
|
||||
|
||||
export interface GitCommit {
|
||||
hash: string
|
||||
shortHash: string
|
||||
subject: string
|
||||
author: string
|
||||
date: string
|
||||
}
|
||||
|
|
@ -7,6 +7,7 @@ export * from "./custom-tool.js"
|
|||
export * from "./events.js"
|
||||
export * from "./experiment.js"
|
||||
export * from "./followup.js"
|
||||
export * from "./git.js"
|
||||
export * from "./global-settings.js"
|
||||
export * from "./history.js"
|
||||
export * from "./image-generation.js"
|
||||
|
|
@ -24,6 +25,7 @@ export * from "./terminal.js"
|
|||
export * from "./tool.js"
|
||||
export * from "./tool-params.js"
|
||||
export * from "./type-fu.js"
|
||||
export * from "./vscode-extension-host.js"
|
||||
export * from "./vscode.js"
|
||||
|
||||
export * from "./providers/index.js"
|
||||
|
|
|
|||
|
|
@ -86,3 +86,8 @@ export const installMarketplaceItemOptionsSchema = z.object({
|
|||
})
|
||||
|
||||
export type InstallMarketplaceItemOptions = z.infer<typeof installMarketplaceItemOptionsSchema>
|
||||
|
||||
export interface MarketplaceInstalledMetadata {
|
||||
project: Record<string, { type: string }>
|
||||
global: Record<string, { type: string }>
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
import { z } from "zod"
|
||||
|
||||
/**
|
||||
* MCP Server Use Types
|
||||
* McpServerUse
|
||||
*/
|
||||
|
||||
export interface McpServerUse {
|
||||
type: string
|
||||
serverName: string
|
||||
|
|
@ -39,3 +40,91 @@ export const mcpExecutionStatusSchema = z.discriminatedUnion("status", [
|
|||
])
|
||||
|
||||
export type McpExecutionStatus = z.infer<typeof mcpExecutionStatusSchema>
|
||||
|
||||
/**
|
||||
* McpServer
|
||||
*/
|
||||
|
||||
export type McpServer = {
|
||||
name: string
|
||||
config: string
|
||||
status: "connected" | "connecting" | "disconnected"
|
||||
error?: string
|
||||
errorHistory?: McpErrorEntry[]
|
||||
tools?: McpTool[]
|
||||
resources?: McpResource[]
|
||||
resourceTemplates?: McpResourceTemplate[]
|
||||
disabled?: boolean
|
||||
timeout?: number
|
||||
source?: "global" | "project"
|
||||
projectPath?: string
|
||||
instructions?: string
|
||||
}
|
||||
|
||||
export type McpTool = {
|
||||
name: string
|
||||
description?: string
|
||||
inputSchema?: object
|
||||
alwaysAllow?: boolean
|
||||
enabledForPrompt?: boolean
|
||||
}
|
||||
|
||||
export type McpResource = {
|
||||
uri: string
|
||||
name: string
|
||||
mimeType?: string
|
||||
description?: string
|
||||
}
|
||||
|
||||
export type McpResourceTemplate = {
|
||||
uriTemplate: string
|
||||
name: string
|
||||
description?: string
|
||||
mimeType?: string
|
||||
}
|
||||
|
||||
export type McpResourceResponse = {
|
||||
_meta?: Record<string, any> // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
contents: Array<{
|
||||
uri: string
|
||||
mimeType?: string
|
||||
text?: string
|
||||
blob?: string
|
||||
}>
|
||||
}
|
||||
|
||||
export type McpToolCallResponse = {
|
||||
_meta?: Record<string, any> // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
content: Array<
|
||||
| {
|
||||
type: "text"
|
||||
text: string
|
||||
}
|
||||
| {
|
||||
type: "image"
|
||||
data: string
|
||||
mimeType: string
|
||||
}
|
||||
| {
|
||||
type: "audio"
|
||||
data: string
|
||||
mimeType: string
|
||||
}
|
||||
| {
|
||||
type: "resource"
|
||||
resource: {
|
||||
uri: string
|
||||
mimeType?: string
|
||||
text?: string
|
||||
blob?: string
|
||||
}
|
||||
}
|
||||
>
|
||||
isError?: boolean
|
||||
}
|
||||
|
||||
export type McpErrorEntry = {
|
||||
message: string
|
||||
timestamp: number
|
||||
level: "error" | "warn" | "info"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { z } from "zod"
|
||||
import { DynamicProvider, LocalProvider } from "./provider-settings.js"
|
||||
|
||||
/**
|
||||
* ReasoningEffort
|
||||
|
|
@ -140,3 +141,7 @@ export const modelInfoSchema = z.object({
|
|||
})
|
||||
|
||||
export type ModelInfo = z.infer<typeof modelInfoSchema>
|
||||
|
||||
export type ModelRecord = Record<string, ModelInfo>
|
||||
|
||||
export type RouterModels = Record<DynamicProvider | LocalProvider, ModelRecord>
|
||||
|
|
|
|||
327
packages/types/src/vscode-extension-host.ts
Normal file
327
packages/types/src/vscode-extension-host.ts
Normal file
|
|
@ -0,0 +1,327 @@
|
|||
import type { GlobalSettings } from "./global-settings.js"
|
||||
import type { ProviderSettings, ProviderSettingsEntry } from "./provider-settings.js"
|
||||
import type { HistoryItem } from "./history.js"
|
||||
import type { ModeConfig } from "./mode.js"
|
||||
import type { TelemetrySetting } from "./telemetry.js"
|
||||
import type { Experiments } from "./experiment.js"
|
||||
import type { ClineMessage, QueuedMessage } from "./message.js"
|
||||
import type { MarketplaceItem, MarketplaceInstalledMetadata } from "./marketplace.js"
|
||||
import type { TodoItem } from "./todo.js"
|
||||
import type { CloudUserInfo, CloudOrganizationMembership, OrganizationAllowList, ShareVisibility } from "./cloud.js"
|
||||
import type { SerializedCustomToolDefinition } from "./custom-tool.js"
|
||||
import type { GitCommit } from "./git.js"
|
||||
import type { McpServer } from "./mcp.js"
|
||||
import type { ModelRecord, RouterModels } from "./model.js"
|
||||
|
||||
// Represents JSON data that is sent from extension to the webview or cli.
|
||||
export interface ExtensionMessage {
|
||||
type:
|
||||
| "action"
|
||||
| "state"
|
||||
| "selectedImages"
|
||||
| "theme"
|
||||
| "workspaceUpdated"
|
||||
| "invoke"
|
||||
| "messageUpdated"
|
||||
| "mcpServers"
|
||||
| "enhancedPrompt"
|
||||
| "commitSearchResults"
|
||||
| "listApiConfig"
|
||||
| "routerModels"
|
||||
| "openAiModels"
|
||||
| "ollamaModels"
|
||||
| "lmStudioModels"
|
||||
| "vsCodeLmModels"
|
||||
| "huggingFaceModels"
|
||||
| "vsCodeLmApiAvailable"
|
||||
| "updatePrompt"
|
||||
| "systemPrompt"
|
||||
| "autoApprovalEnabled"
|
||||
| "updateCustomMode"
|
||||
| "deleteCustomMode"
|
||||
| "exportModeResult"
|
||||
| "importModeResult"
|
||||
| "checkRulesDirectoryResult"
|
||||
| "deleteCustomModeCheck"
|
||||
| "currentCheckpointUpdated"
|
||||
| "checkpointInitWarning"
|
||||
| "browserToolEnabled"
|
||||
| "browserConnectionResult"
|
||||
| "remoteBrowserEnabled"
|
||||
| "ttsStart"
|
||||
| "ttsStop"
|
||||
| "maxReadFileLine"
|
||||
| "fileSearchResults"
|
||||
| "toggleApiConfigPin"
|
||||
| "acceptInput"
|
||||
| "setHistoryPreviewCollapsed"
|
||||
| "commandExecutionStatus"
|
||||
| "mcpExecutionStatus"
|
||||
| "vsCodeSetting"
|
||||
| "authenticatedUser"
|
||||
| "condenseTaskContextStarted"
|
||||
| "condenseTaskContextResponse"
|
||||
| "singleRouterModelFetchResponse"
|
||||
| "rooCreditBalance"
|
||||
| "indexingStatusUpdate"
|
||||
| "indexCleared"
|
||||
| "codebaseIndexConfig"
|
||||
| "marketplaceInstallResult"
|
||||
| "marketplaceRemoveResult"
|
||||
| "marketplaceData"
|
||||
| "shareTaskSuccess"
|
||||
| "codeIndexSettingsSaved"
|
||||
| "codeIndexSecretStatus"
|
||||
| "showDeleteMessageDialog"
|
||||
| "showEditMessageDialog"
|
||||
| "commands"
|
||||
| "insertTextIntoTextarea"
|
||||
| "dismissedUpsells"
|
||||
| "organizationSwitchResult"
|
||||
| "interactionRequired"
|
||||
| "browserSessionUpdate"
|
||||
| "browserSessionNavigate"
|
||||
| "claudeCodeRateLimits"
|
||||
| "customToolsResult"
|
||||
| "modes"
|
||||
text?: string
|
||||
payload?: any // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
checkpointWarning?: {
|
||||
type: "WAIT_TIMEOUT" | "INIT_TIMEOUT"
|
||||
timeout: number
|
||||
}
|
||||
action?:
|
||||
| "chatButtonClicked"
|
||||
| "settingsButtonClicked"
|
||||
| "historyButtonClicked"
|
||||
| "marketplaceButtonClicked"
|
||||
| "cloudButtonClicked"
|
||||
| "didBecomeVisible"
|
||||
| "focusInput"
|
||||
| "switchTab"
|
||||
| "toggleAutoApprove"
|
||||
invoke?: "newChat" | "sendMessage" | "primaryButtonClick" | "secondaryButtonClick" | "setChatBoxMessage"
|
||||
state?: ExtensionState
|
||||
images?: string[]
|
||||
filePaths?: string[]
|
||||
openedTabs?: Array<{
|
||||
label: string
|
||||
isActive: boolean
|
||||
path?: string
|
||||
}>
|
||||
clineMessage?: ClineMessage
|
||||
routerModels?: RouterModels
|
||||
openAiModels?: string[]
|
||||
ollamaModels?: ModelRecord
|
||||
lmStudioModels?: ModelRecord
|
||||
vsCodeLmModels?: { vendor?: string; family?: string; version?: string; id?: string }[]
|
||||
huggingFaceModels?: Array<{
|
||||
id: string
|
||||
object: string
|
||||
created: number
|
||||
owned_by: string
|
||||
providers: Array<{
|
||||
provider: string
|
||||
status: "live" | "staging" | "error"
|
||||
supports_tools?: boolean
|
||||
supports_structured_output?: boolean
|
||||
context_length?: number
|
||||
pricing?: {
|
||||
input: number
|
||||
output: number
|
||||
}
|
||||
}>
|
||||
}>
|
||||
mcpServers?: McpServer[]
|
||||
commits?: GitCommit[]
|
||||
listApiConfig?: ProviderSettingsEntry[]
|
||||
mode?: string
|
||||
customMode?: ModeConfig
|
||||
slug?: string
|
||||
success?: boolean
|
||||
values?: Record<string, any> // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
requestId?: string
|
||||
promptText?: string
|
||||
results?:
|
||||
| { path: string; type: "file" | "folder"; label?: string }[]
|
||||
| { name: string; description?: string; argumentHint?: string; source: "global" | "project" | "built-in" }[]
|
||||
error?: string
|
||||
setting?: string
|
||||
value?: any // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
hasContent?: boolean
|
||||
items?: MarketplaceItem[]
|
||||
userInfo?: CloudUserInfo
|
||||
organizationAllowList?: OrganizationAllowList
|
||||
tab?: string
|
||||
marketplaceItems?: MarketplaceItem[]
|
||||
organizationMcps?: MarketplaceItem[]
|
||||
marketplaceInstalledMetadata?: MarketplaceInstalledMetadata
|
||||
errors?: string[]
|
||||
visibility?: ShareVisibility
|
||||
rulesFolderPath?: string
|
||||
settings?: any // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
messageTs?: number
|
||||
hasCheckpoint?: boolean
|
||||
context?: string
|
||||
commands?: Command[]
|
||||
queuedMessages?: QueuedMessage[]
|
||||
list?: string[] // For dismissedUpsells
|
||||
organizationId?: string | null // For organizationSwitchResult
|
||||
browserSessionMessages?: ClineMessage[] // For browser session panel updates
|
||||
isBrowserSessionActive?: boolean // For browser session panel updates
|
||||
stepIndex?: number // For browserSessionNavigate: the target step index to display
|
||||
tools?: SerializedCustomToolDefinition[] // For customToolsResult
|
||||
modes?: { slug: string; name: string }[] // For modes response
|
||||
}
|
||||
|
||||
export type ExtensionState = Pick<
|
||||
GlobalSettings,
|
||||
| "currentApiConfigName"
|
||||
| "listApiConfigMeta"
|
||||
| "pinnedApiConfigs"
|
||||
| "customInstructions"
|
||||
| "dismissedUpsells"
|
||||
| "autoApprovalEnabled"
|
||||
| "alwaysAllowReadOnly"
|
||||
| "alwaysAllowReadOnlyOutsideWorkspace"
|
||||
| "alwaysAllowWrite"
|
||||
| "alwaysAllowWriteOutsideWorkspace"
|
||||
| "alwaysAllowWriteProtected"
|
||||
| "alwaysAllowBrowser"
|
||||
| "alwaysAllowMcp"
|
||||
| "alwaysAllowModeSwitch"
|
||||
| "alwaysAllowSubtasks"
|
||||
| "alwaysAllowFollowupQuestions"
|
||||
| "alwaysAllowExecute"
|
||||
| "followupAutoApproveTimeoutMs"
|
||||
| "allowedCommands"
|
||||
| "deniedCommands"
|
||||
| "allowedMaxRequests"
|
||||
| "allowedMaxCost"
|
||||
| "browserToolEnabled"
|
||||
| "browserViewportSize"
|
||||
| "screenshotQuality"
|
||||
| "remoteBrowserEnabled"
|
||||
| "cachedChromeHostUrl"
|
||||
| "remoteBrowserHost"
|
||||
| "ttsEnabled"
|
||||
| "ttsSpeed"
|
||||
| "soundEnabled"
|
||||
| "soundVolume"
|
||||
| "maxConcurrentFileReads"
|
||||
| "terminalOutputLineLimit"
|
||||
| "terminalOutputCharacterLimit"
|
||||
| "terminalShellIntegrationTimeout"
|
||||
| "terminalShellIntegrationDisabled"
|
||||
| "terminalCommandDelay"
|
||||
| "terminalPowershellCounter"
|
||||
| "terminalZshClearEolMark"
|
||||
| "terminalZshOhMy"
|
||||
| "terminalZshP10k"
|
||||
| "terminalZdotdir"
|
||||
| "terminalCompressProgressBar"
|
||||
| "diagnosticsEnabled"
|
||||
| "diffEnabled"
|
||||
| "fuzzyMatchThreshold"
|
||||
| "language"
|
||||
| "modeApiConfigs"
|
||||
| "customModePrompts"
|
||||
| "customSupportPrompts"
|
||||
| "enhancementApiConfigId"
|
||||
| "condensingApiConfigId"
|
||||
| "customCondensingPrompt"
|
||||
| "codebaseIndexConfig"
|
||||
| "codebaseIndexModels"
|
||||
| "profileThresholds"
|
||||
| "includeDiagnosticMessages"
|
||||
| "maxDiagnosticMessages"
|
||||
| "imageGenerationProvider"
|
||||
| "openRouterImageGenerationSelectedModel"
|
||||
| "includeTaskHistoryInEnhance"
|
||||
| "reasoningBlockCollapsed"
|
||||
| "enterBehavior"
|
||||
| "includeCurrentTime"
|
||||
| "includeCurrentCost"
|
||||
| "maxGitStatusFiles"
|
||||
| "requestDelaySeconds"
|
||||
> & {
|
||||
version: string
|
||||
clineMessages: ClineMessage[]
|
||||
currentTaskItem?: HistoryItem
|
||||
currentTaskTodos?: TodoItem[] // Initial todos for the current task
|
||||
apiConfiguration: ProviderSettings
|
||||
uriScheme?: string
|
||||
shouldShowAnnouncement: boolean
|
||||
|
||||
taskHistory: HistoryItem[]
|
||||
|
||||
writeDelayMs: number
|
||||
|
||||
enableCheckpoints: boolean
|
||||
checkpointTimeout: number // Timeout for checkpoint initialization in seconds (default: 15)
|
||||
maxOpenTabsContext: number // Maximum number of VSCode open tabs to include in context (0-500)
|
||||
maxWorkspaceFiles: number // Maximum number of files to include in current working directory details (0-500)
|
||||
showRooIgnoredFiles: boolean // Whether to show .rooignore'd files in listings
|
||||
enableSubfolderRules: boolean // Whether to load rules from subdirectories
|
||||
maxReadFileLine: number // Maximum number of lines to read from a file before truncating
|
||||
maxImageFileSize: number // Maximum size of image files to process in MB
|
||||
maxTotalImageSize: number // Maximum total size for all images in a single read operation in MB
|
||||
|
||||
experiments: Experiments // Map of experiment IDs to their enabled state
|
||||
|
||||
mcpEnabled: boolean
|
||||
enableMcpServerCreation: boolean
|
||||
|
||||
mode: string
|
||||
customModes: ModeConfig[]
|
||||
toolRequirements?: Record<string, boolean> // Map of tool names to their requirements (e.g. {"apply_diff": true} if diffEnabled)
|
||||
|
||||
cwd?: string // Current working directory
|
||||
telemetrySetting: TelemetrySetting
|
||||
telemetryKey?: string
|
||||
machineId?: string
|
||||
|
||||
renderContext: "sidebar" | "editor"
|
||||
settingsImportedAt?: number
|
||||
historyPreviewCollapsed?: boolean
|
||||
|
||||
cloudUserInfo: CloudUserInfo | null
|
||||
cloudIsAuthenticated: boolean
|
||||
cloudAuthSkipModel?: boolean // Flag indicating auth completed without model selection (user should pick 3rd-party provider)
|
||||
cloudApiUrl?: string
|
||||
cloudOrganizations?: CloudOrganizationMembership[]
|
||||
sharingEnabled: boolean
|
||||
publicSharingEnabled: boolean
|
||||
organizationAllowList: OrganizationAllowList
|
||||
organizationSettingsVersion?: number
|
||||
|
||||
isBrowserSessionActive: boolean // Actual browser session state
|
||||
|
||||
autoCondenseContext: boolean
|
||||
autoCondenseContextPercent: number
|
||||
marketplaceItems?: MarketplaceItem[]
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
marketplaceInstalledMetadata?: { project: Record<string, any>; global: Record<string, any> }
|
||||
profileThresholds: Record<string, number>
|
||||
hasOpenedModeSelector: boolean
|
||||
openRouterImageApiKey?: string
|
||||
messageQueue?: QueuedMessage[]
|
||||
lastShownAnnouncementId?: string
|
||||
apiModelId?: string
|
||||
mcpServers?: McpServer[]
|
||||
hasSystemPromptOverride?: boolean
|
||||
mdmCompliant?: boolean
|
||||
remoteControlEnabled: boolean
|
||||
taskSyncEnabled: boolean
|
||||
featureRoomoteControlEnabled: boolean
|
||||
claudeCodeIsAuthenticated?: boolean
|
||||
debug?: boolean
|
||||
}
|
||||
|
||||
export interface Command {
|
||||
name: string
|
||||
source: "global" | "project" | "built-in"
|
||||
filePath?: string
|
||||
description?: string
|
||||
argumentHint?: string
|
||||
}
|
||||
|
|
@ -3,14 +3,13 @@ import { z } from "zod"
|
|||
|
||||
import {
|
||||
type ModelInfo,
|
||||
type ModelRecord,
|
||||
HUGGINGFACE_API_URL,
|
||||
HUGGINGFACE_CACHE_DURATION,
|
||||
HUGGINGFACE_DEFAULT_MAX_TOKENS,
|
||||
HUGGINGFACE_DEFAULT_CONTEXT_WINDOW,
|
||||
} from "@roo-code/types"
|
||||
|
||||
import type { ModelRecord } from "../../../shared/api"
|
||||
|
||||
const huggingFaceProviderSchema = z.object({
|
||||
provider: z.string(),
|
||||
status: z.enum(["live", "staging", "error"]),
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
import axios from "axios"
|
||||
import { z } from "zod"
|
||||
|
||||
import { type ModelInfo, IO_INTELLIGENCE_CACHE_DURATION } from "@roo-code/types"
|
||||
|
||||
import type { ModelRecord } from "../../../shared/api"
|
||||
import { type ModelInfo, type ModelRecord, IO_INTELLIGENCE_CACHE_DURATION } from "@roo-code/types"
|
||||
|
||||
const ioIntelligenceModelSchema = z.object({
|
||||
id: z.string(),
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import axios from "axios"
|
||||
|
||||
import type { ModelRecord } from "../../../shared/api"
|
||||
import type { ModelRecord } from "@roo-code/types"
|
||||
|
||||
import { DEFAULT_HEADERS } from "../constants"
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import * as fsSync from "fs"
|
|||
import NodeCache from "node-cache"
|
||||
import { z } from "zod"
|
||||
|
||||
import type { ProviderName } from "@roo-code/types"
|
||||
import type { ProviderName, ModelRecord } from "@roo-code/types"
|
||||
import { modelInfoSchema, TelemetryEventName } from "@roo-code/types"
|
||||
import { TelemetryService } from "@roo-code/telemetry"
|
||||
|
||||
|
|
@ -13,7 +13,7 @@ import { safeWriteJson } from "../../../utils/safeWriteJson"
|
|||
|
||||
import { ContextProxy } from "../../../core/config/ContextProxy"
|
||||
import { getCacheDirectoryPath } from "../../../utils/storage"
|
||||
import type { RouterName, ModelRecord } from "../../../shared/api"
|
||||
import type { RouterName } from "../../../shared/api"
|
||||
import { fileExistsAtPath } from "../../../utils/fs"
|
||||
|
||||
import { getOpenRouterModels } from "./openrouter"
|
||||
|
|
|
|||
|
|
@ -2,13 +2,15 @@ import * as path from "path"
|
|||
import fs from "fs/promises"
|
||||
|
||||
import NodeCache from "node-cache"
|
||||
import { safeWriteJson } from "../../../utils/safeWriteJson"
|
||||
import sanitize from "sanitize-filename"
|
||||
|
||||
import type { ModelRecord } from "@roo-code/types"
|
||||
|
||||
import { ContextProxy } from "../../../core/config/ContextProxy"
|
||||
import { RouterName } from "../../../shared/api"
|
||||
import { getCacheDirectoryPath } from "../../../utils/storage"
|
||||
import { RouterName, ModelRecord } from "../../../shared/api"
|
||||
import { fileExistsAtPath } from "../../../utils/fs"
|
||||
import { safeWriteJson } from "../../../utils/safeWriteJson"
|
||||
|
||||
import { getOpenRouterModelEndpoints } from "./openrouter"
|
||||
import { getModels } from "./modelCache"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import { RooModelsResponseSchema, type ModelInfo } from "@roo-code/types"
|
||||
import { RooModelsResponseSchema, type ModelInfo, type ModelRecord } from "@roo-code/types"
|
||||
|
||||
import type { ModelRecord } from "../../../shared/api"
|
||||
import { parseApiPrice } from "../../../shared/cost"
|
||||
|
||||
import { DEFAULT_HEADERS } from "../constants"
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
import OpenAI from "openai"
|
||||
import { Anthropic } from "@anthropic-ai/sdk"
|
||||
|
||||
import type { ApiHandlerOptions, ModelRecord } from "../../shared/api"
|
||||
import type { ModelRecord } from "@roo-code/types"
|
||||
|
||||
import type { ApiHandlerOptions } from "../../shared/api"
|
||||
import { ApiStream } from "../transform/stream"
|
||||
import { convertToOpenAiMessages } from "../transform/openai-format"
|
||||
import type { SingleCompletionHandler, ApiHandlerCreateMessageMetadata } from "../index"
|
||||
|
|
|
|||
|
|
@ -3,18 +3,19 @@ import OpenAI from "openai"
|
|||
import { z } from "zod"
|
||||
|
||||
import {
|
||||
type ModelRecord,
|
||||
ApiProviderError,
|
||||
openRouterDefaultModelId,
|
||||
openRouterDefaultModelInfo,
|
||||
OPENROUTER_DEFAULT_PROVIDER_NAME,
|
||||
OPEN_ROUTER_PROMPT_CACHING_MODELS,
|
||||
DEEP_SEEK_DEFAULT_TEMPERATURE,
|
||||
ApiProviderError,
|
||||
} from "@roo-code/types"
|
||||
import { TelemetryService } from "@roo-code/telemetry"
|
||||
|
||||
import { NativeToolCallParser } from "../../core/assistant-message/NativeToolCallParser"
|
||||
|
||||
import type { ApiHandlerOptions, ModelRecord } from "../../shared/api"
|
||||
import type { ApiHandlerOptions } from "../../shared/api"
|
||||
|
||||
import { convertToOpenAiMessages } from "../transform/openai-format"
|
||||
import { normalizeMistralToolCallId } from "../transform/mistral-format"
|
||||
|
|
|
|||
|
|
@ -3,13 +3,14 @@ import OpenAI from "openai"
|
|||
|
||||
import {
|
||||
type ModelInfo,
|
||||
type ModelRecord,
|
||||
requestyDefaultModelId,
|
||||
requestyDefaultModelInfo,
|
||||
TOOL_PROTOCOL,
|
||||
NATIVE_TOOL_DEFAULTS,
|
||||
} from "@roo-code/types"
|
||||
|
||||
import type { ApiHandlerOptions, ModelRecord } from "../../shared/api"
|
||||
import type { ApiHandlerOptions } from "../../shared/api"
|
||||
import { resolveToolProtocol } from "../../utils/resolveToolProtocol"
|
||||
import { calculateApiCostOpenAI } from "../../shared/cost"
|
||||
|
||||
|
|
|
|||
|
|
@ -2,11 +2,12 @@ import { Anthropic } from "@anthropic-ai/sdk"
|
|||
import OpenAI from "openai"
|
||||
|
||||
import { rooDefaultModelId, getApiProtocol, type ImageGenerationApiMethod } from "@roo-code/types"
|
||||
import { NativeToolCallParser } from "../../core/assistant-message/NativeToolCallParser"
|
||||
import { CloudService } from "@roo-code/cloud"
|
||||
|
||||
import { NativeToolCallParser } from "../../core/assistant-message/NativeToolCallParser"
|
||||
|
||||
import { Package } from "../../shared/package"
|
||||
import type { ApiHandlerOptions, ModelRecord } from "../../shared/api"
|
||||
import type { ApiHandlerOptions } from "../../shared/api"
|
||||
import { ApiStream } from "../transform/stream"
|
||||
import { getModelParams } from "../transform/model-params"
|
||||
import { convertToOpenAiMessages } from "../transform/openai-format"
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import OpenAI from "openai"
|
||||
|
||||
import { type ModelInfo, NATIVE_TOOL_DEFAULTS } from "@roo-code/types"
|
||||
import { type ModelInfo, type ModelRecord, NATIVE_TOOL_DEFAULTS } from "@roo-code/types"
|
||||
|
||||
import { ApiHandlerOptions, RouterName, ModelRecord } from "../../shared/api"
|
||||
import { ApiHandlerOptions, RouterName } from "../../shared/api"
|
||||
|
||||
import { BaseProvider } from "./base-provider"
|
||||
import { getModels, getModelsFromCache } from "./fetchers/modelCache"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,12 @@
|
|||
import { type ClineAsk, type McpServerUse, type FollowUpData, isNonBlockingAsk } from "@roo-code/types"
|
||||
import {
|
||||
type ClineAsk,
|
||||
type McpServerUse,
|
||||
type FollowUpData,
|
||||
type ExtensionState,
|
||||
isNonBlockingAsk,
|
||||
} from "@roo-code/types"
|
||||
|
||||
import type { ClineSayTool, ExtensionState } from "../../shared/ExtensionMessage"
|
||||
import type { ClineSayTool } from "../../shared/ExtensionMessage"
|
||||
import { ClineAskResponse } from "../../shared/WebviewMessage"
|
||||
|
||||
import { isWriteToolAction, isReadOnlyToolAction } from "./tools"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,4 @@
|
|||
import type { McpServerUse } from "@roo-code/types"
|
||||
|
||||
import type { McpServer, McpTool } from "../../shared/mcp"
|
||||
import type { McpServerUse, McpServer, McpTool } from "@roo-code/types"
|
||||
|
||||
export function isMcpToolAlwaysAllowed(mcpServerUse: McpServerUse, mcpServers: McpServer[] | undefined): boolean {
|
||||
if (mcpServerUse.type === "use_mcp_tool" && mcpServerUse.toolName) {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,10 @@
|
|||
import type OpenAI from "openai"
|
||||
import { getMcpServerTools } from "../mcp_server"
|
||||
|
||||
import type { McpServer, McpTool } from "@roo-code/types"
|
||||
|
||||
import type { McpHub } from "../../../../../services/mcp/McpHub"
|
||||
import type { McpServer, McpTool } from "../../../../../shared/mcp"
|
||||
|
||||
import { getMcpServerTools } from "../mcp_server"
|
||||
|
||||
// Helper type to access function tools
|
||||
type FunctionTool = OpenAI.Chat.ChatCompletionTool & { type: "function" }
|
||||
|
|
|
|||
|
|
@ -1688,6 +1688,16 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
|
|||
}
|
||||
|
||||
private async resumeTaskFromHistory() {
|
||||
// Reset abort and streaming state to ensure clean continuation.
|
||||
// This matches the behavior in resumeAfterDelegation() and prevents
|
||||
// corrupted state from a previous cancellation.
|
||||
this.abort = false
|
||||
this.abandoned = false
|
||||
this.abortReason = undefined
|
||||
this.didFinishAbortingStream = false
|
||||
this.isStreaming = false
|
||||
this.isWaitingForFirstChunk = false
|
||||
|
||||
if (this.enableBridge) {
|
||||
try {
|
||||
await BridgeOrchestrator.subscribeToTask(this)
|
||||
|
|
|
|||
|
|
@ -34,6 +34,9 @@ import {
|
|||
type CreateTaskOptions,
|
||||
type TokenUsage,
|
||||
type ToolUsage,
|
||||
type ExtensionMessage,
|
||||
type ExtensionState,
|
||||
type MarketplaceInstalledMetadata,
|
||||
RooCodeEventName,
|
||||
requestyDefaultModelId,
|
||||
openRouterDefaultModelId,
|
||||
|
|
@ -51,7 +54,6 @@ import { Package } from "../../shared/package"
|
|||
import { findLast } from "../../shared/array"
|
||||
import { supportPrompt } from "../../shared/support-prompt"
|
||||
import { GlobalFileNames } from "../../shared/globalFileNames"
|
||||
import type { ExtensionMessage, ExtensionState, MarketplaceInstalledMetadata } from "../../shared/ExtensionMessage"
|
||||
import { Mode, defaultModeSlug, getModeBySlug } from "../../shared/modes"
|
||||
import { experimentDefault } from "../../shared/experiments"
|
||||
import { formatLanguage } from "../../shared/language"
|
||||
|
|
|
|||
|
|
@ -7,12 +7,13 @@ import axios from "axios"
|
|||
import {
|
||||
type ProviderSettingsEntry,
|
||||
type ClineMessage,
|
||||
type ExtensionMessage,
|
||||
type ExtensionState,
|
||||
ORGANIZATION_ALLOW_ALL,
|
||||
DEFAULT_CHECKPOINT_TIMEOUT_SECONDS,
|
||||
} from "@roo-code/types"
|
||||
import { TelemetryService } from "@roo-code/telemetry"
|
||||
|
||||
import { ExtensionMessage, ExtensionState } from "../../../shared/ExtensionMessage"
|
||||
import { defaultModeSlug } from "../../../shared/modes"
|
||||
import { experimentDefault } from "../../../shared/experiments"
|
||||
import { setTtsEnabled } from "../../../utils/tts"
|
||||
|
|
|
|||
|
|
@ -10,10 +10,11 @@ vi.mock("../diagnosticsHandler", () => ({
|
|||
generateErrorDiagnostics: vi.fn().mockResolvedValue({ success: true, filePath: "/tmp/diagnostics.json" }),
|
||||
}))
|
||||
|
||||
import type { ModelRecord } from "@roo-code/types"
|
||||
|
||||
import { webviewMessageHandler } from "../webviewMessageHandler"
|
||||
import type { ClineProvider } from "../ClineProvider"
|
||||
import { getModels } from "../../../api/providers/fetchers/modelCache"
|
||||
import type { ModelRecord } from "../../../shared/api"
|
||||
|
||||
const mockGetModels = getModels as Mock<typeof getModels>
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import {
|
|||
type ClineMessage,
|
||||
type TelemetrySetting,
|
||||
type UserSettingsConfig,
|
||||
type ModelRecord,
|
||||
TelemetryEventName,
|
||||
RooCodeSettings,
|
||||
ExperimentId,
|
||||
|
|
@ -29,7 +30,7 @@ import { handleCheckpointRestoreOperation } from "./checkpointRestoreHandler"
|
|||
import { generateErrorDiagnostics } from "./diagnosticsHandler"
|
||||
import { changeLanguage, t } from "../../i18n"
|
||||
import { Package } from "../../shared/package"
|
||||
import { type RouterName, type ModelRecord, toRouterName } from "../../shared/api"
|
||||
import { type RouterName, toRouterName } from "../../shared/api"
|
||||
import { MessageEnhancer } from "./messageEnhancer"
|
||||
|
||||
import {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
import * as fs from "fs/promises"
|
||||
import * as path from "path"
|
||||
|
||||
import * as vscode from "vscode"
|
||||
import { Client } from "@modelcontextprotocol/sdk/client/index.js"
|
||||
import { StdioClientTransport, getDefaultEnvironment } from "@modelcontextprotocol/sdk/client/stdio.js"
|
||||
import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js"
|
||||
|
|
@ -13,22 +17,23 @@ import {
|
|||
import chokidar, { FSWatcher } from "chokidar"
|
||||
import delay from "delay"
|
||||
import deepEqual from "fast-deep-equal"
|
||||
import * as fs from "fs/promises"
|
||||
import * as path from "path"
|
||||
import * as vscode from "vscode"
|
||||
import { z } from "zod"
|
||||
import { t } from "../../i18n"
|
||||
|
||||
import { ClineProvider } from "../../core/webview/ClineProvider"
|
||||
import { GlobalFileNames } from "../../shared/globalFileNames"
|
||||
import {
|
||||
import type {
|
||||
McpResource,
|
||||
McpResourceResponse,
|
||||
McpResourceTemplate,
|
||||
McpServer,
|
||||
McpTool,
|
||||
McpToolCallResponse,
|
||||
} from "../../shared/mcp"
|
||||
} from "@roo-code/types"
|
||||
|
||||
import { t } from "../../i18n"
|
||||
|
||||
import { ClineProvider } from "../../core/webview/ClineProvider"
|
||||
|
||||
import { GlobalFileNames } from "../../shared/globalFileNames"
|
||||
|
||||
import { fileExistsAtPath } from "../../utils/fs"
|
||||
import { arePathsEqual, getWorkspacePath } from "../../utils/path"
|
||||
import { injectVariables } from "../../utils/config"
|
||||
|
|
|
|||
|
|
@ -1,44 +1,3 @@
|
|||
import type {
|
||||
GlobalSettings,
|
||||
ProviderSettingsEntry,
|
||||
ProviderSettings,
|
||||
HistoryItem,
|
||||
ModeConfig,
|
||||
TelemetrySetting,
|
||||
Experiments,
|
||||
ClineMessage,
|
||||
MarketplaceItem,
|
||||
TodoItem,
|
||||
CloudUserInfo,
|
||||
CloudOrganizationMembership,
|
||||
OrganizationAllowList,
|
||||
ShareVisibility,
|
||||
QueuedMessage,
|
||||
SerializedCustomToolDefinition,
|
||||
} from "@roo-code/types"
|
||||
|
||||
import { GitCommit } from "../utils/git"
|
||||
|
||||
import { McpServer } from "./mcp"
|
||||
import { Mode } from "./modes"
|
||||
import { ModelRecord, RouterModels } from "./api"
|
||||
|
||||
// Command interface for frontend/backend communication
|
||||
export interface Command {
|
||||
name: string
|
||||
source: "global" | "project" | "built-in"
|
||||
filePath?: string
|
||||
description?: string
|
||||
argumentHint?: string
|
||||
}
|
||||
|
||||
// Type for marketplace installed metadata
|
||||
export interface MarketplaceInstalledMetadata {
|
||||
project: Record<string, { type: string }>
|
||||
global: Record<string, { type: string }>
|
||||
}
|
||||
|
||||
// Indexing status types
|
||||
export interface IndexingStatus {
|
||||
systemStatus: string
|
||||
message?: string
|
||||
|
|
@ -60,313 +19,6 @@ export interface LanguageModelChatSelector {
|
|||
id?: string
|
||||
}
|
||||
|
||||
// Represents JSON data that is sent from extension to webview, called
|
||||
// ExtensionMessage and has 'type' enum which can be 'plusButtonClicked' or
|
||||
// 'settingsButtonClicked' or 'hello'. Webview will hold state.
|
||||
export interface ExtensionMessage {
|
||||
type:
|
||||
| "action"
|
||||
| "state"
|
||||
| "selectedImages"
|
||||
| "theme"
|
||||
| "workspaceUpdated"
|
||||
| "invoke"
|
||||
| "messageUpdated"
|
||||
| "mcpServers"
|
||||
| "enhancedPrompt"
|
||||
| "commitSearchResults"
|
||||
| "listApiConfig"
|
||||
| "routerModels"
|
||||
| "openAiModels"
|
||||
| "ollamaModels"
|
||||
| "lmStudioModels"
|
||||
| "vsCodeLmModels"
|
||||
| "huggingFaceModels"
|
||||
| "vsCodeLmApiAvailable"
|
||||
| "updatePrompt"
|
||||
| "systemPrompt"
|
||||
| "autoApprovalEnabled"
|
||||
| "updateCustomMode"
|
||||
| "deleteCustomMode"
|
||||
| "exportModeResult"
|
||||
| "importModeResult"
|
||||
| "checkRulesDirectoryResult"
|
||||
| "deleteCustomModeCheck"
|
||||
| "currentCheckpointUpdated"
|
||||
| "checkpointInitWarning"
|
||||
| "browserToolEnabled"
|
||||
| "browserConnectionResult"
|
||||
| "remoteBrowserEnabled"
|
||||
| "ttsStart"
|
||||
| "ttsStop"
|
||||
| "maxReadFileLine"
|
||||
| "fileSearchResults"
|
||||
| "toggleApiConfigPin"
|
||||
| "acceptInput"
|
||||
| "setHistoryPreviewCollapsed"
|
||||
| "commandExecutionStatus"
|
||||
| "mcpExecutionStatus"
|
||||
| "vsCodeSetting"
|
||||
| "authenticatedUser"
|
||||
| "condenseTaskContextStarted"
|
||||
| "condenseTaskContextResponse"
|
||||
| "singleRouterModelFetchResponse"
|
||||
| "rooCreditBalance"
|
||||
| "indexingStatusUpdate"
|
||||
| "indexCleared"
|
||||
| "codebaseIndexConfig"
|
||||
| "marketplaceInstallResult"
|
||||
| "marketplaceRemoveResult"
|
||||
| "marketplaceData"
|
||||
| "shareTaskSuccess"
|
||||
| "codeIndexSettingsSaved"
|
||||
| "codeIndexSecretStatus"
|
||||
| "showDeleteMessageDialog"
|
||||
| "showEditMessageDialog"
|
||||
| "commands"
|
||||
| "insertTextIntoTextarea"
|
||||
| "dismissedUpsells"
|
||||
| "organizationSwitchResult"
|
||||
| "interactionRequired"
|
||||
| "browserSessionUpdate"
|
||||
| "browserSessionNavigate"
|
||||
| "claudeCodeRateLimits"
|
||||
| "customToolsResult"
|
||||
| "modes"
|
||||
text?: string
|
||||
payload?: any // Add a generic payload for now, can refine later
|
||||
// Checkpoint warning message
|
||||
checkpointWarning?: {
|
||||
type: "WAIT_TIMEOUT" | "INIT_TIMEOUT"
|
||||
timeout: number
|
||||
}
|
||||
action?:
|
||||
| "chatButtonClicked"
|
||||
| "settingsButtonClicked"
|
||||
| "historyButtonClicked"
|
||||
| "marketplaceButtonClicked"
|
||||
| "cloudButtonClicked"
|
||||
| "didBecomeVisible"
|
||||
| "focusInput"
|
||||
| "switchTab"
|
||||
| "toggleAutoApprove"
|
||||
invoke?: "newChat" | "sendMessage" | "primaryButtonClick" | "secondaryButtonClick" | "setChatBoxMessage"
|
||||
state?: ExtensionState
|
||||
images?: string[]
|
||||
filePaths?: string[]
|
||||
openedTabs?: Array<{
|
||||
label: string
|
||||
isActive: boolean
|
||||
path?: string
|
||||
}>
|
||||
clineMessage?: ClineMessage
|
||||
routerModels?: RouterModels
|
||||
openAiModels?: string[]
|
||||
ollamaModels?: ModelRecord
|
||||
lmStudioModels?: ModelRecord
|
||||
vsCodeLmModels?: { vendor?: string; family?: string; version?: string; id?: string }[]
|
||||
huggingFaceModels?: Array<{
|
||||
id: string
|
||||
object: string
|
||||
created: number
|
||||
owned_by: string
|
||||
providers: Array<{
|
||||
provider: string
|
||||
status: "live" | "staging" | "error"
|
||||
supports_tools?: boolean
|
||||
supports_structured_output?: boolean
|
||||
context_length?: number
|
||||
pricing?: {
|
||||
input: number
|
||||
output: number
|
||||
}
|
||||
}>
|
||||
}>
|
||||
mcpServers?: McpServer[]
|
||||
commits?: GitCommit[]
|
||||
listApiConfig?: ProviderSettingsEntry[]
|
||||
mode?: Mode
|
||||
customMode?: ModeConfig
|
||||
slug?: string
|
||||
success?: boolean
|
||||
values?: Record<string, any>
|
||||
requestId?: string
|
||||
promptText?: string
|
||||
results?:
|
||||
| { path: string; type: "file" | "folder"; label?: string }[]
|
||||
| { name: string; description?: string; argumentHint?: string; source: "global" | "project" | "built-in" }[]
|
||||
error?: string
|
||||
setting?: string
|
||||
value?: any
|
||||
hasContent?: boolean // For checkRulesDirectoryResult
|
||||
items?: MarketplaceItem[]
|
||||
userInfo?: CloudUserInfo
|
||||
organizationAllowList?: OrganizationAllowList
|
||||
tab?: string
|
||||
marketplaceItems?: MarketplaceItem[]
|
||||
organizationMcps?: MarketplaceItem[]
|
||||
marketplaceInstalledMetadata?: MarketplaceInstalledMetadata
|
||||
errors?: string[]
|
||||
visibility?: ShareVisibility
|
||||
rulesFolderPath?: string
|
||||
settings?: any
|
||||
messageTs?: number
|
||||
hasCheckpoint?: boolean
|
||||
context?: string
|
||||
commands?: Command[]
|
||||
queuedMessages?: QueuedMessage[]
|
||||
list?: string[] // For dismissedUpsells
|
||||
organizationId?: string | null // For organizationSwitchResult
|
||||
browserSessionMessages?: ClineMessage[] // For browser session panel updates
|
||||
isBrowserSessionActive?: boolean // For browser session panel updates
|
||||
stepIndex?: number // For browserSessionNavigate: the target step index to display
|
||||
tools?: SerializedCustomToolDefinition[] // For customToolsResult
|
||||
modes?: { slug: string; name: string }[] // For modes response
|
||||
}
|
||||
|
||||
export type ExtensionState = Pick<
|
||||
GlobalSettings,
|
||||
| "currentApiConfigName"
|
||||
| "listApiConfigMeta"
|
||||
| "pinnedApiConfigs"
|
||||
| "customInstructions"
|
||||
| "dismissedUpsells"
|
||||
| "autoApprovalEnabled"
|
||||
| "alwaysAllowReadOnly"
|
||||
| "alwaysAllowReadOnlyOutsideWorkspace"
|
||||
| "alwaysAllowWrite"
|
||||
| "alwaysAllowWriteOutsideWorkspace"
|
||||
| "alwaysAllowWriteProtected"
|
||||
| "alwaysAllowBrowser"
|
||||
| "alwaysAllowMcp"
|
||||
| "alwaysAllowModeSwitch"
|
||||
| "alwaysAllowSubtasks"
|
||||
| "alwaysAllowFollowupQuestions"
|
||||
| "alwaysAllowExecute"
|
||||
| "followupAutoApproveTimeoutMs"
|
||||
| "allowedCommands"
|
||||
| "deniedCommands"
|
||||
| "allowedMaxRequests"
|
||||
| "allowedMaxCost"
|
||||
| "browserToolEnabled"
|
||||
| "browserViewportSize"
|
||||
| "screenshotQuality"
|
||||
| "remoteBrowserEnabled"
|
||||
| "cachedChromeHostUrl"
|
||||
| "remoteBrowserHost"
|
||||
| "ttsEnabled"
|
||||
| "ttsSpeed"
|
||||
| "soundEnabled"
|
||||
| "soundVolume"
|
||||
| "maxConcurrentFileReads"
|
||||
| "terminalOutputLineLimit"
|
||||
| "terminalOutputCharacterLimit"
|
||||
| "terminalShellIntegrationTimeout"
|
||||
| "terminalShellIntegrationDisabled"
|
||||
| "terminalCommandDelay"
|
||||
| "terminalPowershellCounter"
|
||||
| "terminalZshClearEolMark"
|
||||
| "terminalZshOhMy"
|
||||
| "terminalZshP10k"
|
||||
| "terminalZdotdir"
|
||||
| "terminalCompressProgressBar"
|
||||
| "diagnosticsEnabled"
|
||||
| "diffEnabled"
|
||||
| "fuzzyMatchThreshold"
|
||||
| "language"
|
||||
| "modeApiConfigs"
|
||||
| "customModePrompts"
|
||||
| "customSupportPrompts"
|
||||
| "enhancementApiConfigId"
|
||||
| "condensingApiConfigId"
|
||||
| "customCondensingPrompt"
|
||||
| "codebaseIndexConfig"
|
||||
| "codebaseIndexModels"
|
||||
| "profileThresholds"
|
||||
| "includeDiagnosticMessages"
|
||||
| "maxDiagnosticMessages"
|
||||
| "imageGenerationProvider"
|
||||
| "openRouterImageGenerationSelectedModel"
|
||||
| "includeTaskHistoryInEnhance"
|
||||
| "reasoningBlockCollapsed"
|
||||
| "enterBehavior"
|
||||
| "includeCurrentTime"
|
||||
| "includeCurrentCost"
|
||||
| "maxGitStatusFiles"
|
||||
| "requestDelaySeconds"
|
||||
> & {
|
||||
version: string
|
||||
clineMessages: ClineMessage[]
|
||||
currentTaskItem?: HistoryItem
|
||||
currentTaskTodos?: TodoItem[] // Initial todos for the current task
|
||||
apiConfiguration: ProviderSettings
|
||||
uriScheme?: string
|
||||
shouldShowAnnouncement: boolean
|
||||
|
||||
taskHistory: HistoryItem[]
|
||||
|
||||
writeDelayMs: number
|
||||
|
||||
enableCheckpoints: boolean
|
||||
checkpointTimeout: number // Timeout for checkpoint initialization in seconds (default: 15)
|
||||
maxOpenTabsContext: number // Maximum number of VSCode open tabs to include in context (0-500)
|
||||
maxWorkspaceFiles: number // Maximum number of files to include in current working directory details (0-500)
|
||||
showRooIgnoredFiles: boolean // Whether to show .rooignore'd files in listings
|
||||
enableSubfolderRules: boolean // Whether to load rules from subdirectories
|
||||
maxReadFileLine: number // Maximum number of lines to read from a file before truncating
|
||||
maxImageFileSize: number // Maximum size of image files to process in MB
|
||||
maxTotalImageSize: number // Maximum total size for all images in a single read operation in MB
|
||||
|
||||
experiments: Experiments // Map of experiment IDs to their enabled state
|
||||
|
||||
mcpEnabled: boolean
|
||||
enableMcpServerCreation: boolean
|
||||
|
||||
mode: Mode
|
||||
customModes: ModeConfig[]
|
||||
toolRequirements?: Record<string, boolean> // Map of tool names to their requirements (e.g. {"apply_diff": true} if diffEnabled)
|
||||
|
||||
cwd?: string // Current working directory
|
||||
telemetrySetting: TelemetrySetting
|
||||
telemetryKey?: string
|
||||
machineId?: string
|
||||
|
||||
renderContext: "sidebar" | "editor"
|
||||
settingsImportedAt?: number
|
||||
historyPreviewCollapsed?: boolean
|
||||
|
||||
cloudUserInfo: CloudUserInfo | null
|
||||
cloudIsAuthenticated: boolean
|
||||
cloudAuthSkipModel?: boolean // Flag indicating auth completed without model selection (user should pick 3rd-party provider)
|
||||
cloudApiUrl?: string
|
||||
cloudOrganizations?: CloudOrganizationMembership[]
|
||||
sharingEnabled: boolean
|
||||
publicSharingEnabled: boolean
|
||||
organizationAllowList: OrganizationAllowList
|
||||
organizationSettingsVersion?: number
|
||||
|
||||
isBrowserSessionActive: boolean // Actual browser session state
|
||||
|
||||
autoCondenseContext: boolean
|
||||
autoCondenseContextPercent: number
|
||||
marketplaceItems?: MarketplaceItem[]
|
||||
marketplaceInstalledMetadata?: { project: Record<string, any>; global: Record<string, any> }
|
||||
profileThresholds: Record<string, number>
|
||||
hasOpenedModeSelector: boolean
|
||||
openRouterImageApiKey?: string
|
||||
messageQueue?: QueuedMessage[]
|
||||
lastShownAnnouncementId?: string
|
||||
apiModelId?: string
|
||||
mcpServers?: McpServer[]
|
||||
hasSystemPromptOverride?: boolean
|
||||
mdmCompliant?: boolean
|
||||
remoteControlEnabled: boolean
|
||||
taskSyncEnabled: boolean
|
||||
featureRoomoteControlEnabled: boolean
|
||||
claudeCodeIsAuthenticated?: boolean
|
||||
debug?: boolean
|
||||
}
|
||||
|
||||
export interface ClineSayTool {
|
||||
tool:
|
||||
| "editedExistingFile"
|
||||
|
|
|
|||
|
|
@ -39,12 +39,6 @@ export function toRouterName(value?: string): RouterName {
|
|||
throw new Error(`Invalid router name: ${value}`)
|
||||
}
|
||||
|
||||
// RouterModels
|
||||
|
||||
export type ModelRecord = Record<string, ModelInfo>
|
||||
|
||||
export type RouterModels = Record<RouterName, ModelRecord>
|
||||
|
||||
// Reasoning
|
||||
|
||||
export const shouldUseReasoningBudget = ({
|
||||
|
|
|
|||
|
|
@ -1,83 +0,0 @@
|
|||
export type McpErrorEntry = {
|
||||
message: string
|
||||
timestamp: number
|
||||
level: "error" | "warn" | "info"
|
||||
}
|
||||
|
||||
export type McpServer = {
|
||||
name: string
|
||||
config: string
|
||||
status: "connected" | "connecting" | "disconnected"
|
||||
error?: string
|
||||
errorHistory?: McpErrorEntry[]
|
||||
tools?: McpTool[]
|
||||
resources?: McpResource[]
|
||||
resourceTemplates?: McpResourceTemplate[]
|
||||
disabled?: boolean
|
||||
timeout?: number
|
||||
source?: "global" | "project"
|
||||
projectPath?: string
|
||||
instructions?: string
|
||||
}
|
||||
|
||||
export type McpTool = {
|
||||
name: string
|
||||
description?: string
|
||||
inputSchema?: object
|
||||
alwaysAllow?: boolean
|
||||
enabledForPrompt?: boolean
|
||||
}
|
||||
|
||||
export type McpResource = {
|
||||
uri: string
|
||||
name: string
|
||||
mimeType?: string
|
||||
description?: string
|
||||
}
|
||||
|
||||
export type McpResourceTemplate = {
|
||||
uriTemplate: string
|
||||
name: string
|
||||
description?: string
|
||||
mimeType?: string
|
||||
}
|
||||
|
||||
export type McpResourceResponse = {
|
||||
_meta?: Record<string, any>
|
||||
contents: Array<{
|
||||
uri: string
|
||||
mimeType?: string
|
||||
text?: string
|
||||
blob?: string
|
||||
}>
|
||||
}
|
||||
|
||||
export type McpToolCallResponse = {
|
||||
_meta?: Record<string, any>
|
||||
content: Array<
|
||||
| {
|
||||
type: "text"
|
||||
text: string
|
||||
}
|
||||
| {
|
||||
type: "image"
|
||||
data: string
|
||||
mimeType: string
|
||||
}
|
||||
| {
|
||||
type: "audio"
|
||||
data: string
|
||||
mimeType: string
|
||||
}
|
||||
| {
|
||||
type: "resource"
|
||||
resource: {
|
||||
uri: string
|
||||
mimeType?: string
|
||||
text?: string
|
||||
blob?: string
|
||||
}
|
||||
}
|
||||
>
|
||||
isError?: boolean
|
||||
}
|
||||
|
|
@ -3,25 +3,15 @@ import * as path from "path"
|
|||
import { promises as fs } from "fs"
|
||||
import { exec } from "child_process"
|
||||
import { promisify } from "util"
|
||||
|
||||
import type { GitRepositoryInfo, GitCommit } from "@roo-code/types"
|
||||
|
||||
import { truncateOutput } from "../integrations/misc/extract-text"
|
||||
|
||||
const execAsync = promisify(exec)
|
||||
|
||||
const GIT_OUTPUT_LINE_LIMIT = 500
|
||||
|
||||
export interface GitRepositoryInfo {
|
||||
repositoryUrl?: string
|
||||
repositoryName?: string
|
||||
defaultBranch?: string
|
||||
}
|
||||
|
||||
export interface GitCommit {
|
||||
hash: string
|
||||
shortHash: string
|
||||
subject: string
|
||||
author: string
|
||||
date: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts git repository information from the workspace's .git directory
|
||||
* @param workspaceRoot The root path of the workspace
|
||||
|
|
|
|||
|
|
@ -2,13 +2,13 @@ import React, { useCallback, useEffect, useRef, useState, useMemo } from "react"
|
|||
import { useEvent } from "react-use"
|
||||
import { QueryClient, QueryClientProvider } from "@tanstack/react-query"
|
||||
|
||||
import { ExtensionMessage } from "@roo/ExtensionMessage"
|
||||
import { type ExtensionMessage, TelemetryEventName } from "@roo-code/types"
|
||||
|
||||
import TranslationProvider from "./i18n/TranslationContext"
|
||||
import { MarketplaceViewStateManager } from "./components/marketplace/MarketplaceViewStateManager"
|
||||
|
||||
import { vscode } from "./utils/vscode"
|
||||
import { telemetryClient } from "./utils/TelemetryClient"
|
||||
import { TelemetryEventName } from "@roo-code/types"
|
||||
import { initializeSourceMaps, exposeSourceMapsForDebugging } from "./utils/sourceMapInitializer"
|
||||
import { ExtensionStateContextProvider, useExtensionState } from "./context/ExtensionStateContext"
|
||||
import ChatView, { ChatViewRef } from "./components/chat/ChatView"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import type { Command } from "@roo/ExtensionMessage"
|
||||
import type { Command } from "@roo-code/types"
|
||||
|
||||
import { getContextMenuOptions, ContextMenuOptionType } from "../utils/context-mentions"
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import React, { createContext, useContext, useState, useEffect, useCallback } from "react"
|
||||
import { ExtensionMessage } from "@roo/ExtensionMessage"
|
||||
|
||||
import { type ExtensionMessage } from "@roo-code/types"
|
||||
|
||||
interface BrowserPanelState {
|
||||
browserViewportSize: string
|
||||
|
|
|
|||
|
|
@ -1,14 +1,18 @@
|
|||
import React, { useEffect, useState } from "react"
|
||||
import { type ClineMessage } from "@roo-code/types"
|
||||
import BrowserSessionRow from "../chat/BrowserSessionRow"
|
||||
|
||||
import { type ClineMessage, type ExtensionMessage } from "@roo-code/types"
|
||||
|
||||
import { TooltipProvider } from "@src/components/ui/tooltip"
|
||||
import ErrorBoundary from "../ErrorBoundary"
|
||||
import TranslationProvider from "@src/i18n/TranslationContext"
|
||||
import { ExtensionMessage } from "@roo/ExtensionMessage"
|
||||
import { BrowserPanelStateProvider, useBrowserPanelState } from "./BrowserPanelStateProvider"
|
||||
import { vscode } from "@src/utils/vscode"
|
||||
|
||||
import { ExtensionStateContextProvider } from "@/context/ExtensionStateContext"
|
||||
|
||||
import BrowserSessionRow from "../chat/BrowserSessionRow"
|
||||
import ErrorBoundary from "../ErrorBoundary"
|
||||
|
||||
import { BrowserPanelStateProvider, useBrowserPanelState } from "./BrowserPanelStateProvider"
|
||||
|
||||
interface BrowserSessionPanelState {
|
||||
messages: ClineMessage[]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,10 +3,11 @@ import { useEvent } from "react-use"
|
|||
import DynamicTextArea from "react-textarea-autosize"
|
||||
import { VolumeX, Image, WandSparkles, SendHorizontal, MessageSquareX } from "lucide-react"
|
||||
|
||||
import type { ExtensionMessage } from "@roo-code/types"
|
||||
|
||||
import { mentionRegex, mentionRegexGlobal, commandRegexGlobal, unescapeSpaces } from "@roo/context-mentions"
|
||||
import { WebviewMessage } from "@roo/WebviewMessage"
|
||||
import { Mode, getAllModes } from "@roo/modes"
|
||||
import { ExtensionMessage } from "@roo/ExtensionMessage"
|
||||
|
||||
import { vscode } from "@src/utils/vscode"
|
||||
import { useExtensionState } from "@src/context/ExtensionStateContext"
|
||||
|
|
|
|||
|
|
@ -11,9 +11,9 @@ import { Trans } from "react-i18next"
|
|||
import { useDebounceEffect } from "@src/utils/useDebounceEffect"
|
||||
import { appendImages } from "@src/utils/imageUtils"
|
||||
|
||||
import type { ClineAsk, ClineMessage } from "@roo-code/types"
|
||||
import type { ClineAsk, ClineMessage, ExtensionMessage } from "@roo-code/types"
|
||||
|
||||
import { ClineSayTool, ExtensionMessage } from "@roo/ExtensionMessage"
|
||||
import { ClineSayTool } from "@roo/ExtensionMessage"
|
||||
import { findLast } from "@roo/array"
|
||||
import { SuggestionItem } from "@roo-code/types"
|
||||
import { combineApiRequests } from "@roo/combineApiRequests"
|
||||
|
|
|
|||
|
|
@ -3,11 +3,9 @@ import { useEvent } from "react-use"
|
|||
import { t } from "i18next"
|
||||
import { ChevronDown, OctagonX } from "lucide-react"
|
||||
|
||||
import { CommandExecutionStatus, commandExecutionStatusSchema } from "@roo-code/types"
|
||||
import { type ExtensionMessage, type CommandExecutionStatus, commandExecutionStatusSchema } from "@roo-code/types"
|
||||
|
||||
import { ExtensionMessage } from "@roo/ExtensionMessage"
|
||||
import { safeJsonParse } from "@roo/safeJsonParse"
|
||||
|
||||
import { COMMAND_OUTPUT_STRING } from "@roo/combineCommandSequences"
|
||||
import { parseCommand } from "@roo/parse-command"
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
import React, { useEffect, useMemo, useRef, useState } from "react"
|
||||
import { getIconForFilePath, getIconUrlByName, getIconForDirectoryPath } from "vscode-material-icons"
|
||||
import { Trans } from "react-i18next"
|
||||
import { t } from "i18next"
|
||||
import { Settings } from "lucide-react"
|
||||
|
||||
import type { ModeConfig } from "@roo-code/types"
|
||||
import type { Command } from "@roo/ExtensionMessage"
|
||||
import type { ModeConfig, Command } from "@roo-code/types"
|
||||
|
||||
import {
|
||||
ContextMenuOptionType,
|
||||
|
|
@ -13,9 +14,8 @@ import {
|
|||
} from "@src/utils/context-mentions"
|
||||
import { removeLeadingNonAlphanumeric } from "@src/utils/removeLeadingNonAlphanumeric"
|
||||
import { vscode } from "@src/utils/vscode"
|
||||
|
||||
import { buildDocLink } from "@/utils/docLinks"
|
||||
import { Trans } from "react-i18next"
|
||||
import { t } from "i18next"
|
||||
|
||||
interface ContextMenuProps {
|
||||
onSelect: (type: ContextMenuOptionType, value?: string) => void
|
||||
|
|
|
|||
|
|
@ -3,13 +3,16 @@ import { Server, ChevronDown } from "lucide-react"
|
|||
import { useEvent } from "react-use"
|
||||
import { useTranslation } from "react-i18next"
|
||||
|
||||
import { McpExecutionStatus, mcpExecutionStatusSchema } from "@roo-code/types"
|
||||
import { ExtensionMessage, ClineAskUseMcpServer } from "../../../../src/shared/ExtensionMessage"
|
||||
import { safeJsonParse } from "../../../../src/shared/safeJsonParse"
|
||||
import { type ExtensionMessage, type McpExecutionStatus, mcpExecutionStatusSchema } from "@roo-code/types"
|
||||
|
||||
import { cn } from "@src/lib/utils"
|
||||
import { Button } from "@src/components/ui"
|
||||
|
||||
import { ClineAskUseMcpServer } from "../../../../src/shared/ExtensionMessage"
|
||||
import { safeJsonParse } from "../../../../src/shared/safeJsonParse"
|
||||
import CodeBlock from "../common/CodeBlock"
|
||||
import McpToolRow from "../mcp/McpToolRow"
|
||||
|
||||
import { Markdown } from "./Markdown"
|
||||
|
||||
interface McpExecutionProps {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import React from "react"
|
||||
import { Edit, Trash2 } from "lucide-react"
|
||||
|
||||
import type { Command } from "@roo/ExtensionMessage"
|
||||
import type { Command } from "@roo-code/types"
|
||||
|
||||
import { useAppTranslation } from "@/i18n/TranslationContext"
|
||||
import { Button, StandardTooltip } from "@/components/ui"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import React from "react"
|
||||
|
||||
import type { Command } from "@roo/ExtensionMessage"
|
||||
import type { Command } from "@roo-code/types"
|
||||
|
||||
interface SlashCommandItemSimpleProps {
|
||||
command: Command
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { render, screen, fireEvent } from "@/utils/test-utils"
|
||||
import type { Command } from "@roo-code/types"
|
||||
|
||||
import type { Command } from "@roo/ExtensionMessage"
|
||||
import { render, screen, fireEvent } from "@/utils/test-utils"
|
||||
|
||||
import { SlashCommandItemSimple } from "../SlashCommandItemSimple"
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
import { useState, useEffect } from "react"
|
||||
import { Building2, User, Plus } from "lucide-react"
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, SelectSeparator } from "@/components/ui/select"
|
||||
import { type CloudUserInfo, type CloudOrganizationMembership } from "@roo-code/types"
|
||||
|
||||
import { type CloudUserInfo, type CloudOrganizationMembership, type ExtensionMessage } from "@roo-code/types"
|
||||
|
||||
import { useAppTranslation } from "@src/i18n/TranslationContext"
|
||||
import { vscode } from "@src/utils/vscode"
|
||||
import { type ExtensionMessage } from "@roo/ExtensionMessage"
|
||||
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, SelectSeparator } from "@/components/ui/select"
|
||||
|
||||
type OrganizationSwitcherProps = {
|
||||
userInfo: CloudUserInfo
|
||||
|
|
|
|||
|
|
@ -11,10 +11,10 @@
|
|||
* 3. Using minimal state updates to avoid resetting scroll position
|
||||
*/
|
||||
|
||||
import { MarketplaceItem } from "@roo-code/types"
|
||||
import { MarketplaceItem, MarketplaceInstalledMetadata } from "@roo-code/types"
|
||||
|
||||
import { vscode } from "../../utils/vscode"
|
||||
import { WebviewMessage } from "../../../../src/shared/WebviewMessage"
|
||||
import type { MarketplaceInstalledMetadata } from "../../../../src/shared/ExtensionMessage"
|
||||
|
||||
export interface ViewState {
|
||||
allItems: MarketplaceItem[]
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { VSCodeCheckbox } from "@vscode/webview-ui-toolkit/react"
|
||||
import { FormEvent } from "react"
|
||||
import { VSCodeCheckbox } from "@vscode/webview-ui-toolkit/react"
|
||||
|
||||
import { useExtensionState } from "@src/context/ExtensionStateContext"
|
||||
import { useAppTranslation } from "@src/i18n/TranslationContext"
|
||||
import { vscode } from "@src/utils/vscode"
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { useMemo } from "react"
|
||||
import { formatRelative } from "date-fns"
|
||||
|
||||
import type { McpErrorEntry } from "@roo/mcp"
|
||||
import type { McpErrorEntry } from "@roo-code/types"
|
||||
|
||||
type McpErrorRowProps = {
|
||||
error: McpErrorEntry
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { McpResource, McpResourceTemplate } from "@roo/mcp"
|
||||
import type { McpResource, McpResourceTemplate } from "@roo-code/types"
|
||||
|
||||
type McpResourceRowProps = {
|
||||
item: McpResource | McpResourceTemplate
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { VSCodeCheckbox } from "@vscode/webview-ui-toolkit/react"
|
||||
|
||||
import { McpTool } from "@roo/mcp"
|
||||
import type { McpTool } from "@roo-code/types"
|
||||
|
||||
import { useAppTranslation } from "@src/i18n/TranslationContext"
|
||||
import { vscode } from "@src/utils/vscode"
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import {
|
|||
} from "@vscode/webview-ui-toolkit/react"
|
||||
import { Webhook } from "lucide-react"
|
||||
|
||||
import { McpServer } from "@roo/mcp"
|
||||
import type { McpServer } from "@roo-code/types"
|
||||
|
||||
import { vscode } from "@src/utils/vscode"
|
||||
import { useExtensionState } from "@src/context/ExtensionStateContext"
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import React, { useState, useEffect } from "react"
|
|||
import { Plus, Globe, Folder, Settings, SquareSlash } from "lucide-react"
|
||||
import { Trans } from "react-i18next"
|
||||
|
||||
import type { Command } from "@roo/ExtensionMessage"
|
||||
import type { Command } from "@roo-code/types"
|
||||
|
||||
import { useAppTranslation } from "@/i18n/TranslationContext"
|
||||
import { useExtensionState } from "@/context/ExtensionStateContext"
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import { Trans } from "react-i18next"
|
|||
import { buildDocLink } from "@src/utils/docLinks"
|
||||
import { useEvent, useMount } from "react-use"
|
||||
|
||||
import { ExtensionMessage } from "@roo/ExtensionMessage"
|
||||
import { type ExtensionMessage } from "@roo-code/types"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
import { Slider } from "@/components/ui"
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { render, screen, fireEvent, waitFor } from "@/utils/test-utils"
|
||||
import { QueryClient, QueryClientProvider } from "@tanstack/react-query"
|
||||
|
||||
import type { Command } from "@roo/ExtensionMessage"
|
||||
import type { Command } from "@roo-code/types"
|
||||
|
||||
import { ExtensionStateContextProvider } from "@/context/ExtensionStateContext"
|
||||
import { vscode } from "@/utils/vscode"
|
||||
|
|
|
|||
|
|
@ -1,14 +1,12 @@
|
|||
import { useCallback } from "react"
|
||||
import { VSCodeTextField } from "@vscode/webview-ui-toolkit/react"
|
||||
|
||||
import type { ProviderSettings, OrganizationAllowList } from "@roo-code/types"
|
||||
import type { ProviderSettings, OrganizationAllowList, RouterModels } from "@roo-code/types"
|
||||
import { chutesDefaultModelId } from "@roo-code/types"
|
||||
|
||||
import { useAppTranslation } from "@src/i18n/TranslationContext"
|
||||
import { VSCodeButtonLink } from "@src/components/common/VSCodeButtonLink"
|
||||
|
||||
import type { RouterModels } from "@roo/api"
|
||||
|
||||
import { ModelPicker } from "../ModelPicker"
|
||||
import { inputEventTransform } from "../transforms"
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,11 @@
|
|||
import React from "react"
|
||||
|
||||
import { type ProviderSettings, claudeCodeDefaultModelId, claudeCodeModels } from "@roo-code/types"
|
||||
|
||||
import { useAppTranslation } from "@src/i18n/TranslationContext"
|
||||
import { Button } from "@src/components/ui"
|
||||
import { vscode } from "@src/utils/vscode"
|
||||
|
||||
import { ModelPicker } from "../ModelPicker"
|
||||
import { ClaudeCodeRateLimitDashboard } from "./ClaudeCodeRateLimitDashboard"
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,12 @@
|
|||
import { useCallback, useEffect, useState } from "react"
|
||||
import { VSCodeTextField } from "@vscode/webview-ui-toolkit/react"
|
||||
|
||||
import { OrganizationAllowList, type ProviderSettings, deepInfraDefaultModelId } from "@roo-code/types"
|
||||
|
||||
import type { RouterModels } from "@roo/api"
|
||||
import {
|
||||
type OrganizationAllowList,
|
||||
type ProviderSettings,
|
||||
type RouterModels,
|
||||
deepInfraDefaultModelId,
|
||||
} from "@roo-code/types"
|
||||
|
||||
import { vscode } from "@src/utils/vscode"
|
||||
import { useAppTranslation } from "@src/i18n/TranslationContext"
|
||||
|
|
|
|||
|
|
@ -2,9 +2,8 @@ import { useCallback, useState, useEffect, useMemo } from "react"
|
|||
import { useEvent } from "react-use"
|
||||
import { VSCodeTextField } from "@vscode/webview-ui-toolkit/react"
|
||||
|
||||
import type { ProviderSettings } from "@roo-code/types"
|
||||
import type { ProviderSettings, ExtensionMessage } from "@roo-code/types"
|
||||
|
||||
import { ExtensionMessage } from "@roo/ExtensionMessage"
|
||||
import { vscode } from "@src/utils/vscode"
|
||||
import { useAppTranslation } from "@src/i18n/TranslationContext"
|
||||
import { VSCodeButtonLink } from "@src/components/common/VSCodeButtonLink"
|
||||
|
|
|
|||
|
|
@ -4,15 +4,13 @@ import { Trans } from "react-i18next"
|
|||
import { Checkbox } from "vscrui"
|
||||
import { VSCodeLink, VSCodeRadio, VSCodeRadioGroup, VSCodeTextField } from "@vscode/webview-ui-toolkit/react"
|
||||
|
||||
import type { ProviderSettings } from "@roo-code/types"
|
||||
import type { ProviderSettings, ExtensionMessage, ModelRecord } from "@roo-code/types"
|
||||
|
||||
import { useAppTranslation } from "@src/i18n/TranslationContext"
|
||||
import { ExtensionMessage } from "@roo/ExtensionMessage"
|
||||
import { useRouterModels } from "@src/components/ui/hooks/useRouterModels"
|
||||
import { vscode } from "@src/utils/vscode"
|
||||
|
||||
import { inputEventTransform } from "../transforms"
|
||||
import { ModelRecord } from "@roo/api"
|
||||
|
||||
type LMStudioProps = {
|
||||
apiConfiguration: ProviderSettings
|
||||
|
|
|
|||
|
|
@ -1,10 +1,14 @@
|
|||
import { useCallback, useState, useEffect, useRef } from "react"
|
||||
import { VSCodeTextField, VSCodeCheckbox } from "@vscode/webview-ui-toolkit/react"
|
||||
|
||||
import { type ProviderSettings, type OrganizationAllowList, litellmDefaultModelId } from "@roo-code/types"
|
||||
import {
|
||||
type ProviderSettings,
|
||||
type OrganizationAllowList,
|
||||
type ExtensionMessage,
|
||||
litellmDefaultModelId,
|
||||
} from "@roo-code/types"
|
||||
|
||||
import { RouterName } from "@roo/api"
|
||||
import { ExtensionMessage } from "@roo/ExtensionMessage"
|
||||
|
||||
import { vscode } from "@src/utils/vscode"
|
||||
import { useExtensionState } from "@src/context/ExtensionStateContext"
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
import { useCallback } from "react"
|
||||
import { VSCodeTextField } from "@vscode/webview-ui-toolkit/react"
|
||||
|
||||
import { type ProviderSettings, mistralDefaultModelId } from "@roo-code/types"
|
||||
|
||||
import type { RouterModels } from "@roo/api"
|
||||
import { type ProviderSettings, type RouterModels, mistralDefaultModelId } from "@roo-code/types"
|
||||
|
||||
import { useAppTranslation } from "@src/i18n/TranslationContext"
|
||||
import { VSCodeButtonLink } from "@src/components/common/VSCodeButtonLink"
|
||||
|
|
|
|||
|
|
@ -2,16 +2,13 @@ import { useState, useCallback, useMemo, useEffect } from "react"
|
|||
import { useEvent } from "react-use"
|
||||
import { VSCodeTextField, VSCodeRadioGroup, VSCodeRadio } from "@vscode/webview-ui-toolkit/react"
|
||||
|
||||
import type { ProviderSettings } from "@roo-code/types"
|
||||
|
||||
import { ExtensionMessage } from "@roo/ExtensionMessage"
|
||||
import type { ProviderSettings, ExtensionMessage, ModelRecord } from "@roo-code/types"
|
||||
|
||||
import { useAppTranslation } from "@src/i18n/TranslationContext"
|
||||
import { useRouterModels } from "@src/components/ui/hooks/useRouterModels"
|
||||
import { vscode } from "@src/utils/vscode"
|
||||
|
||||
import { inputEventTransform } from "../transforms"
|
||||
import { ModelRecord } from "@roo/api"
|
||||
|
||||
type OllamaProps = {
|
||||
apiConfiguration: ProviderSettings
|
||||
|
|
|
|||
|
|
@ -8,12 +8,11 @@ import {
|
|||
type ModelInfo,
|
||||
type ReasoningEffort,
|
||||
type OrganizationAllowList,
|
||||
type ExtensionMessage,
|
||||
azureOpenAiDefaultApiVersion,
|
||||
openAiModelInfoSaneDefaults,
|
||||
} from "@roo-code/types"
|
||||
|
||||
import { ExtensionMessage } from "@roo/ExtensionMessage"
|
||||
|
||||
import { useAppTranslation } from "@src/i18n/TranslationContext"
|
||||
import { Button, StandardTooltip } from "@src/components/ui"
|
||||
|
||||
|
|
|
|||
|
|
@ -2,9 +2,12 @@ import { useCallback, useState } from "react"
|
|||
import { Checkbox } from "vscrui"
|
||||
import { VSCodeTextField } from "@vscode/webview-ui-toolkit/react"
|
||||
|
||||
import { type ProviderSettings, type OrganizationAllowList, openRouterDefaultModelId } from "@roo-code/types"
|
||||
|
||||
import type { RouterModels } from "@roo/api"
|
||||
import {
|
||||
type ProviderSettings,
|
||||
type OrganizationAllowList,
|
||||
type RouterModels,
|
||||
openRouterDefaultModelId,
|
||||
} from "@roo-code/types"
|
||||
|
||||
import { useAppTranslation } from "@src/i18n/TranslationContext"
|
||||
import { getOpenRouterAuthUrl } from "@src/oauth/urls"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import React from "react"
|
||||
import { VSCodeTextField, VSCodeLink } from "@vscode/webview-ui-toolkit/react"
|
||||
|
||||
import { type ProviderSettings } from "@roo-code/types"
|
||||
|
||||
interface QwenCodeProps {
|
||||
|
|
|
|||
|
|
@ -1,9 +1,12 @@
|
|||
import { useCallback, useEffect, useState } from "react"
|
||||
import { VSCodeCheckbox, VSCodeTextField } from "@vscode/webview-ui-toolkit/react"
|
||||
|
||||
import { type ProviderSettings, type OrganizationAllowList, requestyDefaultModelId } from "@roo-code/types"
|
||||
|
||||
import type { RouterModels } from "@roo/api"
|
||||
import {
|
||||
type ProviderSettings,
|
||||
type OrganizationAllowList,
|
||||
type RouterModels,
|
||||
requestyDefaultModelId,
|
||||
} from "@roo-code/types"
|
||||
|
||||
import { vscode } from "@src/utils/vscode"
|
||||
import { useAppTranslation } from "@src/i18n/TranslationContext"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
import { type ProviderSettings, type OrganizationAllowList, rooDefaultModelId } from "@roo-code/types"
|
||||
|
||||
import type { RouterModels } from "@roo/api"
|
||||
import {
|
||||
type ProviderSettings,
|
||||
type OrganizationAllowList,
|
||||
type RouterModels,
|
||||
rooDefaultModelId,
|
||||
} from "@roo-code/types"
|
||||
|
||||
import { useAppTranslation } from "@src/i18n/TranslationContext"
|
||||
import { vscode } from "@src/utils/vscode"
|
||||
|
|
|
|||
|
|
@ -2,9 +2,12 @@ import { useCallback, useState, useRef } from "react"
|
|||
import { VSCodeTextField } from "@vscode/webview-ui-toolkit/react"
|
||||
import { useQueryClient } from "@tanstack/react-query"
|
||||
|
||||
import { type ProviderSettings, type OrganizationAllowList, unboundDefaultModelId } from "@roo-code/types"
|
||||
|
||||
import type { RouterModels } from "@roo/api"
|
||||
import {
|
||||
type ProviderSettings,
|
||||
type OrganizationAllowList,
|
||||
type RouterModels,
|
||||
unboundDefaultModelId,
|
||||
} from "@roo-code/types"
|
||||
|
||||
import { useAppTranslation } from "@src/i18n/TranslationContext"
|
||||
import { VSCodeButtonLink } from "@src/components/common/VSCodeButtonLink"
|
||||
|
|
|
|||
|
|
@ -2,9 +2,7 @@ import { useState, useCallback } from "react"
|
|||
import { useEvent } from "react-use"
|
||||
import { LanguageModelChatSelector } from "vscode"
|
||||
|
||||
import type { ProviderSettings } from "@roo-code/types"
|
||||
|
||||
import { ExtensionMessage } from "@roo/ExtensionMessage"
|
||||
import type { ProviderSettings, ExtensionMessage } from "@roo-code/types"
|
||||
|
||||
import { useAppTranslation } from "@src/i18n/TranslationContext"
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@src/components/ui"
|
||||
|
|
|
|||
|
|
@ -1,9 +1,12 @@
|
|||
import { useCallback } from "react"
|
||||
import { VSCodeTextField } from "@vscode/webview-ui-toolkit/react"
|
||||
|
||||
import { type ProviderSettings, type OrganizationAllowList, vercelAiGatewayDefaultModelId } from "@roo-code/types"
|
||||
|
||||
import type { RouterModels } from "@roo/api"
|
||||
import {
|
||||
type ProviderSettings,
|
||||
type OrganizationAllowList,
|
||||
type RouterModels,
|
||||
vercelAiGatewayDefaultModelId,
|
||||
} from "@roo-code/types"
|
||||
|
||||
import { useAppTranslation } from "@src/i18n/TranslationContext"
|
||||
import { VSCodeButtonLink } from "@src/components/common/VSCodeButtonLink"
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { useCallback } from "react"
|
||||
import { VSCodeTextField, VSCodeDropdown, VSCodeOption } from "@vscode/webview-ui-toolkit/react"
|
||||
|
||||
import { zaiApiLineConfigs, zaiApiLineSchema, type ProviderSettings } from "@roo-code/types"
|
||||
import { type ProviderSettings, zaiApiLineConfigs, zaiApiLineSchema } from "@roo-code/types"
|
||||
|
||||
import { useAppTranslation } from "@src/i18n/TranslationContext"
|
||||
import { VSCodeButtonLink } from "@src/components/common/VSCodeButtonLink"
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import { useQuery } from "@tanstack/react-query"
|
||||
|
||||
import { ModelRecord } from "@roo/api"
|
||||
import { ExtensionMessage } from "@roo/ExtensionMessage"
|
||||
import { type ModelRecord, type ExtensionMessage } from "@roo-code/types"
|
||||
|
||||
import { vscode } from "@src/utils/vscode"
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import { useQuery } from "@tanstack/react-query"
|
||||
|
||||
import { ModelRecord } from "@roo/api"
|
||||
import { ExtensionMessage } from "@roo/ExtensionMessage"
|
||||
import { type ModelRecord, type ExtensionMessage } from "@roo-code/types"
|
||||
|
||||
import { vscode } from "@src/utils/vscode"
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
import { useEffect, useState } from "react"
|
||||
import type { ExtensionMessage } from "@roo/ExtensionMessage"
|
||||
|
||||
import type { ExtensionMessage } from "@roo-code/types"
|
||||
|
||||
import { vscode } from "@src/utils/vscode"
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import { useQuery } from "@tanstack/react-query"
|
||||
|
||||
import { RouterModels } from "@roo/api"
|
||||
import { ExtensionMessage } from "@roo/ExtensionMessage"
|
||||
import { type RouterModels, type ExtensionMessage } from "@roo-code/types"
|
||||
|
||||
import { vscode } from "@src/utils/vscode"
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ import {
|
|||
type ProviderName,
|
||||
type ProviderSettings,
|
||||
type ModelInfo,
|
||||
type ModelRecord,
|
||||
type RouterModels,
|
||||
anthropicModels,
|
||||
bedrockModels,
|
||||
cerebrasModels,
|
||||
|
|
@ -36,8 +38,6 @@ import {
|
|||
NATIVE_TOOL_DEFAULTS,
|
||||
} from "@roo-code/types"
|
||||
|
||||
import type { ModelRecord, RouterModels } from "@roo/api"
|
||||
|
||||
import { useRouterModels } from "./useRouterModels"
|
||||
import { useOpenRouterModelProviders } from "./useOpenRouterModelProviders"
|
||||
import { useLmStudioModels } from "./useLmStudioModels"
|
||||
|
|
|
|||
|
|
@ -10,18 +10,22 @@ import {
|
|||
type TelemetrySetting,
|
||||
type OrganizationAllowList,
|
||||
type CloudOrganizationMembership,
|
||||
type ExtensionMessage,
|
||||
type ExtensionState,
|
||||
type MarketplaceInstalledMetadata,
|
||||
type Command,
|
||||
type McpServer,
|
||||
RouterModels,
|
||||
ORGANIZATION_ALLOW_ALL,
|
||||
DEFAULT_CHECKPOINT_TIMEOUT_SECONDS,
|
||||
} from "@roo-code/types"
|
||||
|
||||
import { ExtensionMessage, ExtensionState, MarketplaceInstalledMetadata, Command } from "@roo/ExtensionMessage"
|
||||
import { findLastIndex } from "@roo/array"
|
||||
import { McpServer } from "@roo/mcp"
|
||||
|
||||
import { checkExistKey } from "@roo/checkExistApiConfig"
|
||||
import { Mode, defaultModeSlug, defaultPrompts } from "@roo/modes"
|
||||
import { CustomSupportPrompts } from "@roo/support-prompt"
|
||||
import { experimentDefault } from "@roo/experiments"
|
||||
import { RouterModels } from "@roo/api"
|
||||
|
||||
import { vscode } from "@src/utils/vscode"
|
||||
import { convertTextMateToHljs } from "@src/utils/textMateToHljs"
|
||||
|
|
|
|||
|
|
@ -1,8 +1,11 @@
|
|||
import { render, screen, act } from "@/utils/test-utils"
|
||||
|
||||
import { ProviderSettings, ExperimentId, DEFAULT_CHECKPOINT_TIMEOUT_SECONDS } from "@roo-code/types"
|
||||
|
||||
import { ExtensionState } from "@roo/ExtensionMessage"
|
||||
import {
|
||||
type ProviderSettings,
|
||||
type ExperimentId,
|
||||
type ExtensionState,
|
||||
DEFAULT_CHECKPOINT_TIMEOUT_SECONDS,
|
||||
} from "@roo-code/types"
|
||||
|
||||
import { ExtensionStateContextProvider, useExtensionState, mergeExtensionState } from "../ExtensionStateContext"
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,4 @@
|
|||
import type { ProviderSettings, OrganizationAllowList } from "@roo-code/types"
|
||||
|
||||
import { RouterModels } from "@roo/api"
|
||||
import type { ProviderSettings, OrganizationAllowList, RouterModels } from "@roo-code/types"
|
||||
|
||||
// Mock i18next to return translation keys with interpolated values
|
||||
vi.mock("i18next", () => ({
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import { Fzf } from "fzf"
|
||||
|
||||
import type { ModeConfig } from "@roo-code/types"
|
||||
import type { Command } from "@roo/ExtensionMessage"
|
||||
import type { ModeConfig, Command } from "@roo-code/types"
|
||||
|
||||
import { mentionRegex } from "@roo/context-mentions"
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { McpResource, McpResourceTemplate } from "@roo/mcp"
|
||||
import type { McpResource, McpResourceTemplate } from "@roo-code/types"
|
||||
|
||||
/**
|
||||
* Matches a URI against an array of URI templates and returns the matching template
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import {
|
|||
type ProviderSettings,
|
||||
type OrganizationAllowList,
|
||||
type ProviderName,
|
||||
type RouterModels,
|
||||
modelIdKeysByProvider,
|
||||
isProviderName,
|
||||
isDynamicProvider,
|
||||
|
|
@ -11,8 +12,6 @@ import {
|
|||
isCustomProvider,
|
||||
} from "@roo-code/types"
|
||||
|
||||
import type { RouterModels } from "@roo/api"
|
||||
|
||||
export function validateApiConfiguration(
|
||||
apiConfiguration: ProviderSettings,
|
||||
routerModels?: RouterModels,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue