Inline pending approvals into composer header and actions - #184
Conversation
Co-authored-by: codex <codex@users.noreply.github.com>
- Treat pending approvals as a dedicated composer state - Disable prompt input and hide command menu/image chips while approval is active - Move approval decision buttons into footer actions and simplify the header panel
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
| {/* Error banner */} | ||
| <ProviderHealthBanner status={activeProviderStatus} /> | ||
| <ThreadErrorBanner error={activeThread.error} /> | ||
| <PendingApprovalsPanel |
There was a problem hiding this comment.
Missing approval-state guard in send and key handlers
Medium Severity
The onComposerCommandKey handler calls onSend() when Enter is pressed (line 3222) without checking isComposerApprovalState. The onSend handler itself also has no early-return for approval state. If the Lexical editor dispatches key commands while disabled (Lexical's setEditable(false) still processes registered commands), pressing Enter during approval state could trigger onSend, which would proceed with the stale prompt value — potentially submitting a plan follow-up or sending a message while the user intended only to resolve an approval.
Additional Locations (1)
Merges `pingdotgg/t3code` into the fork: `7445aa733..5781b52`, 41 commits. 191 files landed (`git diff --stat HEAD^1 HEAD`) against 192 in the upstream range; the gap of one is `apps/server/src/cli/pair.ts`, a deliberate fork deletion that pingdotgg#12657 modified — kept deleted. Fork delta 786 files. Four conflicts, each resolved with the verdict `preflight.mjs` printed. The one worth reading is `ProjectScriptsControl.tsx` / `chat/ChatHeader.tsx`: upstream extracted a shared `scriptItems` const and moved the header's controls into a `headerActions` fragment, so the fork's task-scoped-script deltas had no anchor left and were re-applied onto upstream's structure rather than kept as the fork's copy of it. Details in `docs/fork/upstream-merge-log.md`. `verify.mjs`: all 10 checks pass. Two failures were found and fixed here — the `dataUpdatedAt` field pingdotgg#12545 added to `EnvironmentQueryView`, which the fork's two sandbox hooks build by hand; and a latent bug in `features.test.ts` where `import.meta.glob` keys a sibling as `./name.ts`, so every inventory delta guard on a file in `apps/web/src/fork/` had been silently unchecked since the guards landed. The first commit on this branch, `docs(fork): stack an upstream merge on an open merge PR`, is the instruction change asked for separately: a run that finds a merge PR still open now branches from its head and opens its PR against that branch instead of stopping. ## Usable as-is - Undo for settle, snooze and archive, with a `mod+z` shortcut (pingdotgg#12848), and undo after unpin (`6b0a04ade`). - Composer fixes: control visibility, Escape handling, paste, inline chips (`6cc7f7006`, `a4bc7deb9`, `dca84efb5`, `c789cd174`). - Branch-picker fixes (`67285e4b8`, `7ade2d2c6`) and the narrow chat-header layout (`c14f6015b`). - Pull request link hover preview (`933492470`) and sidebar PR status reuse (pingdotgg#12545), diff whitespace settings (`4a560b4e4`), mobile diff word wrap (`f6cc6bc7e`). - Sidebar shelf motion (`f391b88c3`), notification icons (`30e3649c3`), the `MiddleTruncate` component (`f7efb5354`), Codex citation backslashes (`2efb8178d`). - The client half of the raised attachment limits (pingdotgg#12620) — the contract now allows 100 attachments per message. ## Unsupported in Moatless / needs implementation - **The device hub**, seven commits of it (pingdotgg#12819, pingdotgg#12818, pingdotgg#12817, pingdotgg#12816, pingdotgg#12807, pingdotgg#12809, pingdotgg#12639) across `apps/server/src/device/*`, `apps/web/src/components/device/*` and `packages/contracts/src/device.ts`. Already held by `FEATURES.deviceHub: false` and the existing `UnsupportedMethodError` entries for the `device.*` methods; the new `DeviceHostUpdates.tsx` needed no gate of its own, since all three of its call sites are already behind that flag. - **Worktree-mode-only UI** (`a6cb1dd20`, `584450a1f`) — behind `FEATURES.worktreeSelection`. - **Connections copy** (`ead1dee22`) — behind `FEATURES.connections`. - **Pull request detail surface** (`a9ab9049b`, `411da2a73`, `6a699f0f2`) — behind `FEATURES.pullRequestSurface`; Moatless serves only `pullRequests.summary`. - **Electron-only preview recording** (`55c24273a`, desktop half) — the fork ships no desktop build. ## Backend behavior to consider reproducing in Moatless New entries in `docs/fork/gaps.md`, 2026-09-21 group: - **Attachment and image payload budget** (pingdotgg#12620). The per-message cap goes from 8 attachments to 100, with a new 80 MiB aggregate image budget beside the existing 10 MiB per-image one, derived in `getProviderAttachmentLimitError` and applied twice by the server — before decoding, and again per decoded data URL, so a client that under-reports `sizeBytes` is still caught. Moatless normalizes turns itself and has the raised count already; without the aggregate check, 100 images at the per-image limit is a gigabyte of base64 bound for a sandbox. - **Idempotent host teardown and tool reclaim** (pingdotgg#12807, pingdotgg#12819). Shutting down an already-stopped simulator is treated as success, and obsolete managed tool versions are pruned while current, previous, active and half-installed ones are kept. Moot while `FEATURES.deviceHub` is off, recorded because Moatless tears down sandboxes and installs managed tooling on its own schedule. - **Per-signal OTLP export settings** (pingdotgg#12657), folded into the existing pingdotgg#12493 bullet: traces, metrics and logs each carry their own endpoint and headers, so one signal can go elsewhere or be turned off without the other two following. Contracts: `unsupported-methods.mjs` reports ADD 0 and DROP 0, so no union entry in `packages/contracts/src/rpc.ts` changed. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --- Moatless task: https://moatless.soaplabstest.com/tasks/4ed6d32e-0278-4fff-9a6e-923ded2b30fe


Summary
1/N) when multiple approvals are pending.Testing
Note
Medium Risk
Changes the chat composer’s state/priority logic and approval-response UI, which could regress send/compose behavior or block interactions if the approval state is misdetected. No backend/API or security-sensitive logic changes.
Overview
Pending approvals are now handled inline in the composer instead of a separate banner/panel. The UI shows only the active approval (with
1/Nposition when multiple are queued) in a new composer header and moves approval decision buttons into the composer’s bottom toolbar.While an approval is pending, the composer input is disabled/cleared and its placeholder shows the approval detail, and the command menu + image attachments UI are suppressed to keep the flow focused on resolving the approval.
Written by Cursor Bugbot for commit 005dd9a. This will update automatically on new commits. Configure here.
Note
Inline pending approvals into the chat composer by disabling
ChatViewinput, showing a header, and replacing the toolbar with approval action buttonsIntroduce approval-aware state in
ChatViewto render an inline header and compact actions during an active approval, hide command menu and images, disable and clear the prompt input with an approval placeholder, and remove the top-of-thread approvals panel. AddComposerPendingApprovalPanelandComposerPendingApprovalActions. RemovePendingApprovalsPanel. Changes center on ChatView.tsx.📍Where to Start
Start with the approval gating and composer branching in
ChatViewwithin ChatView.tsx, focusing on howactivePendingApprovalandisComposerApprovalStatecontrol rendering and actions.Macroscope summarized 005dd9a.