Files
rohitg00__agentmemory/website/components/CommandCenter.tsx
Rohit Ghumare 9ba346789b docs(website): refresh agent-memory.dev for v0.9.15+ (#415)
* docs(website): refresh agent-memory.dev for v0.9.15+ DevEx surface

Drift accumulated across the website from v0.9.0 through v0.9.15.
Each section caught up:

CommandCenter:
- "iii CONSOLE · OPTIONAL" → "iii CONSOLE · FIRST-CLASS". User
  pushback: the console gives engine-level visibility (workers,
  functions, queues, traces) and is now installed inline by the
  agentmemory CLI on first run from v0.9.16. Not optional.
- Bullet "49 HTTP TRIGGERS" → "107 HTTP ENDPOINTS" to match
  generated-meta.json restEndpoints count. Dropped the stale "33
  REGISTERED FUNCTIONS" subhead.
- Section lede now mentions both UIs are first-class + inline-
  installed.

Compare:
- MCP TOOLS our column 44 → 51 (matches generated-meta.json).
- New REST ENDPOINTS row (107) — competitors don't ship a REST
  shape per their docs, so dashes for mem0/letta/cognee.
- New NATIVE PLUGINS row listing the 6 first-party agents +
  Cursor/Gemini CLI.

Agents:
- FEATURED expanded from 4 to 6 (added pi + OpenHuman). Codex CLI
  pitch updated to "6 hooks + MCP · native plugin" reflecting the
  hooks addition in PR #383.
- Section title "FOUR FIRST-PARTY" → "SIX FIRST-PARTY".
- Section lede now mentions `agentmemory connect <agent>`
  (shipped in v0.9.15 PR #402).

Hero:
- "START IN 60 SECONDS" CTA → "START IN 30 SECONDS". Cold install
  + engine spawn measured 8-12s on v0.9.15 with the native binary
  path; 60s was the v0.9.0-era Docker-first claim.

generated-meta.json regenerated by the build (auto-derive rule).
Website build clean.

* chore(website): refresh generated-meta timestamp

* feat(website): AS FEATURED IN bar — AlphaSignal, AAIF, Trendshift

Wedges between Hero and Stats. Three text-cells in a 3-col row (1-col
on mobile), each links to the source article. Matches the existing
brutalist mono aesthetic — no logo files, no marquee animation, no
JS. Border + small ↗ glyph on each card; gold border on hover.

Sources chosen for brand authority + independence:
- AlphaSignal (180K technical subscribers) →
  alphasignalai.substack.com/p/how-agentmemory-works-and-how-to
- Agentic AI Foundation (Linux Foundation backed) → aaif.io
- Trendshift "NEW 2026 · Position #19" → trendshift.io/repositories/25123

Static, server-rendered, no client bundle impact.

* feat(website): real logos in AS FEATURED IN bar

Replaced text-only treatment with actual brand marks:

- AlphaSignal — github.com/Alpha-Signal org avatar (verified)
  https://avatars.githubusercontent.com/u/64016073?s=200&v=4
- Agentic AI Foundation — aaif.io's own favicon PNG (verified by
  fetching their site)
- Trendshift — their official badge endpoint
  trendshift.io/api/badge/repositories/25123 — bakes the repo's live
  star + position count into the image, so the cell tracks the
  Trendshift state automatically

Layout split: AlphaSignal + AAIF render logo-left / text-right with
↗ arrow. Trendshift renders centered with the full badge image (it's
already a wide brand mark with the rank + stars baked in, so making
it text-bound looks cramped).

next.config.ts adds the three new image hosts to remotePatterns
(aaif.io, trendshift.io, raw.githubusercontent.com). Existing
unoptimized={true} per image so we don't proxy through Vercel's
optimizer.

Build clean. No new deps.

* feat(website): use real AAIF wordmark logo + center 3-card grid

User pushed the actual Agentic AI Foundation wordmark — 838x203 PNG
on transparent background, black artwork. Dropped the favicon and
self-hosted the wordmark at /featured/aaif-logo.png so the brand
reads cleanly on the dark cell.

Rendered as a badge-style cell (centered, wide-form) like Trendshift,
with a `filter: invert(1) brightness(1.05)` so the black artwork
inverts to white-on-dark and matches the site palette without
shipping a second asset.

Grid template balanced: 1fr / 1.3fr / 1fr — gives AAIF the extra
horizontal room its wordmark needs while keeping AlphaSignal and
Trendshift consistent on either side. Max width bumped to 1000px.

`badgeImg` got `object-fit: contain` and an explicit `max-height` so
the AAIF + Trendshift badges sit at the same vertical baseline.

* fix(website): coderabbit PR #415 — meta drift + a11y + dead CSS

Five findings, all valid against the branch:

1. CommandCenter line 48 hardcoded "107 HTTP ENDPOINTS" but
   website/lib/generated-meta.json reports restEndpoints: 121.
   Bumped to 121. The meta file is the source of truth (auto-derived
   from src/triggers/api.ts at build via scripts/derive-meta.js).

2. Compare.tsx REST ENDPOINTS row same drift: "107" → "121".

3. Compare.tsx NATIVE PLUGINS row claimed "6" in the label but the
   parenthesized list had 8 names (Cursor + Gemini included). Per
   README: those two are MCP-server tier, not native plugin. List
   trimmed to the actual 6 native-plugin agents:
   Claude/Codex/OpenClaw/Hermes/pi/OpenHuman.

4. FeaturedIn.module.css .cell had :hover only — keyboard users
   tabbing through saw no focus indicator (WCAG 2.4.7). Added
   :focus-visible with gold border + outline.

5. .cellBadge declared `grid-template-columns: none` while using
   display: flex. Dead property removed.
2026-05-15 19:23:45 +01:00

163 lines
5.8 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"use client";
import { useState } from "react";
import Image from "next/image";
import styles from "./CommandCenter.module.css";
type Tab = "viewer" | "console" | "state" | "traces";
const TABS: Array<{ id: Tab; label: string; sub: string }> = [
{ id: "viewer", label: "VIEWER", sub: ":3113 · LIVE OBSERVATION STREAM" },
{ id: "console", label: "iii CONSOLE", sub: ":3114 · ENGINE DASHBOARD" },
{ id: "state", label: "STATE", sub: "RAW KV BROWSER + JSON EDITOR" },
{ id: "traces", label: "TRACES", sub: "OTEL WATERFALL + FLAME" },
];
const PANELS: Record<
Tab,
{
title: string;
blurb: string;
bullets: string[];
img: string;
alt: string;
launch: string;
}
> = {
viewer: {
title: "SHIP-WITH VIEWER · PORT 3113",
blurb:
"The agentmemory server auto-starts a real-time viewer on port 3113. No install, no config. Everything the server sees, the viewer shows.",
bullets: [
"LIVE OBSERVATION STREAM · EVERY HOOK AS IT FIRES",
"SESSION EXPLORER · REPLAY ANY PAST SESSION",
"MEMORY BROWSER · FILTER BY PROJECT / TYPE / CONFIDENCE",
"KNOWLEDGE GRAPH VISUALIZATION · FORCE-DIRECTED",
"HEALTH DASHBOARD · HEAP / RSS / EVENT LOOP LAG",
],
img: "/demo.gif",
alt: "agentmemory viewer live demo",
launch: "open http://localhost:3113",
},
console: {
title: "iii CONSOLE · FIRST-CLASS",
blurb:
"agentmemory runs on the iii engine, so the official iii console gives engine-level visibility: every function call, every worker, every queue, every trace. From v0.9.16 the agentmemory CLI prompts to install iii console alongside the engine. Launch on :3114 so the viewer keeps :3113.",
bullets: [
"REGISTERED FUNCTIONS · INVOKE ANY DIRECTLY WITH JSON",
"121 HTTP ENDPOINTS · REPLAY ANY REST CALL",
"WEBSOCKET STREAM MONITOR · WATCH FRAMES LIVE",
"OTEL EXPORTER = MEMORY (DEFAULT) · TRACES STAY LOCAL",
"NO AUTH · BIND TO 127.0.0.1 ONLY",
],
img: "/dashboard.png",
alt: "iii console dashboard",
launch: "iii-console --port 3114 --engine-port 3111",
},
state: {
title: "RAW KV BROWSER",
blurb:
"Three-panel view of the key/value store behind every memory, session, retention score, audit row, and access log. Edit JSON in place.",
bullets: [
"SCOPED NAMESPACES · mem:memories / mem:sessions / mem:retention",
"JSON-NATIVE EDIT · NO MIGRATIONS",
"AUDIT ROW PER CHANGE · FORENSIC TRAIL",
"BACKED BY iii STATE ADAPTERS · IN-MEMORY OR FILE-BASED",
],
img: "/states.png",
alt: "iii console state browser",
launch: "open http://localhost:3114/states",
},
traces: {
title: "OPENTELEMETRY OUT OF THE BOX",
blurb:
"iii-observability ships with exporter: memory, sampling_ratio: 1.0. Every memory operation emits a trace span + structured log. Swap to OTLP for Jaeger / Honeycomb / Tempo.",
bullets: [
"WATERFALL · FLAME · SERVICE BREAKDOWN · TRACE MAP",
"FILTER BY TRACE ID · SERVICE · DURATION",
"MEMORY SEARCH SPAN TREE · BM25 → VECTOR → GRAPH → RERANK",
"SWAP EXPORTER TO OTLP FOR PROD TELEMETRY",
],
img: "/traces-waterfall.png",
alt: "iii console traces waterfall",
launch: "open http://localhost:3114/traces",
},
};
export function CommandCenter() {
const [tab, setTab] = useState<Tab>("viewer");
const panel = PANELS[tab];
return (
<section
className={styles.wrap}
id="command-center"
aria-labelledby="cc-title"
>
<header className="section-head">
<span className="section-eyebrow">COMMAND CENTER</span>
<h2 id="cc-title" className="section-title">
TWO UIs.<br />ONE MEMORY RUNTIME.
</h2>
<p className="section-lede">
AGENTMEMORY SHIPS A REAL-TIME VIEWER FOR YOUR MEMORIES AND AN
ENGINE-LEVEL CONSOLE FOR EVERY FUNCTION, TRIGGER, AND OTEL SPAN.
BOTH ARE FIRST-CLASS — INSTALLED INLINE BY THE CLI ON FIRST RUN.
</p>
</header>
<div className={styles.tabs} role="tablist" aria-label="Command center">
{TABS.map((t) => (
<button
key={t.id}
role="tab"
aria-selected={tab === t.id}
className={`${styles.tab} ${tab === t.id ? styles.tabActive : ""}`}
onClick={() => setTab(t.id)}
>
<span className={styles.tabLabel}>{t.label}</span>
<span className={styles.tabSub}>{t.sub}</span>
</button>
))}
</div>
<div className={styles.panel}>
<div className={styles.panelText}>
<h3 className={styles.panelTitle}>{panel.title}</h3>
<p className={styles.panelBlurb}>{panel.blurb}</p>
<ul className={styles.panelBullets}>
{panel.bullets.map((b) => (
<li key={b}>
<span aria-hidden>›</span>
{b}
</li>
))}
</ul>
<pre className={styles.launch}>
<code>
<span className={styles.launchPrompt}>$</span> {panel.launch}
</code>
</pre>
</div>
<div className={styles.panelFrame}>
<div className={styles.frameChrome}>
<span className={`${styles.dot} ${styles.red}`} />
<span className={`${styles.dot} ${styles.yellow}`} />
<span className={`${styles.dot} ${styles.green}`} />
<span className={styles.frameTitle}>{panel.title}</span>
</div>
<div className={styles.frameShot}>
<Image
src={panel.img}
alt={panel.alt}
width={1600}
height={1000}
unoptimized={panel.img.endsWith(".gif")}
priority={false}
style={{ width: "100%", height: "auto", display: "block" }}
/>
</div>
</div>
</div>
</section>
);
}