From e916ed41ea86d217de8a19061b38c887769f6e21 Mon Sep 17 00:00:00 2001 From: xcaliber Date: Wed, 1 Apr 2026 20:19:45 +0000 Subject: [PATCH] V0.7.0 shell contract (#54) --- CHANGELOG.md | 52 ++ ROADMAP-UI.md | 151 ------ ROADMAP.md | 286 +++++------ VERSION | 2 +- docs/AUDIT-surfaces.md | 209 ++++++++ docs/DESIGN-shell-contract.md | 448 ++++++++++++++++++ docs/DESIGN-surface-runners.md | 407 ++++++++++++++++ icons/apple-touch-icon-b-dark.png | Bin 0 -> 1631 bytes icons/apple-touch-icon-b-light.png | Bin 0 -> 1616 bytes icons/apple-touch-icon-e-dark.png | Bin 0 -> 1828 bytes icons/apple-touch-icon-e-light.png | Bin 0 -> 1826 bytes icons/favicon-16-b-dark.png | Bin 0 -> 218 bytes icons/favicon-16-b-light.png | Bin 0 -> 214 bytes icons/favicon-16-e-dark.png | Bin 0 -> 304 bytes icons/favicon-16-e-light.png | Bin 0 -> 312 bytes icons/favicon-32-b-dark.png | Bin 0 -> 363 bytes icons/favicon-32-b-light.png | Bin 0 -> 332 bytes icons/favicon-32-e-dark.png | Bin 0 -> 457 bytes icons/favicon-32-e-light.png | Bin 0 -> 459 bytes icons/favicon-animated.svg | 20 + icons/favicon.svg | 16 + icons/icon-128-b-dark.png | Bin 0 -> 1186 bytes icons/icon-128-b-light.png | Bin 0 -> 1186 bytes icons/icon-128-e-dark.png | Bin 0 -> 1350 bytes icons/icon-128-e-light.png | Bin 0 -> 1341 bytes icons/icon-192-b-dark.png | Bin 0 -> 1813 bytes icons/icon-192-b-light.png | Bin 0 -> 1786 bytes icons/icon-192-e-dark.png | Bin 0 -> 1962 bytes icons/icon-192-e-light.png | Bin 0 -> 1974 bytes icons/icon-256-b-dark.png | Bin 0 -> 2556 bytes icons/icon-256-b-light.png | Bin 0 -> 2553 bytes icons/icon-256-e-dark.png | Bin 0 -> 2628 bytes icons/icon-256-e-light.png | Bin 0 -> 2617 bytes icons/icon-48-b-dark.png | Bin 0 -> 496 bytes icons/icon-48-b-light.png | Bin 0 -> 492 bytes icons/icon-48-e-dark.png | Bin 0 -> 564 bytes icons/icon-48-e-light.png | Bin 0 -> 559 bytes icons/icon-512-b-dark.png | Bin 0 -> 5554 bytes icons/icon-512-b-light.png | Bin 0 -> 5548 bytes icons/icon-512-e-dark.png | Bin 0 -> 5837 bytes icons/icon-512-e-light.png | Bin 0 -> 5839 bytes icons/icon-64-b-dark.png | Bin 0 -> 626 bytes icons/icon-64-b-light.png | Bin 0 -> 620 bytes icons/icon-64-e-dark.png | Bin 0 -> 711 bytes icons/icon-64-e-light.png | Bin 0 -> 707 bytes icons/icon-b-dark-animated.svg | 48 ++ icons/icon-b-dark.svg | 21 + icons/icon-b-light-animated.svg | 43 ++ icons/icon-b-light.svg | 17 + icons/icon-e-dark-animated.svg | 67 +++ icons/icon-e-dark.svg | 23 + icons/icon-e-light-animated.svg | 63 +++ icons/icon-e-light.svg | 19 + icons/icon-morph-dark-animated.svg | 174 +++++++ icons/icon-morph-light-animated.svg | 127 +++++ icons/preview-sheet.png | Bin 0 -> 15331 bytes icons/wordmark-dark.svg | 12 + icons/wordmark-light.svg | 10 + packages/hello-dashboard/css/main.css | 17 - packages/hello-dashboard/js/main.js | 84 ---- packages/hello-dashboard/manifest.json | 13 - packages/icd-test-runner/js/tier-security.js | 12 +- packages/workflow-demo/js/main.js | 12 +- server/events/bus_test.go | 26 + server/events/types.go | 11 +- server/events/ws.go | 6 + server/handlers/groups.go | 22 + server/handlers/notifications.go | 5 +- server/handlers/packages.go | 25 + server/handlers/teams.go | 60 +++ server/main.go | 5 + server/pages/templates/base.html | 8 +- server/pages/templates/surfaces/admin.html | 1 + server/pages/templates/surfaces/docs.html | 1 + .../pages/templates/surfaces/extension.html | 1 + server/pages/templates/surfaces/settings.html | 1 + .../pages/templates/surfaces/team-admin.html | 1 + src/apple-touch-icon.png | Bin 0 -> 1631 bytes src/css/sw-primitives.css | 19 + src/css/sw-shell.css | 83 ++++ src/favicon-light-256.png | Bin 0 -> 2553 bytes src/favicon-light-32.png | Bin 0 -> 332 bytes src/favicon-light.svg | 25 +- src/icons/apple-touch-icon-b-dark.png | Bin 0 -> 1631 bytes src/icons/apple-touch-icon-b-light.png | Bin 0 -> 1616 bytes src/icons/apple-touch-icon-e-dark.png | Bin 0 -> 1828 bytes src/icons/apple-touch-icon-e-light.png | Bin 0 -> 1826 bytes src/icons/favicon-16-b-dark.png | Bin 0 -> 218 bytes src/icons/favicon-16-b-light.png | Bin 0 -> 214 bytes src/icons/favicon-16-e-dark.png | Bin 0 -> 304 bytes src/icons/favicon-16-e-light.png | Bin 0 -> 312 bytes src/icons/favicon-32-b-dark.png | Bin 0 -> 363 bytes src/icons/favicon-32-b-light.png | Bin 0 -> 332 bytes src/icons/favicon-32-e-dark.png | Bin 0 -> 457 bytes src/icons/favicon-32-e-light.png | Bin 0 -> 459 bytes src/icons/favicon-animated.svg | 20 + src/icons/favicon.svg | 16 + src/icons/icon-128-b-dark.png | Bin 0 -> 1186 bytes src/icons/icon-128-b-light.png | Bin 0 -> 1186 bytes src/icons/icon-128-e-dark.png | Bin 0 -> 1350 bytes src/icons/icon-128-e-light.png | Bin 0 -> 1341 bytes src/icons/icon-192-b-dark.png | Bin 0 -> 1813 bytes src/icons/icon-192-b-light.png | Bin 0 -> 1786 bytes src/icons/icon-192-e-dark.png | Bin 0 -> 1962 bytes src/icons/icon-192-e-light.png | Bin 0 -> 1974 bytes src/icons/icon-256-b-dark.png | Bin 0 -> 2556 bytes src/icons/icon-256-b-light.png | Bin 0 -> 2553 bytes src/icons/icon-256-e-dark.png | Bin 0 -> 2628 bytes src/icons/icon-256-e-light.png | Bin 0 -> 2617 bytes src/icons/icon-48-b-dark.png | Bin 0 -> 496 bytes src/icons/icon-48-b-light.png | Bin 0 -> 492 bytes src/icons/icon-48-e-dark.png | Bin 0 -> 564 bytes src/icons/icon-48-e-light.png | Bin 0 -> 559 bytes src/icons/icon-512-b-dark.png | Bin 0 -> 5554 bytes src/icons/icon-512-b-light.png | Bin 0 -> 5548 bytes src/icons/icon-512-e-dark.png | Bin 0 -> 5837 bytes src/icons/icon-512-e-light.png | Bin 0 -> 5839 bytes src/icons/icon-64-b-dark.png | Bin 0 -> 626 bytes src/icons/icon-64-b-light.png | Bin 0 -> 620 bytes src/icons/icon-64-e-dark.png | Bin 0 -> 711 bytes src/icons/icon-64-e-light.png | Bin 0 -> 707 bytes src/icons/icon-b-dark-animated.svg | 48 ++ src/icons/icon-b-dark.svg | 21 + src/icons/icon-b-light-animated.svg | 43 ++ src/icons/icon-b-light.svg | 17 + src/icons/icon-e-dark-animated.svg | 67 +++ src/icons/icon-e-dark.svg | 23 + src/icons/icon-e-light-animated.svg | 63 +++ src/icons/icon-e-light.svg | 19 + src/icons/icon-morph-dark-animated.svg | 174 +++++++ src/icons/icon-morph-light-animated.svg | 127 +++++ src/icons/preview-sheet.png | Bin 0 -> 15331 bytes src/icons/wordmark-dark.svg | 12 + src/icons/wordmark-light.svg | 10 + src/js/sw/sdk/index.js | 28 +- src/js/sw/shell/notification-bell.js | 32 +- src/js/sw/shell/shell-topbar.js | 95 ++++ src/js/sw/shell/user-menu.js | 24 +- src/js/sw/surfaces/admin/groups.js | 14 +- src/js/sw/surfaces/admin/index.js | 49 +- src/js/sw/surfaces/admin/packages.js | 12 +- src/js/sw/surfaces/admin/workflows.js | 13 +- src/js/sw/surfaces/docs/index.js | 11 +- src/js/sw/surfaces/settings/index.js | 98 +--- src/js/sw/surfaces/team-admin/groups.js | 37 -- src/js/sw/surfaces/team-admin/index.js | 157 ++---- src/js/sw/surfaces/team-admin/workflows.js | 2 +- src/manifest.json | 17 +- src/wordmark-dark.svg | 12 + src/wordmark-light.svg | 10 + src/wordmark.svg | 10 + 151 files changed, 3250 insertions(+), 684 deletions(-) delete mode 100644 ROADMAP-UI.md create mode 100644 docs/AUDIT-surfaces.md create mode 100644 docs/DESIGN-shell-contract.md create mode 100644 docs/DESIGN-surface-runners.md create mode 100644 icons/apple-touch-icon-b-dark.png create mode 100644 icons/apple-touch-icon-b-light.png create mode 100644 icons/apple-touch-icon-e-dark.png create mode 100644 icons/apple-touch-icon-e-light.png create mode 100644 icons/favicon-16-b-dark.png create mode 100644 icons/favicon-16-b-light.png create mode 100644 icons/favicon-16-e-dark.png create mode 100644 icons/favicon-16-e-light.png create mode 100644 icons/favicon-32-b-dark.png create mode 100644 icons/favicon-32-b-light.png create mode 100644 icons/favicon-32-e-dark.png create mode 100644 icons/favicon-32-e-light.png create mode 100644 icons/favicon-animated.svg create mode 100644 icons/favicon.svg create mode 100644 icons/icon-128-b-dark.png create mode 100644 icons/icon-128-b-light.png create mode 100644 icons/icon-128-e-dark.png create mode 100644 icons/icon-128-e-light.png create mode 100644 icons/icon-192-b-dark.png create mode 100644 icons/icon-192-b-light.png create mode 100644 icons/icon-192-e-dark.png create mode 100644 icons/icon-192-e-light.png create mode 100644 icons/icon-256-b-dark.png create mode 100644 icons/icon-256-b-light.png create mode 100644 icons/icon-256-e-dark.png create mode 100644 icons/icon-256-e-light.png create mode 100644 icons/icon-48-b-dark.png create mode 100644 icons/icon-48-b-light.png create mode 100644 icons/icon-48-e-dark.png create mode 100644 icons/icon-48-e-light.png create mode 100644 icons/icon-512-b-dark.png create mode 100644 icons/icon-512-b-light.png create mode 100644 icons/icon-512-e-dark.png create mode 100644 icons/icon-512-e-light.png create mode 100644 icons/icon-64-b-dark.png create mode 100644 icons/icon-64-b-light.png create mode 100644 icons/icon-64-e-dark.png create mode 100644 icons/icon-64-e-light.png create mode 100644 icons/icon-b-dark-animated.svg create mode 100644 icons/icon-b-dark.svg create mode 100644 icons/icon-b-light-animated.svg create mode 100644 icons/icon-b-light.svg create mode 100644 icons/icon-e-dark-animated.svg create mode 100644 icons/icon-e-dark.svg create mode 100644 icons/icon-e-light-animated.svg create mode 100644 icons/icon-e-light.svg create mode 100644 icons/icon-morph-dark-animated.svg create mode 100644 icons/icon-morph-light-animated.svg create mode 100644 icons/preview-sheet.png create mode 100644 icons/wordmark-dark.svg create mode 100644 icons/wordmark-light.svg delete mode 100644 packages/hello-dashboard/css/main.css delete mode 100644 packages/hello-dashboard/js/main.js delete mode 100644 packages/hello-dashboard/manifest.json create mode 100644 src/apple-touch-icon.png create mode 100644 src/favicon-light-256.png create mode 100644 src/favicon-light-32.png create mode 100644 src/icons/apple-touch-icon-b-dark.png create mode 100644 src/icons/apple-touch-icon-b-light.png create mode 100644 src/icons/apple-touch-icon-e-dark.png create mode 100644 src/icons/apple-touch-icon-e-light.png create mode 100644 src/icons/favicon-16-b-dark.png create mode 100644 src/icons/favicon-16-b-light.png create mode 100644 src/icons/favicon-16-e-dark.png create mode 100644 src/icons/favicon-16-e-light.png create mode 100644 src/icons/favicon-32-b-dark.png create mode 100644 src/icons/favicon-32-b-light.png create mode 100644 src/icons/favicon-32-e-dark.png create mode 100644 src/icons/favicon-32-e-light.png create mode 100644 src/icons/favicon-animated.svg create mode 100644 src/icons/favicon.svg create mode 100644 src/icons/icon-128-b-dark.png create mode 100644 src/icons/icon-128-b-light.png create mode 100644 src/icons/icon-128-e-dark.png create mode 100644 src/icons/icon-128-e-light.png create mode 100644 src/icons/icon-192-b-dark.png create mode 100644 src/icons/icon-192-b-light.png create mode 100644 src/icons/icon-192-e-dark.png create mode 100644 src/icons/icon-192-e-light.png create mode 100644 src/icons/icon-256-b-dark.png create mode 100644 src/icons/icon-256-b-light.png create mode 100644 src/icons/icon-256-e-dark.png create mode 100644 src/icons/icon-256-e-light.png create mode 100644 src/icons/icon-48-b-dark.png create mode 100644 src/icons/icon-48-b-light.png create mode 100644 src/icons/icon-48-e-dark.png create mode 100644 src/icons/icon-48-e-light.png create mode 100644 src/icons/icon-512-b-dark.png create mode 100644 src/icons/icon-512-b-light.png create mode 100644 src/icons/icon-512-e-dark.png create mode 100644 src/icons/icon-512-e-light.png create mode 100644 src/icons/icon-64-b-dark.png create mode 100644 src/icons/icon-64-b-light.png create mode 100644 src/icons/icon-64-e-dark.png create mode 100644 src/icons/icon-64-e-light.png create mode 100644 src/icons/icon-b-dark-animated.svg create mode 100644 src/icons/icon-b-dark.svg create mode 100644 src/icons/icon-b-light-animated.svg create mode 100644 src/icons/icon-b-light.svg create mode 100644 src/icons/icon-e-dark-animated.svg create mode 100644 src/icons/icon-e-dark.svg create mode 100644 src/icons/icon-e-light-animated.svg create mode 100644 src/icons/icon-e-light.svg create mode 100644 src/icons/icon-morph-dark-animated.svg create mode 100644 src/icons/icon-morph-light-animated.svg create mode 100644 src/icons/preview-sheet.png create mode 100644 src/icons/wordmark-dark.svg create mode 100644 src/icons/wordmark-light.svg create mode 100644 src/js/sw/shell/shell-topbar.js delete mode 100644 src/js/sw/surfaces/team-admin/groups.js create mode 100644 src/wordmark-dark.svg create mode 100644 src/wordmark-light.svg create mode 100644 src/wordmark.svg diff --git a/CHANGELOG.md b/CHANGELOG.md index 406ef37..3eb9797 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,58 @@ All notable changes to Armature are documented here. +## v0.7.0 — Shell Contract + Surface Audit + Rebrand + +**Shell Infrastructure** +- Kernel-injected two-slot topbar for all surfaces (home, left slot, center slot, bell, user menu) +- `sw.shell.topbar` SDK API: `setLeft()`, `setSlot()`, `setTitle()`, `hide()`, `show()` +- `.sw-topbar__tabs` / `.sw-topbar__tab` CSS classes for consistent tab styling +- Shell topbar auto-mounts on extension surfaces via `#shell-topbar` div + +**Backend WS Events** +- `package.changed` event broadcast on install/uninstall/enable/disable/update +- `auth.changed` event targeted to affected user on team/group membership changes +- `notification.all_read` event split from `notification.read` for cleaner badge sync +- `Hub.Broadcast()` method for untargeted all-client events + +**User Menu + Bell Reactivity** +- User menu re-fetches surface list on `package.changed` and `auth.changed` events +- Notification bell syncs on `notification.read` and `notification.all_read` across tabs + +**Surface Migrations** +- Settings: Pattern B (flat tabs in topbar, no sidebar, full-width content) +- Admin: Pattern C (category tabs in topbar, surface-owned sidebar below) +- Team Admin: Pattern B (flat tabs, no sidebar, Groups tab removed) +- Docs: Pattern A (shell topbar auto-renders, removed explicit Topbar import) +- All 4 surfaces now have notification bell and user menu via shell topbar + +**Error Handling + Empty States** +- `.sw-inline-error` CSS primitive for inline error + retry pattern +- `.sw-empty-state` CSS primitive for guided empty states +- Admin Workflows, Packages, Groups: inline error on list fetch failure +- Admin Workflows, Groups: descriptive empty state guidance + +**Announcement Global Dismiss** +- Announcement dismiss state persisted to localStorage keyed by content hash +- Dismissed once on any surface, dismissed everywhere + +**Rebrand Assets** +- `favicon-light.svg` renamed to `wordmark.svg` (was a 520x80 wordmark, not an icon) +- New `favicon-light.svg`: actual square light-mode icon +- New `wordmark-dark.svg`, `wordmark-light.svg` for dark/light backgrounds +- New `favicon-light-32.png`, `favicon-light-256.png` raster icons +- Full icon library deployed to `src/icons/` (both b/e variants, animated SVGs) +- `manifest.json` description updated to "Self-hosted extension platform" +- Light-mode icon entries added to PWA manifest + +**Bug Fixes** +- Docs: "On this page" outline links now scroll to headings (IDs were missing from rendered HTML) +- ICD security tier: tightened path traversal assertion (400/422, not 409), added `finally` cleanup +- Workflow demo: replaced silent catch with inline error + retry +- Team Admin: signoff panel shows display names instead of raw UUIDs +- Deleted `packages/hello-dashboard/` (dead package) +- Deleted `team-admin/groups.js` (37-line dead-end, no CRUD) + ## v0.6.18 — CI Bundle Wiring Wire `BUNDLED_PACKAGES` env var into the Gitea CI pipeline so each diff --git a/ROADMAP-UI.md b/ROADMAP-UI.md deleted file mode 100644 index 9c93ff8..0000000 --- a/ROADMAP-UI.md +++ /dev/null @@ -1,151 +0,0 @@ -# Armature — v0.6.x UI Hardening Roadmap - -> **Goal**: Fix all viewport scaling, banner integration, and styling inconsistencies -> so Claude Code can run a meaningful automated usability survey against a -> stable, uniform UI. - ---- - -## Problem Inventory - -### P1 — Viewport & Scaling (blocks everything) - -| # | Issue | Where | Impact | -|---|-------|-------|--------| -| 1 | **Dual layout systems** — `base.html` template has its own banner→surface→footer column; `app-shell.js` Preact shell has a separate `sw-shell` → `sw-shell__body` → `sw-shell__surface` column. They never coordinate. | `server/pages/templates/base.html` ↔ `src/js/sw/shell/app-shell.js` | Every surface inherits an ambiguous viewport ancestor. | -| 2 | **Transform-based scaling is broken** — `transform: scale()` on `#surfaceInner` doesn't reflow layout. Breaks `getBoundingClientRect` (menu.js already carries a scale-correction hack at line 20), scroll containment, pointer events, and the inverse-width/height hack (`100/s%`) doesn't account for banners consuming viewport space. | `base.html:56-67`, `appearance.js:41-53`, `menu.js:20-33` | Menus, tooltips, dropdowns all mis-positioned at any non-100% scale. Click targets wrong. | -| 3 | **Banner height desync** — `base.html` hardcodes `--banner-h: 28px` and renders banners in-flow. `app-shell.js` ShellBanner measures `offsetHeight` into `--banner-top-height` / `--banner-bottom-height` and uses `position: fixed` + body padding. Two independent banner systems. | `base.html:31,72-75,103-107` ↔ `app-shell.js:25-42`, `sw-shell.css:22-37,63-69` | With banners enabled, content overflows by the banner height or gets double-inset depending on which code path is active. | -| 4 | **`100vh` on mobile** — `.sw-shell`, `.chat-app`, `.chat-loading`, `.login-shell` use `100vh` which doesn't subtract mobile browser chrome (address bar, toolbar). | `sw-shell.css:9`, `chat/css/main.css:15,25`, `sw-login.css:7` | Content overflows on iOS Safari, Android Chrome. | -| 5 | **Chat uses `100vh` not `100%`** — `.chat-app { height: 100vh }` ignores parent container (which already excludes banners/footer). Notes correctly uses `height: 100%`. Every extension surface that copies chat's pattern will inherit the bug. | `packages/chat/css/main.css:15` | Chat surface overflows behind banners. | - -### P2 — CSS Architecture - -| # | Issue | Where | Impact | -|---|-------|-------|--------| -| 6 | **Class name collisions** — `.settings-section` defined in both `modals.css:41-43` and `surfaces.css:75-83` with different padding, margin, and border-bottom rules. `.sw-dropdown` in `primitives.css:443` (styled `