Roo-Code/packages/evals/src/db/queries/copyRun.ts
Daniel d52b6834e3
Add back post-revert bug fixes and features (Step 2) (#11463)
* fix: cancel backend auto-approval timeout when auto-approve is toggled off mid-countdown (#11439)

Co-authored-by: Sannidhya <sann@Sannidhyas-MacBook-Pro.local>

* fix: prevent chat history loss during cloud/settings navigation (#11371) (#11372)

Co-authored-by: Sannidhya <sann@Sannidhyas-MacBook-Pro.local>

* fix: preserve pasted images in chatbox during chat activity (#11375)

Co-authored-by: Roo Code <roomote@roocode.com>

* fix: resolve chat scroll anchoring and task-switch scroll race condit… (#11385)

* fix: avoid zsh process-substitution false positives in assignments (#11365)

* fix(editor): make tab close best-effort in DiffViewProvider.open (#11363)

* fix(checkpoints): canonicalize core.worktree comparison to prevent Windows path mismatch failures (#11346)

* fix: prevent double notification sound playback (#11283)

* fix: prevent false unsaved changes prompt with OpenAI Compatible headers (#8230) (#11334)

fix: prevent false unsaved changes prompt with OpenAI Compatible headers

Mark automatic header syncs in ApiOptions and OpenAICompatible as
non-user actions (isUserAction: false) and enhance SettingsView change
detection to skip automatic syncs with semantically equal values.

Root cause: two components (ApiOptions and OpenAICompatible) manage
openAiHeaders state and automatically sync it back on mount/remount.
These syncs were treated as user changes, triggering a false dirty state.

Co-authored-by: Robert McIntyre <robertjmcintyre@users.noreply.github.com>

* fix: remove noisy console.warn logs from NativeToolCallParser (#11264)

Remove two console.warn messages that fire excessively when loading tasks
from history:
- 'Attempting to finalize unknown tool call' in finalizeStreamingToolCall()
- 'Received chunk for unknown tool call' in processStreamingChunk()

The defensive null-return behavior is preserved; only the log output is removed.

* refactor: remove footgun prompting (file-based system prompt override) (#11387)

* refactor: delete orphaned per-provider caching transform files (#11388)

* feat: add disabledTools setting to globally disable native tools (#11277)

* feat: add disabledTools setting to globally disable native tools

Add a disabledTools field to GlobalSettings that allows disabling specific
native tools by name. This enables cloud agents to be configured with
restricted tool access.

Schema:
- Add disabledTools: z.array(toolNamesSchema).optional() to globalSettingsSchema
- Add disabledTools to organizationDefaultSettingsSchema.pick()
- Add disabledTools to ExtensionState Pick type

Prompt generation (tool filtering):
- Add disabledTools to BuildToolsOptions interface
- Pass disabledTools through filterSettings to filterNativeToolsForMode()
- Remove disabled tools from allowedToolNames set in filterNativeToolsForMode()

Execution-time validation (safety net):
- Extract disabledTools from state in presentAssistantMessage
- Convert disabledTools to toolRequirements format for validateToolUse()

Wiring:
- Add disabledTools to ClineProvider getState() and getStateToPostToWebview()
- Pass disabledTools to all buildNativeToolsArrayWithRestrictions() call sites

EXT-778

* fix: check toolRequirements before ALWAYS_AVAILABLE_TOOLS

Moves the toolRequirements check before the ALWAYS_AVAILABLE_TOOLS
early-return in isToolAllowedForMode(). This ensures disabledTools
can block always-available tools (switch_mode, new_task, etc.) at
execution time, making the validation layer consistent with the
filtering layer.

* feat: add support for .agents/skills directory (#11181)

* feat: add support for .agents/skills directory

This change adds support for discovering skills from the .agents/skills
directory, following the Agent Skills convention for sharing skills
across different AI coding tools.

Priority order (later entries override earlier ones):
1. Global ~/.agents/skills (shared across AI coding tools, lowest priority)
2. Project .agents/skills
3. Global ~/.roo/skills (Roo-specific)
4. Project .roo/skills (highest priority)

Changes:
- Add getGlobalAgentsDirectory() and getProjectAgentsDirectoryForCwd()
  functions to roo-config
- Update SkillsManager.getSkillsDirectories() to include .agents/skills
- Update SkillsManager.setupFileWatchers() to watch .agents/skills
- Add tests for new functionality

* fix: clarify skill priority comment to match actual behavior

* fix: clarify skill priority comment to explain Map.set replacement mechanism

---------

Co-authored-by: Roo Code <roomote@roocode.com>

* feat(history): render nested subtasks as recursive tree (#11299)

* feat(history): render nested subtasks as recursive tree

* fix(lockfile): resolve missing ai-sdk provider entry

* fix: address review feedback — dedupe countAll, increase SubtaskRow max-h

- HistoryView: replace local countAll with imported countAllSubtasks from types.ts
- SubtaskRow: increase nested children max-h from 500px to 2000px to match TaskGroupItem

* perf(refactor): consolidate getState calls in resolveWebviewView (#11320)

* perf(refactor): consolidate getState calls in resolveWebviewView

Replace three separate this.getState().then() calls with a single
await this.getState() and destructuring. This avoids running the
full getState() method (CloudService calls, ContextProxy reads, etc.)
three times during webview view resolution.

* fix: keep getState consolidation non-blocking to avoid delaying webview render

---------

Co-authored-by: daniel-lxs <ricciodaniel98@gmail.com>

* fix: harden command auto-approval against inline JS false positives (#11382)

* feat: rename search_and_replace tool to edit and unify edit-family UI (#11296)

* Revert "refactor: delete orphaned per-provider caching transform files (#11388)"

This reverts commit 13a45b0361.

* chore: regenerate built-in-skills.ts with updated formatting

* fix: add missing maxReadFileLine property to test baseState

The ExtensionState type now requires maxReadFileLine property (added in commit 63e3f769a).
Update the test to include this property with the default value of -1 (unlimited reading).

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* feat: add pnpm serve command for code-server development (#10964)

Co-authored-by: Roo Code <roomote@roocode.com>

* chore: remove Feature Request from issue template options (#11141)

Co-authored-by: Roo Code <roomote@roocode.com>

* refactor(docs-extractor): simplify mode to focus on raw fact extraction (#11129)

* Add cli support for linux (#11167)

* fix: replace heredocs with echo statements in cli-release workflow (#11168)

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>

* Drop MacOS-13 cli support (#11169)

* fix(cli): correct example in install script (#11170)

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>

* feat: add Kimi K2.5 model to Fireworks provider (#11177)

* feat(cli): improve dev experience and roo provider API key support (#11203)

- Allow --api-key and ROO_API_KEY env var for the roo provider instead of
  requiring cloud auth token
- Switch dev/start scripts to use tsx for running directly from source
  without building first
- Fix path resolution (version.ts, extension.ts, extension-host.ts) to
  work from both source and bundled locations
- Disable debug log file (~/.roo/cli-debug.log) unless --debug is passed
- Update README with complete env var table and dev workflow docs

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>

* Roo Code CLI v0.0.50 (#11204)

* Roo Code CLI v0.0.50

* docs(cli): add --exit-on-error to changelog

---------

Co-authored-by: Roo Code <roomote@roocode.com>

* feat(cli): update default model from Opus 4.5 to Opus 4.6 (#11273)

Co-authored-by: Roo Code <roomote@roocode.com>

* feat(web): replace Roomote Control with Linear Integration in cloud features grid (#11280)

Co-authored-by: Roo Code <roomote@roocode.com>

* Add linux-arm64 for the roo cli (#11314)

* chore: clean up repo-facing mode rules (#11410)

* Make CLI auto-approve by default with require-approval opt-in (#11424)

Co-authored-by: Roo Code <roomote@roocode.com>

* Add new code owners to CODEOWNERS file

* Update next.js (#11108)

* feat(web): Replace bespoke navigation menu with shadcn navigation menu (#11117)

Co-authored-by: Roo Code <roomote@roocode.com>

---------

Co-authored-by: SannidhyaSah <sah_sannidhya@outlook.com>
Co-authored-by: Sannidhya <sann@Sannidhyas-MacBook-Pro.local>
Co-authored-by: roomote[bot] <219738659+roomote[bot]@users.noreply.github.com>
Co-authored-by: Roo Code <roomote@roocode.com>
Co-authored-by: Hannes Rudolph <hrudolph@gmail.com>
Co-authored-by: 0xMink <dennis@dennismink.com>
Co-authored-by: Robert McIntyre <robertjmcintyre@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
Co-authored-by: Matt Rubens <mrubens@users.noreply.github.com>
Co-authored-by: Chris Estreich <cestreich@gmail.com>
2026-02-13 18:40:28 -05:00

183 lines
4.8 KiB
TypeScript

import { eq } from "drizzle-orm"
import type { NodePgDatabase } from "drizzle-orm/node-postgres"
import type { InsertRun, InsertTask, InsertTaskMetrics, InsertToolError } from "../schema"
import { schema } from "../schema"
import { RecordNotFoundError, RecordNotCreatedError } from "./errors"
export const copyRun = async ({
sourceDb,
targetDb,
runId,
}: {
sourceDb: NodePgDatabase<typeof schema>
targetDb: NodePgDatabase<typeof schema>
runId: number
}) => {
const sourceRun = await sourceDb.query.runs.findFirst({
where: eq(schema.runs.id, runId),
with: { taskMetrics: true },
})
if (!sourceRun) {
throw new RecordNotFoundError(`Run with ID ${runId} not found`)
}
let newRunTaskMetricsId: number | null = null
if (sourceRun.taskMetrics) {
const runTaskMetricsData: InsertTaskMetrics = {
tokensIn: sourceRun.taskMetrics.tokensIn,
tokensOut: sourceRun.taskMetrics.tokensOut,
tokensContext: sourceRun.taskMetrics.tokensContext,
cacheWrites: sourceRun.taskMetrics.cacheWrites,
cacheReads: sourceRun.taskMetrics.cacheReads,
cost: sourceRun.taskMetrics.cost,
duration: sourceRun.taskMetrics.duration,
toolUsage: sourceRun.taskMetrics.toolUsage,
}
const newRunTaskMetrics = await targetDb
.insert(schema.taskMetrics)
.values({
...runTaskMetricsData,
createdAt: new Date(),
})
.returning()
const createdRunTaskMetrics = newRunTaskMetrics[0]
if (!createdRunTaskMetrics) {
throw new RecordNotCreatedError("Failed to create run taskMetrics")
}
newRunTaskMetricsId = createdRunTaskMetrics.id
}
const runData: InsertRun = {
taskMetricsId: newRunTaskMetricsId,
model: sourceRun.model,
description: sourceRun.description,
settings: sourceRun.settings,
pid: sourceRun.pid,
socketPath: sourceRun.socketPath,
concurrency: sourceRun.concurrency,
passed: sourceRun.passed,
failed: sourceRun.failed,
}
const newRuns = await targetDb
.insert(schema.runs)
.values({ ...runData, createdAt: new Date() })
.returning()
const newRun = newRuns[0]
if (!newRun) {
throw new RecordNotCreatedError("Failed to create run")
}
const newRunId = newRun.id
const sourceTasks = await sourceDb.query.tasks.findMany({
where: eq(schema.tasks.runId, runId),
with: { taskMetrics: true },
})
const taskIdMapping = new Map<number, number>()
for (const sourceTask of sourceTasks) {
let newTaskMetricsId: number | null = null
if (sourceTask.taskMetrics) {
const taskMetricsData: InsertTaskMetrics = {
tokensIn: sourceTask.taskMetrics.tokensIn,
tokensOut: sourceTask.taskMetrics.tokensOut,
tokensContext: sourceTask.taskMetrics.tokensContext,
cacheWrites: sourceTask.taskMetrics.cacheWrites,
cacheReads: sourceTask.taskMetrics.cacheReads,
cost: sourceTask.taskMetrics.cost,
duration: sourceTask.taskMetrics.duration,
toolUsage: sourceTask.taskMetrics.toolUsage,
}
const newTaskMetrics = await targetDb
.insert(schema.taskMetrics)
.values({ ...taskMetricsData, createdAt: new Date() })
.returning()
const createdTaskMetrics = newTaskMetrics[0]
if (!createdTaskMetrics) {
throw new RecordNotCreatedError("Failed to create task taskMetrics")
}
newTaskMetricsId = createdTaskMetrics.id
}
const taskData: InsertTask = {
runId: newRunId,
taskMetricsId: newTaskMetricsId,
language: sourceTask.language,
exercise: sourceTask.exercise,
passed: sourceTask.passed,
startedAt: sourceTask.startedAt,
finishedAt: sourceTask.finishedAt,
}
const newTasks = await targetDb
.insert(schema.tasks)
.values({ ...taskData, createdAt: new Date() })
.returning()
const newTask = newTasks[0]
if (!newTask) {
throw new RecordNotCreatedError("Failed to create task")
}
taskIdMapping.set(sourceTask.id, newTask.id)
}
for (const [oldTaskId, newTaskId] of taskIdMapping) {
const sourceTaskToolErrors = await sourceDb.query.toolErrors.findMany({
where: eq(schema.toolErrors.taskId, oldTaskId),
})
for (const sourceToolError of sourceTaskToolErrors) {
const toolErrorData: InsertToolError = {
runId: newRunId,
taskId: newTaskId,
toolName: sourceToolError.toolName,
error: sourceToolError.error,
}
await targetDb.insert(schema.toolErrors).values({
...toolErrorData,
createdAt: new Date(),
})
}
}
const sourceRunToolErrors = await sourceDb.query.toolErrors.findMany({
where: eq(schema.toolErrors.runId, runId),
})
for (const sourceToolError of sourceRunToolErrors) {
if (sourceToolError.taskId && taskIdMapping.has(sourceToolError.taskId)) {
continue
}
const toolErrorData: InsertToolError = {
runId: newRunId,
taskId: sourceToolError.taskId ? taskIdMapping.get(sourceToolError.taskId) || null : null,
toolName: sourceToolError.toolName,
error: sourceToolError.error,
}
await targetDb.insert(schema.toolErrors).values({ ...toolErrorData, createdAt: new Date() })
}
return newRunId
}