refactor(memory-safety): group the shared bounding primitives into one folder

The six primitives that exist to stop unbounded memory growth were scattered
through `src/shared/` next to unrelated modules, so there was nowhere to state
when a new ceiling is warranted — and the last attempt at this work added many
that were not.

Moves them under `src/shared/memory-safety/` and adds a README carrying the
doctrine: bound at ingress, not in the interior; set limits far above real use;
decide overload behavior explicitly; and prefer fixing measured growth over
adding a speculative ceiling.

No behavior change. Pure move plus import-path updates across 48 files, with
`git mv` preserving history. Includes two `vi.mock` paths that had to move with
their modules — a mock left on the old path silently stops applying, which the
suite caught.

Verified: typecheck clean, oxlint 0 errors, 18,668 tests passing across
src/shared and src/main.
This commit is contained in:
Neil
2026-07-26 18:54:06 -07:00
parent feb321f6a0
commit d38b04e383
54 changed files with 132 additions and 54 deletions
+1 -1
View File
@@ -2,7 +2,7 @@ import { mkdtempSync, rmSync, truncateSync, writeFileSync } from 'node:fs'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import { afterEach, describe, expect, it } from 'vitest'
import { NodeFileReadTooLargeError } from '../shared/node-bounded-file-reader'
import { NodeFileReadTooLargeError } from '../shared/memory-safety/node-bounded-file-reader'
import {
MAX_AGENT_STATE_FILE_BYTES,
MAX_AGENT_STATE_JSON_NESTING_DEPTH,
+2 -2
View File
@@ -1,5 +1,5 @@
import { readNodeFileSyncWithinLimit } from '../shared/node-bounded-file-reader'
import { assertJsonTextStructureWithinLimits } from '../shared/json-text-structure-limit'
import { readNodeFileSyncWithinLimit } from '../shared/memory-safety/node-bounded-file-reader'
import { assertJsonTextStructureWithinLimits } from '../shared/memory-safety/json-text-structure-limit'
export const MAX_AGENT_STATE_FILE_BYTES = 4 * 1024 * 1024
export const MAX_AGENT_STATE_JSON_STRUCTURAL_TOKENS = 1_000_000
@@ -1,7 +1,7 @@
import {
readNodeFileSyncWithinLimit,
readNodeFileWithinLimit
} from '../../shared/node-bounded-file-reader'
} from '../../shared/memory-safety/node-bounded-file-reader'
export function readTerminalHistoryBuffer(filePath: string, maxBytes: number): Buffer {
return readNodeFileSyncWithinLimit(filePath, maxBytes).buffer
+2 -2
View File
@@ -1,7 +1,7 @@
/* eslint-disable max-lines -- Why: git status/discard/chunking behavior is verified together here to keep the command contract readable in one place. */
import { beforeEach, describe, expect, it, vi } from 'vitest'
import type * as NodeFs from 'node:fs'
import type * as BoundedFileReader from '../../shared/node-bounded-file-reader'
import type * as BoundedFileReader from '../../shared/memory-safety/node-bounded-file-reader'
import path from 'node:path'
import {
MAX_RENDERED_DIFF_COMBINED_CHARACTERS,
@@ -63,7 +63,7 @@ vi.mock('fs', () => ({
existsSync: existsSyncMock
}))
vi.mock('../../shared/node-bounded-file-reader', async (importOriginal) => {
vi.mock('../../shared/memory-safety/node-bounded-file-reader', async (importOriginal) => {
const actual = await importOriginal<typeof BoundedFileReader>()
return {
...actual,
@@ -1,4 +1,4 @@
import { clampUtf8TextTail } from '../../../../shared/utf8-byte-limits'
import { clampUtf8TextTail } from '../../../../shared/memory-safety/utf8-byte-limits'
export type EagerBufferChunk = {
data: string
@@ -1,7 +1,7 @@
import { beforeAll, beforeEach, describe, expect, it, vi } from 'vitest'
import { TERMINAL_SCROLLBACK_SESSION_BUFFER_BYTE_LIMIT } from '../../../../shared/terminal-scrollback-limits'
import type { TerminalLayoutSnapshot } from '../../../../shared/types'
import { getUtf8ByteLength } from '../../../../shared/utf8-byte-limits'
import { getUtf8ByteLength } from '../../../../shared/memory-safety/utf8-byte-limits'
const LEAF_ID = '11111111-1111-4111-8111-111111111111' as const
const LEAF_ID_2 = '22222222-2222-4222-8222-222222222222' as const
@@ -7,7 +7,7 @@ import { mergeCapturedLeafState } from './merge-captured-leaf-state'
import { resolveTerminalLayoutActiveLeafId } from './terminal-layout-leaf-ids'
import { TERMINAL_SCROLLBACK_SESSION_BUFFER_BYTE_LIMIT } from '../../../../shared/terminal-scrollback-limits'
import { serializeWithAbsoluteCursor } from '../../../../shared/terminal-serialize-absolute-cursor'
import { measureUtf8ByteLength } from '../../../../shared/utf8-byte-limits'
import { measureUtf8ByteLength } from '../../../../shared/memory-safety/utf8-byte-limits'
const MAX_BUFFER_BYTES = TERMINAL_SCROLLBACK_SESSION_BUFFER_BYTE_LIMIT
+1 -1
View File
@@ -63,7 +63,7 @@ import {
resolveGrokSessionsDir
} from './grok-session-paths'
import { sweepStaleAgentHookEndpointTemps } from './agent-hook-endpoint-temp-cleanup'
import { assertJsonTextStructureWithinLimits } from './json-text-structure-limit'
import { assertJsonTextStructureWithinLimits } from './memory-safety/json-text-structure-limit'
/** Maximum request body size accepted by the listener (1 MB). */
export const HOOK_REQUEST_MAX_BYTES = 1_000_000
+1 -1
View File
@@ -9,7 +9,7 @@ import {
normalizeOptionalMultilineField,
normalizePromptField
} from './agent-status-field-normalization'
import { assertJsonTextStructureWithinLimits } from './json-text-structure-limit'
import { assertJsonTextStructureWithinLimits } from './memory-safety/json-text-structure-limit'
export { AGENT_STATUS_MAX_FIELD_LENGTH } from './agent-status-field-normalization'
+1 -1
View File
@@ -1,4 +1,4 @@
import { assertJsonTextStructureWithinLimits } from './json-text-structure-limit'
import { assertJsonTextStructureWithinLimits } from './memory-safety/json-text-structure-limit'
const BROWSER_SCREENCAST_KIND = 0x62
const BROWSER_SCREENCAST_VERSION = 1
+1 -1
View File
@@ -1,6 +1,6 @@
import type { TuiAgent } from './types'
import { isTuiAgentEnabled } from './tui-agent-selection'
import { assertJsonTextStructureWithinLimits } from './json-text-structure-limit'
import { assertJsonTextStructureWithinLimits } from './memory-safety/json-text-structure-limit'
/* eslint-disable max-lines -- Why: this is the single registry for non-interactive commit-message agents, their model discovery parsers, and UI capabilities. */
+1 -1
View File
@@ -5,7 +5,7 @@ import {
MAX_SSH_RELAY_GRACE_PERIOD_SECONDS,
MIN_SSH_RELAY_GRACE_PERIOD_SECONDS
} from './ssh-types'
import { assertJsonTextStructureWithinLimits } from './json-text-structure-limit'
import { assertJsonTextStructureWithinLimits } from './memory-safety/json-text-structure-limit'
// Why: ephemeral-vm-recipe-doctor imports Node's fs/path, so it must NOT be
// re-exported through this barrel — the renderer/web-client imports this module
// and would otherwise pull Node built-ins into the browser bundle (build fails).
+3 -3
View File
@@ -1,8 +1,8 @@
import { existsSync } from 'node:fs'
import { join } from 'node:path'
import { JsonStringifyByteLimitError } from './node-bounded-json-stringify'
import { readNodeFileSyncWithinLimit } from './node-bounded-file-reader'
import { writeSecureJsonFileWithinLimit } from './bounded-secure-json-file'
import { JsonStringifyByteLimitError } from './memory-safety/node-bounded-json-stringify'
import { readNodeFileSyncWithinLimit } from './memory-safety/node-bounded-file-reader'
import { writeSecureJsonFileWithinLimit } from './memory-safety/bounded-secure-json-file'
import { hardenExistingSecureFile } from './secure-file'
import {
EphemeralVmRuntimeRecordSchema,
+5 -2
View File
@@ -1,8 +1,11 @@
import { NodeFileReadTooLargeError, readNodeFileWithinLimit } from './node-bounded-file-reader'
import {
NodeFileReadTooLargeError,
readNodeFileWithinLimit
} from './memory-safety/node-bounded-file-reader'
import {
assertJsonTextStructureWithinLimits,
type JsonTextStructureLimits
} from './json-text-structure-limit'
} from './memory-safety/json-text-structure-limit'
export const EXTERNAL_AUTOMATION_JOBS_FILE_MAX_BYTES = 8 * 1024 * 1024
export const EXTERNAL_AUTOMATION_JOBS_MAX_ENTRIES = 10_000
+1 -1
View File
@@ -1,7 +1,7 @@
import {
assertJsonTextStructureWithinLimits,
type JsonTextStructureLimits
} from './json-text-structure-limit'
} from './memory-safety/json-text-structure-limit'
const INITIAL_RESPONSE_CAPACITY_BYTES = 64 * 1024
@@ -7,7 +7,7 @@ const { lstatMock, readFileMock } = vi.hoisted(() => ({
vi.mock('fs/promises', () => ({ lstat: lstatMock }))
vi.mock('./node-bounded-file-reader', () => ({
vi.mock('./memory-safety/node-bounded-file-reader', () => ({
readNodeFileWithinLimit: async (path: string) => ({
buffer: await readFileMock(path),
stats: mockFileStat(0)
+1 -1
View File
@@ -4,7 +4,7 @@ import { isBinaryBuffer } from './binary-buffer'
import { decodeGitCQuotedPath } from './git-cquoted-path'
import { DEFAULT_GIT_STATUS_LIMIT } from './git-status-limit'
import { iterateNulDelimitedFields } from './nul-delimited-fields'
import { readNodeFileWithinLimit } from './node-bounded-file-reader'
import { readNodeFileWithinLimit } from './memory-safety/node-bounded-file-reader'
export type GitLineStats = { added?: number; removed?: number }
+1 -1
View File
@@ -1,4 +1,4 @@
import { measureUtf8ByteLength } from './utf8-byte-limits'
import { measureUtf8ByteLength } from './memory-safety/utf8-byte-limits'
export const HTML_TO_PDF_MAX_INPUT_BYTES = 32 * 1024 * 1024
export const HTML_TO_PDF_MEMORY_LIMIT_ERROR = 'HTML export exceeds the PDF memory limit'
+1 -1
View File
@@ -1,4 +1,4 @@
import { readNodeFileWithinLimit } from './node-bounded-file-reader'
import { readNodeFileWithinLimit } from './memory-safety/node-bounded-file-reader'
export const LINUX_PROC_NETWORK_TABLE_MAX_BYTES = 8 * 1024 * 1024
export const LINUX_PROC_LISTENING_SOCKET_MAX_ENTRIES = 2_048
@@ -1,5 +1,5 @@
import type { MarkdownDocument } from './types'
import { measureUtf8ByteLength } from './utf8-byte-limits'
import { measureUtf8ByteLength } from './memory-safety/utf8-byte-limits'
export const MARKDOWN_DOCUMENT_LISTING_MAX_DOCUMENTS = 20_000
export const MARKDOWN_DOCUMENT_LISTING_MAX_METADATA_BYTES = 8 * 1024 * 1024
+1 -1
View File
@@ -1,4 +1,4 @@
import { measureUtf8ByteLength } from './utf8-byte-limits'
import { measureUtf8ByteLength } from './memory-safety/utf8-byte-limits'
export const MCP_CONFIG_INSPECTION_MAX_BYTES = 256 * 1024
export const MCP_CONFIG_INSPECTION_MAX_CODE_UNITS = 256 * 1024
+72
View File
@@ -0,0 +1,72 @@
# Memory safety
Shared primitives that stop unbounded memory growth. Renderer OOM is Orca's dominant crash class
(#9984): heap climbs to V8's ~3.5 GB ceiling and the process is killed. The reported reproduction
(#9872) was a single unbounded `Map` that also spread-copied itself on every update.
**Read this before adding a new limit, and before writing code that reads or accumulates data.**
## The rule: bound at ingress, not in the interior
Put a ceiling where untrusted or unpredictably-large data first enters memory:
- **Files** — anything read from disk, a repo, or a remote host
- **Transport** — IPC, WebSocket frames, relay/SSH payloads, subprocess output
- **Parsing** — JSON/YAML/CSV/notebook text, base64, image headers
- **Enumeration** — directory walks, provider pagination, session scans
- **Long-lived accumulators** — caches and maps keyed by something a user can grow without limit
(pane IDs, session IDs, paths) that live for the process lifetime
Do **not** add ceilings to interior data structures whose size is already implied by a bounded
input. A second ceiling behind an existing one is not defense in depth; it is a second thing that
can be wrong, and every ceiling is a new user-visible failure mode when it is hit.
If you cannot name the untrusted input and the bound it crosses, you do not need a limit.
### Never copy an accumulator on every update
The crash that started this (#9872) was not only an unbounded `Map` — it also rebuilt itself on every
status ping (`state = { ...state, [key]: value }`). Copy-per-update turns a large collection into
repeated large allocations, so it reaches the heap ceiling far sooner than its size suggests. Mutate
in place, or use `BoundedMap`. No lint rule catches this; it is on you to notice.
## What's here
| Module | Use it for |
| -------------------------------- | ----------------------------------------------------------------------------------------- |
| `bounded-map.ts` | A cache/map that must not grow forever. Count and/or byte ceiling with LRU eviction. |
| `node-bounded-file-reader.ts` | Reading a file whose size you do not control. Checks before allocating and while growing. |
| `node-bounded-json-stringify.ts` | Serializing to JSON when the result could be huge. |
| `bounded-secure-json-file.ts` | Writing a secret-bearing JSON file within a byte ceiling. |
| `json-text-structure-limit.ts` | Guarding `JSON.parse` against depth/token amplification before it runs. |
| `utf8-byte-limits.ts` | Measuring/truncating UTF-8 without materializing the whole string. |
Domain-specific ceilings (e.g. `git-status-limit.ts`, `terminal-scrollback-limits.ts`) live next to
the code they bound, not here. This folder is only for primitives reused across domains.
## Rules for a new ceiling
1. **Set it far above real use.** A limit a normal user reaches is a bug. Ordinary large repos, long
terminal sessions, and big diffs must pass untouched. State the headroom in a comment.
2. **Fail closed, and never crash a remote host.** An unmeasurable size rejects the item; it must not
poison a ledger or throw into a relay running on someone else's machine.
3. **Decide overload behavior explicitly** — reject, evict, or truncate — and document which.
Silent truncation of user data is the worst option; prefer a visible, recoverable failure.
4. **Release on every exit path**, including throw, abort, disconnect, and renderer teardown. Pair
acquisition with `try`/`finally`; do not rely on the happy path.
5. **Test the exact boundary and boundary+1**, through every entry point — including hydration,
restore, and replay paths, not just the create path.
## Enforcement
None of this is lint-enforced today: `readFile`, `JSON.parse`/`stringify`, unbounded `fetch` body
reads, `createReadStream`, `readdir`, recursion depth, copy-per-update amplification, and
accumulator growth are all caught by review, not tooling. The rules above are the standard a
reviewer should hold you to.
## Before you add one
Prefer fixing the actual growth. The real crash was fixed by capping one map that was already known
to grow, found via the heap-highwater breadcrumbs in `renderer_memory_highwater` (#9984). Measure
first: if you cannot point at evidence that something grows, a new ceiling is speculation, and
speculation here costs review burden, user-visible failure modes, and code that outlives its reason.
@@ -1,5 +1,5 @@
import { stringifyJsonWithinByteLimit } from './node-bounded-json-stringify'
import { writeSecureFile } from './secure-file'
import { writeSecureFile } from '../secure-file'
export function writeSecureJsonFileWithinLimit(
targetPath: string,
@@ -2,7 +2,10 @@ import { closeSync, ftruncateSync, mkdtempSync, openSync, rmSync, writeFileSync
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import { afterEach, describe, expect, it } from 'vitest'
import { NodeFileReadTooLargeError, readNodeFileSyncWithinLimit } from './node-bounded-file-reader'
import {
NodeFileReadTooLargeError,
readNodeFileSyncWithinLimit
} from './memory-safety/node-bounded-file-reader'
const tempDirectories: string[] = []
+1 -1
View File
@@ -1,4 +1,4 @@
import { measureUtf8ByteLength } from './utf8-byte-limits'
import { measureUtf8ByteLength } from './memory-safety/utf8-byte-limits'
export const MAX_ORCA_YAML_BYTES = 256 * 1024
export const MAX_ORCA_YAML_CODE_UNITS = 256 * 1024
@@ -10,8 +10,8 @@ import {
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import { afterEach, beforeEach, describe, expect, it } from 'vitest'
import { NodeFileReadTooLargeError } from './node-bounded-file-reader'
import { JsonStringifyByteLimitError } from './node-bounded-json-stringify'
import { NodeFileReadTooLargeError } from './memory-safety/node-bounded-file-reader'
import { JsonStringifyByteLimitError } from './memory-safety/node-bounded-json-stringify'
import {
PersistedStateSecretCapacityError,
assertPersistedStateSecretWithinLimit,
+3 -3
View File
@@ -5,15 +5,15 @@ import {
NodeFileReadTooLargeError,
readNodeFileSyncWithinLimit,
type BoundedNodeFileRead
} from './node-bounded-file-reader'
} from './memory-safety/node-bounded-file-reader'
import {
JsonStringifyByteLimitError,
stringifyJsonWithinByteLimit
} from './node-bounded-json-stringify'
} from './memory-safety/node-bounded-json-stringify'
import {
assertJsonTextStructureWithinLimits,
type JsonTextStructureLimits
} from './json-text-structure-limit'
} from './memory-safety/json-text-structure-limit'
export const ORCA_PERSISTED_STATE_MAX_BYTES = 64 * 1024 * 1024
export const ORCA_PERSISTED_STATE_SECRET_MAX_BYTES = 4 * 1024 * 1024
+1 -1
View File
@@ -1,5 +1,5 @@
import { truncateDiffForPrompt } from './commit-message-prompt'
import { assertJsonTextStructureWithinLimits } from './json-text-structure-limit'
import { assertJsonTextStructureWithinLimits } from './memory-safety/json-text-structure-limit'
export const GENERATED_PULL_REQUEST_JSON_STRUCTURE_LIMITS = {
structuralTokens: 64,
+1 -1
View File
@@ -1,4 +1,4 @@
import { readNodeFileWithinLimit } from './node-bounded-file-reader'
import { readNodeFileWithinLimit } from './memory-safety/node-bounded-file-reader'
import { getProcessOutputFields, iterateProcessOutputLines } from './process-output-field-scanner'
const GENERIC_LINUX_RIPGREP_INSTALL =
+1 -1
View File
@@ -1,4 +1,4 @@
import { assertJsonTextStructureWithinLimits } from './json-text-structure-limit'
import { assertJsonTextStructureWithinLimits } from './memory-safety/json-text-structure-limit'
export const RELAY_JSON_MAX_STRUCTURAL_TOKENS = 1_000_000
export const RELAY_JSON_MAX_NESTING_DEPTH = 128
+1 -1
View File
@@ -2,7 +2,7 @@ import { mkdtempSync, rmSync, truncateSync, writeFileSync } from 'node:fs'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import { afterEach, describe, expect, it } from 'vitest'
import { NodeFileReadTooLargeError } from './node-bounded-file-reader'
import { NodeFileReadTooLargeError } from './memory-safety/node-bounded-file-reader'
import { RELAY_VERSION_MARKER_MAX_BYTES, readRelayVersionMarkerSync } from './relay-version-marker'
const roots: string[] = []
+1 -1
View File
@@ -1,4 +1,4 @@
import { readNodeFileSyncWithinLimit } from './node-bounded-file-reader'
import { readNodeFileSyncWithinLimit } from './memory-safety/node-bounded-file-reader'
export const RELAY_VERSION_MARKER_MAX_BYTES = 4 * 1024
+1 -1
View File
@@ -1,7 +1,7 @@
import {
JsonStringifyByteLimitError,
stringifyJsonWithinByteLimit
} from './node-bounded-json-stringify'
} from './memory-safety/node-bounded-json-stringify'
import { RemoteRuntimeClientError } from './remote-runtime-client-error'
export const REMOTE_RUNTIME_MAX_OUTBOUND_JSON_BYTES = 4 * 1024 * 1024
+1 -1
View File
@@ -4,7 +4,7 @@ import {
isKeepaliveFrame
} from './runtime-rpc-envelope'
import { RemoteRuntimeClientError } from './remote-runtime-client-error'
import { assertJsonTextStructureWithinLimits } from './json-text-structure-limit'
import { assertJsonTextStructureWithinLimits } from './memory-safety/json-text-structure-limit'
export const REMOTE_RUNTIME_JSON_STRUCTURE_LIMITS = {
structuralTokens: 256 * 1024,
+1 -1
View File
@@ -1,5 +1,5 @@
import { join } from 'node:path'
import { assertJsonTextStructureWithinLimits } from './json-text-structure-limit'
import { assertJsonTextStructureWithinLimits } from './memory-safety/json-text-structure-limit'
export type RuntimeTransportMetadata =
| {
+3 -3
View File
@@ -1,10 +1,10 @@
import { randomUUID } from 'node:crypto'
import { existsSync } from 'node:fs'
import { join } from 'node:path'
import { JsonStringifyByteLimitError } from './node-bounded-json-stringify'
import { readNodeFileSyncWithinLimit } from './node-bounded-file-reader'
import { JsonStringifyByteLimitError } from './memory-safety/node-bounded-json-stringify'
import { readNodeFileSyncWithinLimit } from './memory-safety/node-bounded-file-reader'
import { parsePairingCode, type PairingOffer } from './pairing'
import { writeSecureJsonFileWithinLimit } from './bounded-secure-json-file'
import { writeSecureJsonFileWithinLimit } from './memory-safety/bounded-secure-json-file'
import { hardenExistingSecureFile } from './secure-file'
import {
createEnvironmentFromPairingOffer,
+1 -1
View File
@@ -1,5 +1,5 @@
import { join } from 'node:path'
import { assertJsonTextStructureWithinLimits } from './json-text-structure-limit'
import { assertJsonTextStructureWithinLimits } from './memory-safety/json-text-structure-limit'
export const SERVE_UPDATE_HANDOFF_PATH_ENV = 'ORCA_SERVE_UPDATE_HANDOFF_PATH'
export const SERVE_UPDATE_HANDOFF_FILE = 'serve-update-handoff.json'
@@ -6,7 +6,7 @@ import {
SETUP_SCRIPT_IMPORT_MAX_TOML_LINES,
SETUP_SCRIPT_IMPORT_MAX_UNSUPPORTED_FIELDS
} from './setup-script-import-limits'
import { measureUtf8ByteLength } from './utf8-byte-limits'
import { measureUtf8ByteLength } from './memory-safety/utf8-byte-limits'
const CODEX_ENVIRONMENT_PATH = '.codex/environments/environment.toml'
+1 -1
View File
@@ -1,4 +1,4 @@
import { measureUtf8ByteLength } from './utf8-byte-limits'
import { measureUtf8ByteLength } from './memory-safety/utf8-byte-limits'
export const SETUP_SCRIPT_IMPORT_FILE_MAX_BYTES = 256 * 1024
export const SETUP_SCRIPT_IMPORT_MAX_CODE_UNITS = 256 * 1024
@@ -1,5 +1,5 @@
import { describe, expect, it } from 'vitest'
import { getUtf8ByteLength } from './utf8-byte-limits'
import { getUtf8ByteLength } from './memory-safety/utf8-byte-limits'
import {
admitSshConnectionState,
admitSshDetectedPorts,
+1 -1
View File
@@ -1,5 +1,5 @@
import type { EnrichedDetectedPort, SshConnectionState, SshConnectionStatus } from './ssh-types'
import { clampUtf8TextPrefix, measureUtf8ByteLength } from './utf8-byte-limits'
import { clampUtf8TextPrefix, measureUtf8ByteLength } from './memory-safety/utf8-byte-limits'
export const SSH_RETAINED_IDENTIFIER_MAX_UTF8_BYTES = 1024
export const SSH_CONNECTION_ERROR_MAX_UTF8_BYTES = 16 * 1024
+1 -1
View File
@@ -1,4 +1,4 @@
import { assertJsonTextStructureWithinLimits } from './json-text-structure-limit'
import { assertJsonTextStructureWithinLimits } from './memory-safety/json-text-structure-limit'
const TERMINAL_STREAM_KIND = 0x74
const TERMINAL_STREAM_VERSION = 1
+1 -1
View File
@@ -11,7 +11,7 @@
* Design doc: docs/design/share-text-search.md.
*/
import { posix, win32 } from 'node:path'
import { assertJsonTextStructureWithinLimits } from './json-text-structure-limit'
import { assertJsonTextStructureWithinLimits } from './memory-safety/json-text-structure-limit'
import { normalizeSearchResult } from './search-match-count'
import { escapeRegex } from './string-utils'
import type { SearchFileResult, SearchMatch, SearchOptions, SearchResult } from './types'
@@ -2,7 +2,7 @@ import { describe, expect, it } from 'vitest'
import { FLOATING_TERMINAL_WORKTREE_ID } from './constants'
import type { WorkspaceSessionState } from './types'
import { TERMINAL_SCROLLBACK_SESSION_BUFFER_BYTE_LIMIT } from './terminal-scrollback-limits'
import { getUtf8ByteLength } from './utf8-byte-limits'
import { getUtf8ByteLength } from './memory-safety/utf8-byte-limits'
import {
pruneLocalTerminalScrollbackBuffers,
shouldPreserveTerminalScrollbackBuffers
@@ -2,7 +2,7 @@ import type { Repo, WorkspaceSessionState } from './types'
import { FLOATING_TERMINAL_WORKTREE_ID } from './constants'
import { getRepoIdFromWorktreeId } from './worktree-id'
import { TERMINAL_SCROLLBACK_SESSION_BUFFER_BYTE_LIMIT } from './terminal-scrollback-limits'
import { clampUtf8TextTail, measureUtf8ByteLength } from './utf8-byte-limits'
import { clampUtf8TextTail, measureUtf8ByteLength } from './memory-safety/utf8-byte-limits'
import { parseExecutionHostId } from './execution-host'
export type RepoConnection = Pick<Repo, 'id' | 'connectionId' | 'executionHostId'>