mirror of
https://github.com/hansjone/netxops.git
synced 2026-10-15 12:13:28 +08:00
Compose Netx Ops preset from host standard instead of embedding it.
Drop the declarative @deepseek-ai/dsh-agent-preset patch (and the huge flat standard copy) so web/CLI boot no longer needs that package; install copies shipped standard then overlays persona/tools/skills. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
3655eeef73
commit
2d86f55bf9
9 changed files with 468 additions and 1075 deletions
353
lib/index.js
353
lib/index.js
|
|
@ -2,14 +2,183 @@ import { createRequire } from "node:module";
|
|||
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
||||
|
||||
// src/index.ts
|
||||
import { cpSync, existsSync as existsSync5, mkdirSync as mkdirSync2, rmSync as rmSync2, writeFileSync as writeFileSync2 } from "node:fs";
|
||||
import { homedir as homedir3 } from "node:os";
|
||||
import { dirname as dirname4, join as join7 } from "node:path";
|
||||
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
||||
import z from "@deepseek-ai/schemastery";
|
||||
import { credentialRef } from "@deepseek-ai/dsh-credentials";
|
||||
import * as DshSettings from "@deepseek-ai/dsh-settings";
|
||||
|
||||
// src/agent-preset-install.ts
|
||||
import {
|
||||
cpSync,
|
||||
existsSync,
|
||||
mkdirSync,
|
||||
readFileSync,
|
||||
rmSync,
|
||||
writeFileSync
|
||||
} from "node:fs";
|
||||
import { createRequire as createRequire2 } from "node:module";
|
||||
import { homedir } from "node:os";
|
||||
import { dirname, join } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
var NETXOPS_PRESET_ID = "netxops";
|
||||
function packageRoot() {
|
||||
return join(dirname(fileURLToPath(import.meta.url)), "..");
|
||||
}
|
||||
function resolveDshHome() {
|
||||
const fromEnv = process.env.DSH_HOME?.trim();
|
||||
if (fromEnv !== undefined && fromEnv.length > 0)
|
||||
return fromEnv;
|
||||
return join(homedir(), ".dsh");
|
||||
}
|
||||
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")
|
||||
];
|
||||
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", "web", "node_modules"),
|
||||
join(dshHome, "profiles", "desktop", "node_modules")
|
||||
]) {
|
||||
const pkgJson = join(nm, "@deepseek-ai", "dsh-agent-presets", "package.json");
|
||||
if (!existsSync(pkgJson))
|
||||
continue;
|
||||
try {
|
||||
const req = createRequire2(pkgJson);
|
||||
const root = dirname(req.resolve("@deepseek-ai/dsh-agent-presets/package.json"));
|
||||
const dir = join(root, "presets", "standard");
|
||||
if (existsSync(join(dir, "agent.cordis.yml")))
|
||||
return dir;
|
||||
} catch {}
|
||||
}
|
||||
try {
|
||||
const req = createRequire2(import.meta.url);
|
||||
const root = dirname(req.resolve("@deepseek-ai/dsh-agent-presets/package.json"));
|
||||
const dir = join(root, "presets", "standard");
|
||||
if (existsSync(join(dir, "agent.cordis.yml")))
|
||||
return dir;
|
||||
} catch {}
|
||||
return null;
|
||||
}
|
||||
function replaceTopLevelEntry(cordis, id, replacement) {
|
||||
const lines = cordis.replace(/\r\n/g, `
|
||||
`).split(`
|
||||
`);
|
||||
const start = lines.findIndex((line) => line === `- id: ${id}`);
|
||||
const block = replacement.replace(/\r\n/g, `
|
||||
`).trimEnd().split(`
|
||||
`);
|
||||
if (start < 0) {
|
||||
return `${cordis.replace(/\r\n/g, `
|
||||
`).trimEnd()}
|
||||
|
||||
${block.join(`
|
||||
`)}
|
||||
`;
|
||||
}
|
||||
let end = start + 1;
|
||||
while (end < lines.length && !lines[end].startsWith("- id:"))
|
||||
end += 1;
|
||||
while (end > start + 1 && lines[end - 1].trim() === "")
|
||||
end -= 1;
|
||||
return [...lines.slice(0, start), ...block, "", ...lines.slice(end)].join(`
|
||||
`).replace(/\n{3,}/g, `
|
||||
|
||||
`);
|
||||
}
|
||||
function ensureNetxopsToolsRow(cordis) {
|
||||
if (/^- id: netxops-tools$/m.test(cordis))
|
||||
return cordis;
|
||||
const row = `- id: netxops-tools
|
||||
name: dsh-netxops/tools`;
|
||||
if (/^- id: tool-skill$/m.test(cordis)) {
|
||||
const lines = cordis.replace(/\r\n/g, `
|
||||
`).split(`
|
||||
`);
|
||||
const start = lines.findIndex((line) => line === "- id: tool-skill");
|
||||
let end = start + 1;
|
||||
while (end < lines.length && !lines[end].startsWith("- id:"))
|
||||
end += 1;
|
||||
while (end > start + 1 && lines[end - 1].trim() === "")
|
||||
end -= 1;
|
||||
return [...lines.slice(0, end), "", ...row.split(`
|
||||
`), "", ...lines.slice(end)].join(`
|
||||
`).replace(/\n{3,}/g, `
|
||||
|
||||
`);
|
||||
}
|
||||
return `${cordis.replace(/\r\n/g, `
|
||||
`).trimEnd()}
|
||||
|
||||
${row}
|
||||
`;
|
||||
}
|
||||
function personaEntryFromMarkdown(md) {
|
||||
const body = md.replace(/\r\n/g, `
|
||||
`).replace(/^#[^\n]*\n+/u, "").replace(/\n+$/u, "");
|
||||
const indented = body.split(`
|
||||
`).map((line) => ` ${line}`).join(`
|
||||
`);
|
||||
return [
|
||||
"- id: persona",
|
||||
" name: '@deepseek-ai/dsh-persona'",
|
||||
" config:",
|
||||
" suffix: Your working directory is {{cwd}}.",
|
||||
" # Body from presets/netxops/PERSONA.md (composed onto standard at install).",
|
||||
" prefix: |-",
|
||||
indented
|
||||
].join(`
|
||||
`);
|
||||
}
|
||||
function ensureAgentPresetInstalled(logger) {
|
||||
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;
|
||||
}
|
||||
const standardDir = resolveStandardPresetDir();
|
||||
if (standardDir === null) {
|
||||
logger.warn("netxops: cannot find shipped standard preset (@deepseek-ai/dsh-agent-presets) — skip user-preset install");
|
||||
return;
|
||||
}
|
||||
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(`
|
||||
`), "utf8");
|
||||
logger.info("netxops: agent preset composed from standard → %s", dest);
|
||||
} catch (error) {
|
||||
logger.error("netxops: failed to install agent preset: %s", error);
|
||||
}
|
||||
}
|
||||
// src/netx/alarm-push-status.ts
|
||||
var STORE_KEY = Symbol.for("dsh-netxops.alarm-push-status");
|
||||
function emptyStatus(partial = {}) {
|
||||
|
|
@ -404,16 +573,16 @@ async function deliverAlarmToIm(ctx, payload, options) {
|
|||
}
|
||||
|
||||
// src/netx/alarm-session.ts
|
||||
import { homedir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
import { homedir as homedir2 } from "node:os";
|
||||
import { join as join2 } from "node:path";
|
||||
var PRESET_ID = "netxops";
|
||||
var PERMISSION_PRESET = "default";
|
||||
var sticky = null;
|
||||
var deliveryChain = Promise.resolve();
|
||||
function resolveWorkspacePath() {
|
||||
const fromEnv = process.env.DSH_HOME?.trim();
|
||||
const home = fromEnv && fromEnv.length > 0 ? fromEnv : join(homedir(), ".dsh");
|
||||
return join(home, "workspaces", "netxops-alarms");
|
||||
const home = fromEnv && fromEnv.length > 0 ? fromEnv : join2(homedir2(), ".dsh");
|
||||
return join2(home, "workspaces", "netxops-alarms");
|
||||
}
|
||||
async function disposeSticky(handle) {
|
||||
if (!handle)
|
||||
|
|
@ -684,29 +853,29 @@ function toolNamesForGroups(groupIds) {
|
|||
}
|
||||
|
||||
// src/netx/group-skills.ts
|
||||
import { existsSync } from "node:fs";
|
||||
import { existsSync as existsSync2 } from "node:fs";
|
||||
import { readdir, readFile, stat } from "node:fs/promises";
|
||||
import { dirname, join as join2 } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { dirname as dirname2, join as join3 } from "node:path";
|
||||
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
||||
function opsSkillsRoot() {
|
||||
const envRoot = process.env.NETX_SKILLS_ROOT?.trim();
|
||||
if (envRoot && existsSync(envRoot))
|
||||
if (envRoot && existsSync2(envRoot))
|
||||
return envRoot;
|
||||
const here = dirname(fileURLToPath(import.meta.url));
|
||||
const here = dirname2(fileURLToPath2(import.meta.url));
|
||||
const siblingCandidates = [
|
||||
join2(here, "..", "..", "..", "netx", "skills"),
|
||||
join2(here, "..", "..", "netx", "skills")
|
||||
join3(here, "..", "..", "..", "netx", "skills"),
|
||||
join3(here, "..", "..", "netx", "skills")
|
||||
];
|
||||
for (const candidate of siblingCandidates) {
|
||||
if (existsSync(candidate))
|
||||
if (existsSync2(candidate))
|
||||
return candidate;
|
||||
}
|
||||
const packaged = [
|
||||
join2(here, "..", "presets", "netxops", "skills"),
|
||||
join2(here, "..", "..", "presets", "netxops", "skills")
|
||||
join3(here, "..", "presets", "netxops", "skills"),
|
||||
join3(here, "..", "..", "presets", "netxops", "skills")
|
||||
];
|
||||
for (const candidate of packaged) {
|
||||
if (existsSync(candidate))
|
||||
if (existsSync2(candidate))
|
||||
return candidate;
|
||||
}
|
||||
return packaged[0];
|
||||
|
|
@ -753,7 +922,7 @@ function stripQuotes(value) {
|
|||
return value;
|
||||
}
|
||||
async function loadSkillBundle(dir) {
|
||||
const skillPath = join2(dir, "SKILL.md");
|
||||
const skillPath = join3(dir, "SKILL.md");
|
||||
let raw;
|
||||
try {
|
||||
raw = await readFile(skillPath, "utf8");
|
||||
|
|
@ -776,7 +945,7 @@ async function loadSkillBundle(dir) {
|
|||
};
|
||||
}
|
||||
async function loadGroupSkills(skillsRoot, groupId) {
|
||||
const groupDir = join2(skillsRoot, SKILL_DIR_BY_GROUP[groupId]);
|
||||
const groupDir = join3(skillsRoot, SKILL_DIR_BY_GROUP[groupId]);
|
||||
let entries;
|
||||
try {
|
||||
entries = await readdir(groupDir);
|
||||
|
|
@ -785,7 +954,7 @@ async function loadGroupSkills(skillsRoot, groupId) {
|
|||
}
|
||||
const skills = [];
|
||||
for (const entry of entries) {
|
||||
const full = join2(groupDir, entry);
|
||||
const full = join3(groupDir, entry);
|
||||
let isDir = false;
|
||||
try {
|
||||
isDir = (await stat(full)).isDirectory();
|
||||
|
|
@ -831,8 +1000,8 @@ async function registerGroupSkills(ctx, groupIds, providerLabel) {
|
|||
}
|
||||
|
||||
// src/netx/kb-local-path.ts
|
||||
import { existsSync as existsSync2, realpathSync, statSync } from "node:fs";
|
||||
import { join as join3, relative, resolve, sep } from "node:path";
|
||||
import { existsSync as existsSync3, realpathSync, statSync } from "node:fs";
|
||||
import { join as join4, relative, resolve, sep } from "node:path";
|
||||
var KB_LOCAL_WRITABLE_ROOTS = Object.freeze([
|
||||
"memories",
|
||||
"drafts",
|
||||
|
|
@ -943,7 +1112,7 @@ function resolveExistingWritableFile(localRoot, pathArg) {
|
|||
}
|
||||
const checked = resolveWritableLocalPath(localRoot, ...relative(localRoot, absolutePath).split(/[/\\]/).filter(Boolean));
|
||||
try {
|
||||
if (existsSync2(checked.absolutePath)) {
|
||||
if (existsSync3(checked.absolutePath)) {
|
||||
const realFile = realpathSync(checked.absolutePath);
|
||||
const realLocal = realpathSync(localRoot);
|
||||
const realRel = relative(realLocal, realFile);
|
||||
|
|
@ -971,16 +1140,16 @@ function resolveExistingWritableFile(localRoot, pathArg) {
|
|||
return checked;
|
||||
}
|
||||
function memoryDir(bucket) {
|
||||
return join3("memories", MEMORY_BUCKET_DIR[bucket]);
|
||||
return join4("memories", MEMORY_BUCKET_DIR[bucket]);
|
||||
}
|
||||
function suggestionDir(kind) {
|
||||
return join3("suggestions", kind);
|
||||
return join4("suggestions", kind);
|
||||
}
|
||||
function draftDir(domain) {
|
||||
const d = domain?.trim();
|
||||
if (!d)
|
||||
return "drafts";
|
||||
return join3("drafts", sanitizeSlug(d, "misc"));
|
||||
return join4("drafts", sanitizeSlug(d, "misc"));
|
||||
}
|
||||
function refDir(area, device) {
|
||||
if (!REF_AREAS.includes(area)) {
|
||||
|
|
@ -991,9 +1160,9 @@ function refDir(area, device) {
|
|||
if (!host) {
|
||||
throw new Error("refs/devices requires device (host_name)");
|
||||
}
|
||||
return join3("refs", "devices", host);
|
||||
return join4("refs", "devices", host);
|
||||
}
|
||||
return join3("refs", area);
|
||||
return join4("refs", area);
|
||||
}
|
||||
|
||||
// src/netx/kb-context-skill.ts
|
||||
|
|
@ -1086,8 +1255,8 @@ function registerKbContextSkill(ctx, snapshot) {
|
|||
}
|
||||
|
||||
// src/netx/kb-manifest.ts
|
||||
import { existsSync as existsSync3, readdirSync, readFileSync, statSync as statSync2 } from "node:fs";
|
||||
import { basename, dirname as dirname2, join as join4, resolve as resolve2 } from "node:path";
|
||||
import { existsSync as existsSync4, readdirSync, readFileSync as readFileSync2, statSync as statSync2 } from "node:fs";
|
||||
import { basename, dirname as dirname3, join as join5, resolve as resolve2 } from "node:path";
|
||||
var EMPTY_CONTENT = {
|
||||
hasRegions: false,
|
||||
hasTheory: false,
|
||||
|
|
@ -1140,8 +1309,8 @@ function findManifest(kbRoot, maxDepth = 3) {
|
|||
if (!rootStat.isDirectory()) {
|
||||
return { paths: [], error: `kbRoot is not a directory: ${root}` };
|
||||
}
|
||||
const direct = join4(root, "MANIFEST.json");
|
||||
if (existsSync3(direct)) {
|
||||
const direct = join5(root, "MANIFEST.json");
|
||||
if (existsSync4(direct)) {
|
||||
try {
|
||||
if (statSync2(direct).isFile())
|
||||
return { paths: [direct] };
|
||||
|
|
@ -1151,8 +1320,8 @@ function findManifest(kbRoot, maxDepth = 3) {
|
|||
const walk = (dir, depth) => {
|
||||
if (depth > maxDepth)
|
||||
return;
|
||||
const candidate = join4(dir, "MANIFEST.json");
|
||||
if (existsSync3(candidate)) {
|
||||
const candidate = join5(dir, "MANIFEST.json");
|
||||
if (existsSync4(candidate)) {
|
||||
try {
|
||||
if (statSync2(candidate).isFile())
|
||||
found.push(candidate);
|
||||
|
|
@ -1169,7 +1338,7 @@ function findManifest(kbRoot, maxDepth = 3) {
|
|||
for (const name of entries) {
|
||||
if (name === "node_modules" || name === ".git")
|
||||
continue;
|
||||
const full = join4(dir, name);
|
||||
const full = join5(dir, name);
|
||||
let st;
|
||||
try {
|
||||
st = statSync2(full);
|
||||
|
|
@ -1189,7 +1358,7 @@ function findManifest(kbRoot, maxDepth = 3) {
|
|||
for (const name of topEntries) {
|
||||
if (name === "node_modules" || name === ".git")
|
||||
continue;
|
||||
const full = join4(root, name);
|
||||
const full = join5(root, name);
|
||||
let st;
|
||||
try {
|
||||
st = statSync2(full);
|
||||
|
|
@ -1285,7 +1454,7 @@ function resolveKbRoot(kbRoot, maxDepth = 3) {
|
|||
const st = statSync2(root);
|
||||
if (st.isFile()) {
|
||||
if (basename(root).toLowerCase() === "manifest.json") {
|
||||
root = dirname2(root);
|
||||
root = dirname3(root);
|
||||
} else {
|
||||
return errorSnapshot(`kbRoot is not a directory: ${root}`);
|
||||
}
|
||||
|
|
@ -1307,7 +1476,7 @@ function resolveKbRoot(kbRoot, maxDepth = 3) {
|
|||
const manifestPath = located.paths[0];
|
||||
let raw;
|
||||
try {
|
||||
raw = readFileSync(manifestPath, "utf8");
|
||||
raw = readFileSync2(manifestPath, "utf8");
|
||||
} catch (error) {
|
||||
return errorSnapshot(`cannot read MANIFEST: ${error instanceof Error ? error.message : String(error)}`);
|
||||
}
|
||||
|
|
@ -1315,7 +1484,7 @@ function resolveKbRoot(kbRoot, maxDepth = 3) {
|
|||
const parsed = parseManifest(raw);
|
||||
return {
|
||||
status: "configured",
|
||||
realRoot: dirname2(manifestPath),
|
||||
realRoot: dirname3(manifestPath),
|
||||
operatorName: parsed.operatorName,
|
||||
country: parsed.country,
|
||||
version: parsed.version,
|
||||
|
|
@ -1333,15 +1502,15 @@ import { defineTool } from "@deepseek-ai/dsh-tools";
|
|||
|
||||
// src/netx/kb-local-ops.ts
|
||||
import {
|
||||
existsSync as existsSync4,
|
||||
mkdirSync,
|
||||
existsSync as existsSync5,
|
||||
mkdirSync as mkdirSync2,
|
||||
readdirSync as readdirSync2,
|
||||
readFileSync as readFileSync2,
|
||||
rmSync,
|
||||
readFileSync as readFileSync3,
|
||||
rmSync as rmSync2,
|
||||
statSync as statSync3,
|
||||
writeFileSync
|
||||
writeFileSync as writeFileSync2
|
||||
} from "node:fs";
|
||||
import { dirname as dirname3, join as join5 } from "node:path";
|
||||
import { dirname as dirname4, join as join6 } from "node:path";
|
||||
function requireLocalRoot(snapshot) {
|
||||
const root = resolveKbLocalRoot(snapshot);
|
||||
if (!root) {
|
||||
|
|
@ -1387,12 +1556,12 @@ function createMemory(snapshot, args) {
|
|||
const localRoot = requireLocalRoot(snapshot);
|
||||
const name = memoryFileName({ date: args.date, slug: args.slug });
|
||||
const target = resolveWritableLocalPath(localRoot, memoryDir(args.bucket), name);
|
||||
if (existsSync4(target.absolutePath) && !args.overwrite) {
|
||||
if (existsSync5(target.absolutePath) && !args.overwrite) {
|
||||
throw new Error(`file already exists (pass overwrite=true to replace): ${target.relativePath}`);
|
||||
}
|
||||
mkdirSync(dirname3(target.absolutePath), { recursive: true });
|
||||
const existed = existsSync4(target.absolutePath);
|
||||
writeFileSync(target.absolutePath, args.body.endsWith(`
|
||||
mkdirSync2(dirname4(target.absolutePath), { recursive: true });
|
||||
const existed = existsSync5(target.absolutePath);
|
||||
writeFileSync2(target.absolutePath, args.body.endsWith(`
|
||||
`) ? args.body : `${args.body}
|
||||
`, "utf8");
|
||||
return {
|
||||
|
|
@ -1406,12 +1575,12 @@ function createDraft(snapshot, args) {
|
|||
const localRoot = requireLocalRoot(snapshot);
|
||||
const name = draftFileName({ date: args.date, slug: args.slug });
|
||||
const target = resolveWritableLocalPath(localRoot, draftDir(args.domain), name);
|
||||
if (existsSync4(target.absolutePath) && !args.overwrite) {
|
||||
if (existsSync5(target.absolutePath) && !args.overwrite) {
|
||||
throw new Error(`file already exists (pass overwrite=true to replace): ${target.relativePath}`);
|
||||
}
|
||||
mkdirSync(dirname3(target.absolutePath), { recursive: true });
|
||||
const existed = existsSync4(target.absolutePath);
|
||||
writeFileSync(target.absolutePath, ensureDraftBody(args.body), "utf8");
|
||||
mkdirSync2(dirname4(target.absolutePath), { recursive: true });
|
||||
const existed = existsSync5(target.absolutePath);
|
||||
writeFileSync2(target.absolutePath, ensureDraftBody(args.body), "utf8");
|
||||
return {
|
||||
ok: true,
|
||||
action: existed ? "updated" : "created",
|
||||
|
|
@ -1423,12 +1592,12 @@ function createSuggestion(snapshot, args) {
|
|||
const localRoot = requireLocalRoot(snapshot);
|
||||
const name = suggestionFileName({ date: args.date, slug: args.slug });
|
||||
const target = resolveWritableLocalPath(localRoot, suggestionDir(args.kind), name);
|
||||
if (existsSync4(target.absolutePath) && !args.overwrite) {
|
||||
if (existsSync5(target.absolutePath) && !args.overwrite) {
|
||||
throw new Error(`file already exists (pass overwrite=true to replace): ${target.relativePath}`);
|
||||
}
|
||||
mkdirSync(dirname3(target.absolutePath), { recursive: true });
|
||||
const existed = existsSync4(target.absolutePath);
|
||||
writeFileSync(target.absolutePath, args.body.endsWith(`
|
||||
mkdirSync2(dirname4(target.absolutePath), { recursive: true });
|
||||
const existed = existsSync5(target.absolutePath);
|
||||
writeFileSync2(target.absolutePath, args.body.endsWith(`
|
||||
`) ? args.body : `${args.body}
|
||||
`, "utf8");
|
||||
return {
|
||||
|
|
@ -1442,12 +1611,12 @@ function createRef(snapshot, args) {
|
|||
const localRoot = requireLocalRoot(snapshot);
|
||||
const name = refFileName(args.slug);
|
||||
const target = resolveWritableLocalPath(localRoot, refDir(args.area, args.device), name);
|
||||
if (existsSync4(target.absolutePath) && !args.overwrite) {
|
||||
if (existsSync5(target.absolutePath) && !args.overwrite) {
|
||||
throw new Error(`file already exists (pass overwrite=true to replace): ${target.relativePath}`);
|
||||
}
|
||||
mkdirSync(dirname3(target.absolutePath), { recursive: true });
|
||||
const existed = existsSync4(target.absolutePath);
|
||||
writeFileSync(target.absolutePath, args.body.endsWith(`
|
||||
mkdirSync2(dirname4(target.absolutePath), { recursive: true });
|
||||
const existed = existsSync5(target.absolutePath);
|
||||
writeFileSync2(target.absolutePath, args.body.endsWith(`
|
||||
`) ? args.body : `${args.body}
|
||||
`, "utf8");
|
||||
return {
|
||||
|
|
@ -1460,13 +1629,13 @@ function createRef(snapshot, args) {
|
|||
function updateLocalFile(snapshot, args) {
|
||||
const localRoot = requireLocalRoot(snapshot);
|
||||
const target = resolveExistingWritableFile(localRoot, args.path);
|
||||
if (!existsSync4(target.absolutePath)) {
|
||||
if (!existsSync5(target.absolutePath)) {
|
||||
throw new Error(`file not found: ${target.relativePath}`);
|
||||
}
|
||||
const body = target.writableRoot === "drafts" ? ensureDraftBody(args.body) : args.body.endsWith(`
|
||||
`) ? args.body : `${args.body}
|
||||
`;
|
||||
writeFileSync(target.absolutePath, body, "utf8");
|
||||
writeFileSync2(target.absolutePath, body, "utf8");
|
||||
return {
|
||||
ok: true,
|
||||
action: "updated",
|
||||
|
|
@ -1477,10 +1646,10 @@ function updateLocalFile(snapshot, args) {
|
|||
function deleteLocalFile(snapshot, args) {
|
||||
const localRoot = requireLocalRoot(snapshot);
|
||||
const target = resolveExistingWritableFile(localRoot, args.path);
|
||||
if (!existsSync4(target.absolutePath)) {
|
||||
if (!existsSync5(target.absolutePath)) {
|
||||
throw new Error(`file not found: ${target.relativePath}`);
|
||||
}
|
||||
rmSync(target.absolutePath, { force: false });
|
||||
rmSync2(target.absolutePath, { force: false });
|
||||
return {
|
||||
ok: true,
|
||||
action: "deleted",
|
||||
|
|
@ -1498,7 +1667,7 @@ function walkFiles(dir, baseLocal, out) {
|
|||
for (const name of entries) {
|
||||
if (name === "." || name === "..")
|
||||
continue;
|
||||
const full = join5(dir, name);
|
||||
const full = join6(dir, name);
|
||||
let st;
|
||||
try {
|
||||
st = statSync3(full);
|
||||
|
|
@ -1523,7 +1692,7 @@ function listLocalFiles(snapshot, args = {}) {
|
|||
const roots = args.root && args.root !== "all" ? [args.root] : [...KB_LOCAL_WRITABLE_ROOTS];
|
||||
const entries = [];
|
||||
for (const r of roots) {
|
||||
walkFiles(join5(localRoot, r), localRoot, entries);
|
||||
walkFiles(join6(localRoot, r), localRoot, entries);
|
||||
}
|
||||
entries.sort((a, b) => b.mtimeMs - a.mtimeMs);
|
||||
const limit = Math.min(Math.max(args.limit ?? 50, 1), 200);
|
||||
|
|
@ -1771,19 +1940,19 @@ function registerKbLocalTools(ctx, snapshot = getKbContext()) {
|
|||
|
||||
// src/netx/kb-pack-skills.ts
|
||||
import { readdir as readdir2, stat as stat2 } from "node:fs/promises";
|
||||
import { join as join6 } from "node:path";
|
||||
import { join as join7 } from "node:path";
|
||||
function kbPackSkillsEnabled(snapshot) {
|
||||
return snapshot.status === "configured" && snapshot.content.hasSkills === true;
|
||||
}
|
||||
function resolveKbSkillsRoot(snapshot) {
|
||||
const rel = snapshot.paths.skills?.trim() || "_skills";
|
||||
return join6(snapshot.realRoot, rel);
|
||||
return join7(snapshot.realRoot, rel);
|
||||
}
|
||||
function resolveKbLocalSkillsRoot(snapshot) {
|
||||
const rel = snapshot.paths.localSkills?.trim();
|
||||
if (!rel)
|
||||
return null;
|
||||
return join6(snapshot.realRoot, rel);
|
||||
return join7(snapshot.realRoot, rel);
|
||||
}
|
||||
async function registerSkillsUnderRoot(ctx, skillsApi, root, provider, options) {
|
||||
let entries;
|
||||
|
|
@ -1799,7 +1968,7 @@ async function registerSkillsUnderRoot(ctx, skillsApi, root, provider, options)
|
|||
return [];
|
||||
const disposers = [];
|
||||
for (const entry of entries) {
|
||||
const full = join6(root, entry);
|
||||
const full = join7(root, entry);
|
||||
let isDir = false;
|
||||
try {
|
||||
isDir = (await stat2(full)).isDirectory();
|
||||
|
|
@ -2013,11 +2182,11 @@ function watchNetxConnection(listener) {
|
|||
}
|
||||
|
||||
// src/netx/session-export.ts
|
||||
import { homedir as homedir2, hostname as osHostname } from "node:os";
|
||||
import { homedir as homedir3, hostname as osHostname } from "node:os";
|
||||
|
||||
// node_modules/.pnpm/fflate@0.8.3/node_modules/fflate/esm/index.mjs
|
||||
import { createRequire as createRequire2 } from "module";
|
||||
var require2 = createRequire2("/");
|
||||
import { createRequire as createRequire3 } from "module";
|
||||
var require2 = createRequire3("/");
|
||||
var _a;
|
||||
var Worker;
|
||||
var isMarkedAsUntransferable;
|
||||
|
|
@ -5234,7 +5403,6 @@ var name = "netxops";
|
|||
var inject = ["credentials"];
|
||||
var NETXOPS_RPC_CHANNEL = "/netxops";
|
||||
var NETXOPS_SETTINGS_NAMESPACE = "netxops";
|
||||
var NETXOPS_PRESET_ID = "netxops";
|
||||
var DEFAULT_TOKEN_REF = "NETX_API_TOKEN";
|
||||
function vol(schema) {
|
||||
const candidate = schema;
|
||||
|
|
@ -5265,37 +5433,6 @@ var Config = z.object({
|
|||
groupKbInPreset: vol(z.boolean().default(true)),
|
||||
groupKbPublic: vol(z.boolean().default(false))
|
||||
});
|
||||
function packageRoot() {
|
||||
return join7(dirname4(fileURLToPath2(import.meta.url)), "..");
|
||||
}
|
||||
function resolveDshHome() {
|
||||
const fromEnv = process.env.DSH_HOME?.trim();
|
||||
if (fromEnv !== undefined && fromEnv.length > 0)
|
||||
return fromEnv;
|
||||
return join7(homedir3(), ".dsh");
|
||||
}
|
||||
function ensureAgentPresetInstalled(logger) {
|
||||
const src = join7(packageRoot(), "presets", NETXOPS_PRESET_ID);
|
||||
const composition = join7(src, "agent.cordis.yml");
|
||||
if (!existsSync5(composition)) {
|
||||
logger.warn("netxops: bundled preset missing at %s — skip user-preset install", src);
|
||||
return;
|
||||
}
|
||||
const destParent = join7(resolveDshHome(), ".agent-presets");
|
||||
const dest = join7(destParent, NETXOPS_PRESET_ID);
|
||||
try {
|
||||
mkdirSync2(destParent, { recursive: true });
|
||||
if (existsSync5(dest)) {
|
||||
rmSync2(dest, { recursive: true, force: true });
|
||||
}
|
||||
cpSync(src, dest, { recursive: true });
|
||||
writeFileSync2(join7(dest, ".dsh-netxops-managed"), `${new Date().toISOString()}
|
||||
`, "utf8");
|
||||
logger.info("netxops: agent preset installed at %s", dest);
|
||||
} catch (error) {
|
||||
logger.error("netxops: failed to install agent preset: %s", error);
|
||||
}
|
||||
}
|
||||
async function resolveToken(ctx, refName) {
|
||||
const hit = await ctx.credentials.resolve(credentialRef(refName));
|
||||
return hit?.value ?? "";
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue