feat: allow goose askai bot to search goose codebase (#7508)
Signed-off-by: The-Best-Codes <106822363+The-Best-Codes@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
|
||||
const GITHUB_BASE_URL = "https://github.com/block/goose/blob/main";
|
||||
|
||||
function getCodebaseDir(): string {
|
||||
return process.env.CODEBASE_PATH || path.join(process.cwd(), "../..");
|
||||
}
|
||||
|
||||
function generateGitHubUrl(filePath: string, startLine?: number): string {
|
||||
const url = `${GITHUB_BASE_URL}/${filePath}`;
|
||||
if (startLine && startLine > 0) {
|
||||
return `${url}#L${startLine}`;
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
||||
function getCodeChunk(
|
||||
filePath: string,
|
||||
startLine: number = 0,
|
||||
lineCount: number = 200,
|
||||
): {
|
||||
filePath: string;
|
||||
content: string;
|
||||
totalLines: number;
|
||||
githubUrl: string;
|
||||
} {
|
||||
const baseDir = path.resolve(getCodebaseDir());
|
||||
const fullPath = path.resolve(path.join(baseDir, filePath));
|
||||
|
||||
if (!fullPath.startsWith(baseDir + "/")) {
|
||||
throw new Error("Invalid file path - directory traversal not allowed");
|
||||
}
|
||||
|
||||
if (!fs.existsSync(fullPath)) {
|
||||
throw new Error(`File not found: ${filePath}`);
|
||||
}
|
||||
|
||||
const stat = fs.statSync(fullPath);
|
||||
if (stat.isDirectory()) {
|
||||
throw new Error(
|
||||
`Path is a directory, not a file: ${filePath}. Use search_codebase with scope to explore directories, or list_codebase_files to list directory contents.`,
|
||||
);
|
||||
}
|
||||
|
||||
const content = fs.readFileSync(fullPath, "utf-8");
|
||||
const lines = content.split("\n");
|
||||
const totalLines = lines.length;
|
||||
|
||||
const actualStart = Math.max(0, Math.min(startLine, lines.length - 1));
|
||||
const actualEnd = Math.min(actualStart + lineCount, lines.length);
|
||||
const chunkLines = lines.slice(actualStart, actualEnd);
|
||||
|
||||
const numberedContent = chunkLines
|
||||
.map((line, i) => `${actualStart + i + 1}: ${line}`)
|
||||
.join("\n");
|
||||
|
||||
return {
|
||||
filePath,
|
||||
content: numberedContent,
|
||||
totalLines,
|
||||
githubUrl: generateGitHubUrl(
|
||||
filePath,
|
||||
actualStart > 0 ? actualStart + 1 : undefined,
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
export function viewCodebaseFiles(
|
||||
filePaths: string | string[],
|
||||
startLine: number = 0,
|
||||
lineCount: number = 200,
|
||||
): string {
|
||||
const paths = Array.isArray(filePaths) ? filePaths : [filePaths];
|
||||
|
||||
const results = paths.map((filePath) => {
|
||||
const chunk = getCodeChunk(filePath, startLine, lineCount);
|
||||
const ext = path.extname(filePath).slice(1) || "text";
|
||||
const lineInfo =
|
||||
startLine > 0
|
||||
? ` (lines ${startLine + 1}-${Math.min(startLine + lineCount, chunk.totalLines)} of ${chunk.totalLines})`
|
||||
: ` (${chunk.totalLines} lines total)`;
|
||||
|
||||
return `**${chunk.filePath}**${lineInfo}\nGitHub: <${chunk.githubUrl}>\n\`\`\`${ext}\n${chunk.content}\n\`\`\``;
|
||||
});
|
||||
|
||||
return results.join("\n\n---\n\n");
|
||||
}
|
||||
Reference in New Issue
Block a user