dsh-expert-group 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +38 -0
- package/README.md +355 -0
- package/THIRD_PARTY_NOTICES.md +35 -0
- package/assets/notification-whoosh.wav +0 -0
- package/bin/prompt-inspector.mjs +63 -0
- package/client-bundle.js +14891 -0
- package/client-expert-group-model.js +426 -0
- package/client-expert-group-sidebar.js +5401 -0
- package/client-freshness.js +364 -0
- package/client-model-config.js +2155 -0
- package/client-notifications.js +38 -0
- package/client.js +6487 -0
- package/cordis.patch.yml +10 -0
- package/fanout-host.js +1507 -0
- package/fanout.js +2981 -0
- package/host/composition.js +155 -0
- package/host/expert-group-runtime.js +822 -0
- package/host/expert-group-snapshot.js +450 -0
- package/host/fanout-runtime.js +822 -0
- package/host/handoff.js +80 -0
- package/host/lineage.js +274 -0
- package/host/notifications.js +189 -0
- package/host/persistence-health.js +389 -0
- package/host/recovery.js +242 -0
- package/host/rpc-transport.js +573 -0
- package/host/settings-runtime.js +168 -0
- package/host/settings-source.js +265 -0
- package/host/storage-binding.js +94 -0
- package/host/system-toast.js +916 -0
- package/image-routing.js +263 -0
- package/index.js +9327 -0
- package/install.ps1 +219 -0
- package/orchestrator.js +239 -0
- package/package.json +142 -0
- package/prompt-contracts.js +148 -0
- package/prompt-inspector.js +584 -0
- package/prompt-sidecar.js +610 -0
- package/resource-budget.js +540 -0
- package/role-registry.js +286 -0
- package/rpc-host.js +310 -0
- package/scripts/assemble-client.mjs +605 -0
- package/scripts/build.mjs +124 -0
- package/shared.js +4003 -0
- package/storage.js +190 -0
- package/uninstall.ps1 +47 -0
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { access, mkdtemp, readdir, readFile, rm, writeFile } from "node:fs/promises";
|
|
3
|
+
import { constants } from "node:fs";
|
|
4
|
+
import { spawn, spawnSync } from "node:child_process";
|
|
5
|
+
import { tmpdir } from "node:os";
|
|
6
|
+
import { isAbsolute, join, relative, resolve } from "node:path";
|
|
7
|
+
import { fileURLToPath } from "node:url";
|
|
8
|
+
import { assembleClientBundle } from "./assemble-client.mjs";
|
|
9
|
+
|
|
10
|
+
const root = resolve(fileURLToPath(new URL("..", import.meta.url)));
|
|
11
|
+
// client-bundle.js 是发布入口;先从独立源文件确定性生成,再执行发布面和语法门禁。
|
|
12
|
+
await assembleClientBundle();
|
|
13
|
+
const packagePath = join(root, "package.json");
|
|
14
|
+
const packageJson = JSON.parse(await readFile(packagePath, "utf8"));
|
|
15
|
+
|
|
16
|
+
function addTarget(targets, value, label) {
|
|
17
|
+
if (typeof value !== "string" || value.length === 0) throw new Error(label + " 必须是非空字符串");
|
|
18
|
+
const normalized = value.startsWith("./") ? value.slice(2) : value;
|
|
19
|
+
if (isAbsolute(normalized) || normalized === ".." || normalized.startsWith("../")) {
|
|
20
|
+
throw new Error(label + " 不能指向包目录外部: " + value);
|
|
21
|
+
}
|
|
22
|
+
targets.add(normalized);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function addExportTargets(targets, value, label) {
|
|
26
|
+
if (typeof value === "string") {
|
|
27
|
+
addTarget(targets, value, label);
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
if (value === null || typeof value !== "object") throw new Error(label + " 的 export 目标无效");
|
|
31
|
+
for (const [condition, nested] of Object.entries(value)) addExportTargets(targets, nested, label + "." + condition);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const targets = new Set();
|
|
35
|
+
for (const file of packageJson.files ?? []) addTarget(targets, file, "files");
|
|
36
|
+
for (const [name, target] of Object.entries(packageJson.exports ?? {})) addExportTargets(targets, target, "exports[" + name + "]");
|
|
37
|
+
for (const [name, target] of Object.entries(packageJson.bin ?? {})) addTarget(targets, target, "bin[" + name + "]");
|
|
38
|
+
|
|
39
|
+
const sourceTargets = [];
|
|
40
|
+
for (const target of [...targets].sort()) {
|
|
41
|
+
const absolute = resolve(root, target);
|
|
42
|
+
const backToRoot = relative(root, absolute);
|
|
43
|
+
if (backToRoot === ".." || backToRoot.startsWith(".." + "\\") || backToRoot.startsWith(".." + "/") || isAbsolute(backToRoot)) {
|
|
44
|
+
throw new Error("解析后的发布路径越界: " + target);
|
|
45
|
+
}
|
|
46
|
+
await access(absolute, constants.R_OK);
|
|
47
|
+
if (/\.(?:js|mjs|cjs)$/i.test(target)) sourceTargets.push(absolute);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
for (const source of sourceTargets) {
|
|
51
|
+
await new Promise((resolvePromise, reject) => {
|
|
52
|
+
const child = spawn(process.execPath, ["--check", source], { stdio: "inherit" });
|
|
53
|
+
child.once("error", reject);
|
|
54
|
+
child.once("exit", (code, signal) => {
|
|
55
|
+
if (code === 0) resolvePromise();
|
|
56
|
+
else reject(new Error("语法检查失败: " + source + (signal ? " (" + signal + ")" : "")));
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// ── bin 入口 smoke ─────────────────────────────────────────────────────────
|
|
62
|
+
// "文件存在 + node --check 通过"发现不了 bin 入口损坏(导出缺失、参数解析回归、
|
|
63
|
+
// sidecar 写入失败),所以构建本身也要真实执行一次 Prompt Inspector CLI。
|
|
64
|
+
// 夹具形状与 test/package-portability.test.mjs 的同类 smoke 保持一致;临时输入与
|
|
65
|
+
// 临时输出都来自 node:os tmpdir 的 mkdtemp,不依赖固定个人路径,结束即清理。
|
|
66
|
+
const CLI_SMOKE_EVENT = JSON.stringify({
|
|
67
|
+
type: "request/header",
|
|
68
|
+
id: "build-smoke-session",
|
|
69
|
+
data: { header: { system: "可移植发布门禁 prompt🙂" } },
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
async function smokePromptInspectorCli() {
|
|
73
|
+
const binTarget = packageJson.bin?.["prompt-inspector"];
|
|
74
|
+
if (typeof binTarget !== "string" || binTarget.length === 0) {
|
|
75
|
+
throw new Error("package.json 缺少 bin[prompt-inspector],无法执行 CLI smoke");
|
|
76
|
+
}
|
|
77
|
+
const cli = resolve(root, binTarget);
|
|
78
|
+
const directory = await mkdtemp(join(tmpdir(), "deg-build-prompt-inspector-"));
|
|
79
|
+
const input = join(directory, "session.jsonl");
|
|
80
|
+
const output = join(directory, "sidecar");
|
|
81
|
+
try {
|
|
82
|
+
await writeFile(input, CLI_SMOKE_EVENT + "\n", "utf8");
|
|
83
|
+
// 同步 spawn(不经 shell):构建脚本不需要并发,退出码与输出都要拿到。
|
|
84
|
+
const result = spawnSync(process.execPath, [cli, input, "--out", output, "--max-bytes", "32"], {
|
|
85
|
+
cwd: root,
|
|
86
|
+
encoding: "utf8",
|
|
87
|
+
maxBuffer: 8 * 1024 * 1024,
|
|
88
|
+
});
|
|
89
|
+
if (result.error) throw new Error("Prompt Inspector CLI 无法启动: " + result.error.message);
|
|
90
|
+
if (result.status !== 0) {
|
|
91
|
+
throw new Error("Prompt Inspector CLI 退出码 " + result.status + ": " + String(result.stderr ?? "").trim());
|
|
92
|
+
}
|
|
93
|
+
let summary;
|
|
94
|
+
try {
|
|
95
|
+
summary = JSON.parse(result.stdout);
|
|
96
|
+
} catch {
|
|
97
|
+
throw new Error("Prompt Inspector CLI stdout 不是 JSON: " + String(result.stdout ?? "").trim());
|
|
98
|
+
}
|
|
99
|
+
if (summary?.verified !== true) {
|
|
100
|
+
throw new Error("Prompt Inspector CLI 生成的 sidecar 未通过校验: " + JSON.stringify(summary));
|
|
101
|
+
}
|
|
102
|
+
// 输出目录必须留下真实产物:manifest 与至少一个分块文件。
|
|
103
|
+
await access(join(output, "manifest.json"), constants.R_OK);
|
|
104
|
+
const chunkEntries = await readdir(join(output, "records"), { recursive: true });
|
|
105
|
+
if (!chunkEntries.some((entry) => entry.endsWith(".txt"))) {
|
|
106
|
+
throw new Error("Prompt Inspector CLI 未写出分块文件: " + chunkEntries.join(","));
|
|
107
|
+
}
|
|
108
|
+
return summary;
|
|
109
|
+
} finally {
|
|
110
|
+
await rm(directory, { recursive: true, force: true });
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const cliSummary = await smokePromptInspectorCli();
|
|
115
|
+
|
|
116
|
+
const dshPeers = Object.entries(packageJson.peerDependencies ?? {})
|
|
117
|
+
.filter(([name]) => name.startsWith("@deepseek-ai/dsh-"))
|
|
118
|
+
.map(([, version]) => version);
|
|
119
|
+
if (dshPeers.length === 0 || new Set(dshPeers).size !== 1) {
|
|
120
|
+
throw new Error("所有 DSH peerDependencies 必须保持同一版本范围");
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
console.log("DEG build verification passed: " + sourceTargets.length + " JavaScript files, "
|
|
124
|
+
+ targets.size + " published targets, prompt-inspector CLI smoke verified=" + cliSummary.verified);
|