Skip to content

refactor(hooks): dissolve src/hooks/workStation into owning modules - #821

Merged
Chloe-JY merged 5 commits into
developfrom
dev/dissolve-hooks-workstation
Aug 16, 2026
Merged

refactor(hooks): dissolve src/hooks/workStation into owning modules#821
Chloe-JY merged 5 commits into
developfrom
dev/dissolve-hooks-workstation

Conversation

@Harry19081

Copy link
Copy Markdown
Member

Summary

  • Dissolve src/hooks/workStation/ (78 files, the largest subtree in the global hooks layer) into the modules that own each hook; same treatment for hooks/dependencies, hooks/git/sourceControl, hooks/testRunner, hooks/benchmark.
  • New cross-cutting home src/hooks/tabHost/ for the workstation tab-host contract (useWorkStationTabs, usePublishWorkstationTabHeader, useWorkStationPanels, shortcut bridge, …) — the only part of the old dir that is genuinely consumed by WorkStation, ProjectManager, MainApp, features and engines.
  • Hook return contracts that store/ and services/ depend on move to src/types/workstation/{output,gitOutputIntegration}.ts.
  • ~1,300 lines of dead code removed; all per-group barrels deleted (consumers import files directly).
  • no-restricted-imports tripwire on the old paths, with messages pointing at the new homes.

Problem

A static import-graph pass over src/ showed src/hooks/ — nominally the global hooks dir — had drifted into a dumping ground:

  • hooks/workStation/ was a module named after modules/WorkStation living in the global layer. ~60 of its 78 files had exactly one consuming area; the top-level barrel hid this (40 files imported through it, and the barrel itself carried a "DO NOT re-export browser — circular deps" warning).
  • It held ~1,300 lines with zero consumers (indexing/, search/useCodeSearch, usePanelResize, useTabSwitchVerification, a duplicated latestRequestGuard), plus an orphan src/hooks/index.ts re-exporting from engines/.
  • It created inverted edges: hooks → modules/WorkStation/Browser, hooks → scaffold/ContextMenu, hooks → CodeEditor/…/ProblemsContent, and store → hooks / services → hooks via hook return types.
  • The same single-area pattern repeated in hooks/dependencies (MainApp), hooks/git/sourceControl + hooks/testRunner (CodeEditor), hooks/benchmark (BenchmarkPanel).

Solution

Five commits, each independently typechecking, reviewable in order:

  1. Dead code — delete the zero-consumer hooks and the orphan hooks/index.ts.

  2. Contracts out of hooksUseOutputChannelsReturn / UseTaskOutputIntegrationReturntypes/workstation/output.ts; useGitOutputIntegration/types.tstypes/workstation/gitOutputIntegration.ts. store/…/{gitOutputAtom,taskOutputAtom} and services/guiAgent now import types, not hooks.

  3. Dissolve hooks/workStationgit mv per this map, then a codemod that splits barrel imports per symbol and recomputes relative imports in moved files:

    Old (src/hooks/workStation/…) New
    tabs/*, useWorkstationTabHeader, useWorkStationTabShortcutBridge, panels/useWorkStationPanels src/hooks/tabHost/
    editor/*, useCodeEditor/, fileContent/, diagnostics/, output/, useGitOutputIntegration/, git/useGitDiffState modules/WorkStation/CodeEditor/hooks/
    browser/useBrowserPaneState, useBrowserSessions, browserDiagnosticsPolicy modules/WorkStation/Browser/hooks/
    database/* …/FilePreviewContent/DbPreviewView/ (sole consumer)
    sessionCapture/* features/SessionSetup/hooks/
    panels/useContextMenu, contextMenuSearch{Handlers,Roots} scaffold/ContextMenu/
    git/useDiff engines/GitWorkflow/GitHubDiff/ (sole consumer)
    useNarrowChatFocus, browser/useOpenUrlInBrowser src/modules/ (sole consumer modules/index.tsx)
    latestRequestGuard util/core/
  4. Wave 2dependenciesmodules/MainApp/Integrations/hooks/ (+ usePostPaintGitProbeapp/root/); git/sourceControl + testRunnerCodeEditor/hooks/; benchmarkfeatures/BenchmarkPanel/hooks/; generateCommitMessage (a bare invoke wrapper) → api/tauri/git/commitMessage.ts so the ChatPanel test that exercises it does not import from modules/.

  5. Guard + docsno-restricted-imports entry in .eslintrc.js; hooks placement rules added to src/util/util-organization.md (dead hooks-organization.md link fixed).

Placement rules applied uniformly: single consumer area → colocate; cohesive family over one store stays together (useFocusTab/usePinnedTabs/useSelectedFile go to tabHost with useWorkStationTabs); generic primitive → util/; no new barrels; never create an upward edge (extract the type/API wrapper instead). hooks/fileReview was considered and kept — it is consumed by engines/ChatPanel/ChatView.tsx plus two modules, so it is genuinely cross-cutting.

Potential risks

  • In-flight branches importing @src/hooks/workStation…, @src/hooks/dependencies…, @src/hooks/git/sourceControl…, @src/hooks/testRunner… or @src/hooks/benchmark… will fail lint/typecheck on rebase. The new no-restricted-imports message names the replacement path for each group. Bulk of the churn is a mechanical import rewrite; no runtime logic changed.
  • Pure relocation + type extraction: no behavior change intended, no schema/migration, no i18n. The three vi.mock sites that mocked the barrel now mock the specific file (CanvasApp*.test.ts, GitHistoryContent.remount.test.ts).
  • Not exercised: a manual smoke of the app surfaces whose hooks moved (CodeEditor source-control sidebar / problems / testing / DB preview, Browser pane, ProjectManager work items header, Cursor/Kiro session setup, Cmd-K + right-click menu, Benchmark sidebar). Typecheck + full unit suite are clean, but a click-through of those surfaces before merge would be worthwhile.
  • Left as follow-ups (deliberately not mixed into a move PR): two same-named useFileContent.ts now under CodeEditor/hooks/{fileContent,useCodeEditor}/; duplicate OutputChannel interface in types/workstation/gitOutputIntegration.ts vs output.ts; three loose hooks still at CodeEditor/ root; gitDiffActions.test.ts asserting generateCommitMessage.

Test plan

  • pnpm typecheck — 0 errors (also gated per commit by the pre-commit hook)
  • pnpm lint over src/ — 0 errors, including the new no-restricted-imports rule
  • pnpm test — 1099 test files / 8680 tests pass; the 31 relocated test files are discovered at their new paths
  • Import-graph re-run: src/hooks/ 328 → 238 files, single-consumer 91 → 59, orphans 14 → 6; layer-inverted edges 111 → 101 (10 removed, 0 added — diffed edge by edge); zero remaining store/services → hooks edges from the moved set
  • rg for the old paths across src/** → only the eslint tripwire and the doc mention them
  • Manual smoke of the moved surfaces (see risks) — not run

Submit checklist

  • The PR is focused and has a scoped Conventional Commits title, such as feat(scope): summary or fix(scope): summary.
  • I ran the relevant checks, or explained why they were not run.
  • No secrets, private config, generated output, or unrelated formatting changes are included.
  • Docs, screenshots, and locale updates are included when the change needs them.

Delete hooks with zero consumers: workStation/indexing (2 hooks), workStation/search
(useCodeSearch + duplicate latestRequestGuard), usePanelResize, useTabSwitchVerification,
benchmark/useBenchmarkRun, and src/hooks/index.ts (unreferenced barrel re-exporting engines/).
UseOutputChannelsReturn and UseTaskOutputIntegrationReturn now live in
types/workstation/output.ts; useGitOutputIntegration/types.ts moves to
types/workstation/gitOutputIntegration.ts. store/ atoms and services/guiAgent
no longer import from src/hooks (inverted edges), and the hooks import their
own return contracts from types/.
hooks/workStation was a module-named subtree in the global hooks layer;
~60 of its files had exactly one consumer area. Files now live next to
their consumers:

- hooks/tabHost/           cross-cutting tab-host contract hooks (tabs,
                            header publish, panels, shortcut bridge)
- modules/WorkStation/CodeEditor/hooks/  editor, fileContent, diagnostics,
                            output, gitOutputIntegration, useCodeEditor
- modules/WorkStation/Browser/hooks/     browser pane/session hooks
- modules/                 useNarrowChatFocus, useOpenUrlInBrowser
- features/SessionSetup/hooks/           session capture / OAuth capture
- scaffold/ContextMenu/    useContextMenu + search handlers/roots
- engines/GitWorkflow/GitHubDiff/useDiff.ts
- util/core/latestRequestGuard.ts
- DbPreviewView/           useDbPreview + utils next to sole consumer

All per-group barrels removed; consumers import files directly.
- hooks/dependencies  -> modules/MainApp/Integrations/hooks (useSystemDependencies,
                          usePrerequisiteCheck) and app/root/usePostPaintGitProbe.ts
- hooks/git/sourceControl -> modules/WorkStation/CodeEditor/hooks/sourceControl;
                          generateCommitMessage (a bare invoke wrapper) -> api/tauri/git/commitMessage.ts
                          so the ChatPanel test does not import from modules/
- hooks/testRunner    -> modules/WorkStation/CodeEditor/hooks/useTestRunner.ts
- hooks/benchmark     -> features/BenchmarkPanel/hooks (WorkStation sidebar imports the feature)

Group barrels removed; consumers import files directly.
no-restricted-imports blocks @src/hooks/{workStation,dependencies,
git/sourceControl,testRunner,benchmark} with messages naming the new
homes, so in-flight branches get a pointer on rebase. util-organization.md
gains the hooks placement rules and drops its dead hooks-organization link.
@Chloe-JY
Chloe-JY merged commit 47cb514 into develop Aug 16, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants