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
+49
View File
@@ -0,0 +1,49 @@
// 圖遍歷路由入口
// 僅驗證參數,呼叫 actionsactions 走基本盤 API,圖在插件層組裝)
import { Hono } from 'hono';
import type { Bindings } from '../types';
import { traverseGraph, queryRelation } from '../actions/graph-traverse';
import { getNodeEdges, getNeighbors } from '../actions/graph-nodes';
import { findShortestPath } from '../actions/graph-path';
import { makeKbdbClient } from '../lib/kbdb-client';
const graphRoutes = new Hono<{ Bindings: Bindings }>();
graphRoutes.get('/traverse', async (c) => {
const start = c.req.query('start');
if (!start) return c.json({ error: 'start parameter required' }, 400);
const depth = Number(c.req.query('depth') ?? 2);
const results = await traverseGraph(makeKbdbClient(c.env), start, depth);
return c.json({ start, depth, nodes: results, nodeCount: results.length });
});
graphRoutes.get('/relation', async (c) => {
const from = c.req.query('from');
const to = c.req.query('to');
if (!from || !to) return c.json({ error: 'from and to parameters required' }, 400);
const relations = await queryRelation(makeKbdbClient(c.env), from, to);
return c.json({ from, to, relations, count: relations.length });
});
// GET /graph/neighbors/:name — 合併原 nodes/:name 的 edges + neighbors
graphRoutes.get('/neighbors/:name', async (c) => {
const name = decodeURIComponent(c.req.param('name'));
const client = makeKbdbClient(c.env);
const [edges, neighbors] = await Promise.all([
getNodeEdges(client, name),
getNeighbors(client, name),
]);
return c.json({ node: name, edges, neighbors, edgeCount: edges.length, neighborCount: neighbors.length });
});
// GET /graph/path — 取代 /shortest-path,行為不變
graphRoutes.get('/path', async (c) => {
const from = c.req.query('from');
const to = c.req.query('to');
if (!from || !to) return c.json({ error: 'from and to parameters required' }, 400);
const result = await findShortestPath(makeKbdbClient(c.env), from, to);
return c.json({ from, to, ...result });
});
export { graphRoutes };