ship 1.4.59:Arcrun@f87260b1234f
This commit is contained in:
@@ -29,7 +29,7 @@ Served via jsDelivr; fetched automatically during install — you never need to
|
||||
- `arcrun-wait/` — **arcrun-wait**(首裝)
|
||||
- `daemon/` — 桌面 App(Mac/Windows)安裝檔
|
||||
|
||||
Built from `Arcrun@ad60863a8017` by `installer/scripts/ship.mjs`(arcrun-rag repo,release 1.4.58,built 2026-08-27)。
|
||||
Built from `Arcrun@f87260b1234f` by `installer/scripts/ship.mjs`(arcrun-rag repo,release 1.4.59,built 2026-08-27)。
|
||||
|
||||
⚠️ 這份檔案由出貨管線每次自動重寫(`installer/scripts/render-bundles-readme.mjs`)——
|
||||
不要手動改這裡列的零件清單——它是算出來的:公庫=Arcrun 這一版編了什麼,
|
||||
|
||||
@@ -3195,15 +3195,6 @@ function kbdbBase(env) {
|
||||
function tenant(c) {
|
||||
return c.req.header("X-Arcrun-API-Key") ?? null;
|
||||
}
|
||||
function graphBase(env) {
|
||||
if (env.KBDB_GRAPH_URL) return env.KBDB_GRAPH_URL.replace(/\/$/, "");
|
||||
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 init_kbdb_proxy = __esm({
|
||||
"cypher-executor/src/routes/kbdb-proxy.ts"() {
|
||||
@@ -3359,14 +3350,23 @@ var init_kbdb_proxy = __esm({
|
||||
return new Response(res.body, { status: res.status, headers: { "Content-Type": "application/json" } });
|
||||
});
|
||||
kbdbProxyRouter.get("/kbdb/graph/neighbors/:name", async (c) => {
|
||||
if (!tenant(c)) return c.json(NEED_KEY, 401);
|
||||
const base = graphBase(c.env);
|
||||
const headers = graphHeaders(c.env);
|
||||
const owner = tenant(c);
|
||||
if (!owner) return c.json(NEED_KEY, 401);
|
||||
const { base, headers } = kbdbBase(c.env);
|
||||
const params = new URLSearchParams();
|
||||
params.set("owner_id", owner);
|
||||
for (const k of ["depth", "template", "directed"]) {
|
||||
const v = c.req.query(k);
|
||||
if (v) params.set(k, v);
|
||||
}
|
||||
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"))}?${params.toString()}`,
|
||||
{ headers }
|
||||
);
|
||||
return new Response(res.body, { status: res.status, headers: { "Content-Type": "application/json" } });
|
||||
} catch (e) {
|
||||
return c.json({ error: `kbdb-graph-plugin \u4E0D\u53EF\u9054\uFF08${base}\uFF09\uFF1A${e instanceof Error ? e.message : String(e)}` }, 502);
|
||||
return c.json({ error: `KBDB \u4E0D\u53EF\u9054\uFF08${base}\uFF09\uFF1A${e instanceof Error ? e.message : String(e)}` }, 502);
|
||||
}
|
||||
});
|
||||
kbdbProxyRouter.get("/kbdb/map", async (c) => {
|
||||
@@ -15047,7 +15047,6 @@ consoleDashboardRouter.get("/console/dashboard-data", async (c) => {
|
||||
const tenant2 = knowledgeOwner(c.env);
|
||||
const now2 = Date.now();
|
||||
const { base: kbdbUrl, headers: kbdbHeaders2 } = kbdbBase(c.env);
|
||||
const graphUrl = graphBase(c.env);
|
||||
const [
|
||||
beatEntries,
|
||||
taskEntries,
|
||||
@@ -15056,7 +15055,7 @@ consoleDashboardRouter.get("/console/dashboard-data", async (c) => {
|
||||
giteaSprint,
|
||||
kbdbHealth,
|
||||
embedStatus,
|
||||
graphStats,
|
||||
graphProbe,
|
||||
tripletTotal,
|
||||
entriesTotal,
|
||||
wikiCardTotal,
|
||||
@@ -15069,11 +15068,15 @@ consoleDashboardRouter.get("/console/dashboard-data", async (c) => {
|
||||
cachedGiteaSprint(c.env, now2, (p) => c.executionCtx.waitUntil(p)),
|
||||
fetchJson(`${kbdbUrl}/health`, kbdbHeaders2),
|
||||
fetchJson(`${kbdbUrl}/embed/backfill/status`, kbdbHeaders2),
|
||||
// graph-plugin 只拿來判「圖服務活著沒」(燈號)——數字不從這裡拿,見 fetchTripletTotal。
|
||||
// headers 一定要帶:plugin 的 /triplets 前綴掛 Bearer 閘,漏帶=永遠 401=永遠假紅燈(#100)。
|
||||
// 圖服務活著沒(燈號)——數字不從這裡拿,見 fetchTripletTotal。
|
||||
// 🔴 inkstone/Arcrun#168 收斂:原本探的是 kbdb-graph-plugin 的 /triplets/stats,
|
||||
// 但圖能力已收斂回 KBDB(GET /graph/neighbors/:node)⇒ 探那顆 plugin 等於在量一個
|
||||
// 沒有人走的服務:它沒裝就永遠紅燈、裝了也只證明一個不再被使用的東西活著。
|
||||
// 改探 KBDB 那支端點本身——用一個不存在的節點名,它會誠實回 count:0 的 200
|
||||
//(graph-query.ts:查不到就是空結果,不是錯誤),正好當「這條路通不通」的探針。
|
||||
fetchJson(
|
||||
`${graphUrl}/triplets/stats`,
|
||||
graphHeaders(c.env)
|
||||
`${kbdbUrl}/graph/neighbors/${encodeURIComponent("__arcrun_graph_probe__")}?depth=1`,
|
||||
kbdbHeaders2
|
||||
),
|
||||
fetchTripletTotal(c.env, tenant2),
|
||||
// owner_id 一律鎖本租戶:原本不帶 owner 會混到別租戶(實測 459,137 vs leo 的 458,732)
|
||||
@@ -15183,8 +15186,8 @@ consoleDashboardRouter.get("/console/dashboard-data", async (c) => {
|
||||
system: {
|
||||
kbdb_ok: kbdbHealth ? kbdbHealth.ok === true : false,
|
||||
embed: embedStatus ? { enabled: embedStatus.enabled === true, embedded: embedStatus.embedded ?? null, pending: embedStatus.pending ?? null } : null,
|
||||
// ok = plugin 通不通(graphStats 讀得到就是通);triplets = KBDB 真 COUNT(與 plugin 分頁長度無關)
|
||||
graph: { ok: graphStats !== null, triplets: tripletTotal },
|
||||
// ok = 圖查詢通不通(探針讀得到就是通);triplets = KBDB 真 COUNT(兩件事,不互相吞)
|
||||
graph: { ok: graphProbe !== null, triplets: tripletTotal },
|
||||
workflow_total: workflowTotal
|
||||
},
|
||||
kb: {
|
||||
@@ -15270,7 +15273,6 @@ consoleDashboardRouter.post("/console/triage-check", async (c) => {
|
||||
|
||||
// cypher-executor/src/routes/portal-data.ts
|
||||
init_dist();
|
||||
init_kbdb_proxy();
|
||||
init_webhook_handlers();
|
||||
|
||||
// cypher-executor/src/lib/app-system.ts
|
||||
@@ -17001,7 +17003,7 @@ function unwrapWorkflowData(data, key) {
|
||||
}
|
||||
return outer;
|
||||
}
|
||||
function mapGraphWorkflowOutput(data) {
|
||||
function mapGraphNeighborsResponse(data) {
|
||||
const layer = unwrapWorkflowData(data, "neighbors");
|
||||
const neighbors = Array.isArray(layer.neighbors) ? layer.neighbors : [];
|
||||
const edges = Array.isArray(layer.edges) ? layer.edges : [];
|
||||
@@ -17168,6 +17170,14 @@ portalDataRouter.get(
|
||||
return c.json({ success: true, entry });
|
||||
})
|
||||
);
|
||||
async function fetchNeighborsFromKbdb(env, tenant2, node, depth) {
|
||||
const qs = new URLSearchParams();
|
||||
qs.set("depth", String(depth));
|
||||
qs.set("template", "triplet");
|
||||
const res = await kbdbFetch(env, `/graph/neighbors/${encodeURIComponent(node)}?${qs.toString()}&${ownerQuery(tenant2)}`);
|
||||
const body = await res.json().catch(() => null);
|
||||
return { ok: res.ok, status: res.status, body };
|
||||
}
|
||||
portalDataRouter.get(
|
||||
"/portal/data/graph/neighbors/:name",
|
||||
(c) => run(c, async () => {
|
||||
@@ -17177,50 +17187,41 @@ portalDataRouter.get(
|
||||
if (!await hasGraphAccess(c.env, libraries)) {
|
||||
return c.json({ error: "\u7121\u77E5\u8B58\u5716\u8B5C\u6AA2\u8996\u6B0A\u9650" }, 403);
|
||||
}
|
||||
const nodeName = normalizeCjkQuery(c.req.param("name"));
|
||||
const tenant2 = knowledgeOwner(c.env);
|
||||
const wfGraph = await getTenantWorkflowGraph(c.env, "graph_neighbors");
|
||||
if (wfGraph) {
|
||||
const depthRaw = c.req.query("depth") ?? "";
|
||||
const depth = /^\d{1,2}$/.test(depthRaw) ? Number(depthRaw) : 2;
|
||||
const result = await executeWebhookGraph(
|
||||
c.env,
|
||||
wfGraph,
|
||||
// t116: 補傳 kbdb_base;t128: 補傳 template(workflow fetch_triplets.url 用 {{input.template}})
|
||||
{ node: nodeName, depth, namespace: tenant2, owner: tenant2, kbdb_base: c.env.KBDB_BASE_URL ?? "", template: "triplet" },
|
||||
"graph_neighbors",
|
||||
tenant2,
|
||||
c.executionCtx
|
||||
);
|
||||
if (!result.success) {
|
||||
return c.json({ error: `graph_neighbors workflow \u57F7\u884C\u5931\u6557\uFF1A${result.error ?? "\u672A\u77E5\u932F\u8AA4"}` }, 502);
|
||||
}
|
||||
return c.json(mapGraphWorkflowOutput(result.data));
|
||||
}
|
||||
const base = graphBase(c.env);
|
||||
const headers = graphHeaders(c.env);
|
||||
const rawName = c.req.param("name");
|
||||
const depthRaw = c.req.query("depth") ?? "";
|
||||
const depth = /^\d{1,2}$/.test(depthRaw) ? Number(depthRaw) : 2;
|
||||
const tryNames = [rawName];
|
||||
const normalized = normalizeCjkQuery(rawName);
|
||||
if (normalized !== rawName) tryNames.push(normalized);
|
||||
let first = null;
|
||||
try {
|
||||
const res = await fetch(`${base}/graph/neighbors/${encodeURIComponent(nodeName)}`, { headers });
|
||||
if (!res.ok) {
|
||||
return new Response(res.body, { status: res.status, headers: { "Content-Type": "application/json" } });
|
||||
for (const name of tryNames) {
|
||||
const r = await fetchNeighborsFromKbdb(c.env, tenant2, name, depth);
|
||||
if (!first) first = r;
|
||||
if (!r.ok) break;
|
||||
const mapped = mapGraphNeighborsResponse(r.body);
|
||||
if (mapped.count > 0) return c.json(mapped);
|
||||
}
|
||||
const resText = await res.text().catch(() => "");
|
||||
let data = null;
|
||||
try {
|
||||
data = JSON.parse(resText);
|
||||
} catch {
|
||||
}
|
||||
if (data && Array.isArray(data.neighbors) && data.neighbors.length === 0 && Array.isArray(data.edges) && data.edges.length === 0) {
|
||||
const fallbackName = await fuzzyFindNode(c.env, tenant2, nodeName);
|
||||
if (fallbackName && fallbackName !== nodeName) {
|
||||
const res2 = await fetch(`${base}/graph/neighbors/${encodeURIComponent(fallbackName)}`, { headers });
|
||||
return new Response(res2.body, { status: res2.status, headers: { "Content-Type": "application/json" } });
|
||||
if (first?.ok) {
|
||||
const fallbackName = await fuzzyFindNode(c.env, tenant2, rawName);
|
||||
if (fallbackName && !tryNames.includes(fallbackName)) {
|
||||
const r = await fetchNeighborsFromKbdb(c.env, tenant2, fallbackName, depth);
|
||||
if (r.ok) {
|
||||
const mapped = mapGraphNeighborsResponse(r.body);
|
||||
if (mapped.count > 0) return c.json(mapped);
|
||||
}
|
||||
}
|
||||
}
|
||||
return new Response(resText, { status: res.status, headers: { "Content-Type": "application/json" } });
|
||||
} catch (e) {
|
||||
return c.json({ error: `kbdb-graph-plugin \u4E0D\u53EF\u9054\uFF1A${e instanceof Error ? e.message : String(e)}` }, 502);
|
||||
return c.json({ error: `KBDB \u5716\u8B5C\u67E5\u8A62\u4E0D\u53EF\u9054\uFF1A${e instanceof Error ? e.message : String(e)}` }, 502);
|
||||
}
|
||||
if (!first) return c.json({ error: "KBDB \u5716\u8B5C\u67E5\u8A62\u6C92\u6709\u56DE\u61C9" }, 502);
|
||||
if (!first.ok) {
|
||||
const err = first.body && typeof first.body === "object" ? first.body : { error: `KBDB \u5716\u8B5C\u67E5\u8A62\u5931\u6557\uFF08HTTP ${first.status}\uFF09` };
|
||||
return c.json(err, first.status);
|
||||
}
|
||||
return c.json(mapGraphNeighborsResponse(first.body));
|
||||
})
|
||||
);
|
||||
portalDataRouter.get(
|
||||
@@ -17538,6 +17539,29 @@ function canReadRecord(rec, tenant2, libraries) {
|
||||
const lib = recordLibrary(rec.values);
|
||||
return lib === null || canReadLibrary(libraries, lib);
|
||||
}
|
||||
function cardOriginalLocation(entries, library, libraryRoot) {
|
||||
for (const e of entries) {
|
||||
if (typeof e.metadata_json !== "string" || !e.metadata_json) continue;
|
||||
let meta;
|
||||
try {
|
||||
meta = JSON.parse(e.metadata_json);
|
||||
} catch {
|
||||
continue;
|
||||
}
|
||||
const sourcePath = typeof meta.source_path === "string" && meta.source_path.trim() ? meta.source_path.trim() : null;
|
||||
const machine = typeof meta.machine_label === "string" && meta.machine_label.trim() ? meta.machine_label.trim() : typeof meta.machine === "string" && meta.machine.trim() ? meta.machine.trim() : null;
|
||||
if (!sourcePath && !machine) continue;
|
||||
const root = libraryRoot && libraryRoot.trim() ? libraryRoot.trim() : null;
|
||||
return {
|
||||
machine,
|
||||
library,
|
||||
library_root: root,
|
||||
source_path: sourcePath,
|
||||
full_path: root && sourcePath ? `${root.replace(/\/+$/, "")}/${sourcePath.replace(/^\/+/, "")}` : null
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
portalDataRouter.get(
|
||||
"/portal/data/library-cards",
|
||||
(c) => run(c, async () => {
|
||||
@@ -17579,7 +17603,19 @@ portalDataRouter.get(
|
||||
}
|
||||
const entries = filterDeprecatedEntries(body.entries);
|
||||
if (entries.length === 0) return notFound(c);
|
||||
return c.json({ success: true, library, page_name: pageName, entries, count: entries.length });
|
||||
const libRecords = await listRecordsByTemplate(c.env, LIBRARY_TEMPLATE).catch(() => []);
|
||||
const libRootRaw = libRecords.find((r) => String(r.values.name ?? "") === library)?.values.root;
|
||||
const libraryRoot = typeof libRootRaw === "string" ? libRootRaw : null;
|
||||
const location = cardOriginalLocation(entries, library, libraryRoot);
|
||||
return c.json({
|
||||
success: true,
|
||||
library,
|
||||
page_name: pageName,
|
||||
entries,
|
||||
count: entries.length,
|
||||
location,
|
||||
...location ? {} : { location_hint: "\u9019\u5F35\u5361\u7684\u6BB5\u843D\u6C92\u6709 machine/source_path \u4E2D\u7E7C\u8CC7\u6599\uFF0C\u7B54\u4E0D\u51FA\u539F\u6587\u7684\u5BE6\u9AD4\u4F4D\u7F6E" }
|
||||
});
|
||||
})
|
||||
);
|
||||
portalDataRouter.get(
|
||||
@@ -17711,6 +17747,19 @@ portalDataRouter.get(
|
||||
if (!auth.ok) return auth.res;
|
||||
const libraries = parseLibraries(auth.user.values.libraries);
|
||||
if (libraries.length === 0) return c.json({ success: true, records: [], count: 0, total: 0 });
|
||||
const template = c.req.param("template");
|
||||
if (template === LIBRARY_TEMPLATE) {
|
||||
const all = await listRecordsByTemplate(c.env, LIBRARY_TEMPLATE);
|
||||
const records2 = libraries.includes("*") ? all : all.filter((r) => libraries.includes(String(r.values.name ?? "")));
|
||||
return c.json({
|
||||
success: true,
|
||||
records: records2,
|
||||
count: records2.length,
|
||||
page_size: all.length,
|
||||
filtered_out: all.length - records2.length,
|
||||
total: records2.length
|
||||
});
|
||||
}
|
||||
const tenant2 = knowledgeOwner(c.env);
|
||||
const params = new URLSearchParams(ownerQuery(tenant2));
|
||||
for (const k of ["limit", "offset"]) {
|
||||
|
||||
+116
-2
@@ -4241,11 +4241,15 @@ async function selectLibrariesForQuestion(db, question, opts = {}) {
|
||||
SELECT object AS name, ${libraryOf("library")} AS library FROM act WHERE object IS NOT NULL)
|
||||
SELECT name, library, COUNT(*) AS degree
|
||||
FROM ent
|
||||
WHERE LENGTH(name) >= 2 AND instr(?, lower(name)) > 0
|
||||
WHERE LENGTH(name) >= 2
|
||||
AND (
|
||||
instr(?, lower(name)) > 0
|
||||
OR (LENGTH(?) >= 2 AND instr(lower(name), ?) > 0)
|
||||
)
|
||||
GROUP BY name, library
|
||||
ORDER BY degree DESC, name ASC
|
||||
LIMIT 200`
|
||||
).bind(...params, qNorm).all();
|
||||
).bind(...params, qNorm, qNorm, qNorm).all();
|
||||
for (const r of res.results ?? []) {
|
||||
const cur = hits.get(r.library) ?? { entities: /* @__PURE__ */ new Set(), score: 0 };
|
||||
cur.entities.add(r.name);
|
||||
@@ -4545,6 +4549,109 @@ mapRoutes.get("/:library", async (c) => {
|
||||
return c.json({ success: true, map });
|
||||
});
|
||||
|
||||
// kbdb/src/actions/graph-query.ts
|
||||
async function findTripletEdgesByNode(db, templateIdOrName, fields, nodeValue, owner_id) {
|
||||
if (!nodeValue || fields.length === 0) return [];
|
||||
const tpl = await getTemplate(db, templateIdOrName);
|
||||
if (!tpl) return [];
|
||||
const valueSql = owner_id ? `SELECT id FROM entries WHERE content = ? AND entry_type = 'value' AND (owner_id = ? OR owner_id IS NULL)` : `SELECT id FROM entries WHERE content = ? AND entry_type = 'value'`;
|
||||
const valueParams = owner_id ? [nodeValue, owner_id] : [nodeValue];
|
||||
const valueRows = await db.prepare(valueSql).bind(...valueParams).all();
|
||||
const valueIds = (valueRows.results ?? []).map((r) => r.id);
|
||||
if (valueIds.length === 0) return [];
|
||||
const fieldIds = fields.map((f) => fieldEntryId(tpl.id, f));
|
||||
const dstPh = valueIds.map(() => "?").join(",");
|
||||
const relPh = fieldIds.map(() => "?").join(",");
|
||||
const relSql = owner_id ? `SELECT DISTINCT src_id AS record_id FROM entries
|
||||
WHERE dst_id IN (${dstPh}) AND rel_id IN (${relPh}) AND owner_id = ?` : `SELECT DISTINCT src_id AS record_id FROM entries
|
||||
WHERE dst_id IN (${dstPh}) AND rel_id IN (${relPh})`;
|
||||
const relParams = owner_id ? [...valueIds, ...fieldIds, owner_id] : [...valueIds, ...fieldIds];
|
||||
const relRows = await db.prepare(relSql).bind(...relParams).all();
|
||||
const recordIds = (relRows.results ?? []).map((r) => r.record_id);
|
||||
if (recordIds.length === 0) return [];
|
||||
const recPh = recordIds.map(() => "?").join(",");
|
||||
const pivotSql = `
|
||||
SELECT b.src_id AS record_id,
|
||||
MAX(CASE WHEN r.rel_id = ? THEN v.content END) AS subject,
|
||||
MAX(CASE WHEN r.rel_id = ? THEN v.content END) AS predicate,
|
||||
MAX(CASE WHEN r.rel_id = ? THEN v.content END) AS object,
|
||||
MAX(CASE WHEN r.rel_id = ? THEN v.content END) AS status
|
||||
FROM entries b
|
||||
LEFT JOIN entries r ON r.src_id = b.src_id AND r.rel_id != 'sys_belongs'
|
||||
LEFT JOIN entries v ON v.id = r.dst_id
|
||||
WHERE b.rel_id = 'sys_belongs' AND b.src_id IN (${recPh})
|
||||
GROUP BY b.src_id`;
|
||||
const pivotParams = [
|
||||
fieldEntryId(tpl.id, "subject"),
|
||||
fieldEntryId(tpl.id, "predicate"),
|
||||
fieldEntryId(tpl.id, "object"),
|
||||
fieldEntryId(tpl.id, "status"),
|
||||
...recordIds
|
||||
];
|
||||
const pivotRows = await db.prepare(pivotSql).bind(...pivotParams).all();
|
||||
return pivotRows.results ?? [];
|
||||
}
|
||||
async function graphNeighbors(db, start, opts = {}) {
|
||||
const depth = Math.max(1, Math.min(Math.floor(opts.depth ?? 1) || 1, 10));
|
||||
const template = opts.template ?? "triplet";
|
||||
const directed = !!opts.directed;
|
||||
const owner_id = opts.owner_id;
|
||||
const visited = /* @__PURE__ */ new Set([start]);
|
||||
let frontier = [start];
|
||||
const neighbors = [];
|
||||
for (let d = 1; d <= depth; d++) {
|
||||
if (frontier.length === 0) break;
|
||||
const next = [];
|
||||
for (const cur of frontier) {
|
||||
const outgoing = await findTripletEdgesByNode(db, template, ["subject"], cur, owner_id);
|
||||
for (const e of outgoing) {
|
||||
if (e.status === "deprecated") continue;
|
||||
const nb = e.object;
|
||||
if (!nb || visited.has(nb)) continue;
|
||||
visited.add(nb);
|
||||
neighbors.push({ node: nb, predicate: e.predicate ?? "", from: cur, depth: d });
|
||||
next.push(nb);
|
||||
}
|
||||
if (!directed) {
|
||||
const incoming = await findTripletEdgesByNode(db, template, ["object"], cur, owner_id);
|
||||
for (const e of incoming) {
|
||||
if (e.status === "deprecated") continue;
|
||||
const nb = e.subject;
|
||||
if (!nb || visited.has(nb)) continue;
|
||||
visited.add(nb);
|
||||
neighbors.push({ node: nb, predicate: e.predicate ?? "", from: cur, depth: d });
|
||||
next.push(nb);
|
||||
}
|
||||
}
|
||||
}
|
||||
frontier = next;
|
||||
}
|
||||
return { success: true, start, depth, directed, neighbors, count: neighbors.length };
|
||||
}
|
||||
|
||||
// kbdb/src/routes/graph.ts
|
||||
var graphRoutes = new Hono2();
|
||||
graphRoutes.get("/neighbors/:node", async (c) => {
|
||||
const node = c.req.param("node");
|
||||
if (!node) return c.json({ success: false, error: "node required" }, 400);
|
||||
const depthRaw = Number(c.req.query("depth"));
|
||||
const depth = Number.isFinite(depthRaw) && depthRaw > 0 ? Math.floor(depthRaw) : void 0;
|
||||
const directed = c.req.query("directed") === "true";
|
||||
const template = c.req.query("template") || void 0;
|
||||
const owner_id = c.req.query("owner_id") || void 0;
|
||||
try {
|
||||
const result = await graphNeighbors(c.env.DB, node, { depth, template, directed, owner_id });
|
||||
const edges = result.neighbors.map((n) => ({
|
||||
subject: n.from,
|
||||
predicate: n.predicate,
|
||||
object: n.node
|
||||
}));
|
||||
return c.json({ ...result, edges });
|
||||
} catch (e) {
|
||||
return c.json({ success: false, error: e instanceof Error ? e.message : String(e) }, 500);
|
||||
}
|
||||
});
|
||||
|
||||
// kbdb/src/actions/execution-log.ts
|
||||
var SUCCESS_MESSAGE_MAX = 200;
|
||||
var FAILED_MESSAGE_MAX = 2e3;
|
||||
@@ -4832,6 +4939,12 @@ var GENERATIONS = [
|
||||
// 🪦 entry_values 2026-08-15 廢除;「看到它=那台沒跟上,不是它還合法」。
|
||||
{ kind: "no_table", name: "entry_values" }
|
||||
]
|
||||
},
|
||||
{
|
||||
n: 8,
|
||||
file: "0008_entries_content_index.sql",
|
||||
what: "entries.content \u7D22\u5F15\u2014\u2014graph \u9130\u5C45\u67E5\u8A62\u5F9E\u7BC0\u9EDE\u540D\u76F4\u63A5\u67E5\uFF08\u4E0D\u6488\u5168\u8868\uFF09\uFF0CArcrun#168 \u6839\u56E0\u4FEE\u5FA9\u7684\u5730\u57FA",
|
||||
checks: [{ kind: "index", name: "idx_entries_content" }]
|
||||
}
|
||||
];
|
||||
var EXPECTED_GENERATION = GENERATIONS[GENERATIONS.length - 1].n;
|
||||
@@ -4990,6 +5103,7 @@ app.route("/recipe-stats", recipeStatRoutes);
|
||||
app.route("/execution-log", executionLogRoutes);
|
||||
app.route("/embed", embedRoutes);
|
||||
app.route("/map", mapRoutes);
|
||||
app.route("/graph", graphRoutes);
|
||||
var index_default = app;
|
||||
export {
|
||||
index_default as default
|
||||
|
||||
+24
-3
@@ -32025,7 +32025,7 @@ function registerAllKbdbGraphTools(server, env, orgNamespace, identity) {
|
||||
function registerGraphNeighbors(server, env, orgNamespace, identity) {
|
||||
server.tool(
|
||||
"kbdb_graph_neighbors",
|
||||
"knowledge graph \u9130\u5C45\u67E5\u8A62\uFF081-hop/N-hop \u95DC\u4FC2\u904D\u6B77\uFF09\uFF1A\u7D66\u4E00\u500B\u7BC0\u9EDE\u540D\uFF0C\u6CBF KBDB triplet\uFF08subject-predicate-object\uFF09\u8A18\u9304\u505A BFS\uFF0C\u56DE\u50B3 depth \u8DF3\u5167\u7684\u9130\u5C45\u6E05\u55AE\uFF08[{node, predicate, from, depth}]\uFF09\u3002\u8207 kbdb_search\uFF08\u95DC\u9375\u5B57/\u8A9E\u7FA9\uFF09\u4E92\u88DC\uFF1A\u627E\u300C\u8DDF X \u6709\u95DC\u4FC2\u7684\u6771\u897F\u300D\u7528\u672C\u5DE5\u5177\uFF0C\u627E\u300C\u5167\u5BB9\u542B\u95DC\u9375\u5B57\u7684\u6771\u897F\u300D\u7528 kbdb_search\u3002\u9700\u8981 namespace \u88E1\u5DF2\u90E8\u7F72 graph_neighbors workflow\uFF08\u6C92\u88DD\u6703\u56DE\u5B89\u88DD\u6307\u5F15\uFF0C\u4E0D\u6703 crash\uFF09\u3002",
|
||||
"knowledge graph \u9130\u5C45\u67E5\u8A62\uFF081-hop/N-hop \u95DC\u4FC2\u904D\u6B77\uFF09\uFF1A\u7D66\u4E00\u500B\u7BC0\u9EDE\u540D\uFF0C\u6CBF KBDB triplet\uFF08subject-predicate-object\uFF09\u8A18\u9304\u505A BFS\uFF0C\u56DE\u50B3 depth \u8DF3\u5167\u7684\u9130\u5C45\u6E05\u55AE\uFF08[{node, predicate, from, depth}]\uFF09\u3002\u8207 kbdb_search\uFF08\u95DC\u9375\u5B57/\u8A9E\u7FA9\uFF09\u4E92\u88DC\uFF1A\u627E\u300C\u8DDF X \u6709\u95DC\u4FC2\u7684\u6771\u897F\u300D\u7528\u672C\u5DE5\u5177\uFF0C\u627E\u300C\u5167\u5BB9\u542B\u95DC\u9375\u5B57\u7684\u6771\u897F\u300D\u7528 kbdb_search\u3002\u767B\u5165\u8EAB\u5206\uFF08\u5E33\u5BC6\uFF0FOAuth\uFF09\u76F4\u63A5\u8D70 KBDB \u7684\u5716 API\uFF0C\u4E0D\u9700\u8981\u88DD\u4EFB\u4F55 workflow\uFF1B\u670D\u52D9\u7D1A token \u9023\u7DDA\u624D\u9700\u8981 namespace \u88E1\u5DF2\u90E8\u7F72 graph_neighbors workflow\uFF08\u6C92\u88DD\u6703\u56DE\u5B89\u88DD\u6307\u5F15\uFF0C\u4E0D\u6703 crash\uFF09\u3002",
|
||||
{
|
||||
subject: external_exports.string().min(1).describe(
|
||||
"\u8D77\u9EDE\u7BC0\u9EDE\u540D\uFF08graph triplet \u7684 subject/object \u503C\uFF09\uFF0C\u5982 'Arcrun'"
|
||||
@@ -32331,6 +32331,20 @@ function registerGetMap(server, env, identity) {
|
||||
|
||||
// mcp/src/tools/kbdb_index.ts
|
||||
var INDEX_CARD_NAME = "00-INDEX";
|
||||
function locationHints(location, hint) {
|
||||
if (location) {
|
||||
const where = [
|
||||
location.machine ? `\u8A2D\u5099\u300C${location.machine}\u300D` : null,
|
||||
`\u5EAB\u300C${location.library}\u300D`,
|
||||
location.full_path ? `\u8DEF\u5F91 ${location.full_path}` : location.source_path ? `\u5EAB\u5167\u8DEF\u5F91 ${location.source_path}\uFF08\u9019\u500B\u5EAB\u9084\u6C92\u767B\u8A18\u5BE6\u9AD4\u8CC7\u6599\u593E\uFF0C\u7B54\u4E0D\u51FA\u5B8C\u6574\u8DEF\u5F91\uFF09` : null
|
||||
].filter(Boolean);
|
||||
return [
|
||||
`\u539F\u6587\u5728\u54EA\uFF1A${where.join("\u3001")}\u3002`,
|
||||
"\u{1F534} \u56DE\u7B54\u300C\u539F\u6587\u5728\u54EA\u300D\u6642\u7528\u9019\u500B location \u6B04\u4F4D\uFF0C\u4E0D\u8981\u5F15\u7528\u5361\u7247\u5167\u6587\u88E1\u300C### \u51FA\u8655\u300D\u90A3\u4E00\u6BB5\u2014\u2014\u90A3\u5BEB\u7684\u662F\u5167\u90E8\u76F8\u5C0D\u8DEF\u5F91\uFF08`../\u6A94\u540D`\uFF09\uFF0C\u4F7F\u7528\u8005\u62FF\u8457\u5B83\u8D70\u4E0D\u5230\u4EFB\u4F55\u5730\u65B9\u3002"
|
||||
];
|
||||
}
|
||||
return [hint ?? "\u9019\u5F35\u5361\u6C92\u6709 machine/source_path \u4E2D\u7E7C\u8CC7\u6599\uFF0C\u7B54\u4E0D\u51FA\u539F\u6587\u7684\u5BE6\u9AD4\u4F4D\u7F6E\u2014\u2014\u4E0D\u8981\u7528\u5167\u6587\u300C### \u51FA\u8655\u300D\u90A3\u6BB5\u4EE3\u7B54\u3002"];
|
||||
}
|
||||
function anchorOf(block) {
|
||||
try {
|
||||
const meta = typeof block.metadata_json === "string" ? JSON.parse(block.metadata_json) : block.metadata_json ?? {};
|
||||
@@ -32464,11 +32478,13 @@ function registerGetCard(server, env, identity) {
|
||||
);
|
||||
}
|
||||
const content = assembleCard(blocks);
|
||||
const location = isPortal ? body.location ?? null : null;
|
||||
return successResponse(
|
||||
{ library, page_name, content, block_count: blocks.length },
|
||||
{ library, page_name, content, block_count: blocks.length, location },
|
||||
[
|
||||
`\u9019\u662F\u300C${page_name}\u300D\u7684\u5B8C\u6574\u5167\u5BB9\uFF08${blocks.length} \u6BB5\uFF0C\u5DF2\u7167\u539F\u7A3F\u9806\u5E8F\u7D44\u597D\uFF09`,
|
||||
"\u8981\u770B\u5B83\u9023\u5230\u54EA\u4E9B\u5361\uFF1Akbdb_graph_neighbors(name)"
|
||||
"\u8981\u770B\u5B83\u9023\u5230\u54EA\u4E9B\u5361\uFF1Akbdb_graph_neighbors(name)",
|
||||
...locationHints(location, isPortal ? body.location_hint : void 0)
|
||||
]
|
||||
);
|
||||
} catch (e) {
|
||||
@@ -32567,6 +32583,11 @@ var KNOWLEDGE_FIRST = [
|
||||
"3. **\u628A\u90A3\u5F35\u5361\u6574\u5F35\u8B80\u5B8C** \u2192 `kbdb_get_card({ library, page_name })`",
|
||||
" \u6458\u8981\uFF0B\u91CD\u9EDE\uFF0B\u5BE6\u9AD4\uFF0B\u95DC\u806F\u4E00\u6B21\u5230\u624B\uFF0C\u7167\u539F\u7A3F\u9806\u5E8F\u7D44\u597D\u3002**\u5F15\u7528\u5167\u5BB9\u6642\u4E00\u5F8B\u7528\u9019\u4E00\u652F\u3002**",
|
||||
"",
|
||||
"\u{1F534} **\u6709\u4EBA\u554F\u300C\u539F\u6587\u5728\u54EA\uFF0F\u9019\u4EFD\u8CC7\u6599\u54EA\u4F86\u7684\u300D\u2014\u2014\u7B54\u6848\u8981\u8B80 `kbdb_get_card` \u56DE\u61C9\u7684 `location` \u6B04\u4F4D",
|
||||
"\uFF08\u8A2D\u5099\uFF0F\u5EAB\uFF0F\u5EAB\u5167\u8DEF\u5F91\uFF09\uFF0C\u4E0D\u8981\u5F15\u7528\u5361\u7247\u5167\u6587\u88E1\u300C### \u51FA\u8655\u300D\u90A3\u4E00\u6BB5\u3002** \u90A3\u6BB5\u5BEB\u7684\u662F\u8403\u5361\u7576\u4E0B\u7684",
|
||||
"\u5167\u90E8\u76F8\u5C0D\u8DEF\u5F91\uFF08\u5F62\u5982 `../\u6A94\u540D`\uFF09\uFF0C\u4F7F\u7528\u8005\u62FF\u8457\u5B83\u8D70\u4E0D\u5230\u4EFB\u4F55\u5730\u65B9\uFF08inkstone/Arcrun#167\uFF09\u3002",
|
||||
"`location` \u662F null \u6642\uFF0C`kbdb_get_card` \u7684 hints \u6703\u8AA0\u5BE6\u8B1B\u7F3A\u4EC0\u9EBC\u2014\u2014\u7167\u8457\u8AAA\uFF0C\u4E0D\u8981\u7528\u5167\u6587\u90A3\u6BB5\u4EE3\u7B54\u3002",
|
||||
"",
|
||||
"\u70BA\u4EC0\u9EBC\u662F\u9019\u4E09\u6B65\u3001\u800C\u4E0D\u662F\u76F4\u63A5\u5168\u6587\u641C\uFF1A\u4E00\u500B\u554F\u984C\u7684\u7B54\u6848\u901A\u5E38**\u6574\u5F35\u5361**\u624D\u8AAA\u5F97\u5B8C\u6574\uFF0C",
|
||||
"\u800C\u641C\u5C0B\u53EA\u6703\u56DE**\u547D\u4E2D\u95DC\u9375\u5B57\u7684\u90A3\u5E7E\u6BB5**\u2014\u2014\u4F60\u53EF\u80FD\u62FF\u5230\u6458\u8981\u537B\u6C92\u62FF\u5230\u6578\u5B57\u3001\u62FF\u5230\u95DC\u806F\u537B\u6C92\u62FF\u5230\u5BE6\u9AD4\uFF0C",
|
||||
"\u800C\u4E14**\u4F60\u4E0D\u6703\u77E5\u9053\u81EA\u5DF1\u6F0F\u4E86\u54EA\u5E7E\u6BB5**\u3002\u76EE\u9304\u7684\u5B58\u5728\u5C31\u662F\u70BA\u4E86\u8B93\u4F60\u5148\u770B\u5230\u300C\u6709\u4EC0\u9EBC\u300D\u518D\u6C7A\u5B9A\u8B80\u4EC0\u9EBC\u3002",
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Executable
BIN
Binary file not shown.
+50
-46
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"schema": 2,
|
||||
"built": "2026-08-27",
|
||||
"source": "Arcrun@ad60863a8017",
|
||||
"source": "Arcrun@f87260b1234f",
|
||||
"core": [
|
||||
{
|
||||
"name": "arcrun-array-ops",
|
||||
@@ -198,7 +198,7 @@
|
||||
"name": "arcrun-cypher-executor",
|
||||
"main_module": "worker.mjs",
|
||||
"main_file": "arcrun-cypher-executor/worker.mjs",
|
||||
"js_bytes": 694462,
|
||||
"js_bytes": 696639,
|
||||
"modules": [],
|
||||
"compat_date": "2025-02-19",
|
||||
"compat_flags": [
|
||||
@@ -239,10 +239,10 @@
|
||||
"stripped": {
|
||||
"services": 13
|
||||
},
|
||||
"source_commit": "af6f244b44b28a16a3578cf554d1e199a170a05e",
|
||||
"source_content_sha256": "531937c2ebade75fe67676071ca5f658775c11aa855359330ae19117db1d1807",
|
||||
"sha256": "531937c2ebade75fe67676071ca5f658775c11aa855359330ae19117db1d1807",
|
||||
"bytes": 694462
|
||||
"source_commit": "f87260b1234f0c108c378caf474d7af78cdd6cb9",
|
||||
"source_content_sha256": "2390294711ed529125559e505ed8f575093798480606253b31021b6faca4c758",
|
||||
"sha256": "2390294711ed529125559e505ed8f575093798480606253b31021b6faca4c758",
|
||||
"bytes": 696639
|
||||
},
|
||||
{
|
||||
"name": "arcrun-date-ops",
|
||||
@@ -396,7 +396,7 @@
|
||||
"name": "arcrun-kbdb",
|
||||
"main_module": "worker.mjs",
|
||||
"main_file": "arcrun-kbdb/worker.mjs",
|
||||
"js_bytes": 189149,
|
||||
"js_bytes": 194366,
|
||||
"modules": [],
|
||||
"compat_date": "2025-02-19",
|
||||
"compat_flags": [
|
||||
@@ -416,16 +416,16 @@
|
||||
"ENVIRONMENT": "production"
|
||||
}
|
||||
},
|
||||
"source_commit": "af6f244b44b28a16a3578cf554d1e199a170a05e",
|
||||
"source_content_sha256": "80d647b70a89f3d42398be621001ebfcdd08371b68ba523b6fa1f2048c06b64b",
|
||||
"sha256": "80d647b70a89f3d42398be621001ebfcdd08371b68ba523b6fa1f2048c06b64b",
|
||||
"bytes": 189149
|
||||
"source_commit": "f87260b1234f0c108c378caf474d7af78cdd6cb9",
|
||||
"source_content_sha256": "97140b9d10337c0f995b5bd5a4a3403ff06403afb6a51394b3ede013293c5bf6",
|
||||
"sha256": "97140b9d10337c0f995b5bd5a4a3403ff06403afb6a51394b3ede013293c5bf6",
|
||||
"bytes": 194366
|
||||
},
|
||||
{
|
||||
"name": "arcrun-mcp",
|
||||
"main_module": "worker.mjs",
|
||||
"main_file": "arcrun-mcp/worker.mjs",
|
||||
"js_bytes": 1205568,
|
||||
"js_bytes": 1208080,
|
||||
"modules": [],
|
||||
"compat_date": "2024-11-27",
|
||||
"compat_flags": [
|
||||
@@ -440,10 +440,10 @@
|
||||
"ai": false,
|
||||
"vars": {}
|
||||
},
|
||||
"source_commit": "af6f244b44b28a16a3578cf554d1e199a170a05e",
|
||||
"source_content_sha256": "03d2022d9d3134988fddfd52bd9aa6d1c7734f9d14870fbe1cbb39d9aa27a2f4",
|
||||
"sha256": "03d2022d9d3134988fddfd52bd9aa6d1c7734f9d14870fbe1cbb39d9aa27a2f4",
|
||||
"bytes": 1205568
|
||||
"source_commit": "f87260b1234f0c108c378caf474d7af78cdd6cb9",
|
||||
"source_content_sha256": "fad73a5128b50f8f42317ea1c4844ea39eee3c32846ab061282e77b731d810d0",
|
||||
"sha256": "fad73a5128b50f8f42317ea1c4844ea39eee3c32846ab061282e77b731d810d0",
|
||||
"bytes": 1208080
|
||||
},
|
||||
{
|
||||
"name": "arcrun-merge",
|
||||
@@ -507,7 +507,7 @@
|
||||
"name": "arcrun-rag-ui",
|
||||
"main_module": "index.js",
|
||||
"main_file": "tier2/ui/index.js",
|
||||
"js_bytes": 673028,
|
||||
"js_bytes": 677629,
|
||||
"modules": [],
|
||||
"compat_date": "2026-07-01",
|
||||
"compat_flags": [],
|
||||
@@ -518,10 +518,10 @@
|
||||
"ai": false,
|
||||
"vars": {}
|
||||
},
|
||||
"source_commit": "790b41d10d48f8d6d117797c4b81f9884f909209",
|
||||
"source_content_sha256": "8a6048f8ffe7125d0077688043a787849e8332d9613d6b693494583aef9de927",
|
||||
"sha256": "8a6048f8ffe7125d0077688043a787849e8332d9613d6b693494583aef9de927",
|
||||
"bytes": 673028
|
||||
"source_commit": "f87260b1234f0c108c378caf474d7af78cdd6cb9",
|
||||
"source_content_sha256": "8f3bbc90f901a0f06f40f4fdaaf5ec4ed80a2012822596a78ae47a92014a9a42",
|
||||
"sha256": "8f3bbc90f901a0f06f40f4fdaaf5ec4ed80a2012822596a78ae47a92014a9a42",
|
||||
"bytes": 677629
|
||||
},
|
||||
{
|
||||
"name": "arcrun-set",
|
||||
@@ -698,12 +698,12 @@
|
||||
"bytes": 67697
|
||||
}
|
||||
],
|
||||
"release": "1.4.58",
|
||||
"release": "1.4.59",
|
||||
"built_for": "oauth-installer-lazy-load",
|
||||
"notes": [
|
||||
"rag_takedown_direct 用了 __CARDS_PREFIX__,但安裝器的代換表沒有它 ⇒ 這個佔位符會原封不動被推進使用者的工作流。"
|
||||
],
|
||||
"fingerprint": "0216b2185da93feb5878b09abb05c72eb25978a9eeeef0e2c06639b377d67be9",
|
||||
"fingerprint": "6d5575253074f913fa548e13da8ce6c9cda4d9598a8bd5971642ab66ea43bf80",
|
||||
"library": [
|
||||
{
|
||||
"name": "arcrun-array-ops",
|
||||
@@ -888,7 +888,7 @@
|
||||
"name": "arcrun-cypher-executor",
|
||||
"main_module": "worker.mjs",
|
||||
"main_file": "arcrun-cypher-executor/worker.mjs",
|
||||
"js_bytes": 694462,
|
||||
"js_bytes": 696639,
|
||||
"modules": [],
|
||||
"compat_date": "2025-02-19",
|
||||
"compat_flags": [
|
||||
@@ -929,8 +929,8 @@
|
||||
"stripped": {
|
||||
"services": 13
|
||||
},
|
||||
"source_commit": "af6f244b44b28a16a3578cf554d1e199a170a05e",
|
||||
"source_content_sha256": "531937c2ebade75fe67676071ca5f658775c11aa855359330ae19117db1d1807",
|
||||
"source_commit": "f87260b1234f0c108c378caf474d7af78cdd6cb9",
|
||||
"source_content_sha256": "2390294711ed529125559e505ed8f575093798480606253b31021b6faca4c758",
|
||||
"first_install": true
|
||||
},
|
||||
{
|
||||
@@ -1075,7 +1075,7 @@
|
||||
"name": "arcrun-kbdb",
|
||||
"main_module": "worker.mjs",
|
||||
"main_file": "arcrun-kbdb/worker.mjs",
|
||||
"js_bytes": 189149,
|
||||
"js_bytes": 194366,
|
||||
"modules": [],
|
||||
"compat_date": "2025-02-19",
|
||||
"compat_flags": [
|
||||
@@ -1095,15 +1095,15 @@
|
||||
"ENVIRONMENT": "production"
|
||||
}
|
||||
},
|
||||
"source_commit": "af6f244b44b28a16a3578cf554d1e199a170a05e",
|
||||
"source_content_sha256": "80d647b70a89f3d42398be621001ebfcdd08371b68ba523b6fa1f2048c06b64b",
|
||||
"source_commit": "f87260b1234f0c108c378caf474d7af78cdd6cb9",
|
||||
"source_content_sha256": "97140b9d10337c0f995b5bd5a4a3403ff06403afb6a51394b3ede013293c5bf6",
|
||||
"first_install": true
|
||||
},
|
||||
{
|
||||
"name": "arcrun-mcp",
|
||||
"main_module": "worker.mjs",
|
||||
"main_file": "arcrun-mcp/worker.mjs",
|
||||
"js_bytes": 1205568,
|
||||
"js_bytes": 1208080,
|
||||
"modules": [],
|
||||
"compat_date": "2024-11-27",
|
||||
"compat_flags": [
|
||||
@@ -1118,8 +1118,8 @@
|
||||
"ai": false,
|
||||
"vars": {}
|
||||
},
|
||||
"source_commit": "af6f244b44b28a16a3578cf554d1e199a170a05e",
|
||||
"source_content_sha256": "03d2022d9d3134988fddfd52bd9aa6d1c7734f9d14870fbe1cbb39d9aa27a2f4",
|
||||
"source_commit": "f87260b1234f0c108c378caf474d7af78cdd6cb9",
|
||||
"source_content_sha256": "fad73a5128b50f8f42317ea1c4844ea39eee3c32846ab061282e77b731d810d0",
|
||||
"first_install": true
|
||||
},
|
||||
{
|
||||
@@ -1180,7 +1180,7 @@
|
||||
"name": "arcrun-rag-ui",
|
||||
"main_module": "index.js",
|
||||
"main_file": "tier2/ui/index.js",
|
||||
"js_bytes": 673028,
|
||||
"js_bytes": 677629,
|
||||
"modules": [],
|
||||
"compat_date": "2026-07-01",
|
||||
"compat_flags": [],
|
||||
@@ -1191,8 +1191,8 @@
|
||||
"ai": false,
|
||||
"vars": {}
|
||||
},
|
||||
"source_commit": "790b41d10d48f8d6d117797c4b81f9884f909209",
|
||||
"source_content_sha256": "8a6048f8ffe7125d0077688043a787849e8332d9613d6b693494583aef9de927",
|
||||
"source_commit": "f87260b1234f0c108c378caf474d7af78cdd6cb9",
|
||||
"source_content_sha256": "8f3bbc90f901a0f06f40f4fdaaf5ec4ed80a2012822596a78ae47a92014a9a42",
|
||||
"first_install": true
|
||||
},
|
||||
{
|
||||
@@ -1375,13 +1375,17 @@
|
||||
"worker": "arcrun-mcp",
|
||||
"why": "leo 2026-08-10:「今天只要清單含有 MCP 即可」。產品承諾是「把自己的 AI 接上自己的知識庫」,MCP 就是那條線;缺它的話那句承諾從第一步就不成立(prod 1.4.30 曾整包沒有它)。"
|
||||
},
|
||||
{
|
||||
"worker": "arcrun-code",
|
||||
"why": "graph_neighbors/prep 用 __CODE_URL__"
|
||||
},
|
||||
{
|
||||
"worker": "arcrun-http-request",
|
||||
"why": "graph_neighbors/fetch_triplets 用 __HTTP_REQ_URL__"
|
||||
"why": "graph_neighbors/fetch_neighbors 用 __HTTP_REQ_URL__"
|
||||
},
|
||||
{
|
||||
"worker": "arcrun-code",
|
||||
"why": "graph_neighbors/bfs_neighbors 用 __CODE_URL__"
|
||||
"why": "graph_neighbors/parse_neighbors 用 __CODE_URL__"
|
||||
},
|
||||
{
|
||||
"worker": "arcrun-auth-static-key",
|
||||
@@ -1485,20 +1489,20 @@
|
||||
}
|
||||
],
|
||||
"daemon": {
|
||||
"version": "0.18.40",
|
||||
"version": "0.18.41",
|
||||
"mac": {
|
||||
"file": "daemon/Arcrun-0.18.40.dmg",
|
||||
"sha256": "5434b22742c9d1b449d22ab18fe48f2bb9f57c6ac4690e824e391135e7df0ab3"
|
||||
"file": "daemon/Arcrun-0.18.41.dmg",
|
||||
"sha256": "c37705824a139a2b0f2f8fb7d3d5aede686296e6c7820cb96b246d5e6638af61"
|
||||
},
|
||||
"win": {
|
||||
"file": "daemon/Arcrun-win-0.18.40.exe",
|
||||
"sha256": "d84c3159379fd3a415bcab5192a376ae3753f9e12dd8624c5ffced59406b5139"
|
||||
"file": "daemon/Arcrun-win-0.18.41.exe",
|
||||
"sha256": "873ffe08176cfcd381d1ef02a9c88f52be12a8f918eaa83d2004d59db257c19f"
|
||||
},
|
||||
"msix": {
|
||||
"file": "daemon/Arcrun-0.18.40.msix",
|
||||
"sha256": "809b0da36d43ce0b75780f91e34f9f4f0138ea075f3ac92c95155a4f0df8d804"
|
||||
"file": "daemon/Arcrun-0.18.41.msix",
|
||||
"sha256": "6806a58b6efd570e59502f7a5c4d7307fda2fcae39162f8089bab135110c4532"
|
||||
},
|
||||
"built": "20260827-1401",
|
||||
"notes": "卡住的檔案不再擋住後面所有人"
|
||||
"built": "20260827-1950",
|
||||
"notes": "不叫「docs」的文件夾,現在也認得出來"
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user