hataraku
Version:
An autonomous coding agent for building AI-powered development tools. The name "Hataraku" (働く) means "to work" in Japanese.
156 lines • 6.43 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.listFiles = listFiles;
const fast_glob_1 = __importDefault(require("fast-glob"));
const os_1 = __importDefault(require("os"));
const path = __importStar(require("path"));
const path_1 = require("../../utils/path");
/**
* Lists files in a directory with safety checks for root and home directories.
*
* @param dirPath - The directory path to list files from
* @param recursive - Whether to list files recursively in subdirectories
* @param limit - Maximum number of files to return
* @returns A tuple containing [array of file paths, boolean indicating if limit was reached]
* @throws Will throw an error if the globbing process times out (via internal globbyLevelByLevel function)
*
* @example
* ```typescript
* // List up to 100 files in the current directory (non-recursive)
* const [files, limitReached] = await listFiles('.', false, 100);
*
* // List up to 1000 files recursively
* const [allFiles, hitLimit] = await listFiles('./src', true, 1000);
* ```
*/
async function listFiles(dirPath, recursive, limit) {
const absolutePath = path.resolve(dirPath);
// Do not allow listing files in root or home directory, which cline tends to want to do when the user's prompt is vague.
const root = process.platform === "win32" ? path.parse(absolutePath).root : "/";
const isRoot = (0, path_1.arePathsEqual)(absolutePath, root);
if (isRoot) {
return [[root], false];
}
const homeDir = os_1.default.homedir();
const isHomeDir = (0, path_1.arePathsEqual)(absolutePath, homeDir);
if (isHomeDir) {
return [[homeDir], false];
}
const dirsToIgnore = [
"node_modules",
"__pycache__",
"env",
"venv",
"target/dependency",
"build/dependencies",
"dist",
"out",
"bundle",
"vendor",
"tmp",
"temp",
"deps",
"pkg",
"Pods",
".*", // '!**/.*' excludes hidden directories, while '!**/.*/**' excludes only their contents. This way we are at least aware of the existence of hidden directories.
].map((dir) => `**/${dir}/**`);
const options = {
cwd: dirPath,
dot: true, // do not ignore hidden files/directories
absolute: true,
markDirectories: true, // Append a / on any directories matched (/ is used on windows as well, so dont use path.sep)
gitignore: recursive, // fast-glob also supports gitignore
ignore: recursive ? dirsToIgnore : undefined, // just in case there is no gitignore, we ignore sensible defaults
onlyFiles: false, // true by default, false means it will list directories on their own too
};
// * globs all files in one dir, ** globs files in nested directories
const files = recursive ? await globbyLevelByLevel(limit, options) : (await (0, fast_glob_1.default)("*", options)).slice(0, limit);
return [files, files.length >= limit];
}
/**
* Performs breadth-first traversal of directory structure level by level up to a limit.
*
* Features:
* - Queue-based approach ensures proper breadth-first traversal
* - Processes directory patterns level by level
* - Captures a representative sample of the directory structure up to the limit
* - Minimizes risk of missing deeply nested files
*
* @param limit - Maximum number of files to return
* @param options - Options to pass to fast-glob
* @returns Array of file paths up to the specified limit
* @throws Will throw an error if the globbing process times out (after 10 seconds)
*
* Notes:
* - Relies on fast-glob to mark directories with /
* - Potential for loops if symbolic links reference back to parent
* - Timeout mechanism prevents infinite loops
*/
async function globbyLevelByLevel(limit, options) {
let results = new Set();
let queue = ["*"];
const globbingProcess = async () => {
while (queue.length > 0 && results.size < limit) {
const pattern = queue.shift();
const filesAtLevel = await (0, fast_glob_1.default)(pattern, options);
for (const file of filesAtLevel) {
if (results.size >= limit) {
break;
}
results.add(file);
if (file.endsWith("/")) {
queue.push(`${file}*`);
}
}
}
return Array.from(results).slice(0, limit);
};
// Timeout after 10 seconds and return partial results
const timeoutPromise = new Promise((_, reject) => {
setTimeout(() => reject(new Error("Globbing timeout")), 10_000);
});
try {
return await Promise.race([globbingProcess(), timeoutPromise]);
}
catch (error) {
console.warn("Globbing timed out, returning partial results");
return Array.from(results);
}
}
//# sourceMappingURL=list-files.js.map