feat(arcrun): mira wiki page with tag filter + accumulated WIP

- landing/app/mira/wiki: tag=mira-wiki list now shows all wiki paragraphs
  (depends on KBDB tag filter exposed in matrix/kbdb commit, separate repo)
- landing: app/mira hub + feed split + various WIP from prior sessions
- registry/components: claude_api / kbdb_create_block / kbdb_get / km_writer /
  platform_crypto / auth_oauth2 contracts + main.go (accumulated)
- .component-builds: pkg-lock updates + index.ts adjustments (WIP)
- .agents/specs/arcrun/frontend-redesign: design notes
- docs/test_credentials, docs/user_requirements/arcrun-landing-page: WIP docs
- cypher-executor: auth-dispatcher / wasi-shim adjustments (WIP)

Includes accumulated work from prior sessions plus the wiki UI tag-filter
update that surfaces the AI-generated wiki paragraphs at /mira/wiki.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-07 16:52:01 +08:00
parent e8fca33f80
commit 519423cb0d
127 changed files with 23909 additions and 264 deletions
+87
View File
@@ -0,0 +1,87 @@
'use client';
// Mira 子應用 layout
// SDD: polaris/mira/.agents/specs/mira-app/design.md §5.5
// 規範:白名單 user 進得去;非白名單 user 看到「即將開放」頁
// middleware 已做未登入跳 /loginredirect=/mira 檢查(不在這裡重做)
import { useEffect, useState } from 'react';
import SiteNav from '../components/SiteNav';
import { MATRIX_APPS } from '../components/apps';
const API_BASE = process.env.NEXT_PUBLIC_API_BASE ?? 'https://cypher.arcrun.dev';
type Me = { email: string; display_name: string; api_key: string };
const MIRA = MATRIX_APPS.find(a => a.id === 'mira');
const ALLOWED = new Set(MIRA?.allowlist_emails ?? []);
export default function MiraLayout({ children }: { children: React.ReactNode }) {
const [me, setMe] = useState<Me | null | undefined>(undefined);
useEffect(() => {
fetch(`${API_BASE}/me`, { credentials: 'include' })
.then(r => r.ok ? r.json() as Promise<Me> : null)
.then(u => setMe(u))
.catch(() => setMe(null));
}, []);
if (me === undefined) {
return (
<>
<SiteNav currentPath="/mira" />
<div className="flex-1 flex items-center justify-center text-[#666]"></div>
</>
);
}
if (me === null) {
// 理論上 middleware 已擋住,但保險
if (typeof window !== 'undefined') {
window.location.href = '/login?redirect=/mira';
}
return null;
}
if (!ALLOWED.has(me.email)) {
return (
<>
<SiteNav currentPath="/mira" />
<BetaBlocked email={me.email} />
</>
);
}
return (
<>
<SiteNav currentPath="/mira" />
{children}
</>
);
}
function BetaBlocked({ email }: { email: string }) {
return (
<main className="flex-1 flex items-center justify-center px-6">
<div className="max-w-md text-center space-y-4">
<div className="text-6xl mb-2">🌊</div>
<h1 className="text-3xl font-bold text-white">Mira </h1>
<p className="text-[#888] leading-relaxed">
Mira arcrun KM
</p>
<p className="text-sm text-[#555]">
<span className="font-mono text-[#888]">{email}</span>
</p>
<div className="pt-4">
<a
href="/dashboard"
className="inline-block bg-indigo-600 hover:bg-indigo-500 text-white px-5 py-2 rounded-md text-sm font-medium transition-colors"
>
Dashboard
</a>
</div>
</div>
</main>
);
}