9815319d5f
PaneTab gated its hover close button on two independent inputs: the onClose verb, and a showCloseButton prop that TreeGroup fed from a showCloseButton flag on the pane contribution. The middle-click and Meta-click gestures read only onClose. A tab could therefore close on a pointer gesture and advertise no control for it. The flag had no user that hideOnly did not already cover. Both setters also set hideOnly: true, which removes every close gesture: - the sessions pane (app/contrib/controller.tsx), - the Bots pane (plugins/hermes-bots/plugin.js). The flag was an opt-out marker with no reachable effect, so this change deletes it instead of teaching it to track the gestures. onClose alone now decides both shapes. A tab that closes shows the button. A tab without the verb shows nothing. To make a tab uncloseable, give it no close verb. hideOnly and uncloseable keep their meaning. They gate the verb, and both shapes follow the verb together. The DialogContent and SheetContent prop of the same name is a different prop and stays. It has no close verb to derive from, and one caller changes it while the dialog is open. Tests: the new tab-close-affordance test renders the real TreeGroup and asserts that button presence equals middle-click closure. It covers hideOnly chrome, a plain side pane, the uncloseable workspace, and a session tile. It reads closure from the layout tree, not from a spy, so a wired-up mock cannot pass it. A regression that hides the button on a closeable tab fails two of the four cases. The compiler rejects the deleted prop, so the test carries no fixture for it. The pane-tab unit test moves off the deleted prop. Verified with the full apps/desktop vitest suite, npm run typecheck, and npm run lint. Two electron process-spawn tests fail on this machine. They also fail on a clean tree, and they do not touch the pane shell.