File size: 1,825 Bytes
d47b053
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
import type { StudioToolDefinition, StudioToolResult } from '../domain/types'
import type { StudioRuntimeBackedToolContext } from '../runtime/tool-runtime-context'
import { truncateToolText, toWorkspaceRelativePath } from './workspace-paths'
import { applyWorkspacePatch } from './workspace-edits'

interface ApplyPatchToolInput {
  path?: string
  file?: string
  patches?: Array<{ search: string; replace: string; replaceAll?: boolean }>
}

export function createStudioApplyPatchTool(): StudioToolDefinition<ApplyPatchToolInput> {
  return {
    name: 'apply_patch',
    description: 'Apply structured search/replace patches to a workspace file.',
    category: 'edit',
    permission: 'apply_patch',
    allowedAgents: ['builder'],
    requiresTask: false,
    execute: async (input, context) => executeApplyPatchTool(input, context as StudioRuntimeBackedToolContext)
  }
}

async function executeApplyPatchTool(
  input: ApplyPatchToolInput,
  context: StudioRuntimeBackedToolContext
): Promise<StudioToolResult> {
  const target = input.path ?? input.file
  if (!target || !Array.isArray(input.patches) || input.patches.length === 0) {
    throw new Error('Apply_patch tool requires "path" and non-empty "patches"')
  }

  const result = await applyWorkspacePatch({
    baseDirectory: context.session.directory,
    targetPath: target,
    patches: input.patches
  })

  const relativePath = toWorkspaceRelativePath(context.session.directory, result.absolutePath).replace(/\\/g, '/')
  const output = truncateToolText(result.content)

  return {
    title: `Patched ${relativePath}`,
    output: output.text,
    metadata: {
      path: relativePath,
      absolutePath: result.absolutePath,
      replacements: result.replacements,
      patchCount: input.patches.length,
      truncated: output.truncated
    }
  }
}