diff --git a/packages/coding-agent/src/prompts/tools/bash.md b/packages/coding-agent/src/prompts/tools/bash.md
index 34fdf0c68..817641c49 100644
--- a/packages/coding-agent/src/prompts/tools/bash.md
+++ b/packages/coding-agent/src/prompts/tools/bash.md
@@ -33,8 +33,8 @@ You **MUST** use specialized tools instead of bash for ALL file operations:
|`rg 'pattern' dir/`|`grep(pattern="pattern", path="dir/")`|
|`find dir -name '*.ts'`|`find(pattern="dir/**/*.ts")`|
|`ls dir/`|`read(path="dir/")`|
-|`cat <<'EOF' > file`|`write(path="file", content="...")`|
-|`sed -i 's/old/new/' file`|`edit(path="file", edits=[...])`|
+|`cat <<'EOF' > file`|`write(path="file", content="…")`|
+|`sed -i 's/old/new/' file`|`edit(path="file", edits=[…])`|
- If `ast_grep` / `ast_edit` tools are available in the session, you **MUST** use them for structural code search/rewrites instead of bash `grep`/`sed`/`awk`/`perl` pipelines
- Bash is for command execution, not syntax-aware code transformation; prefer `ast_grep` for discovery and `ast_edit` for codemods
- You **MUST NOT** use Bash for these operations like read, grep, find, edit, write, where specialized tools exist.
diff --git a/packages/coding-agent/src/utils/prompt-format.ts b/packages/coding-agent/src/utils/prompt-format.ts
index 5f387a847..a4476d1a1 100644
--- a/packages/coding-agent/src/utils/prompt-format.ts
+++ b/packages/coding-agent/src/utils/prompt-format.ts
@@ -86,9 +86,7 @@ export function formatPromptContent(content: string, options: PromptFormatOption
for (let i = 0; i < lines.length; i++) {
let line = lines[i].trimEnd();
- const trimmed = line.trim();
- const trimmedStart = line.trimStart();
-
+ let trimmedStart = line.trimStart();
if (CODE_FENCE.test(trimmedStart)) {
inCodeBlock = !inCodeBlock;
result.push(line);
@@ -103,6 +101,8 @@ export function formatPromptContent(content: string, options: PromptFormatOption
if (replaceAsciiSymbols) {
line = replaceCommonAsciiSymbols(line);
}
+ trimmedStart = line.trimStart();
+ const trimmed = line.trim();
const isOpeningXml = OPENING_XML.test(trimmedStart) && !trimmedStart.endsWith("/>");
if (isOpeningXml && line.length === trimmedStart.length) {
diff --git a/packages/coding-agent/test/prompt-format.test.ts b/packages/coding-agent/test/prompt-format.test.ts
index 51ee5c72a..13dba1969 100644
--- a/packages/coding-agent/test/prompt-format.test.ts
+++ b/packages/coding-agent/test/prompt-format.test.ts
@@ -43,4 +43,15 @@ describe("formatPromptContent renderPhase", () => {
expect(preRender).toBe("\n{{#if ok}}\nvalue\n{{/if}}\n");
expect(postRender).toBe("\n{{#if ok}}\nvalue\n\n{{/if}}\n");
});
+ test("pre-render compacts table rows and does not duplicate content when replacing ascii", () => {
+ const input =
+ '|`cat <<\'EOF\' > file`|`write(path="file", content="...")`|\n|`sed -i \'s/old/new/\' file`|`edit(path="file", edits=[...])`|';
+ const output = formatPromptContent(input, {
+ renderPhase: "pre-render",
+ replaceAsciiSymbols: true,
+ });
+ expect(output).toBe(
+ '|`cat <<\'EOF\' > file`|`write(path="file", content="…")`|\n|`sed -i \'s/old/new/\' file`|`edit(path="file", edits=[…])`|',
+ );
+ });
});