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:
@@ -0,0 +1,70 @@
|
||||
// Pending Alias — 零 SQL / 零 D1。全走基本盤 API(template=entity_pending record)。
|
||||
//
|
||||
// base 缺口 [→arcrun]:無 DELETE /records/:id → pending record 無法硬刪。
|
||||
// confirm/reject 採 soft:執行動作但不刪 pending(待 base 補 DELETE)。
|
||||
// 故 getPendingAliases 須由 caller 自行過濾已處理者,或待 DELETE 補上後在此硬刪。
|
||||
|
||||
import type { Entity, PendingAlias } from '../types';
|
||||
import type { KbdbClient } from '../lib/kbdb-client';
|
||||
import { TPL_ENTITY_PENDING, ensurePluginTemplates } from '../lib/templates';
|
||||
import { createEntity, addAlias } from './entity-crud';
|
||||
|
||||
/** 建立 Pending Alias 記錄(一筆 entity_pending record)。 */
|
||||
export async function createPendingAlias(
|
||||
client: KbdbClient,
|
||||
rawName: string,
|
||||
candidateEntityId: string,
|
||||
candidateCanonical: string,
|
||||
similarity: number,
|
||||
owner?: string,
|
||||
): Promise<PendingAlias> {
|
||||
await ensurePluginTemplates(client);
|
||||
const id = await client.createRecord(
|
||||
TPL_ENTITY_PENDING,
|
||||
{
|
||||
raw_name: rawName,
|
||||
candidate_entity_id: candidateEntityId,
|
||||
candidate_canonical: candidateCanonical,
|
||||
similarity: String(similarity),
|
||||
},
|
||||
owner,
|
||||
);
|
||||
return {
|
||||
id,
|
||||
raw_name: rawName,
|
||||
candidate_entity_id: candidateEntityId,
|
||||
candidate_canonical: candidateCanonical,
|
||||
similarity,
|
||||
created_at: Math.floor(Date.now() / 1000),
|
||||
};
|
||||
}
|
||||
|
||||
/** 列出所有 Pending Aliases。 */
|
||||
export async function getPendingAliases(client: KbdbClient, limit = 100, owner?: string): Promise<PendingAlias[]> {
|
||||
const records = await client.listRecordsByTemplate(TPL_ENTITY_PENDING, owner);
|
||||
return records
|
||||
.filter((r) => r.values.raw_name)
|
||||
.map((r) => ({
|
||||
id: r.record_id,
|
||||
raw_name: r.values.raw_name,
|
||||
candidate_entity_id: r.values.candidate_entity_id ?? '',
|
||||
candidate_canonical: r.values.candidate_canonical ?? '',
|
||||
similarity: parseFloat(r.values.similarity ?? '0'),
|
||||
created_at: 0,
|
||||
}))
|
||||
.slice(0, limit);
|
||||
}
|
||||
|
||||
/** 確認 → addAlias 到候選 entity。pending soft 保留([→arcrun] base 缺 DELETE record)。 */
|
||||
export async function confirmPendingAlias(client: KbdbClient, pendingId: string, owner?: string): Promise<void> {
|
||||
const rec = await client.getRecord(pendingId);
|
||||
if (!rec || !rec.values.raw_name) throw new Error(`Pending alias ${pendingId} not found`);
|
||||
await addAlias(client, rec.values.candidate_entity_id, rec.values.raw_name, owner);
|
||||
}
|
||||
|
||||
/** 拒絕 → 以 raw_name 建新 entity。pending soft 保留([→arcrun] base 缺 DELETE record)。 */
|
||||
export async function rejectPendingAlias(client: KbdbClient, pendingId: string, owner?: string): Promise<Entity> {
|
||||
const rec = await client.getRecord(pendingId);
|
||||
if (!rec || !rec.values.raw_name) throw new Error(`Pending alias ${pendingId} not found`);
|
||||
return createEntity(client, rec.values.raw_name, owner);
|
||||
}
|
||||
Reference in New Issue
Block a user