Fix all linter errors (and fix the lint scripts too) (#2958)

This commit is contained in:
Chris Estreich 2025-04-26 09:45:26 -07:00 committed by GitHub
parent 418791a743
commit 1924e10e72
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
93 changed files with 181 additions and 413 deletions

View file

@ -364,7 +364,7 @@
"install-webview": "cd webview-ui && npm install",
"install-e2e": "cd e2e && npm install",
"lint": "npm-run-all -l -p lint:*",
"lint:extension": "eslint src/**/*.ts",
"lint:extension": "eslint src --ext .ts",
"lint:webview": "cd webview-ui && npm run lint",
"lint:e2e": "cd e2e && npm run lint",
"check-types": "npm-run-all -l -p check-types:*",

View file

@ -24,26 +24,6 @@ const baseTestDirs = [
"/test/log/path",
]
// Helper function to format instructions
const formatInstructions = (sections: string[]): string => {
const joinedSections = sections.filter(Boolean).join("\n\n")
return joinedSections
? `
====
USER'S CUSTOM INSTRUCTIONS
The following additional instructions are provided by the user, and should be followed to the best of your ability without interfering with the TOOL USE guidelines.
${joinedSections}`
: ""
}
// Helper function to format rule content
const formatRuleContent = (ruleFile: string, content: string): string => {
return `Rules:\n# Rules from ${ruleFile}:\n${content}`
}
type RuleFiles = {
".clinerules-code": string
".clinerules-ask": string
@ -65,7 +45,7 @@ const ensureDirectoryExists = (path: string) => {
}
const mockFs = {
readFile: jest.fn().mockImplementation(async (filePath: string, encoding?: string) => {
readFile: jest.fn().mockImplementation(async (filePath: string, _encoding?: string) => {
// Return stored content if it exists
if (mockFiles.has(filePath)) {
return mockFiles.get(filePath)

View file

@ -13,7 +13,7 @@
* @param vscodeAppRoot - Optional VSCode app root path (can be undefined)
* @returns Promise resolving to a mock path to the ripgrep binary
*/
export const getBinPath = jest.fn().mockImplementation(async (vscodeAppRoot?: string): Promise<string> => {
export const getBinPath = jest.fn().mockImplementation(async (_vscodeAppRoot?: string): Promise<string> => {
return "/mock/path/to/rg"
})
@ -30,7 +30,7 @@ export const getBinPath = jest.fn().mockImplementation(async (vscodeAppRoot?: st
export const regexSearchFiles = jest
.fn()
.mockImplementation(
async (cwd?: string, directoryPath?: string, regex?: string, filePattern?: string): Promise<string> => {
async (_cwd?: string, _directoryPath?: string, _regex?: string, _filePattern?: string): Promise<string> => {
return "Mock search results"
},
)
@ -43,6 +43,6 @@ export const regexSearchFiles = jest
* @param maxLength - Optional maximum length (can be undefined)
* @returns The original line or empty string if undefined
*/
export const truncateLine = jest.fn().mockImplementation((line?: string, maxLength?: number): string => {
export const truncateLine = jest.fn().mockImplementation((line?: string, _maxLength?: number): string => {
return line || ""
})

View file

@ -77,7 +77,7 @@ export function buildApiHandler(configuration: ApiConfiguration): ApiHandler {
case "requesty":
return new RequestyHandler(options)
case "human-relay":
return new HumanRelayHandler(options)
return new HumanRelayHandler()
case "fake-ai":
return new FakeAIHandler(options)
case "xai":

View file

@ -1,3 +1,5 @@
// npx jest src/api/providers/__tests__/bedrock-custom-arn.test.ts
import { AwsBedrockHandler } from "../bedrock"
import { ApiHandlerOptions } from "../../../shared/api"
import { logger } from "../../../utils/logging"
@ -52,9 +54,6 @@ jest.mock("@aws-sdk/client-bedrock-runtime", () => {
}
})
// Get mock module for testing
const bedrockMock = jest.requireMock("@aws-sdk/client-bedrock-runtime").__mock
describe("Bedrock ARN Handling", () => {
// Helper function to create a handler with specific options
const createHandler = (options: Partial<ApiHandlerOptions> = {}) => {
@ -236,7 +235,8 @@ describe("Bedrock ARN Handling", () => {
// Create handler with ARN region different from provided region
const arn =
"arn:aws:bedrock:eu-west-1:123456789012:inference-profile/anthropic.claude-3-sonnet-20240229-v1:0"
const handler = createHandler({
createHandler({
awsCustomArn: arn,
awsRegion: "us-east-1", // Different from ARN region
})

View file

@ -1,3 +1,9 @@
// npx jest src/api/providers/__tests__/bedrock-invokedModelId.test.ts
import { ApiHandlerOptions } from "../../../shared/api"
import { AwsBedrockHandler, StreamEvent } from "../bedrock"
// Mock AWS SDK credential providers and Bedrock client
jest.mock("@aws-sdk/credential-providers", () => ({
fromIni: jest.fn().mockReturnValue({
@ -62,11 +68,6 @@ jest.mock("@aws-sdk/client-bedrock-runtime", () => {
}
})
import { AwsBedrockHandler, StreamEvent } from "../bedrock"
import { ApiHandlerOptions } from "../../../shared/api"
import { BedrockRuntimeClient } from "@aws-sdk/client-bedrock-runtime"
const { fromIni } = require("@aws-sdk/credential-providers")
describe("AwsBedrockHandler with invokedModelId", () => {
let mockSend: jest.Mock
@ -279,17 +280,6 @@ describe("AwsBedrockHandler with invokedModelId", () => {
}
})
// Mock getModel to return expected values
const getModelSpy = jest.spyOn(handler, "getModel").mockReturnValue({
id: "anthropic.claude-3-5-sonnet-20241022-v2:0",
info: {
maxTokens: 4096,
contextWindow: 128_000,
supportsPromptCache: false,
supportsImages: true,
},
})
// Create a message generator
const messageGenerator = handler.createMessage("system prompt", [{ role: "user", content: "user message" }])

View file

@ -22,11 +22,8 @@ jest.mock("@aws-sdk/client-bedrock-runtime", () => ({
}))
import { AwsBedrockHandler } from "../bedrock"
import { MessageContent } from "../../../shared/api"
import { BedrockRuntimeClient, ConverseStreamCommand } from "@aws-sdk/client-bedrock-runtime"
import { Anthropic } from "@anthropic-ai/sdk"
const { fromIni } = require("@aws-sdk/credential-providers")
import { logger } from "../../../utils/logging"
describe("AwsBedrockHandler", () => {
let handler: AwsBedrockHandler

View file

@ -95,7 +95,7 @@ describe("GeminiHandler", () => {
const stream = handler.createMessage(systemPrompt, mockMessages)
await expect(async () => {
for await (const chunk of stream) {
for await (const _chunk of stream) {
// Should throw before yielding any chunks
}
}).rejects.toThrow()

View file

@ -1,7 +1,7 @@
import { Anthropic } from "@anthropic-ai/sdk"
import { LmStudioHandler } from "../lmstudio"
import { ApiHandlerOptions } from "../../../shared/api"
import OpenAI from "openai"
import { Anthropic } from "@anthropic-ai/sdk"
// Mock OpenAI client
const mockCreate = jest.fn()
@ -120,7 +120,7 @@ describe("LmStudioHandler", () => {
const stream = handler.createMessage(systemPrompt, messages)
await expect(async () => {
for await (const chunk of stream) {
for await (const _chunk of stream) {
// Should not reach here
}
}).rejects.toThrow("Please check the LM Studio developer logs to debug what went wrong")

View file

@ -1,6 +1,7 @@
import { MistralHandler } from "../mistral"
import { ApiHandlerOptions, mistralDefaultModelId } from "../../../shared/api"
import { Anthropic } from "@anthropic-ai/sdk"
import { MistralHandler } from "../mistral"
import { ApiHandlerOptions } from "../../../shared/api"
import { ApiStreamTextChunk } from "../../transform/stream"
// Mock Mistral client
@ -9,7 +10,7 @@ jest.mock("@mistralai/mistralai", () => {
return {
Mistral: jest.fn().mockImplementation(() => ({
chat: {
stream: mockCreate.mockImplementation(async (options) => {
stream: mockCreate.mockImplementation(async (_options) => {
const stream = {
[Symbol.asyncIterator]: async function* () {
yield {

View file

@ -1,7 +1,7 @@
import { Anthropic } from "@anthropic-ai/sdk"
import { OllamaHandler } from "../ollama"
import { ApiHandlerOptions } from "../../../shared/api"
import OpenAI from "openai"
import { Anthropic } from "@anthropic-ai/sdk"
// Mock OpenAI client
const mockCreate = jest.fn()
@ -120,7 +120,7 @@ describe("OllamaHandler", () => {
const stream = handler.createMessage(systemPrompt, messages)
await expect(async () => {
for await (const chunk of stream) {
for await (const _chunk of stream) {
// Should not reach here
}
}).rejects.toThrow("API Error")

View file

@ -1,7 +1,7 @@
import { Anthropic } from "@anthropic-ai/sdk"
import { OpenAiNativeHandler } from "../openai-native"
import { ApiHandlerOptions } from "../../../shared/api"
import OpenAI from "openai"
import { Anthropic } from "@anthropic-ai/sdk"
// Mock OpenAI client
const mockCreate = jest.fn()
@ -116,7 +116,7 @@ describe("OpenAiNativeHandler", () => {
mockCreate.mockRejectedValueOnce(new Error("API Error"))
const stream = handler.createMessage(systemPrompt, messages)
await expect(async () => {
for await (const chunk of stream) {
for await (const _chunk of stream) {
// Should not reach here
}
}).rejects.toThrow("API Error")

View file

@ -176,7 +176,7 @@ describe("OpenAiHandler", () => {
const stream = handler.createMessage("system prompt", testMessages)
await expect(async () => {
for await (const chunk of stream) {
for await (const _chunk of stream) {
// Should not reach here
}
}).rejects.toThrow("API Error")
@ -191,7 +191,7 @@ describe("OpenAiHandler", () => {
const stream = handler.createMessage("system prompt", testMessages)
await expect(async () => {
for await (const chunk of stream) {
for await (const _chunk of stream) {
// Should not reach here
}
}).rejects.toThrow("Rate limit exceeded")

View file

@ -1,6 +1,6 @@
import { Anthropic } from "@anthropic-ai/sdk"
import OpenAI from "openai"
import { ApiHandlerOptions, ModelInfo, requestyDefaultModelInfo } from "../../../shared/api"
import { ApiHandlerOptions, ModelInfo } from "../../../shared/api"
import { RequestyHandler } from "../requesty"
import { convertToOpenAiMessages } from "../../transform/openai-format"
import { convertToR1Format } from "../../transform/r1-format"
@ -40,9 +40,7 @@ describe("RequestyHandler", () => {
jest.clearAllMocks()
// Setup mock create function that preserves params
let lastParams: any
mockCreate = jest.fn().mockImplementation((params) => {
lastParams = params
mockCreate = jest.fn().mockImplementation((_params) => {
return {
[Symbol.asyncIterator]: async function* () {
yield {

View file

@ -2,7 +2,6 @@
import { Anthropic } from "@anthropic-ai/sdk"
import { AnthropicVertex } from "@anthropic-ai/vertex-sdk"
import { BetaThinkingConfigParam } from "@anthropic-ai/sdk/resources/beta"
import { VertexHandler } from "../vertex"
import { ApiStreamChunk } from "../../transform/stream"
@ -388,7 +387,7 @@ describe("VertexHandler", () => {
const stream = handler.createMessage(systemPrompt, mockMessages)
await expect(async () => {
for await (const chunk of stream) {
for await (const _chunk of stream) {
// Should throw before yielding any chunks
}
}).rejects.toThrow("Vertex API error")

View file

@ -21,7 +21,7 @@ jest.mock("vscode", () => {
return {
workspace: {
onDidChangeConfiguration: jest.fn((callback) => ({
onDidChangeConfiguration: jest.fn((_callback) => ({
dispose: jest.fn(),
})),
},

View file

@ -603,8 +603,8 @@ export class AwsBedrockHandler extends BaseProvider implements SingleCompletionH
// Look for a pattern where the first segment before a dot doesn't contain dots or colons
// and the remaining parts still contain at least one dot
const genericPrefixMatch = modelId.match(/^([^.:]+)\.(.+\..+)$/)
if (genericPrefixMatch) {
const genericPrefix = genericPrefixMatch[1] + "."
return genericPrefixMatch[2]
}
}
@ -708,10 +708,11 @@ export class AwsBedrockHandler extends BaseProvider implements SingleCompletionH
if (Array.isArray(content)) {
return content.map((block) => {
// Use destructuring to remove cachePoint property
const { cachePoint, ...rest } = block
const { cachePoint: _, ...rest } = block
return rest
})
}
return content
}
@ -864,7 +865,7 @@ Suggestions:
/**
* Formats an error message based on the error type and context
*/
private formatErrorMessage(error: unknown, errorType: string, isStreamContext: boolean): string {
private formatErrorMessage(error: unknown, errorType: string, _isStreamContext: boolean): string {
const definition = AwsBedrockHandler.ERROR_TYPES[errorType] || AwsBedrockHandler.ERROR_TYPES.GENERIC
let template = definition.messageTemplate

View file

@ -4,7 +4,6 @@ import {
type GenerateContentResponseUsageMetadata,
type GenerateContentParameters,
type Content,
CreateCachedContentConfig,
} from "@google/genai"
import NodeCache from "node-cache"

View file

@ -1,23 +1,16 @@
// filepath: e:\Project\Roo-Code\src\api\providers\human-relay.ts
import { Anthropic } from "@anthropic-ai/sdk"
import { ApiHandlerOptions, ModelInfo } from "../../shared/api"
import * as vscode from "vscode"
import { ModelInfo } from "../../shared/api"
import { ApiHandler, SingleCompletionHandler } from "../index"
import { ApiStream } from "../transform/stream"
import * as vscode from "vscode"
import { ExtensionMessage } from "../../shared/ExtensionMessage"
import { getPanel } from "../../activate/registerCommands" // Import the getPanel function
/**
* Human Relay API processor
* This processor does not directly call the API, but interacts with the model through human operations copy and paste.
*/
export class HumanRelayHandler implements ApiHandler, SingleCompletionHandler {
private options: ApiHandlerOptions
constructor(options: ApiHandlerOptions) {
this.options = options
}
countTokens(content: Array<Anthropic.Messages.ContentBlockParam>): Promise<number> {
countTokens(_content: Array<Anthropic.Messages.ContentBlockParam>): Promise<number> {
return Promise.resolve(0)
}
@ -125,15 +118,10 @@ async function showHumanRelayDialog(promptText: string): Promise<string | undefi
vscode.commands.executeCommand(
"roo-cline.registerHumanRelayCallback",
requestId,
(response: string | undefined) => {
resolve(response)
},
(response: string | undefined) => resolve(response),
)
// Open the dialog box directly using the current panel
vscode.commands.executeCommand("roo-cline.showHumanRelayDialog", {
requestId,
promptText,
})
vscode.commands.executeCommand("roo-cline.showHumanRelayDialog", { requestId, promptText })
})
}

View file

@ -1,16 +1,7 @@
import { Anthropic } from "@anthropic-ai/sdk"
import { Mistral } from "@mistralai/mistralai"
import { SingleCompletionHandler } from "../"
import {
ApiHandlerOptions,
mistralDefaultModelId,
MistralModelId,
mistralModels,
ModelInfo,
openAiNativeDefaultModelId,
OpenAiNativeModelId,
openAiNativeModels,
} from "../../shared/api"
import { ApiHandlerOptions, mistralDefaultModelId, MistralModelId, mistralModels, ModelInfo } from "../../shared/api"
import { convertToMistralMessages } from "../transform/mistral-format"
import { ApiStream } from "../transform/stream"
import { BaseProvider } from "./base-provider"

View file

@ -226,7 +226,7 @@ export class OpenAiHandler extends BaseProvider implements SingleCompletionHandl
}
}
protected processUsageMetrics(usage: any, modelInfo?: ModelInfo): ApiStreamUsageChunk {
protected processUsageMetrics(usage: any, _modelInfo?: ModelInfo): ApiStreamUsageChunk {
return {
type: "usage",
inputTokens: usage?.prompt_tokens || 0,

View file

@ -57,15 +57,6 @@ interface VertexMessage extends Omit<Anthropic.Messages.MessageParam, "content">
content: string | VertexContentBlock[]
}
interface VertexMessageCreateParams {
model: string
max_tokens: number
temperature: number
system: string | VertexTextBlock[]
messages: VertexMessage[]
stream: boolean
}
interface VertexMessageResponse {
content: Array<{ type: "text"; text: string }>
}
@ -259,7 +250,7 @@ export class VertexHandler extends BaseProvider implements SingleCompletionHandl
private async *createClaudeMessage(systemPrompt: string, messages: Anthropic.Messages.MessageParam[]): ApiStream {
const model = this.getModel()
let { id, info, temperature, maxTokens, thinking } = model
let { id, temperature, maxTokens, thinking } = model
const useCache = model.info.supportsPromptCache
// Find indices of user messages that we want to cache

View file

@ -122,7 +122,7 @@ export class VsCodeLmHandler extends BaseProvider implements SingleCompletionHan
family: "lm",
version: "1.0",
maxInputTokens: 8192,
sendRequest: async (messages, options, token) => {
sendRequest: async (_messages, _options, _token) => {
// Provide a minimal implementation
return {
stream: (async function* () {

View file

@ -1,10 +1,10 @@
import { MultiPointStrategy } from "../multi-point-strategy"
import { CacheStrategy } from "../base-strategy"
import { CacheStrategyConfig, ModelInfo, CachePointPlacement } from "../types"
import { ContentBlock, SystemContentBlock } from "@aws-sdk/client-bedrock-runtime"
import { Anthropic } from "@anthropic-ai/sdk"
import { BedrockRuntimeClient } from "@aws-sdk/client-bedrock-runtime"
import { MultiPointStrategy } from "../multi-point-strategy"
import { CacheStrategyConfig, ModelInfo, CachePointPlacement } from "../types"
import { AwsBedrockHandler } from "../../../providers/bedrock"
import { BedrockRuntimeClient, ConverseStreamCommand } from "@aws-sdk/client-bedrock-runtime"
// Common test utilities
const defaultModelInfo: ModelInfo = {
@ -363,7 +363,7 @@ describe("Cache Strategy", () => {
// Call the method that uses convertToBedrockConverseMessages
const stream = handler.createMessage(systemPrompt, mockMessages)
for await (const chunk of stream) {
for await (const _chunk of stream) {
// Just consume the stream
}
@ -404,7 +404,7 @@ describe("Cache Strategy", () => {
// Call the method that uses convertToBedrockConverseMessages
const stream = handler.createMessage(systemPrompt, mockMessages)
for await (const chunk of stream) {
for await (const _chunk of stream) {
// Just consume the stream
}
@ -505,7 +505,7 @@ describe("Cache Strategy", () => {
// Call the method that uses convertToBedrockConverseMessages
const stream = handler.createMessage(systemPrompt, mockMessages)
for await (const chunk of stream) {
for await (const _chunk of stream) {
// Just consume the stream
}
@ -555,7 +555,7 @@ describe("Cache Strategy", () => {
// Call the method that uses convertToBedrockConverseMessages
const stream = handler.createMessage(systemPrompt, mockMessages)
for await (const chunk of stream) {
for await (const _chunk of stream) {
// Just consume the stream
}
@ -931,7 +931,7 @@ describe("Cache Strategy", () => {
// (260 tokens from messages 7-8 plus 400 tokens from the new messages)
// Create messages matching Example 5 from documentation
const messages = [
const _messages = [
createMessage("user", "Tell me about machine learning.", 100),
createMessage("assistant", "Machine learning is a field of study...", 200),
createMessage("user", "What about deep learning?", 100),
@ -948,7 +948,7 @@ describe("Cache Strategy", () => {
]
// Previous cache point placements from Example 4
const previousCachePointPlacements: CachePointPlacement[] = [
const _previousCachePointPlacements: CachePointPlacement[] = [
{
index: 2, // After the second user message
type: "message",

View file

@ -1,7 +1,6 @@
import { Anthropic } from "@anthropic-ai/sdk"
import { ContentBlock, SystemContentBlock, Message, ConversationRole } from "@aws-sdk/client-bedrock-runtime"
import { CacheStrategyConfig, CacheResult, CachePointPlacement } from "./types"
import { logger } from "../../../utils/logging"
export abstract class CacheStrategy {
/**

View file

@ -95,9 +95,6 @@ export class MultiPointStrategy extends CacheStrategy {
return placements
}
// Calculate total tokens in the conversation
const totalTokens = this.config.messages.reduce((acc, curr) => acc + this.estimateTokenCount(curr), 0)
// Calculate tokens in new messages (added since last cache point placement)
const lastPreviousIndex = previousPlacements[previousPlacements.length - 1].index
const newMessagesTokens = this.config.messages
@ -181,7 +178,6 @@ export class MultiPointStrategy extends CacheStrategy {
} else if (i === smallestGapIndex) {
// Replace with a combined placement
const combinedEndIndex = previousPlacements[i + 1].index
const combinedTokens = tokensBetweenPlacements[i] + tokensBetweenPlacements[i + 1]
// Find the optimal placement within this combined range
const startOfRange = i === 0 ? 0 : previousPlacements[i - 1].index + 1

View file

@ -21,7 +21,7 @@ export function convertToMistralMessages(anthropicMessages: Anthropic.Messages.M
})
} else {
if (anthropicMessage.role === "user") {
const { nonToolMessages, toolMessages } = anthropicMessage.content.reduce<{
const { nonToolMessages } = anthropicMessage.content.reduce<{
nonToolMessages: (Anthropic.TextBlockParam | Anthropic.ImageBlockParam)[]
toolMessages: Anthropic.ToolResultBlockParam[]
}>(
@ -53,7 +53,7 @@ export function convertToMistralMessages(anthropicMessages: Anthropic.Messages.M
})
}
} else if (anthropicMessage.role === "assistant") {
const { nonToolMessages, toolMessages } = anthropicMessage.content.reduce<{
const { nonToolMessages } = anthropicMessage.content.reduce<{
nonToolMessages: (Anthropic.TextBlockParam | Anthropic.ImageBlockParam)[]
toolMessages: Anthropic.ToolUseBlockParam[]
}>(

View file

@ -191,19 +191,19 @@ describe("Cline", () => {
return undefined
}),
update: jest.fn().mockImplementation((key, value) => Promise.resolve()),
update: jest.fn().mockImplementation((_key, _value) => Promise.resolve()),
keys: jest.fn().mockReturnValue([]),
},
globalStorageUri: storageUri,
workspaceState: {
get: jest.fn().mockImplementation((key) => undefined),
update: jest.fn().mockImplementation((key, value) => Promise.resolve()),
get: jest.fn().mockImplementation((_key) => undefined),
update: jest.fn().mockImplementation((_key, _value) => Promise.resolve()),
keys: jest.fn().mockReturnValue([]),
},
secrets: {
get: jest.fn().mockImplementation((key) => Promise.resolve(undefined)),
store: jest.fn().mockImplementation((key, value) => Promise.resolve()),
delete: jest.fn().mockImplementation((key) => Promise.resolve()),
get: jest.fn().mockImplementation((_key) => Promise.resolve(undefined)),
store: jest.fn().mockImplementation((_key, _value) => Promise.resolve()),
delete: jest.fn().mockImplementation((_key) => Promise.resolve()),
},
extensionUri: {
fsPath: "/mock/extension/path",
@ -385,7 +385,7 @@ describe("Cline", () => {
// Mock the method with a stable implementation
jest.spyOn(Cline.prototype, "getEnvironmentDetails").mockImplementation(
// Use 'any' type to allow for dynamic test properties
async function (this: any, verbose: boolean = false): Promise<string> {
async function (this: any, _verbose: boolean = false): Promise<string> {
// Use test-specific mock if available
if (this._mockGetEnvironmentDetails) {
return this._mockGetEnvironmentDetails()

View file

@ -1,6 +1,6 @@
// npx jest src/core/__tests__/mode-validator.test.ts
import { isToolAllowedForMode, getModeConfig, modes, ModeConfig } from "../../shared/modes"
import { isToolAllowedForMode, modes, ModeConfig } from "../../shared/modes"
import { TOOL_GROUPS } from "../../shared/tools"
import { validateToolUse } from "../mode-validator"
@ -10,7 +10,6 @@ describe("mode-validator", () => {
describe("isToolAllowedForMode", () => {
describe("code mode", () => {
it("allows all code mode tools", () => {
const mode = getModeConfig(codeMode)
// Code mode has all groups
Object.entries(TOOL_GROUPS).forEach(([_, config]) => {
config.tools.forEach((tool: string) => {
@ -26,7 +25,6 @@ describe("mode-validator", () => {
describe("architect mode", () => {
it("allows configured tools", () => {
const mode = getModeConfig(architectMode)
// Architect mode has read, browser, and mcp groups
const architectTools = [
...TOOL_GROUPS.read.tools,
@ -41,7 +39,6 @@ describe("mode-validator", () => {
describe("ask mode", () => {
it("allows configured tools", () => {
const mode = getModeConfig(askMode)
// Ask mode has read, browser, and mcp groups
const askTools = [...TOOL_GROUPS.read.tools, ...TOOL_GROUPS.browser.tools, ...TOOL_GROUPS.mcp.tools]
askTools.forEach((tool) => {

View file

@ -8,7 +8,6 @@ import { extractTextFromFile } from "../../integrations/misc/extract-text"
import { parseSourceCodeDefinitionsForFile } from "../../services/tree-sitter"
import { isBinaryFile } from "isbinaryfile"
import { ReadFileToolUse } from "../../shared/tools"
import { ToolUsage } from "../../schemas"
// Mock dependencies
jest.mock("../../integrations/misc/line-counter")
@ -100,7 +99,7 @@ describe("read_file tool with maxReadFileLine setting", () => {
mockInputContent = fileContent
// Setup the extractTextFromFile mock implementation with the current mockInputContent
mockedExtractTextFromFile.mockImplementation((filePath) => {
mockedExtractTextFromFile.mockImplementation((_filePath) => {
const actual = jest.requireActual("../../integrations/misc/extract-text")
return Promise.resolve(actual.addLineNumbers(mockInputContent))
})

View file

@ -8,7 +8,6 @@ import { extractTextFromFile } from "../../integrations/misc/extract-text"
import { parseSourceCodeDefinitionsForFile } from "../../services/tree-sitter"
import { isBinaryFile } from "isbinaryfile"
import { ReadFileToolUse } from "../../shared/tools"
import { ToolUsage } from "../../schemas"
// Mock dependencies
jest.mock("../../integrations/misc/line-counter")
@ -22,7 +21,7 @@ jest.mock("../../integrations/misc/extract-text", () => {
...actual,
// Expose the spy so tests can access it
__addLineNumbersSpy: addLineNumbersSpy,
extractTextFromFile: jest.fn().mockImplementation((filePath) => {
extractTextFromFile: jest.fn().mockImplementation((_filePath) => {
// Use the actual addLineNumbers function
const content = mockInputContent
return Promise.resolve(actual.addLineNumbers(content))

View file

@ -1,7 +1,7 @@
import { ExtensionContext } from "vscode"
import { z, ZodError } from "zod"
import { providerSettingsSchema, ApiConfigMeta, ProviderSettings } from "../../schemas"
import { providerSettingsSchema, ApiConfigMeta } from "../../schemas"
import { Mode, modes } from "../../shared/modes"
import { telemetryService } from "../../services/telemetry/TelemetryService"
@ -78,7 +78,7 @@ export class ProviderSettingsManager {
let isDirty = false
// Ensure all configs have IDs.
for (const [name, apiConfig] of Object.entries(providerProfiles.apiConfigs)) {
for (const [_name, apiConfig] of Object.entries(providerProfiles.apiConfigs)) {
if (!apiConfig.id) {
apiConfig.id = this.generateId()
isDirty = true
@ -130,7 +130,7 @@ export class ProviderSettingsManager {
rateLimitSeconds = 0
}
for (const [name, apiConfig] of Object.entries(providerProfiles.apiConfigs)) {
for (const [_name, apiConfig] of Object.entries(providerProfiles.apiConfigs)) {
if (apiConfig.rateLimitSeconds === undefined) {
apiConfig.rateLimitSeconds = rateLimitSeconds
}
@ -162,7 +162,7 @@ export class ProviderSettingsManager {
fuzzyMatchThreshold = 1.0
}
for (const [name, apiConfig] of Object.entries(providerProfiles.apiConfigs)) {
for (const [_name, apiConfig] of Object.entries(providerProfiles.apiConfigs)) {
if (apiConfig.diffEnabled === undefined) {
apiConfig.diffEnabled = diffEnabled
}

View file

@ -170,7 +170,7 @@ describe("CustomModesManager", () => {
throw new Error("File not found")
})
;(fs.writeFile as jest.Mock).mockImplementation(
async (path: string, content: string, encoding?: string) => {
async (path: string, content: string, _encoding?: string) => {
if (path === mockSettingsPath) {
settingsContent = JSON.parse(content)
}
@ -297,7 +297,7 @@ describe("CustomModesManager", () => {
throw new Error("File not found")
})
;(fs.writeFile as jest.Mock).mockImplementation(
async (path: string, content: string, encoding?: string) => {
async (path: string, content: string, _encoding?: string) => {
if (path === mockSettingsPath) {
settingsContent = JSON.parse(content)
}

View file

@ -203,7 +203,7 @@ Only use a single line of '=======' between search and replacement content, beca
const SEARCH_PREFIX = "<<<<<<<"
const REPLACE_PREFIX = ">>>>>>>"
const reportMergeConflictError = (found: string, expected: string) => ({
const reportMergeConflictError = (found: string, _expected: string) => ({
success: false,
error:
`ERROR: Special marker '${found}' found in your diff content at line ${state.line}:\n` +
@ -525,7 +525,7 @@ Only use a single line of '=======' between search and replacement content, beca
})
// Apply the replacement while preserving exact indentation
const indentedReplaceLines = replaceLines.map((line, i) => {
const indentedReplaceLines = replaceLines.map((line) => {
// Get the matched line's exact indentation
const matchedIndent = originalIndents[0] || ""

View file

@ -3,7 +3,7 @@ export const LOCK_TEXT_SYMBOL = "\u{1F512}"
export class RooIgnoreController {
rooIgnoreContent: string | undefined = undefined
constructor(cwd: string) {
constructor(_cwd: string) {
// No-op constructor
}
@ -12,12 +12,12 @@ export class RooIgnoreController {
return Promise.resolve()
}
validateAccess(filePath: string): boolean {
validateAccess(_filePath: string): boolean {
// Default implementation: allow all access
return true
}
validateCommand(command: string): string | undefined {
validateCommand(_command: string): string | undefined {
// Default implementation: allow all commands
return undefined
}

View file

@ -4,7 +4,6 @@ import { RooIgnoreController } from "../RooIgnoreController"
import * as path from "path"
import * as fs from "fs/promises"
import { fileExistsAtPath } from "../../../utils/fs"
import * as vscode from "vscode"
// Mock dependencies
jest.mock("fs/promises")

View file

@ -433,9 +433,6 @@ describe("RooIgnoreController", () => {
mockFileExists.mockResolvedValue(true)
mockReadFile.mockResolvedValue("node_modules")
// Find and trigger the onCreate handler
const onCreateHandler = mockWatcher.onDidCreate.mock.calls[0][0]
// Force reload of .rooignore content manually
await controller.initialize()

View file

@ -2,7 +2,7 @@ import * as vscode from "vscode"
import * as path from "path"
import { openFile } from "../../integrations/misc/open-file"
import { UrlContentFetcher } from "../../services/browser/UrlContentFetcher"
import { mentionRegexGlobal, formatGitSuggestion, type MentionSuggestion } from "../../shared/context-mentions"
import { mentionRegexGlobal } from "../../shared/context-mentions"
import fs from "fs/promises"
import { extractTextFromFile } from "../../integrations/misc/extract-text"
import { isBinaryFile } from "isbinaryfile"

View file

@ -35,7 +35,7 @@ describe("getCapabilitiesSection", () => {
const mockDiffStrategy: DiffStrategy = {
getName: () => "MockStrategy",
getToolDescription: () => "apply_diff tool description",
applyDiff: async (originalContent: string, diffContent: string): Promise<DiffResult> => {
applyDiff: async (_originalContent: string, _diffContent: string): Promise<DiffResult> => {
return { success: true, content: "mock result" }
},
}

View file

@ -2,11 +2,9 @@ import * as vscode from "vscode"
import { SYSTEM_PROMPT } from "../system"
import { McpHub } from "../../../services/mcp/McpHub"
import { ClineProvider } from "../../../core/webview/ClineProvider"
import { defaultModeSlug, modes, Mode, ModeConfig } from "../../../shared/modes"
import "../../../utils/path" // Import path utils to get access to toPosix string extension.
import { addCustomInstructions } from "../sections/custom-instructions"
import { EXPERIMENT_IDS } from "../../../shared/experiments"
import { MultiSearchReplaceDiffStrategy } from "../../diff/strategies/multi-search-replace"
// Mock the sections
@ -119,14 +117,6 @@ const mockContext = {
},
} as unknown as vscode.ExtensionContext
// Create a minimal mock of ClineProvider
const mockProvider = {
ensureMcpServersDirectoryExists: async () => "/mock/mcp/path",
ensureSettingsDirectoryExists: async () => "/mock/settings/path",
postMessageToWebview: async () => {},
context: mockContext,
} as unknown as ClineProvider
// Instead of extending McpHub, create a mock that implements just what we need
const createMockMcpHub = (): McpHub =>
({
@ -481,7 +471,6 @@ describe("SYSTEM_PROMPT", () => {
})
describe("addCustomInstructions", () => {
let experiments: Record<string, boolean> | undefined
beforeAll(() => {
// Ensure fs mock is properly initialized
const mockFs = jest.requireMock("fs/promises")
@ -493,9 +482,6 @@ describe("addCustomInstructions", () => {
}
throw new Error(`ENOENT: no such file or directory, mkdir '${path}'`)
})
// Initialize experiments as undefined by default
experiments = undefined
})
beforeEach(() => {

View file

@ -1,6 +1,6 @@
import * as path from "path"
import * as vscode from "vscode"
import { promises as fs } from "fs"
import { GlobalFileNames } from "../../../shared/globalFileNames"
export async function createModeInstructions(context: vscode.ExtensionContext | undefined): Promise<string> {

View file

@ -1,8 +1,8 @@
import { loadRuleFiles, addCustomInstructions } from "../custom-instructions"
import fs from "fs/promises"
import path from "path"
import { PathLike } from "fs"
import { loadRuleFiles, addCustomInstructions } from "../custom-instructions"
// Mock fs/promises
jest.mock("fs/promises")
@ -134,7 +134,7 @@ describe("loadRuleFiles", () => {
] as any)
statMock.mockImplementation(
(path) =>
(_path) =>
({
isFile: jest.fn().mockReturnValue(true),
}) as any,
@ -428,7 +428,7 @@ describe("addCustomInstructions", () => {
] as any)
statMock.mockImplementation(
(path) =>
(_path) =>
({
isFile: jest.fn().mockReturnValue(true),
}) as any,

View file

@ -1,8 +1,8 @@
import * as path from "path"
import * as vscode from "vscode"
import { promises as fs } from "fs"
import { ModeConfig, getAllModesWithPrompts } from "../../../shared/modes"
import { GlobalFileNames } from "../../../shared/globalFileNames"
export async function getModesSection(context: vscode.ExtensionContext): Promise<string> {
const settingsDir = path.join(context.globalStorageUri.fsPath, "settings")

View file

@ -1,6 +1,6 @@
import { DiffStrategy } from "../../../shared/tools"
function getEditingInstructions(diffStrategy?: DiffStrategy, experiments?: Record<string, boolean>): string {
function getEditingInstructions(diffStrategy?: DiffStrategy): string {
const instructions: string[] = []
const availableTools: string[] = []
@ -44,12 +44,7 @@ function getEditingInstructions(diffStrategy?: DiffStrategy, experiments?: Recor
return instructions.join("\n")
}
export function getRulesSection(
cwd: string,
supportsComputerUse: boolean,
diffStrategy?: DiffStrategy,
experiments?: Record<string, boolean> | undefined,
): string {
export function getRulesSection(cwd: string, supportsComputerUse: boolean, diffStrategy?: DiffStrategy): string {
return `====
RULES
@ -61,7 +56,7 @@ RULES
- Before using the execute_command tool, you must first think about the SYSTEM INFORMATION context provided to understand the user's environment and tailor your commands to ensure they are compatible with their system. You must also consider if the command you need to run should be executed in a specific directory outside of the current working directory '${cwd.toPosix()}', and if so prepend with \`cd\`'ing into that directory && then executing the command (as one command since you are stuck operating from '${cwd.toPosix()}'). For example, if you needed to run \`npm install\` in a project outside of '${cwd.toPosix()}', you would need to prepend with a \`cd\` i.e. pseudocode for this would be \`cd (path to project) && (command, in this case npm install)\`.
- When using the search_files tool, craft your regex patterns carefully to balance specificity and flexibility. Based on the user's task you may use it to find code patterns, TODO comments, function definitions, or any text-based information across the project. The results include context, so analyze the surrounding code to better understand the matches. Leverage the search_files tool in combination with other tools for more comprehensive analysis. For example, use it to find specific code patterns, then use read_file to examine the full context of interesting matches before using ${diffStrategy ? "apply_diff or write_to_file" : "write_to_file"} to make informed changes.
- When creating a new project (such as an app, website, or any software project), organize all new files within a dedicated project directory unless the user specifies otherwise. Use appropriate file paths when writing files, as the write_to_file tool will automatically create any necessary directories. Structure the project logically, adhering to best practices for the specific type of project being created. Unless otherwise specified, new projects should be easily run without additional setup, for example most projects can be built in HTML, CSS, and JavaScript - which you can open in a browser.
${getEditingInstructions(diffStrategy, experiments)}
${getEditingInstructions(diffStrategy)}
- Some modes have restrictions on which files they can edit. If you attempt to edit a restricted file, the operation will be rejected with a FileRestrictionError that will specify which file patterns are allowed for the current mode.
- Be sure to consider the type of project (e.g. Python, JavaScript, web application) when determining the appropriate structure and files to include. Also consider what files may be most relevant to accomplishing the task, for example looking at a project's manifest file would help you understand the project's dependencies, which you could incorporate into any code you write.
* For example, in architect mode trying to edit app.js would be rejected because architect mode can only edit files matching "\\.md$"

View file

@ -1,15 +1,9 @@
import defaultShell from "default-shell"
import os from "os"
import osName from "os-name"
import { Mode, ModeConfig, getModeBySlug, defaultModeSlug, isToolAllowedForMode } from "../../../shared/modes"
import { getShell } from "../../../utils/shell"
export function getSystemInfoSection(cwd: string, currentMode: Mode, customModes?: ModeConfig[]): string {
const findModeBySlug = (slug: string, modes?: ModeConfig[]) => modes?.find((m) => m.slug === slug)
const currentModeName = findModeBySlug(currentMode, customModes)?.name || currentMode
const codeModeName = findModeBySlug(defaultModeSlug, customModes)?.name || "Code"
export function getSystemInfoSection(cwd: string): string {
let details = `====
SYSTEM INFORMATION

View file

@ -3,7 +3,6 @@ import {
modes,
CustomModePrompts,
PromptComponent,
getRoleDefinition,
defaultModeSlug,
ModeConfig,
getModeBySlug,
@ -87,9 +86,9 @@ ${getCapabilitiesSection(cwd, supportsComputerUse, mcpHub, effectiveDiffStrategy
${modesSection}
${getRulesSection(cwd, supportsComputerUse, effectiveDiffStrategy, experiments)}
${getRulesSection(cwd, supportsComputerUse, effectiveDiffStrategy)}
${getSystemInfoSection(cwd, mode, customModeConfigs)}
${getSystemInfoSection(cwd)}
${getObjectiveSection()}

View file

@ -1,6 +1,6 @@
import { ToolArgs } from "./types"
export function getNewTaskDescription(args: ToolArgs): string {
export function getNewTaskDescription(_args: ToolArgs): string {
return `## new_task
Description: Create a new task with a specified starting mode and initial message. This tool instructs the system to create a new Cline instance in the given mode with the provided message.

View file

@ -96,8 +96,6 @@ export async function applyDiffTool(
error: "No diff strategy available",
}
let partResults = ""
if (!diffResult.success) {
cline.consecutiveMistakeCount++
const currentCount = (cline.consecutiveMistakeCountForApplyDiff.get(relPath) || 0) + 1
@ -116,8 +114,6 @@ export async function applyDiffTool(
formattedError = `<error_details>\n${
failPart.error
}${errorDetails ? `\n\nDetails:\n${errorDetails}` : ""}\n</error_details>`
partResults += formattedError
}
} else {
const errorDetails = diffResult.details ? JSON.stringify(diffResult.details, null, 2) : ""

View file

@ -90,7 +90,7 @@ export async function useMcpToolTool(
return item.text
}
if (item.type === "resource") {
const { blob, ...rest } = item.resource
const { blob: _, ...rest } = item.resource
return JSON.stringify(rest, null, 2)
}
return ""

View file

@ -82,7 +82,7 @@ const mockAddCustomInstructions = jest.fn().mockResolvedValue("Combined instruct
// Mock delay module
jest.mock("delay", () => {
const delayFn = (ms: number) => Promise.resolve()
const delayFn = (_ms: number) => Promise.resolve()
delayFn.createDelay = () => delayFn
delayFn.reject = () => Promise.reject(new Error("Delay rejected"))
delayFn.range = () => Promise.resolve()
@ -137,7 +137,7 @@ jest.mock("vscode", () => ({
get: jest.fn().mockReturnValue([]),
update: jest.fn(),
}),
onDidChangeConfiguration: jest.fn().mockImplementation((callback) => ({
onDidChangeConfiguration: jest.fn().mockImplementation(() => ({
dispose: jest.fn(),
})),
onDidSaveTextDocument: jest.fn(() => ({ dispose: jest.fn() })),
@ -212,7 +212,7 @@ jest.mock("../../Cline", () => ({
Cline: jest
.fn()
.mockImplementation(
(provider, apiConfiguration, customInstructions, diffEnabled, fuzzyMatchThreshold, task, taskId) => ({
(_provider, _apiConfiguration, _customInstructions, _diffEnabled, _fuzzyMatchThreshold, _task, taskId) => ({
api: undefined,
abortTask: jest.fn(),
handleWebviewAskResponse: jest.fn(),
@ -231,7 +231,7 @@ jest.mock("../../Cline", () => ({
// Mock extract-text
jest.mock("../../../integrations/misc/extract-text", () => ({
extractTextFromFile: jest.fn().mockImplementation(async (filePath: string) => {
extractTextFromFile: jest.fn().mockImplementation(async (_filePath: string) => {
const content = "const x = 1;\nconst y = 2;\nconst z = 3;"
const lines = content.split("\n")
return lines.map((line, index) => `${index + 1} | ${line}`).join("\n")
@ -322,9 +322,7 @@ describe("ClineProvider", () => {
callback()
return { dispose: jest.fn() }
}),
onDidChangeVisibility: jest.fn().mockImplementation((callback) => {
return { dispose: jest.fn() }
}),
onDidChangeVisibility: jest.fn().mockImplementation(() => ({ dispose: jest.fn() })),
} as unknown as vscode.WebviewView
provider = new ClineProvider(mockContext, mockOutputChannel, "sidebar", new ContextProxy(mockContext))
@ -1055,7 +1053,7 @@ describe("ClineProvider", () => {
// Reset and setup mock
mockAddCustomInstructions.mockClear()
mockAddCustomInstructions.mockImplementation(
(modeInstructions: string, globalInstructions: string, cwd: string) => {
(modeInstructions: string, globalInstructions: string, _cwd: string) => {
return Promise.resolve(modeInstructions || globalInstructions || "")
},
)
@ -2028,7 +2026,6 @@ describe.skip("ContextProxy integration", () => {
let mockContext: vscode.ExtensionContext
let mockOutputChannel: vscode.OutputChannel
let mockContextProxy: any
let mockGlobalStateUpdate: jest.Mock
beforeEach(() => {
// Reset mocks
@ -2050,8 +2047,6 @@ describe.skip("ContextProxy integration", () => {
mockOutputChannel = { appendLine: jest.fn() } as unknown as vscode.OutputChannel
mockContextProxy = new ContextProxy(mockContext)
provider = new ClineProvider(mockContext, mockOutputChannel, "sidebar", mockContextProxy)
mockGlobalStateUpdate = mockContext.globalState.update as jest.Mock
})
test("updateGlobalState uses contextProxy", async () => {

View file

@ -64,7 +64,7 @@ describe("countFileLines", () => {
}
const mockReadStream = {
on: jest.fn().mockImplementation(function (this: any, event, callback) {
on: jest.fn().mockImplementation(function (this: any, _event, _callback) {
return this
}),
}
@ -96,7 +96,7 @@ describe("countFileLines", () => {
}
const mockReadStream = {
on: jest.fn().mockImplementation(function (this: any, event, callback) {
on: jest.fn().mockImplementation(function (this: any, _event, _callback) {
return this
}),
}
@ -126,7 +126,7 @@ describe("countFileLines", () => {
}
const mockReadStream = {
on: jest.fn().mockImplementation(function (this: any, event, callback) {
on: jest.fn().mockImplementation(function (this: any, _event, _callback) {
return this
}),
}

View file

@ -354,25 +354,13 @@ function runBenchmark() {
const lineLimit = 500 // Standard line limit for truncation
console.log("\n--- Function 1: processCarriageReturns ---")
const processCarriageReturnsResult = runPerformanceTest(
"processCarriageReturns",
processCarriageReturns,
testData,
iterations,
)
runPerformanceTest("processCarriageReturns", processCarriageReturns, testData, iterations)
console.log("\n--- Function 2: applyRunLengthEncoding ---")
const applyRunLengthEncodingResult = runPerformanceTest(
"applyRunLengthEncoding",
applyRunLengthEncoding,
testData,
iterations,
)
runPerformanceTest("applyRunLengthEncoding", applyRunLengthEncoding, testData, iterations)
console.log("\n--- Function 3: truncateOutput ---")
const truncateOutputResult = runPerformanceTest("truncateOutput", truncateOutput, testData, iterations, [
lineLimit,
])
runPerformanceTest("truncateOutput", truncateOutput, testData, iterations, [lineLimit])
// Run baseline test to measure variance between identical runs
runBaselineTest(testData, Math.max(5, Math.floor(iterations / 4)))

View file

@ -187,7 +187,6 @@ export function applyRunLengthEncoding(content: string): string {
let pos = 0
let repeatCount = 0
let prevLine = null
let firstOccurrence = true
while (pos < content.length) {
const nextNewlineIdx = content.indexOf("\n", pos) // Find next line feed (\n) index

View file

@ -7,7 +7,6 @@
* Now you can read a range of lines from a file
*/
import { createReadStream } from "fs"
import { createInterface } from "readline"
const outOfRangeError = (filepath: string, n: number) => {
return new RangeError(`Line with index ${n} does not exist in '${filepath}'. Note that line indexing is zero-based`)

View file

@ -412,7 +412,8 @@ export class TerminalProcess extends EventEmitter<TerminalProcessEvents> {
}
// Wait for shell execution to complete and handle exit details
const exitDetails = await shellExecutionComplete
await shellExecutionComplete
this.isHot = false
if (commandOutputStarted) {

View file

@ -221,7 +221,6 @@ async function testTerminalCommand(
const exitDetails = TerminalProcess.interpretExitCode(exitCode)
// Set a timeout to avoid hanging tests
let timeoutId: NodeJS.Timeout
const timeoutPromise = new Promise<void>((_, reject) => {
timeoutId = setTimeout(() => {
reject(new Error("Test timed out after 1000ms"))

View file

@ -69,7 +69,6 @@ async function testCmdCommand(
let startTime: bigint = BigInt(0)
let endTime: bigint = BigInt(0)
let timeRecorded = false
let timeoutId: NodeJS.Timeout | undefined
// Create a mock terminal with shell integration
const mockTerminal = {

View file

@ -71,7 +71,6 @@ async function testPowerShellCommand(
let startTime: bigint = BigInt(0)
let endTime: bigint = BigInt(0)
let timeRecorded = false
let timeoutId: NodeJS.Timeout | undefined
// Create a mock terminal with shell integration
const mockTerminal = {

View file

@ -1,20 +1,5 @@
import { TerminalProcess } from "../TerminalProcess"
import { execSync } from "child_process"
import { Terminal } from "../Terminal"
import * as vscode from "vscode"
// Mock vscode.Terminal for testing
const mockTerminal = {
name: "Test Terminal",
processId: Promise.resolve(123),
creationOptions: {},
exitStatus: undefined,
state: { isInteractedWith: true },
dispose: jest.fn(),
hide: jest.fn(),
show: jest.fn(),
sendText: jest.fn(),
} as unknown as vscode.Terminal
describe("TerminalProcess.interpretExitCode", () => {
it("should handle undefined exit code", () => {

View file

@ -1,10 +1,10 @@
import * as vscode from "vscode"
import * as path from "path"
import { listFiles } from "../../services/glob/list-files"
import { ClineProvider } from "../../core/webview/ClineProvider"
import { toRelativePath } from "../../utils/path"
import { getWorkspacePath } from "../../utils/path"
import { logger } from "../../utils/logging"
const MAX_INITIAL_FILES = 1_000

View file

@ -6,7 +6,6 @@ import { Browser, Page, ScreenshotOptions, TimeoutError, launch, connect } from
import PCR from "puppeteer-chromium-resolver"
import pWaitFor from "p-wait-for"
import delay from "delay"
import axios from "axios"
import { fileExistsAtPath } from "../../utils/fs"
import { BrowserActionResult } from "../../shared/ExtensionMessage"
import { discoverChromeHostUrl, tryChromeHostUrl } from "./browserDiscovery"

View file

@ -45,8 +45,7 @@ export async function isPortOpen(host: string, port: number, timeout = 1000): Pr
export async function tryChromeHostUrl(chromeHostUrl: string): Promise<boolean> {
try {
console.log(`Trying to connect to Chrome at: ${chromeHostUrl}/json/version`)
const response = await axios.get(`${chromeHostUrl}/json/version`, { timeout: 1000 })
const data = response.data
await axios.get(`${chromeHostUrl}/json/version`, { timeout: 1000 })
return true
} catch (error) {
return false

View file

@ -1,4 +1,4 @@
import { CommitResult, SimpleGit } from "simple-git"
import { CommitResult } from "simple-git"
export type CheckpointResult = Partial<CommitResult> & Pick<CommitResult, "commit">

View file

@ -21,18 +21,6 @@ const mockResolve = (dirPath: string): string => {
return dirPath.startsWith("/") ? dirPath : `/mock/path/${dirPath}`
}
/**
* Mock function to check if paths are equal without importing path module
* Provides simple equality comparison for testing
*
* @param path1 - First path to compare
* @param path2 - Second path to compare
* @returns Whether paths are equal
*/
const mockArePathsEqual = (path1: string, path2: string): boolean => {
return path1 === path2
}
/**
* Mock implementation of listFiles function
* Returns different results based on input path for testing different scenarios
@ -42,7 +30,7 @@ const mockArePathsEqual = (path1: string, path2: string): boolean => {
* @param limit - Maximum number of files to return
* @returns Promise resolving to [file paths, limit reached flag]
*/
export const listFiles = jest.fn((dirPath: string, recursive: boolean, limit: number) => {
export const listFiles = jest.fn((dirPath: string, _recursive: boolean, _limit: number) => {
// Special case: Root or home directories
// Prevents tests from trying to list all files in these directories
if (dirPath === "/" || dirPath === "/root" || dirPath === "/home/user") {

View file

@ -1,5 +1,5 @@
import { Client } from "@modelcontextprotocol/sdk/client/index.js"
import { StdioClientTransport, StdioServerParameters } from "@modelcontextprotocol/sdk/client/stdio.js"
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js"
import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js"
import ReconnectingEventSource from "reconnecting-eventsource"
import {
@ -205,11 +205,7 @@ export class McpHub {
* @param error The error object
*/
private showErrorMessage(message: string, error: unknown): void {
const errorMessage = error instanceof Error ? error.message : `${error}`
console.error(`${message}:`, error)
// if (vscode.window && typeof vscode.window.showErrorMessage === 'function') {
// vscode.window.showErrorMessage(`${message}: ${errorMessage}`)
// }
}
public setupWorkspaceFoldersWatcher(): void {

View file

@ -37,7 +37,6 @@ describe("McpHub", () => {
// Store original console methods
const originalConsoleError = console.error
const mockSettingsPath = "/mock/settings/path/mcp_settings.json"
beforeEach(() => {
jest.clearAllMocks()

View file

@ -1,8 +1,9 @@
import * as vscode from "vscode"
import * as childProcess from "child_process"
import * as path from "path"
import * as fs from "fs"
import * as readline from "readline"
import * as vscode from "vscode"
import { RooIgnoreController } from "../../core/ignore/RooIgnoreController"
import { fileExistsAtPath } from "../../utils/fs"
/*
@ -160,7 +161,6 @@ export async function regexSearchFiles(
}
const results: SearchFileResult[] = []
let currentResult: Partial<SearchResult> | null = null
let currentFile: SearchFileResult | null = null
output.split("\n").forEach((line) => {

View file

@ -28,8 +28,6 @@ export async function initializeTreeSitter() {
}
const TreeSitter = await initializeWorkingParser()
const wasmPath = path.join(process.cwd(), "dist/tree-sitter-tsx.wasm")
const tsxLang = await TreeSitter.Language.load(wasmPath)
initializedTreeSitter = TreeSitter
return TreeSitter
@ -68,7 +66,6 @@ export async function testParseSourceCodeDefinitions(
} = {},
): Promise<string | undefined> {
// Set default options
const language = options.language || "tsx"
const wasmFile = options.wasmFile || "tree-sitter-tsx.wasm"
const queryString = options.queryString || tsxQuery
const extKey = options.extKey || "tsx"

View file

@ -1,9 +1,9 @@
import * as fs from "fs/promises"
import { parseSourceCodeForDefinitionsTopLevel } from "../index"
import { listFiles } from "../../glob/list-files"
import { loadRequiredLanguageParsers } from "../languageParser"
import { fileExistsAtPath } from "../../../utils/fs"
import * as fs from "fs/promises"
import * as path from "path"
// Mock dependencies
jest.mock("../../glob/list-files")

View file

@ -1,6 +1,7 @@
import { describe, expect, it, jest, beforeEach } from "@jest/globals"
import * as fs from "fs/promises"
import * as path from "path"
import { describe, expect, it, jest, beforeEach } from "@jest/globals"
import { parseSourceCodeDefinitionsForFile } from "../index"
// Mock fs.readFile

View file

@ -1,12 +1,7 @@
import { describe, expect, it, jest, beforeEach } from "@jest/globals"
import { parseSourceCodeDefinitionsForFile } from ".."
import * as fs from "fs/promises"
import * as path from "path"
import Parser from "web-tree-sitter"
import { fileExistsAtPath } from "../../../utils/fs"
import { loadRequiredLanguageParsers } from "../languageParser"
import { cppQuery } from "../queries"
import { initializeTreeSitter, testParseSourceCodeDefinitions, inspectTreeStructure, debugLog } from "./helpers"
import { testParseSourceCodeDefinitions } from "./helpers"
// Sample C++ content for tests covering all supported structures:
// - struct declarations
@ -516,7 +511,6 @@ const cppOptions = {
// Mock file system operations
jest.mock("fs/promises")
const mockedFs = jest.mocked(fs)
// Mock loadRequiredLanguageParsers
jest.mock("../languageParser", () => ({
@ -654,12 +648,10 @@ describe("parseSourceCodeDefinitionsForFile with C++", () => {
})
it("should parse C++ using declarations and aliases", async () => {
const result = await testParseSourceCodeDefinitions("/test/file.cpp", sampleCppContent, cppOptions)
const resultLines = result?.split("\n") || []
// const result = await testParseSourceCodeDefinitions("/test/file.cpp", sampleCppContent, cppOptions)
// const resultLines = result?.split("\n") || []
// Test using declarations - not supported by current parser
// expect(resultLines.some((line) => line.includes("using std::string"))).toBe(true)
// Test using directives - not supported by current parser
// expect(resultLines.some((line) => line.includes("using namespace std"))).toBe(true)
// Test alias declarations - not supported by current parser
@ -683,12 +675,10 @@ describe("parseSourceCodeDefinitionsForFile with C++", () => {
})
it("should parse C++ attributes and macros", async () => {
const result = await testParseSourceCodeDefinitions("/test/file.cpp", sampleCppContent, cppOptions)
const resultLines = result?.split("\n") || []
// const result = await testParseSourceCodeDefinitions("/test/file.cpp", sampleCppContent, cppOptions)
// const resultLines = result?.split("\n") || []
// Test attributes - not supported by current parser
// expect(resultLines.some((line) => line.includes("[[nodiscard]]") || line.includes("attribute_declaration"))).toBe(true)
// Test macro definitions - not supported by current parser
// expect(resultLines.some((line) => line.includes("#define SQUARE"))).toBe(true)
})
@ -721,12 +711,10 @@ describe("parseSourceCodeDefinitionsForFile with C++", () => {
})
it("should parse C++ inline functions and variables", async () => {
const result = await testParseSourceCodeDefinitions("/test/file.cpp", sampleCppContent, cppOptions)
const resultLines = result?.split("\n") || []
// const result = await testParseSourceCodeDefinitions("/test/file.cpp", sampleCppContent, cppOptions)
// const resultLines = result?.split("\n") || []
// Test inline functions - not supported by current parser
// expect(resultLines.some((line) => line.includes("inline double square"))).toBe(true)
// Test inline variables - not supported by current parser
// expect(resultLines.some((line) => line.includes("inline constexpr double PI"))).toBe(true)
})

View file

@ -1,12 +1,7 @@
import { describe, expect, it, jest, beforeEach } from "@jest/globals"
import { parseSourceCodeDefinitionsForFile } from ".."
import * as fs from "fs/promises"
import * as path from "path"
import Parser from "web-tree-sitter"
import { fileExistsAtPath } from "../../../utils/fs"
import { loadRequiredLanguageParsers } from "../languageParser"
import { goQuery } from "../queries"
import { initializeTreeSitter, testParseSourceCodeDefinitions, inspectTreeStructure, debugLog } from "./helpers"
import { testParseSourceCodeDefinitions } from "./helpers"
// Sample Go content for tests covering all supported structures:
// - function declarations (with associated comments)
@ -260,7 +255,6 @@ const goOptions = {
// Mock file system operations
jest.mock("fs/promises")
const mockedFs = jest.mocked(fs)
// Mock loadRequiredLanguageParsers
jest.mock("../languageParser", () => ({
@ -279,7 +273,6 @@ describe("parseSourceCodeDefinitionsForFile with Go", () => {
it("should parse Go struct definitions", async () => {
const result = await testParseSourceCodeDefinitions("/test/file.go", sampleGoContent, goOptions)
const resultLines = result?.split("\n") || []
// Check for struct definitions - we only check for the ones that are actually captured
expect(result).toContain("type Point struct")
@ -289,7 +282,6 @@ describe("parseSourceCodeDefinitionsForFile with Go", () => {
it("should parse Go method declarations", async () => {
const result = await testParseSourceCodeDefinitions("/test/file.go", sampleGoContent, goOptions)
const resultLines = result?.split("\n") || []
// Check for method declarations - we only check for the ones that are actually captured
expect(result).toContain("func (p *Point) Move")
@ -298,7 +290,6 @@ describe("parseSourceCodeDefinitionsForFile with Go", () => {
it("should parse Go function declarations", async () => {
const result = await testParseSourceCodeDefinitions("/test/file.go", sampleGoContent, goOptions)
const resultLines = result?.split("\n") || []
// Check for function declarations - we only check for the ones that are actually captured
expect(result).toContain("func CalculateDistance")
@ -308,7 +299,6 @@ describe("parseSourceCodeDefinitionsForFile with Go", () => {
it("should parse Go interface definitions", async () => {
const result = await testParseSourceCodeDefinitions("/test/file.go", sampleGoContent, goOptions)
const resultLines = result?.split("\n") || []
// Check for interface definitions - we only check for the ones that are actually captured
expect(result).toContain("type Shape interface")
@ -327,8 +317,7 @@ describe("parseSourceCodeDefinitionsForFile with Go", () => {
})
it("should parse Go type aliases", async () => {
const result = await testParseSourceCodeDefinitions("/test/file.go", sampleGoContent, goOptions)
const resultLines = result?.split("\n") || []
await testParseSourceCodeDefinitions("/test/file.go", sampleGoContent, goOptions)
// Note: Type aliases might not be captured due to Tree-Sitter parser limitations
// This test is kept for completeness
@ -336,9 +325,7 @@ describe("parseSourceCodeDefinitionsForFile with Go", () => {
})
it("should parse Go embedded structs and interfaces", async () => {
const result = await testParseSourceCodeDefinitions("/test/file.go", sampleGoContent, goOptions)
const resultLines = result?.split("\n") || []
await testParseSourceCodeDefinitions("/test/file.go", sampleGoContent, goOptions)
// Note: Embedded structs and interfaces might not be captured due to Tree-Sitter parser limitations
// This test is kept for completeness
expect(true).toBe(true)
@ -346,7 +333,6 @@ describe("parseSourceCodeDefinitionsForFile with Go", () => {
it("should parse Go init functions", async () => {
const result = await testParseSourceCodeDefinitions("/test/file.go", sampleGoContent, goOptions)
const resultLines = result?.split("\n") || []
// Check for init functions
expect(result).toContain("func init")

View file

@ -1,12 +1,7 @@
import { describe, expect, it, jest, beforeEach } from "@jest/globals"
import { parseSourceCodeDefinitionsForFile } from ".."
import * as fs from "fs/promises"
import * as path from "path"
import Parser from "web-tree-sitter"
import { fileExistsAtPath } from "../../../utils/fs"
import { loadRequiredLanguageParsers } from "../languageParser"
import { javaQuery } from "../queries"
import { initializeTreeSitter, testParseSourceCodeDefinitions, inspectTreeStructure, debugLog } from "./helpers"
import { testParseSourceCodeDefinitions } from "./helpers"
// Sample Java content for tests covering all supported structures:
// - class declarations (including inner and anonymous classes)
@ -309,7 +304,6 @@ const javaOptions = {
// Mock file system operations
jest.mock("fs/promises")
const mockedFs = jest.mocked(fs)
// Mock loadRequiredLanguageParsers
jest.mock("../languageParser", () => ({

View file

@ -1,11 +1,10 @@
import { describe, expect, it, jest, beforeEach } from "@jest/globals"
import { parseSourceCodeDefinitionsForFile } from ".."
import * as fs from "fs/promises"
import * as path from "path"
import { fileExistsAtPath } from "../../../utils/fs"
import { loadRequiredLanguageParsers } from "../languageParser"
import { describe, expect, it, jest, beforeEach } from "@jest/globals"
import { javascriptQuery } from "../queries"
import { initializeTreeSitter, testParseSourceCodeDefinitions, inspectTreeStructure, debugLog } from "./helpers"
import { initializeTreeSitter, testParseSourceCodeDefinitions, debugLog } from "./helpers"
// Sample JSON content for tests
const sampleJsonContent = `{
@ -68,9 +67,6 @@ describe("jsonParserDebug", () => {
parser.setLanguage(jsLang)
const tree = parser.parse(sampleJsonContent)
// Extract definitions using JavaScript query
const query = jsLang.query(javascriptQuery)
expect(tree).toBeDefined()
})

View file

@ -1,12 +1,7 @@
import { describe, expect, it, jest, beforeEach } from "@jest/globals"
import { parseSourceCodeDefinitionsForFile } from ".."
import * as fs from "fs/promises"
import * as path from "path"
import Parser from "web-tree-sitter"
import { fileExistsAtPath } from "../../../utils/fs"
import { loadRequiredLanguageParsers } from "../languageParser"
import { pythonQuery } from "../queries"
import { initializeTreeSitter, testParseSourceCodeDefinitions, inspectTreeStructure, debugLog } from "./helpers"
import { testParseSourceCodeDefinitions } from "./helpers"
// Sample Python content for tests covering all supported structures:
// - class definitions
@ -355,7 +350,6 @@ const pythonOptions = {
// Mock file system operations
jest.mock("fs/promises")
const mockedFs = jest.mocked(fs)
// Mock loadRequiredLanguageParsers
jest.mock("../languageParser", () => ({
@ -374,7 +368,6 @@ describe("parseSourceCodeDefinitionsForFile with Python", () => {
it("should parse Python class definitions", async () => {
const result = await testParseSourceCodeDefinitions("/test/file.py", samplePythonContent, pythonOptions)
const resultLines = result?.split("\n") || []
// Check for class definitions
expect(result).toContain("class Point")
@ -386,7 +379,6 @@ describe("parseSourceCodeDefinitionsForFile with Python", () => {
it("should parse Python function definitions", async () => {
const result = await testParseSourceCodeDefinitions("/test/file.py", samplePythonContent, pythonOptions)
const resultLines = result?.split("\n") || []
// Check for function definitions
expect(result).toContain("def calculate_average")

View file

@ -1,12 +1,7 @@
import { describe, expect, it, jest, beforeEach } from "@jest/globals"
import { parseSourceCodeDefinitionsForFile } from ".."
import * as fs from "fs/promises"
import * as path from "path"
import Parser from "web-tree-sitter"
import { fileExistsAtPath } from "../../../utils/fs"
import { loadRequiredLanguageParsers } from "../languageParser"
import { rustQuery } from "../queries"
import { initializeTreeSitter, testParseSourceCodeDefinitions, inspectTreeStructure, debugLog } from "./helpers"
import { testParseSourceCodeDefinitions } from "./helpers"
// Sample Rust content for tests covering all supported structures:
// - struct definitions
@ -318,7 +313,6 @@ const rustOptions = {
// Mock file system operations
jest.mock("fs/promises")
const mockedFs = jest.mocked(fs)
// Mock loadRequiredLanguageParsers
jest.mock("../languageParser", () => ({

View file

@ -1,11 +1,11 @@
import { describe, expect, it, jest, beforeEach, beforeAll } from "@jest/globals"
import { parseSourceCodeDefinitionsForFile } from ".."
// npx jest src/services/tree-sitter/__tests__/parseSourceCodeDefinitions.tsx.test.ts
import * as fs from "fs/promises"
import * as path from "path"
import { fileExistsAtPath } from "../../../utils/fs"
import { loadRequiredLanguageParsers } from "../languageParser"
import tsxQuery from "../queries/tsx"
import { initializeTreeSitter, testParseSourceCodeDefinitions, inspectTreeStructure, debugLog } from "./helpers"
import { describe, expect, it, jest, beforeEach } from "@jest/globals"
import { initializeTreeSitter, testParseSourceCodeDefinitions, debugLog } from "./helpers"
// Sample component content with enhanced TypeScript language constructs
const sampleTsxContent = `
@ -338,9 +338,6 @@ describe("treeParserDebug", () => {
const tree = parser.parse(sampleCode)
// console.log("Parsed tree:", tree.rootNode.toString())
// Extract definitions using TSX query
const query = tsxLang.query(tsxQuery)
expect(tree).toBeDefined()
})
@ -571,7 +568,6 @@ it("should parse conditional types", async function () {
// Save the initial line count to compare later
const initialLineCount = initialResult ? initialResult.split("\n").length : 0
const initialCaptures = initialResult ? initialResult : ""
// Now check if the new query pattern improves the output
const updatedResult = await testParseSourceCodeDefinitions("/test/conditional-type.tsx", conditionalTypeContent)

View file

@ -3,7 +3,7 @@ import * as path from "path"
import { listFiles } from "../glob/list-files"
import { LanguageParser, loadRequiredLanguageParsers } from "./languageParser"
import { fileExistsAtPath } from "../../utils/fs"
import { parseMarkdown, formatMarkdownCaptures } from "./markdownParser"
import { parseMarkdown } from "./markdownParser"
import { RooIgnoreController } from "../../core/ignore/RooIgnoreController"
const extensions = [
@ -109,7 +109,7 @@ export async function parseSourceCodeForDefinitionsTopLevel(
let result = ""
// Separate files to parse and remaining files
const { filesToParse, remainingFiles } = separateFiles(allFiles)
const { filesToParse } = separateFiles(allFiles)
// Filter filepaths for access if controller is provided
const allowedFilesToParse = rooIgnoreController ? rooIgnoreController.filterPaths(filesToParse) : filesToParse
@ -227,9 +227,6 @@ function processCaptures(captures: any[], lines: string[], minComponentLines: nu
// Sort captures by their start position
captures.sort((a, b) => a.node.startPosition.row - b.node.startPosition.row)
// Keep track of the last line we've processed
let lastLine = -1
// Track already processed lines to avoid duplicates
const processedLines = new Set<string>()
@ -300,13 +297,12 @@ function processCaptures(captures: any[], lines: string[], minComponentLines: nu
}
}
}
lastLine = endLine
})
if (formattedOutput.length > 0) {
return formattedOutput
}
return null
}

View file

@ -1,4 +1,4 @@
import { stringifyVsCodeLmModelSelector, SELECTOR_SEPARATOR } from "../vsCodeSelectorUtils"
import { stringifyVsCodeLmModelSelector } from "../vsCodeSelectorUtils"
import { LanguageModelChatSelector } from "vscode"
describe("vsCodeSelectorUtils", () => {

View file

@ -1,7 +1,8 @@
import { jest } from "@jest/globals"
import { searchCommits, getCommitInfo, getWorkingState, GitCommit } from "../git"
import { ExecException } from "child_process"
import { searchCommits, getCommitInfo, getWorkingState } from "../git"
type ExecFunction = (
command: string,
options: { cwd?: string },

View file

@ -142,7 +142,7 @@ export class CompactLogger implements ILogger {
l: level,
m: message,
c: meta?.ctx,
d: meta ? (({ ctx, ...rest }) => (Object.keys(rest).length > 0 ? rest : undefined))(meta) : undefined,
d: meta ? (({ ctx: _, ...rest }) => (Object.keys(rest).length > 0 ? rest : undefined))(meta) : undefined,
}
this.transport.write(entry)

View file

@ -4,8 +4,7 @@
"private": true,
"type": "module",
"scripts": {
"lint": "eslint src/**/*.ts src/**/*.tsx",
"lint-fix": "eslint src/**/*.ts src/**/*.tsx --fix",
"lint": "eslint src --ext .ts,.tsx",
"check-types": "tsc",
"test": "jest -w=40%",
"dev": "vite",

View file

@ -94,11 +94,12 @@ const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
// Close dropdown when clicking outside.
useEffect(() => {
const handleClickOutside = (event: MouseEvent) => {
const handleClickOutside = () => {
if (showDropdown) {
setShowDropdown(false)
}
}
document.addEventListener("mousedown", handleClickOutside)
return () => document.removeEventListener("mousedown", handleClickOutside)
}, [showDropdown])

View file

@ -33,7 +33,6 @@ const ContextMenu: React.FC<ContextMenuProps> = ({
selectedType,
queryItems,
modes,
loading = false,
dynamicSearchResults = [],
}) => {
const [materialIconsBaseUri, setMaterialIconsBaseUri] = useState("")

View file

@ -360,7 +360,7 @@ describe("ChatTextArea", () => {
const outsidePath = "/Users/other/project/file.js"
// Mock the convertToMentionPath function to return the original path for paths outside cwd
mockConvertToMentionPath.mockImplementationOnce((path, cwd) => {
mockConvertToMentionPath.mockImplementationOnce((path, _cwd) => {
return path // Return original path for this test
})

View file

@ -100,7 +100,7 @@ const StyledPre = styled.pre<{ theme: any }>`
${(props) =>
Object.keys(props.theme)
.map((key, index) => {
.map((key) => {
return `
& ${key} {
color: ${props.theme[key]};
@ -135,7 +135,7 @@ const CodeBlock = memo(({ source, forceWrap = false }: CodeBlockProps) => {
],
rehypeReactOptions: {
components: {
pre: ({ node, ...preProps }: any) => <StyledPre {...preProps} theme={theme} />,
pre: ({ node: _, ...preProps }: any) => <StyledPre {...preProps} theme={theme} />,
},
},
})

View file

@ -160,7 +160,7 @@ const StyledPre = styled.pre<{ theme: any }>`
${(props) =>
Object.keys(props.theme)
.map((key, index) => {
.map((key) => {
return `
& ${key} {
color: ${props.theme[key]};
@ -195,7 +195,7 @@ const MarkdownBlock = memo(({ markdown }: MarkdownBlockProps) => {
],
rehypeReactOptions: {
components: {
pre: ({ node, children, ...preProps }: any) => {
pre: ({ node: _, children, ...preProps }: any) => {
if (Array.isArray(children) && children.length === 1 && React.isValidElement(children[0])) {
const child = children[0] as React.ReactElement<{ className?: string }>
if (child.props?.className?.includes("language-mermaid")) {

View file

@ -316,7 +316,7 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
// Handle clicks outside the config menu
useEffect(() => {
const handleClickOutside = (event: MouseEvent) => {
const handleClickOutside = () => {
if (showConfigMenu) {
setShowConfigMenu(false)
}

View file

@ -57,7 +57,6 @@ export const AutoApproveSettings = ({
alwaysAllowExecute,
allowedCommands,
setCachedStateField,
className,
...props
}: AutoApproveSettingsProps) => {
const { t } = useAppTranslation()

View file

@ -18,7 +18,6 @@ type ExperimentalSettingsProps = HTMLAttributes<HTMLDivElement> & {
}
export const ExperimentalSettings = ({
setCachedStateField,
experiments,
setExperimentEnabled,
className,

View file

@ -1,6 +1,5 @@
// npx jest src/components/settings/__tests__/ApiConfigManager.test.tsx
import React from "react"
import { render, screen, fireEvent, within } from "@testing-library/react"
import ApiConfigManager from "../ApiConfigManager"
@ -21,14 +20,14 @@ jest.mock("@vscode/webview-ui-toolkit/react", () => ({
jest.mock("@/components/ui", () => ({
...jest.requireActual("@/components/ui"),
Dialog: ({ children, open, onOpenChange }: any) => (
Dialog: ({ children, open }: any) => (
<div role="dialog" aria-modal="true" style={{ display: open ? "block" : "none" }} data-testid="dialog">
{children}
</div>
),
DialogContent: ({ children }: any) => <div data-testid="dialog-content">{children}</div>,
DialogTitle: ({ children }: any) => <div data-testid="dialog-title">{children}</div>,
Button: ({ children, onClick, disabled, variant, "data-testid": dataTestId }: any) => (
Button: ({ children, onClick, disabled, "data-testid": dataTestId }: any) => (
<button onClick={onClick} disabled={disabled} data-testid={dataTestId}>
{children}
</button>
@ -43,16 +42,16 @@ jest.mock("@/components/ui", () => ({
/>
),
// New components for searchable dropdown
Popover: ({ children, open, onOpenChange }: any) => (
Popover: ({ children, open }: any) => (
<div className="popover" style={{ position: "relative" }}>
{children}
{open && <div className="popover-content" style={{ position: "absolute", top: "100%", left: 0 }}></div>}
</div>
),
PopoverTrigger: ({ children, asChild }: any) => <div className="popover-trigger">{children}</div>,
PopoverContent: ({ children, className }: any) => <div className="popover-content">{children}</div>,
PopoverTrigger: ({ children }: any) => <div className="popover-trigger">{children}</div>,
PopoverContent: ({ children }: any) => <div className="popover-content">{children}</div>,
Command: ({ children }: any) => <div className="command">{children}</div>,
CommandInput: ({ value, onValueChange, placeholder, className, "data-testid": dataTestId, ref }: any) => (
CommandInput: ({ value, onValueChange, placeholder, className, "data-testid": dataTestId }: any) => (
<input
value={value}
onChange={(e) => onValueChange(e.target.value)}
@ -70,7 +69,7 @@ jest.mock("@/components/ui", () => ({
</div>
),
// Keep old components for backward compatibility
Select: ({ children, value, onValueChange }: any) => (
Select: ({ value, onValueChange }: any) => (
<select
value={value}
onChange={(e) => {

View file

@ -1,4 +1,4 @@
// npx jest webview-ui/src/components/ui/__tests__/select-dropdown.test.tsx
// npx jest src/components/ui/__tests__/select-dropdown.test.tsx
import { ReactNode } from "react"
import { render, screen, fireEvent } from "@testing-library/react"
@ -16,7 +16,6 @@ jest.mock("@/components/ui", () => {
return {
Popover: ({
children,
open,
onOpenChange,
}: {
children: ReactNode
@ -44,10 +43,6 @@ jest.mock("@/components/ui", () => {
PopoverContent: ({
children,
align,
sideOffset,
container,
className,
}: {
children: ReactNode
align?: string

View file

@ -20,7 +20,7 @@ interface ChatMessageProps {
append?: ChatHandler["append"]
}
export function ChatMessage({ message, isLast, isHeaderVisible, isLoading, append }: ChatMessageProps) {
export function ChatMessage({ message, isLast, isHeaderVisible }: ChatMessageProps) {
const badges = useMemo(
() =>
message.annotations