chore(worker-builds): 重編——#100 的修法要進執行檔才會送到用戶那台

cypher-executor source 525faaf → a5e4caf(sha 49d59597 → d1765930)。
今天第三次在同一件事上被提醒:改完源碼沒重編,出貨與安裝送出去的還是舊的。
This commit is contained in:
uncle6me-web
2026-08-12 13:36:39 +08:00
parent cbeddf7535
commit 793a94ecb5
2 changed files with 89 additions and 19 deletions
@@ -3145,6 +3145,11 @@ function graphBase(env) {
if (env.KBDB_GRAPH_URL) return env.KBDB_GRAPH_URL.replace(/\/$/, ""); if (env.KBDB_GRAPH_URL) return env.KBDB_GRAPH_URL.replace(/\/$/, "");
return `https://kbdb-graph-plugin.${env.WORKER_SUBDOMAIN}.workers.dev`; return `https://kbdb-graph-plugin.${env.WORKER_SUBDOMAIN}.workers.dev`;
} }
function graphHeaders(env) {
const headers = {};
if (env.KBDB_INTERNAL_TOKEN) headers["Authorization"] = `Bearer ${env.KBDB_INTERNAL_TOKEN}`;
return headers;
}
var kbdbProxyRouter, NEED_KEY; var kbdbProxyRouter, NEED_KEY;
var init_kbdb_proxy = __esm({ var init_kbdb_proxy = __esm({
"cypher-executor/src/routes/kbdb-proxy.ts"() { "cypher-executor/src/routes/kbdb-proxy.ts"() {
@@ -3278,8 +3283,7 @@ var init_kbdb_proxy = __esm({
kbdbProxyRouter.get("/kbdb/graph/neighbors/:name", async (c) => { kbdbProxyRouter.get("/kbdb/graph/neighbors/:name", async (c) => {
if (!tenant(c)) return c.json(NEED_KEY, 401); if (!tenant(c)) return c.json(NEED_KEY, 401);
const base = graphBase(c.env); const base = graphBase(c.env);
const headers = {}; const headers = graphHeaders(c.env);
if (c.env.KBDB_INTERNAL_TOKEN) headers["Authorization"] = `Bearer ${c.env.KBDB_INTERNAL_TOKEN}`;
try { try {
const res = await fetch(`${base}/graph/neighbors/${encodeURIComponent(c.req.param("name"))}`, { headers }); const res = await fetch(`${base}/graph/neighbors/${encodeURIComponent(c.req.param("name"))}`, { headers });
return new Response(res.body, { status: res.status, headers: { "Content-Type": "application/json" } }); return new Response(res.body, { status: res.status, headers: { "Content-Type": "application/json" } });
@@ -14537,6 +14541,20 @@ async function fetchJson(url, headers) {
return null; return null;
} }
} }
async function fetchTripletTotal(env, tenant2) {
const { base, headers } = kbdbBase(env);
const data = await fetchJson(
`${base}/records/triplet-stats?owner_id=${encodeURIComponent(tenant2)}`,
headers
);
if (!data || !Array.isArray(data.stats)) return null;
let total = 0;
for (const row of data.stats) {
if (typeof row?.triplet_count !== "number") return null;
total += row.triplet_count;
}
return total;
}
async function fetchEntryTotal(env, filters) { async function fetchEntryTotal(env, filters) {
const { base, headers } = kbdbBase(env); const { base, headers } = kbdbBase(env);
const params = new URLSearchParams({ ...filters, limit: "1" }); const params = new URLSearchParams({ ...filters, limit: "1" });
@@ -14644,6 +14662,7 @@ consoleDashboardRouter.get("/console/dashboard-data", async (c) => {
kbdbHealth, kbdbHealth,
embedStatus, embedStatus,
graphStats, graphStats,
tripletTotal,
entriesTotal, entriesTotal,
wikiCardTotal, wikiCardTotal,
workflowTotal workflowTotal
@@ -14655,7 +14674,13 @@ consoleDashboardRouter.get("/console/dashboard-data", async (c) => {
cachedGiteaSprint(c.env, now2, (p) => c.executionCtx.waitUntil(p)), cachedGiteaSprint(c.env, now2, (p) => c.executionCtx.waitUntil(p)),
fetchJson(`${kbdbUrl}/health`, kbdbHeaders), fetchJson(`${kbdbUrl}/health`, kbdbHeaders),
fetchJson(`${kbdbUrl}/embed/backfill/status`, kbdbHeaders), fetchJson(`${kbdbUrl}/embed/backfill/status`, kbdbHeaders),
fetchJson(`${graphUrl}/triplets/stats`), // graph-plugin 只拿來判「圖服務活著沒」(燈號)——數字不從這裡拿,見 fetchTripletTotal。
// headers 一定要帶:plugin 的 /triplets 前綴掛 Bearer 閘,漏帶=永遠 401=永遠假紅燈(#100)。
fetchJson(
`${graphUrl}/triplets/stats`,
graphHeaders(c.env)
),
fetchTripletTotal(c.env, tenant2),
// owner_id 一律鎖本租戶:原本不帶 owner 會混到別租戶(實測 459,137 vs leo 的 458,732 // owner_id 一律鎖本租戶:原本不帶 owner 會混到別租戶(實測 459,137 vs leo 的 458,732
fetchEntryTotal(c.env, { owner_id: tenant2 }), fetchEntryTotal(c.env, { owner_id: tenant2 }),
fetchEntryTotal(c.env, { entry_type: "wiki_card", owner_id: tenant2 }), fetchEntryTotal(c.env, { entry_type: "wiki_card", owner_id: tenant2 }),
@@ -14763,13 +14788,14 @@ consoleDashboardRouter.get("/console/dashboard-data", async (c) => {
system: { system: {
kbdb_ok: kbdbHealth ? kbdbHealth.ok === true : false, kbdb_ok: kbdbHealth ? kbdbHealth.ok === true : false,
embed: embedStatus ? { enabled: embedStatus.enabled === true, embedded: embedStatus.embedded ?? null, pending: embedStatus.pending ?? null } : null, embed: embedStatus ? { enabled: embedStatus.enabled === true, embedded: embedStatus.embedded ?? null, pending: embedStatus.pending ?? null } : null,
graph: graphStats ? { ok: true, triplets: graphStats.total ?? null } : { ok: false, triplets: null }, // ok = plugin 通不通(graphStats 讀得到就是通);triplets = KBDB 真 COUNT(與 plugin 分頁長度無關)
graph: { ok: graphStats !== null, triplets: tripletTotal },
workflow_total: workflowTotal workflow_total: workflowTotal
}, },
kb: { kb: {
entries_total: entriesTotal, entries_total: entriesTotal,
wiki_card_total: wikiCardTotal, wiki_card_total: wikiCardTotal,
triplets_total: graphStats?.total ?? null triplets_total: tripletTotal
}, },
generated_at: new Date(now2).toISOString() generated_at: new Date(now2).toISOString()
}); });
@@ -14777,22 +14803,22 @@ consoleDashboardRouter.get("/console/dashboard-data", async (c) => {
consoleDashboardRouter.get("/console/kb-scale-data", async (c) => { consoleDashboardRouter.get("/console/kb-scale-data", async (c) => {
const tenant2 = c.env.CONSOLE_TENANT || "leo"; const tenant2 = c.env.CONSOLE_TENANT || "leo";
const { base, headers } = kbdbBase(c.env); const { base, headers } = kbdbBase(c.env);
const graphUrl = graphBase(c.env);
const now2 = Date.now(); const now2 = Date.now();
const [wikiCards, graphStats, embedStatus] = await Promise.all([ const [wikiCards, tripletTotal, embedStatus] = await Promise.all([
// limit=1 順手拿最新一筆 created_atlist 為 created_at DESC)=「最近寫入時間」 // limit=1 順手拿最新一筆 created_atlist 為 created_at DESC)=「最近寫入時間」
fetchJson( fetchJson(
`${base}/entries?${new URLSearchParams({ owner_id: tenant2, entry_type: "wiki_card", limit: "1" }).toString()}`, `${base}/entries?${new URLSearchParams({ owner_id: tenant2, entry_type: "wiki_card", limit: "1" }).toString()}`,
headers headers
), ),
fetchJson(`${graphUrl}/triplets/stats`), // #100:三元組數改讀 KBDB 真 COUNT,不再讀 graph-plugin 的分頁長度(見 fetchTripletTotal 註)
fetchTripletTotal(c.env, tenant2),
fetchJson(`${base}/embed/backfill/status`, headers) fetchJson(`${base}/embed/backfill/status`, headers)
]); ]);
const latestMs = parseCreatedAtMs(wikiCards?.entries?.[0]?.created_at ?? null); const latestMs = parseCreatedAtMs(wikiCards?.entries?.[0]?.created_at ?? null);
return c.json({ return c.json({
wiki_card_total: typeof wikiCards?.total === "number" ? wikiCards.total : null, wiki_card_total: typeof wikiCards?.total === "number" ? wikiCards.total : null,
wiki_card_latest_ago_minutes: latestMs === null ? -1 : agoMinutes(now2, latestMs), wiki_card_latest_ago_minutes: latestMs === null ? -1 : agoMinutes(now2, latestMs),
triplets_total: typeof graphStats?.total === "number" ? graphStats.total : null, triplets_total: tripletTotal,
embedded: embedStatus?.embedded ?? null, embedded: embedStatus?.embedded ?? null,
embed_enabled: embedStatus ? embedStatus.enabled === true : null, embed_enabled: embedStatus ? embedStatus.enabled === true : null,
generated_at: new Date(now2).toISOString() generated_at: new Date(now2).toISOString()
@@ -14944,6 +14970,27 @@ function findBestNodeMatch(searchTerm, nodeNames) {
if (hits.length === 0) return null; if (hits.length === 0) return null;
return hits.reduce((a, b) => a.length <= b.length ? a : b); return hits.reduce((a, b) => a.length <= b.length ? a : b);
} }
async function tripletCount(env, owner) {
try {
const res = await kbdbFetch(env, `/records/triplet-stats?owner_id=${encodeURIComponent(owner)}`);
if (!res.ok) return null;
const body = await res.json().catch(() => null);
if (!body || !Array.isArray(body.stats)) return null;
let total = 0;
for (const row of body.stats) {
if (typeof row?.triplet_count !== "number") return null;
total += row.triplet_count;
}
return total;
} catch {
return null;
}
}
async function tripletCensus(env, tenant2) {
const owned = await tripletCount(env, tenant2);
if (owned !== 0) return { owned, any: null };
return { owned, any: await tripletCount(env, "") };
}
async function fuzzyFindNode(env, tenant2, searchTerm) { async function fuzzyFindNode(env, tenant2, searchTerm) {
try { try {
const res = await kbdbFetch(env, `/records/by-template/triplet?owner_id=${encodeURIComponent(tenant2)}`); const res = await kbdbFetch(env, `/records/by-template/triplet?owner_id=${encodeURIComponent(tenant2)}`);
@@ -15045,8 +15092,7 @@ portalDataRouter.get(
return c.json(mapGraphWorkflowOutput(result.data)); return c.json(mapGraphWorkflowOutput(result.data));
} }
const base = graphBase(c.env); const base = graphBase(c.env);
const headers = {}; const headers = graphHeaders(c.env);
if (c.env.KBDB_INTERNAL_TOKEN) headers["Authorization"] = `Bearer ${c.env.KBDB_INTERNAL_TOKEN}`;
try { try {
const res = await fetch(`${base}/graph/neighbors/${encodeURIComponent(nodeName)}`, { headers }); const res = await fetch(`${base}/graph/neighbors/${encodeURIComponent(nodeName)}`, { headers });
if (!res.ok) { if (!res.ok) {
@@ -15081,12 +15127,19 @@ portalDataRouter.get(
return c.json({ error: "\u7121\u77E5\u8B58\u5716\u8B5C\u6AA2\u8996\u6B0A\u9650" }, 403); return c.json({ error: "\u7121\u77E5\u8B58\u5716\u8B5C\u6AA2\u8996\u6B0A\u9650" }, 403);
} }
const tenant2 = portalTenant(c.env); const tenant2 = portalTenant(c.env);
const res = await kbdbFetch(c.env, `/records/by-template/triplet?owner_id=${encodeURIComponent(tenant2)}`); const [res, census] = await Promise.all([
kbdbFetch(c.env, `/records/by-template/triplet?owner_id=${encodeURIComponent(tenant2)}&limit=500`),
tripletCensus(c.env, tenant2)
]);
const tripletsTotal = census.owned;
if (!res.ok) { if (!res.ok) {
return new Response(res.body, { status: res.status, headers: { "Content-Type": "application/json" } }); return new Response(res.body, { status: res.status, headers: { "Content-Type": "application/json" } });
} }
const body = await res.json().catch(() => null); const body = await res.json().catch(() => null);
const records = body && Array.isArray(body.records) ? body.records : []; if (!body || !Array.isArray(body.records)) {
return c.json({ error: "\u4E09\u5143\u7D44\u8B80\u53D6\u5931\u6557\uFF1AKBDB \u56DE\u61C9\u4E0D\u662F\u9810\u671F\u7684 records \u6E05\u55AE" }, 502);
}
const records = body.records;
const EDGE_CAP = 500; const EDGE_CAP = 500;
const seen = /* @__PURE__ */ new Set(); const seen = /* @__PURE__ */ new Set();
const edges = []; const edges = [];
@@ -15112,7 +15165,24 @@ portalDataRouter.get(
degree.set(o, (degree.get(o) ?? 0) + 1); degree.set(o, (degree.get(o) ?? 0) + 1);
} }
const nodes = [...degree.entries()].map(([name, d]) => ({ name, degree: d })); const nodes = [...degree.entries()].map(([name, d]) => ({ name, degree: d }));
return c.json({ nodes, edges, node_count: nodes.length, edge_count: edges.length, truncated }); let emptyReason = null;
if (nodes.length === 0) {
if (census.owned === null) emptyReason = "unreadable";
else if (census.owned > 0) emptyReason = "scope_mismatch";
else if (census.any === null) emptyReason = "unreadable";
else emptyReason = census.any > 0 ? "scope_mismatch" : "confirmed_empty";
}
return c.json({
nodes,
edges,
node_count: nodes.length,
edge_count: edges.length,
// 取到的 record 已達 KBDB 單頁上限 → 這張圖只是全庫的一部分,別讓 meta 看起來像全部
truncated: truncated || records.length >= 500,
triplets_total: tripletsTotal,
empty_confirmed: nodes.length > 0 || emptyReason === "confirmed_empty",
empty_reason: emptyReason
});
}) })
); );
portalDataRouter.get( portalDataRouter.get(
+5 -5
View File
@@ -1,18 +1,18 @@
{ {
"schema": 1, "schema": 1,
"built_for": "arcrun-tier2-worker-artifacts", "built_for": "arcrun-tier2-worker-artifacts",
"generated_at": "2026-08-12T04:21:48.581Z", "generated_at": "2026-08-12T05:36:26.216Z",
"repo_head": "b302c03ea8076bcfe82bbcebb1523dcec2d1e830", "repo_head": "cbeddf753537fbf836e20b7efce5b47b50f30d06",
"repo_dirty": false, "repo_dirty": false,
"workers": [ "workers": [
{ {
"name": "arcrun-cypher-executor", "name": "arcrun-cypher-executor",
"source_dir": "cypher-executor", "source_dir": "cypher-executor",
"source_commit": "525faaf5d01e156a9b8f90808607bead92f40165", "source_commit": "a5e4caf5cb38c376f892708d8a46ad96a9cc23cc",
"main_module": "worker.mjs", "main_module": "worker.mjs",
"main_file": "arcrun-cypher-executor/worker.mjs", "main_file": "arcrun-cypher-executor/worker.mjs",
"js_bytes": 570290, "js_bytes": 572842,
"content_sha256": "49d59597c01b5264875e0295c86c7bb2212bf54d3c5858cd4a167752370fa716", "content_sha256": "d1765930ce157de07400dcff21d620a3b5549e0a66f0d6428cc6901631ba73b2",
"modules": [], "modules": [],
"compat_date": "2025-02-19", "compat_date": "2025-02-19",
"compat_flags": [ "compat_flags": [