Files
kbdb-graph-plugin/src/actions/entity-pending.ts
T
Leo efe8e165cf 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>
2026-06-14 20:59:41 +08:00

71 lines
2.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Pending Alias — 零 SQL / 零 D1。全走基本盤 APItemplate=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);
}