* refactor(ipc): split repos.ts into focused modules
* test: point repo notification mocks at the extracted module
* fix(ipc): repoint the child-process allowlists after the repos split
The type-only `import type { ChildProcess }` moved from repos.ts to
repos/repo-clone-lifecycle.ts, so the import-boundary entry follows it and the
windows-console entry (now stale, and that list only shrinks) is dropped.
Fixture-only; the base file had no runtime child_process use at all.
* Refactor terminal coordination modules
* preserve terminal completion and stale-connect guards
* restore pre-spawn E2E barrier and stale-connect check order in ipc-pty-connect
* restore merge-base title-working replay and stamped-tail delete semantics
* fix(terminal): merge the duplicated shortcut-matching import
Two adjacent imports of the same module tripped oxlint's
no-duplicate-imports under --deny-warnings. Import-only; no behavior change.
* refactor(rate-limits): split Codex and Claude fetchers
* refactor(rate-limits): restore base error-message defaulting
The split moved the 'Unknown error' fallback from inside String() to the call site, which changed behavior for an Error with an empty .message: base surfaced '', head surfaced 'Unknown error'. Restore the base form.
* refactor oversized Electron facilities
* fix interactive process timeout and shortcut repeat guard
* chore(child-process): drop stale cli-installer allowlist entry
cli-installer.ts now routes privileged spawns through runProcess via
cli-privileged-processes.ts, so the shrink-only ratchet flags it as stale.
* refactor(child-process): extract the bounded output sink
runProcess's timeoutMs opt-out (required to preserve the unbounded osascript
admin prompt) pushed run-process.ts past the 300-line cap. Move createOutputSink
to its own module rather than add a max-lines bypass, which AGENTS.md forbids.
Moved verbatim; no behavior change.
* refactor(editor): split editor and watch surfaces
* fix(editor): revert behavior changes smuggled into the surface split
Restore merge-base React keys in IpynbCellOutputs: the content-identity keys
JSON.stringify'd every output value, including raw base64 image payloads, on
every keystroke.
Collapse the duplicated lazy() declarations into editor-lazy-views so each
viewer keeps a single React.lazy identity across the extracted surfaces.
* refactor: split agent config and auth services
* chore: repoint wsl and global-fetch guards at split module paths
* fix: restore merge-base Claude CLI error propagation
Drop the secret-redaction rewriting added to Claude CLI error paths in the
refactor: spawn errors again reject with the original Error (preserving
.code/.errno/.syscall/.stack) and command output/auth-status logs are no
longer rewritten.
* refactor(renderer): split composer state
* fix(renderer): satisfy composer static analysis
* test(renderer): migrate composer boundary contracts
* fix(composer): restore project group reset effect
Revert read-side mask back to the merge-base state clear so a momentarily
unavailable host permanently drops the folder group instead of silently
retargeting Create when the host reappears.
* refactor(workspaces): split lifecycle modules
* preserve workspace cleanup consent contract
* restore workspace delete shortcut hint in context menu view
* restore host-qualified visit recency and viewed-candidate predicate
* test(cleanup): pin the viewed-mark upgrade path and host-qualified visit reads
Two invariants a refactor broke in this PR, both silent:
- viewed marks are persisted, so gating `shouldPreserveCleanupInspection` on any
newer field voids the grace period for every entry written by an older build
- visits are stamped under `${hostId}|${worktreeId}` whenever the host is known
(the normal case, including 'local'), so a bare map[worktreeId] read misses
every modern entry and yields 0, disabling the recent-visible-context blocker
Verified discriminating: reintroducing each bug fails exactly its own test.
* refactor(daemon): split oversized PTY services
* revert(daemon): restore merge-base session listing and canceled-spawn behavior
Two behavior changes rode along with the file-splitting refactor:
- listLiveTerminalHostSessions dropped sessions with isTerminating, not just
dead ones, hiding sessions the merge base still advertised.
- spawnAndPublishSession called session.beginTermination() before publishing a
canceled spawn into the host map.
Both hunks are reverted to the merge base; the refactor is untouched.
* refactor Linear workspace surfaces
* refactor(linear): restore merge-base behavior in split modules
The Linear surface split smuggled in three behavior changes; revert them
so the refactor is a pure move.
- detail-state: drop 'project' from EDITED_LINEAR_ISSUE_FIELDS. List
issues never carry `project` (only getIssue maps it), so preserving it
across hydration permanently blanked the hydrated project whenever an
edit landed while linearGetIssue was in flight.
- detail-state: handleProjectChanged no longer sets hasEditedRef.
- project-selector: remove the mountedRef/requestId guards around the
global patchLinearIssue write and the success/error toasts.
- sub-issues: remove the added isComposing guard on the title Enter key.
The detail-state test asserted the smuggled project-preservation; updated
to assert hydration owns `project`.
* refactor settings maintenance modules
* revert behavior changes smuggled into settings split
- hoist isAdvancedOpen state back into RepositoryHooksSection so it survives
SearchableSetting unmount during settings search
- drop isComposing guards absent from the merge-base AgentsPane handlers
- restore merge-base JSX for the 'when one exists.' fragment (no separator)
* refactor feature wall animated visuals
* fix(feature-wall): restore merge-base render behavior in split visuals
- Hoist workbench reduced-motion state to module constants so cursorTarget
identity is stable and the cursor layout effect stops re-firing per render.
- Render one frame component and branch on the state source so toggling
reducedMotion re-renders the storyboard instead of remounting its DOM.
* rm unused files
* remove unused files
* Refactor PTY IPC and add host environment paths
- Split PTY handlers out of inline baseline checks
- Rename local PTY shell provider for clarity
- Pass userDataPath and resourcesPath to host environment
* Establish PTY daemon identity before first await in spawn flow
Move identity setup, session ID minting, and hidden delivery state to
the beginning of preflight, ensuring these complete synchronously
before any awaited operations. Defer async operations like folder
workspace validation; add liveness tracking for SSH provider failures.
Refactor pane spawn reservation to prevent concurrent spawns from
creating duplicate providers.
* Add incarnationId tracking throughout PTY exit lifecycle
Track PTY incarnation IDs in exit messages sent to renderer, and add cause tracking for exit events. This enables proper lifecycle state management when PTYs can be respawned or have multiple concurrent instances. Also adds deadline support to process listing operations and stop-request tracking for better shutdown observability.
* Use fake timers in SFTP namespace tests for deterministic abort handling
Tests now use `vi.useFakeTimers()` to control time during abort scenarios,
advancing timers explicitly instead of waiting on real async delays. Ensures
more reliable test execution without flakiness from timing-dependent behavior.
* Fix PTY spawn lifecycle: handle concurrent races and cleanup abandoned a
Properly release Agent Teams leader handles when spawns are abandoned or fail,
restore provisional PTY sizes on reattachment, and settle concurrent spawn races
for the same pane. Add validation guards for destroyed renderers and improve
handler re-registration to reset delivery state before bridging a new window.
* Move PTY cleanup to localized error boundaries
Restore provisional PTY size when build-options fails and guard pre-allocated handle registration. This ensures cleanup happens at the point of error, not deferred to the general catch block.
* Replace Promise.resolve() with vi.waitFor in PTY claim test
Wait explicitly for the providerSpawn call to be made using vi.waitFor()
instead of relying on event-loop yielding. This makes the test more
deterministic and reduces flakiness from timing assumptions.
* Redact PTY IDs in pending data drop diagnostics
Prevent workspace paths embedded in session IDs from leaking through
diagnostic logs by using redactPtyIdForDiagnostics.
* Mark PTY exit events as observed by provider
Exit handlers now receive `providerExitObserved: true` to
distinguish definitive provider-witnessed exits from inferred
state changes. Preserves optional exit cause when present.
* Add defensive input validation to PTY IPC handlers
Validate that IPC arguments are present and the correct type before
passing them to handler logic. Uses optional chaining and type checks
to safely handle malformed requests from the renderer process.
* Replace direct Electron imports with PTY host bindings
Abstract app, ipcMain, and powerMonitor access through getter functions
to support multiple host environments and improve testability.
* Defend against transient PTY setup failures with state cleanup
Host-env setup failures now trigger cleanup of runtime-allocated PTY state. Cached PTY geometry is preserved after transient reattach failures but cleared when the provider reports the PTY exited before the spawn reply—preventing stale geometry from corrupting future operations. Error handling now distinguishes expired SSH sessions and early-exit conditions to preserve geometry appropriately.
* refactor: split pty-connection.ts under 400 lines
* rm design doc
* refactor(pty-connection): extract reattach payload handlers as factories
- Replace bindApplyReattachPayload with createReattachPayloadHandlers factory that returns handlers instead of mutating session directly, enabling better composability and testing
- Extract waitForUserInitiatedSshConnect as standalone function for reuse across deferred session attach flows
- Create ReattachPayloadSession type to document and isolate required session capabilities
- Add test coverage for overlapping reattach payload attempts
- Clean up comments to remove redundant prefixes (session.pane → pane, session.transport → transport)
* fix(pty-connection): correct sequencing and state bugs in spawn and reat
- Fix terminal tail slice to take prefix instead of suffix, preserving escape
sequence markers needed by next scan
- Clear pending pane serializer when direct SSH retry PTY is unclaimed
- Initialize interrupt status baseline to undefined so first input advances
sequence counter
- Bump reattach generation only after confirming current attempt owns the stream,
preventing superseded results from canceling in-flight prepaint
* fix(pty-connection): correct sequencing and state bugs in spawn and reat
- Fix terminal tail slice to take prefix instead of suffix, preserving escape
sequence markers needed by next scan
- Clear pending pane serializer when direct SSH retry PTY is unclaimed
- Initialize interrupt status baseline to undefined so first input advances
sequence counter
- Bump reattach generation only after confirming current attempt owns the stream,
preventing superseded results from canceling in-flight prepaint
* fix(test): increase poll iterations to prevent Node 26 test leakage
Increase event loop turns from 40 to 200 in the timer settlement loop.
Node 26's libuv poll phase can briefly starve when concurrent workers
transform tests, causing cleanup to leak into the next test. The higher
iteration count ensures async operations complete before returning.
* fix(foreground-output-budgets): use >= for budget window boundary check
At the exact window boundary, the budget should roll over. Change the
comparison from > to >= so the window resets when now equals
windowStart + FOREGROUND_BUDGET_WINDOW_MS, not just after. Add tests
to verify budget rejection and rollover behavior.
* refactor(pty-connection): add status observations and routing improvemen
- Track agent status observations with origin and transition metadata
- Separate interactive redraw input timing from general terminal input
- Restore pane authority on bind and reattach
- Refine routing trust and confirmation state handling
- Invoke queued startup callbacks when PTY is bound
- Resolve Windows shell overrides with user settings
* refactor: extract resolveLaunchAgentCandidate helper
Consolidate duplicated launch-agent resolution logic into a shared helper to prevent future divergence between paneExpectsLaunchAgent and resolveExpectedLaunchTuiAgent.
* refactor(pty-connection): use model snapshot for direct SSH reconnects
Direct SSH reconnects now restore from the full SSH model snapshot (complete scrollback) when dimensions are compatible, instead of the bounded relay tail. Falls back gracefully when incompatible or alternate-screen was exited.
* refactor(pty): retry unverifiable SSH reattaches via preserved bindings
Preserve deferred SSH session IDs longer when they serve as the only retry binding,
allowing the system to attempt recovery through direct SSH retries or PTY remounts
when reattach fails in an unverifiable way. Simplify reconnect model restoration
by removing the conditional model snapshot probe and using relay replay directly.
* test: poll terminal readiness in expectSingleOwningPty
Retry the terminal list assertion with polling to account for timing
delays in PTY state reporting from the runtime.
* refactor(github-client): reorganize client into lifecycle folders
* refactor(github-client): extract PR refresh data and outcome assembly
Separate the derived data calculation and outcome assembly logic from
branch-lookup-resolution into dedicated modules for better separation of
concerns. Modernize type import syntax and format exports consistently.
* refactor(github-client): improve error handling and resilience
Defensive GraphQL parsing prevents partial responses from breaking REST fallbacks.
Cache failures now use shorter TTLs for faster recovery. PR operations have
dedicated error classification. GraphQL mutations track rate limit usage to prevent
quota exhaustion. Data validation improved to reject spurious values.
* Extract check rerun error classification with operation context
Create classifyRerunChecksError() to provide operation-specific error
messages when check reruns fail. This replaces generic GitHub error
copy with context appropriate to what the user attempted (rerun
checks). Follows the pattern of classifyListPrsError and improves
error handling by delegating extraction to extractExecError.
* Make check-rerun not-found error message resource-neutral
Error handling for failed check reruns now covers both workflow-run
reruns and standalone check-run rerequests. Tests verify the neutral
message works for both scenarios.
* refactor: split BrowserPane.tsx under 400 lines
* rm plan
* refactor(browser-pane): reorganize into lifecycle folders
Cut/paste + import rewrites only; no intentional behavior change.
- annotate/, assemble-chrome/, host-guest/, navigate/, stream-remote/,
describe-page/ (foundation sink, zero outgoing edges)
- BrowserPane.tsx is now a pure re-export barrel; its component body moved
verbatim to assemble-chrome/browser-workspace-pane.tsx so no dest file
imports the barrel
- browser-runtime.ts -> describe-page/live-browser-url-registry.ts (banned
name; relocating the contract collapsed the host-guest/navigate mutual pair)
- repath browser-pane test paths in config/reliability-gates.jsonc
* refactor: sync addressBarValueRef with useEffect
Move ref synchronization into useEffect hook with proper dependency
tracking to ensure the ref updates are handled through React's
lifecycle. Consolidate related imports from browser-page-types.
* refactor(browser-pane): fix React lifecycle and external store patterns
- Replace local state + effects with useSyncExternalStore for external subscriptions (draw hint, address bar, slot viewport)
- Fix React StrictMode double-invoke issues in pointer handlers and state updates
- Add keyboard navigation to context menu (arrows, Home, End, Escape) with focus management
- Improve error handling for mobile driver reclaim and grab action IPC failures
- Add test coverage for BrowserFind session flags, keyboard behavior, viewport lifecycle
- Remove react-doctor/no-adjust-state-on-prop-change lint disables (root causes now fixed)
* i18n: extract grab and download UI messages
Move hardcoded toast notifications and error messages to translation
system for both grab annotations and file drop handling. Also apply
lazy initialization to address bar value and remove duplicate event
recording.
* fix(browser-pane): stop mutating refs during render
React Doctor fails static analysis when refs are written in render.
Mirror latest values in useLayoutEffect, and read the current page id
from the latest grab callbacks.
* fix(browser-pane): drop unused grab-mode exit dependency
exit already reads the page id from a ref, so listing browserPageId
trips the changed-code exhaustive-deps gate.
* test(e2e): hide the window when Linux minimize is a no-op
Xvfb has no window manager, so BrowserWindow.minimize() never sets
isMinimized() on the frameless Linux CI window. Hide still occludes
the guest compositor so restore coverage can run.
* refactor: split db.ts under 400 lines
* rm plan
* fix(orchestration-db): add safety guards to database operations
Add status guards to UPDATE statements to prevent late operations from
overwriting changes made by concurrent requests. Validate mutation results
to surface silent no-ops. Extract circuit-break threshold, add transaction
wrapping, and sanitize untrusted input. Bump schema version to v28.
* Add transactional safety to dispatch and message operations
Wrap dispatch failures and batched message updates with SAVEPOINTs to
ensure atomicity and idempotency:
- Dispatch failures now check status guards and roll back if the
related task update fails, preventing partial state corruption
- Message batches (across multiple 500-id chunks) roll back entirely
if any batch fails, avoiding partial mutations
- Add tests verifying idempotency and atomicity under failure conditions
* Handle concurrent writes and improve transactional safety
- Remote question answering: add classification check before and after UPDATE to safely detect concurrent modifications. Prevents false success when the UPDATE loses a race.
- Transaction rollback: wrap in try-catch to prevent errors from masking the original failure.
- Question thread reset: use status update instead of deletion to preserve message references.
* test: add answer replay and race condition edge case coverage
Add test cases for answer replay idempotency, conflict detection, and a race condition between concurrent answer updates in federation relay. Also verify local question state transitions during orchestration reset.
* refactor: split PullRequestPage.tsx under 400 lines
Move the 5888-line PR page into nested domain modules under
src/renderer/src/components/pull-request-page/ and leave a thin public
barrel. No intentional behavior change.
* rm plan
* Improve React stability and remove manual ref caching
- Stabilize React keys in CheckDetailsPanel using content fields instead of array indices to prevent unnecessary remounting
- Remove manual ref-based entries cache in PRFilesCombinedDiffViewer, rely on useMemo dependency (diffEntrySignature) instead
- Move sectionsRef assignment to useLayoutEffect to avoid render-phase ref writes
- Refactor usePRFileSectionLoader to destructure args for readability
* Improve PR page stability: add error handling and fix race conditions
- Add error handling with user feedback (toast notifications) for comment submission, review comments, diff loading, and file view syncing
- Internationalize hardcoded strings for PR state labels and error messages
- Fix race condition in reviewer submission by using a ref-based guard instead of render-time state
- Fix scroll restoration to avoid overwriting target positions with intermediate clamp values
- Add effectiveRepoId parameter for proper repo context in review operations
- Disable reviewer picker during submission to prevent concurrent requests
* Improve PR page stability: add timeout and stable list keys
- Add 45s timeout for diff loading to prevent indefinite hangs
- Fix React list key generation for annotations/jobs using content-based keys with occurrence tracking
- Refactor scroll position caching to properly handle mid-restore teardown
- Replace interpolated error messages with full locale-specific strings for close/reopen actions
* Fix PR diff viewer cache isolation and list key collisions
- Changed list key generation from string concatenation to JSON serialization to avoid collisions with actual content keys
- Added host-aware scoping to diff view caches so local and remote execution don't share entries
- Optimized virtualizer keys to use lightweight revision counter instead of full serialized signature
* Extract PR file state into entry-scoped hooks
Replace manual state resets with custom hooks that automatically clear section heights and active section when switching PR entries. This prevents state leakage between files and simplifies the diff viewer component. Also validates the active section key exists before passing it to child components.
* Improve PR page error messages, accessibility, and stability
- Show actual error messages from failed operations instead of generic fallbacks
- Add aria attributes for combobox/listbox patterns and proper option identifiers
- Consolidate duplicate label/assignee update logic and fix event listener passive mode
- Memoize GitHub source runtime to prevent stale closure in checks callbacks
- Extract filled state badge tone for reuse and fix workspace attachment type
- Guard textarea shortcuts against concurrent saves and add mention query test
* Add explicit PR file content cache eviction
Extract PRFileContentRequestArgs type and create evictPRFileContentRequest
function to handle cache eviction explicitly. Call eviction on load timeout
so retries fetch fresh content. Adds tests for cache behavior.
* refactor: split GitHubItemDialog.tsx under 400 lines
No intentional behavior change.
* refactor: group github-item-dialog into lifecycle folders
Reorganize the 50 flat files under src/renderer/src/components/
github-item-dialog/ into six lifecycle folders:
load-item-details/ shared types, both caches, fetch/settle, state badge
open-dialog/ dialog shell, headers, body, tabs, link copy
discuss-item/ conversation tab, comments, composer, timeline
edit-item-fields/ GH edit section, labels, assignees, status
inspect-pull-request/ combined diff viewer, checks tab
land-pull-request/ PR actions, merge menu, reviewers
No intentional behavior change. All 50 files moved verbatim; the only
edits are relative-import specifiers (sibling paths plus a depth bump
for ../../../../shared) and the hardcoded module paths in the two
source-boundary tests.
Import graph stays acyclic: zero mutual folder pairs, no file importing
4+ sibling folders, no dest file importing the public barrel, and no
per-folder index barrels.
* refactor: split item references and improve diff-viewer remount logic
- Break down full `GitHubWorkItem` props into discrete `itemId`, `itemNumber`, and
`itemRepoId` in mutation and action functions to prevent over-memoization of callbacks
and improve dependency clarity.
- Extract `getPRFilesCombinedDiffSignature()` and use it as a component key to safely
remount the diff viewer when the PR revision changes, replacing generationRef tracking.
- Add `getKeyedCheckAnnotations()` and `getKeyedCheckJobs()` to generate stable,
collision-resistant keys for check arrays that may contain duplicates.
- Consolidate interpreter timeouts into a single `SPAWNED_INTERPRETER_TIMEOUT_MS` constant
and apply it via describe options rather than per-test values.
* refactor: improve github-item-dialog repo context and i18n coverage
- Add repoId prop to ConversationTab for explicit repo context override
- Internationalize UI strings in diff viewer and PR action components
- Improve error handling with cache rollback and guard cleanup on sync failure
- Enhance cache key validation for cross-window invalidation by repoPath
- Add repository access validation before rendering diff viewer
- Fix cross-platform issues: skip symlink test on Windows, normalize CRLF in test assertions
* Refactor check button i18n key and update text
- Replace hash-based key with semantic name for maintainability
- Change button label to "Open in browser" for broader context
* refactor: split editor.ts under 400 lines
Move editor slice types, file-id/tab helpers, and action factories under
src/renderer/src/store/slices/editor/. The source file is now a public
barrel. No intentional behavior change.
* refactor: split editor-chrome-slice into state modules
- Move EditorDraftState, ExplorerDirState, and RightSidebarState type definitions into their respective action files
- Simplify state creator return types from Pick<EditorSlice, ...> to specific state types
- Improve modularity by colocating types with implementations
* refactor(persistence): extract modules to half persistence.ts
* refactor(persistence): tighten the extracted operations seam
Review follow-ups on the module extraction, all behavior-neutral.
The extracted operations read and mutate the Store's state object in place, but
every seam typed it as a bare PersistedState, so nothing at the boundary said a
caller must pass the live reference — a future caller handing over a clone would
have its writes silently dropped. Name that contract: StoreOwnedPersistedState
carries it to every operations interface and every mutating free function.
normalizePersistedPaneIdentityState and backfillFolderScopeConnectionIds stay on
PersistedState; they build a fresh state rather than mutating the Store's.
The six *PersistenceOperations wrappers were constructed per delegate call. They
are stateless today, so this was inert, but any future instance state would be
lost between calls. Memoize them, and mark state and gitUsernameCache readonly
so the compiler enforces the single-assignment invariant memoizing them relies
on.
Also: restore flushSshPtyConsumerRecovery, whose inlining left its rationale
duplicated at both call sites; document that migrateWorktreeIdentity's boolean
gates the caller's save, since the extracted function kept no docs of its own;
and merge a duplicate shared/types import that was failing lint under
--deny-warnings.
* delete plan doc
* refactor(persistence): add error recovery and improve field cleanup
- Rollback failed migrations to prevent corrupted state that blocks retry
- Gracefully skip malformed entries in normalization instead of aborting
- Strip retired fields to prevent orphaned state and sync issues
* refactor(persistence): drop the redundant persistence- filename prefix
The extracted modules already live in src/main/persistence/, so name
them after the domain they own. Point leftover shared/types imports
at the real type modules while touching those files.
* refactor(persistence): optimize lookups and fix unsanitized updates
- Use Maps instead of repeated array searches for O(1) lookups
- Apply sanitized updates instead of raw input in ui-state-update
- Compare fields directly rather than JSON strings to avoid false dirty states from persisted key ordering differences
* refactor(persistence): group modules into lifecycle folders
Move the 42 flat persistence modules into six folders named for what the
module does, and lift the Store class out of the barrel so persistence.ts
becomes an 8-line public surface.
Bodies are unchanged: every moved file diffs clean against HEAD once import
blocks are excluded. Only import specifiers were rewritten, by resolving each
one to an absolute path and mapping it through the move map.
Store keeps its existing max-lines suppression; its baseline entry is repathed
rather than re-added. Its 119-method public API sets a ~525-line floor, so it
cannot meet the 400-line cap without breaking the API for 153 importers.
* Sanitize worktree visibility sources and preferences on hydration
Ensure invalid or corrupted data from disk (untracked whitespace,
relative paths, bogus preference values) is cleaned during load
rather than corrupting the in-memory store.
`source-control-dropdown-items.ts` was 524 counted lines behind an
`eslint-disable max-lines`. It splits along the seams the resolver already had:
- `source-control-dropdown-item-types` — the row union, consumed by CommitArea,
the composer and the action dispatcher without pulling in the state machine.
- `source-control-dropdown-labels` — count/label/title wording.
- `source-control-dropdown-action-context` — the branch, upstream and review
facts every row reads, derived once so rows cannot disagree about them.
- `source-control-dropdown-commit-items` / `-remote-items` / `-review-items` —
the three row groups, each keeping its own disabled-reason ladder intact.
`resolveDropdownItems` is now just the entry order plus the conflict-abort and
hosted-review-busy passes.
Verified output-identical to the pre-split resolver: a differential harness ran
both implementations over 16,380 generated input combinations (every upstream
shape × PR state × conflict operation × blocked reason × staged count ×
provider) and compared entries deeply. The harness was scaffolding and is not
committed.
Splits the nine oversized modules in the daemon/provider/runtime domain into
focused per-concern files and drops their max-lines baseline entries.
- daemon: `Session` decomposes into an output plane (emulator, pending-output
buffer, client fan-out), a producer-pause controller, a shell-ready barrier and
a termination controller; `DaemonClient` into socket connect, hello handshake,
ndjson readers, pending-request settlement, listener registry and notify
settlement; `daemon-health` into pid-file parsing, process identity,
stale-kill, TCC attribution and bundle staleness; `shell-ready` into the marker
constant and the bash/zsh rcfile generators.
- providers: local-pty shell-ready wrapper generation, wrapper root, startup
command and bash rcfile split out of local-pty-shell-ready.
- runtime: `Coordinator` sheds DAG convergence, decision gates, escalation
triage, the runtime contract, the stale-base flag and task dispatch; the
files/git/github rpc modules split into per-domain method groups.
Behavior-preserving: the extracted units keep their original construction order,
guards and timer lifetimes, and every RPC method name is still registered.
Test `vi.mock` surfaces were re-partitioned to follow the moved symbols.
The two tab-group hooks, the pane manager, worktree activation, and the terminal
pane context menu each carried a file-level `eslint-disable max-lines` and ran
461-745 counted lines against a 300-line budget. AGENTS.md calls for splitting
rather than suppressing, and config/max-lines-baseline.txt is a shrink-only
ratchet, so this removes all five suppressions and prunes their entries
(341 -> 335).
Pure move, no behavior change. useTabDragSplit is cut into gesture lifecycle,
hover preview and drop commit; useTabGroupWorkspaceModel into item projections
plus the tab-close, close-scope, activation and creation command sets; the pane
manager into host, tree mutations, pane creation, drag wiring, reparent frame
tracking, layout sweeps and rendering diagnostics.
react-hooks exhaustive-deps stays at zero warnings, matching HEAD. Dependency
additions are only stable identifiers -- refs and callbacks that became
parameters -- and no `.current` dereference was added to any dependency array.
Verified: oxlint clean, ratchet passes, typecheck clean, full unit suite green
(the three remaining failures are pre-existing load flakes in untouched files,
each green when re-run serially), no new runtime import cycles among 1020
modules, no barrel files, and no lint suppression added anywhere.
The four editor modules, the diff-comment decorator and the file-type icon table
each carried a file-level `eslint-disable max-lines` and ran 319-806 counted
lines against 300/400-line budgets. AGENTS.md calls for splitting rather than
suppressing, and config/max-lines-baseline.txt is a shrink-only ratchet, so this
removes all six suppressions and prunes their entries (341 -> 334).
Pure move, no behavior change. MonacoEditor is cut along its own seams -- mount,
input bindings, markdown annotations, decorations, content sync, view-state
persistence and reveal scheduling -- with the markdown overlay becoming its own
component. useEditorPanelContentState splits into file and diff content loaders
plus the active-tab load and reload triggers.
When the mount module came in at 370 counted lines, over the 300 ceiling, it was
split again into its parameter types and its input bindings rather than carrying
a suppression.
Hook usage is identical to HEAD across all three React split families: the same
counts of every hook type between each original and its extracted modules, so no
hook was added, dropped, or converted to a plain function. react-hooks
exhaustive-deps stays at zero warnings, matching HEAD.
Verified: oxlint clean, ratchet passes, typecheck clean, full unit suite green
(the four remaining failures are pre-existing load flakes in untouched files,
each green when re-run serially), no new runtime import cycles among 884
modules, and no lint suppression added anywhere.
The six right-sidebar modules and the remote file browser each carried a
file-level `eslint-disable max-lines` and ran 347-797 counted lines against
300/400-line budgets. AGENTS.md calls for splitting rather than suppressing, and
config/max-lines-baseline.txt is a shrink-only ratchet, so this removes all seven
suppressions and prunes their entries (341 -> 333).
Pure move, no behavior change.
Two renderer-specific hazards were found and fixed rather than shipped.
First, effect and ref LIFETIME. FileExplorer's `if (!worktreePath) return` sits
above the files pane, so moving the worktree-reset effect into that pane made its
guard ref `lastResetWorktreePathRef` die on any render where worktreePath was
transiently null (workspace-list refresh, store rehydrate, remote worktree
reload). On remount the guard read null, so the reset fired even when returning
to the SAME worktree -- wiping dirCache, collapsing every expanded directory,
clearing the name filter and undo history, and forcing a full re-read over SSH.
The tree-load effects now live in a hook called from FileExplorer above the early
return, and the pane is purely presentational with zero hooks. That also restores
the original parent-effect ordering, which had shifted because React flushes
child effects before parent effects.
Second, extracting a hook silently degrades dependency analysis: `setX` setters
that the linter knew were stable when created locally become opaque parameters,
producing 8 new react-hooks/exhaustive-deps warnings where src/renderer had zero.
Those are fixed by listing the genuinely stable identifiers (useState setters and
ref OBJECTS). No `.current` dereference was added to any dependency array, since
that would change callback identity as the ref mutates.
Verified: oxlint clean with exhaustive-deps back to zero, ratchet passes,
typecheck clean, full unit suite green on the first pass, no new runtime import
cycles, no lint suppression added, and hook usage identical to HEAD across both
split families.
The three usage scanners and their stores, plus the renderer usage-overview
model, each carried a file-level `eslint-disable max-lines` and had grown to
338-769 counted lines against a 300-line budget. AGENTS.md calls for splitting
rather than suppressing, and config/max-lines-baseline.txt is a shrink-only
ratchet, so this removes all seven suppressions and prunes their entries
(341 -> 334).
Each file is cut along the seams it already had -- and that several of the
suppression comments named out loud: filesystem discovery / record parsing /
attribution / aggregation for the scanners, and pricing policy / scope filters /
rollups / session rows / automation attribution for the stores.
Pure move, no behavior change. Code is relocated verbatim; the only edits are
import plumbing and, where a private class method became a free function, the
mechanical `this.state` -> `state` parameter threading. Every converted call
site passes `this.state` at call time and the automation path takes a live
`getState: () => this.state` getter, so no state is snapshotted. No barrel
exports: each new module owns real logic and importers point at the owner.
Verified: oxlint clean, ratchet passes, typecheck clean, full unit suite green
(remaining failures are pre-existing load flakes in untouched files, each green
when re-run serially), no import cycles among the 64 affected modules, and a
statement-level diff of every split confirms the moves are verbatim.