preen-window-consistency
Preen Window Consistency
Proactively search for opportunities to normalize window components, standardize refresh patterns, and consolidate shared logic into packages/window-manager.
When to Run
Run this skill when maintaining window components or during slack time. It searches for:
- Duplicated patterns across windowed applications that should be centralized
- Legacy implementations that should adopt existing window-manager hooks/components
- Components in individual windows that could be promoted to window-manager
- Inconsistent refresh/refetch patterns that should use standardized hooks
- Cross-window navigation that bypasses the
WindowOpenRequestPayloadspattern
Discovery Phase
Search for opportunities to normalize and standardize:
# Find window components across packages
find packages -name "*Window*.tsx" -not -path "*/node_modules/*" -not -path "*/dist/*" | head -30
# Find sidebar components that might have refresh patterns
find packages -name "*Sidebar*.tsx" -not -path "*/node_modules/*" -not -path "*/dist/*" | head -30
# Find manual refreshToken patterns not using useSidebarRefetch
rg -n --glob '*.tsx' 'lastRefreshTokenRef|lastRefreshToken' packages | head -20
# Find manual refreshToken state not using useWindowRefresh
rg -n --glob '*.tsx' 'setRefreshToken.*prev.*\+.*1|refreshToken.*useState.*0' packages | head -20
# Find combined refresh token patterns not using useCombinedRefresh
rg -n --glob '*.tsx' 'combinedRefreshToken|internalRefreshToken.*external' packages | head -20
# Find potential WindowSidebarItem candidates (custom sidebar items not using the standard component)
rg -n --glob '*.tsx' 'className=.*sidebar.*item|flex.*items-center.*gap.*rounded.*text-sm' packages | rg -v 'WindowSidebarItem|node_modules' | head -20
# Find potential WindowSidebarHeader candidates
rg -n --glob '*.tsx' 'className=.*border-b.*px.*py|sidebar.*header' packages | rg -v 'WindowSidebarHeader|node_modules' | head -20
# Find drag-over patterns not using useSidebarDragOver
rg -n --glob '*.tsx' 'dragOverId|dragCounter|setDragOver' packages | rg -v 'useSidebarDragOver|window-manager' | head -20
# Find resize handle patterns not using useResizableSidebar
rg -n --glob '*.tsx' 'cursor-col-resize|onWidthChange.*width|resizeHandle' packages | rg -v 'useResizableSidebar|window-manager' | head -20
# Find cross-window navigation patterns using navigate() instead of openWindow/requestWindowOpen
# These are windows that should open in floating mode but currently route-navigate
rg -n --glob '*.tsx' 'navigate\(.*/(help|notes|contacts|photos|audio|videos|documents|files|email|chat|ai)\b' packages | rg -v 'isMobile|test\.tsx' | head -20
# Check WindowOpenRequestPayloads vs actual window types that need open requests
echo "=== Window types supporting open requests ==="
rg -A5 'interface WindowOpenRequestPayloads' packages/client/src/contexts/WindowManagerContext.tsx | head -20
# Check window-manager exports vs actual usage
echo "=== Window Manager Exports ==="
rg '^export' packages/window-manager/src/index.ts | head -30
echo "=== Unused Window Manager Components ==="
for comp in WindowSidebarItem WindowSidebarHeader WindowSidebarLoading WindowSidebarError WindowStatusBar WindowControlBar; do
count=$(rg -l "$comp" packages --glob '*.tsx' | rg -v 'window-manager' | wc -l | tr -d ' ')
echo "$comp: $count usages"
done
# Find windows missing File menu
echo "=== Windows Without File Menu ==="
rg -l 'FloatingWindow|DesktopFloatingWindow' packages --glob '*Window.tsx' | xargs -I {} sh -c 'rg -q "DropdownMenu trigger=\"File\"" {} || echo {}'
# Find potential duplicate back buttons or misplaced actions in content area
echo "=== Potential Misplaced Actions ==="
rg -n --glob '*Window*.tsx' '<Button.*onClick.*(ArrowLeft|Plus|RefreshCw|Trash2)' packages | rg -v 'WindowControl|test\.tsx' | head -20
Dependency and Export Wiring Checks
When adopting @tearleads/window-manager abstractions in a package, verify package metadata and exports are aligned:
# Find packages importing window-manager in source
echo "=== Packages importing @tearleads/window-manager ==="
rg -l "from '@tearleads/window-manager'" packages/*/src --glob '*.{ts,tsx}' \
| awk -F/ '{print $2}' | sort -u
# Find package.json files that already declare window-manager as a peer dependency
echo "=== Packages declaring window-manager peerDependency ==="
rg -l '"@tearleads/window-manager"' packages/*/package.json | awk -F/ '{print $2}' | sort -u
# Manual diff target: importers should generally also declare peerDependency
Candidate Signals
Prioritize opportunities that meet at least two signals:
Promote to window-manager
- Component is used in 2+ different window packages
- Component follows a consistent pattern across windows
- Component has no window-specific business logic
- Component is a generic UI primitive (sidebar item, header, loading state)
Adopt window-manager patterns
- Sidebar uses manual refreshToken useEffect instead of
useSidebarRefetch - Window uses manual refreshToken state instead of
useWindowRefresh- Migration recipe: replace
const [refreshToken, setRefreshToken] = useState(0)withconst { refreshToken, triggerRefresh } = useWindowRefresh()and replace every token increment withtriggerRefresh(). - Keep passing
refreshTokenthrough existing props to data/list components; do not switch to remount-by-key unless already required. - Add
triggerRefreshto callback dependency arrays where it's used; this replaces any dependency on the oldsetRefreshTokensetter. - If tests mock
@tearleads/window-manager, ensure they spread the real module exports souseWindowRefreshremains available.
- Migration recipe: replace
- Component uses combined refresh tokens instead of
useCombinedRefresh - Component has custom drag-over tracking instead of
useSidebarDragOver - Component has custom resize handling instead of
useResizableSidebar - Cross-window navigation uses
navigate()instead ofopenWindow()/requestWindowOpen() - Package imports window-manager abstractions but does not expose dependency wiring in
peerDependencies
Consolidate duplicated code
- Same hook logic appears in multiple sidebars
- Same UI pattern appears in multiple windows
- Same context menu structure appears in multiple places
Do NOT refactor:
- Components with significant business logic that shouldn't be in window-manager
- Patterns that are intentionally different for good reasons
- Code that would require breaking API changes to standardize
- Test files or storybook files
Window Structure Patterns
Every window should follow a consistent structure with these required elements:
Menu Bar Pattern
All windows must have a menu bar with at minimum a File menu containing Close:
<FloatingWindow ...>
<div className="flex h-full flex-col">
<WindowMenuBar onClose={onClose} />
<WindowControlBar>...</WindowControlBar>
{/* Content */}
</div>
</FloatingWindow>
Standard menu bar structure:
<div className="flex shrink-0 border-b bg-muted/30 px-1">
<DropdownMenu trigger="File">
{/* Optional: New, Open, Save actions */}
<DropdownMenuItem onClick={onClose}>Close</DropdownMenuItem>
</DropdownMenu>
<DropdownMenu trigger="View">
{/* Optional: View mode toggles, show/hide options */}
<WindowOptionsMenuItem />
</DropdownMenu>
<DropdownMenu trigger="Help">
<AboutMenuItem appName="AppName" version={packageJson.version} />
</DropdownMenu>
</div>
Discovery command for missing menu bars:
# Find windows without menu bars
rg -l 'FloatingWindow|DesktopFloatingWindow' packages --glob '*Window.tsx' | xargs -I {} sh -c 'rg -q "DropdownMenu trigger=\"File\"" {} || echo "NO MENU: {}"'
Control Bar Pattern
All window actions belong in the WindowControlBar, not in the content area.
Good pattern:
<WindowControlBar>
<WindowControlGroup>
{showBackButton && (
<WindowControlButton icon={<ArrowLeft />} onClick={onBack}>
Back
</WindowControlButton>
)}
</WindowControlGroup>
<WindowControlGroup align="right">
<WindowControlButton icon={<Plus />} onClick={onCreate}>
New
</WindowControlButton>
<WindowControlButton icon={<RefreshCw />} onClick={onRefresh}>
Refresh
</WindowControlButton>
</WindowControlGroup>
</WindowControlBar>
Bad patterns to fix:
- Duplicate back buttons (one in control bar, one in content)
- Action buttons (new, refresh, delete) inside content area
- Navigation controls scattered throughout the component
Discovery command for misplaced actions:
# Find potential misplaced actions in content (buttons with action icons not in control bar)
rg -n --glob '*Window*.tsx' '<Button.*onClick.*(ArrowLeft|Plus|RefreshCw|Trash2)' packages | rg -v 'WindowControl|test\.tsx' | head -20
Detail View Pattern
When a window has list/detail views, the control bar should change based on the selected state:
<WindowControlBar>
<WindowControlGroup>
{selectedItemId && (
<WindowControlButton icon={<ArrowLeft />} onClick={handleBack}>
Back
</WindowControlButton>
)}
</WindowControlGroup>
<WindowControlGroup align="right">
{selectedItemId ? (
// Detail view actions (right-aligned)
<WindowControlButton icon={<Trash2 />} onClick={handleDelete}>
Delete
</WindowControlButton>
) : (
// List view actions (right-aligned)
<>
<WindowControlButton icon={<Plus />} onClick={handleCreate}>
New
</WindowControlButton>
<WindowControlButton icon={<RefreshCw />} onClick={handleRefresh}>
Refresh
</WindowControlButton>
</>
)}
</WindowControlGroup>
</WindowControlBar>
Key principles:
- Single back button - Only in control bar, never duplicated in content
- Actions right-aligned - New, Refresh, Delete go in
WindowControlGroup align="right" - Context-aware actions - Control bar shows relevant actions for current view state
- Content area is for content - Headers in content area show only title/icon, not action buttons
Workflow
- Discovery: Run discovery commands to identify candidates across all packages.
- Selection: Choose one high-value candidate meeting at least two signals.
- Analysis: Understand the existing pattern and the target window-manager abstraction.
- Create branch:
git checkout -b refactor/window-consistency-<component-or-pattern> - Implement:
- For promotion: Add component/hook to window-manager with tests
- For adoption: Update window to use existing window-manager exports
- For consolidation: Extract shared code into window-manager
- Rebuild: Run
pnpm --filter window-manager buildto ensure exports are available - Update consumers: Update all affected window packages to use the new/existing abstractions
- Tests: Ensure existing tests pass; add tests for new window-manager code
- Validate: Run lint, type-check, and relevant tests
- Commit and merge: Run
/commit-and-push, then/enter-merge-queue
If no high-value candidate is found, report findings and stop.
Available Window Manager Abstractions
Reference these existing exports when looking for adoption opportunities:
Hooks
| Hook | Purpose |
|---|---|
useSidebarRefetch |
Watch refreshToken and trigger refetch on change |
useWindowRefresh |
Manage refreshToken state with triggerRefresh function |
useCombinedRefresh |
Combine external and internal refresh tokens |
useSidebarDragOver |
Track drag-over state for sidebar items |
useResizableSidebar |
Handle sidebar resize with keyboard support |
useFloatingWindow |
Manage floating window position and size |
Components
| Component | Purpose |
|---|---|
WindowSidebarItem |
Standard sidebar list item with icon, label, count |
WindowSidebarHeader |
Standard sidebar header with title and action button |
WindowSidebarLoading |
Loading spinner for sidebar content |
WindowSidebarError |
Error message for sidebar content |
WindowStatusBar |
Status bar for window footer |
WindowControlBar |
Control bar for window actions |
WindowContextMenu |
Context menu container |
WindowContextMenuItem |
Context menu item |
FloatingWindow |
Base floating window component |
Auth Requirement Patterns
Windows may require authentication at different levels. Use consistent patterns:
Auth Levels
| Level | Component | Use Case |
|---|---|---|
| Database unlock only | InlineUnlock |
Local-only features (notes, files, photos) |
| Login only | InlineLogin |
API-only features with no local storage |
| Database + Login | InlineRequiresLoginAndUnlock |
Features needing both local DB and API auth |
Standard Patterns
Database unlock only (most local-data windows):
// Inside window content area
{!isLoading && !isUnlocked && <InlineUnlock description="notes" />}
Database + Login (preferred composite approach):
// Wrap content with composite - handles all states internally
<InlineRequiresLoginAndUnlock
description="MLS Chat"
unlockDescription="MLS chat"
>
{/* Content only rendered when both conditions met */}
</InlineRequiresLoginAndUnlock>
Database + Login (props approach - legacy, for packages without client access):
// In external package (e.g., @tearleads/app-email)
interface WindowProps {
isUnlocked?: boolean;
isDatabaseLoading?: boolean;
lockedFallback?: ReactNode;
}
// In client wrapper
const isFullyUnlocked = isDatabaseUnlocked && isAuthenticated;
const lockedFallback = useMemo(() => {
if (!isDatabaseUnlocked) return <InlineUnlock description="email" />;
if (!isAuthenticated) return <InlineLogin description="email" />;
return null;
}, [isDatabaseUnlocked, isAuthenticated]);
Auth Discovery Commands
# Find windows using InlineUnlock (database unlock only)
rg -n --glob '*Window*.tsx' 'InlineUnlock' packages | rg -v 'InlineRequiresLoginAndUnlock|test|mock' | head -20
# Find windows using InlineRequiresLoginAndUnlock (both)
rg -n --glob '*Window*.tsx' 'InlineRequiresLoginAndUnlock' packages | rg -v 'test|mock' | head -10
# Find windows using props-based auth (email pattern)
rg -n --glob '*Window*.tsx' 'isUnlocked.*isDatabaseLoading.*lockedFallback' packages | head -10
# Find admin windows that may need auth but don't have it
rg -l --glob '*Window*.tsx' 'Admin.*Window' packages | xargs -I {} sh -c 'rg -q "InlineUnlock|InlineLogin|isUnlocked" {} || echo "NO AUTH: {}"'
Admin Window Auth Requirements
Admin windows (admin-*) should use InlineRequiresLoginAndUnlock because:
- They require API authentication to access admin endpoints
- They may cache/display data that needs local database access
- Consistent pattern across all protected features
For admin windows in external packages (e.g., @tearleads/app-admin), create client wrappers:
packages/client/src/components/window-admin-users/
├── index.tsx # Wrapper with InlineRequiresLoginAndUnlock
└── AdminUsersWindow.test.tsx
Cross-Window Opening Pattern
When one window needs to open content in another window (e.g., search opening a help doc), use the WindowOpenRequestPayloads pattern instead of navigate():
-
Add payload type to
WindowOpenRequestPayloadsinWindowManagerContext.tsx:export interface WindowOpenRequestPayloads { // ... existing payloads help: { helpDocId?: HelpDocId }; } -
Consume in target window using
useWindowOpenRequest:const openRequest = useWindowOpenRequest('help'); useEffect(() => { if (!openRequest?.requestId || !openRequest?.helpDocId) return; setView(openRequest.helpDocId); }, [openRequest?.helpDocId, openRequest?.requestId]); -
Open from source window using
openWindow+requestWindowOpen:if (isMobile) { navigate('/help/docs/...'); return; } openWindow('help'); requestWindowOpen('help', { helpDocId });
This ensures that when clicking items in a floating window (e.g., search results), the target content opens in another floating window rather than route-navigating away.
Guardrails
- Do not introduce breaking changes to window-manager public API
- Do not mix UI refactoring with behavior changes
- Do not create overly generic abstractions with limited reuse value
- Keep window-specific business logic out of window-manager
- Ensure all window-manager exports have tests
- Do not introduce
anyor unsafe type assertions - Build window-manager before running consumer tests
PR Strategy
Use focused PRs:
- PR 1: Add new abstraction to window-manager (if needed)
- PR 2+: Update individual windows to adopt the abstraction
In each PR description, include:
- Why this pattern was selected for normalization
- What abstraction was created or adopted
- Which windows were updated
- Confirmation of no behavior change
- Test evidence
Metric
Count of non-standardized patterns:
MANUAL_REFRESH=$(rg -c --glob '*.tsx' 'lastRefreshTokenRef|lastRefreshToken' packages 2>/dev/null | rg -v 'window-manager' | awk -F: '{sum+=$2} END {print sum+0}')
MANUAL_DRAG=$(rg -c --glob '*.tsx' 'dragOverId.*useState|setDragOver.*Id' packages 2>/dev/null | rg -v 'window-manager' | awk -F: '{sum+=$2} END {print sum+0}')
MANUAL_RESIZE=$(rg -c --glob '*.tsx' 'cursor-col-resize.*onMouseDown|handleResize.*MouseEvent' packages 2>/dev/null | rg -v 'window-manager' | awk -F: '{sum+=$2} END {print sum+0}')
CROSS_WINDOW_NAV=$(rg -c --glob '*.tsx' 'navigate\(.*/(help|notes|contacts|email|chat|ai|audio|photos|videos|documents|files).*\)' packages 2>/dev/null | rg -v 'isMobile|test\.tsx' | awk -F: '{sum+=$2} END {print sum+0}')
echo $((MANUAL_REFRESH + MANUAL_DRAG + MANUAL_RESIZE + CROSS_WINDOW_NAV))
Token Efficiency
# Limit discovery output with head commands (already done above)
# Suppress verbose validation output
pnpm --filter window-manager build >/dev/null
pnpm lint >/dev/null
pnpm typecheck >/dev/null
pnpm test >/dev/null
git commit -S -m "message" >/dev/null
git push >/dev/null
On failure, re-run without suppression to see errors.
More from a2f0/tearleads
commit-and-push
Commit staged changes and push to the remote using conventional commits with GPG signing. Use when you need to commit and push work, create a PR if missing, and wait for Gemini review before addressing feedback.
33rebase
Rebase the current branch onto the latest main branch, resolving conflicts by preferring upstream changes.
2preen
Stateful preening across all preen skills. Lands focused improvements, opens a PR, and enters merge queue.
1issue-slice-autopilot
Run a long-lived, multi-PR issue completion loop for complex issues by selecting the largest non-overlapping sane slice, implementing it, and then invoking $commit-and-push followed by $enter-merge-queue for each slice until the issue is complete.
1serena-bootstrap
Serena Bootstrap
1preen-knip
Proactively reduce knip findings by removing unused dependencies, exports, and files in coherent, low-risk slices. Use when maintaining code quality or during slack time.
1