'use client'; // Mira Wiki 索引頁 // SDD: polaris/mira/.agents/specs/mira-app/design.md §5.2 + §3.5.10 // 對應 task: 7C.1 // 階段 7-A 已建:mira-wiki-schema、mira-wiki-index(+4 children)、mira-wiki-log(+1 child) // 此頁列出這些 infra block 與既有 wiki-page,方便 leo 在瀏覽器確認 schema 寫得對不對 import { useEffect, useMemo, useState } from 'react'; import Link from 'next/link'; import '../mira.css'; const KBDB_BASE = 'https://kbdb.finally.click'; const API_BASE = process.env.NEXT_PUBLIC_API_BASE ?? 'https://cypher.arcrun.dev'; type Block = { id: string; page_name: string; content: string; type: string; parent_id: string | null; tags_json: string | null; created_at: number; }; export default function WikiIndexPage() { const [schema, setSchema] = useState(null); const [indexChildren, setIndexChildren] = useState([]); const [logEntries, setLogEntries] = useState([]); const [otherWikiPages, setOtherWikiPages] = useState([]); const [indexEntries, setIndexEntries] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); useEffect(() => { let cancelled = false; async function load() { try { // 先拿 ak_ partner key(同 page.tsx pattern) const meRes = await fetch(`${API_BASE}/me`, { credentials: 'include' }); if (!meRes.ok) throw new Error('未登入'); const me = (await meRes.json()) as { api_key: string }; const headers = { Authorization: `Bearer ${me.api_key}` }; // 撈所有 type=wiki-page,再 client 端過濾 tags 含 'mira-wiki' // 原本 ?tag=mira-wiki 撞 KBDB worker D1 bug(malformed JSON),改 type filter // 待 KBDB 修 tag filter 後可改回(SDD 待開 kbdb-tag-filter-fix) const res = await fetch( `${KBDB_BASE}/blocks?type=wiki-page&limit=200`, { headers }, ); if (!res.ok) throw new Error(`KBDB ${res.status}`); const data = await res.json(); if (cancelled) return; const allWikiBlocks: Block[] = data.blocks ?? []; // Client 端過濾:只留 tags 含 'mira-wiki' const blocks: Block[] = allWikiBlocks.filter((b) => { if (!b.tags_json) return false; try { const tags = JSON.parse(b.tags_json) as string[]; return tags.includes('mira-wiki'); } catch { return false; } }); const tagsOf = (b: Block): string[] => { if (!b.tags_json) return []; try { return JSON.parse(b.tags_json) as string[]; } catch { return []; } }; const hasSubtype = (b: Block, st: string) => tagsOf(b).includes(`subtype:${st}`); const hasAnyInfraSubtype = (b: Block) => ['schema', 'index', 'index-child', 'log', 'log-child'].some((st) => hasSubtype(b, st)); const hasMetaTag = (b: Block) => tagsOf(b).some((t) => t === 'data-source-config' || t === 'source-skill'); setSchema(blocks.find((b) => hasSubtype(b, 'schema')) ?? null); setIndexChildren( blocks .filter((b) => hasSubtype(b, 'index-child')) .sort((a, b) => a.page_name.localeCompare(b.page_name)), ); setLogEntries( blocks .filter((b) => hasSubtype(b, 'log-child')) .sort((a, b) => b.page_name.localeCompare(a.page_name)), ); // 真正的 wiki-page paragraphs(排除 infra 跟 meta 配置) setOtherWikiPages( blocks .filter((b) => !hasAnyInfraSubtype(b) && !hasMetaTag(b)) .sort((a, b) => (b.created_at ?? 0) - (a.created_at ?? 0)), ); // 平行撈 index-entry blocks(per-entity 摘要,CC navigation entry point) // 對應 design.md §3.5.12.4.1 / 7B.3f const idxRes = await fetch( `${KBDB_BASE}/blocks?type=index-entry&limit=200`, { headers }, ); if (idxRes.ok) { const idxData = await idxRes.json(); if (!cancelled) { const idxBlocks: Block[] = idxData.blocks ?? []; setIndexEntries( idxBlocks.sort((a, b) => (a.page_name ?? '').localeCompare(b.page_name ?? '')), ); } } } catch (e: any) { if (!cancelled) setError(e?.message ?? 'load failed'); } finally { if (!cancelled) setLoading(false); } } load(); return () => { cancelled = true; }; }, []); // Dedupe wiki-pages by entity(content)— 累積式設計每個 raw 各建一個 wiki-page, // 同 entity 多版只在 listing 顯示最新一張卡 + 版本數提示 const dedupedWikiPages = useMemo(() => { const groups = new Map(); for (const p of otherWikiPages) { const entity = (p.content || '').trim() || p.page_name || '?'; const existing = groups.get(entity); if (!existing) { groups.set(entity, { entity, latest: p, versionCount: 1 }); } else { existing.versionCount++; if ((p.created_at ?? 0) > (existing.latest.created_at ?? 0)) { existing.latest = p; } } } return Array.from(groups.values()).sort( (a, b) => (b.latest.created_at ?? 0) - (a.latest.created_at ?? 0), ); }, [otherWikiPages]); return (
← Mira 首頁

📚 Mira Wiki

leo 的個人觀點累積(Karpathy LLM Wiki 風格)

{loading &&
載入中⋯
} {error && (
讀取失敗:{error}
)} {!loading && !error && ( <>
{schema ? ( ) : ( 尚未建立 schema )}
{indexChildren.length > 0 ? (
{indexChildren.map((b) => { const tags = b.tags_json ? (JSON.parse(b.tags_json) as string[]) : []; const key = tags.find((t) => t.startsWith('index-key:'))?.replace('index-key:', '') ?? '?'; return ( ); })}
) : ( index children 尚未建立 )}
{indexEntries.length > 0 ? (
{indexEntries.map((b) => { const entity = (b.page_name ?? '').replace(/^index-/, ''); const firstLine = firstLineOf(b.content) .replace(/^#+\s*/, '') .slice(0, 80); return ( ); })}
) : ( 尚未有 index-entry(wiki_synthesis 跑完後自動建) )}
{logEntries.length > 0 ? (
{logEntries.map((b) => ( ))}
) : ( 尚未有 log )}
{dedupedWikiPages.length > 0 ? (
{dedupedWikiPages.map((g) => ( 1 ? `${g.versionCount} 版累積 ・ 最新 ${new Date((g.latest.created_at ?? 0) * 1000).toLocaleString('zh-TW')}` : `建立 ${new Date((g.latest.created_at ?? 0) * 1000).toLocaleString('zh-TW')}` } /> ))}
) : ( 尚未有 wiki page(待 7-B ai-canon-wiki workflow 跑出第一張) )}
)}
); } function Section({ title, children }: { title: string; children: React.ReactNode }) { return (

{title}

{children}
); } function Empty({ children }: { children: React.ReactNode }) { return (
{children}
); } function WikiCardLink({ page_name, title, excerpt, }: { page_name: string; title: string; excerpt: string; }) { return (
{title}
{excerpt && (
{excerpt}
)} ); } function iconForKey(key: string): string { return ( { entities: '🧩', topics: '📂', sources: '🔗', stale: '⚠️', }[key] ?? '•' ); } function firstLineOf(content: string): string { if (!content) return ''; const firstNonHeader = content .split('\n') .map((l) => l.trim()) .find((l) => l && !l.startsWith('#') && !l.startsWith('>')); return firstNonHeader ?? ''; }