UNPKG

@nanocollective/nanocoder

Version:

A local-first CLI coding agent that brings the power of agentic coding tools like Claude Code and Gemini CLI to local models or controlled APIs like OpenRouter

88 lines 3.48 kB
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import { constants } from 'node:fs'; import { access, rm, stat } from 'node:fs/promises'; import { resolve } from 'node:path'; import { Box, Text } from 'ink'; import React from 'react'; import ToolMessage from '../../components/tool-message.js'; import { ThemeContext } from '../../hooks/useTheme.js'; import { jsonSchema, tool } from '../../types/core.js'; import { invalidateCache } from '../../utils/file-cache.js'; import { isValidFilePath, resolveFilePath } from '../../utils/path-validation.js'; const executeDeleteFile = async (args) => { const absPath = resolve(args.path); const fileStat = await stat(absPath); if (fileStat.isDirectory()) { return `Error: "${args.path}" is a directory. Use execute_bash with rm -r for directory removal.`; } await rm(absPath); invalidateCache(absPath); return `File deleted: ${args.path}`; }; const deleteFileCoreTool = tool({ description: 'Delete a file. Only deletes single files, not directories. Always requires user approval.', inputSchema: jsonSchema({ type: 'object', properties: { path: { type: 'string', description: 'The relative path to the file to delete.', }, }, required: ['path'], }), // High risk: destructive operation, always requires approval needsApproval: true, execute: async (args, _options) => { return await executeDeleteFile(args); }, }); const DeleteFileFormatter = React.memo(({ args, result }) => { const themeContext = React.useContext(ThemeContext); if (!themeContext) { throw new Error('ThemeContext is required'); } const { colors } = themeContext; const messageContent = (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: colors.tool, children: "\u2692 delete_file" }), _jsxs(Box, { children: [_jsx(Text, { color: colors.secondary, children: "Path: " }), _jsx(Text, { color: colors.text, children: args.path })] }), result && (_jsxs(Box, { children: [_jsx(Text, { color: colors.secondary, children: "Result: " }), _jsx(Text, { color: colors.text, children: result })] }))] })); return _jsx(ToolMessage, { message: messageContent, hideBox: true }); }); const deleteFileFormatter = (args, result) => { return _jsx(DeleteFileFormatter, { args: args, result: result }); }; const deleteFileValidator = async (args) => { if (!isValidFilePath(args.path)) { return { valid: false, error: `⚒ Invalid file path: "${args.path}". Path must be relative and within the project directory.`, }; } try { const cwd = process.cwd(); resolveFilePath(args.path, cwd); } catch (error) { const errorMessage = error instanceof Error ? error.message : 'Unknown error'; return { valid: false, error: `⚒ Path validation failed: ${errorMessage}`, }; } const absPath = resolve(args.path); try { await access(absPath, constants.F_OK); } catch { return { valid: false, error: `⚒ File does not exist: "${args.path}"`, }; } return { valid: true }; }; export const deleteFileTool = { name: 'delete_file', tool: deleteFileCoreTool, formatter: deleteFileFormatter, validator: deleteFileValidator, }; //# sourceMappingURL=delete-file.js.map