MCPcopy Create free account
hub / github.com/FSoft-AI4Code/CodeWiki / handle_edit_doc_file

Function handle_edit_doc_file

codewiki/mcp/tools/doc_writer.py:113–214  ·  view source on GitHub ↗

Edit an existing documentation file (str_replace, insert, or undo).

(
    arguments: Dict[str, Any],
    store: SessionStore,
)

Source from the content-addressed store, hash-verified

111
112
113async def handle_edit_doc_file(
114 arguments: Dict[str, Any],
115 store: SessionStore,
116) -> str:
117 """Edit an existing documentation file (str_replace, insert, or undo)."""
118 session_id = arguments["session_id"]
119 session = store.get(session_id)
120 if session is None:
121 return json.dumps({"error": f"Session {session_id} not found or expired."})
122
123 filename = arguments["filename"]
124 doc_path = _safe_doc_path(session, filename)
125 if doc_path is None:
126 return json.dumps({"error": "Filename escapes output directory."})
127
128 command = arguments["command"]
129
130 if command == "undo":
131 # Undo via registry history
132 history = session.registry.get("file_history", {})
133 if isinstance(history, str):
134 history = json.loads(history)
135 path_history = history.get(str(doc_path), [])
136 if not path_history:
137 return json.dumps({"error": f"No edit history found for {filename}."})
138 old_content = path_history.pop()
139 history[str(doc_path)] = path_history
140 session.registry["file_history"] = history
141 await asyncio.to_thread(doc_path.write_text, old_content, "utf-8")
142
143 # Validate Mermaid after undo
144 mermaid_result = await _validate_mermaid(str(doc_path), filename)
145 return json.dumps({
146 "status": "undone",
147 "filename": filename,
148 "mermaid_validation": mermaid_result,
149 }, ensure_ascii=False)
150
151 if not await asyncio.to_thread(doc_path.exists):
152 return json.dumps({"error": f"File not found: {filename}. Use write_doc_file to create it."})
153
154 current_content = await asyncio.to_thread(doc_path.read_text, "utf-8")
155
156 if command == "str_replace":
157 old_str = arguments.get("old_str")
158 new_str = arguments.get("new_str", "")
159 if old_str is None:
160 return json.dumps({"error": "old_str is required for str_replace."})
161
162 occurrences = current_content.count(old_str)
163 if occurrences == 0:
164 return json.dumps({"error": f"old_str not found in {filename}."})
165 if occurrences > 1:
166 return json.dumps({"error": f"old_str appears {occurrences} times in {filename}. Make it unique."})
167
168 new_content = current_content.replace(old_str, new_str, 1)
169 # Save history only for edits that actually happen, so undo never
170 # pops a no-op entry left behind by a failed/rejected command.

Callers 2

call_toolFunction · 0.90

Calls 4

_safe_doc_pathFunction · 0.85
_validate_mermaidFunction · 0.85
_save_historyFunction · 0.85
getMethod · 0.80

Tested by 1