Workaround for write_file failures caused by special characters (apostrophes, backticks, template literals) using a Python heredoc script, plus a reliable TypeS
复制下面这句话,粘贴给 Claude Code、Codex、Cursor 等 AI 编程工具,它会读取安装说明并在你确认后完成安装。
请阅读 https://ai.atlankj.com/install/asset/gh-write-special-chars-ts-check-2cde96d97667 ,按照其中的说明把「write-special-chars-ts-check」安装到你(当前 AI 工具)中。执行前先告诉我将运行的命令和写入的位置,等我确认。
查看 AI 将读取的安装说明正在读取 GitHub 原文…
内容来自 GitHub 原始文件,由原作者维护。在 GitHub 查看
The write_file tool may fail with [ERROR] unknown error when file content
contains special characters such as:
')`)`${variable}`) common in TypeScript/JavaScriptThis is especially common when writing TypeScript, JavaScript, shell scripts, or any source file with string interpolation syntax.
Additionally, after writing TypeScript files, you need to verify they are
type-correct — but common methods like npx tsc or ./node_modules/.bin/tsc
can fail with [ERROR] unknown error due to timeout or symlink resolution
issues. The reliable method is to call the TypeScript binary directly.
Write a small Python script to /tmp/ that uses triple-quoted strings to
embed the file content, then execute it with python3.
"""...""")./tmp/ — its content is plain enough
that write_file will succeed (no problematic characters in the wrapper).run_shell: python3 /tmp/write_<name>.py| Character | How to handle |
|---|---|
Backslash \ | Escape as \\ |
Triple double-quote """ | Escape as \"\"\" or use ''' strings instead |
Everything else (backticks, $, ', {}) | No escaping needed |
#!/usr/bin/env python3
content = """
<YOUR FILE CONTENT HERE>
""".lstrip("\n")
with open("/path/to/target/file.ts", "w") as f:
f.write(content)
print("File written successfully.")
Suppose you need to write a TypeScript file with template literals and
apostrophes that causes write_file to fail:
Step 1 — Write the Python helper to /tmp/:
Use write_file with path /tmp/write_greeting.py and content:
#!/usr/bin/env python3
content = """
export function greet(name: string): string {
const msg = `Hello, ${name}! It's a great day.`;
console.log(`Greeting: ${msg}`);
return msg;
}
""".lstrip("\n")
with open("/app/src/greeting.ts", "w") as f:
f.write(content)
print("Written: /app/src/greeting.ts")
Step 2 — Execute the helper:
python3 /tmp/write_greeting.py
Step 3 — Verify the file was created:
cat /app/src/greeting.ts
After writing TypeScript files, always verify they introduce zero new type
errors. Use the direct binary path — not npx or .bin symlinks, which
are prone to timeout and path-resolution failures.
node node_modules/typescript/bin/tsc --noEmit 2>&1 | grep "src/greeting.ts"
Key points:
node node_modules/typescript/bin/tsc — invokes TypeScript directly via
node, bypassing npx overhead and symlink resolution entirely.--noEmit — type-checks only; does not write output files.2>&1 — merges stderr into stdout so grep can filter everything.| grep "<filename>" — filters output to only lines mentioning your
newly-written file(s), so pre-existing errors in other files do not
create false alarms.| Method | Risk |
|---|---|
npx tsc --noEmit | Frequently returns [ERROR] unknown error (timeout, network, PATH issues) |
./node_modules/.bin/tsc --noEmit | Symlink resolution can fail in some environments |
node node_modules/typescript/bin/tsc --noEmit | Reliable — direct JS execution, no symlinks, no network |
When you've written several files, pipe through a more specific grep pattern:
node node_modules/typescript/bin/tsc --noEmit 2>&1 | grep -E "src/(greeting|utils|component)\.ts"
Or use a directory prefix to catch all new files in one folder:
node node_modules/typescript/bin/tsc --noEmit 2>&1 | grep "src/myfeature/"
Example clean output (no new errors):
(no output)
Example with errors:
src/greeting.ts(3,14): error TS2345: Argument of type 'number' is not assignable to parameter of type 'string'.
Step 1 — Write the Python helper to /tmp/:
Use write_file with path /tmp/write_settings_files.py:
#!/usr/bin/env python3
import os
files = {
"/app/src/settings/settings-keys.ts": """
export const SETTINGS_KEYS = {
theme: 'app.theme',
language: 'app.language',
} as const;
export type SettingKey = keyof typeof SETTINGS_KEYS;
""".lstrip("\n"),
"/app/src/settings/settings-store.ts": """
import { SETTINGS_KEYS, SettingKey } from './settings-keys';
export class SettingsStore {
private data: Record<string, string> = {};
get(key: SettingKey): string | undefined {
return this.data[SETTINGS_KEYS[key]];
}
set(key: SettingKey, value: string): void {
this.data[SETTINGS_KEYS[key]] = value;
}
}
""".lstrip("\n"),
}
for path, content in files.items():
os.makedirs(os.path.dirname(path), exist_ok=True)
with open(path, "w") as f:
f.write(content)
print(f"Written: {path}")
Step 2 — Execute the helper:
python3 /tmp/write_settings_files.py
Step 3 — Verify file contents:
cat /app/src/settings/settings-keys.ts
cat /app/src/settings/settings-store.ts
Step 4 — Type-check only the new files:
cd /app && node node_modules/typescript/bin/tsc --noEmit 2>&1 | grep "src/settings/"
Expected output if all is well: (empty — no errors in the new files)
Step 5 — Optional cleanup:
rm /tmp/write_settings_files.py
write_file returns [ERROR] unknown error for a specific file.For writing several problematic files in one pass, consolidate them into a single Python script:
#!/usr/bin/env python3
import os
files = {
"/app/src/component.tsx": """
import React from 'react';
const App = () => (
<div className={`container`}>
<h1>It's working!</h1>
</div>
);
export default App;
""".lstrip("\n"),
"/app/src/utils.ts": """
export const format = (val: number) => `Value: ${val.toFixed(2)}`;
""".lstrip("\n"),
}
for path, content in files.items():
os.makedirs(os.path.dirname(path), exist_ok=True)
with open(path, "w") as f:
f.write(content)
print(f"Written: {path}")
.py file can be inspected if needed.node invocation avoids npx/symlink failures.rm /tmp/write_*.py after all files are written.