Skip to content

Commit be9a1c7

Browse files
catlog22claude
andcommitted
refactor(tool): simplify edit_file to parameter-based input only
- Remove JSON input support, use CLI parameters only - Remove line mode, keep text replacement only - Add sed as line operation alternative in tool-strategy.md - Update documentation to English Usage: ccw tool exec edit_file --path file.txt --old "old" --new "new" 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <[email protected]>
1 parent fcc811d commit be9a1c7

File tree

3 files changed

+71
-152
lines changed

3 files changed

+71
-152
lines changed

.claude/workflows/tool-strategy.md

Lines changed: 48 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -14,71 +14,66 @@
1414

1515
**When to Use**: Edit tool fails 1+ times on same file
1616

17-
### update Mode (Default)
17+
### Usage
1818

1919
**Best for**: Code block replacements, function rewrites, multi-line changes
2020

2121
```bash
22-
ccw tool exec edit_file '{
23-
"path": "file.py",
24-
"oldText": "def old():\n pass",
25-
"newText": "def new():\n return True"
26-
}'
22+
ccw tool exec edit_file --path "file.py" --old "def old():
23+
pass" --new "def new():
24+
return True"
2725
```
2826

29-
### line Mode (Precise Line Operations)
27+
**Parameters**:
28+
- `--path`: File path to edit
29+
- `--old`: Text to find and replace
30+
- `--new`: New text to insert
3031

31-
**Best for**: Config files, line insertions/deletions, precise line number control
32+
**Features**:
33+
- ✅ Exact text matching (precise and predictable)
34+
- ✅ Auto line ending adaptation (CRLF/LF)
35+
- ✅ No JSON escaping issues
36+
- ✅ Multi-line text supported with quotes
37+
38+
### Fallback Strategy
39+
40+
1. **Edit fails 1+ times** → Use `ccw tool exec edit_file`
41+
2. **Still fails** → Use Write to recreate file
42+
43+
## ⚡ sed Line Operations (Line Mode Alternative)
44+
45+
**When to Use**: Precise line number control (insert, delete, replace specific lines)
46+
47+
### Common Operations
3248

3349
```bash
34-
# Insert after specific line
35-
ccw tool exec edit_file '{
36-
"path": "config.txt",
37-
"mode": "line",
38-
"operation": "insert_after",
39-
"line": 10,
40-
"text": "new config line"
41-
}'
42-
43-
# Delete line range
44-
ccw tool exec edit_file '{
45-
"path": "log.txt",
46-
"mode": "line",
47-
"operation": "delete",
48-
"line": 5,
49-
"end_line": 8
50-
}'
51-
52-
# Replace specific line
53-
ccw tool exec edit_file '{
54-
"path": "script.sh",
55-
"mode": "line",
56-
"operation": "replace",
57-
"line": 3,
58-
"text": "#!/bin/bash"
59-
}'
60-
```
50+
# Insert after line 10
51+
sed -i '10a\new line content' file.txt
6152

62-
**Operations**:
63-
- `insert_before`: Insert text before specified line
64-
- `insert_after`: Insert text after specified line
65-
- `replace`: Replace line or line range
66-
- `delete`: Delete line or line range
53+
# Insert before line 5
54+
sed -i '5i\new line content' file.txt
6755

68-
### Mode Selection Guide
56+
# Delete line 3
57+
sed -i '3d' file.txt
6958

70-
| Scenario | Mode | Reason |
71-
|----------|------|--------|
72-
| Code refactoring | update | Content-driven replacement |
73-
| Function rewrite | update | Simple oldText/newText |
74-
| Config line change | line | Precise line number control |
75-
| Insert at specific position | line | Exact line number needed |
76-
| Delete line range | line | Line-based operation |
59+
# Delete lines 5-8
60+
sed -i '5,8d' file.txt
7761

78-
### Fallback Strategy
62+
# Replace line 3 content
63+
sed -i '3c\replacement line' file.txt
64+
65+
# Replace lines 3-5 content
66+
sed -i '3,5c\single replacement line' file.txt
67+
```
68+
69+
### Operation Reference
7970

80-
1. **Edit fails 1+ times** → Use `ccw tool exec edit_file` (update mode)
81-
2. **update mode fails** → Try line mode with precise line numbers
82-
3. **All fails** → Use Write to recreate file
71+
| Operation | Command | Example |
72+
|-----------|---------|---------|
73+
| Insert after | `Na\text` | `sed -i '10a\new' file` |
74+
| Insert before | `Ni\text` | `sed -i '5i\new' file` |
75+
| Delete line | `Nd` | `sed -i '3d' file` |
76+
| Delete range | `N,Md` | `sed -i '5,8d' file` |
77+
| Replace line | `Nc\text` | `sed -i '3c\new' file` |
8378

84-
**Default mode**: update (exact matching with line ending adaptation)
79+
**Note**: Use `sed -i` for in-place file modification (works in Git Bash on Windows)

ccw/src/cli.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,9 +108,12 @@ export function run(argv) {
108108

109109
// Tool command
110110
program
111-
.command('tool [subcommand] [args] [json]')
111+
.command('tool [subcommand] [args]')
112112
.description('Execute CCW tools')
113-
.action((subcommand, args, json) => toolCommand(subcommand, args, { json }));
113+
.option('--path <path>', 'File path (for edit_file)')
114+
.option('--old <text>', 'Old text to replace (for edit_file)')
115+
.option('--new <text>', 'New text (for edit_file)')
116+
.action((subcommand, args, options) => toolCommand(subcommand, args, options));
114117

115118
program.parse(argv);
116119
}

ccw/src/commands/tool.js

Lines changed: 18 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -66,80 +66,13 @@ async function schemaAction(options) {
6666
}
6767
}
6868

69-
/**
70-
* Read from stdin if available
71-
*/
72-
async function readStdin() {
73-
// Check if stdin is a TTY (interactive terminal)
74-
if (process.stdin.isTTY) {
75-
return null;
76-
}
77-
78-
return new Promise((resolve, reject) => {
79-
let data = '';
80-
81-
process.stdin.setEncoding('utf8');
82-
83-
process.stdin.on('readable', () => {
84-
let chunk;
85-
while ((chunk = process.stdin.read()) !== null) {
86-
data += chunk;
87-
}
88-
});
89-
90-
process.stdin.on('end', () => {
91-
resolve(data.trim() || null);
92-
});
93-
94-
process.stdin.on('error', (err) => {
95-
reject(err);
96-
});
97-
});
98-
}
99-
100-
/**
101-
* Smart JSON parser with Windows path handling
102-
*/
103-
function parseJsonWithPathFix(jsonString) {
104-
try {
105-
// Try normal parse first
106-
return JSON.parse(jsonString);
107-
} catch (firstError) {
108-
// If parsing fails, try to fix Windows paths
109-
try {
110-
// Pattern: "path": "X:\..." or "path":"X:\..."
111-
const fixedJson = jsonString.replace(
112-
/("(?:path|file|target|source|dest|destination)":\s*")([A-Za-z]:[^"]+)"/g,
113-
(match, prefix, path) => {
114-
// Convert backslashes to forward slashes (universal)
115-
const fixedPath = path.replace(/\\/g, '/');
116-
return `${prefix}${fixedPath}"`;
117-
}
118-
);
119-
120-
return JSON.parse(fixedJson);
121-
} catch (secondError) {
122-
// If still fails, throw original error with helpful message
123-
const errorMsg = firstError.message;
124-
const hint = errorMsg.includes('escaped character') || errorMsg.includes('position')
125-
? '\n\n' + chalk.yellow('Hint: Windows paths in JSON need forward slashes or double backslashes:') +
126-
'\n ' + chalk.green('✓ "D:/Claude_dms3/file.md"') +
127-
'\n ' + chalk.green('✓ "D:\\\\Claude_dms3\\\\file.md"') +
128-
'\n ' + chalk.red('✗ "D:\\Claude_dms3\\file.md"')
129-
: '';
130-
131-
throw new Error(errorMsg + hint);
132-
}
133-
}
134-
}
135-
13669
/**
13770
* Execute a tool with given parameters
13871
*/
139-
async function execAction(toolName, jsonInput, options) {
72+
async function execAction(toolName, options) {
14073
if (!toolName) {
14174
console.error(chalk.red('Tool name is required'));
142-
console.error(chalk.gray('Usage: ccw tool exec <tool-name> \'{"param": "value"}\''));
75+
console.error(chalk.gray('Usage: ccw tool exec edit_file --path file.txt --old "old" --new "new"'));
14376
process.exit(1);
14477
}
14578

@@ -150,34 +83,22 @@ async function execAction(toolName, jsonInput, options) {
15083
process.exit(1);
15184
}
15285

153-
// Parse JSON input (default format)
154-
let params = {};
86+
// Build params from CLI options
87+
const params = {};
15588

156-
if (jsonInput) {
157-
try {
158-
params = parseJsonWithPathFix(jsonInput);
159-
} catch (error) {
160-
console.error(chalk.red(`Invalid JSON: ${error.message}`));
89+
if (toolName === 'edit_file') {
90+
if (!options.path || !options.old || !options.new) {
91+
console.error(chalk.red('edit_file requires --path, --old, and --new parameters'));
92+
console.error(chalk.gray('Usage: ccw tool exec edit_file --path file.txt --old "old text" --new "new text"'));
16193
process.exit(1);
16294
}
163-
}
164-
165-
// Check for stdin input (for piped commands)
166-
const stdinData = await readStdin();
167-
if (stdinData) {
168-
// If tool has an 'input' parameter, use it
169-
// Otherwise, try to parse stdin as JSON and merge with params
170-
if (tool.parameters?.properties?.input) {
171-
params.input = stdinData;
172-
} else {
173-
try {
174-
const stdinJson = JSON.parse(stdinData);
175-
params = { ...stdinJson, ...params };
176-
} catch {
177-
// If not JSON, store as 'input' anyway
178-
params.input = stdinData;
179-
}
180-
}
95+
params.path = options.path;
96+
params.oldText = options.old;
97+
params.newText = options.new;
98+
} else {
99+
console.error(chalk.red(`Tool "${toolName}" is not supported via CLI parameters`));
100+
console.error(chalk.gray('Currently only edit_file is supported'));
101+
process.exit(1);
181102
}
182103

183104
// Execute tool
@@ -200,7 +121,7 @@ export async function toolCommand(subcommand, args, options) {
200121
await schemaAction({ name: args });
201122
break;
202123
case 'exec':
203-
await execAction(args, options.json, options);
124+
await execAction(args, options);
204125
break;
205126
default:
206127
console.log(chalk.bold.cyan('\nCCW Tool System\n'));
@@ -209,9 +130,9 @@ export async function toolCommand(subcommand, args, options) {
209130
console.log(chalk.gray(' schema [name] Show tool schema (JSON)'));
210131
console.log(chalk.gray(' exec <name> Execute a tool'));
211132
console.log();
212-
console.log('Examples:');
133+
console.log('Usage:');
213134
console.log(chalk.gray(' ccw tool list'));
214135
console.log(chalk.gray(' ccw tool schema edit_file'));
215-
console.log(chalk.gray(' ccw tool exec edit_file \'{"path":"file.txt","oldText":"old","newText":"new"}\''));
136+
console.log(chalk.gray(' ccw tool exec edit_file --path file.txt --old "old text" --new "new text"'));
216137
}
217138
}

0 commit comments

Comments
 (0)