Miscellaneous cleanup (#6453)

This commit is contained in:
Chris Estreich 2025-07-30 16:10:53 -07:00 committed by GitHub
parent b8dc31581c
commit cb6dccab95
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 74 additions and 52 deletions

View file

@ -4,7 +4,7 @@
- Before attempting completion, always make sure that any code changes have test coverage
- Ensure all tests pass before submitting changes
- The vitest framework is used for testing; the `describe`, `test`, `it`, etc functions are defined by default in `tsconfig.json` and therefore don't need to be imported
- The vitest framework is used for testing; the `vi`, `describe`, `test`, `it`, etc functions are defined by default in `tsconfig.json` and therefore don't need to be imported from `vitest`
- Tests must be run from the same directory as the `package.json` file that specifies `vitest` in `devDependencies`
- Run tests with: `npx vitest run <relative-path-from-workspace-root>`
- Do NOT run tests from project root - this causes "vitest: command not found" error
@ -18,6 +18,7 @@
- Never disable any lint rules without explicit user approval
3. Styling Guidelines:
- Use Tailwind CSS classes instead of inline style objects for new markup
- VSCode CSS variables must be added to webview-ui/src/index.css before using them in Tailwind classes
- Example: `<div className="text-md text-vscode-descriptionForeground mb-2" />` instead of style objects

View file

@ -1 +0,0 @@
readme test

View file

@ -9,7 +9,7 @@
"format": "prettier --write src",
"build": "next build",
"start": "next start",
"clean": "rimraf .next .turbo"
"clean": "rimraf tsconfig.tsbuildinfo .next .turbo"
},
"dependencies": {
"@hookform/resolvers": "^5.1.1",

View file

@ -7,7 +7,8 @@
"check-types": "tsc --noEmit",
"dev": "next dev",
"build": "next build",
"start": "next start"
"start": "next start",
"clean": "rimraf .next .turbo"
},
"dependencies": {
"@radix-ui/react-dialog": "^1.1.14",

View file

@ -48,6 +48,7 @@ export class CloudService {
try {
const cloudToken = process.env.ROO_CODE_CLOUD_TOKEN
if (cloudToken && cloudToken.length > 0) {
this.authService = new StaticTokenAuthService(this.context, cloudToken, this.log)
} else {
@ -62,8 +63,9 @@ export class CloudService {
this.authService.on("logged-out", this.authListener)
this.authService.on("user-info", this.authListener)
// Check for static settings environment variable
// Check for static settings environment variable.
const staticOrgSettings = process.env.ROO_CODE_CLOUD_ORG_SETTINGS
if (staticOrgSettings && staticOrgSettings.length > 0) {
this.settingsService = new StaticSettingsService(staticOrgSettings, this.log)
} else {
@ -73,12 +75,12 @@ export class CloudService {
() => this.callbacks.stateChanged?.(),
this.log,
)
cloudSettingsService.initialize()
this.settingsService = cloudSettingsService
}
this.telemetryClient = new TelemetryClient(this.authService, this.settingsService)
this.shareService = new ShareService(this.authService, this.settingsService, this.log)
try {

View file

@ -93,10 +93,9 @@ import { getMessagesSinceLastSummary, summarizeConversation } from "../condense"
import { maybeRemoveImageBlocks } from "../../api/transform/image-cleaning"
import { restoreTodoListForTask } from "../tools/updateTodoListTool"
// Constants
const MAX_EXPONENTIAL_BACKOFF_SECONDS = 600 // 10 minutes
export type ClineEvents = {
export type TaskEvents = {
message: [{ action: "created" | "updated"; message: ClineMessage }]
taskStarted: []
taskModeSwitched: [taskId: string, mode: string]
@ -110,6 +109,10 @@ export type ClineEvents = {
taskToolFailed: [taskId: string, tool: ToolName, error: string]
}
export type TaskEventHandlers = {
[K in keyof TaskEvents]: (...args: TaskEvents[K]) => void | Promise<void>
}
export type TaskOptions = {
provider: ClineProvider
apiConfiguration: ProviderSettings
@ -125,10 +128,10 @@ export type TaskOptions = {
rootTask?: Task
parentTask?: Task
taskNumber?: number
onCreated?: (cline: Task) => void
onCreated?: (task: Task) => void
}
export class Task extends EventEmitter<ClineEvents> {
export class Task extends EventEmitter<TaskEvents> {
todoList?: TodoItem[]
readonly taskId: string
readonly instanceId: string
@ -137,6 +140,7 @@ export class Task extends EventEmitter<ClineEvents> {
readonly parentTask: Task | undefined = undefined
readonly taskNumber: number
readonly workspacePath: string
/**
* The mode associated with this task. Persisted across sessions
* to maintain user context when reopening tasks from history.
@ -279,10 +283,12 @@ export class Task extends EventEmitter<ClineEvents> {
}
this.taskId = historyItem ? historyItem.id : crypto.randomUUID()
// normal use-case is usually retry similar history task with new workspace
// Normal use-case is usually retry similar history task with new workspace.
this.workspacePath = parentTask
? parentTask.workspacePath
: getWorkspacePath(path.join(os.homedir(), "Desktop"))
this.instanceId = crypto.randomUUID().slice(0, 8)
this.taskNumber = -1
@ -311,25 +317,26 @@ export class Task extends EventEmitter<ClineEvents> {
this.parentTask = parentTask
this.taskNumber = taskNumber
// Store the task's mode when it's created
// For history items, use the stored mode; for new tasks, we'll set it after getting state
// Store the task's mode when it's created.
// For history items, use the stored mode; for new tasks, we'll set it
// after getting state.
if (historyItem) {
this._taskMode = historyItem.mode || defaultModeSlug
this.taskModeReady = Promise.resolve()
TelemetryService.instance.captureTaskRestarted(this.taskId)
} else {
// For new tasks, don't set the mode yet - wait for async initialization
// For new tasks, don't set the mode yet - wait for async initialization.
this._taskMode = undefined
this.taskModeReady = this.initializeTaskMode(provider)
TelemetryService.instance.captureTaskCreated(this.taskId)
}
// Only set up diff strategy if diff is enabled
// Only set up diff strategy if diff is enabled.
if (this.diffEnabled) {
// Default to old strategy, will be updated if experiment is enabled
// Default to old strategy, will be updated if experiment is enabled.
this.diffStrategy = new MultiSearchReplaceDiffStrategy(this.fuzzyMatchThreshold)
// Check experiment asynchronously and update strategy if needed
// Check experiment asynchronously and update strategy if needed.
provider.getState().then((state) => {
const isMultiFileApplyDiffEnabled = experiments.isEnabled(
state.experiments ?? {},
@ -1230,7 +1237,7 @@ export class Task extends EventEmitter<ClineEvents> {
}
} catch (error) {
console.error("Error disposing RooIgnoreController:", error)
// This is the critical one for the leak fix
// This is the critical one for the leak fix.
}
try {
@ -1240,7 +1247,7 @@ export class Task extends EventEmitter<ClineEvents> {
}
try {
// If we're not streaming then `abortStream` won't be called
// If we're not streaming then `abortStream` won't be called.
if (this.isStreaming && this.diffViewProvider.isEditing) {
this.diffViewProvider.revertChanges().catch(console.error)
}
@ -1847,6 +1854,7 @@ export class Task extends EventEmitter<ClineEvents> {
public async *attemptApiRequest(retryAttempt: number = 0): ApiStream {
const state = await this.providerRef.deref()?.getState()
const {
apiConfiguration,
autoApprovalEnabled,
@ -1858,21 +1866,24 @@ export class Task extends EventEmitter<ClineEvents> {
profileThresholds = {},
} = state ?? {}
// Get condensing configuration for automatic triggers
// Get condensing configuration for automatic triggers.
const customCondensingPrompt = state?.customCondensingPrompt
const condensingApiConfigId = state?.condensingApiConfigId
const listApiConfigMeta = state?.listApiConfigMeta
// Determine API handler to use for condensing
// Determine API handler to use for condensing.
let condensingApiHandler: ApiHandler | undefined
if (condensingApiConfigId && listApiConfigMeta && Array.isArray(listApiConfigMeta)) {
// Using type assertion for the id property to avoid implicit any
// Using type assertion for the id property to avoid implicit any.
const matchingConfig = listApiConfigMeta.find((config: any) => config.id === condensingApiConfigId)
if (matchingConfig) {
const profile = await this.providerRef.deref()?.providerSettingsManager.getProfile({
id: condensingApiConfigId,
})
// Ensure profile and apiProvider exist before trying to build handler
// Ensure profile and apiProvider exist before trying to build handler.
if (profile && profile.apiProvider) {
condensingApiHandler = buildApiHandler(profile)
}

View file

@ -23,12 +23,12 @@ import {
type TerminalActionPromptType,
type HistoryItem,
type CloudUserInfo,
type MarketplaceItem,
requestyDefaultModelId,
openRouterDefaultModelId,
glamaDefaultModelId,
ORGANIZATION_ALLOW_ALL,
DEFAULT_TERMINAL_OUTPUT_CHARACTER_LIMIT,
DEFAULT_WRITE_DELAY_MS,
} from "@roo-code/types"
import { TelemetryService } from "@roo-code/telemetry"
import { CloudService, getRooCodeApiUrl } from "@roo-code/cloud"
@ -41,9 +41,8 @@ import { supportPrompt } from "../../shared/support-prompt"
import { GlobalFileNames } from "../../shared/globalFileNames"
import { ExtensionMessage, MarketplaceInstalledMetadata } from "../../shared/ExtensionMessage"
import { Mode, defaultModeSlug, getModeBySlug } from "../../shared/modes"
import { experimentDefault, experiments, EXPERIMENT_IDS } from "../../shared/experiments"
import { experimentDefault } from "../../shared/experiments"
import { formatLanguage } from "../../shared/language"
import { DEFAULT_WRITE_DELAY_MS } from "@roo-code/types"
import { Terminal } from "../../integrations/terminal/Terminal"
import { downloadTask } from "../../integrations/misc/export-markdown"
import { getTheme } from "../../integrations/theme/getTheme"
@ -78,13 +77,7 @@ import { getWorkspaceGitInfo } from "../../utils/git"
*/
export type ClineProviderEvents = {
clineCreated: [cline: Task]
}
class OrganizationAllowListViolationError extends Error {
constructor(message: string) {
super(message)
}
taskCreated: [task: Task]
}
export class ClineProvider
@ -380,6 +373,7 @@ export class ClineProvider
// Errors from terminal commands seem to get swallowed / ignored.
vscode.window.showErrorMessage(error.message)
}
throw error
}
}
@ -526,7 +520,7 @@ export class ClineProvider
// of tasks, each one being a sub task of the previous one until the main
// task is finished.
public async initClineWithTask(
task?: string,
text?: string,
images?: string[],
parentTask?: Task,
options: Partial<
@ -549,30 +543,30 @@ export class ClineProvider
throw new OrganizationAllowListViolationError(t("common:errors.violated_organization_allowlist"))
}
const cline = new Task({
const task = new Task({
provider: this,
apiConfiguration,
enableDiff,
enableCheckpoints,
fuzzyMatchThreshold,
consecutiveMistakeLimit: apiConfiguration.consecutiveMistakeLimit,
task,
task: text,
images,
experiments,
rootTask: this.clineStack.length > 0 ? this.clineStack[0] : undefined,
parentTask,
taskNumber: this.clineStack.length + 1,
onCreated: (cline) => this.emit("clineCreated", cline),
onCreated: (instance) => this.emit("taskCreated", instance),
...options,
})
await this.addClineToStack(cline)
await this.addClineToStack(task)
this.log(
`[subtasks] ${cline.parentTask ? "child" : "parent"} task ${cline.taskId}.${cline.instanceId} instantiated`,
`[subtasks] ${task.parentTask ? "child" : "parent"} task ${task.taskId}.${task.instanceId} instantiated`,
)
return cline
return task
}
public async initClineWithHistoryItem(historyItem: HistoryItem & { rootTask?: Task; parentTask?: Task }) {
@ -629,7 +623,7 @@ export class ClineProvider
experiments,
} = await this.getState()
const cline = new Task({
const task = new Task({
provider: this,
apiConfiguration,
enableDiff,
@ -641,14 +635,16 @@ export class ClineProvider
rootTask: historyItem.rootTask,
parentTask: historyItem.parentTask,
taskNumber: historyItem.number,
onCreated: (cline) => this.emit("clineCreated", cline),
onCreated: (instance) => this.emit("taskCreated", instance),
})
await this.addClineToStack(cline)
await this.addClineToStack(task)
this.log(
`[subtasks] ${cline.parentTask ? "child" : "parent"} task ${cline.taskId}.${cline.instanceId} instantiated`,
`[subtasks] ${task.parentTask ? "child" : "parent"} task ${task.taskId}.${task.instanceId} instantiated`,
)
return cline
return task
}
public async postMessageToWebview(message: ExtensionMessage) {
@ -1999,3 +1995,9 @@ export class ClineProvider
}
}
}
class OrganizationAllowListViolationError extends Error {
constructor(message: string) {
super(message)
}
}

View file

@ -214,7 +214,7 @@ export class API extends EventEmitter<RooCodeEvents> implements RooCodeAPI {
}
private registerListeners(provider: ClineProvider) {
provider.on("clineCreated", (cline) => {
provider.on("taskCreated", (cline) => {
cline.on("taskStarted", async () => {
this.emit(RooCodeEventName.TaskStarted, cline.taskId)
this.taskMap.set(cline.taskId, provider)

View file

@ -407,7 +407,7 @@
"publish:marketplace": "vsce publish --no-dependencies && ovsx publish --no-dependencies",
"watch:bundle": "pnpm bundle --watch",
"watch:tsc": "cd .. && tsc --noEmit --watch --project src/tsconfig.json",
"clean": "rimraf README.md CHANGELOG.md LICENSE dist mock .turbo"
"clean": "rimraf README.md CHANGELOG.md LICENSE dist logs mock .turbo"
},
"dependencies": {
"@anthropic-ai/bedrock-sdk": "^0.10.2",

View file

@ -1,16 +1,20 @@
import * as vscode from "vscode"
import * as fs from "fs/promises"
import * as path from "path"
import * as vscode from "vscode"
import * as yaml from "yaml"
import { RemoteConfigLoader } from "./RemoteConfigLoader"
import { SimpleInstaller } from "./SimpleInstaller"
import type { MarketplaceItem, MarketplaceItemType, McpMarketplaceItem, OrganizationSettings } from "@roo-code/types"
import { TelemetryService } from "@roo-code/telemetry"
import { CloudService } from "@roo-code/cloud"
import { GlobalFileNames } from "../../shared/globalFileNames"
import { ensureSettingsDirectoryExists } from "../../utils/globalContext"
import { t } from "../../i18n"
import { TelemetryService } from "@roo-code/telemetry"
import type { CustomModesManager } from "../../core/config/CustomModesManager"
import { CloudService } from "@roo-code/cloud"
import { RemoteConfigLoader } from "./RemoteConfigLoader"
import { SimpleInstaller } from "./SimpleInstaller"
export interface MarketplaceItemsResponse {
organizationMcps: MarketplaceItem[]
@ -35,6 +39,7 @@ export class MarketplaceManager {
const errors: string[] = []
let orgSettings: OrganizationSettings | undefined
try {
if (CloudService.hasInstance() && CloudService.instance.isAuthenticated()) {
orgSettings = CloudService.instance.getOrganizationSettings()

View file

@ -41,6 +41,7 @@ export class ProfileValidator {
}
const providerAllowList = allowList.providers[providerName]
if (!providerAllowList) {
return false
}