fix(ui): update AMCS references and add status handling

* Corrected "Advanced Module Control System" to "Avalon Memory Control Service" in documentation and UI components.
* Added status handling to the LoginInfoPanel and LoginPage components.
* Implemented new endpoints for robots.txt and llms.txt.
This commit is contained in:
2026-04-27 00:04:08 +02:00
parent b17241b928
commit a4193b295a
11 changed files with 427 additions and 34 deletions

View File

@@ -153,9 +153,7 @@
await GlobalStateStore.getState().fetchData();
if (GlobalStateStore.getState().isLoggedIn()) {
await loadStatus();
}
await loadStatus();
});
</script>
@@ -171,6 +169,9 @@
{authBusy}
{authError}
{authMessage}
statusData={data}
statusLoading={loading}
statusError={error}
onlogin={handleCredentialLogin}
/>
{:else}

View File

@@ -1,34 +1,226 @@
<script lang="ts">
const { isOAuthCallback }: { isOAuthCallback: boolean } = $props();
import type { StatusResponse } from "../../types";
type IntelligenceCard = {
id: string;
title: string;
accentClass: string;
summary: string;
detail: string;
tools: string[];
};
const {
isOAuthCallback,
data,
loading,
error,
}: {
isOAuthCallback: boolean;
data: StatusResponse | null;
loading: boolean;
error: string;
} = $props();
const intelligenceCards: IntelligenceCard[] = [
{
id: "projects",
title: "Projects",
accentClass: "text-indigo-200",
summary:
"Named containers that scope memory and operations so retrieval stays focused on the right workstream.",
detail:
"Project context can be resolved explicitly or from active session scope depending on client behavior.",
tools: ["list_projects", "create_project", "get_project_context"],
},
{
id: "thoughts",
title: "Thoughts",
accentClass: "text-violet-200",
summary:
"Core memory records with metadata and links that power search, recall, summaries, and relationship traversal.",
detail:
"Thought capture can include metadata enrichment and link-based navigation for richer retrieval.",
tools: ["capture_thought", "search_thoughts", "related_thoughts"],
},
{
id: "skills",
title: "Skills",
accentClass: "text-cyan-200",
summary:
"Reusable agent instructions and capabilities that can be linked to a project and loaded with it.",
detail:
"Use project-linked skills to keep behavior consistent across sessions and assistants.",
tools: ["list_project_skills", "add_skill", "add_project_skill"],
},
{
id: "guardrails",
title: "Guardrails",
accentClass: "text-amber-200",
summary:
"Safety and policy constraints with severity levels that can be enforced globally or per project.",
detail:
"Guardrails provide stable operational boundaries for memory and tool usage behavior.",
tools: [
"list_project_guardrails",
"add_guardrail",
"add_project_guardrail",
],
},
{
id: "learnings",
title: "Learnings",
accentClass: "text-emerald-200",
summary:
"Curated records for durable lessons and decisions, separate from raw thoughts for cleaner review.",
detail:
"Structured fields such as status, priority, and confidence support operational follow-through.",
tools: ["add_learning", "list_learnings", "get_learning"],
},
{
id: "vector-metadata-build",
title: "Vector + Metadata Build",
accentClass: "text-fuchsia-200",
summary:
"Backfill and repair flows for embeddings and metadata so retrieval quality stays healthy over time.",
detail:
"Use dry runs for safe audits, then run updates to regenerate missing vectors or retry failed metadata.",
tools: [
"backfill_embeddings",
"reparse_thought_metadata",
"retry_failed_metadata",
],
},
];
let activeCard = $state("projects");
function setActiveCard(id: string) {
activeCard = id;
}
function handleCardKeydown(event: KeyboardEvent, id: string) {
if (event.key === "Enter" || event.key === " ") {
event.preventDefault();
setActiveCard(id);
}
}
</script>
<div class="rounded-3xl border border-cyan-400/20 bg-slate-900/80 p-8 shadow-2xl shadow-slate-950/40">
<div class="inline-flex items-center gap-2 rounded-full border border-cyan-400/20 bg-cyan-400/10 px-3 py-1 text-sm font-medium text-cyan-200">
<div
class="rounded-3xl border border-cyan-400/20 bg-slate-900/80 p-8 shadow-2xl shadow-slate-950/40"
>
<div
class="inline-flex items-center gap-2 rounded-full border border-cyan-400/20 bg-cyan-400/10 px-3 py-1 text-sm font-medium text-cyan-200"
>
<span class="h-2 w-2 rounded-full bg-emerald-400"></span>
AMCS Control Interface
Avalon Memory Control Service
</div>
<h1 class="mt-6 text-4xl font-semibold tracking-tight text-white">
{#if isOAuthCallback}
Completing login
{:else}
Login
Operator Access
{/if}
</h1>
<p class="mt-3 max-w-2xl text-base leading-7 text-slate-300">
Origin-style operator access for the AMCS admin interface. ResolveSpec OAuth is the front door now,
not the old login shortcut.
AMCS is a Go MCP server for capturing project thoughts, semantic retrieval,
summaries, and linked memory workflows with Postgres + pgvector.
</p>
<p class="mt-2 max-w-2xl text-sm leading-6 text-slate-400">
It stores durable memory for assistants, supports project scoping, and
exposes tools over MCP for capture, search, context recall, and structured
operations.
</p>
<div class="mt-8 grid gap-4 sm:grid-cols-2">
<div class="mt-8 grid gap-4 sm:grid-cols-3">
<div class="rounded-2xl border border-white/10 bg-white/5 p-5">
<p class="text-sm uppercase tracking-[0.2em] text-slate-400">Primary module</p>
<p class="mt-2 text-2xl font-semibold text-white">Projects</p>
<p class="mt-2 text-sm text-slate-400">Projects are the first real admin screen in this rollout.</p>
<p class="text-sm uppercase tracking-[0.2em] text-slate-400">
Server status
</p>
{#if loading}
<p class="mt-2 text-lg font-semibold text-white">Loading…</p>
{:else if error}
<p class="mt-2 text-sm font-medium text-rose-300">Unavailable</p>
<p class="mt-2 text-xs text-rose-200/80">{error}</p>
{:else if data}
<p class="mt-2 text-2xl font-semibold text-white">{data.version}</p>
<p class="mt-2 text-sm text-slate-400">
{data.connected_count} connected in {data.connected_window}
</p>
<a
href="/status"
class="mt-3 inline-flex items-center rounded-lg border border-emerald-300/30 bg-emerald-400/10 px-3 py-1.5 text-xs font-semibold uppercase tracking-[0.12em] text-emerald-100 transition hover:border-emerald-300/50 hover:bg-emerald-400/20"
>
Status Endpoint
</a>
{:else}
<p class="mt-2 text-sm text-slate-400">No status snapshot yet.</p>
{/if}
</div>
<div class="rounded-2xl border border-white/10 bg-white/5 p-5">
<p class="text-sm uppercase tracking-[0.2em] text-slate-400">OAuth path</p>
<p class="mt-2 text-2xl font-semibold text-white">ResolveSpec</p>
<p class="mt-2 text-sm text-slate-400">Client registration, authorize, callback, token exchange.</p>
<p class="text-sm uppercase tracking-[0.2em] text-slate-400">
Memory stack
</p>
<p class="mt-2 text-2xl font-semibold text-white">Postgres + pgvector</p>
<p class="mt-2 text-sm text-slate-400">
Semantic search with full-text fallback when vectors are missing.
</p>
</div>
<div class="rounded-2xl border border-white/10 bg-white/5 p-5">
<p class="text-sm uppercase tracking-[0.2em] text-slate-400">
Operator docs
</p>
<a
href="/llm"
class="mt-2 inline-flex items-center rounded-lg border border-cyan-300/30 bg-cyan-400/10 px-3 py-2 text-sm font-semibold text-cyan-100 transition hover:border-cyan-300/50 hover:bg-cyan-400/20"
>
Open LLM Instructions
</a>
<p class="mt-2 text-sm text-slate-400">
Tool behavior, workflows, and MCP guidance for assistants.
</p>
</div>
</div>
<div class="mt-6 rounded-2xl border border-white/10 bg-slate-950/35 p-5">
<h2 class="text-lg font-semibold text-white">Project intelligence model</h2>
<p class="mt-2 text-sm text-slate-400">
AMCS separates reusable behavior, safety constraints, and curated
knowledge so assistants can be guided consistently across sessions.
</p>
<div class="mt-4 grid gap-4 md:grid-cols-2 xl:grid-cols-3">
{#each intelligenceCards as card}
<article
class={`rounded-xl border p-4 transition ${
activeCard === card.id
? "border-cyan-300/40 bg-cyan-400/[0.08] shadow-lg shadow-cyan-950/30"
: "border-white/10 bg-white/[0.03] hover:border-white/20 hover:bg-white/[0.05]"
}`}
role="button"
tabindex="0"
aria-pressed={activeCard === card.id}
onclick={() => setActiveCard(card.id)}
onkeydown={(event) => handleCardKeydown(event, card.id)}
>
<p class={`text-xs uppercase tracking-[0.16em] ${card.accentClass}`}>
{card.title}
</p>
<p class="mt-2 text-sm text-slate-300">{card.summary}</p>
{#if activeCard === card.id}
<p class="mt-2 text-xs text-slate-300/90">{card.detail}</p>
{/if}
<p class="mt-3 text-xs text-slate-400">
Tools:
{#each card.tools as tool, idx}
<code class="text-slate-200">{tool}</code>{idx <
card.tools.length - 1
? ", "
: ""}
{/each}
</p>
</article>
{/each}
</div>
</div>
</div>

View File

@@ -1,6 +1,7 @@
<script lang="ts">
import LoginInfoPanel from './LoginInfoPanel.svelte';
import LoginPanel from './LoginPanel.svelte';
import type { StatusResponse } from '../../types';
const {
isOAuthCallback,
@@ -8,6 +9,9 @@
authBusy,
authError,
authMessage,
statusData,
statusLoading,
statusError,
onlogin
}: {
isOAuthCallback: boolean;
@@ -15,20 +19,51 @@
authBusy: boolean;
authError: string;
authMessage: string;
statusData: StatusResponse | null;
statusLoading: boolean;
statusError: string;
onlogin: (username: string, password: string) => void;
} = $props();
</script>
<main class="mx-auto flex min-h-screen max-w-6xl items-center px-4 py-10 sm:px-6 lg:px-8">
<section class="grid w-full gap-8 lg:grid-cols-[1.15fr_0.85fr]">
<LoginInfoPanel {isOAuthCallback} />
<LoginPanel
{isOAuthCallback}
{callbackBusy}
{authBusy}
{authError}
{authMessage}
{onlogin}
/>
<main class="mx-auto min-h-screen w-full max-w-6xl px-4 py-8 sm:px-6 lg:px-8">
<section class="flex min-h-[calc(100vh-4rem)] flex-col gap-8">
<LoginInfoPanel {isOAuthCallback} data={statusData} loading={statusLoading} error={statusError} />
<div class="mt-auto">
<LoginPanel
{isOAuthCallback}
{callbackBusy}
{authBusy}
{authError}
{authMessage}
{onlogin}
/>
</div>
<div class="mt-3 flex flex-wrap items-center justify-center gap-3 text-xs text-slate-400">
<a
href="/llms.txt"
class="inline-flex items-center rounded-md border border-white/10 bg-white/[0.03] px-2.5 py-1.5 transition hover:border-cyan-300/40 hover:text-cyan-100"
>
llms.txt
</a>
<a
href="/robots.txt"
class="inline-flex items-center rounded-md border border-white/10 bg-white/[0.03] px-2.5 py-1.5 transition hover:border-cyan-300/40 hover:text-cyan-100"
>
robots.txt
</a>
<a
href="/.well-known/oauth-authorization-server"
class="inline-flex items-center rounded-md border border-white/10 bg-white/[0.03] px-2.5 py-1.5 transition hover:border-cyan-300/40 hover:text-cyan-100"
>
OAuth Discovery
</a>
<a
href="/llm"
class="inline-flex items-center rounded-md border border-white/10 bg-white/[0.03] px-2.5 py-1.5 transition hover:border-cyan-300/40 hover:text-cyan-100"
>
LLM Docs
</a>
</div>
</section>
</main>

View File

@@ -28,7 +28,7 @@
{#if isOAuthCallback}
<h2 class="text-xl font-semibold text-white">Authorizing operator session</h2>
<p class="mt-2 text-sm leading-6 text-slate-400">
Finishing the ResolveSpec handshake and exchanging the returned code for an AMCS token.
Finishing the callback flow and exchanging the returned code for an AMCS token.
</p>
<div class="mt-6 rounded-2xl border border-cyan-400/20 bg-cyan-400/5 px-4 py-6 text-sm text-cyan-100">
@@ -42,7 +42,7 @@
</div>
{:else}
<h2 class="text-xl font-semibold text-white">Operator login</h2>
<p class="mt-1 text-sm text-slate-400">Authenticate with your ResolveSpec credentials.</p>
<p class="mt-1 text-sm text-slate-400">Authenticate to access the AMCS admin interface.</p>
<form class="mt-6 space-y-4" onsubmit={handleSubmit}>
<div>