Fix Desktop Netx Ops preset using host standard and workflow-ptc.

Prefer Desktop's standard.patch.yml / align CLI worker-thread rows to
workflow-ptc, and refuse compositions the host cannot resolve.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
oliver 2026-10-10 04:53:11 +08:00
parent 7a289cf409
commit 6bf5268dfb
8 changed files with 688 additions and 60 deletions

View file

@ -22,6 +22,7 @@ import { fileURLToPath } from "node:url";
var NETXOPS_PRESET_ID = "netxops";
var DESKTOP_PATCH_BEGIN = "# BEGIN dsh-netxops-preset (managed)";
var DESKTOP_PATCH_END = "# END dsh-netxops-preset (managed)";
var PATCH_PLUGIN_INDENT = " ";
function packageRoot() {
return join(dirname(fileURLToPath(import.meta.url)), "..");
}
@ -31,22 +32,72 @@ function resolveDshHome() {
return fromEnv;
return join(homedir(), ".dsh");
}
function electronResourcesRoots() {
const roots = [];
const rp = process.resourcesPath;
if (typeof rp === "string" && rp.length > 0)
roots.push(rp);
roots.push(join(dirname(process.execPath), "resources"));
return roots;
}
function readableFile(path) {
try {
readFileSync(path, { encoding: "utf8", flag: "r" });
return true;
} catch {
return false;
}
}
function resolveDesktopStandardPatchPath() {
const dshHome = resolveDshHome();
const envOverride = process.env.NETXOPS_STANDARD_PATCH?.trim();
const candidates = [];
if (envOverride)
candidates.push(envOverride);
for (const resources of electronResourcesRoots()) {
candidates.push(join(resources, "app.asar", "dsh", "node_modules", "@deepseek-ai", "dsh-web-app", "presets", "standard.patch.yml"), join(resources, "app.asar.unpacked", "dsh", "node_modules", "@deepseek-ai", "dsh-web-app", "presets", "standard.patch.yml"));
}
const requireAnchors = [
join(dshHome, "profiles", "desktop", "package.json"),
join(dshHome, "profiles", "desktop", "node_modules", "dsh-netxops", "package.json"),
join(packageRoot(), "package.json"),
join(dshHome, "profiles", "node_modules", "@deepseek-ai", "dsh-web-app", "package.json"),
join(dshHome, "profiles", "web", "package.json")
];
for (const anchor of requireAnchors) {
if (!existsSync(anchor))
continue;
try {
const req = createRequire2(anchor);
try {
candidates.push(req.resolve("@deepseek-ai/dsh-web-app/presets/standard.patch.yml"));
} catch {}
const pkg = dirname(req.resolve("@deepseek-ai/dsh-web-app/package.json"));
candidates.push(join(pkg, "presets", "standard.patch.yml"));
} catch {}
}
for (const path of candidates) {
if (readableFile(path))
return path;
}
return null;
}
function resolveStandardPresetDir() {
const dshHome = resolveDshHome();
const candidates = [
join(dshHome, "profiles", "node_modules", "@deepseek-ai", "dsh-agent-presets", "presets", "standard"),
join(dshHome, "profiles", "web", "node_modules", "@deepseek-ai", "dsh-agent-presets", "presets", "standard"),
join(dshHome, "profiles", "desktop", "node_modules", "@deepseek-ai", "dsh-agent-presets", "presets", "standard"),
join(dirname(fileURLToPath(import.meta.url)), "..", "..", "DeepSeekHarness", "packages", "preset", "agent-presets", "presets", "standard")
join(dshHome, "profiles", "web", "node_modules", "@deepseek-ai", "dsh-agent-presets", "presets", "standard"),
join(dirname(fileURLToPath(import.meta.url)), "..", "..", "DeepSeekHarness", "packages", "preset", "agent-presets", "presets", "standard"),
join(dshHome, "profiles", "node_modules", "@deepseek-ai", "dsh-agent-presets", "presets", "standard")
];
for (const dir of candidates) {
if (existsSync(join(dir, "agent.cordis.yml")))
return dir;
}
for (const nm of [
join(dshHome, "profiles", "node_modules"),
join(dshHome, "profiles", "desktop", "node_modules"),
join(dshHome, "profiles", "web", "node_modules"),
join(dshHome, "profiles", "desktop", "node_modules")
join(dshHome, "profiles", "node_modules")
]) {
const pkgJson = join(nm, "@deepseek-ai", "dsh-agent-presets", "package.json");
if (!existsSync(pkgJson))
@ -68,6 +119,155 @@ function resolveStandardPresetDir() {
} catch {}
return null;
}
function desktopRuntimeLikelyPresent() {
if (typeof process.versions.electron === "string")
return true;
for (const resources of electronResourcesRoots()) {
if (existsSync(join(resources, "app.asar")))
return true;
}
const localAppData = process.env.LOCALAPPDATA?.trim();
if (localAppData) {
if (existsSync(join(localAppData, "Programs", "DeepSeek Harness", "resources", "app.asar"))) {
return true;
}
}
return false;
}
function hostResolveBases() {
const dshHome = resolveDshHome();
const bases = [];
for (const resources of electronResourcesRoots()) {
bases.push(join(resources, "app.asar", "dsh", "package.json"));
bases.push(join(resources, "app.asar", "dsh", "node_modules"));
}
const localAppData = process.env.LOCALAPPDATA?.trim();
if (localAppData) {
const asarDsh = join(localAppData, "Programs", "DeepSeek Harness", "resources", "app.asar", "dsh");
bases.push(join(asarDsh, "package.json"), join(asarDsh, "node_modules"));
}
bases.push(join(dshHome, "profiles", "desktop", "package.json"), join(dshHome, "profiles", "desktop", "node_modules"), join(dshHome, "profiles", "web", "package.json"), join(dshHome, "profiles", "web", "node_modules"), join(dshHome, "profiles", "node_modules"), join(packageRoot(), "package.json"));
return [...new Set(bases.filter((path) => path.includes("app.asar") || existsSync(path)))];
}
function packageInstalledAbove(name, bases) {
if (name.startsWith("cordis:") || name.startsWith("node:"))
return true;
const pkg = name.split("/").slice(0, name.startsWith("@") ? 2 : 1).join("/");
for (const base of bases) {
let dir = base.endsWith("package.json") ? dirname(base) : base;
for (;; ) {
if (readableFile(join(dir, "node_modules", pkg, "package.json")))
return true;
if (readableFile(join(dir, pkg, "package.json")))
return true;
const parent = dirname(dir);
if (parent === dir)
break;
dir = parent;
}
const requireAnchor = base.endsWith("package.json") ? base : existsSync(join(base, "package.json")) ? join(base, "package.json") : null;
if (requireAnchor !== null) {
try {
createRequire2(requireAnchor).resolve(`${pkg}/package.json`);
return true;
} catch {}
}
}
return false;
}
function collectCompositionPackageNames(yaml) {
const names = [];
for (const match of yaml.matchAll(/^\s*name:\s*(.+)$/gm)) {
let raw = match[1].trim();
if (raw.startsWith("'") && raw.endsWith("'") || raw.startsWith('"') && raw.endsWith('"')) {
raw = raw.slice(1, -1);
}
if (raw.length === 0)
continue;
if (raw.startsWith("./") || raw.startsWith("../") || raw.startsWith("file:"))
continue;
names.push(raw);
}
return [...new Set(names)];
}
function unresolvableCompositionPackages(yaml, bases) {
return collectCompositionPackageNames(yaml).filter((name) => !packageInstalledAbove(name, bases));
}
function remapWorkflowToPtc(cordis) {
return cordis.replaceAll("- id: workflow-worker-thread", "- id: workflow-ptc").replaceAll("@deepseek-ai/dsh-workflow-worker-thread", "@deepseek-ai/dsh-workflow-ptc");
}
function remapWorkflowToWorkerThread(cordis) {
return cordis.replaceAll("- id: workflow-ptc", "- id: workflow-worker-thread").replaceAll("@deepseek-ai/dsh-workflow-ptc", "@deepseek-ai/dsh-workflow-worker-thread");
}
function alignWorkflowEngineForHost(cordis, bases, host = "auto") {
const hasPtc = packageInstalledAbove("@deepseek-ai/dsh-workflow-ptc", bases);
const hasWorker = packageInstalledAbove("@deepseek-ai/dsh-workflow-worker-thread", bases);
const desktop = host === "desktop" || host === "auto" && desktopRuntimeLikelyPresent();
if (hasPtc && !hasWorker)
return remapWorkflowToPtc(cordis);
if (hasPtc && hasWorker && desktop)
return remapWorkflowToPtc(cordis);
if (!hasPtc && hasWorker && desktop) {
return remapWorkflowToPtc(cordis);
}
if (!hasPtc && !hasWorker && desktop && cordis.includes("workflow-worker-thread")) {
return remapWorkflowToPtc(cordis);
}
if (hasWorker && !hasPtc && !desktop)
return remapWorkflowToWorkerThread(cordis);
if (hasWorker && hasPtc && host === "web")
return remapWorkflowToWorkerThread(cordis);
return cordis;
}
function extractPluginsBodyFromStandardPatch(patchYaml) {
const text = patchYaml.replace(/\r\n/g, `
`);
const marker = /^([ \t]*)plugins:\s*$/m;
const match = marker.exec(text);
if (match === null) {
throw new Error("standard.patch.yml has no plugins: block");
}
const pluginsKeyIndent = match[1].length;
const start = match.index + match[0].length;
const rest = text.slice(start).replace(/^\n/, "");
const lines = rest.split(`
`);
const body = [];
for (const line of lines) {
if (line.trim() === "") {
body.push(line);
continue;
}
const indent = line.match(/^[ \t]*/)?.[0].length ?? 0;
if (indent <= pluginsKeyIndent)
break;
body.push(line);
}
while (body.length > 0 && body[body.length - 1].trim() === "")
body.pop();
return body.join(`
`);
}
function pluginsBodyToAgentCordis(pluginsBody) {
const prefix = PATCH_PLUGIN_INDENT;
return `${pluginsBody.replace(/\r\n/g, `
`).split(`
`).map((line) => {
if (line.length === 0)
return "";
if (line.startsWith(prefix))
return line.slice(prefix.length);
return line.trimStart();
}).join(`
`).trimEnd()}
`;
}
function agentCordisToPluginsBody(agentCordis) {
return agentCordis.replace(/\r\n/g, `
`).split(`
`).map((line) => line.length === 0 ? "" : `${PATCH_PLUGIN_INDENT}${line}`).join(`
`);
}
function replaceTopLevelEntry(cordis, id, replacement) {
const lines = cordis.replace(/\r\n/g, `
`).split(`
@ -146,6 +346,9 @@ function readPresetMeta(metaPath) {
order: (metaText.match(/^order:\s*(\d+)/m) || [])[1] || "50"
};
}
function desktopProfilePresent() {
return existsSync(join(resolveDshHome(), "profiles", "desktop"));
}
function composeNetxopsPresetArtifacts() {
const overlayRoot = join(packageRoot(), "presets", NETXOPS_PRESET_ID);
const personaPath = join(overlayRoot, "PERSONA.md");
@ -153,21 +356,43 @@ function composeNetxopsPresetArtifacts() {
if (!existsSync(personaPath) || !existsSync(metaPath)) {
throw new Error(`bundled preset overlay missing under ${overlayRoot}`);
}
const standardDir = resolveStandardPresetDir();
if (standardDir === null) {
throw new Error("cannot find shipped standard preset (@deepseek-ai/dsh-agent-presets)");
}
const meta = readPresetMeta(metaPath);
let agentCordis = replaceTopLevelEntry(readFileSync(join(standardDir, "agent.cordis.yml"), "utf8"), "persona", personaEntryFromMarkdown(readFileSync(personaPath, "utf8")));
const bases = hostResolveBases();
const patchPath = resolveDesktopStandardPatchPath();
const usePatch = patchPath !== null && process.env.NETXOPS_PREFER_DESKTOP_PATCH !== "0" && (typeof process.versions.electron === "string" || process.env.NETXOPS_PREFER_DESKTOP_PATCH === "1" || desktopProfilePresent() || desktopRuntimeLikelyPresent());
let standardSource;
let standardKind;
let standardDir;
let agentCordis;
if (usePatch && patchPath !== null) {
standardSource = patchPath;
standardKind = "desktop-patch";
standardDir = null;
agentCordis = pluginsBodyToAgentCordis(extractPluginsBodyFromStandardPatch(readFileSync(patchPath, "utf8")));
} else {
const dir = resolveStandardPresetDir();
if (dir === null) {
throw new Error("cannot find host standard preset (Desktop standard.patch.yml or @deepseek-ai/dsh-agent-presets)");
}
standardSource = dir;
standardKind = "directory";
standardDir = dir;
agentCordis = readFileSync(join(dir, "agent.cordis.yml"), "utf8");
}
agentCordis = replaceTopLevelEntry(agentCordis, "persona", personaEntryFromMarkdown(readFileSync(personaPath, "utf8")));
agentCordis = ensureNetxopsToolsRow(agentCordis);
agentCordis = alignWorkflowEngineForHost(agentCordis, bases);
if (!agentCordis.endsWith(`
`))
agentCordis += `
`;
const pluginsBody = agentCordis.replace(/\r\n/g, `
`).split(`
`).map((line) => line.length === 0 ? "" : ` ${line}`).join(`
`);
const missing = unresolvableCompositionPackages(agentCordis, bases).filter((name) => !name.startsWith("dsh-netxops"));
const desktopAsar = desktopRuntimeLikelyPresent();
const blocking = missing.filter((name) => !(desktopAsar && name.startsWith("@deepseek-ai/")));
if (blocking.length > 0) {
throw new Error(`composed Netx Ops preset names packages the host cannot resolve: ${blocking.join(", ")} ` + `(standard-source: ${standardSource})`);
}
const pluginsBody = agentCordisToPluginsBody(agentCordis);
const declarativePatch = `# Declarative Netx Ops preset for Desktop 0.2 (@deepseek-ai/dsh-agent-preset).
# Generated from host \`standard\` + presets/netxops overlays — do not hand-edit.
# Regenerate: bun run scripts/gen-preset-patch.mjs
@ -183,7 +408,7 @@ function composeNetxopsPresetArtifacts() {
plugins:
${pluginsBody}
`;
return { standardDir, ...meta, agentCordis, declarativePatch };
return { standardSource, standardKind, standardDir, ...meta, agentCordis, declarativePatch };
}
function installDirectoryPreset(artifacts, logger) {
const overlayRoot = join(packageRoot(), "presets", NETXOPS_PRESET_ID);
@ -192,7 +417,10 @@ function installDirectoryPreset(artifacts, logger) {
mkdirSync(destParent, { recursive: true });
if (existsSync(dest))
rmSync(dest, { recursive: true, force: true });
cpSync(artifacts.standardDir, dest, { recursive: true });
mkdirSync(dest, { recursive: true });
if (artifacts.standardDir !== null && existsSync(artifacts.standardDir)) {
cpSync(artifacts.standardDir, dest, { recursive: true });
}
writeFileSync(join(dest, "preset.yml"), readFileSync(join(overlayRoot, "preset.yml"), "utf8"));
writeFileSync(join(dest, "PERSONA.md"), readFileSync(join(overlayRoot, "PERSONA.md"), "utf8"));
writeFileSync(join(dest, "agent.cordis.yml"), artifacts.agentCordis);
@ -200,13 +428,13 @@ function installDirectoryPreset(artifacts, logger) {
if (existsSync(skillsSrc))
cpSync(skillsSrc, join(dest, "skills"), { recursive: true });
writeFileSync(join(dest, ".dsh-netxops-managed"), [
"composed-from: standard",
`standard-source: ${artifacts.standardDir}`,
`composed-from: ${artifacts.standardKind}`,
`standard-source: ${artifacts.standardSource}`,
`at: ${new Date().toISOString()}`,
""
].join(`
`), "utf8");
logger.info("netxops: directory preset composed from standard → %s", dest);
logger.info("netxops: directory preset composed from %s → %s", artifacts.standardSource, dest);
}
function syncDeclarativeIntoProfilePatch(profileName, declarativePatch, logger) {
if (profileName !== "desktop")