Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/extension/agents/claude/node/claudeCodeSessionService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,8 @@ export class ClaudeCodeSessionService implements IClaudeCodeSessionService {
const summaries = new Map<string, SummaryEntry>();
try {
// Read and parse the JSONL file
const content = await this._fileSystem.readFile(fileUri);
// Claude session files can be large (>5MB), so we disable the size limit
const content = await this._fileSystem.readFile(fileUri, true);
Comment on lines +340 to +341
Copy link

Copilot AI Jan 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Passing disableLimit=true removes the 5MB safeguard for these session files. Since this code auto-loads all *.jsonl sessions, a very large/corrupted file could now cause high memory usage or extension host instability. Consider adding a separate (higher) hard cap for session files (and/or a streaming reader) so “large but reasonable” files work while still protecting against extreme sizes.

Copilot uses AI. Check for mistakes.
if (token.isCancellationRequested) {
throw new CancellationError();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,50 @@ describe('ClaudeCodeSessionService', () => {
service = instaService.createInstance(ClaudeCodeSessionService);
});

it('handles large session files (>5MB) correctly', async () => {
// Create a large session file by repeating a valid message entry
const fileName = 'large-session.jsonl';
const timestamp = new Date().toISOString();

// Create a base message entry
const baseMessage = JSON.stringify({
parentUuid: null,
sessionId: 'large-session',
type: 'user',
message: { role: 'user', content: 'x'.repeat(1000) }, // 1KB per message
uuid: 'uuid-1',
timestamp
});

// Repeat the message 6000 times to create ~6MB file
const lines: string[] = [];
for (let i = 0; i < 6000; i++) {
const message = JSON.parse(baseMessage);
message.uuid = `uuid-${i}`;
if (i > 0) {
message.parentUuid = `uuid-${i - 1}`;
}
lines.push(JSON.stringify(message));
}

const largeFileContents = lines.join('\n');
const fileSizeInMB = Math.round(largeFileContents.length / (1024 * 1024));

// Verify the file is actually large enough (>5MB)
expect(fileSizeInMB).toBeGreaterThan(5);

mockFs.mockDirectory(dirUri, [[fileName, FileType.File]]);
mockFs.mockFile(URI.joinPath(dirUri, fileName), largeFileContents, 1000);

// Should not throw an error for large files
const sessions = await service.getAllSessions(CancellationToken.None);

Comment on lines +91 to +96
Copy link

Copilot AI Jan 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new “large session file” test doesn’t currently validate the regression it’s meant to cover: MockFileSystemService.readFile doesn’t enforce the 5MB limit, so this test would have passed even before the production change. To make this test meaningful, either (a) make the mock apply the same size check unless disableLimit is true (e.g. reuse assertReadFileSizeLimit), or (b) assert via a spy that readFile was called with disableLimit=true when loading sessions.

Copilot uses AI. Check for mistakes.
expect(sessions).toHaveLength(1);
expect(sessions[0].id).toBe('large-session');
// Verify we loaded all messages
expect(sessions[0].messages).toHaveLength(6000);
});

it('loads 2 sessions from 3 real fixture files', async () => {
// Setup mock with all 3 real fixture files
const fileName1 = '553dd2b5-8a53-4fbf-9db2-240632522fe5.jsonl';
Expand Down
2 changes: 1 addition & 1 deletion src/platform/filesystem/node/test/mockFileSystemService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export class MockFileSystemService implements IFileSystemService {
return this.mockDirs.get(uriString) || [];
}

async readFile(uri: URI): Promise<Uint8Array> {
async readFile(uri: URI, disableLimit?: boolean): Promise<Uint8Array> {
Copy link

Copilot AI Jan 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The mock readFile signature was updated to accept disableLimit, but the parameter isn’t used and the mock still doesn’t emulate the real 5MB read limit. Since the new behavior depends on bypassing that limit, consider applying the same limit logic in this mock (and honoring disableLimit) so unit tests can catch regressions around large-file reads.

Copilot uses AI. Check for mistakes.
const uriString = uri.toString();
if (this.mockErrors.has(uriString)) {
throw this.mockErrors.get(uriString);
Expand Down
Loading