hataraku
Version:
An autonomous coding agent for building AI-powered development tools. The name "Hataraku" (働く) means "to work" in Japanese.
100 lines • 4.03 kB
JavaScript
import { z } from 'zod';
import * as fs from 'fs/promises';
import * as path from 'path';
import fg from 'fast-glob';
async function searchInFile(filePath, regex) {
const content = await fs.readFile(filePath, 'utf-8');
const lines = content.split('\n');
const matches = [];
const contextLines = 2; // Number of lines before and after match
for (let i = 0; i < lines.length; i++) {
if (regex.test(lines[i])) {
const start = Math.max(0, i - contextLines);
const end = Math.min(lines.length, i + contextLines + 1);
matches.push(`File: ${filePath}:${i + 1}`, '```', ...lines.slice(start, end).map((line, index) => {
const lineNum = start + index + 1;
const prefix = start + index === i ? ' > ' : ' ';
return `${lineNum}${prefix}${line}`;
}), '```\n');
}
}
return matches;
}
export const searchFilesTool = {
description: "Search for patterns in files using regular expressions. Provides context around matches.",
parameters: z.object({
path: z.string().describe('The path of the directory to search in (relative to the current working directory)'),
regex: z.string().describe('The regular expression pattern to search for'),
file_pattern: z.string().optional().describe('Glob pattern to filter files (e.g., "*.ts" for TypeScript files)')
}),
execute: async ({ path: dirPath, regex, file_pattern }) => {
try {
const absolutePath = path.resolve(process.cwd(), dirPath);
// Validate regex
try {
regex = new RegExp(regex);
}
catch (error) {
return {
isError: true,
content: [{
type: "text",
text: `Invalid regular expression: ${error instanceof Error ? error.message : 'Unknown error'}`
}]
};
}
// Find files to search
const pattern = path.join(absolutePath, file_pattern || '**/*');
const files = await fg(pattern, {
ignore: ['**/node_modules/**', '**/dist/**', '**/build/**'],
onlyFiles: true
});
if (files.length === 0) {
return {
content: [{
type: "text",
text: `No files found matching pattern: ${file_pattern || '*'}`
}]
};
}
// Search in files
const searchRegex = new RegExp(regex);
const allMatches = [];
for (const file of files) {
try {
const matches = await searchInFile(file, searchRegex);
allMatches.push(...matches);
}
catch (error) {
console.warn(`Error searching file ${file}: ${error instanceof Error ? error.message : 'Unknown error'}`);
// Continue with other files instead of returning null
continue;
}
}
if (allMatches.length === 0) {
return {
content: [{
type: "text",
text: `No matches found for pattern: ${regex.source}`
}]
};
}
return {
content: [{
type: "text",
text: allMatches.join('\n')
}]
};
}
catch (error) {
return {
isError: true,
content: [{
type: "text",
text: `Error searching files: ${error instanceof Error ? error.message : 'Unknown error'}`
}]
};
}
}
};
//# sourceMappingURL=search-files.js.map