1b9c761274f5450a131c20eb60d3f9f4ea2cf983
7 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
| 873b00ac42 |
style(web): fix prettier config, format entire web/ tree
.prettierrc.json was missing "semi": false, so prettier wanted to add semicolons to a codebase written without them (763 semicolon-free statements vs. 150 with, in hand-written .ts; zero hand-written .svelte files use them at all). That's why prettier --check failed on 249 files — not because the code was unformatted, but because the config didn't match the actual house style. Added "semi": false; left printWidth/etc as configured (printWidth barely moves the failure count: 218/213/212 files at 100/120/140). Ran `prettier --write .` with the corrected config. Verified semantics-preserving before and after: - eslint: 142 problems both before and after, byte-identical - build passes, 38/38 tests pass - token-stream diff (whitespace/semicolons/quotes normalized) on all 218 changed files: only 52 had any remaining token change, all either trailing-comma removal (matching trailingComma: "none") or import/ ternary reflow — no semantic changes - live smoke test: Knowledge, Tasks, Fleet map, and a chat window (AgentTrace, markdown, Scope graph, activity rail) all render correctly, no console errors Most of the diff is shadcn/ui vendor files (lib/components/ui/) moving from the CLI's own style (double quotes, tabs, semicolons) to house style; re-running `shadcn-svelte add` on a component will need a follow-up format pass. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
|||
| 4e4e2c169c |
feat(web): replace 3D graph with fleet map, add desktop background patterns, rename Knowledge Base to Fleet
- FleetMap: service-centric host -> container -> service graph replacing the WebGL 3D force graph, with health coloring, hover-to-trace blast radius, and click-to-open - Desktop background: configurable CSS pattern picker in Settings -> Appearance (8 patterns, color/fill/opacity/fade/size/rotation), replacing the hardcoded ambient graph background - Fix missing data-orientation/data-disabled Tailwind custom variants so the shadcn Slider's track actually renders - Rename "Knowledge Base" app to "Fleet"; scope its table to the same fleet entities as the graph (compute-entity descendants + service) instead of all entities - Remove dead code: EntityGraph, GraphBackground, categories.ts, MultiSelectFilter (all superseded by the above) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
|||
| 1c12d40712 |
feat(web): adopt shadcn context-menu for mascot + desktop right-click menus
Problem: the mascot's right-click menu was non-interactive — RadialMenu's root div rendered inside MascotLayer's pointer-events-none root (and the new DockedLayer wrapper compounded it) without re-enabling pointer-events, so clicks passed straight through. The desktop right-click menu was a hand-rolled positioned div, inconsistent with the rest of the UI. Change: both menus now use the shadcn-svelte context-menu primitive (bits-ui, portaled to <body>). - Mascot: MascotMenu.svelte renders the action tree recursively — children become ContextMenu.Sub (native hover sub-menu navigation, replacing the manual breadcrumb stack), leaves become ContextMenu.Item with onSelect. MascotLayer wraps <Mascot> in a ContextMenu.Trigger; visibility predicates read reactively off ctx.model so items appear/disappear live. Removed the manual menuPos/openMenu/closeMenu machinery. RadialMenu.svelte deleted. - Desktop: the surface's bare-desktop hit area is now a ContextMenu.Trigger layer (absolute inset-0, pointer-events-auto) placed before the icons/windows in the DOM. The DOM-structure gate (icons/windows are pointer-events-auto siblings that paint on top and intercept their own right-clicks; bare desktop falls through to the trigger) replaces the old fragile e.currentTarget === e.target check. Left-click blur moved onto the trigger; Undo/Redo disabled state snapshotted via onOpenChange (canUndo/canRedo are wmkit methods). Risk: the blocker that made the mascot menu non-interactive in the first place — Mascot.svelte's handleContextMenu called e.stopPropagation(), which would have prevented a ContextMenu.Trigger wrapper from ever seeing the right-click. Removed that handler; bits-ui now owns right-click on the mascot, left-click drag/pet passes through. The context-menu content portals to <body>, escaping the pointer-events-none mascot and docked layers entirely — the structural fix, not just a component swap. Verification: vitest 38/38; svelte-check + tsc clean for changed files; eslint clean (the shadcn-generated ui/context-menu/* files carry the same baseline custom_element_props_identifier warnings as the rest of the ui/ folder, not from this change); vite build green; runtime confirmed — right-click mascot opens the action tree with hover sub-menus, right-click bare desktop opens Cascade/Tile/Show/Reset/ Undo/Redo, right-click on an icon or window does not. |
|||
| 482c7f3448 |
feat(web): app-registry architecture — OS + Apps, lazy loading, installable apps
Problem: the frontend had an implicit OS+Apps metaphor (desktop, floating windows, an app registry) but the contract was informal — the mascot was hardcoded into the shell, all apps were statically imported into one 800KB bundle, and there was no install/uninstall path. Change: three phases landed. - Phase 1 (contract + docked kind): AppDef extended with docked/noIcon and optional geometry; the mascot registered as a docked app via a generic DockedLayer that replaces the hardcoded <MascotLayer />; openAppWindow branches on docked → toggleDocked; persisted docked visibility store (absent key = visible, no APPS import to avoid a static cycle). - Phase 2 (lazy loading): AppDef.component is now a dynamic-import loader; LazyApp renders with a loading skeleton; Vite code-splits each app (main bundle 800KB→485KB); the LazyMascot wrapper is gone since the lazy loader breaks the import cycle directly. - Phase 3 (installable apps, local bundles): AppManifest + catalog + installApp/uninstallApp + localStorage persistence; reactive apps store (built-in + installed) and derived appById; App Store page; Notes demo app; icons.ts and WindowLayer's orphan-close react to registration so installs appear without a reload. - Structure: data-table casing unified to PascalCase; the mislabeled DataTable.svelte.ts (pure types, not runes) renamed to types.ts; LazyApp colocated with its desktop-shell consumers; app-store moved under lib/ so the dependency direction is consistent. Risk: the app registry is now a reactive store, not a static array, so every consumer (Desktop, DockedLayer, Taskbar, icons, windows) reads from derived stores. Two static-cycle traps are documented in docs/mbse/components.md §9: docked.ts must not import APPS (it would fire a TDZ at init via the apps.ts→pages→windows.ts→here path), and apps.ts must not statically import the mascot (the lazy loader defers its module graph). Remote bundle loading, the /api/v1/apps endpoint, and permission enforcement are deliberately NOT in this commit — they are security-critical and deferred to Phase 4 with an ADR. Verification: vitest 38/38; svelte-check + tsc clean for changed files; eslint clean; vite build green; runtime smoke confirmed (install Notes → icon appears → open → uninstall → icon + window gone; survives reload). docs/mbse/components.md Component 9 and the plan updated. Plan: plans/2026-07-21-frontend-os-apps-architecture.md |
|||
| 7b1dfbc8aa |
feat(web): desktop mascot ("Cluck") — egg/chick/adult tamagotchi that roams the desktop, reacts to chat/events, walks on top of windows
Implements plans/2026-07-20-desktop-mascot.md. New code under web/src/lib/mascot/ (types/sprites/render/state/behavior/actions/ stimuli + Mascot/MascotLayer/RadialMenu/NameDialog components) plus CC0 sprite sheets at web/public/mascot/ (chicken + Onocentaur egg pack + reaction bubbles). MascotLayer is inserted into Desktop.svelte after WindowLayer; <2-line integration. Tamagotchi: egg -> chick -> adult lifecycle persisted to localStorage['oikos-mascot'] (debounced 300ms). Egg hatches on first naming (no timed incubation per implementation deviation). Chick/adult wander, peck, sleep, blink autonomously via a weighted-random FSM; the chicken walks above windows (ground line = highest window top edge beneath its x, recomputed each tick from wmState; rides the ground when the window beneath is dragged). Interaction: draggable with flutter-fall physics on release mid-air; plain click = pet (heart bubble + happy anim); right-click opens a rounded-button radial menu (Interact/Care/Identity/Debug nested groups) mirroring the desktop's own right-click menu styling; auto-flips above/ left near screen edges. Awareness: stimulus bus subscribes to chat.ts streaming, activity.ts activityLog (knowledge-entry diff), events.ts liveEvents (critical/ signal -> alarmed, execution -> happy), with priority+cooldown gating. Egg-stage reactions are suppressed. Reaction bubbles are anti-aliased. Sprite loop runs at ~60fps via setTimeout (not rAF) per GraphBackground convention, dt clamped to 100ms; position via transform: translate3d + will-change: transform for compositor-friendly motion. Z-index ordering: WindowLayer z-40 < MascotLayer z-[45] < desktop context menu z-50 < RadialMenu/NameDialog z-[60]. Docs: plan + docs/mascot/README.md (MBSE subsystem model) updated to Implemented with a deviations note covering hatch-on-naming, PNG-sheet art, button-column radial menu, 60fps loop, egg-reaction suppression, and window-walking ground model. VERSION bumped 0.7.13 -> 0.8.0. |
|||
| aee458ce83 |
feat(web): add windowed Settings app, separate from initial Config screen
The taskbar's gear icon reopened the full-page "Connect to Oikos" screen even once already connected. Split that: Config.svelte stays as the first-run/unconfigured screen; a new Settings app (windowed, like Tasks or Operations) now handles in-session changes, with a section list (Connection, Appearance) built to grow — future settings are one more entry, not a new screen. - pages/Settings.svelte: Connection (server URL/token/Authentik, reusing config.ts + oidc.ts) and Appearance (Terracotta/Carbon picker) sections. - apps.ts: registered as a normal desktop app. - Taskbar's gear button now opens the Settings window; removed the onOpenConnection prop threaded through App -> Desktop -> Taskbar, since Settings' "Forget saved connection" (clear config + reload) replaces it. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
|||
| aed068de12 |
feat(web): redesign UI as an OS-style desktop shell
Replace the sidebar + hash-routed page shell with a desktop metaphor:
draggable app icons, apps opening as floating wmkit windows, a centered
"What should Nomos do?" task launcher, and a bottom taskbar showing all
open windows plus a system tray.
- New app registry ($lib/apps.ts) — adding an app is one entry, nothing
else to touch.
- New desktop shell components (Desktop, WindowLayer, DesktopIcon,
Taskbar, TaskLauncher) under $lib/components/desktop-shell/.
- Icon positions are a persisted, collision-avoiding grid ($lib/stores/icons.ts).
- Window layout persists across reloads (wmkit persist), with
drag-to-maximize, F6 window cycling, and now a right-click desktop menu
(cascade/tile/show desktop/reset icons) plus Cmd/Ctrl+Z undo/redo for
window moves, resizes, and closes.
- Taskbar buttons get a hover-close and self-correct their title once a
new task's real goal is known.
- New task windows (desktop launcher and the Tasks app's "New task"
button) open as a window, not a dialog, and hand off to the real
session window once the backend assigns an id.
- Fixed a real gap along the way: GET /sessions/{id} couldn't tell
"session deleted" from "session has no messages yet" (both returned
200 with an empty list) — cmd/nomos/main.go now checks existence and
404s, so a stale/persisted task window shows "Task not found" instead
of a misleadingly empty, live-looking chat.
- Test coverage for the new pure logic (icon placement/collision
avoidance, app registry id helpers) plus a vitest matchMedia polyfill
needed to import anything touching the theme store.
Deletes the now-superseded sidebar shell, MinimizedWindowsBar, and the
standalone Chat/EntityDetail pages (folded into the window layer).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|