Skip to content

Commit 292100f

Browse files
basiclinesCopilot
andcommitted
fix: count files/LOC by scanning output directory
Replace unreliable event-based file tracking (tool name heuristics didn't match actual SDK tool names → 0 files) with a post-compilation directory scan. Skips node_modules, .git, vendor, target, and other common dependency/build folders. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent b0bbbb4 commit 292100f

1 file changed

Lines changed: 30 additions & 42 deletions

File tree

scripts/compile.ts

Lines changed: 30 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,6 @@ interface CompileMetrics {
7979
outputTokens: number;
8080
reasoningTokens: number;
8181
toolCalls: number;
82-
filesWritten: Set<string>;
83-
filesDeleted: Set<string>;
8482
lastAssistantMessage: string;
8583
errors: string[];
8684
}
@@ -417,14 +415,34 @@ function formatDuration(ms: number): string {
417415
}
418416

419417
/** Count LOC across files the agent actually wrote (ignores node_modules etc.) */
420-
function countAgentOutput(filesWritten: Set<string>): { files: number; lines: number } {
421-
let lines = 0;
418+
const SCAN_IGNORE = new Set([
419+
"node_modules", ".git", "__pycache__", ".mypy_cache", ".pytest_cache",
420+
"target", "vendor", ".build", "build", "DerivedData", ".gradle",
421+
".dart_tool", ".packages", "Pods",
422+
]);
423+
424+
function countOutputDir(dir: string): { files: number; lines: number } {
422425
let files = 0;
423-
for (const fp of filesWritten) {
424-
if (!existsSync(fp)) continue;
425-
files++;
426-
lines += readFileSync(fp, "utf-8").split("\n").length;
427-
}
426+
let lines = 0;
427+
if (!existsSync(dir)) return { files, lines };
428+
429+
const walk = (d: string) => {
430+
for (const entry of readdirSync(d, { withFileTypes: true })) {
431+
if (entry.name.startsWith(".") || SCAN_IGNORE.has(entry.name)) continue;
432+
const full = join(d, entry.name);
433+
if (entry.isDirectory()) {
434+
walk(full);
435+
} else if (entry.isFile()) {
436+
files++;
437+
try {
438+
lines += readFileSync(full, "utf-8").split("\n").length;
439+
} catch {
440+
/* binary or unreadable — skip */
441+
}
442+
}
443+
}
444+
};
445+
walk(dir);
428446
return { files, lines };
429447
}
430448

@@ -627,20 +645,18 @@ function printSummary(
627645
passNumber = 1,
628646
): void {
629647
const elapsed = Date.now() - metrics.startTime;
630-
const { files, lines } = countAgentOutput(metrics.filesWritten);
631-
const deleted = metrics.filesDeleted.size;
648+
const { files, lines } = countOutputDir(outDir);
632649
const totalTokens = metrics.inputTokens + metrics.outputTokens;
633650

634651
const tokenDetail =
635652
`(${metrics.inputTokens.toLocaleString()} in / ${metrics.outputTokens.toLocaleString()} out` +
636653
`${metrics.reasoningTokens ? ` / ${metrics.reasoningTokens.toLocaleString()} reasoning` : ""})`;
637654

638655
const passLabel = passNumber > 1 ? ` (pass ${passNumber})` : "";
639-
const filesLine = deleted > 0 ? `${files} written, ${deleted} deleted` : `${files} written`;
640656
const body = [
641657
`Model: ${config.model}${config.effort ? ` (${config.effort} effort)` : ""}`,
642658
`Time: ${formatDuration(elapsed)}`,
643-
`Files: ${filesLine}`,
659+
`Files: ${files}`,
644660
`LOC: ~${lines.toLocaleString()} lines`,
645661
`Tokens: ~${totalTokens.toLocaleString()} total ${tokenDetail}`,
646662
`Tools: ${metrics.toolCalls} calls`,
@@ -719,8 +735,6 @@ async function cmdBuild(
719735
outputTokens: 0,
720736
reasoningTokens: 0,
721737
toolCalls: 0,
722-
filesWritten: new Set(),
723-
filesDeleted: new Set(),
724738
lastAssistantMessage: "",
725739
errors: [],
726740
};
@@ -894,34 +908,8 @@ your final message like this:
894908
metrics.reasoningTokens += event.data.reasoningTokens ?? 0;
895909
});
896910

897-
session.on("tool.execution_start", (event) => {
911+
session.on("tool.execution_start", () => {
898912
metrics.toolCalls++;
899-
const { toolName } = event.data;
900-
const args = event.data.arguments as Record<string, unknown> | undefined;
901-
if (args) {
902-
const filePath = (args.path ?? args.file_path ?? args.filePath ?? args.file) as string | undefined;
903-
const isWrite =
904-
toolName === "edit_file" ||
905-
toolName === "create_file" ||
906-
toolName === "write_file" ||
907-
toolName === "create" ||
908-
toolName === "edit" ||
909-
toolName === "write" ||
910-
toolName === "write_to_file" ||
911-
toolName === "str_replace_editor" ||
912-
toolName === "insert_edit_into_file" ||
913-
toolName.includes("edit") ||
914-
toolName.includes("create") ||
915-
toolName.includes("write");
916-
const isDelete = toolName === "delete_file" || toolName === "delete" || toolName.includes("delete");
917-
918-
if (isDelete && filePath) {
919-
metrics.filesDeleted.add(filePath);
920-
metrics.filesWritten.delete(filePath);
921-
} else if (isWrite && filePath) {
922-
metrics.filesWritten.add(filePath);
923-
}
924-
}
925913
});
926914

927915
session.on("session.error", (event) => {

0 commit comments

Comments
 (0)