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

141 lines 5.99 kB
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; /** * Git Add Tool * * Stage files for commit. */ import { Box, Text } from 'ink'; import { getCurrentMode } from '../../context/mode-context.js'; import { useTheme } from '../../hooks/useTheme.js'; import { jsonSchema, tool } from '../../types/core.js'; import { execGit, formatStatusChar, getDiffStats, parseGitStatus } from './utils.js'; // ============================================================================ // Execution // ============================================================================ const executeGitAdd = async (args) => { try { const gitArgs = ['add']; if (args.all) { gitArgs.push('-A'); } else if (args.update) { gitArgs.push('-u'); } else if (args.files && args.files.length > 0) { gitArgs.push(...args.files); } else { // Default to staging all changes gitArgs.push('-A'); } await execGit(gitArgs); // Get the new status to show what was staged const statusOutput = await execGit(['status', '--porcelain']); const { staged } = parseGitStatus(statusOutput); // Get diff stats for staged files const stats = await getDiffStats(true); for (const file of staged) { const fileStats = stats.get(file.path); if (fileStats) { file.additions = fileStats.additions; file.deletions = fileStats.deletions; } } if (staged.length === 0) { return 'No changes to stage.'; } const totalAdditions = staged.reduce((sum, f) => sum + f.additions, 0); const totalDeletions = staged.reduce((sum, f) => sum + f.deletions, 0); const lines = []; lines.push(`Staged ${staged.length} file(s) (+${totalAdditions}, -${totalDeletions}):`); lines.push(''); for (const file of staged.slice(0, 15)) { const char = formatStatusChar(file.status); const fileStats = file.additions || file.deletions ? ` (+${file.additions}, -${file.deletions})` : ''; lines.push(` ${char} ${file.path}${fileStats}`); } if (staged.length > 15) { lines.push(` ... and ${staged.length - 15} more files`); } return lines.join('\n'); } catch (error) { return `Error: ${error instanceof Error ? error.message : 'Unknown error'}`; } }; // ============================================================================ // Tool Definition // ============================================================================ const gitAddCoreTool = tool({ description: 'Stage files for commit. Use files array for specific files, all=true for all changes including untracked, or update=true for only tracked files.', inputSchema: jsonSchema({ type: 'object', properties: { files: { type: 'array', items: { type: 'string' }, description: 'Specific files or patterns to stage', }, all: { type: 'boolean', description: 'Stage all changes including untracked files (-A)', }, update: { type: 'boolean', description: 'Stage only already tracked files (-u)', }, }, required: [], }), // STANDARD - requires approval in normal mode, skipped in auto-accept needsApproval: () => { const mode = getCurrentMode(); return mode === 'normal'; }, execute: async (args, _options) => { return await executeGitAdd(args); }, }); // ============================================================================ // Formatter // ============================================================================ function GitAddFormatter({ args, result, }) { const { colors } = useTheme(); // Parse result for display let fileCount = 0; let additions = 0; let deletions = 0; if (result) { const countMatch = result.match(/Staged (\d+) file/); if (countMatch) fileCount = parseInt(countMatch[1], 10); const statsMatch = result.match(/\(\+(\d+), -(\d+)\)/); if (statsMatch) { additions = parseInt(statsMatch[1], 10); deletions = parseInt(statsMatch[2], 10); } } // Determine mode let mode = 'all'; if (args.files && args.files.length > 0) { mode = `${args.files.length} specific file(s)`; } else if (args.update) { mode = 'tracked files only'; } return (_jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsx(Text, { color: colors.tool, children: "\u2692 git_add" }), _jsxs(Box, { children: [_jsx(Text, { color: colors.secondary, children: "Mode: " }), _jsx(Text, { color: colors.text, children: mode })] }), fileCount > 0 && (_jsxs(Box, { children: [_jsx(Text, { color: colors.secondary, children: "Staging: " }), _jsxs(Text, { color: colors.text, children: [fileCount, " files "] }), _jsxs(Text, { color: colors.success, children: ["(+", additions] }), _jsx(Text, { color: colors.text, children: ", " }), _jsxs(Text, { color: colors.error, children: ["-", deletions] }), _jsx(Text, { color: colors.text, children: ")" })] })), result?.includes('No changes') && (_jsx(Box, { children: _jsx(Text, { color: colors.warning, children: "No changes to stage" }) }))] })); } const formatter = (args, result) => { return _jsx(GitAddFormatter, { args: args, result: result }); }; // ============================================================================ // Export // ============================================================================ export const gitAddTool = { name: 'git_add', tool: gitAddCoreTool, formatter, }; //# sourceMappingURL=git-add.js.map