'use strict'; const fs = require('fs'); const path = require('path'); function resolvePath(workspace, p) { if (path.isAbsolute(p)) return p; return path.join(workspace, p); } function readLines(content) { return content.split(/\r?\n/); } function applyMaxChars(text, maxChars) { if (!maxChars || text.length <= maxChars) return { text, truncated: false }; return { text: text.slice(0, maxChars), truncated: true }; } function readFileTool(workspace, args) { const target = resolvePath(workspace, args.path); const type = args.type || 'read'; try { const raw = fs.readFileSync(target, 'utf8'); if (type === 'read') { const lines = readLines(raw); const start = Math.max(1, args.start_line || 1); const end = Math.min(lines.length, args.end_line || lines.length); const slice = lines.slice(start - 1, end).join('\n'); const capped = applyMaxChars(slice, args.max_chars); return { success: true, type: 'read', path: target, line_start: start, line_end: end, content: capped.text, truncated: capped.truncated, }; } if (type === 'search') { const lines = readLines(raw); const query = args.query || ''; const caseSensitive = !!args.case_sensitive; const maxMatches = args.max_matches || 20; const before = args.context_before || 0; const after = args.context_after || 0; const matches = []; for (let i = 0; i < lines.length; i++) { const line = lines[i]; const hay = caseSensitive ? line : line.toLowerCase(); const needle = caseSensitive ? query : query.toLowerCase(); if (!needle) break; if (hay.includes(needle)) { const start = Math.max(0, i - before); const end = Math.min(lines.length - 1, i + after); const snippet = lines.slice(start, end + 1).join('\n'); matches.push({ id: `match_${matches.length + 1}`, line_start: start + 1, line_end: end + 1, hits: [i + 1], snippet, }); if (matches.length >= maxMatches) break; } } return { success: true, type: 'search', path: target, query, case_sensitive: caseSensitive, matches, }; } if (type === 'extract') { const lines = readLines(raw); const segments = Array.isArray(args.segments) ? args.segments : []; const extracted = segments.map((seg, idx) => { const start = Math.max(1, seg.start_line || 1); const end = Math.min(lines.length, seg.end_line || lines.length); return { label: seg.label || `segment_${idx + 1}`, line_start: start, line_end: end, content: lines.slice(start - 1, end).join('\n'), }; }); return { success: true, type: 'extract', path: target, segments: extracted, }; } return { success: false, error: '未知 read_file type' }; } catch (err) { return { success: false, error: err.message || String(err) }; } } module.exports = { readFileTool, resolvePath };