Skip to content

Commit 998c90e

Browse files
MintCollectorclaude
andcommitted
fix: optimize SubagentLocator to avoid wasteful file I/O
- hasSubagents(): Remove redundant readFile after stat size check; stat.size > 0 is sufficient to confirm non-empty files - hasSubagentsSync(): Same optimization using statSync instead of reading entire file contents - subagentBelongsToSession(): Use createReadStream + readline to stream only the first line instead of reading entire file via readFile, then close the stream immediately Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent f23c581 commit 998c90e

1 file changed

Lines changed: 22 additions & 21 deletions

File tree

src/main/services/discovery/SubagentLocator.ts

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { buildSubagentsPath, extractBaseDir } from '@main/utils/pathDecoder';
1515
import { createLogger } from '@shared/utils/logger';
1616
import * as fs from 'fs';
1717
import * as path from 'path';
18+
import * as readline from 'readline';
1819

1920
import type { FileSystemProvider } from '@main/services/infrastructure/FileSystemProvider';
2021

@@ -51,16 +52,13 @@ export class SubagentLocator {
5152
);
5253

5354
// Check if at least one subagent file has content (not empty)
55+
// Uses stat() to check file size instead of reading file contents
5456
for (const entry of subagentFiles) {
5557
const filePath = path.join(newSubagentsPath, entry.name);
5658
try {
5759
const stats = await this.fsProvider.stat(filePath);
58-
// File must have size > 0 and contain at least one line
5960
if (stats.size > 0) {
60-
const content = await this.fsProvider.readFile(filePath);
61-
if (content.trim().length > 0) {
62-
return true;
63-
}
61+
return true;
6462
}
6563
} catch (error) {
6664
// Skip this file if we can't read it - log for debugging
@@ -76,9 +74,6 @@ export class SubagentLocator {
7674
return false;
7775
}
7876

79-
/**
80-
* Checks if a session has subagent files (session-specific only).
81-
* Only checks the NEW structure: {projectId}/{sessionId}/subagents/
8277
* Verifies that at least one subagent file has non-empty content.
8378
*
8479
* @param projectId - The project ID
@@ -96,16 +91,13 @@ export class SubagentLocator {
9691
);
9792

9893
// Check if at least one subagent file has content (not empty)
94+
// Uses statSync() to check file size instead of reading file contents
9995
for (const fileName of subagentFiles) {
10096
const filePath = path.join(newSubagentsPath, fileName);
10197
try {
10298
const stats = fs.statSync(filePath);
103-
// File must have size > 0 and contain at least one line
10499
if (stats.size > 0) {
105-
const content = fs.readFileSync(filePath, 'utf8');
106-
if (content.trim().length > 0) {
107-
return true;
108-
}
100+
return true;
109101
}
110102
} catch (error) {
111103
// Skip this file if we can't read it - log for debugging
@@ -210,17 +202,26 @@ export class SubagentLocator {
210202
*/
211203
async subagentBelongsToSession(filePath: string, sessionId: string): Promise<boolean> {
212204
try {
213-
// Read just the first line to check sessionId
214-
const content = await this.fsProvider.readFile(filePath);
215-
const firstNewline = content.indexOf('\n');
216-
const firstLine = firstNewline > 0 ? content.slice(0, firstNewline) : content;
205+
// Stream only the first line instead of reading the entire file
206+
const fileStream = this.fsProvider.createReadStream(filePath, { encoding: 'utf8' });
207+
const rl = readline.createInterface({
208+
input: fileStream,
209+
crlfDelay: Infinity,
210+
});
211+
212+
try {
213+
for await (const line of rl) {
214+
if (!line.trim()) continue;
217215

218-
if (!firstLine.trim()) {
219-
return false;
216+
const entry = JSON.parse(line) as { sessionId?: string };
217+
return entry.sessionId === sessionId;
218+
}
219+
} finally {
220+
rl.close();
221+
fileStream.destroy();
220222
}
221223

222-
const entry = JSON.parse(firstLine) as { sessionId?: string };
223-
return entry.sessionId === sessionId;
224+
return false;
224225
} catch (error) {
225226
// If we can't read or parse the file, don't include it - log for debugging
226227
logger.debug(`SubagentLocator: Could not parse file ${filePath}:`, error);

0 commit comments

Comments
 (0)