mirror of
https://github.com/0xWheatyz/handler.git
synced 2026-08-30 07:26:25 +00:00
dc80e7bc28
The distilled knowledge layer over the raw log/transcript history, inspired by TencentDB-Agent-Memory's memory-hub model, adapted to handler's invariants (state lives only in the database; workers stay stateless and disposable): - memory_notes + memory_links tables (migration 0014) with a portable DAL: scoped listing/search (project + global), idempotent linking, and a one-read graph. Deleting an agent nulls attribution but keeps its notes; deleting a project removes its notes and edges, leaving global knowledge intact. - /memory API routes: reads on the normal token, note/link authoring on the admin token, plus GET /memory/graph for the dashboard. - Bundled handler-memory MCP server (python -m handler.mcpserver), a dependency-free stdio JSON-RPC implementation injected into every launch's --mcp-config ahead of the DB connectors and allowlisted in generated settings, exposing memory_search / memory_get / memory_save / memory_link. Identity and DATABASE_URL arrive via the spawn env, same as hooks. - SessionStart recall hook: injects the most recent notes in scope as additional context at session start, best-effort, never blocking. - Memory page in the web UI: a hand-rolled force-directed SVG graph of the note web (colored by kind, hover highlights, click-through details), plus note/link authoring — the app's first visualization, no chart dependency. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WYqkoYPX8NAo1V2KyXr1pk
34 lines
1.5 KiB
TypeScript
34 lines
1.5 KiB
TypeScript
/* The left-nav map: one entry per section, each its own route/page. This is the single
|
|
* source of truth shared by the sidebar (which renders the links) and the auth frame
|
|
* (which seeds the store's active section from the URL on first load). Runs is the root. */
|
|
import type { Section } from "@/components/store";
|
|
|
|
export interface NavRoute {
|
|
key: Section;
|
|
href: string;
|
|
label: string;
|
|
}
|
|
|
|
export const NAV_ROUTES: NavRoute[] = [
|
|
{ key: "runs", href: "/", label: "Runs" },
|
|
{ key: "repositories", href: "/repositories", label: "Repositories" },
|
|
{ key: "agents", href: "/agents", label: "Agents" },
|
|
{ key: "schedules", href: "/schedules", label: "Schedules" },
|
|
{ key: "approvals", href: "/approvals", label: "Approvals" },
|
|
{ key: "servers", href: "/servers", label: "Git Servers" },
|
|
{ key: "activity", href: "/activity", label: "Activity" },
|
|
{ key: "shared", href: "/shared", label: "Shared" },
|
|
{ key: "memory", href: "/memory", label: "Memory" },
|
|
{ key: "claude", href: "/claude", label: "Claude" },
|
|
];
|
|
|
|
/* Map a browser path back to its section key. Trailing slashes (Next emits them under
|
|
* `trailingSlash: true`) are normalized away; anything unrecognized falls back to Runs.
|
|
* "/login" still maps to the Claude page — the login flow moved into it, and the old
|
|
* route redirects there. */
|
|
export function sectionFromPath(pathname: string): Section {
|
|
const clean = pathname.replace(/\/+$/, "") || "/";
|
|
if (clean === "/login") return "claude";
|
|
return NAV_ROUTES.find((r) => r.href === clean)?.key ?? "runs";
|
|
}
|