From a256240c2fd5d8ba47944209973b1133166ac1b4 Mon Sep 17 00:00:00 2001 From: Val Alexander Date: Tue, 1 Sep 2026 02:17:13 -0500 Subject: [PATCH 1/3] chore: clear release build warnings Three classes of warning stood between v0.0.1 and a clean release build. Rust dead code (4 warnings): the affected items are reachable only under `feature = "phase1-conformance"` or from tests, but were defined unconditionally. Gated them with `#[cfg(...)]` to match their real reachability instead of suppressing with `#[allow(dead_code)]`, so the compiler keeps telling the truth about what is live. CSS descending specificity (7 warnings): six were cross-scope false positives pairing `.fam-*`/`.set-*` selectors against unrelated earlier `.chat-demo .*` rules; one (`.fam-check-mark`) was a genuine ordering bug. The `.fam-*`/`.set-*` block styles FamiliarsPage and SettingsPage, neither of which is rendered from the demo shell, so it was 778 lines of orphaned rules sitting in the shared stylesheet. Extracted it to `src/demo/familiars-settings.css`, imported from the two pages it belongs to, and moved the `.fam-check-mark` base rule above its `.is-pass` modifier. Oversized chunk (541.83 kB > 500 kB): `main.tsx` statically imported both demo surfaces, so demo-only code and CSS shipped in the production bundle. Made them `React.lazy` and moved each stylesheet into the module that owns it. The production entry drops to 315.09 kB and production CSS to 12.08 kB; the demo code splits into chunks that only load under `?demo=chat` / `?demo=minimal`. Verified: `cargo check` and `cargo clippy --all-targets --all-features -- -D warnings` both clean, `pnpm lint` and `pnpm typecheck` clean, `vite build` emits no chunk warning, and the 59 demo tests pass. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src-tauri/src/keyring.rs | 11 +- src-tauri/src/lib.rs | 3 + src-tauri/src/operation.rs | 2 + src/demo/chat-demo.css | 779 -------------------------------- src/demo/chat-demo.tsx | 1 + src/demo/familiars-page.tsx | 2 + src/demo/familiars-settings.css | 778 +++++++++++++++++++++++++++++++ src/demo/familiars-shell.tsx | 1 + src/demo/minimal-macos.tsx | 1 + src/demo/settings-page.tsx | 2 + src/familiars/reads-shell.tsx | 1 + src/main.tsx | 41 +- 12 files changed, 827 insertions(+), 795 deletions(-) create mode 100644 src/demo/familiars-settings.css diff --git a/src-tauri/src/keyring.rs b/src-tauri/src/keyring.rs index 54150c57..74fd1713 100644 --- a/src-tauri/src/keyring.rs +++ b/src-tauri/src/keyring.rs @@ -1747,22 +1747,25 @@ impl NativeKeyring { } } -#[cfg(target_os = "macos")] +#[cfg(all(feature = "phase1-conformance", target_os = "macos"))] const fn native_keyring_backend() -> &'static str { "macos-keychain" } -#[cfg(target_os = "linux")] +#[cfg(all(feature = "phase1-conformance", target_os = "linux"))] const fn native_keyring_backend() -> &'static str { "linux-keyring" } -#[cfg(target_os = "windows")] +#[cfg(all(feature = "phase1-conformance", target_os = "windows"))] const fn native_keyring_backend() -> &'static str { "windows-credential-manager" } -#[cfg(not(any(target_os = "macos", target_os = "linux", target_os = "windows")))] +#[cfg(all( + feature = "phase1-conformance", + not(any(target_os = "macos", target_os = "linux", target_os = "windows")) +))] const fn native_keyring_backend() -> &'static str { "unsupported" } diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index b5de744b..a0fbe174 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -146,14 +146,17 @@ impl NativeConnectionState { self.operations.cancel(attempt_id, reason) } + #[cfg(feature = "phase1-conformance")] fn cancel_all_operations(&self, reason: NativeCancelReason) { self.operations.cancel_all(reason); } + #[cfg(feature = "phase1-conformance")] fn operation_registry(&self) -> Arc { Arc::clone(&self.operations) } + #[cfg(feature = "phase1-conformance")] fn mutation_queue(&self) -> Arc { Arc::clone(&self.mutations) } diff --git a/src-tauri/src/operation.rs b/src-tauri/src/operation.rs index fac59650..3f71bd5c 100644 --- a/src-tauri/src/operation.rs +++ b/src-tauri/src/operation.rs @@ -38,6 +38,7 @@ pub struct NativeOperationInput { } impl NativeOperationInput { + #[cfg(any(test, feature = "phase1-conformance"))] pub(crate) fn new(attempt_id: String, timeout_ms: u32) -> NativeResult { let input = Self { attempt_id, @@ -608,6 +609,7 @@ impl NativeOperationRegistry { Ok(NativeCancelResult::queued()) } + #[cfg(feature = "phase1-conformance")] pub(crate) fn cancel_all(&self, reason: NativeCancelReason) { if let Ok(state) = self.state.lock() { for active in state.active.values() { diff --git a/src/demo/chat-demo.css b/src/demo/chat-demo.css index ac1bf0b8..4f4bdbe4 100644 --- a/src/demo/chat-demo.css +++ b/src/demo/chat-demo.css @@ -2598,785 +2598,6 @@ background: rgba(255, 255, 255, 0.045) !important; } -/* Familiars --------------------------------------------------------------- */ - -.fam-page { - display: grid; - grid-template-columns: 340px 1fr; - height: 100vh; - overflow: hidden; - color: var(--demo-text); -} - -.fam-page button { - border: 0; - background: none; - color: inherit; - cursor: pointer; - font: inherit; -} - -.fam-browse { - display: flex; - flex-direction: column; - gap: 10px; - min-height: 0; - overflow-y: auto; - padding: 16px 12px; - border-right: 1px solid var(--demo-line); - background: var(--demo-sidebar); -} - -.fam-browse-head h1 { - margin: 0 0 10px; - font-size: 19px; - font-weight: 650; -} - -.fam-search, -.fam-input { - width: 100%; - padding: 8px 11px; - border: 1px solid var(--demo-line); - border-radius: 8px; - background: rgba(255, 255, 255, 0.05); - color: var(--demo-text); - font: inherit; -} - -.fam-search:focus-visible, -.fam-input:focus-visible { - outline: 2px solid var(--demo-accent); - outline-offset: 1px; -} - -.fam-create { - display: flex; - gap: 9px; - align-items: center; - justify-content: center; - padding: 11px; - border: 1px dashed var(--demo-line) !important; - border-radius: 10px; - color: var(--demo-muted); -} - -.fam-create:hover { - border-color: var(--demo-accent) !important; - color: var(--demo-text); -} - -.fam-create-mark { - width: 13px; - height: 13px; - border: 1px dashed currentColor; - border-radius: 50%; -} - -.fam-list { - display: grid; - gap: 8px; - margin: 0; - padding: 0; - list-style: none; -} - -.fam-card { - display: grid; - gap: 6px; - width: 100%; - padding: 11px; - border: 1px solid var(--demo-line); - border-radius: 11px; - background: rgba(255, 255, 255, 0.02); - text-align: left; -} - -.fam-card:hover { - background: rgba(255, 255, 255, 0.05); -} - -.fam-card.is-active { - border-color: rgba(154, 142, 205, 0.5); - background: rgba(154, 142, 205, 0.1); -} - -.fam-card-head { - display: flex; - gap: 9px; - align-items: center; -} - -.fam-card-name { - flex: 1; - font-weight: 620; -} - -.fam-card-role, -.fam-template-summary { - color: var(--demo-muted); - font-size: 13px; -} - -.fam-card-foot { - display: flex; - gap: 6px; -} - -.fam-glyph { - display: grid; - flex: none; - place-items: center; - border: 1px solid; - border-radius: 9px; -} - -.fam-status { - width: 8px; - height: 8px; - flex: none; - border-radius: 50%; -} - -.fam-status-available { - background: #34c759; -} - -.fam-status-working { - background: #ffd60a; -} - -.fam-status-offline { - background: #6b6b70; -} - -.fam-pill { - padding: 2px 8px; - border: 1px solid var(--demo-line); - border-radius: 999px; - color: var(--demo-muted); - font-size: 11px; - white-space: nowrap; -} - -.fam-pill.is-pass { - border-color: rgba(48, 209, 88, 0.4); - color: #30d158; -} - -.fam-pill.is-warn { - border-color: rgba(255, 214, 10, 0.4); - color: #ffd60a; -} - -.fam-templates { - display: grid; - gap: 7px; - margin-top: 6px; - padding-top: 12px; - border-top: 1px solid var(--demo-line); -} - -.fam-templates-label { - margin: 0 0 2px; - color: var(--demo-muted); - font-size: 11px; - font-weight: 700; - letter-spacing: 0.09em; - text-transform: uppercase; -} - -.fam-template { - display: grid; - gap: 4px; - justify-items: start; - padding: 10px; - border: 1px solid var(--demo-line); - border-radius: 10px; - text-align: left; -} - -.fam-template:hover { - background: rgba(255, 255, 255, 0.05); -} - -.fam-template-name { - font-weight: 600; -} - -/* Familiar detail --------------------------------------------------------- */ - -.fam-detail { - display: flex; - flex-direction: column; - min-height: 0; - overflow-y: auto; -} - -.fam-detail-head { - display: flex; - gap: 16px; - align-items: flex-start; - justify-content: space-between; - padding: 20px 24px 14px; -} - -.fam-detail-title { - display: flex; - gap: 13px; - align-items: center; -} - -.fam-detail-title h2 { - margin: 0; - font-size: 21px; - font-weight: 650; -} - -.fam-pronouns { - color: var(--demo-muted); - font-size: 13px; - font-weight: 400; -} - -.fam-detail-sub { - margin: 3px 0 0; - color: var(--demo-muted); - font-size: 13px; -} - -.fam-detail-actions { - display: flex; - gap: 9px; - align-items: center; -} - -.fam-button, -.set-button { - padding: 7px 14px; - border: 1px solid var(--demo-line); - border-radius: 999px; - background: rgba(255, 255, 255, 0.05); - color: var(--demo-text); - cursor: pointer; - font: inherit; - font-size: 13px; -} - -.fam-button:hover, -.set-button:hover { - background: rgba(255, 255, 255, 0.11); -} - -.set-button.is-danger { - border-color: rgba(255, 59, 48, 0.4); - color: #ff3b30; -} - -.fam-tabs { - display: flex; - gap: 2px; - padding: 0 24px; - border-bottom: 1px solid var(--demo-line); -} - -.fam-tab { - padding: 9px 14px; - border-bottom: 2px solid transparent !important; - color: var(--demo-muted); - font-size: 13px; -} - -.fam-tab.is-active { - border-bottom-color: var(--demo-accent) !important; - color: var(--demo-text); - font-weight: 600; -} - -.fam-body { - padding: 20px 24px 40px; -} - -.fam-section { - display: grid; - gap: 16px; - max-width: 660px; -} - -.fam-lede, -.set-lede { - margin: 0; - color: var(--demo-muted); - line-height: 1.55; -} - -.fam-checks { - display: grid; - gap: 8px; - margin: 0; - padding: 0; - list-style: none; -} - -.fam-checks li { - display: flex; - gap: 11px; - padding: 12px 14px; - border: 1px solid var(--demo-line); - border-radius: 11px; - background: rgba(255, 255, 255, 0.02); -} - -.fam-checks li.is-pass .fam-check-mark { - color: #30d158; -} - -.fam-checks li.is-fail { - border-color: rgba(255, 214, 10, 0.35); -} - -.fam-checks li.is-fail .fam-check-mark { - color: #ffd60a; -} - -.fam-check-mark { - font-size: 15px; - line-height: 1.4; -} - -.fam-check-body { - display: grid; - gap: 3px; -} - -.fam-check-title { - display: flex; - gap: 9px; - align-items: baseline; - font-weight: 620; -} - -.fam-check-file { - color: var(--demo-muted); - font-family: SFMono-Regular, ui-monospace, monospace; - font-size: 11.5px; - font-weight: 400; -} - -.fam-check-note { - color: var(--demo-muted); - font-size: 13px; - line-height: 1.5; -} - -.fam-warn { - margin: 0; - padding: 11px 14px; - border-left: 2px solid #ffd60a; - color: var(--demo-muted); - font-size: 13px; - line-height: 1.55; -} - -.fam-locked { - padding: 14px; - border: 1px solid var(--demo-line); - border-radius: 11px; - background: rgba(255, 255, 255, 0.03); -} - -.fam-locked-title { - margin: 0 0 9px; - color: var(--demo-muted); - font-size: 11px; - font-weight: 700; - letter-spacing: 0.09em; - text-transform: uppercase; -} - -.fam-locked-list { - display: flex; - gap: 28px; - margin: 0 0 10px; -} - -.fam-locked-list dt { - color: var(--demo-muted); - font-size: 12px; -} - -.fam-locked-list dd { - margin: 2px 0 0; - font-weight: 600; -} - -.fam-locked-note { - margin: 0; - color: var(--demo-muted); - font-size: 12.5px; - line-height: 1.55; -} - -.fam-locked-note code, -.set-code { - padding: 1px 5px; - border: 1px solid var(--demo-line); - border-radius: 4px; - background: rgba(255, 255, 255, 0.05); - font-family: SFMono-Regular, ui-monospace, monospace; - font-size: 12px; -} - -.fam-field { - display: grid; - gap: 5px; -} - -.fam-field-label { - font-weight: 600; -} - -.fam-value { - color: rgba(255, 255, 255, 0.82); -} - -.fam-textarea { - min-height: 68px; - resize: vertical; -} - -.fam-hint { - color: var(--demo-muted); - font-size: 12px; -} - -.fam-items { - display: grid; - gap: 4px; - margin: 0; - padding-left: 18px; - color: rgba(255, 255, 255, 0.82); - line-height: 1.5; -} - -.fam-tiers { - display: grid; - grid-template-columns: 1fr 1fr; - gap: 12px; -} - -.fam-tier { - padding: 13px; - border: 1px solid var(--demo-line); - border-radius: 11px; -} - -.fam-tier.is-held { - border-color: rgba(255, 214, 10, 0.35); -} - -.fam-tier-name { - margin: 0 0 8px; - font-weight: 650; -} - -.fam-tier-name span { - color: var(--demo-muted); - font-size: 12px; - font-weight: 400; -} - -.fam-tier ul { - display: grid; - gap: 4px; - margin: 0; - padding-left: 17px; - color: rgba(255, 255, 255, 0.82); - font-size: 13px; -} - -.fam-empty { - padding: 30px; - color: var(--demo-muted); -} - -/* Settings ---------------------------------------------------------------- */ - -.set-page { - height: 100vh; - overflow-y: auto; - padding: 26px 30px 60px; - color: var(--demo-text); -} - -.set-head { - max-width: 620px; - margin-bottom: 26px; -} - -.set-head h1 { - margin: 0 0 8px; - font-size: 22px; - font-weight: 650; -} - -.set-section { - max-width: 720px; - margin-bottom: 24px; -} - -.set-section-head { - display: flex; - gap: 10px; - align-items: baseline; - justify-content: space-between; - margin-bottom: 8px; -} - -.set-section-head h2 { - margin: 0; - font-size: 14px; - font-weight: 650; -} - -.set-source { - color: var(--demo-muted); - font-size: 11px; - font-style: italic; -} - -.set-rows { - border: 1px solid var(--demo-line); - border-radius: 12px; - overflow: hidden; -} - -.set-row { - display: flex; - gap: 20px; - align-items: center; - justify-content: space-between; - padding: 13px 15px; - background: rgba(255, 255, 255, 0.02); -} - -.set-row + .set-row { - border-top: 1px solid var(--demo-line); -} - -.set-row-text { - display: grid; - gap: 3px; - min-width: 0; -} - -.set-row-label { - font-weight: 570; -} - -.set-row-hint { - color: var(--demo-muted); - font-size: 12.5px; - line-height: 1.5; -} - -.set-row-control { - flex: none; -} - -.set-toggle { - width: 42px; - height: 25px; - padding: 2px; - border: 0; - border-radius: 999px; - background: rgba(255, 255, 255, 0.14); - cursor: pointer; - transition: background 0.14s ease-out; -} - -.set-toggle.is-on { - background: var(--demo-accent); -} - -.set-knob { - display: block; - width: 21px; - height: 21px; - border-radius: 50%; - background: #fff; - transition: transform 0.14s ease-out; -} - -.set-toggle.is-on .set-knob { - transform: translateX(17px); -} - -.set-select { - padding: 6px 10px; - border: 1px solid var(--demo-line); - border-radius: 8px; - background: rgba(255, 255, 255, 0.05); - color: var(--demo-text); - font: inherit; - font-size: 13px; -} - -.set-caps { - display: flex; - flex-wrap: wrap; - gap: 5px; - justify-content: flex-end; - max-width: 340px; -} - -.set-cap { - padding: 2px 8px; - border: 1px solid var(--demo-line); - border-radius: 999px; - color: var(--demo-muted); - font-size: 11px; -} - -.set-value { - color: var(--demo-muted); - font-size: 13px; -} - -.set-kbd { - padding: 3px 8px; - border: 1px solid var(--demo-line); - border-radius: 6px; - background: rgba(255, 255, 255, 0.06); - font-family: inherit; - font-size: 12px; -} - -@media (prefers-reduced-motion: reduce) { - .set-toggle, - .set-knob { - transition: none; - } -} - -/* Familiars: contract report and analytics ------------------------------- */ - -.fam-count { - margin: 0; - color: var(--demo-muted); - font-size: 12.5px; -} - -.fam-notes { - display: grid; - gap: 6px; - margin-top: 14px; -} - -.fam-notes-label { - margin: 0; - color: var(--demo-muted); - font-size: 11px; - font-weight: 600; - letter-spacing: 0.07em; - text-transform: uppercase; -} - -.fam-note { - margin: 0; - color: var(--demo-muted); - font-size: 12.5px; - line-height: 1.55; -} - -.fam-note.is-violation { - color: var(--demo-text); -} - -.fam-note code { - margin-right: 5px; - color: var(--demo-violet); - font-family: ui-monospace, SFMono-Regular, Menlo, monospace; - font-size: 11.5px; -} - -/* A named group of toggles, not tabs: they filter the figures below rather - than swap between panels, and there is no panel for them to control. */ -.fam-windows { - display: flex; - gap: 5px; - min-width: 0; - margin: 0 0 14px; - padding: 0; - border: 0; -} - -.fam-window { - padding: 4px 12px; - border: 1px solid var(--demo-line); - border-radius: 999px; - background: none; - color: var(--demo-muted); - font-size: 12px; -} - -.fam-window.is-active { - border-color: var(--demo-violet-line); - background: rgba(154, 142, 205, 0.16); - color: var(--demo-text); -} - -/* - * The caveat that belongs beside every figure it qualifies. Amber, not red: - * an incomplete import is not a fault, it is a reason to read the numbers as - * provisional. - */ -.fam-backfill { - margin: 0 0 14px; - padding: 10px 13px; - border: 1px solid rgba(255, 214, 10, 0.32); - border-radius: 10px; - background: rgba(255, 214, 10, 0.08); - color: var(--demo-text); - font-size: 12.5px; - line-height: 1.55; -} - -.fam-metrics { - display: grid; - grid-template-columns: repeat(3, 1fr); - gap: 1px; - overflow: hidden; - border: 1px solid var(--demo-line); - border-radius: 12px; - background: var(--demo-line); -} - -.fam-metric { - display: grid; - gap: 4px; - padding: 13px 14px; - background: var(--demo-elevated); -} - -.fam-metric-value { - font-size: 19px; - font-weight: 500; - font-variant-numeric: tabular-nums; - letter-spacing: -0.01em; -} - -.fam-metric-label { - color: var(--demo-muted); - font-size: 11.5px; -} - -.fam-empty { - margin: 0; - color: var(--demo-muted); - font-size: 12.5px; -} - @media (max-width: 820px) { .chat-demo { position: relative; diff --git a/src/demo/chat-demo.tsx b/src/demo/chat-demo.tsx index 82512c55..c4d785eb 100644 --- a/src/demo/chat-demo.tsx +++ b/src/demo/chat-demo.tsx @@ -11,6 +11,7 @@ import { useState, } from 'react'; import { ChatInspector } from './chat-inspector'; +import './chat-demo.css'; import { DocumentReader, type ReaderDocument } from './document-reader'; import { Icon } from './minimal-icons'; import { diff --git a/src/demo/familiars-page.tsx b/src/demo/familiars-page.tsx index 9a6f813f..ac0c819b 100644 --- a/src/demo/familiars-page.tsx +++ b/src/demo/familiars-page.tsx @@ -1,5 +1,7 @@ import { useMemo, useState } from 'react'; +import './familiars-settings.css'; + import { backfillNote, CAVE_ANALYTICS_WINDOWS, diff --git a/src/demo/familiars-settings.css b/src/demo/familiars-settings.css new file mode 100644 index 00000000..c2d5f09e --- /dev/null +++ b/src/demo/familiars-settings.css @@ -0,0 +1,778 @@ +/* Familiars --------------------------------------------------------------- */ + +.fam-page { + display: grid; + grid-template-columns: 340px 1fr; + height: 100vh; + overflow: hidden; + color: var(--demo-text); +} + +.fam-page button { + border: 0; + background: none; + color: inherit; + cursor: pointer; + font: inherit; +} + +.fam-browse { + display: flex; + flex-direction: column; + gap: 10px; + min-height: 0; + overflow-y: auto; + padding: 16px 12px; + border-right: 1px solid var(--demo-line); + background: var(--demo-sidebar); +} + +.fam-browse-head h1 { + margin: 0 0 10px; + font-size: 19px; + font-weight: 650; +} + +.fam-search, +.fam-input { + width: 100%; + padding: 8px 11px; + border: 1px solid var(--demo-line); + border-radius: 8px; + background: rgba(255, 255, 255, 0.05); + color: var(--demo-text); + font: inherit; +} + +.fam-search:focus-visible, +.fam-input:focus-visible { + outline: 2px solid var(--demo-accent); + outline-offset: 1px; +} + +.fam-create { + display: flex; + gap: 9px; + align-items: center; + justify-content: center; + padding: 11px; + border: 1px dashed var(--demo-line) !important; + border-radius: 10px; + color: var(--demo-muted); +} + +.fam-create:hover { + border-color: var(--demo-accent) !important; + color: var(--demo-text); +} + +.fam-create-mark { + width: 13px; + height: 13px; + border: 1px dashed currentColor; + border-radius: 50%; +} + +.fam-list { + display: grid; + gap: 8px; + margin: 0; + padding: 0; + list-style: none; +} + +.fam-card { + display: grid; + gap: 6px; + width: 100%; + padding: 11px; + border: 1px solid var(--demo-line); + border-radius: 11px; + background: rgba(255, 255, 255, 0.02); + text-align: left; +} + +.fam-card:hover { + background: rgba(255, 255, 255, 0.05); +} + +.fam-card.is-active { + border-color: rgba(154, 142, 205, 0.5); + background: rgba(154, 142, 205, 0.1); +} + +.fam-card-head { + display: flex; + gap: 9px; + align-items: center; +} + +.fam-card-name { + flex: 1; + font-weight: 620; +} + +.fam-card-role, +.fam-template-summary { + color: var(--demo-muted); + font-size: 13px; +} + +.fam-card-foot { + display: flex; + gap: 6px; +} + +.fam-glyph { + display: grid; + flex: none; + place-items: center; + border: 1px solid; + border-radius: 9px; +} + +.fam-status { + width: 8px; + height: 8px; + flex: none; + border-radius: 50%; +} + +.fam-status-available { + background: #34c759; +} + +.fam-status-working { + background: #ffd60a; +} + +.fam-status-offline { + background: #6b6b70; +} + +.fam-pill { + padding: 2px 8px; + border: 1px solid var(--demo-line); + border-radius: 999px; + color: var(--demo-muted); + font-size: 11px; + white-space: nowrap; +} + +.fam-pill.is-pass { + border-color: rgba(48, 209, 88, 0.4); + color: #30d158; +} + +.fam-pill.is-warn { + border-color: rgba(255, 214, 10, 0.4); + color: #ffd60a; +} + +.fam-templates { + display: grid; + gap: 7px; + margin-top: 6px; + padding-top: 12px; + border-top: 1px solid var(--demo-line); +} + +.fam-templates-label { + margin: 0 0 2px; + color: var(--demo-muted); + font-size: 11px; + font-weight: 700; + letter-spacing: 0.09em; + text-transform: uppercase; +} + +.fam-template { + display: grid; + gap: 4px; + justify-items: start; + padding: 10px; + border: 1px solid var(--demo-line); + border-radius: 10px; + text-align: left; +} + +.fam-template:hover { + background: rgba(255, 255, 255, 0.05); +} + +.fam-template-name { + font-weight: 600; +} + +/* Familiar detail --------------------------------------------------------- */ + +.fam-detail { + display: flex; + flex-direction: column; + min-height: 0; + overflow-y: auto; +} + +.fam-detail-head { + display: flex; + gap: 16px; + align-items: flex-start; + justify-content: space-between; + padding: 20px 24px 14px; +} + +.fam-detail-title { + display: flex; + gap: 13px; + align-items: center; +} + +.fam-detail-title h2 { + margin: 0; + font-size: 21px; + font-weight: 650; +} + +.fam-pronouns { + color: var(--demo-muted); + font-size: 13px; + font-weight: 400; +} + +.fam-detail-sub { + margin: 3px 0 0; + color: var(--demo-muted); + font-size: 13px; +} + +.fam-detail-actions { + display: flex; + gap: 9px; + align-items: center; +} + +.fam-button, +.set-button { + padding: 7px 14px; + border: 1px solid var(--demo-line); + border-radius: 999px; + background: rgba(255, 255, 255, 0.05); + color: var(--demo-text); + cursor: pointer; + font: inherit; + font-size: 13px; +} + +.fam-button:hover, +.set-button:hover { + background: rgba(255, 255, 255, 0.11); +} + +.set-button.is-danger { + border-color: rgba(255, 59, 48, 0.4); + color: #ff3b30; +} + +.fam-tabs { + display: flex; + gap: 2px; + padding: 0 24px; + border-bottom: 1px solid var(--demo-line); +} + +.fam-tab { + padding: 9px 14px; + border-bottom: 2px solid transparent !important; + color: var(--demo-muted); + font-size: 13px; +} + +.fam-tab.is-active { + border-bottom-color: var(--demo-accent) !important; + color: var(--demo-text); + font-weight: 600; +} + +.fam-body { + padding: 20px 24px 40px; +} + +.fam-section { + display: grid; + gap: 16px; + max-width: 660px; +} + +.fam-lede, +.set-lede { + margin: 0; + color: var(--demo-muted); + line-height: 1.55; +} + +.fam-checks { + display: grid; + gap: 8px; + margin: 0; + padding: 0; + list-style: none; +} + +.fam-checks li { + display: flex; + gap: 11px; + padding: 12px 14px; + border: 1px solid var(--demo-line); + border-radius: 11px; + background: rgba(255, 255, 255, 0.02); +} + +.fam-check-mark { + font-size: 15px; + line-height: 1.4; +} + +.fam-checks li.is-pass .fam-check-mark { + color: #30d158; +} + +.fam-checks li.is-fail { + border-color: rgba(255, 214, 10, 0.35); +} + +.fam-checks li.is-fail .fam-check-mark { + color: #ffd60a; +} + +.fam-check-body { + display: grid; + gap: 3px; +} + +.fam-check-title { + display: flex; + gap: 9px; + align-items: baseline; + font-weight: 620; +} + +.fam-check-file { + color: var(--demo-muted); + font-family: SFMono-Regular, ui-monospace, monospace; + font-size: 11.5px; + font-weight: 400; +} + +.fam-check-note { + color: var(--demo-muted); + font-size: 13px; + line-height: 1.5; +} + +.fam-warn { + margin: 0; + padding: 11px 14px; + border-left: 2px solid #ffd60a; + color: var(--demo-muted); + font-size: 13px; + line-height: 1.55; +} + +.fam-locked { + padding: 14px; + border: 1px solid var(--demo-line); + border-radius: 11px; + background: rgba(255, 255, 255, 0.03); +} + +.fam-locked-title { + margin: 0 0 9px; + color: var(--demo-muted); + font-size: 11px; + font-weight: 700; + letter-spacing: 0.09em; + text-transform: uppercase; +} + +.fam-locked-list { + display: flex; + gap: 28px; + margin: 0 0 10px; +} + +.fam-locked-list dt { + color: var(--demo-muted); + font-size: 12px; +} + +.fam-locked-list dd { + margin: 2px 0 0; + font-weight: 600; +} + +.fam-locked-note { + margin: 0; + color: var(--demo-muted); + font-size: 12.5px; + line-height: 1.55; +} + +.fam-locked-note code, +.set-code { + padding: 1px 5px; + border: 1px solid var(--demo-line); + border-radius: 4px; + background: rgba(255, 255, 255, 0.05); + font-family: SFMono-Regular, ui-monospace, monospace; + font-size: 12px; +} + +.fam-field { + display: grid; + gap: 5px; +} + +.fam-field-label { + font-weight: 600; +} + +.fam-value { + color: rgba(255, 255, 255, 0.82); +} + +.fam-textarea { + min-height: 68px; + resize: vertical; +} + +.fam-hint { + color: var(--demo-muted); + font-size: 12px; +} + +.fam-items { + display: grid; + gap: 4px; + margin: 0; + padding-left: 18px; + color: rgba(255, 255, 255, 0.82); + line-height: 1.5; +} + +.fam-tiers { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 12px; +} + +.fam-tier { + padding: 13px; + border: 1px solid var(--demo-line); + border-radius: 11px; +} + +.fam-tier.is-held { + border-color: rgba(255, 214, 10, 0.35); +} + +.fam-tier-name { + margin: 0 0 8px; + font-weight: 650; +} + +.fam-tier-name span { + color: var(--demo-muted); + font-size: 12px; + font-weight: 400; +} + +.fam-tier ul { + display: grid; + gap: 4px; + margin: 0; + padding-left: 17px; + color: rgba(255, 255, 255, 0.82); + font-size: 13px; +} + +.fam-empty { + padding: 30px; + color: var(--demo-muted); +} + +/* Settings ---------------------------------------------------------------- */ + +.set-page { + height: 100vh; + overflow-y: auto; + padding: 26px 30px 60px; + color: var(--demo-text); +} + +.set-head { + max-width: 620px; + margin-bottom: 26px; +} + +.set-head h1 { + margin: 0 0 8px; + font-size: 22px; + font-weight: 650; +} + +.set-section { + max-width: 720px; + margin-bottom: 24px; +} + +.set-section-head { + display: flex; + gap: 10px; + align-items: baseline; + justify-content: space-between; + margin-bottom: 8px; +} + +.set-section-head h2 { + margin: 0; + font-size: 14px; + font-weight: 650; +} + +.set-source { + color: var(--demo-muted); + font-size: 11px; + font-style: italic; +} + +.set-rows { + border: 1px solid var(--demo-line); + border-radius: 12px; + overflow: hidden; +} + +.set-row { + display: flex; + gap: 20px; + align-items: center; + justify-content: space-between; + padding: 13px 15px; + background: rgba(255, 255, 255, 0.02); +} + +.set-row + .set-row { + border-top: 1px solid var(--demo-line); +} + +.set-row-text { + display: grid; + gap: 3px; + min-width: 0; +} + +.set-row-label { + font-weight: 570; +} + +.set-row-hint { + color: var(--demo-muted); + font-size: 12.5px; + line-height: 1.5; +} + +.set-row-control { + flex: none; +} + +.set-toggle { + width: 42px; + height: 25px; + padding: 2px; + border: 0; + border-radius: 999px; + background: rgba(255, 255, 255, 0.14); + cursor: pointer; + transition: background 0.14s ease-out; +} + +.set-toggle.is-on { + background: var(--demo-accent); +} + +.set-knob { + display: block; + width: 21px; + height: 21px; + border-radius: 50%; + background: #fff; + transition: transform 0.14s ease-out; +} + +.set-toggle.is-on .set-knob { + transform: translateX(17px); +} + +.set-select { + padding: 6px 10px; + border: 1px solid var(--demo-line); + border-radius: 8px; + background: rgba(255, 255, 255, 0.05); + color: var(--demo-text); + font: inherit; + font-size: 13px; +} + +.set-caps { + display: flex; + flex-wrap: wrap; + gap: 5px; + justify-content: flex-end; + max-width: 340px; +} + +.set-cap { + padding: 2px 8px; + border: 1px solid var(--demo-line); + border-radius: 999px; + color: var(--demo-muted); + font-size: 11px; +} + +.set-value { + color: var(--demo-muted); + font-size: 13px; +} + +.set-kbd { + padding: 3px 8px; + border: 1px solid var(--demo-line); + border-radius: 6px; + background: rgba(255, 255, 255, 0.06); + font-family: inherit; + font-size: 12px; +} + +@media (prefers-reduced-motion: reduce) { + .set-toggle, + .set-knob { + transition: none; + } +} + +/* Familiars: contract report and analytics ------------------------------- */ + +.fam-count { + margin: 0; + color: var(--demo-muted); + font-size: 12.5px; +} + +.fam-notes { + display: grid; + gap: 6px; + margin-top: 14px; +} + +.fam-notes-label { + margin: 0; + color: var(--demo-muted); + font-size: 11px; + font-weight: 600; + letter-spacing: 0.07em; + text-transform: uppercase; +} + +.fam-note { + margin: 0; + color: var(--demo-muted); + font-size: 12.5px; + line-height: 1.55; +} + +.fam-note.is-violation { + color: var(--demo-text); +} + +.fam-note code { + margin-right: 5px; + color: var(--demo-violet); + font-family: ui-monospace, SFMono-Regular, Menlo, monospace; + font-size: 11.5px; +} + +/* A named group of toggles, not tabs: they filter the figures below rather + than swap between panels, and there is no panel for them to control. */ +.fam-windows { + display: flex; + gap: 5px; + min-width: 0; + margin: 0 0 14px; + padding: 0; + border: 0; +} + +.fam-window { + padding: 4px 12px; + border: 1px solid var(--demo-line); + border-radius: 999px; + background: none; + color: var(--demo-muted); + font-size: 12px; +} + +.fam-window.is-active { + border-color: var(--demo-violet-line); + background: rgba(154, 142, 205, 0.16); + color: var(--demo-text); +} + +/* + * The caveat that belongs beside every figure it qualifies. Amber, not red: + * an incomplete import is not a fault, it is a reason to read the numbers as + * provisional. + */ +.fam-backfill { + margin: 0 0 14px; + padding: 10px 13px; + border: 1px solid rgba(255, 214, 10, 0.32); + border-radius: 10px; + background: rgba(255, 214, 10, 0.08); + color: var(--demo-text); + font-size: 12.5px; + line-height: 1.55; +} + +.fam-metrics { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 1px; + overflow: hidden; + border: 1px solid var(--demo-line); + border-radius: 12px; + background: var(--demo-line); +} + +.fam-metric { + display: grid; + gap: 4px; + padding: 13px 14px; + background: var(--demo-elevated); +} + +.fam-metric-value { + font-size: 19px; + font-weight: 500; + font-variant-numeric: tabular-nums; + letter-spacing: -0.01em; +} + +.fam-metric-label { + color: var(--demo-muted); + font-size: 11.5px; +} + +.fam-empty { + margin: 0; + color: var(--demo-muted); + font-size: 12.5px; +} diff --git a/src/demo/familiars-shell.tsx b/src/demo/familiars-shell.tsx index 2c181b19..566ef250 100644 --- a/src/demo/familiars-shell.tsx +++ b/src/demo/familiars-shell.tsx @@ -10,6 +10,7 @@ import { useState, } from 'react'; import { type CompletionCommand, Composer, type ComposerAttachment } from '../ui'; +import './familiars-shell.css'; import { clockLabel, FAM_COMMANDS, diff --git a/src/demo/minimal-macos.tsx b/src/demo/minimal-macos.tsx index 4f8d1cb3..02010576 100644 --- a/src/demo/minimal-macos.tsx +++ b/src/demo/minimal-macos.tsx @@ -1,6 +1,7 @@ import { type CSSProperties, useEffect, useRef, useState } from 'react'; import { canUseTauriCommands } from '../lib/desktop-host'; +import './minimal-macos.css'; import { backfillNote, CAVE_ANALYTICS_WINDOWS, diff --git a/src/demo/settings-page.tsx b/src/demo/settings-page.tsx index f6878df4..75e6cae9 100644 --- a/src/demo/settings-page.tsx +++ b/src/demo/settings-page.tsx @@ -1,5 +1,7 @@ import { useState } from 'react'; +import './familiars-settings.css'; + import { MOCK_FAMILIARS } from './mock-familiars'; /** diff --git a/src/familiars/reads-shell.tsx b/src/familiars/reads-shell.tsx index 403c44c1..6951f7d3 100644 --- a/src/familiars/reads-shell.tsx +++ b/src/familiars/reads-shell.tsx @@ -1,6 +1,7 @@ import { useEffect, useMemo, useState } from 'react'; import { availabilityFor, type ControlName } from './capabilities'; +import './reads-shell.css'; import type { Capability, ConversationSummary, diff --git a/src/main.tsx b/src/main.tsx index 706006de..7658c3e5 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -1,21 +1,31 @@ import '@fontsource-variable/inter'; import '@fontsource-variable/jetbrains-mono'; -import { StrictMode } from 'react'; +import { lazy, StrictMode, Suspense } from 'react'; import { createRoot } from 'react-dom/client'; import { App } from './app'; -import { DemoShell } from './demo/chat-demo'; -import './demo/chat-demo.css'; -import { FamiliarsShell } from './demo/familiars-shell'; -import './demo/familiars-shell.css'; -import { createMockFamiliarsSource } from './familiars/mock-source'; -import { FamiliarsReadsShell } from './familiars/reads-shell'; -import './familiars/reads-shell.css'; -import { MinimalMacOS } from './demo/minimal-macos'; -import './demo/minimal-macos.css'; import './styles.css'; import './ui/ui.css'; +const DemoShell = lazy(async () => ({ + default: (await import('./demo/chat-demo')).DemoShell, +})); +const FamiliarsShell = lazy(async () => ({ + default: (await import('./demo/familiars-shell')).FamiliarsShell, +})); +const MinimalMacOS = lazy(async () => ({ + default: (await import('./demo/minimal-macos')).MinimalMacOS, +})); +const FamiliarsReadsShell = lazy(async () => { + const [{ FamiliarsReadsShell: Shell }, { createMockFamiliarsSource }] = await Promise.all([ + import('./familiars/reads-shell'), + import('./familiars/mock-source'), + ]); + const source = createMockFamiliarsSource(); + + return { default: () => }; +}); + const rootElement = document.getElementById('root'); if (!rootElement) { @@ -43,6 +53,9 @@ if (!rootElement) { * honestly serve today, against `MockFamiliarsSource`. It previews the * eventual production route; `chat`'s richer, Stage 2-4 behavior stays * demo-only until Cave serves it. + * + * Each demo, its stylesheet, and its mock data are lazy: only the read-only + * production app ships in the default bundle. */ /** * A demo build opens on a demo surface without a query flag. @@ -64,10 +77,14 @@ function surfaceFor(name: string | null) { } if (name === 'familiars-reads') { - return ; + return ; } return name === 'minimal' ? : ; } -createRoot(rootElement).render({surfaceFor(demo)}); +createRoot(rootElement).render( + + {surfaceFor(demo)} + , +); From b25100b9e21015b62b1bdf8c6ccf2f25f6d8c643 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 1 Sep 2026 07:29:53 +0000 Subject: [PATCH 2/3] fix: scope suspense to demo surfaces Co-authored-by: BunsDev <68980965+BunsDev@users.noreply.github.com> --- src/main.tsx | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/src/main.tsx b/src/main.tsx index 7658c3e5..a1ba3782 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -69,22 +69,36 @@ const demo = new URLSearchParams(window.location.search).get('demo') ?? defaultD function surfaceFor(name: string | null) { if (name === 'chat') { - return ; + return ( + + + + ); } if (name === 'messages') { - return ; + return ( + + + + ); } if (name === 'familiars-reads') { - return ; + return ( + + + + ); } - return name === 'minimal' ? : ; + return name === 'minimal' ? ( + + + + ) : ( + + ); } -createRoot(rootElement).render( - - {surfaceFor(demo)} - , -); +createRoot(rootElement).render({surfaceFor(demo)}); From 5f4b99a1ec15afa6c747d58ef428628f0c0878cb Mon Sep 17 00:00:00 2001 From: Val Alexander Date: Tue, 1 Sep 2026 23:29:35 -0500 Subject: [PATCH 3/3] fix: separate familiar empty states Give the detail-pane and analytics empty states distinct selectors so their spacing is intentional. Keep settings fixtures in a side-effect-free module so extracting page CSS does not pull it into the chat demo chunk. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/demo/chat-inspector.tsx | 2 +- src/demo/familiars-page.tsx | 2 +- src/demo/familiars-settings.css | 4 +++- src/demo/mock-settings.ts | 17 +++++++++++++++++ src/demo/settings-page.tsx | 19 +------------------ 5 files changed, 23 insertions(+), 21 deletions(-) create mode 100644 src/demo/mock-settings.ts diff --git a/src/demo/chat-inspector.tsx b/src/demo/chat-inspector.tsx index c4311275..cbc575ba 100644 --- a/src/demo/chat-inspector.tsx +++ b/src/demo/chat-inspector.tsx @@ -8,7 +8,7 @@ import { } from './minimal-familiar-sdk'; import { Icon, type IconName } from './minimal-icons'; import { contractReport, type MockFamiliar } from './mock-familiars'; -import { MOCK_CREDENTIAL, MOCK_HEALTH } from './settings-page'; +import { MOCK_CREDENTIAL, MOCK_HEALTH } from './mock-settings'; type InspectorTab = 'overview' | 'access' | 'activity'; type InspectorView = 'agent' | 'app'; diff --git a/src/demo/familiars-page.tsx b/src/demo/familiars-page.tsx index ac0c819b..85ea136e 100644 --- a/src/demo/familiars-page.tsx +++ b/src/demo/familiars-page.tsx @@ -237,7 +237,7 @@ export function FamiliarsPage() { ) : ( -

No familiar selected.

+

No familiar selected.

)} diff --git a/src/demo/familiars-settings.css b/src/demo/familiars-settings.css index c2d5f09e..ba182129 100644 --- a/src/demo/familiars-settings.css +++ b/src/demo/familiars-settings.css @@ -495,9 +495,11 @@ font-size: 13px; } -.fam-empty { +.fam-detail-empty { + margin: 0; padding: 30px; color: var(--demo-muted); + font-size: 12.5px; } /* Settings ---------------------------------------------------------------- */ diff --git a/src/demo/mock-settings.ts b/src/demo/mock-settings.ts new file mode 100644 index 00000000..537553ef --- /dev/null +++ b/src/demo/mock-settings.ts @@ -0,0 +1,17 @@ +/** What `GET /api/client/v1/health` reports, mocked. */ +export const MOCK_HEALTH = { + service: 'coven-cave', + apiVersion: '1.4', + minimumClientVersion: '1.0', + instanceId: 'cave-7f3a91c2', + pairingRequired: true, + capabilities: ['attachments', 'attention', 'task-handoff', 'github-actions'] as const, +}; + +/** The paired credential, as the paired-clients surface would describe it. */ +export const MOCK_CREDENTIAL = { + label: 'OpenCoven Chat (desktop)', + scopes: ['chat:read', 'chat:send', 'conversations:write', 'attachments:write'], + createdAt: '12 August 2026', + lastUsed: '4 minutes ago', +}; diff --git a/src/demo/settings-page.tsx b/src/demo/settings-page.tsx index 75e6cae9..09223ccb 100644 --- a/src/demo/settings-page.tsx +++ b/src/demo/settings-page.tsx @@ -3,6 +3,7 @@ import { useState } from 'react'; import './familiars-settings.css'; import { MOCK_FAMILIARS } from './mock-familiars'; +import { MOCK_CREDENTIAL, MOCK_HEALTH } from './mock-settings'; /** * Settings. @@ -27,24 +28,6 @@ import { MOCK_FAMILIARS } from './mock-familiars'; * shown-and-broken. */ -/** What `GET /api/client/v1/health` reports, mocked. */ -export const MOCK_HEALTH = { - service: 'coven-cave', - apiVersion: '1.4', - minimumClientVersion: '1.0', - instanceId: 'cave-7f3a91c2', - pairingRequired: true, - capabilities: ['attachments', 'attention', 'task-handoff', 'github-actions'] as const, -}; - -/** The paired credential, as the paired-clients surface would describe it. */ -export const MOCK_CREDENTIAL = { - label: 'OpenCoven Chat (desktop)', - scopes: ['chat:read', 'chat:send', 'conversations:write', 'attachments:write'], - createdAt: '12 August 2026', - lastUsed: '4 minutes ago', -}; - type Row = { label: string; hint: string; control: React.ReactNode }; function Section({ title, source, rows }: { title: string; source: string; rows: Row[] }) {