From eb2104ada4acf503b230c91ca15affe5d6cd3eb1 Mon Sep 17 00:00:00 2001 From: "bert.hausmans" Date: Wed, 3 Jun 2026 03:33:11 +0200 Subject: [PATCH 1/9] chore: exempt .claude/worktrees/ from protect-files hook Isolated subagents (frontend/backend-implementer) run in a git worktree created under .claude/worktrees/. The protect-files PreToolUse hook blocked all edits to any .claude/ path, making every worktree-isolated agent unable to edit its own checkout. Exempt .claude/worktrees/ (ephemeral agent scratch space) while still protecting the real tooling config under .claude/. Co-Authored-By: Claude Opus 4.8 --- .claude/hooks/protect-files.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.claude/hooks/protect-files.sh b/.claude/hooks/protect-files.sh index 662bf266..48c55579 100755 --- a/.claude/hooks/protect-files.sh +++ b/.claude/hooks/protect-files.sh @@ -36,8 +36,8 @@ if echo "$path" | grep -Eq '(^|/)apps/admin/'; then block "apps/admin/ was deleted in WS-3 and must not return" "Use apps/app/ (Organizer SPA, includes Platform Admin under /platform/*)" fi -# .claude/ tooling self-modification -if echo "$path" | grep -Eq '(^|/)\.claude/'; then +# .claude/ tooling self-modification (allow ephemeral agent worktrees under .claude/worktrees/) +if echo "$path" | grep -Eq '(^|/)\.claude/' && ! echo "$path" | grep -Eq '(^|/)\.claude/worktrees/'; then block "tooling self-modification — Bert reviews .claude/ changes by hand" "Open the file in an editor outside Claude Code, or ask Bert to authorize the change explicitly" fi -- 2.39.5 From b16387b2fbf0719afc5932615361bf7bd7c775fe Mon Sep 17 00:00:00 2001 From: "bert.hausmans" Date: Wed, 3 Jun 2026 03:35:25 +0200 Subject: [PATCH 2/9] fix: explicit non-overlapping mobile drawer close control MOBILE-SHELL-PARITY defect 2. PrimeVue's default drawer header close-X was leaking through 'header: hidden' (non-important 'hidden' lost to PrimeVue's base .p-drawer-header display in stylesheet order) and overlapping the brand row. Force-hide it with the important variant '!hidden' (matching the file's existing !w-64), and provide the mobile close affordance in SidebarHeader's brand row: on mobile the top-right control renders an X ('Sluit menu') and closes the drawer (handleCollapseClick already calls setMobileOpen(false) on mobile), mirroring the slot the desktop sidebar uses for its collapse chevron. Single, non-overlapping close control; showCloseIcon is left at its default. Co-Authored-By: Claude Opus 4.8 --- apps/app/src/components-v2/layout/AppSidebar.vue | 12 +++++++++++- .../src/components-v2/layout/SidebarHeader.vue | 15 +++++++++++---- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/apps/app/src/components-v2/layout/AppSidebar.vue b/apps/app/src/components-v2/layout/AppSidebar.vue index 03a7d061..f7680f35 100644 --- a/apps/app/src/components-v2/layout/AppSidebar.vue +++ b/apps/app/src/components-v2/layout/AppSidebar.vue @@ -114,6 +114,16 @@ const mobileVisible = computed({ The children are intentionally repeated (not factored into a slot or render-fn) — the 3-component block is short and the duplication is preferable to the indirection of a dynamic component or slot wiring. + + Close control (MOBILE-SHELL-PARITY defect 2): PrimeVue's default header + close-X is force-hidden via `header: '!hidden'`. Plain `hidden` lost to + PrimeVue's base `.p-drawer-header` display in stylesheet order, so the + default X leaked through and overlapped the brand row (the reported + defect). The important variant (`!hidden`, matching this file's existing + `!w-64`) wins. The mobile close affordance instead lives in + SidebarHeader's brand row, which renders an X ("Sluit menu") on mobile — + a single, non-overlapping control in the same top-right slot the desktop + sidebar uses for its collapse chevron. No duplicate, no overlap. --> ({ class="!w-64" :pt="{ content: { class: 'flex flex-col p-0 overflow-hidden h-full' }, - header: { class: 'hidden' }, + header: { class: '!hidden' }, }" > diff --git a/apps/app/src/components-v2/layout/SidebarHeader.vue b/apps/app/src/components-v2/layout/SidebarHeader.vue index 571b1418..a1bd544e 100644 --- a/apps/app/src/components-v2/layout/SidebarHeader.vue +++ b/apps/app/src/components-v2/layout/SidebarHeader.vue @@ -109,19 +109,26 @@ function handleCollapseClick(): void { -- 2.39.5 From ba3a25364028f36850e43b511ded6279c7975199 Mon Sep 17 00:00:00 2001 From: "bert.hausmans" Date: Wed, 3 Jun 2026 03:43:21 +0200 Subject: [PATCH 3/9] fix: guard mobile drawer full-height column for WorkspaceSwitcher anchor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit MOBILE-SHELL-PARITY defect 3. Static audit (code + @primeuix base CSS) shows the mobile drawer content is ALREADY a correct full-height flex column: .p-drawer-left .p-drawer-content gets height:100% + flex-grow:1 from base styles, our pt makes it flex flex-col, SidebarNav (flex-1 min-h-0) claims the slack and WorkspaceSwitcher (flex-shrink-0) anchors at the bottom — matching the desktop aside. Add min-h-0 as flex hygiene (children shrink, nav scrolls internally) and document the chain in-code, citing the @primeuix rules. The 'broken height chain' premise did not match the code, so no redundant height fix was fabricated. If WorkspaceSwitcher is still clipped on a real mobile device, the remaining suspect is dynamic-viewport-height (a shrinking address bar making 100% exceed the visual viewport) — flagged for a real-device visual check at the merge gate. Co-Authored-By: Claude Opus 4.8 --- .../src/components-v2/layout/AppSidebar.vue | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/apps/app/src/components-v2/layout/AppSidebar.vue b/apps/app/src/components-v2/layout/AppSidebar.vue index f7680f35..70e328d6 100644 --- a/apps/app/src/components-v2/layout/AppSidebar.vue +++ b/apps/app/src/components-v2/layout/AppSidebar.vue @@ -124,6 +124,23 @@ const mobileVisible = computed({ SidebarHeader's brand row, which renders an X ("Sluit menu") on mobile — a single, non-overlapping control in the same top-right slot the desktop sidebar uses for its collapse chevron. No duplicate, no overlap. + + Bottom anchoring (MOBILE-SHELL-PARITY defect 3 — WorkspaceSwitcher): + the content pt is a full-height flex COLUMN (`flex flex-col h-full + min-h-0`). PrimeVue's @primeuix base styles already give + `.p-drawer-left .p-drawer-content { height: 100% }` + `flex-grow: 1`, + and `.p-drawer-left .p-drawer { height: 100% }` inside the `height:100%` + mask — so the content fills the panel's full viewport height. With the + flex column, SidebarNav (`flex-1 min-h-0 overflow-y-auto`) claims the + slack and WorkspaceSwitcher (`flex-shrink-0`) anchors to the true bottom, + exactly as the desktop