summaryrefslogtreecommitdiffhomepage
path: root/packages/opencode/src/tool/multiedit.ts
blob: 004d3c870dd5320965b5f7b9568b4c2678a70a00 (plain)
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
55
56
57
58
59
60
61
import z from "zod"
import { Effect } from "effect"
import * as Tool from "./tool"
import { EditTool } from "./edit"
import DESCRIPTION from "./multiedit.txt"
import path from "path"
import { Instance } from "../project/instance"

export const MultiEditTool = Tool.define(
  "multiedit",
  Effect.gen(function* () {
    const editInfo = yield* EditTool
    const edit = yield* editInfo.init()

    return {
      description: DESCRIPTION,
      parameters: z.object({
        filePath: z.string().describe("The absolute path to the file to modify"),
        edits: z
          .array(
            z.object({
              filePath: z.string().describe("The absolute path to the file to modify"),
              oldString: z.string().describe("The text to replace"),
              newString: z.string().describe("The text to replace it with (must be different from oldString)"),
              replaceAll: z.boolean().optional().describe("Replace all occurrences of oldString (default false)"),
            }),
          )
          .describe("Array of edit operations to perform sequentially on the file"),
      }),
      execute: (
        params: {
          filePath: string
          edits: Array<{ filePath: string; oldString: string; newString: string; replaceAll?: boolean }>
        },
        ctx: Tool.Context,
      ) =>
        Effect.gen(function* () {
          const results = []
          for (const [, entry] of params.edits.entries()) {
            const result = yield* edit.execute(
              {
                filePath: params.filePath,
                oldString: entry.oldString,
                newString: entry.newString,
                replaceAll: entry.replaceAll,
              },
              ctx,
            )
            results.push(result)
          }
          return {
            title: path.relative(Instance.worktree, params.filePath),
            metadata: {
              results: results.map((r) => r.metadata),
            },
            output: results.at(-1)!.output,
          }
        }),
    }
  }),
)