mirror of
https://github.com/hansjone/netxops.git
synced 2026-10-15 18:10:45 +08:00
Restore Desktop Netx Ops preset via dual-path install.
Compose from host standard for web directories and sync a correctly indented declarative insert into the desktop profile patch (0.1.48). Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
2d86f55bf9
commit
7a289cf409
7 changed files with 674 additions and 109 deletions
162
lib/index.js
162
lib/index.js
|
|
@ -20,6 +20,8 @@ import { homedir } from "node:os";
|
|||
import { dirname, join } from "node:path";
|
||||
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)";
|
||||
function packageRoot() {
|
||||
return join(dirname(fileURLToPath(import.meta.url)), "..");
|
||||
}
|
||||
|
|
@ -34,7 +36,8 @@ function resolveStandardPresetDir() {
|
|||
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(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")
|
||||
];
|
||||
for (const dir of candidates) {
|
||||
if (existsSync(join(dir, "agent.cordis.yml")))
|
||||
|
|
@ -129,54 +132,149 @@ function personaEntryFromMarkdown(md) {
|
|||
" name: '@deepseek-ai/dsh-persona'",
|
||||
" config:",
|
||||
" suffix: Your working directory is {{cwd}}.",
|
||||
" # Body from presets/netxops/PERSONA.md (composed onto standard at install).",
|
||||
" # Body from presets/netxops/PERSONA.md (composed onto standard).",
|
||||
" prefix: |-",
|
||||
indented
|
||||
].join(`
|
||||
`);
|
||||
}
|
||||
function ensureAgentPresetInstalled(logger) {
|
||||
function readPresetMeta(metaPath) {
|
||||
const metaText = readFileSync(metaPath, "utf8");
|
||||
return {
|
||||
name: (metaText.match(/^name:\s*(.+)$/m) || [])[1]?.trim() || "Netx Ops",
|
||||
description: (metaText.match(/^description:\s*(.+)$/m) || [])[1]?.trim() || "",
|
||||
order: (metaText.match(/^order:\s*(\d+)/m) || [])[1] || "50"
|
||||
};
|
||||
}
|
||||
function composeNetxopsPresetArtifacts() {
|
||||
const overlayRoot = join(packageRoot(), "presets", NETXOPS_PRESET_ID);
|
||||
const personaPath = join(overlayRoot, "PERSONA.md");
|
||||
const metaPath = join(overlayRoot, "preset.yml");
|
||||
if (!existsSync(personaPath) || !existsSync(metaPath)) {
|
||||
logger.warn("netxops: bundled preset overlay missing under %s — skip install", overlayRoot);
|
||||
return;
|
||||
throw new Error(`bundled preset overlay missing under ${overlayRoot}`);
|
||||
}
|
||||
const standardDir = resolveStandardPresetDir();
|
||||
if (standardDir === null) {
|
||||
logger.warn("netxops: cannot find shipped standard preset (@deepseek-ai/dsh-agent-presets) — skip user-preset install");
|
||||
return;
|
||||
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")));
|
||||
agentCordis = ensureNetxopsToolsRow(agentCordis);
|
||||
if (!agentCordis.endsWith(`
|
||||
`))
|
||||
agentCordis += `
|
||||
`;
|
||||
const pluginsBody = agentCordis.replace(/\r\n/g, `
|
||||
`).split(`
|
||||
`).map((line) => line.length === 0 ? "" : ` ${line}`).join(`
|
||||
`);
|
||||
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
|
||||
|
||||
- insert:
|
||||
- id: preset-netxops
|
||||
name: '@deepseek-ai/dsh-agent-preset'
|
||||
config:
|
||||
id: netxops
|
||||
order: ${meta.order}
|
||||
name: ${JSON.stringify(meta.name)}
|
||||
description: ${JSON.stringify(meta.description)}
|
||||
plugins:
|
||||
${pluginsBody}
|
||||
`;
|
||||
return { standardDir, ...meta, agentCordis, declarativePatch };
|
||||
}
|
||||
function installDirectoryPreset(artifacts, logger) {
|
||||
const overlayRoot = join(packageRoot(), "presets", NETXOPS_PRESET_ID);
|
||||
const destParent = join(resolveDshHome(), ".agent-presets");
|
||||
const dest = join(destParent, NETXOPS_PRESET_ID);
|
||||
try {
|
||||
mkdirSync(destParent, { recursive: true });
|
||||
if (existsSync(dest))
|
||||
rmSync(dest, { recursive: true, force: true });
|
||||
cpSync(standardDir, dest, { recursive: true });
|
||||
writeFileSync(join(dest, "preset.yml"), readFileSync(metaPath, "utf8"));
|
||||
writeFileSync(join(dest, "PERSONA.md"), readFileSync(personaPath, "utf8"));
|
||||
const standardCordis = readFileSync(join(standardDir, "agent.cordis.yml"), "utf8");
|
||||
let composed = replaceTopLevelEntry(standardCordis, "persona", personaEntryFromMarkdown(readFileSync(personaPath, "utf8")));
|
||||
composed = ensureNetxopsToolsRow(composed);
|
||||
writeFileSync(join(dest, "agent.cordis.yml"), composed.endsWith(`
|
||||
`) ? composed : `${composed}
|
||||
`, "utf8");
|
||||
const skillsSrc = join(overlayRoot, "skills");
|
||||
if (existsSync(skillsSrc)) {
|
||||
cpSync(skillsSrc, join(dest, "skills"), { recursive: true });
|
||||
}
|
||||
writeFileSync(join(dest, ".dsh-netxops-managed"), [
|
||||
`composed-from: standard`,
|
||||
`standard-source: ${standardDir}`,
|
||||
`at: ${new Date().toISOString()}`,
|
||||
""
|
||||
].join(`
|
||||
mkdirSync(destParent, { recursive: true });
|
||||
if (existsSync(dest))
|
||||
rmSync(dest, { recursive: true, force: true });
|
||||
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);
|
||||
const skillsSrc = join(overlayRoot, "skills");
|
||||
if (existsSync(skillsSrc))
|
||||
cpSync(skillsSrc, join(dest, "skills"), { recursive: true });
|
||||
writeFileSync(join(dest, ".dsh-netxops-managed"), [
|
||||
"composed-from: standard",
|
||||
`standard-source: ${artifacts.standardDir}`,
|
||||
`at: ${new Date().toISOString()}`,
|
||||
""
|
||||
].join(`
|
||||
`), "utf8");
|
||||
logger.info("netxops: agent preset composed from standard → %s", dest);
|
||||
logger.info("netxops: directory preset composed from standard → %s", dest);
|
||||
}
|
||||
function syncDeclarativeIntoProfilePatch(profileName, declarativePatch, logger) {
|
||||
if (profileName !== "desktop")
|
||||
return;
|
||||
const profileDir = join(resolveDshHome(), "profiles", profileName);
|
||||
const patchPath = join(profileDir, "cordis.patch.yml");
|
||||
if (!existsSync(profileDir))
|
||||
return;
|
||||
let patch = existsSync(patchPath) ? readFileSync(patchPath, "utf8") : `[]
|
||||
`;
|
||||
patch = stripManagedPresetBlocks(patch);
|
||||
patch = patch.replace(/^- id: preset-netxops\n(?: .*\n)*/m, "");
|
||||
if (patch.trim() === "" || patch.trim() === "[]")
|
||||
patch = "";
|
||||
if (!patch.endsWith(`
|
||||
`) && patch.length > 0)
|
||||
patch += `
|
||||
`;
|
||||
const managed = `${DESKTOP_PATCH_BEGIN}
|
||||
${declarativePatch.trimEnd()}
|
||||
${DESKTOP_PATCH_END}
|
||||
`;
|
||||
writeFileSync(patchPath, `${patch}${managed}`, "utf8");
|
||||
logger.info("netxops: declarative preset synced into profiles/%s/cordis.patch.yml (restart Desktop to load)", profileName);
|
||||
}
|
||||
function stripManagedPresetBlocks(patch) {
|
||||
let out = patch;
|
||||
for (;; ) {
|
||||
const start = out.indexOf(DESKTOP_PATCH_BEGIN);
|
||||
if (start < 0)
|
||||
break;
|
||||
const end = out.indexOf(DESKTOP_PATCH_END, start);
|
||||
if (end < 0) {
|
||||
out = out.slice(0, start);
|
||||
break;
|
||||
}
|
||||
let cut = end + DESKTOP_PATCH_END.length;
|
||||
if (out[cut] === "\r")
|
||||
cut += 1;
|
||||
if (out[cut] === `
|
||||
`)
|
||||
cut += 1;
|
||||
out = `${out.slice(0, start)}${out.slice(cut)}`;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
function ensureAgentPresetInstalled(logger) {
|
||||
let artifacts;
|
||||
try {
|
||||
artifacts = composeNetxopsPresetArtifacts();
|
||||
} catch (error) {
|
||||
logger.error("netxops: failed to install agent preset: %s", error);
|
||||
logger.warn("netxops: skip preset install: %s", error);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
installDirectoryPreset(artifacts, logger);
|
||||
} catch (error) {
|
||||
logger.error("netxops: failed to install directory preset: %s", error);
|
||||
}
|
||||
try {
|
||||
writeFileSync(join(packageRoot(), "presets", "netxops.preset.patch.yml"), artifacts.declarativePatch);
|
||||
} catch {}
|
||||
try {
|
||||
for (const profile of ["desktop", "web"]) {
|
||||
syncDeclarativeIntoProfilePatch(profile, artifacts.declarativePatch, logger);
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error("netxops: failed to sync declarative preset into profile patch: %s", error);
|
||||
}
|
||||
}
|
||||
// src/netx/alarm-push-status.ts
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue