diff --git a/scripts/dev.ts b/scripts/dev.ts index 72919caa8c..c828996f68 100644 --- a/scripts/dev.ts +++ b/scripts/dev.ts @@ -14,11 +14,20 @@ const __dirname = dirname(__filename) const projectRoot = join(__dirname, '..') const cliPath = join(projectRoot, 'src/entrypoints/cli.tsx') +// React production mode — prevents 6,889+ _debugStack Error objects +// (12MB) from accumulating during long-running sessions. +// Opt-in via CLAUDE_CODE_FORCE_NODE_ENV=production for dev sessions that +// need the memory optimization. Default keeps NODE_ENV='development' so +// dev-only diagnostics (DevBar, doctorDiagnostic, AutoUpdater dev branches, +// etc.) continue to work. +const forcedNodeEnv = + process.env.CLAUDE_CODE_FORCE_NODE_ENV ?? + process.env.NODE_ENV ?? + 'development' + const defines = { ...getMacroDefines(), - // React production mode — prevents 6,889+ _debugStack Error objects - // (12MB) from accumulating during long-running sessions. - 'process.env.NODE_ENV': JSON.stringify('production'), + 'process.env.NODE_ENV': JSON.stringify(forcedNodeEnv), } const defineArgs = Object.entries(defines).flatMap(([k, v]) => [ diff --git a/src/screens/REPL.tsx b/src/screens/REPL.tsx index 750da47ca5..66f68cd90b 100644 --- a/src/screens/REPL.tsx +++ b/src/screens/REPL.tsx @@ -4937,7 +4937,7 @@ export function REPL({ useMailboxBridge({ isLoading, onSubmitMessage: handleIncomingPrompt }); useMasterMonitor(); useSlaveNotifications(); - const _pipeIpcState = useAppState(s => getPipeIpc(s as any)); + const _pipeIpcState = useAppState(s => getPipeIpc(s)); usePipePermissionForward({ store, tools, setMessages, setToolUseConfirmQueue, getToolUseContext, mainLoopModel }); usePipeMuteSync({ setToolUseConfirmQueue }); diff --git a/src/services/api/gemini/index.ts b/src/services/api/gemini/index.ts index 6754189af4..10524873d2 100644 --- a/src/services/api/gemini/index.ts +++ b/src/services/api/gemini/index.ts @@ -6,7 +6,7 @@ import type { StreamEvent, SystemAPIErrorMessage, } from '../../../types/message.js' -import { type Tools } from '../../../Tool.js' +import type { Tools } from 'src/Tool.js' import { toolToAPISchema } from '../../../utils/api.js' import { logForDebugging } from '../../../utils/debug.js' import { diff --git a/src/utils/fileHistory.ts b/src/utils/fileHistory.ts index 414c312abc..c43aabbf97 100644 --- a/src/utils/fileHistory.ts +++ b/src/utils/fileHistory.ts @@ -51,8 +51,9 @@ export type FileHistoryState = { snapshotSequence: number } -// Disabled: file checkpointing causes unbounded memory growth (100 snapshots × full file backups). -// See heap snapshot analysis — re-enable only after switching to incremental diffs. +// Throttled: file checkpointing remains enabled (gated by fileHistoryEnabled()) +// but capped to mitigate unbounded memory growth (full file backups x N snapshots). +// See heap snapshot analysis; only raise this cap after switching to incremental diffs. const MAX_SNAPSHOTS = 20 export type DiffStats = | { diff --git a/src/utils/performanceShim.ts b/src/utils/performanceShim.ts index 174518bb6f..7bec8da414 100644 --- a/src/utils/performanceShim.ts +++ b/src/utils/performanceShim.ts @@ -105,6 +105,10 @@ function getEntriesByName(name: string, type?: string): PerformanceEntryLike[] { return entries.filter(e => e.name === name) } +function getEntries(): PerformanceEntryLike[] { + return [...getEntriesByType('mark'), ...getEntriesByType('measure')] +} + function clearMarks(name?: string): void { if (name !== undefined) { marks.delete(name) @@ -128,6 +132,7 @@ const shim = { now, mark, measure: measure as typeof performance.measure, + getEntries: getEntries as typeof performance.getEntries, getEntriesByType: getEntriesByType as typeof performance.getEntriesByType, getEntriesByName: getEntriesByName as typeof performance.getEntriesByName, clearMarks: clearMarks as typeof performance.clearMarks, @@ -140,10 +145,11 @@ const shim = { return original.timeOrigin }, get onresourcetimingbufferfull() { - return (original as any).onresourcetimingbufferfull + return (original as Performance & { onresourcetimingbufferfull?: unknown }) + .onresourcetimingbufferfull }, - set onresourcetimingbufferfull(_v: any) { - // no-op — prevent accumulation + set onresourcetimingbufferfull(_v: unknown) { + // no-op to prevent accumulation }, toJSON() { return original.toJSON() @@ -156,8 +162,11 @@ const shim = { * native Performance reference. */ export function installPerformanceShim(): void { - if ((globalThis as any).__performanceShimInstalled) return - ;(globalThis as any).__performanceShimInstalled = true + const g = globalThis as typeof globalThis & { + __performanceShimInstalled?: boolean + } + if (g.__performanceShimInstalled) return + g.__performanceShimInstalled = true globalThis.performance = shim }