write.ts 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. import { z } from "zod"
  2. import * as path from "path"
  3. import { Tool } from "./tool"
  4. import { FileTimes } from "./util/file-times"
  5. import { LSP } from "../lsp"
  6. import { Permission } from "../permission"
  7. import DESCRIPTION from "./write.txt"
  8. import { App } from "../app/app"
  9. export const WriteTool = Tool.define({
  10. id: "write",
  11. description: DESCRIPTION,
  12. parameters: z.object({
  13. filePath: z
  14. .string()
  15. .describe(
  16. "The absolute path to the file to write (must be absolute, not relative)",
  17. ),
  18. content: z.string().describe("The content to write to the file"),
  19. }),
  20. async execute(params, ctx) {
  21. const app = App.info()
  22. const filepath = path.isAbsolute(params.filePath)
  23. ? params.filePath
  24. : path.join(app.path.cwd, params.filePath)
  25. const file = Bun.file(filepath)
  26. const exists = await file.exists()
  27. if (exists) await FileTimes.assert(ctx.sessionID, filepath)
  28. await Permission.ask({
  29. id: "write",
  30. sessionID: ctx.sessionID,
  31. title: exists
  32. ? "Overwrite this file: " + filepath
  33. : "Create new file: " + filepath,
  34. metadata: {
  35. filePath: filepath,
  36. content: params.content,
  37. exists,
  38. },
  39. })
  40. await Bun.write(filepath, params.content)
  41. FileTimes.read(ctx.sessionID, filepath)
  42. let output = ""
  43. await LSP.touchFile(filepath, true)
  44. const diagnostics = await LSP.diagnostics()
  45. for (const [file, issues] of Object.entries(diagnostics)) {
  46. if (issues.length === 0) continue
  47. if (file === filepath) {
  48. output += `\nThis file has errors, please fix\n<file_diagnostics>\n${issues.map(LSP.Diagnostic.pretty).join("\n")}\n</file_diagnostics>\n`
  49. continue
  50. }
  51. output += `\n<project_diagnostics>\n${file}\n${issues.map(LSP.Diagnostic.pretty).join("\n")}\n</project_diagnostics>\n`
  52. }
  53. return {
  54. metadata: {
  55. diagnostics,
  56. filepath,
  57. exists: exists,
  58. title: path.relative(app.path.root, filepath),
  59. },
  60. output,
  61. }
  62. },
  63. })