feat(ui): add security shield icon in sidepanel header (3 states)

Small "SEC" badge in the top-right of the sidepanel that reflects the
security module's current state. Three states drive color:

  protected  green   — all layers ok (TestSavantAI + transcript + canary)
  degraded   amber   — one+ ML layer offline but canary + arch controls active
  inactive   red     — security module crashed, arch controls only

Consumes /health.security (surfaced in commit 7e9600ff). Updated once on
connection bootstrap. Shield stays hidden until /health arrives so the user
never sees a flickering "unknown" state.

Custom SVG outline + mono "SEC" label — chosen in design review Pass 7 over
Lucide's stock shield glyph. Matches the industrial/CLI brand voice in
DESIGN.md ("monospace as personality font").

Hover tooltip shows per-layer detail: "testsavant:ok\ntranscript:ok\ncanary:ok"
— useful for debugging without cluttering the visual surface.

Known v1 limitation: only updates at connection bootstrap. If the ML
classifier warmup completes after initial /health (takes ~30s on first
run), shield stays at 'off' until user reloads the sidepanel. Follow-up
TODO: extend /sidebar-chat polling to refresh security state.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Garry Tan
2026-04-19 19:20:26 +08:00
parent ffb064afda
commit 59e0635eb5
3 changed files with 74 additions and 0 deletions

View File

@@ -5,6 +5,16 @@
<link rel="stylesheet" href="sidepanel.css">
</head>
<body>
<!-- Security shield — reflects ~/.gstack/security/session-state.json status.
Hidden until the sidebar knows its state (avoids flicker on first load).
Consumes /health.security — see browse/src/security.ts getStatus(). -->
<div class="security-shield" id="security-shield" role="status" aria-label="Security status: unknown" style="display:none" title="Security">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/>
</svg>
<span class="security-shield-label" id="security-shield-label">SEC</span>
</div>
<!-- Connection status banner -->
<div class="conn-banner" id="conn-banner" style="display:none">
<span class="conn-banner-text" id="conn-banner-text">Reconnecting...</span>