🤖 refactor: decompose the ChatInput composer into deep hooks - #4013
Conversation
This comment has been minimized.
This comment has been minimized.
|
@codex review |
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6e4d1387ad
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review |
|
Codex Review: Didn't find any major issues. What shall we delve into next? Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
This comment has been minimized.
This comment has been minimized.
|
@codex review |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
Codex Review: Didn't find any major issues. Swish! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d92b0b4b6b
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review |
|
Codex Review: Didn't find any major issues. Already looking forward to the next diff. Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
This comment has been minimized.
This comment has been minimized.
|
@codex review |
|
Codex Review: Didn't find any major issues. Keep it up! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
This comment has been minimized.
This comment has been minimized.
74d4e13 to
6ea1b80
Compare
|
@codex review |
This comment has been minimized.
This comment has been minimized.
6ea1b80 to
33414ea
Compare
|
@codex review |
This comment has been minimized.
This comment has been minimized.
|
Codex Review: Didn't find any major issues. Delightful! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
33414ea to
1cd8bd4
Compare
1cd8bd4 to
2ce16e8
Compare
_Generated with `xum` • Model: `openai:gpt-5.6-sol` • Thinking: `high`_ <!-- mux-attribution: model=openai:gpt-5.6-sol thinking=high -->
Remove redundant comments and stop exporting extraction-only helper types.
Remove dead hook fields, duplicate metadata work, redundant suggestion branches, and repeated test structure.
85bfc67 to
830926c
Compare
…orts (coder#4472) ## Summary Deletes browser production code that only tests still called, and moves the tests that guarded live behavior onto the live code path. Part of the test-audit follow-up campaign (frontend area, WS7). ## What was removed | Removed | Why it was dead | What happened to its tests | | --- | --- | --- | | `StatsTab` component + its test-only `_snapshot`/`_clearStats` props and `useStatsData` overrides | No production caller since coder#2729 moved the Stats tab to `StatsContainer` (`TimingPanel` + `ModelBreakdownPanel`) | `StatsTab.clear.test.tsx` replaced by `TimingPanel.clear.test.tsx`, which drives the live path: real `WorkspaceStore` stats subscription + `APIProvider` client whose `workspace.stats.clear` rejects | | `compareRecords`, `compareArrays` (`useStableReference.ts`) | Only `compareMaps` is used (`App.tsx`) | 12 comparator tests deleted; stale "tested manually via useUnreadTracking…" comments fixed | | `closeSplit` (`rightSidebarLayout.ts`) | Never called in production since coder#1340 | Test deleted | | `isActionableTaskExecutionStatus` | Last caller removed in coder#4341 | No tests | | `shouldRefreshInlineSkillSuggestions` | coder#4013 made inline suggestions synchronously derived, so there is no refresh gate | Tests deleted | | `getAnthropicThinkingDisableReason` + `hasAnthropicThinkingSignature` | coder#1450 stopped disabling Anthropic thinking | Tests deleted; the one transform test that used it as an oracle now asserts the preserved signature directly | | `useProjectGitStatuses` (`GitStatusStore.ts`) | No production caller | None in CI | | `buildReviewDiffPathFilter`, `normalizeReviewPanelAssistedHunks` (test-only wrappers in `ReviewPanel.tsx`) | Production calls `buildReviewDiffPathFilterSpecs` / `getReviewPanelPathContext` + `normalizeAssistedReviewHunks` directly | Tests retargeted to those production functions (`getReviewPanelPathContext` is now exported) | | `computeTaskAwaitPollGroupInfos` (test-only wrapper) | ChatPane calls `computeOperationalBundleInfos({ taskAwaitPollsOnly })` | Tests use a local fixture helper around the production function | | 2 `/fork` cases in `parser.test.ts` | Same contract and name as `fork.test.ts` | Deleted | Retained on purpose (test reset seams, not dead code): `__resetForTests` (highlight worker), `resetAiSelectionIntentForTests`, `overlayWorkspaceStoreRaw` (test-support module). ## Validation - Sweep: every `export` under `src/browser` (excluding stories) checked for non-test references across `src/`, `tests/`, `vscode/`, `scripts/`, `.storybook/`; orphan-module sweep found only the two HTML entry points. - `TimingPanel.clear.test.tsx` fails when `handleClearStats` stops setting the error (mutation check). - `bun test` on RightSidebar, hooks/useStableReference, utils/{messages,agentSkills,ui,rightSidebarLayout}, stores/GitStatusStore: 1141 pass. - `make static-check` green. LOC: production +11 / −585; tests +134 / −355. --- _Generated with `xum` • Model: `anthropic:claude-opus-5-5` • Thinking: `high` • Cost: `$4.21`_ <!-- mux-attribution: model=anthropic:claude-opus-5-5 thinking=high costs=4.21 -->
Summary
Decomposes the 4,011-line
ChatInputcomposer (ChatInputInner: 27 useState / 37 useRef / 32 useEffect conflating 7 concerns) into three deep hooks plus a pure send-preflight function, with a net -142 LOC delta. Behavior-preserving: no UX, keybind, or feature changes.Background
Refactor #7 from the 2026-08-29 architecture review (evidence at
f04e0f8a3). Every keystroke re-evaluated all 32 effects; the ~570-line send preflight and the four suggestion channels were untestable without DOM, and the four channels duplicated the same cursor/token logic.Implementation
useComposerSuggestions(~500 lines): unifies the four suggestion channels (slash command, @-mention, skill, symbol) behind a single cursor/token seam. Self-contained per repo guidance: derives experiments, plugin enablement, and draft-discovery state internally; the boundary is the input seam plus identity. The token matcher is a pure exported function with DOM-free tests.useComposerAttachments(~190): attachment state, processing counts, PDF/media-type validation, paste/drop/pick entry points, and draft-attachment persistence.useComposerDraft(~160): storage-key scoping (workspace/creation/pending-draft), input persistence and restore across workspace switches, draft-review lifecycle.prepareMessagePayload(~140): pure payload assembly extracted fromhandleSend; the remaining orchestrator is guard, async resolution, prepare, dispatch. Covered by table-driven unit tests, including the compaction-metadata ref gate (proven red-green).index.tsx: 4,011 to 2,924 lines; effects reduced (32 to ~22). No manual memoization anywhere in the new hooks (React Compiler convention); the two effects that previously leaned onuseCallbackidentity now key on data (editingMessage?.id) or hand out latest-ref wrappers (onReadyAPI), and the document keydown listener uses a latest-ref handler attached only on visibility.Net LOC
Irreducible additions:
useComposerSuggestionsconsolidates four previously duplicated channel implementations behind one seam (replacing ~640 deleted lines fromindex.tsx/CommandSuggestions.tsx);prepareMessagePayload+ its tests (+211) make the send preflight unit-testable for the first time, offset by pruning mock-heavy structure-asserting tests (CommandSuggestions.test.tsx-79,symbolShortcuts.test.ts-92 net, collapsed into table-driven cases).Validation
fileMentionsWithSlashCommands) and an edit-populate effect that clobbered in-progress edit text once draft helpers lostuseCallbackidentity (e2ereview.spec). Both suites now pass locally and in CI, alongsidemake static-checkand whole-file bun runs of all touched test files.Risks
Highest-traffic UI surface in the app. The riskiest moves are the unified suggestion token seam (channel trigger/filter/selection semantics), the send preflight extraction, and the effect re-keying described above. Mitigated by the new pure unit tests, the full UAT regression pass, the e2e/jest coverage that already caught the two regressions, and keeping
ChatInputProps/ChatInputAPIunchanged.Generated with
xum• Model:anthropic:claude-fable-5• Thinking:xhigh• Cost:$155.26Stack
Layer 8/10 of the architecture refactor stack (net -5,101 LOC overall). This PR's diff is only this layer, against
mike/arch-turn-context-assembler.