From 93ea938375fdbd88307aecb772cf733ef8d5ba19 Mon Sep 17 00:00:00 2001 From: can1357 Date: Sun, 26 Apr 2026 14:56:16 +0200 Subject: [PATCH] refactor(edit): removed unsupported ignore-case and multiline sed flags - Removed `i` and `m` from the Atom sed schema and docs, so sed now accepts only `pat`, `rep`, `g`, and `F` options. - Updated `SedSpec` parsing and serialization to drop ignore-case and multiline handling. - Adjusted regex construction to apply sed replacements using only global and literal flags. --- packages/coding-agent/src/edit/modes/atom.ts | 20 +++++-------------- .../coding-agent/src/prompts/tools/atom.md | 4 +--- 2 files changed, 6 insertions(+), 18 deletions(-) diff --git a/packages/coding-agent/src/edit/modes/atom.ts b/packages/coding-agent/src/edit/modes/atom.ts index 701eef018..5de5d5fe0 100644 --- a/packages/coding-agent/src/edit/modes/atom.ts +++ b/packages/coding-agent/src/edit/modes/atom.ts @@ -12,7 +12,7 @@ * { path, loc: "5th", pre: [...], splice: [...], post: [...] } * { path, loc: "$", pre: [...] } // prepend to file * { path, loc: "$", post: [...] } // append to file - * { path, loc: "$", sed: { pat, rep, g?, F?, i?, m? } } // sed on every line + * { path, loc: "$", sed: { pat, rep, g?, F? } } // sed on every line * * `splice: []` on a single-anchor locator deletes that line. `splice:[""]` preserves * a blank line. Line ranges are not supported. @@ -72,8 +72,6 @@ export const atomEditSchema = Type.Object( rep: Type.String({ description: "replacement text" }), g: Type.Optional(Type.Boolean({ description: "global replace", default: false })), F: Type.Optional(Type.Boolean({ description: "literal replace", default: false })), - i: Type.Optional(Type.Boolean({ description: "ignore case", default: false })), - m: Type.Optional(Type.Boolean({ description: "multiline mode (^ and $ match line boundaries)", default: false })), }, { additionalProperties: false, @@ -110,11 +108,9 @@ export type AtomEdit = | { op: "sed_file"; spec: SedSpec; expression: string }; export interface SedSpec { - multiline: boolean; pattern: string; replacement: string; global: boolean; - ignoreCase: boolean; literal: boolean; } @@ -270,7 +266,7 @@ function extractAnchorContentHint(raw: string): string | undefined { function parseSedSpec(input: unknown, editIndex: number): SedSpec { if (input === null || typeof input !== "object" || Array.isArray(input)) { - throw new Error(`Edit ${editIndex}: sed must be an object with shape {pat, rep, g?, F?, i?, m?}.`); + throw new Error(`Edit ${editIndex}: sed must be an object with shape {pat, rep, g?, F?}.`); } const obj = input as Record; const pat = obj.pat; @@ -286,7 +282,7 @@ function parseSedSpec(input: unknown, editIndex: number): SedSpec { if (typeof rep !== "string") { throw new Error(`Edit ${editIndex}: sed.rep must be a string.`); } - const readBool = (key: "g" | "F" | "i" | "m", defaultValue: boolean): boolean => { + const readBool = (key: "g" | "F", defaultValue: boolean): boolean => { const v = obj[key]; if (v === undefined) return defaultValue; if (typeof v !== "boolean") { @@ -296,21 +292,17 @@ function parseSedSpec(input: unknown, editIndex: number): SedSpec { }; const global = readBool("g", false); const literal = readBool("F", false); - const ignoreCase = readBool("i", false); - const multiline = readBool("m", false); - return { pattern: pat, replacement: rep, global, literal, ignoreCase, multiline }; + return { pattern: pat, replacement: rep, global, literal }; } function formatSedExpression(spec: SedSpec): string { - const obj: { pat: string; rep: string; g?: boolean; F?: boolean; i?: boolean; m?: boolean } = { + const obj: { pat: string; rep: string; g?: boolean; F?: boolean } = { pat: spec.pattern, rep: spec.replacement, }; // Only emit non-default flags so error messages stay compact (g defaults false). if (spec.global) obj.g = true; if (spec.literal) obj.F = true; - if (spec.ignoreCase) obj.i = true; - if (spec.multiline) obj.m = true; return JSON.stringify(obj); } @@ -335,8 +327,6 @@ function applySedToLine( } let flags = ""; if (spec.global) flags += "g"; - if (spec.ignoreCase) flags += "i"; - if (spec.multiline) flags += "m"; let re: RegExp | undefined; let compileError: string | undefined; try { diff --git a/packages/coding-agent/src/prompts/tools/atom.md b/packages/coding-agent/src/prompts/tools/atom.md index e19e8a92d..0cbaa934d 100644 --- a/packages/coding-agent/src/prompts/tools/atom.md +++ b/packages/coding-agent/src/prompts/tools/atom.md @@ -14,13 +14,11 @@ Verbs: - `splice: […]`: lines are spliced in at the anchor. - `pre: […]`: prepend before the anchor (or at BOF if `loc=$`) - `post: […]`: append after the anchor (or at EOF if `loc=$`) -- `sed: { pat, rep, g?, F?, i?, m? }` — structured find/replace on the anchor line. **Prefer this over `splice` for token-level changes** +- `sed: { pat, rep, g?, F? }` — structured find/replace on the anchor line. **Prefer this over `splice` for token-level changes** - `pat`: pattern to find (regex by default) - `rep`: replacement (regex back-refs like `$1`, `$&` available) - `g`: global — replace every occurrence (default `false`; pass `true` to replace all) - `F`: literal — treat `pat` as a literal substring (no regex). Use this whenever `pat` contains `||`, `.`, `(`, `?`, `\`, etc. you mean literally. - - `i`: ignore case - - `m`: multiline — `^` and `$` match line boundaries You **MUST** keep `pat` as short as possible. Combination rules: