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
+100
View File
@@ -0,0 +1,100 @@
import { createRoute, OpenAPIHono, z } from '@hono/zod-openapi';
import type { Bindings, Variables } from '../types';
import { createTriplet, queryTriplets } from '../actions/triplet-crud';
import { getTripletStats } from '../actions/triplet-stats';
import { makeKbdbClient } from '../lib/kbdb-client';
const tripletRoutes = new OpenAPIHono<{ Bindings: Bindings; Variables: Variables }>();
const TripletSchema = z.object({
id: z.string(),
subject: z.string(),
predicate: z.string(),
object: z.string(),
owner_id: z.string().optional(),
});
// GET /triplets/stats (統計)
const statsRoute = createRoute({
method: 'get',
path: '/stats',
responses: {
200: { description: 'Statistics of the knowledge graph' },
},
tags: ['Triplets'],
});
tripletRoutes.openapi(statsRoute, async (c) => {
const stats = await getTripletStats(makeKbdbClient(c.env));
return c.json(stats, 200);
});
// GET /triplets (查詢)
const queryRoute = createRoute({
method: 'get',
path: '/',
request: {
query: z.object({
subject: z.string().optional(),
predicate: z.string().optional(),
object: z.string().optional(),
limit: z.string().optional().describe('Maximum number of results (default 50)'),
offset: z.string().optional().describe('Pagination offset'),
}),
},
responses: {
200: {
content: {
'application/json': {
schema: z.object({ triplets: z.array(TripletSchema), count: z.number() }),
},
},
description: 'Query results from KBDB Graph',
},
},
tags: ['Triplets'],
});
tripletRoutes.openapi(queryRoute, async (c) => {
const query = c.req.valid('query');
const limit = query.limit ? parseInt(query.limit, 10) : undefined;
const offset = query.offset ? parseInt(query.offset, 10) : undefined;
const results = await queryTriplets(makeKbdbClient(c.env), { ...query, limit, offset });
return c.json(results as any, 200);
});
// POST /triplets (建立)
const createRouteDefinition = createRoute({
method: 'post',
path: '/',
request: {
body: {
content: {
'application/json': {
schema: z.object({
subject: z.string().min(1),
predicate: z.string().min(1),
object: z.string().min(1),
owner_id: z.string().optional(),
source_block_id: z.string().optional(),
confidence: z.number().optional(),
clusters: z.array(z.string()).optional(),
}),
},
},
},
},
responses: {
201: { description: 'Triplet created successfully' },
},
tags: ['Triplets'],
});
tripletRoutes.openapi(createRouteDefinition, async (c) => {
const data = c.req.valid('json');
await createTriplet(makeKbdbClient(c.env), data);
return c.json({ ok: true }, 201);
});
export { tripletRoutes };