mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-08-28 05:27:24 +00:00
Fix linter errors (#3821)
This commit is contained in:
parent
c6851976fa
commit
39cd50b989
44 changed files with 220 additions and 152 deletions
6
.prettierignore
Normal file
6
.prettierignore
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
dist
|
||||
build
|
||||
out
|
||||
.next
|
||||
.venv
|
||||
pnpm-lock.yaml
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
"name": "@roo-code/vscode-e2e",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"lint": "eslint **/*.ts --max-warnings=0",
|
||||
"lint": "eslint src --ext=ts --max-warnings=0",
|
||||
"check-types": "tsc --noEmit",
|
||||
"format": "prettier --write src",
|
||||
"test:ci": "pnpm --filter roo-cline build:development && pnpm test:run",
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import { type RooCodeAPI, Package } from "@roo-code/types"
|
|||
import { waitFor } from "./utils"
|
||||
|
||||
declare global {
|
||||
var api: RooCodeAPI
|
||||
let api: RooCodeAPI
|
||||
}
|
||||
|
||||
export async function run() {
|
||||
|
|
@ -29,7 +29,7 @@ export async function run() {
|
|||
await vscode.commands.executeCommand(`${Package.name}.SidebarProvider.focus`)
|
||||
await waitFor(() => api.isReady())
|
||||
|
||||
// Expose the API to the tests.
|
||||
// @ts-expect-error - Expose the API to the tests.
|
||||
globalThis.api = api
|
||||
|
||||
// Add all the tests to the runner.
|
||||
|
|
|
|||
|
|
@ -1,12 +1,13 @@
|
|||
import * as assert from "assert"
|
||||
|
||||
import type { ClineMessage } from "@roo-code/types"
|
||||
import type { RooCodeAPI, ClineMessage } from "@roo-code/types"
|
||||
|
||||
import { waitUntilCompleted } from "./utils"
|
||||
|
||||
suite("Roo Code Modes", () => {
|
||||
test("Should handle switching modes correctly", async () => {
|
||||
const api = globalThis.api
|
||||
// @ts-expect-error - Expose the API to the tests.
|
||||
const api = globalThis.api as RooCodeAPI
|
||||
|
||||
/**
|
||||
* Switch modes.
|
||||
|
|
@ -15,7 +16,7 @@ suite("Roo Code Modes", () => {
|
|||
const switchModesPrompt =
|
||||
"For each mode (Architect, Ask, Debug) respond with the mode name and what it specializes in after switching to that mode."
|
||||
|
||||
let messages: ClineMessage[] = []
|
||||
const messages: ClineMessage[] = []
|
||||
|
||||
const modeSwitches: string[] = []
|
||||
|
||||
|
|
|
|||
|
|
@ -1,12 +1,13 @@
|
|||
import * as assert from "assert"
|
||||
|
||||
import type { ClineMessage } from "@roo-code/types"
|
||||
import type { RooCodeAPI, ClineMessage } from "@roo-code/types"
|
||||
|
||||
import { sleep, waitFor, waitUntilCompleted } from "./utils"
|
||||
|
||||
suite.skip("Roo Code Subtasks", () => {
|
||||
test("Should handle subtask cancellation and resumption correctly", async () => {
|
||||
const api = globalThis.api
|
||||
// @ts-expect-error - Expose the API to the tests.
|
||||
const api = globalThis.api as RooCodeAPI
|
||||
|
||||
const messages: Record<string, ClineMessage[]> = {}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,12 +1,13 @@
|
|||
import * as assert from "assert"
|
||||
|
||||
import type { ClineMessage } from "@roo-code/types"
|
||||
import type { RooCodeAPI, ClineMessage } from "@roo-code/types"
|
||||
|
||||
import { waitUntilCompleted } from "./utils"
|
||||
|
||||
suite("Roo Code Task", () => {
|
||||
test("Should handle prompt and response correctly", async () => {
|
||||
const api = globalThis.api
|
||||
// @ts-expect-error - Expose the API to the tests.
|
||||
const api = globalThis.api as RooCodeAPI
|
||||
|
||||
const messages: ClineMessage[] = []
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
"main": "./dist/index.js",
|
||||
"types": "./src/index.ts",
|
||||
"scripts": {
|
||||
"lint": "eslint src/**/*.ts --max-warnings=0",
|
||||
"lint": "eslint src --ext=ts --max-warnings=0",
|
||||
"check-types": "tsc --noEmit",
|
||||
"test": "vitest --globals --run",
|
||||
"build": "tsc",
|
||||
|
|
|
|||
|
|
@ -143,8 +143,8 @@ export function generatePackageJson({
|
|||
overrideJson,
|
||||
substitution,
|
||||
}: {
|
||||
packageJson: Record<string, any>
|
||||
overrideJson: Record<string, any>
|
||||
packageJson: Record<string, any> // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
overrideJson: Record<string, any> // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
substitution: [string, string]
|
||||
}) {
|
||||
const { viewsContainers, views, commands, menus, submenus, configuration } = contributesSchema.parse(contributes)
|
||||
|
|
@ -167,6 +167,7 @@ export function generatePackageJson({
|
|||
}
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
function transformArrayRecord<T>(obj: Record<string, any[]>, from: string, to: string, props: string[]): T {
|
||||
return Object.entries(obj).reduce(
|
||||
(acc, [key, ary]) => ({
|
||||
|
|
@ -187,6 +188,7 @@ function transformArrayRecord<T>(obj: Record<string, any[]>, from: string, to: s
|
|||
)
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
function transformArray<T>(arr: any[], from: string, to: string, idProp: string): T[] {
|
||||
return arr.map(({ [idProp]: id, ...rest }) => ({
|
||||
[idProp]: id.replace(from, to),
|
||||
|
|
@ -194,6 +196,7 @@ function transformArray<T>(arr: any[], from: string, to: string, idProp: string)
|
|||
}))
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
function transformRecord<T>(obj: Record<string, any>, from: string, to: string): T {
|
||||
return Object.entries(obj).reduce(
|
||||
(acc, [key, value]) => ({
|
||||
|
|
|
|||
|
|
@ -1,11 +1,13 @@
|
|||
import { execSync } from "child_process"
|
||||
|
||||
export function getGitSha() {
|
||||
let gitSha = undefined
|
||||
let gitSha: string | undefined = undefined
|
||||
|
||||
try {
|
||||
gitSha = execSync("git rev-parse HEAD").toString().trim()
|
||||
} catch (e) {}
|
||||
} catch (_e) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
return gitSha
|
||||
}
|
||||
|
|
|
|||
3
pnpm-lock.yaml
generated
3
pnpm-lock.yaml
generated
|
|
@ -426,9 +426,6 @@ importers:
|
|||
ovsx:
|
||||
specifier: 0.10.2
|
||||
version: 0.10.2
|
||||
prettier:
|
||||
specifier: ^3.4.2
|
||||
version: 3.5.3
|
||||
rimraf:
|
||||
specifier: ^6.0.1
|
||||
version: 6.0.1
|
||||
|
|
|
|||
|
|
@ -128,7 +128,7 @@ export class AnthropicHandler extends BaseProvider implements SingleCompletionHa
|
|||
|
||||
for await (const chunk of stream) {
|
||||
switch (chunk.type) {
|
||||
case "message_start":
|
||||
case "message_start": {
|
||||
// Tells us cache reads/writes/input/output.
|
||||
const usage = chunk.message.usage
|
||||
|
||||
|
|
@ -141,6 +141,7 @@ export class AnthropicHandler extends BaseProvider implements SingleCompletionHa
|
|||
}
|
||||
|
||||
break
|
||||
}
|
||||
case "message_delta":
|
||||
// Tells us stop_reason, stop_sequence, and output tokens
|
||||
// along the way and at the end of the message.
|
||||
|
|
|
|||
|
|
@ -161,7 +161,10 @@ export class AwsBedrockHandler extends BaseProvider implements SingleCompletionH
|
|||
if (this.arnInfo.awsUseCrossRegionInference) this.options.awsUseCrossRegionInference = true
|
||||
}
|
||||
|
||||
this.options.modelTemperature ?? BEDROCK_DEFAULT_TEMPERATURE
|
||||
if (!this.options.modelTemperature) {
|
||||
this.options.modelTemperature = BEDROCK_DEFAULT_TEMPERATURE
|
||||
}
|
||||
|
||||
this.costModelConfig = this.getModel()
|
||||
|
||||
const clientConfig: BedrockRuntimeClientConfig = {
|
||||
|
|
@ -316,6 +319,7 @@ export class AwsBedrockHandler extends BaseProvider implements SingleCompletionH
|
|||
error: error instanceof Error ? error : String(error),
|
||||
})
|
||||
} finally {
|
||||
// eslint-disable-next-line no-unsafe-finally
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,108 +25,103 @@ export class LmStudioHandler extends BaseProvider implements SingleCompletionHan
|
|||
}
|
||||
|
||||
override async *createMessage(systemPrompt: string, messages: Anthropic.Messages.MessageParam[]): ApiStream {
|
||||
const openAiMessages: OpenAI.Chat.ChatCompletionMessageParam[] = [
|
||||
{ role: "system", content: systemPrompt },
|
||||
...convertToOpenAiMessages(messages),
|
||||
]
|
||||
const openAiMessages: OpenAI.Chat.ChatCompletionMessageParam[] = [
|
||||
{ role: "system", content: systemPrompt },
|
||||
...convertToOpenAiMessages(messages),
|
||||
]
|
||||
|
||||
// -------------------------
|
||||
// Track token usage
|
||||
// -------------------------
|
||||
const toContentBlocks = (
|
||||
blocks: Anthropic.Messages.MessageParam[] | string,
|
||||
): Anthropic.Messages.ContentBlockParam[] => {
|
||||
if (typeof blocks === "string") {
|
||||
return [{ type: "text", text: blocks }]
|
||||
}
|
||||
// -------------------------
|
||||
// Track token usage
|
||||
// -------------------------
|
||||
const toContentBlocks = (
|
||||
blocks: Anthropic.Messages.MessageParam[] | string,
|
||||
): Anthropic.Messages.ContentBlockParam[] => {
|
||||
if (typeof blocks === "string") {
|
||||
return [{ type: "text", text: blocks }]
|
||||
}
|
||||
|
||||
const result: Anthropic.Messages.ContentBlockParam[] = []
|
||||
for (const msg of blocks) {
|
||||
if (typeof msg.content === "string") {
|
||||
result.push({ type: "text", text: msg.content })
|
||||
} else if (Array.isArray(msg.content)) {
|
||||
for (const part of msg.content) {
|
||||
if (part.type === "text") {
|
||||
result.push({ type: "text", text: part.text })
|
||||
const result: Anthropic.Messages.ContentBlockParam[] = []
|
||||
for (const msg of blocks) {
|
||||
if (typeof msg.content === "string") {
|
||||
result.push({ type: "text", text: msg.content })
|
||||
} else if (Array.isArray(msg.content)) {
|
||||
for (const part of msg.content) {
|
||||
if (part.type === "text") {
|
||||
result.push({ type: "text", text: part.text })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
let inputTokens = 0
|
||||
try {
|
||||
inputTokens = await this.countTokens([
|
||||
{ type: "text", text: systemPrompt },
|
||||
...toContentBlocks(messages),
|
||||
])
|
||||
} catch (err) {
|
||||
console.error("[LmStudio] Failed to count input tokens:", err)
|
||||
inputTokens = 0
|
||||
}
|
||||
|
||||
let assistantText = ""
|
||||
|
||||
try {
|
||||
const params: OpenAI.Chat.ChatCompletionCreateParamsStreaming & { draft_model?: string } = {
|
||||
model: this.getModel().id,
|
||||
messages: openAiMessages,
|
||||
temperature: this.options.modelTemperature ?? LMSTUDIO_DEFAULT_TEMPERATURE,
|
||||
stream: true,
|
||||
return result
|
||||
}
|
||||
|
||||
if (this.options.lmStudioSpeculativeDecodingEnabled && this.options.lmStudioDraftModelId) {
|
||||
params.draft_model = this.options.lmStudioDraftModelId
|
||||
let inputTokens = 0
|
||||
try {
|
||||
inputTokens = await this.countTokens([{ type: "text", text: systemPrompt }, ...toContentBlocks(messages)])
|
||||
} catch (err) {
|
||||
console.error("[LmStudio] Failed to count input tokens:", err)
|
||||
inputTokens = 0
|
||||
}
|
||||
|
||||
const results = await this.client.chat.completions.create(params)
|
||||
let assistantText = ""
|
||||
|
||||
const matcher = new XmlMatcher(
|
||||
"think",
|
||||
(chunk) =>
|
||||
({
|
||||
type: chunk.matched ? "reasoning" : "text",
|
||||
text: chunk.data,
|
||||
}) as const,
|
||||
)
|
||||
try {
|
||||
const params: OpenAI.Chat.ChatCompletionCreateParamsStreaming & { draft_model?: string } = {
|
||||
model: this.getModel().id,
|
||||
messages: openAiMessages,
|
||||
temperature: this.options.modelTemperature ?? LMSTUDIO_DEFAULT_TEMPERATURE,
|
||||
stream: true,
|
||||
}
|
||||
|
||||
for await (const chunk of results) {
|
||||
const delta = chunk.choices[0]?.delta
|
||||
if (this.options.lmStudioSpeculativeDecodingEnabled && this.options.lmStudioDraftModelId) {
|
||||
params.draft_model = this.options.lmStudioDraftModelId
|
||||
}
|
||||
|
||||
if (delta?.content) {
|
||||
assistantText += delta.content
|
||||
for (const processedChunk of matcher.update(delta.content)) {
|
||||
yield processedChunk
|
||||
const results = await this.client.chat.completions.create(params)
|
||||
|
||||
const matcher = new XmlMatcher(
|
||||
"think",
|
||||
(chunk) =>
|
||||
({
|
||||
type: chunk.matched ? "reasoning" : "text",
|
||||
text: chunk.data,
|
||||
}) as const,
|
||||
)
|
||||
|
||||
for await (const chunk of results) {
|
||||
const delta = chunk.choices[0]?.delta
|
||||
|
||||
if (delta?.content) {
|
||||
assistantText += delta.content
|
||||
for (const processedChunk of matcher.update(delta.content)) {
|
||||
yield processedChunk
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const processedChunk of matcher.final()) {
|
||||
yield processedChunk
|
||||
}
|
||||
for (const processedChunk of matcher.final()) {
|
||||
yield processedChunk
|
||||
}
|
||||
|
||||
|
||||
let outputTokens = 0
|
||||
try {
|
||||
outputTokens = await this.countTokens([{ type: "text", text: assistantText }])
|
||||
} catch (err) {
|
||||
console.error("[LmStudio] Failed to count output tokens:", err)
|
||||
outputTokens = 0
|
||||
}
|
||||
let outputTokens = 0
|
||||
try {
|
||||
outputTokens = await this.countTokens([{ type: "text", text: assistantText }])
|
||||
} catch (err) {
|
||||
console.error("[LmStudio] Failed to count output tokens:", err)
|
||||
outputTokens = 0
|
||||
}
|
||||
|
||||
yield {
|
||||
type: "usage",
|
||||
inputTokens,
|
||||
outputTokens,
|
||||
} as const
|
||||
} catch (error) {
|
||||
throw new Error(
|
||||
"Please check the LM Studio developer logs to debug what went wrong. You may need to load the model with a larger context length to work with Roo Code's prompts.",
|
||||
)
|
||||
yield {
|
||||
type: "usage",
|
||||
inputTokens,
|
||||
outputTokens,
|
||||
} as const
|
||||
} catch (error) {
|
||||
throw new Error(
|
||||
"Please check the LM Studio developer logs to debug what went wrong. You may need to load the model with a larger context length to work with Roo Code's prompts.",
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override getModel(): { id: string; info: ModelInfo } {
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import { DEFAULT_HEADERS, DEEP_SEEK_DEFAULT_TEMPERATURE } from "./constants"
|
|||
|
||||
export const AZURE_AI_INFERENCE_PATH = "/models/chat/completions"
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
||||
export interface OpenAiHandlerOptions extends ApiHandlerOptions {}
|
||||
|
||||
export class OpenAiHandler extends BaseProvider implements SingleCompletionHandler {
|
||||
|
|
|
|||
|
|
@ -99,9 +99,11 @@ export class OpenRouterHandler extends BaseProvider implements SingleCompletionH
|
|||
|
||||
// https://openrouter.ai/docs/features/prompt-caching
|
||||
if (isCacheAvailable) {
|
||||
modelId.startsWith("google")
|
||||
? addGeminiCacheBreakpoints(systemPrompt, openAiMessages)
|
||||
: addAnthropicCacheBreakpoints(systemPrompt, openAiMessages)
|
||||
if (modelId.startsWith("google")) {
|
||||
addGeminiCacheBreakpoints(systemPrompt, openAiMessages)
|
||||
} else {
|
||||
addAnthropicCacheBreakpoints(systemPrompt, openAiMessages)
|
||||
}
|
||||
}
|
||||
|
||||
// https://openrouter.ai/docs/transforms
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
/* eslint-disable @typescript-eslint/no-unsafe-function-type */
|
||||
|
||||
// node --expose-gc --import tsx src/core/assistant-message/__tests__/parseAssistantMessageBenchmark.ts
|
||||
|
||||
import { performance } from "perf_hooks"
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
/* eslint-disable no-irregular-whitespace */
|
||||
|
||||
import { distance } from "fastest-levenshtein"
|
||||
|
||||
import { addLineNumbers, everyLineHasLineNumbers, stripLineNumbers } from "../../../integrations/misc/extract-text"
|
||||
|
|
|
|||
|
|
@ -1212,7 +1212,7 @@ export class Task extends EventEmitter<ClineEvents> {
|
|||
cacheReadTokens += chunk.cacheReadTokens ?? 0
|
||||
totalCost = chunk.totalCost
|
||||
break
|
||||
case "text":
|
||||
case "text": {
|
||||
assistantMessage += chunk.text
|
||||
|
||||
// Parse raw assistant message into content blocks.
|
||||
|
|
@ -1228,6 +1228,7 @@ export class Task extends EventEmitter<ClineEvents> {
|
|||
// Present content to user.
|
||||
presentAssistantMessage(this)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (this.abort) {
|
||||
|
|
|
|||
|
|
@ -548,6 +548,7 @@ describe("Cline", () => {
|
|||
// Create a stream that fails on first chunk
|
||||
const mockError = new Error("API Error")
|
||||
const mockFailedStream = {
|
||||
// eslint-disable-next-line require-yield
|
||||
async *[Symbol.asyncIterator]() {
|
||||
throw mockError
|
||||
},
|
||||
|
|
@ -672,6 +673,7 @@ describe("Cline", () => {
|
|||
// Create a stream that fails on first chunk
|
||||
const mockError = new Error("API Error")
|
||||
const mockFailedStream = {
|
||||
// eslint-disable-next-line require-yield
|
||||
async *[Symbol.asyncIterator]() {
|
||||
throw mockError
|
||||
},
|
||||
|
|
|
|||
|
|
@ -144,7 +144,7 @@ export class ClineProvider extends EventEmitter<ClineProviderEvents> implements
|
|||
}
|
||||
|
||||
// Pop the top Cline instance from the stack.
|
||||
var cline = this.clineStack.pop()
|
||||
let cline = this.clineStack.pop()
|
||||
|
||||
if (cline) {
|
||||
console.log(`[subtasks] removing task ${cline.taskId}.${cline.instanceId} from stack`)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
import * as esbuild from "esbuild"
|
||||
import * as path from "path"
|
||||
import { fileURLToPath } from "url"
|
||||
import process from "node:process"
|
||||
import * as console from "node:console"
|
||||
|
||||
import { copyPaths, copyWasms, copyLocales, setupLocaleWatcher } from "@roo-code/build"
|
||||
|
||||
|
|
|
|||
|
|
@ -5,26 +5,31 @@ export default [
|
|||
...config,
|
||||
{
|
||||
rules: {
|
||||
// TODO: These should be fixed and the rules re-enabled.
|
||||
"no-regex-spaces": "off",
|
||||
"no-useless-escape": "off",
|
||||
"no-empty": "off",
|
||||
"prefer-const": "off",
|
||||
|
||||
"@typescript-eslint/no-unused-vars": "off",
|
||||
"@typescript-eslint/no-explicit-any": "off",
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ["i18n/setup.ts", "utils/tts.ts"],
|
||||
rules: {
|
||||
"@typescript-eslint/no-require-imports": "off",
|
||||
"@typescript-eslint/ban-ts-comment": "off",
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ["shared/support-prompt.ts"],
|
||||
files: ["core/assistant-message/presentAssistantMessage.ts", "core/webview/webviewMessageHandler.ts"],
|
||||
rules: {
|
||||
"no-prototype-builtins": "off",
|
||||
"no-case-declarations": "off",
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ["shared/combineApiRequests.ts", "utils/tts.ts"],
|
||||
files: ["__mocks__/**/*.js"],
|
||||
rules: {
|
||||
"no-empty": "off",
|
||||
"no-undef": "off",
|
||||
},
|
||||
},
|
||||
{
|
||||
ignores: ["webview-ui", "out"],
|
||||
},
|
||||
]
|
||||
|
|
|
|||
|
|
@ -303,22 +303,23 @@ export class DiffViewProvider {
|
|||
|
||||
private async closeAllDiffViews(): Promise<void> {
|
||||
const closeOps = vscode.window.tabGroups.all
|
||||
.flatMap(group => group.tabs)
|
||||
.filter(
|
||||
tab =>
|
||||
tab.input instanceof vscode.TabInputTextDiff &&
|
||||
tab.input.original.scheme === DIFF_VIEW_URI_SCHEME &&
|
||||
!tab.isDirty
|
||||
)
|
||||
.map(tab =>
|
||||
vscode.window.tabGroups.close(tab).then(
|
||||
() => undefined,
|
||||
err => {
|
||||
console.error(`Failed to close diff tab ${tab.label}`, err);
|
||||
}
|
||||
));
|
||||
|
||||
await Promise.all(closeOps);
|
||||
.flatMap((group) => group.tabs)
|
||||
.filter(
|
||||
(tab) =>
|
||||
tab.input instanceof vscode.TabInputTextDiff &&
|
||||
tab.input.original.scheme === DIFF_VIEW_URI_SCHEME &&
|
||||
!tab.isDirty,
|
||||
)
|
||||
.map((tab) =>
|
||||
vscode.window.tabGroups.close(tab).then(
|
||||
() => undefined,
|
||||
(err) => {
|
||||
console.error(`Failed to close diff tab ${tab.label}`, err)
|
||||
},
|
||||
),
|
||||
)
|
||||
|
||||
await Promise.all(closeOps)
|
||||
}
|
||||
|
||||
private async openDiffEditor(): Promise<vscode.TextEditor> {
|
||||
|
|
@ -425,7 +426,7 @@ export class DiffViewProvider {
|
|||
return result
|
||||
}
|
||||
|
||||
async reset() : Promise<void> {
|
||||
async reset(): Promise<void> {
|
||||
await this.closeAllDiffViews()
|
||||
this.editType = undefined
|
||||
this.isEditing = false
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ export function formatContentBlockToMarkdown(block: Anthropic.Messages.ContentBl
|
|||
return block.text
|
||||
case "image":
|
||||
return `[Image]`
|
||||
case "tool_use":
|
||||
case "tool_use": {
|
||||
let input: string
|
||||
if (typeof block.input === "object" && block.input !== null) {
|
||||
input = Object.entries(block.input)
|
||||
|
|
@ -57,7 +57,8 @@ export function formatContentBlockToMarkdown(block: Anthropic.Messages.ContentBl
|
|||
input = String(block.input)
|
||||
}
|
||||
return `[Tool Use: ${block.name}]\n${input}`
|
||||
case "tool_result":
|
||||
}
|
||||
case "tool_result": {
|
||||
// For now we're not doing tool name lookup since we don't use tools anymore
|
||||
// const toolName = findToolName(block.tool_use_id, messages)
|
||||
const toolName = "Tool"
|
||||
|
|
@ -70,6 +71,7 @@ export function formatContentBlockToMarkdown(block: Anthropic.Messages.ContentBl
|
|||
} else {
|
||||
return `[${toolName}${block.is_error ? " (Error)" : ""}]`
|
||||
}
|
||||
}
|
||||
default:
|
||||
return "[Unexpected content type]"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,9 @@ export async function extractTextFromFile(filePath: string): Promise<string> {
|
|||
} catch (error) {
|
||||
throw new Error(`File not found: ${filePath}`)
|
||||
}
|
||||
|
||||
const fileExtension = path.extname(filePath).toLowerCase()
|
||||
|
||||
switch (fileExtension) {
|
||||
case ".pdf":
|
||||
return extractTextFromPDF(filePath)
|
||||
|
|
@ -19,13 +21,15 @@ export async function extractTextFromFile(filePath: string): Promise<string> {
|
|||
return extractTextFromDOCX(filePath)
|
||||
case ".ipynb":
|
||||
return extractTextFromIPYNB(filePath)
|
||||
default:
|
||||
default: {
|
||||
const isBinary = await isBinaryFile(filePath).catch(() => false)
|
||||
|
||||
if (!isBinary) {
|
||||
return addLineNumbers(await fs.readFile(filePath, "utf8"))
|
||||
} else {
|
||||
throw new Error(`Cannot read text for file type: ${fileExtension}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -392,6 +392,7 @@ export class TerminalProcess extends BaseTerminalProcess {
|
|||
// should be carefully considered to ensure they only remove control codes and don't
|
||||
// alter the actual content or behavior of the output stream.
|
||||
private removeEscapeSequences(str: string): string {
|
||||
// eslint-disable-next-line no-control-regex
|
||||
return stripAnsi(str.replace(/\x1b\]633;[^\x07]+\x07/gs, "").replace(/\x1b\]133;[^\x07]+\x07/gs, ""))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ const hasPwsh = isPowerShellCoreAvailable()
|
|||
|
||||
// Define interface for global test environment
|
||||
declare global {
|
||||
// eslint-disable-next-line @typescript-eslint/no-namespace
|
||||
namespace NodeJS {
|
||||
interface Global {
|
||||
__TEST_ENV__: {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
import process from "node:process"
|
||||
|
||||
/** @type {import('ts-jest').JestConfigWithTsJest} */
|
||||
module.exports = {
|
||||
export default {
|
||||
preset: "ts-jest",
|
||||
testEnvironment: "node",
|
||||
moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json", "node"],
|
||||
|
|
@ -318,7 +318,7 @@
|
|||
}
|
||||
},
|
||||
"scripts": {
|
||||
"lint": "eslint **/*.ts --max-warnings=0",
|
||||
"lint": "eslint . --ext=ts --max-warnings=0",
|
||||
"check-types": "tsc --noEmit",
|
||||
"pretest": "pnpm bundle",
|
||||
"test": "jest -w=40% && vitest run",
|
||||
|
|
@ -429,7 +429,6 @@
|
|||
"nock": "^14.0.4",
|
||||
"npm-run-all2": "^8.0.1",
|
||||
"ovsx": "0.10.2",
|
||||
"prettier": "^3.4.2",
|
||||
"rimraf": "^6.0.1",
|
||||
"ts-jest": "^29.2.5",
|
||||
"tsup": "^8.4.0",
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ export const createPrompt = (template: string, params: PromptParams): string =>
|
|||
return template.replace(/\${(.*?)}/g, (_, key) => {
|
||||
if (key === "diagnosticText") {
|
||||
return generateDiagnosticText(params["diagnostics"] as any[])
|
||||
// eslint-disable-next-line no-prototype-builtins
|
||||
} else if (params.hasOwnProperty(key)) {
|
||||
// Ensure the value is treated as a string for replacement
|
||||
const value = params[key]
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
import { jest } from "@jest/globals"
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-function-type */
|
||||
|
||||
import { ExecException } from "child_process"
|
||||
|
||||
import { jest } from "@jest/globals"
|
||||
|
||||
import { searchCommits, getCommitInfo, getWorkingState } from "../git"
|
||||
|
||||
type ExecFunction = (
|
||||
|
|
|
|||
|
|
@ -7,12 +7,31 @@ export default [
|
|||
rules: {
|
||||
"@typescript-eslint/no-unused-vars": "off",
|
||||
"@typescript-eslint/no-explicit-any": "off",
|
||||
"react/prop-types": "off",
|
||||
"react/display-name": "off",
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ["src/utils/context-mentions.ts", "src/utils/highlighter.ts"],
|
||||
files: ["src/components/chat/ChatRow.tsx", "src/components/settings/ModelInfoView.tsx"],
|
||||
rules: {
|
||||
"prefer-const": "off",
|
||||
"react/jsx-key": "off",
|
||||
},
|
||||
},
|
||||
{
|
||||
files: [
|
||||
"src/components/chat/ChatRow.tsx",
|
||||
"src/components/chat/ChatView.tsx",
|
||||
"src/components/chat/BrowserSessionRow.tsx",
|
||||
"src/components/history/useTaskSearch.ts",
|
||||
],
|
||||
rules: {
|
||||
"no-case-declarations": "off",
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ["src/__mocks__/**/*.js"],
|
||||
rules: {
|
||||
"no-undef": "off",
|
||||
},
|
||||
},
|
||||
]
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"lint": "eslint src/**/*.{ts,tsx} --max-warnings=0",
|
||||
"lint": "eslint src --ext=ts,tsx --max-warnings=0",
|
||||
"check-types": "tsc",
|
||||
"test": "jest -w=40%",
|
||||
"format": "prettier --write src",
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ interface ChatRowProps {
|
|||
onSuggestionClick?: (answer: string, event?: React.MouseEvent) => void
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
||||
interface ChatRowContentProps extends Omit<ChatRowProps, "onHeightChange"> {}
|
||||
|
||||
const ChatRow = memo(
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ const TaskHeader = ({
|
|||
<div
|
||||
className={cn(
|
||||
"rounded-xs p-2.5 flex flex-col gap-1.5 relative z-1 border",
|
||||
!!isTaskExpanded
|
||||
isTaskExpanded
|
||||
? "border-vscode-panel-border text-vscode-foreground"
|
||||
: "border-vscode-panel-border/80 text-vscode-foreground/80",
|
||||
)}>
|
||||
|
|
|
|||
|
|
@ -77,7 +77,9 @@ const mockInputRef = React.createRef<HTMLInputElement>()
|
|||
const mockFocus = jest.fn()
|
||||
|
||||
jest.mock("../ChatTextArea", () => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
||||
const mockReact = require("react")
|
||||
|
||||
return {
|
||||
__esModule: true,
|
||||
default: mockReact.forwardRef(function MockChatTextArea(
|
||||
|
|
|
|||
|
|
@ -140,6 +140,7 @@ describe("CodeBlock", () => {
|
|||
|
||||
it("handles WASM loading errors", async () => {
|
||||
const mockError = new Error("WASM load failed")
|
||||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
||||
const highlighterUtil = require("../../../utils/highlighter")
|
||||
highlighterUtil.getHighlighter.mockRejectedValueOnce(mockError)
|
||||
|
||||
|
|
@ -163,6 +164,7 @@ describe("CodeBlock", () => {
|
|||
|
||||
it("verifies highlighter utility is used correctly", async () => {
|
||||
const code = "const x = 1;"
|
||||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
||||
const highlighterUtil = require("../../../utils/highlighter")
|
||||
|
||||
await act(async () => {
|
||||
|
|
|
|||
|
|
@ -19,7 +19,10 @@ export const CopyButton = ({ itemTask }: CopyButtonProps) => {
|
|||
const tempDiv = document.createElement("div")
|
||||
tempDiv.innerHTML = itemTask
|
||||
const text = tempDiv.textContent || tempDiv.innerText || ""
|
||||
!isCopied && copy(text)
|
||||
|
||||
if (!isCopied) {
|
||||
copy(text)
|
||||
}
|
||||
},
|
||||
[isCopied, copy, itemTask],
|
||||
)
|
||||
|
|
|
|||
|
|
@ -116,7 +116,6 @@ export const OpenRouter = ({
|
|||
<Trans
|
||||
i18nKey="settings:providers.openRouterTransformsText"
|
||||
components={{
|
||||
// eslint-disable-next-line jsx-a11y/anchor-has-content
|
||||
a: <a href="https://openrouter.ai/docs/transforms" />,
|
||||
}}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ const CommandInput = React.forwardRef<
|
|||
React.ElementRef<typeof CommandPrimitive.Input>,
|
||||
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Input>
|
||||
>(({ className, ...props }, ref) => (
|
||||
// eslint-disable-next-line react/no-unknown-property
|
||||
<div className="flex items-center border-b border-vscode-dropdown-border px-3" cmdk-input-wrapper="">
|
||||
<MagnifyingGlassIcon className="mr-2 h-4 w-4 shrink-0 opacity-50" />
|
||||
<CommandPrimitive.Input
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
/* eslint-disable no-useless-escape */
|
||||
/* eslint-disable no-template-curly-in-string */
|
||||
|
||||
// npx jest src/utils/__tests__/command-validation.test.ts
|
||||
|
||||
|
|
|
|||
|
|
@ -255,7 +255,7 @@ export function getContextMenuOptions(
|
|||
// Convert search results to queryItems format
|
||||
const searchResultItems = dynamicSearchResults.map((result) => {
|
||||
// Ensure paths start with / for consistency
|
||||
let formattedPath = result.path.startsWith("/") ? result.path : `/${result.path}`
|
||||
const formattedPath = result.path.startsWith("/") ? result.path : `/${result.path}`
|
||||
|
||||
// For display purposes, we don't escape spaces in the label or description
|
||||
const displayPath = formattedPath
|
||||
|
|
|
|||
|
|
@ -128,7 +128,7 @@ const LANGUAGE_LOAD_DELAY = 0
|
|||
const initialLanguages: BundledLanguage[] = ["shell", "log"]
|
||||
|
||||
// Singleton state
|
||||
let state: {
|
||||
const state: {
|
||||
instance: Highlighter | null
|
||||
instanceInitPromise: Promise<Highlighter> | null
|
||||
loadedLanguages: Set<ExtendedLanguage>
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ function getGitSha() {
|
|||
try {
|
||||
gitSha = execSync("git rev-parse HEAD").toString().trim()
|
||||
} catch (_error) {
|
||||
// NO-OP
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
return gitSha
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue