Files
oh-my-pi/packages/coding-agent/src/tools/grouped-file-output.ts
T
can1357 c8d6efa395 style(coding-agent/tools): removed tree glyph from grouped file headers
- Simplified diagnostic grouping output in the LSP utility to use plain `## file` headers.
- Adjusted AstEdit, AstGrep, and Grep tools to emit file headings without the `└─` tree prefix.
- Removed the GrepTool context legend text and its related guard variable from output construction.
2026-04-26 19:16:36 +02:00

97 lines
2.8 KiB
TypeScript

import path from "node:path";
/**
* One file's contribution to a grouped file output. The header itself is generated
* by `formatGroupedFiles` (single `#` for root files, `##` for files inside a dir);
* use `headerSuffix` to tack on extras like ` (1 replacement)`.
*/
export interface GroupedFileSection {
/** Optional suffix appended to the file header. */
headerSuffix?: string;
/** Body lines emitted into the textual model output. */
modelLines: string[];
/** Body lines emitted into the display output. Defaults to `modelLines`. */
displayLines?: string[];
/** When true, the file (and its header) is omitted entirely. */
skip?: boolean;
}
export interface GroupedFilesOutput {
model: string[];
display: string[];
}
/**
* Render a list of files as directory-grouped sections shared by grep, ast-grep,
* ast-edit, and the LSP diagnostic formatter.
*
* Layout:
* # dir/
* ## file.ts
* …body…
*
* # otherdir/
* ## other.ts
* …body…
*
* Files in the project root (directory `.`) become single-`#` headers without a
* `## file` line, matching the existing convention.
*/
export function formatGroupedFiles(
files: string[],
renderFile: (filePath: string) => GroupedFileSection,
): GroupedFilesOutput {
const filesByDirectory = new Map<string, string[]>();
for (const filePath of files) {
const directory = path.dirname(filePath).replace(/\\/g, "/");
if (!filesByDirectory.has(directory)) {
filesByDirectory.set(directory, []);
}
filesByDirectory.get(directory)!.push(filePath);
}
const model: string[] = [];
const display: string[] = [];
const pushSeparatorIfNeeded = () => {
if (model.length > 0) {
model.push("");
display.push("");
}
};
for (const [directory, dirFiles] of filesByDirectory) {
if (directory === ".") {
for (const filePath of dirFiles) {
const section = renderFile(filePath);
if (section.skip) continue;
pushSeparatorIfNeeded();
const header = `# ${path.basename(filePath)}${section.headerSuffix ?? ""}`;
model.push(header, ...section.modelLines);
display.push(header, ...(section.displayLines ?? section.modelLines));
}
continue;
}
const sections: Array<{ filePath: string; section: GroupedFileSection }> = [];
for (const filePath of dirFiles) {
const section = renderFile(filePath);
if (section.skip) continue;
sections.push({ filePath, section });
}
if (sections.length === 0) continue;
pushSeparatorIfNeeded();
const dirHeader = `# ${directory}/`;
model.push(dirHeader);
display.push(dirHeader);
for (const { filePath, section } of sections) {
const fileHeader = `## ${path.basename(filePath)}${section.headerSuffix ?? ""}`;
model.push(fileHeader, ...section.modelLines);
display.push(fileHeader, ...(section.displayLines ?? section.modelLines));
}
}
return { model, display };
}