Best-effort coercion for inputs from quirky models.
(input: unknown)
| 46 | |
| 47 | /** Best-effort coercion for inputs from quirky models. */ |
| 48 | function prepareArguments(input: unknown): { path: string; edits: Edit[] } { |
| 49 | if (!input || typeof input !== "object") return input as { path: string; edits: Edit[] }; |
| 50 | const args = input as Record<string, unknown>; |
| 51 | |
| 52 | // Some models pack edits into a JSON string. |
| 53 | if (typeof args.edits === "string") { |
| 54 | try { |
| 55 | const parsed = JSON.parse(args.edits); |
| 56 | if (Array.isArray(parsed)) args.edits = parsed; |
| 57 | } catch { |
| 58 | /* fall through to validation error */ |
| 59 | } |
| 60 | } |
| 61 | |
| 62 | // Legacy single-edit shape: oldText/newText siblings on the root object. |
| 63 | if (typeof args.oldText === "string" && typeof args.newText === "string") { |
| 64 | const edits = Array.isArray(args.edits) ? [...(args.edits as Edit[])] : []; |
| 65 | edits.push({ oldText: args.oldText as string, newText: args.newText as string }); |
| 66 | args.edits = edits; |
| 67 | delete args.oldText; |
| 68 | delete args.newText; |
| 69 | } |
| 70 | |
| 71 | return args as { path: string; edits: Edit[] }; |
| 72 | } |
| 73 | |
| 74 | // Per-path mutation queue. Edit and write should never race on the same file: |
| 75 | // fuzzy matching reads the entire buffer, applies a textual change, then |