feat: KBDB-graph 插件獨立 — 全面改寫成走基本盤 API(API-as-Wall)

按 leo 鐵律(2026-06-14)把插件從「直接 SQL 操作基本盤表」改寫成
「只透過基本盤 arcrun/kbdb HTTP API 讀寫」。零建表、零 migration、零 SQL。

- 新增 src/lib/kbdb-client.ts:唯一對外通道,封裝 entries/templates/records API
- 新增 src/lib/templates.ts:triplet/entity template 定義(替代建表)
- 改寫 21 個違規 action(triplet/graph/entity/search)→ 走 client,圖在插件層記憶體組裝
- 移除所有 migrations、D1/Vectorize/AI 綁定;embedding/語意搜尋歸基本盤 optional 模組
- index.ts 只掛 triplets/graph/entities/search 路由;基本盤路由歸 arcrun/kbdb
- 測試改走 mock client(純 node);裁剪 CLAUDE.md 只留 graph 插件 + 鐵律
- 修正 SDD design.md「讀現狀推翻鐵律」的錯誤判斷(共用 D1 → API-as-Wall)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-14 20:59:41 +08:00
commit efe8e165cf
62 changed files with 7671 additions and 0 deletions
+41
View File
@@ -0,0 +1,41 @@
// Triplet 統計 action — 知識圖譜規模統計
// 零 SQL / 零 D1:取全部 triplet record(走基本盤 API),在記憶體 reduce 出統計。
// GET /triplets/stats
import type { KbdbClient } from '../lib/kbdb-client';
import { queryTriplets } from './triplet-crud';
export interface TripletStats {
total: number;
// 保留 by_owner_id(原 by_user_id 改名,對齊基本盤 owner_id 欄位)。
// 注:基本盤 record 不回傳 owner_id / 時間戳,故 by_owner_id/recent 在純插件層無法填,
// 待 [→arcrun] base 於 record 回應帶上 owner_id + created_at 後補。
by_owner_id: Record<string, number>;
recent: { today: number; this_week: number };
top_subjects: { subject: string; count: number }[];
top_predicates: { predicate: string; count: number }[];
}
export async function getTripletStats(client: KbdbClient): Promise<TripletStats> {
const { triplets } = await queryTriplets(client, { limit: 2000 });
const subjectCounts = new Map<string, number>();
const predicateCounts = new Map<string, number>();
const ownerCounts: Record<string, number> = {};
for (const t of triplets) {
subjectCounts.set(t.subject, (subjectCounts.get(t.subject) ?? 0) + 1);
predicateCounts.set(t.predicate, (predicateCounts.get(t.predicate) ?? 0) + 1);
}
const top = (m: Map<string, number>) =>
[...m.entries()].sort((a, b) => b[1] - a[1]).slice(0, 10);
return {
total: triplets.length,
by_owner_id: ownerCounts, // base record 暫無 owner_id,待上游補
recent: { today: 0, this_week: 0 }, // base record 暫無 created_at,待上游補
top_subjects: top(subjectCounts).map(([subject, count]) => ({ subject, count })),
top_predicates: top(predicateCounts).map(([predicate, count]) => ({ predicate, count })),
};
}