chore(仓库对齐): 文档库结构治理 + IM/插件线落地
build / build-and-scan (push) Canceled after 0s

文档库:目录改为编号制(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/;交接单不入库(政策)。
This commit is contained in:
admin committed 2026-09-24 07:25:16 +08:00
1 parent 3d8f50e366
commit e6207aa691
239 files changed
+34477 -14633

No files matched your search

+7
View File
@@ -0,0 +1,7 @@
// @dsh-local/carbon-mcp-probe — client 半区(POC)
// 本轮问题**只涉及 host 半区**(MCP 工具能否暴露给 agent),
// 故 client 侧刻意留空 apply:不做任何界面、不注入任何槽位。
export function apply() {
// 空 apply —— 见文件头说明
}
+132
View File
@@ -0,0 +1,132 @@
// @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?.();
}