( toolName: string, params: Record<string, string>, )
| 190 | } |
| 191 | |
| 192 | export async function executeFileTool( |
| 193 | toolName: string, |
| 194 | params: Record<string, string>, |
| 195 | ): Promise<string> { |
| 196 | switch (toolName) { |
| 197 | case 'file_read': { |
| 198 | const filePath = (params.file_path || '').replace(/^\/+/, ''); |
| 199 | if (!filePath) return 'error: file_path is required'; |
| 200 | try { |
| 201 | const content = await idb.getFile(filePath); |
| 202 | if (content === null || content === undefined) { |
| 203 | return 'error: file not found'; |
| 204 | } |
| 205 | return typeof content === 'string' ? content : JSON.stringify(content, null, 2); |
| 206 | } catch (e) { |
| 207 | return `error: ${String(e)}`; |
| 208 | } |
| 209 | } |
| 210 | |
| 211 | case 'file_write': { |
| 212 | const filePath = (params.file_path || '').replace(/^\/+/, ''); |
| 213 | let content = params.content; |
| 214 | if (!filePath) return 'error: file_path is required'; |
| 215 | if (content === undefined) return 'error: content is required'; |
| 216 | // For JSON files, extract JSON (strip markdown wrapping) and validate |
| 217 | if (filePath.endsWith('.json')) { |
| 218 | content = extractJson(content); |
| 219 | try { |
| 220 | JSON.parse(content); |
| 221 | } catch (e) { |
| 222 | return `error: invalid JSON — ${String(e)}. Please regenerate valid JSON.`; |
| 223 | } |
| 224 | } |
| 225 | try { |
| 226 | const parts = filePath.split('/'); |
| 227 | const name = parts.pop()!; |
| 228 | const dir = parts.join('/'); |
| 229 | await idb.putTextFilesByJSON({ |
| 230 | files: [{ path: dir || undefined, name, content }], |
| 231 | }); |
| 232 | return 'success'; |
| 233 | } catch (e) { |
| 234 | return `error: ${String(e)}`; |
| 235 | } |
| 236 | } |
| 237 | |
| 238 | case 'file_list': { |
| 239 | const dir = (params.directory || '').replace(/^\/+/, '').replace(/\/+$/, ''); |
| 240 | try { |
| 241 | const result = await idb.listFiles(dir || '/'); |
| 242 | const items = result.files.map((f) => { |
| 243 | const name = f.path.split('/').pop() || f.path; |
| 244 | return f.type === 1 ? `[dir] ${name}` : `[file] ${name}`; |
| 245 | }); |
| 246 | if (items.length === 0) return 'empty directory'; |
| 247 | return items.join('\n'); |
| 248 | } catch (e) { |
| 249 | return `error: ${String(e)}`; |
no test coverage detected