Files
dsh_shenxian/poc/carbon-mcp-probe/lib/index.js
T
admin e6207aa691
build / build-and-scan (push) Waiting to run
chore(仓库对齐): 文档库结构治理 + IM/插件线落地
文档库:目录改为编号制(01-规范/02-架构设计/03-数据库/04-调整方案/
05-交接单/06-ops/07-scripts/08-skills/09-archive),顶层散文件归入 01-规范/;
INDEX.md 与 docs-manifest.json 重刷(档案 146 篇);旧目录名引用全量对齐。

IM 线:src/im/**(SDK / hub / store / presence / ws / gateway-token)、
src/web/routes/im.ts、src/db/plugin-data/**、src/supervisor/plugin-assembly.ts
及对应 test/**。

插件线:poc/{im-agent-bridge,im-connection-gateway,im-conversation-tabs,
business-plugins-im,carbon-mcp-probe}、src/web/routes/{sessions,overlay-device}.ts、
src/net/relay/{device-grant,instance-credential}.ts。

仓库卫生:清出 40 个历史误入库 / 已改名文件(34 个交接单归档 + 6 个旧结构,
本地均有副本);dsh-server-docs/.gitignore 补 tmp/;交接单不入库(政策)。
2026-09-24 07:25:16 +08:00

133 lines
5.1 KiB
JavaScript
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.
// @dsh-local/carbon-mcp-probe — host 半区(POC 探针)
//
// 本包在 host 侧只做一件事:**取证**。
// 真正的 MCP 挂载不在这里写代码,而是由同目录的 cordis.patch.yml
// insert 一条内核 `@deepseek-ai/dsh-mcp-client` entry 完成 —— 这正是本轮要验证的契约。
//
// 探针把「boot 后 ctx.tools 注册表里到底有没有 MCP 工具」落成 JSON 证据文件,
// 使验收不依赖 agent / 模型 / 界面。
import { appendFileSync, writeFileSync } from "node:fs";
const DUMP = process.env.CARBON_PROBE_DUMP || "/tmp/carbon-probe-dump.json";
const LOG = process.env.CARBON_PROBE_LOG || "/tmp/carbon-probe-host.log";
const DELAY_MS = Number(process.env.CARBON_PROBE_DELAY_MS || 8000);
function log(line) {
const row = `${new Date().toISOString()} ${line}\n`;
try { appendFileSync(LOG, row); } catch { /* 日志不可写不致命 */ }
process.stdout.write(`[carbon-mcp-probe] ${row}`);
}
/** 在有界预算内 BFS 一个对象图,收集所有含 needle 的键/字符串路径。 */
function bfsFind(root, needle, maxDepth = 5, maxNodes = 600) {
const seen = new Set();
const hits = [];
const queue = [[root, "$", 0]];
let visited = 0;
while (queue.length && visited < maxNodes) {
const [value, path, depth] = queue.shift();
if (value === null || value === undefined) continue;
const t = typeof value;
if (t !== "object" && t !== "function") {
if (t === "string" && value.includes(needle)) hits.push({ path, kind: "string", value: value.slice(0, 160) });
continue;
}
if (seen.has(value)) continue;
seen.add(value);
visited += 1;
let keys = [];
try { keys = Object.getOwnPropertyNames(value); } catch { continue; }
for (const k of keys) {
if (k.includes(needle)) hits.push({ path: `${path}.${k}`, kind: "KEY" });
if (depth + 1 > maxDepth) continue;
let child;
try { child = value[k]; } catch { continue; } // getter 抛错就跳过,绝不冒泡
const childPath = `${path}.${k}`;
if (child instanceof Map) {
let i = 0;
for (const [mk, mv] of child) {
const mp = `${childPath}{Map}["${String(mk)}"]`;
if (String(mk).includes(needle)) hits.push({ path: mp, kind: "MAPKEY" });
if (i++ > 250) break;
queue.push([mv, mp, depth + 1]);
}
} else if (Array.isArray(child)) {
child.slice(0, 60).forEach((v, i) => queue.push([v, `${childPath}[${i}]`, depth + 1]));
} else if (typeof child === "string") {
if (child.includes(needle)) hits.push({ path: childPath, kind: "string", value: child.slice(0, 160) });
} else if (child !== null && typeof child === "object") {
queue.push([child, childPath, depth + 1]);
}
}
}
return { hits, visited, truncated: queue.length > 0 };
}
function probeTools(ctx) {
const rec = { ts: new Date().toISOString(), pid: process.pid };
// 通道 A:直接属性(未声明 inject 时应报错 —— 这本身是契约事实)
try {
const direct = ctx.tools;
rec.channelA = { ok: true, type: typeof direct };
} catch (e) {
rec.channelA = { ok: false, error: String(e) };
}
// 通道 B:ctx.get(name)
let tools = null;
try {
tools = typeof ctx.get === "function" ? ctx.get("tools") : null;
rec.channelB = { ok: !!tools, name: tools && tools.name };
} catch (e) {
rec.channelB = { ok: false, error: String(e) };
}
if (!tools) return rec;
// 通道 C:已知候选方法(不预设签名,逐个试)
rec.channelC = {};
for (const m of ["list", "view", "schemas", "sdkSchemas", "get", "names"]) {
try {
if (typeof tools[m] !== "function") { rec.channelC[m] = { skipped: "not a function" }; continue; }
const v = typeof tools[m] === "function" ? tools[m]() : undefined;
if (v && typeof v.then === "function") { rec.channelC[m] = { async: true }; continue; }
rec.channelC[m] = { type: typeof v, preview: JSON.stringify(v).slice(0, 400) };
} catch (e) {
rec.channelC[m] = { threw: String(e).slice(0, 200) };
}
}
// 通道 D:有界 BFS —— 不依赖任何 API 形状,直接找 mcp__ 命名
try {
rec.channelD = bfsFind(tools, "mcp__");
rec.hasMcpQualified = rec.channelD.hits.length > 0;
} catch (e) {
rec.channelD = { error: String(e) };
rec.hasMcpQualified = false;
}
// 通道 E:同上,只要 carbonprobe 片段(防命名前缀差异)
try {
rec.channelE = bfsFind(tools, "carbonprobe", 5, 600);
} catch (e) {
rec.channelE = { error: String(e) };
}
return rec;
}
export function apply(ctx) {
log(`apply pid=${process.pid} node=${process.version} dump=${DUMP}`);
const timer = setTimeout(() => {
let rec;
try { rec = probeTools(ctx); }
catch (e) { rec = { ts: new Date().toISOString(), fatal: String(e) }; }
try { writeFileSync(DUMP, JSON.stringify(rec, null, 2)); log(`dump written -> ${DUMP}`); }
catch (e) { log(`dump write failed: ${e}`); }
log(`SUMMARY hasMcpQualified=${rec.hasMcpQualified} D.hits=${JSON.stringify(rec.channelD?.hits || []).slice(0, 800)}`);
}, DELAY_MS);
timer.unref?.();
}