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: 3 additions & 0 deletions .jules/bolt.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,6 @@
## 2023-10-27 - O(N) Re-renders in List Components
**Learning:** React list components mapped from arrays (e.g. `sessions.map(...)`) will experience severe O(N) re-renders when a single element changes state if the evaluation is done inline inside the map without memoization. Passing the active check (e.g., `isActive={activeSessionId === s.id}`) down to a `React.memo` wrapper component is necessary to convert this into an O(1) re-render (only the two affected components will update).
**Action:** When creating high-frequency updating list elements with individual active states in React, extract the items into `React.memo` components and pass simple boolean flags to prevent massive VDOM updates.
## 2024-05-24 - [Remove Synchronous File Operations]
**Learning:** Checking for file existence using `fs.existsSync` introduces blocking I/O on the Node.js event loop, creating micro-stutters and reducing application concurrency.
**Action:** Always prefer asynchronous file access (e.g., `fs.promises.readFile` or `fs.promises.access`) enclosed in a `try...catch` block. This approach avoids blocking and eliminates Time-of-Check to Time-of-Use (TOCTOU) race conditions.
11 changes: 4 additions & 7 deletions packages/core/src/agent.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import Anthropic from '@anthropic-ai/sdk';
import type { MessageParam, Tool, ToolUseBlock, TextBlock, ContentBlock } from '@anthropic-ai/sdk/resources/messages';
import fetch from 'node-fetch';
import { existsSync, readFileSync } from 'fs';
import { readFile } from 'fs/promises';
import { join } from 'path';
import { homedir } from 'os';
Expand Down Expand Up @@ -759,12 +758,10 @@ export class EnhancedAgent extends EventEmitter {
} else {
// Fallback: read .xibecode/memory.md directly (cheap single read)
const fallbackMd = join(process.cwd(), '.xibecode', 'memory.md');
if (existsSync(fallbackMd)) {
try {
const content = await readFile(fallbackMd, 'utf-8');
this.autoMemoryMarkdownSection = `\n\n## Project Memory\n\n${content.trim()}`;
} catch { /* ignore */ }
}
try {
const content = await readFile(fallbackMd, 'utf-8');
this.autoMemoryMarkdownSection = `\n\n## Project Memory\n\n${content.trim()}`;
} catch { /* ignore if not exist */ }
}

if (newMem.trim() && !this.autoMemoryMarkdownSection.includes(newMem.trim())) {
Expand Down
10 changes: 9 additions & 1 deletion packages/core/src/code-graph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,15 @@ export class CodeGraph {
if (this.isInitialized) return;

const tsConfigPath = path.join(this.workingDir, 'tsconfig.json');
if (fs.existsSync(tsConfigPath)) {
let hasTsConfig = false;
try {
await fs.promises.access(tsConfigPath);
hasTsConfig = true;
} catch {
hasTsConfig = false;
}
Comment on lines 26 to +33

if (hasTsConfig) {
this.project = new Project({
tsConfigFilePath: tsConfigPath,
skipAddingFilesFromTsConfig: false,
Expand Down
11 changes: 6 additions & 5 deletions packages/core/src/memory.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import * as fs from 'fs/promises';
import { existsSync } from 'fs';
import * as path from 'path';
import { createHash } from 'crypto';
import { MemoryPromotions } from './memory-promotions.js';
Expand Down Expand Up @@ -36,13 +35,15 @@ export class NeuralMemory {

try {
const xibeDir = path.dirname(this.memoryFile);
if (!existsSync(xibeDir)) {
await fs.mkdir(xibeDir, { recursive: true });
}
await fs.mkdir(xibeDir, { recursive: true });

if (existsSync(this.memoryFile)) {
try {
const content = await fs.readFile(this.memoryFile, 'utf-8');
this.memory = JSON.parse(content);
} catch (readError: any) {
if (readError.code !== 'ENOENT') {
throw readError;
}
}
this.initialized = true;
} catch (error) {
Expand Down
5 changes: 0 additions & 5 deletions packages/core/src/permission-store.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import * as fs from 'fs/promises';
import { existsSync } from 'fs';
import * as path from 'path';
import type { PermissionMode } from './permissions.js';

Expand All @@ -18,10 +17,6 @@ export class PermissionStore {
}

async load(): Promise<PersistedPermissionState | null> {
if (!existsSync(this.storePath)) {
return null;
}

try {
const raw = await fs.readFile(this.storePath, 'utf8');
const parsed = JSON.parse(raw) as PersistedPermissionState;
Expand Down
10 changes: 2 additions & 8 deletions packages/core/src/utils/auto-memory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@
* Keyword relevance scoring; optional env to disable.
*/

import { existsSync } from 'fs';
import { readFile, readdir } from 'fs/promises';
import { readFile, readdir, access } from 'fs/promises';
import { homedir } from 'os';
import { join } from 'path';

Expand Down Expand Up @@ -75,9 +74,6 @@ async function loadMemoryFile(
type: LoadedMemory['type'],
): Promise<LoadedMemory | null> {
try {
if (!existsSync(filePath)) {
return null;
}
const content = await readFile(filePath, 'utf-8');
return {
path: filePath,
Expand Down Expand Up @@ -117,11 +113,9 @@ async function loadProjectMemories(cwd: string): Promise<LoadedMemory[]> {
}

const autoDir = join(cwd, '.xibecode', 'memories');
if (!existsSync(autoDir)) {
return memories;
}

try {
await access(autoDir);
const names = await readdir(autoDir, { withFileTypes: true });
const mdFiles = names.filter((d) => d.isFile() && d.name.endsWith('.md')).map((d) => join(autoDir, d.name));
for (const fp of mdFiles.slice(0, MAX_AUTO_LOAD_MEMORIES)) {
Comment on lines 117 to 121
Expand Down
Loading