UI 2.0: reskin the production frontend to the prototype design#832
Open
backnotprop wants to merge 60 commits into
Open
UI 2.0: reskin the production frontend to the prototype design#832backnotprop wants to merge 60 commits into
backnotprop wants to merge 60 commits into
Conversation
- legacy-design-state.md: current production UI anatomy - prototype-design-state.md: the DiffKit goal-prototype as authoritative target - transfer-map.md: current→target diff + phased migration plan
Ports the DiffKit goal-prototype's shadcn-neutral palette as a first-class theme. Pins explicit --surface-0/1/2 elevation (stepping up from the card) rather than the global muted-derived surfaces, preserving the prototype's layered look. Maps the prototype's light-default :root → .theme-simple.light and .dark → .theme-simple (dark default) to match Plannotator's polarity.
Stand up the shared primitive layer in packages/ui (the package both the plan and code-review apps consume), mirroring the frontend's shadcn-style conventions (cva + cn + data-slot): - lib/utils.ts: shared cn() = twMerge(clsx) - deps: class-variance-authority, clsx, tailwind-merge, @radix-ui/react-slot - exports: ./components/ui/*, ./lib/* - components/ui/card.tsx: Card + Header/Title/Description/Content/Footer Card ports the prototype's primitive verbatim against shared tokens. Additive — no existing component consumes it yet.
Three leaf primitives ported from the prototype against shared tokens: - badge.tsx: cva variants (default/secondary/destructive/outline), asChild - state-pill.tsx: tone-based status pill (open/closed/merged/muted/secondary) - textarea.tsx: field-sizing-content auto-grow input Additive; no consumers yet.
…ants Move the Button primitive to packages/ui (shared by the shell and the embedded plan/review apps) and add two token-driven variants for the plan app's actions: - success: solid green (Approve), via --success - accent: soft accent tint (Feedback) The frontend's components/ui/button.tsx becomes a thin re-export, so its "@/components/ui/button" importers are unchanged and there is a single Button implementation. Verified: ui + frontend typecheck, frontend single-file build.
Radix-backed dropdown menu (shadcn-style) to replace the plan app's hand-rolled ApproveDropdown / QuickLabelDropdown / header menus. Ported from the prototype with lucide-react icons; adds @radix-ui/react-dropdown-menu to packages/ui.
Resolve the transfer-map §8 forks: keep dark-first polarity, keep all ~50 themes, keep the production project→worktree sidebar, no Cmd+K command palette, keep highlight.js, keep production-grade markdown rendering, rebuild primitives inside packages/ui (not vendored). Code-review layout engine deferred (out of plan-app scope).
Full catalog of the header surface before any styling change: the shell, the per-mode button sets (callback/goal-setup/annotate/normal), action buttons + Approve hover-warning, the OpenCode Approve split-dropdown + agent-switch persistence, panel/AI toggles, the dense Options menu (theme switcher, Settings, Export, Agent Instructions, Download, Print, Share, Import, version section), and the 11-tab Settings modal. Decision recorded: keep the Options dropdown, do not add the prototype grid button. Everything listed must survive the reskin.
Action buttons (Feedback/Approve/Exit) -> Button primitive (accent/success/secondary variants); ApproveDropdown split button -> Button while preserving agent-switch persistence + dropdown; PlanHeaderMenu trigger -> ghost Button and all item icons -> lucide (every menu item, gating, theme switcher, version section, update dot intact); AppHeader panel/AI toggles -> ghost Button + lucide (SparklesIcon + unread dot kept; orchestration + Approve hover-warning untouched). Integration fixes: restore exact gray-on-disabled for the action buttons. Adds lucide-react dep to plan-review.
Swap the 6 hand-rolled tool SVGs to lucide icons and align the warning hover token (amber -> --warning). The expand-on-hover mechanics are byte-for-byte intact (ICON_SIZE/H_PAD/GAP/DURATION, width measurement, compact/iconOnly/default modes). Integration fix: keep group/help tracks on bg-muted/50 (not bg-surface-1, which is not bridged in the portal build).
Route PlanDiffBadge classes through cn(); keep the active tint on bg-primary/15 to match the app-bar toggle active-states. Toggle behavior + counts unchanged. (DocBadges + PlanDiffViewer chip/icon cleanup deferred to a follow-up — out of this band's scope.)
Flexible dev launcher for manual/visual UX testing against the running daemon, using the tests/test-fixtures/ markdown fixtures. Supports plan, annotate, and review modes; resolves a fixture by path, number, or name fragment; prints an auth-included openable URL. Supersedes the hardcoded scripts/test-plan-session.sh for everyday testing.
- simple.css: --success-foreground was near-black in LIGHT mode → Approve rendered black text on green. Set to white (matches dark mode; white-on-green like prototype). - Remove the broken 'accent' Button variant (text-accent on bg-accent = zero contrast in neutral-accent themes like Simple — the cause of the grey/invisible Feedback text). - Feedback button → outline variant + Send icon (the prototype's design: neutral outline, foreground text, paper-plane icon — readable in every theme/mode). - Approve button → add the Check icon (prototype: green + white + check). - AppHeader panel toggle → stateful PanelRightClose/PanelRightOpen (matches prototype, more elegant than the static panel glyph).
…ons) The prototype's left sidebar icon is a hugeicons SidebarLeft (softer rounded panel + divider + content ticks, stroke 1.5), not lucide's plainer PanelLeft. Replicate just that one glyph as a custom SVG in packages/ui/components/icons/PanelLeftIcon.tsx and use it in the shell SidebarTrigger. Avoids adding the hugeicons dependency; everything else stays on lucide-react.
Cited anatomy of both the production plan-document area and the prototype PlanEditor, with a transfer matrix. Key divergences: grid is always-on in production vs optional/ default-off in the prototype; production uses custom overlayscrollbars vs the prototype's native OS scrollbars; the prototype moves metadata + toolstrip INSIDE the article and keeps a minimal top bar; view modes differ (production reshapes layout, prototype is width-only). Lists transfer decisions + production-wins kept out of scope.
Make the plan-document grid pattern an opt-in preference (default off) instead of
always-on. Wired through the Zustand config store (a 'gridEnabled' SettingDef, like
taterMode) — App reads it reactively via useConfigValue('gridEnabled'), the toggle in
Settings -> Plan Display sets it via configStore. No uiPreferences prop-drilling.
Match the prototype: grid OFF (default) drops the heavy shadow-xl + border for a subtle --card-shadow (clean, flat-feeling document); grid ON keeps the floating shadow-xl+border card on the grid pattern. Viewer takes a gridEnabled prop (default false = flat), passed from the plan App's config-store value.
The --card-shadow I'd just added includes a 1px ring that reads as a border. Grid-off now has no shadow, no border, no ring — just bg-card + rounded corners, so the plan feels embedded like the prototype. Grid-on still floats (shadow-xl + border).
The plan app root is bg-background but the article was bg-card; in most themes --card != --background, so the plan read as a distinct panel (only blended in Simple). Grid-off now uses bg-background (matches the page) -> embedded in all ~50 themes. Grid-on keeps bg-card + shadow-xl + border (floating card on the grid).
…olor) Revert the bg-background experiment. Keep the plan as bg-card, and make the document scroll area (<main>) bg-card too when grid is off, so they match -> the plan embeds seamlessly at the card color in every theme. Grid-on: main shows the grid pattern and the plan floats as a bg-card card (shadow-xl + border).
Left content sidebar (bg-card/50), annotations panel + AI panel (bg-card/30) -> solid bg-card (drop the translucency + backdrop-blur). The whole plan app now reads as one continuous card surface in every theme, separated only by thin borders.
HTML content (HtmlViewer / --render-html) is always full view — edge-to-edge, no card, no grid, ever. Does NOT get the plan document's grid/embed treatment. Records the reference fullViewport implementation (built in feat/collab, tied to rooms) and that it arrives via that merge — deferred here, not re-implemented.
…px rail Replace the overlayscrollbars-react wrapper (#509) with native OS scrollbars. The element rendered IS the scroll node now, so OverlayScrollArea collapses 217 -> ~80 lines while preserving the exact API (onViewportReady + handle) — the ~20 consumers are untouched. Removes the deferred-init event dance, the force-recompute ResizeObserver (the perf cost), the ClickScrollPlugin, and the os-theme CSS. Critically: delete the ::-webkit-scrollbar { width: 6px } rail in theme.css AND styles.css — that thin rail was the original 'can't grab the scrollbar' bug (#354). Native scrollbars are styled via the standard scrollbar-width: thin + scrollbar-color (cross-browser, grabbable). Lib is now unused/tree-shaken (~48KB smaller); dep removal + print.css/globals.d.ts cleanup to follow.
Self-review sweep — nothing left hanging: - Remove overlayscrollbars + overlayscrollbars-react deps from packages/ui (unused) - Drop dead print.css rules (.os-scrollbar + [data-overlayscrollbars-*]) — the native <main>/[data-print-region] print rule already un-clips - Remove .os-scrollbar from the popout z-index rule in theme.css - Dedup: drop the frontend styles.css scrollbar block (theme.css already defines it) - Refresh stale comments (theme.css scrollbar header, useOverlayViewport jsdoc) Verified: ui + frontend typecheck, frontend single-file build.
Extracts the PLAN_MD template literal from the DiffKit goal-prototype's PlanEditor.tsx (Real-time Collaboration plan) into a reusable markdown fixture for visual/reskin testing — rich content: multi-language code fences, tables, callouts, headings. Launch with: ./scripts/launch-session.sh plan 16
The Plan Width setting didn't apply because planWidth lived in uiPreferences (local useState) — which doesn't cross the settings<->embedded-plan-app React tree boundary. Moved it to the Zustand config store (like grid/taterMode): reactive across trees, so changing it now updates the plan live. Add 'ultrawide' (px: null = no max-width cap, full width). planMaxWidth now derives from PLAN_WIDTH_OPTIONS so ultrawide -> null -> full width. Touches both width controls (Settings.tsx monolith + PlanDisplayTab) because they duplicate the picker — see note in reply about that debt.
…ig-store dialog Workflow-produced + adversarially-reviewed plan (13 units). Key findings: most migration already done (settings on config store, embedded apps already route to global dialog); monolith kept alive by only 4 import sites + the portal (the blocker). Adversarial pass caught a real regression (identity re-tag is wired only through the monolith) + that code-review's aiProviders is not settings-only. Records units, critical path, fixes, and the open product decisions (portal settings, scope, section-visibility UX).
…diffOptions.ts First cut severing the monolith: move the 7 diff-option constant arrays out of Settings.tsx into a neutral settings/diffOptions.ts; repoint DiffOptionsPopover off the monolith. Also record the LOCKED decisions (one universal dialog, daemon-aware config store, full migration).
…onolith-free Sequential extraction (workflow waremxcbr, per-unit adversarial verify): - U2 GitTab -> settings/ReviewGitTab.tsx - U3 ReviewDisplayTab -> settings/ReviewDisplayTab.tsx (co-located SegmentedControl/ToggleSwitch for visual parity) - U4 CommentsTab (+ CCLabel helpers) -> settings/CommentsTab.tsx - U5 AppSettingsDialog repointed to the new files -> imports NOTHING from the monolith All config-store-only, byte-for-byte parity verified. Monolith still compiles (its own JSX + the portal/standalone path) until later units. Verified: frontend typecheck + build, AND build:portal green.
…tag, code-review rewired
- U6: global dialog defaults to the active session's section (plan->plan-general,
review->review-display, else general); all sections stay reachable; aiProviders type
carries models. (Fixed the plan-tab default the verifier caught.)
- Identity re-tag preserved via a decoupled window event ('plannotator:identity-change'):
identity util fires old->new; both apps subscribe + re-author annotations. Works from
the global dialog with no prop threading; idempotent on the monolith double-fire.
- U7: code-review deletes its dead <Settings> mount + monolith import + openSettingsMenu;
opens only the global dialog. KEEPS the aiProviders fetch (drives the live AI chat).
Verified: ui+frontend typecheck, frontend build, build:portal.
One SettingsDialog (packages/ui/components/settings/SettingsDialog.tsx) now serves every surface, adapting via a `daemonAvailable` flag instead of being wired to the frontend app-store: - Daemon/session present (frontend): full dialog, server-synced, all tabs. - No daemon (standalone plan editor / portal): same dialog, cookie-only, daemon-only tabs hidden (AI, Hooks, git-name, legacyTabMode). - New shared dialog + Dialog/Tabs primitives in packages/ui (radix-tabs dep). - AppSettingsDialog is now a thin frontend adapter feeding the shared dialog its session context (mode/origin/apiBase) from the app-store. - Plan editor's standalone built-in (AppHeader) renders the shared dialog (sessionContext=null, daemonAvailable=false); embedded path unchanged. - configStore skips the server POST when no daemon/session base resolves (no doomed request in the portal); cookie writes unchanged. - Deleted packages/ui/components/Settings.tsx (the last monolith). Verified: packages/ui + apps/frontend typecheck clean; build:hook (verified single-file) and build:portal both green; two adversarial reviews found nothing.
The portal (share.plannotator.ai) was shipping unstyled on this branch: the UI2.0 redesign wired the frontend's Tailwind entry but never the portal's, so the portal built a ~4KB stylesheet with zero utilities. Both apps render the same plan editor, so the design system now lives in ONE shared file imported by both — they look identical, one source underneath. - New packages/ui/design-system.css: fonts + theme tokens + tailwindcss + animate plugin + the @theme bridge extras (sidebar/surface) + @layer base surfaces + editor animations + plan-review rules. @source globs are anchored to this file so they resolve for both consumers. - Frontend styles.css imports the shared file and keeps only shell-only bits (its own @source scans, sidebar transitions, grid, print, scroll-shadow). - Portal imports the shared file (replacing the styles-only import); CDN font and hljs <link>s dropped (now bundled). - packages/ui gains tailwindcss + tailwindcss-animate + shared fonts as deps so the shared file resolves them deterministically. - Elegance: the base color/radius/font bridge stays solely in theme.css (also used standalone by the marketing site); the shared file only adds the sidebar + surface extras, not a duplicate base bridge. Instrument Sans is frontend-shell-only, imported from the frontend entry so the portal does not bundle an unused font. Verified by rebuilding both: portal CSS ~4KB -> 186KB with real utilities, all theme tokens (--primary x235), surfaces, animate classes, and plan-review rules; frontend unregressed (identical atomic class set). Two adversarial reviewers independently rebuilt and confirmed parity; 0 critical/major.
Addresses the three Act-On findings from the interrogate review. - toc/sticky -> config store: migrate tocEnabled + stickyActionsEnabled from the non-reactive uiPreferences module to the reactive config store (same cookie keys, default true), so toggling Auto-open Sidebar / Sticky Actions takes effect live everywhere, including the standalone/portal plan editor. Delete UIPreferences/getUIPreferences/saveUIPreferences (keep PlanWidth + PLAN_WIDTH_OPTIONS). Drop the uiPrefs state in plan App.tsx. - Dead code: remove the 5 vestigial settings-feed props (taterMode, gitUser, onTaterModeChange, onIdentityChange, onUIPreferencesChange) from AppHeader + the App.tsx call site, plus the orphaned handleTaterModeChange + gitUser state, and GeneralTab's dead onIdentityChange prop. Re-tag flows through the window event; taterMode toggles via the config store. - AI provider: pass origin to AISettingsTab in SettingsDialog so per-origin provider overrides actually persist (was silently dropped). - Extras: guard SettingsDialog's daemon fetches against post-close state writes; drop the stale Instrument Sans mention in the portal fonts comment. Verified: packages/ui + apps/frontend typecheck clean; build:hook + build:portal green; two adversarial reviewers found 0 actionable issues.
Match the DiffKit prototype's annotation UI while retaining all behavior.
- AnnotationPanel cards: flatten from bordered badge-pill cards to borderless
hover:bg-surface-1/50 (selected: bg-surface-1 ring-1 ring-border/50) cards
with a single header row (type word + author·time + hover-revealed
pencil/trash), a line-clamped mono quote, a text-[13px] body, and an inline
edit textarea with Button xxs Cancel/Save. Panel header flattened to h-10,
count pill bg-primary/10, two-line empty state.
- Toolstrip active-tool indicators use the prototype's blue/red/yellow; the
toolbar + card type-word keep the theme's accent/destructive so the card
color stays consistent with the in-document highlight CSS (.comment amber,
.deletion red). Global label uses purple (legible on light + dark cards).
- EditorAnnotationCard is shared with the code-review sidebar: added a
variant ('plan' | 'code-review') prop so code-review keeps its bordered
look and only the plan editor gets the flat restyle.
Retained + verified: click annotation -> scroll-to-doc (data-annotation-id +
listRef effect), edit-in-place (Cmd+Enter/Esc), delete/redline, image
attachments, global comments, diff-view annotations, copy/share footer. The
in-doc highlight CSS + useAnnotationHighlighter were not touched.
Verified: packages/ui + apps/frontend typecheck clean; build:hook verified;
two adversarial reviewers (behavior-retention + visual fidelity) — the one
real regression they found (EditorAnnotationCard bleeding into code-review)
was fixed via the variant prop.
Replace the mouse/touch + setState-per-move handlers with Pointer Events on window (fire reliably for every move, even past the window edge), rAF-coalesced to one write per frame, and an optional imperative `apply` that drives width through a :root CSS var so heavy hosts never re-render mid-drag. The handle bar is hidden while dragging. Also scope the width-animation transition to the global sidebar only. It was applied to every element under [data-slot="sidebar-wrapper"] (the whole app), so every panel animated its width over 150ms and trailed the cursor when dragged. Now in-plan panels snap 1:1.
Restore the redline backspace glyph as a RedlineIcon component (from the icons package, not inlined). Drive the comment accent through a new --annotation-comment token that defaults to the theme accent and only overrides to blue in the simple theme, so fixing simple-theme contrast no longer regresses every other theme. Flat toolstrip/toolbar styling to match the prototype.
Flatten the nested TocItemComponent / CountBadge layer into the main component.
Consolidate the scattered Tater sprites into one packages/ui/components/sprites/ module (SpriteSheet primitive + per-pose components, exported from the package); drop the old top-level sprite_package_* dirs and stray TaterSprite files; swap in the new sidebar sprite. Sidebar: add a 'New project' button + 'Projects' label above the tree, drop the project tree down a touch (logo stays pinned), replace the worktree git-branch icon with a 'W' glyph, and bump row sizing. AddProjectDialog now filters recent projects as you type instead of showing the full list. Plan App: drive the TOC and annotation panel widths through :root CSS vars so the new render-free resize applies to them too.
Remove the disclosure chevron from project and worktree rows (it ate a column of space). The project's folder icon now doubles as the open/closed indicator (Folder vs FolderOpen). Drop the chevron-width spacer on session rows so the tree nests by indent alone, and delete the now-dead CHEVRON constant + group/disc markers.
Both in-plan sidebar headers now share one spec: h-10 band, text-xs font-medium labels (the left tab bar was shorter with text-[10px]; the right title was font-semibold). Add a collapse button to the shared ResizeHandle (onCollapse), centered on the handle, that reveals on hover of the *whole* adjacent sidebar — pure CSS via :has() on the panes container + data-plan-sidebar markers, no JS state or layout wrappers (which would risk the sidebar's sticky positioning). Drop the redundant left-header close X now that both sides collapse via the handle.
Extract the chat-bubble comment glyph to CommentIcon in the icons package (it was inlined in AnnotationToolbar) and use it for the header annotations toggle, which the reskin had swapped to lucide's PanelRight* (a formal sidebar panel). De-dupe the toolbar to the packaged icon. Fade the app-shell sidebar trigger to text-muted-foreground/60 (brightens on hover), matching the prototype.
The article card carried full padding (p-5..xl:p-12) in every mode, so the plan text was inset while the badges and action buttons sat at the card's outer edge. With a visible card (grid on) that reads as a padded card with a header bar at its edges. With grid off there's no visible card, so the chrome looked ~80px wider than the text. Match the prototype: horizontal card padding only exists in grid mode. - Article: split p-* into py-* (always) + px-* (grid only). - Badges: flush to left-0 when grid off (was left-3), card-corner inset when on. - Action buttons: cancel the panel's own p-1/md:p-2 with -mr-1/md:-mr-2 when grid off so they sit flush to the right text edge; keep the larger -mr pull for grid mode. Grid-on layout is unchanged.
Only the in-plan Contents sidebar had snap-to-close. Wire onSnapClose into the other resizable panels so all of them close the same way: - Right panel (annotations + Ask AI) snaps shut via setIsPanelOpen(false). - Global app sidebar snaps shut via setOpen(false). Its close fn lives inside SidebarProvider (useSidebar), so Layout bridges it through a ref that LayoutContent fills.
Theme switching stays in Settings. Drops the toggle button plus its now-dead useTheme hook, toggleTheme callback, and Moon/Sun/useCallback imports.
Mirrors apps/portal for the plan editor: a tiny Vite app that mounts the code-review App and renders its built-in DEMO_DIFF, so the code-review screen can be developed daemon-free with hot reload. New command: bun run dev:review. Zero changes to the code-review app itself.
Every project and worktree row gets an 'Annotate' row that opens (or reuses) a folder-annotate session and navigates to it. When the session is live the row IS that session: it highlights when active and isn't duplicated as a separate row. - client: createAnnotateFolderSession(cwd) (action annotate + mode annotate-folder). - sidebar: FolderAnnotateRow under projects + worktrees; empty worktrees now render. - server: folder matches reuse any LIVE session (not just awaiting-resubmission), so repeat opens land in the same session; single-file/last annotate unchanged. - expose matchKey on the session summary; sidebar folds the folder session into the Annotate row (excluded from session rows + count). - replace the overloaded collapsedWorktrees set with worktreeOpen overrides + computed default (open when real session or contains the active session). - hide the linked-doc breadcrumb in folder mode (sidebar browser is the way back); kept in plan/single-file/HTML where it's the only way back. Docs in goals/folder-annotate/.
…-picker add dialog Landing page reorganization (the C1 direction): - Project rows are now act-on-the-row: hover Review/Annotate launch directly on the project (or worktree/PR via a right-chevron drill-down). Removed the multi-select + batch 'Launch' bar; one launch() helper creates-or-reuses and navigates. (A proper 'select multiple' UX is a planned follow-up.) - Two-line project rows: name + branch on top, ~-prettified mono path below, aligned. - Active sessions: sorted (live first, then most-recent) via shared session-sort.ts; the box is just the list, with 'History →' on the section heading. ConjoinedSessions History replaced by a focused ActiveSessionsList. - History page (FullSessionsHistoryView) defaults to the history tab and sorts by date; groups inherit recency order. - Add Project dialog: removed 'Recent' (it only re-added existing projects) — now a clean directory picker. - prettyPath() added to packages/shared/project.ts (home → ~, browser-safe). - goals/landing-redesign/ design mocks (current + C1..C5 explorations).
Interactive CLI commands (review/annotate/annotate-last/setup-goal/copilot-*) now print the session URL to stderr so a launched session is never a silent black box. Adds browserAction to the create-session response for the message. presentSession now always opens the session URL in a focused tab for local sessions instead of trying to reuse a connected tab. Browser self-reported visibility (document.hidden/hasFocus) can't distinguish 'the user is looking at Plannotator' from 'a Plannotator window is open elsewhere' across macOS Spaces, so reuse-and-activate surfaced the wrong window. Opening the URL focuses the session in the window the user is actually in. Remote keeps stream-into-visible. goals/session-presentation/findings.md documents the research and dead ends.
…o top - Sidebar drag-to-snap-shut + hover-reveal collapse handles to match plan app. - Unified file-tree/annotations headers; FolderTree icon for the left toggle; options menu moved to the far right of the header. - AgentsTab reskin (segmented pickers, toggle, status squares) with the launch panel moved to the TOP of the sidebar; dropdowns open downward. - Add Opus 4.8 / Opus 4.8 (1M) to the agent-job Claude model picker. - Declare lucide-react in the code-review package (was relying on hoisting).
… session presentation, Opus 4.8 Brings the sibling code-review branch onto feat/ui2-plan: - Code-review sidebar reskin (parity resize, headers, agents tab, agent launchpad to top). - Git dashboard: project filter + open/merged queried separately + hide zero +/- stat. - Session presentation: print the session URL and always open a tab locally. - Opus 4.8 / 4.8 (1M) in the Claude Ask AI provider + picker; lucide-react dep fix. Both sides only co-touched daemon-protocol.ts (distinct interfaces) — auto-merged.
The daemon is a local-only dev tool, not an enterprise service. The per-start auth token (query-param bootstrap → HttpOnly cookie → Bearer header) added friction on every tab open and across restarts without buying enough for the threat model. Remove it entirely: - state.ts: drop authToken field, createDaemonAuthToken(), and the query-param/cookie constants. createDaemonBrowserAuthUrl() now returns a plain URL. - server.ts: drop the cookie-bootstrap 302 redirect and the /daemon/* auth gate. Keep the same-origin WebSocket check (DNS-rebinding guard). - event-hub.ts: drop daemonAuthenticated connection state and its gates. - client.ts: drop Bearer header and withDaemonAuth helpers. - vite.config.ts, launch-session.sh, test-plan-session.sh: drop token plumbing. - tests: rewrite the auth tests to assert no-auth access and origin-only WS gating. Verified: 153 daemon tests pass, frontend+server typecheck clean, daemon serves /daemon/status, /daemon/sessions, and / with no auth.
Self-review of the daemon auth removal surfaced three leftovers: - release.yml: the macOS/Linux/Windows release smoke gated its entire health check on reading authToken from the state file (`if [ -n "$token" ]` / `if ($token)`). With the token gone that branch never ran, so $ok stayed false and the smoke would FAIL with 'did not expose a daemon-scoped endpoint'. Drop the token plumbing and curl the now-open /daemon/sessions directly. This would have broken the release pipeline. - Rename createDaemonBrowserAuthUrl -> createDaemonBrowserUrl (state.ts, runtime.ts, apps/hook index.ts ×5). The name no longer describes anything — there is no auth in the URL. - manual-test.md: drop the stale jq .authToken / Bearer header lines. Verified: server typecheck clean, 153 daemon tests pass.
Final sweep after the auth-token removal — eliminate the last dead remnants of the mechanism: - server.test.ts: drop AUTH_TOKEN const, the authHeaders() helper, the daemonAuthenticated FakeSocket data, the authToken state props, and rewrite every authHeaders(...) call site to plain headers. - runtime.test.ts: drop the daemonAuthHeaders helper (it read the now-removed state.authToken) and its call sites. - client.test.ts: drop the now-unused AUTH_TOKEN const. - frontend client.ts: drop the dead 'action-level unauthorized' WS fallback (only the token gate ever produced it) and the now-unused DaemonHubActionError import. Kept (not auth-token remnants): the same-origin WebSocket guard and its 'unauthorized' error code (server.ts/daemon-protocol.ts), and the general DaemonHubActionError class. Verified: 153 daemon tests pass, frontend + server typecheck clean.
Extensive lexicon sweep turned up two stale spots missed earlier:
- manual-test.md: still had 3 'Authorization: Bearer ${AUTH}' header
lines (the earlier pass only fixed the first block). With AUTH no
longer defined, those curls were broken — removed all three.
- ui2point0/legacy-design-state.md: corrected two 'Bearer auth'
descriptions of the daemon client/proxy to 'no auth — open on
localhost'.
Left intact: provenance.md and historical plan.md (immutable records of
when auth existed), PR-platform auth (checkPRAuth / gh / glab), and the
same-origin WebSocket guard.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Reskins the production frontend (the single-server daemon shell) to match the DiffKit goal-prototype design. Stacks on #733 (single-server-runtime); base is `feat/single-server-runtime`, not `main`.
39 commits, grouped by theme:
Design foundation
packages/uiprimitive foundation:cnutil, Card, Button (canonical home, + success/accent variants), Badge, StatePill, Textarea, DropdownMenuHeader reskin
Plan document reskin
bg-cardOverlayScrollAreagutted to a thin shim, deadoverlayscrollbarsdeps/CSS removedSettings consolidation
Annotation / comment restyle
--annotation-comment, blue only in Simple theme — no cross-theme regression)RedlineIconcomponentSidebar + sprites
packages/ui/components/sprites/module; scatteredsprite_package_*dirs removedResize fluidity (latest)
apply(render-free, drives width through a:rootvar so heavy hosts don't re-render mid-drag)Tooling
scripts/launch-session.shad-hoc launcher; prototype sample plan as test fixture 16Test plan
bun run typecheck+bun run build:hookgreen