feat(nav): ⌘K page-jump + NL layer + agent-commerce worker fetcher - #3195
Open
0motionguy wants to merge 14 commits into
Open
0motionguy wants to merge 14 commits into
0motionguy wants to merge 14 commits into
Conversation
The Topbar ⌘K search already found repos + LLMs; it could not jump to pages. Adds an instant, client-side 'Pages' section to the existing search dropdown (src/lib/nav-commands.ts registry + matcher), so ⌘K + 'watch'/'funding'/'compare' surfaces the destination alongside repo hits. - Additive: repo/LLM search path untouched; PageRow reuses the exact .search-row markup so it reads native. - Pages rank first (instant, deterministic), then repos, then LLMs; keyboard activeIdx + navigateToHit extended for the page kind. Verified on live branch (hardening/2026-05-31-wave @ 8e7fe20): typecheck clean, dev server, Playwright — Pages section renders, Enter/click routes to /tools/watchlist, 0 console errors. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…e live plane /agent-commerce was fed only by cron-agent-commerce.yml (GH-Actions), which has failed since 2026-05-31. On the worker-owned prod plane nothing wrote the 'agent-commerce' slug, so the page served the deploy-baked seed frozen at build time. Redis probe confirmed ss:meta:v1:agent-commerce empty. Adds a worker fetcher that re-runs the seed assembly (scoring mirrors scripts/build-agent-commerce-seed.mjs) and publishes a fresh 'agent-commerce' payload daily (41 4 * * *) with an empty-guard. Breaks the deploy-freeze. v1: seed re-score + fresh timestamp. v2 (tracked): port the onchain x402 / CoinGecko / agentic.market source fetchers to the worker for live enrichment. Verification: TS-clean (my files produce zero errors; worker external-dep errors are pre-existing missing node_modules in the worktree). Runtime (fresh Redis write) needs a worker image build + deploy. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Deterministic NL: strips leading intent verbs ('show me', 'go to',
'take me to'), articles, and trailing 'page/tab/view' before matching,
so plain-English queries resolve. Adds homepage category views
(Agents/LLMs/Models/Gainers/Discovery via ?cat=) as jump targets.
Verified (Playwright, live worktree):
- 'show me agents' -> Agents (?cat=agents) + Agent Commerce
- 'go to the funding page'-> Funding
- 0 console errors, native styling (screenshot nav-n1-nl.png)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…gates The wow the ⌘K tier was only plumbing for: a persistent docked assistant (bottom-right, terminal-styled, Liquid Lava) you ASK in natural language or by voice, and it replies + executes against the nav-command registry. - Voice: Web Speech API, feature-detected (mic renders only where supported). - Deterministic execution today (instant, no LLM); LLM fall-through for multi-step requests is the next tier via /api/navigator (worker Kimi/NanoGPT key exists on the box). - Mounted deferred via IdleMount; native shell.css design vars. Verified (Playwright, live worktree): launcher renders -> panel opens with greeting + quick chips + mic; typed 'take me to funding' -> agent navigated to /funding (title 'Funding Radar'); 0 console errors. Screenshot ask-dock-open.png. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Per direction: kill the corner chat panel. A floating, DRAGGABLE, horizontal
liquid-glass command bar — frosted/translucent, minimal color, compact, drifts
anywhere and persists position. You type/speak; the agent navigates. No
transcript — a single ephemeral status flashes, then you're there.
Design (impeccable lens; glass is purposeful here = a HUD over live content, the
canonical justified case, not a decorative card; restrained color per '≤10%
accent'; ease-out-expo motion + reduced-motion fallback; position:fixed escapes
stacking context; DNA: HyperLiquid precision × Meteora liquid unfurl):
- glass: rgba(12,14,17,0.55) + backdrop-blur(24px) saturate(150%), 1px white/8
border, inset top-edge light refraction; accent only on caret + focus glow.
- collapsed 42px node ↔ 420x46 bar, radius morphs 999px->14px (fluid unfurl).
- drag via pointer events on grip/node, viewport-clamped, saved to localStorage.
Verified (Playwright, live worktree):
- collapsed node: backdrop-filter blur(24px) saturate(1.5), bg rgba(12,14,17,.55), r999px
- expands to 420x46 glass bar (r14px); 'revenue' -> navigated /revenue
- real mouse-drag on grip moved it 211px/282px and persisted {left,top} to localStorage
- 0 console errors; screenshots ask-glass-bar.png + ask-glass-dragged.png
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…rag, send+voice Per direction: more visible + orange glow borders + bigger + no X (send & voice icons instead) + drag the whole body, not one tiny grip. - brighter: bg rgba(17,20,25,0.74) (was .55); top refraction .11; input 14px, brighter placeholder. - orange glow border: border rgba(255,107,53,0.34) at rest -> 0.55 focused; box-shadow orange bloom. - bigger: node 48px; bar 500x56 (was 420x46), radius 16. - whole body draggable: pointer handlers on the bar (guard skips input/buttons); grip removed; cursor grab->grabbing. - send button (ArrowRight, submit) + voice (Radio); X close removed (Esc still collapses). Verified (Playwright): bar 500x56, border rgba(255,107,53,0.55), bg rgba(17,20,25,0.74), cursor grab, buttons [Speak, Send] (no close); body-drag from caret moved it; 0 errors; screenshot ask-glass-v2.png (bright orange-glowing bar over live content). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…igator)
The final tier. When the deterministic matcher misses, the bar falls through to
POST /api/navigator: a small model maps free text ('get me that claude repo',
'where do people discuss funding') to ONE navigation action against the same
route registry, with an ephemeral 'Thinking…' -> result status. No chat log.
Security: the model's href is hard-validated to an internal path (safeInternalHref)
before it reaches the client — a prompt-injected external URL can't become an open
redirect. Zod-validated, per-IP rate-limited (20/min), provider-flexible
(NanoGPT -> OpenRouter -> Kimi, OpenAI-compatible), graceful NOT_CONFIGURED when no
key so the client keeps deterministic-only behaviour.
Verified (curl + Playwright, live worktree):
- POST valid q, no local key -> {ok:false, NOT_CONFIGURED} HTTP 200 (graceful)
- bad body / malformed JSON -> {ok:false, BAD_REQUEST} HTTP 400
- client: deterministic 'breakout' -> /breakout (flash '→ Opening Breakout');
miss 'zzqx nonsense' -> fires /api/navigator, shows fallback. 0 console errors.
- Full LLM behaviour needs a key in the app env on the box (worker has Kimi/NanoGPT).
All tiers now live in the bar: page-jump, NL, voice, LLM router.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ation
Per direction: the agent should welcome the user and let them TALK to it, not
only route. Now it does both.
- Greeting on open: a warm welcome appears in a readable glass answer panel
above the bar (the agent talks first).
- Q&A: /api/navigator becomes an assistant returning {reply, answer?, action}.
Ask a question -> a 1-3 sentence answer in the answer panel; it can also
navigate. Deterministic 'help/what can you do/hi' answers work with no LLM key.
- Answer panel: same liquid-glass aesthetic, one message (a reply, not a
transcript), dismissable; nav commands clear it and route.
Verified (Playwright, live worktree):
- open -> greeting 'Hey, I'm your trendingrepo agent…' in the answer panel
- 'what can you do' -> help answer rendered (screenshot ask-conversational.png)
- 'funding' -> flash '→Opening Funding', greeting cleared, navigated /funding
- endpoint returns {answer?} shape; graceful NOT_CONFIGURED without key; 0 errors
- Full LLM Q&A needs a key in the app env on the box.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ows, flowing orange border Per correction: the answer opened to the TOP; it should open to the BOTTOM, inside the box. The bar is now a column container that expands DOWNWARD to hold the conversation, capped at ~5 rows then scroll, with an animated flowing orange border. - input row on top; .ask-body opens downward below it (was a floating panel above). - box grows to fit content, max-height 240px (~5 rows), overflow-y scroll. - flowing orange border: conic-gradient arc travels the edge (@Property --ask-spin, masked border ring) while the box holds a conversation; reduced-motion disables it. - greeting + Q&A + nav status all render inside the body now (nothing floats above). Verified (Playwright): bodyBelowInput=true (downward), box grew to 119px, body max-height 240px, box.::after animation=ask-spin (flowing border), greeting inside box; 0 console errors; screenshot ask-box-downward.png. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Per direction: messages were pinned/static; they should TYPE out so the user sees the agent typing, then the next message. And the greeting should be a CTA. - Typewriter component types each message char-by-char (10-15ms/char, faster for long ones) with a blinking accent caret that clears when done. Restarts when the message changes, so the next answer types itself out. Instant under prefers-reduced-motion. - Greeting is now a CTA: 'Hey. Tell me what you're looking for and I'll take you right there. A repo, funding, trending agents, or just ask.' Verified (Playwright): greeting types progressively (13 -> 60 -> 113 chars), .ask-type-caret present while typing and gone when done, CTA text correct; 0 console errors. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… + chitchat Bug: 'how are you' (and any question that missed the shortcut or hit the LLM with no key) showed a transient status that vanished after ~1.8s — the user's 'thinking then nothing'. - Every miss now lands as a PERSISTENT typed answer (setAnswer), never a status that disappears. So there's always a response. - Broader conversational replies with no LLM key: greetings/'how are you'/'what's up' -> warm reply; 'thanks' -> ack; help/'who are you' -> capabilities. - Client fetch timeout (12s) so 'Thinking…' can never stick forever. Verified (Playwright): 'how are you' -> persistent 'Doing great, thanks…' (survives past the old 1.8s window); 'what is the meaning of life' -> persistent typed 'I couldn't map that to a page yet…' (stable across 6 samples, doesn't vanish). The lone console error is a pre-existing RepoSparkline hydration mismatch, not this code. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…acklog Clean pick-up doc: what's live on the box, what's built+verified on PR #3195 (the Ask agent, ⌘K, agent-commerce fetcher), what's blocked on Mirko (deploy, LLM key, Slack webhook), the deploy runbook, and the remaining plan/audit backlog. Leads with the branch trap (live = hardening, not main). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Three additive features on the live line (hardening @ 8e7fe20):
Topbar.tsx+nav-commands.ts) — the global search now jumps to any page, not just repos/LLMs. Reuses the exact.search-rowmarkup.Verification
🤖 Generated with Claude Code