mirror of
https://github.com/hansjone/netxops.git
synced 2026-10-20 06:33:18 +08:00
feat(skills): merge unavailable tools into footnote, bind cache to token, prune stale caches, warn on remote plain HTTP
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
056f2d4ea3
commit
05bfd97c6e
19 changed files with 1100 additions and 496 deletions
|
|
@ -1,5 +1,5 @@
|
|||
// src/netx/group-tools-plugin.ts
|
||||
import { readFileSync as readFileSync6 } from "node:fs";
|
||||
import { readFileSync as readFileSync7 } from "node:fs";
|
||||
import { dirname as dirname6, join as join11 } from "node:path";
|
||||
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
||||
|
||||
|
|
@ -267,6 +267,15 @@ function mcpContentText(content, fallback = "") {
|
|||
|
||||
// src/netx/skills-cache.ts
|
||||
import { createHash } from "node:crypto";
|
||||
import {
|
||||
existsSync,
|
||||
mkdirSync,
|
||||
readdirSync,
|
||||
readFileSync,
|
||||
rmSync,
|
||||
statSync,
|
||||
writeFileSync
|
||||
} from "node:fs";
|
||||
import { homedir } from "node:os";
|
||||
import { dirname, join } from "node:path";
|
||||
|
||||
|
|
@ -293,6 +302,7 @@ function normalizeApiUrl(raw) {
|
|||
}
|
||||
|
||||
// src/netx/skills-cache.ts
|
||||
var STALE_CACHE_MS = 30 * 24 * 60 * 60 * 1000;
|
||||
function dshHome() {
|
||||
const fromEnv = process.env.DSH_HOME?.trim();
|
||||
return fromEnv || join(homedir(), ".dsh");
|
||||
|
|
@ -305,9 +315,46 @@ function skillsCacheKey(apiUrl) {
|
|||
const base = normalizeSkillsApiUrl(apiUrl);
|
||||
return createHash("sha256").update(base).digest("hex").slice(0, 16);
|
||||
}
|
||||
function skillsCacheDir(apiUrl) {
|
||||
return join(dshHome(), "netxops-mcp-skills", skillsCacheKey(apiUrl));
|
||||
function cacheParent() {
|
||||
return join(dshHome(), "netxops-mcp-skills");
|
||||
}
|
||||
function skillsCacheDir(apiUrl) {
|
||||
return join(cacheParent(), skillsCacheKey(apiUrl));
|
||||
}
|
||||
function tokenFingerprint(token) {
|
||||
const raw = token.trim();
|
||||
return raw ? createHash("sha256").update(raw).digest("hex").slice(0, 16) : "";
|
||||
}
|
||||
function readMeta(root) {
|
||||
try {
|
||||
const meta = JSON.parse(readFileSync(join(root, ".meta.json"), "utf8"));
|
||||
return meta && typeof meta === "object" && !Array.isArray(meta) ? meta : null;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
function usableSkillsCacheDir(apiUrl, token) {
|
||||
if (!apiUrl.trim())
|
||||
return "";
|
||||
const root = skillsCacheDir(apiUrl);
|
||||
const pulledWith = readMeta(root)?.tokenFp;
|
||||
if (pulledWith && pulledWith !== tokenFingerprint(token))
|
||||
return "";
|
||||
return root;
|
||||
}
|
||||
function cachedUnavailableTools(root) {
|
||||
const raw = readMeta(root)?.unavailableTools;
|
||||
const out = {};
|
||||
if (!raw || typeof raw !== "object")
|
||||
return out;
|
||||
for (const group of CAPABILITY_GROUP_IDS) {
|
||||
const names = raw[group];
|
||||
if (Array.isArray(names))
|
||||
out[group] = names.filter((n) => typeof n === "string");
|
||||
}
|
||||
return out;
|
||||
}
|
||||
var summaryMemo = new Map;
|
||||
|
||||
// src/netx/mcp-store.ts
|
||||
var STORE_KEY = Symbol.for("dsh-netxops.mcp-catalog-store");
|
||||
|
|
@ -512,12 +559,12 @@ function disabledFootnote(names, lang) {
|
|||
const en = (lang ?? "").trim().toLowerCase().startsWith("en");
|
||||
return en ? `
|
||||
|
||||
## Disabled tools
|
||||
The following tools are disabled: ${list}. Do not call them.
|
||||
## Unavailable tools
|
||||
The following tools are disabled or not granted to this token: ${list}. Do not call them; skip steps that need them.
|
||||
` : `
|
||||
|
||||
## 已禁用工具
|
||||
以下工具已禁用:${list},不要调用。
|
||||
## 不可用工具
|
||||
以下工具已禁用或当前 token 无权使用:${list},不要调用,涉及它们的步骤请跳过。
|
||||
`;
|
||||
}
|
||||
function resolveSkillsRoot(options) {
|
||||
|
|
@ -527,7 +574,7 @@ function resolveSkillsRoot(options) {
|
|||
const connection = getNetxConnection();
|
||||
if (!connection?.apiUrl?.trim())
|
||||
return "";
|
||||
return skillsCacheDir(connection.apiUrl);
|
||||
return usableSkillsCacheDir(connection.apiUrl, connection.token ?? "");
|
||||
}
|
||||
async function registerGroupSkills(ctx, groupIds, providerLabel, signalOrOptions) {
|
||||
const options = signalOrOptions instanceof AbortSignal || signalOrOptions === undefined ? { signal: signalOrOptions } : signalOrOptions;
|
||||
|
|
@ -546,6 +593,7 @@ async function registerGroupSkills(ctx, groupIds, providerLabel, signalOrOptions
|
|||
}
|
||||
return () => {};
|
||||
}
|
||||
const unavailable = cachedUnavailableTools(root);
|
||||
try {
|
||||
for (const groupId of CAPABILITY_GROUP_IDS) {
|
||||
if (!enabled.has(groupId))
|
||||
|
|
@ -559,7 +607,11 @@ async function registerGroupSkills(ctx, groupIds, providerLabel, signalOrOptions
|
|||
if (skills.length === 0) {
|
||||
log?.warn?.("%s: no skills loaded for group=%s from %s", providerLabel, groupId, join2(root, SKILL_DIR_BY_GROUP[groupId]));
|
||||
}
|
||||
const footnote = disabledFootnote(options.disabledByGroup?.[groupId] ?? [], options.lang);
|
||||
const offNames = new Set([
|
||||
...options.disabledByGroup?.[groupId] ?? [],
|
||||
...(unavailable[groupId] ?? []).map(publicToolName)
|
||||
]);
|
||||
const footnote = disabledFootnote([...offNames].sort(), options.lang);
|
||||
for (const skill of skills) {
|
||||
const base = groupId === "topology" ? `${skill.content}
|
||||
|
||||
|
|
@ -593,11 +645,11 @@ Use only tools present in this session. Dual-unit/orbit/polish recipes require s
|
|||
}
|
||||
|
||||
// src/netx/kb-context-skill.ts
|
||||
import { readdirSync as readdirSync2, readFileSync as readFileSync2, statSync as statSync3 } from "node:fs";
|
||||
import { readdirSync as readdirSync3, readFileSync as readFileSync3, statSync as statSync4 } from "node:fs";
|
||||
import { join as join5 } from "node:path";
|
||||
|
||||
// src/netx/kb-manifest.ts
|
||||
import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
|
||||
import { existsSync as existsSync2, readdirSync as readdirSync2, readFileSync as readFileSync2, statSync as statSync2 } from "node:fs";
|
||||
import { basename, dirname as dirname2, join as join3, resolve } from "node:path";
|
||||
var EMPTY_CONTENT = {
|
||||
hasRegions: false,
|
||||
|
|
@ -624,7 +676,7 @@ function resolveKbPaths(snapshot) {
|
|||
const paths = { skills: "_skills", ...snapshot.paths };
|
||||
return Object.entries(paths).filter((entry) => typeof entry[1] === "string" && entry[1].trim() !== "").map(([key, rel]) => {
|
||||
const absolute = resolve(snapshot.realRoot, rel);
|
||||
return { key, relative: rel, absolute, exists: existsSync(absolute) };
|
||||
return { key, relative: rel, absolute, exists: existsSync2(absolute) };
|
||||
});
|
||||
}
|
||||
function renderKbPathTable(snapshot) {
|
||||
|
|
@ -640,7 +692,7 @@ function renderKbPathTable(snapshot) {
|
|||
}
|
||||
|
||||
// src/netx/kb-local-path.ts
|
||||
import { existsSync as existsSync2, realpathSync, statSync as statSync2 } from "node:fs";
|
||||
import { existsSync as existsSync3, realpathSync, statSync as statSync3 } from "node:fs";
|
||||
import { join as join4, relative, resolve as resolve2, sep } from "node:path";
|
||||
var KB_LOCAL_WRITABLE_ROOTS = Object.freeze([
|
||||
"memories",
|
||||
|
|
@ -749,7 +801,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);
|
||||
|
|
@ -760,7 +812,7 @@ function resolveExistingWritableFile(localRoot, pathArg) {
|
|||
if (!KB_LOCAL_WRITABLE_ROOTS.includes(top)) {
|
||||
throw new Error(`path not under writable roots: ${realRel}`);
|
||||
}
|
||||
if (!statSync2(realFile).isFile()) {
|
||||
if (!statSync3(realFile).isFile()) {
|
||||
throw new Error(`not a file: ${realFile}`);
|
||||
}
|
||||
return {
|
||||
|
|
@ -813,7 +865,7 @@ function readKbIdentity(snapshot) {
|
|||
const dir = join5(localRoot, "identity");
|
||||
let names;
|
||||
try {
|
||||
names = readdirSync2(dir).filter((name) => /\.md$/i.test(name) && !/^readme\.md$/i.test(name)).sort();
|
||||
names = readdirSync3(dir).filter((name) => /\.md$/i.test(name) && !/^readme\.md$/i.test(name)).sort();
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
|
|
@ -825,9 +877,9 @@ function readKbIdentity(snapshot) {
|
|||
const full = join5(dir, name);
|
||||
let text;
|
||||
try {
|
||||
if (!statSync3(full).isFile())
|
||||
if (!statSync4(full).isFile())
|
||||
continue;
|
||||
text = readFileSync2(full, "utf8").replace(/^\uFEFF/, "").trim();
|
||||
text = readFileSync3(full, "utf8").replace(/^\uFEFF/, "").trim();
|
||||
} catch {
|
||||
continue;
|
||||
}
|
||||
|
|
@ -950,13 +1002,13 @@ import { defineTool } from "@deepseek-ai/dsh-tools";
|
|||
|
||||
// src/netx/kb-local-ops.ts
|
||||
import {
|
||||
existsSync as existsSync3,
|
||||
mkdirSync,
|
||||
readdirSync as readdirSync3,
|
||||
readFileSync as readFileSync3,
|
||||
rmSync,
|
||||
statSync as statSync4,
|
||||
writeFileSync
|
||||
existsSync as existsSync4,
|
||||
mkdirSync as mkdirSync2,
|
||||
readdirSync as readdirSync4,
|
||||
readFileSync as readFileSync4,
|
||||
rmSync as rmSync2,
|
||||
statSync as statSync5,
|
||||
writeFileSync as writeFileSync2
|
||||
} from "node:fs";
|
||||
import { dirname as dirname3, join as join6 } from "node:path";
|
||||
function requireLocalRoot(snapshot) {
|
||||
|
|
@ -1004,12 +1056,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 (existsSync3(target.absolutePath) && !args.overwrite) {
|
||||
if (existsSync4(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 = existsSync3(target.absolutePath);
|
||||
writeFileSync(target.absolutePath, args.body.endsWith(`
|
||||
mkdirSync2(dirname3(target.absolutePath), { recursive: true });
|
||||
const existed = existsSync4(target.absolutePath);
|
||||
writeFileSync2(target.absolutePath, args.body.endsWith(`
|
||||
`) ? args.body : `${args.body}
|
||||
`, "utf8");
|
||||
return {
|
||||
|
|
@ -1023,12 +1075,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 (existsSync3(target.absolutePath) && !args.overwrite) {
|
||||
if (existsSync4(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 = existsSync3(target.absolutePath);
|
||||
writeFileSync(target.absolutePath, ensureDraftBody(args.body), "utf8");
|
||||
mkdirSync2(dirname3(target.absolutePath), { recursive: true });
|
||||
const existed = existsSync4(target.absolutePath);
|
||||
writeFileSync2(target.absolutePath, ensureDraftBody(args.body), "utf8");
|
||||
return {
|
||||
ok: true,
|
||||
action: existed ? "updated" : "created",
|
||||
|
|
@ -1040,12 +1092,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 (existsSync3(target.absolutePath) && !args.overwrite) {
|
||||
if (existsSync4(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 = existsSync3(target.absolutePath);
|
||||
writeFileSync(target.absolutePath, args.body.endsWith(`
|
||||
mkdirSync2(dirname3(target.absolutePath), { recursive: true });
|
||||
const existed = existsSync4(target.absolutePath);
|
||||
writeFileSync2(target.absolutePath, args.body.endsWith(`
|
||||
`) ? args.body : `${args.body}
|
||||
`, "utf8");
|
||||
return {
|
||||
|
|
@ -1059,12 +1111,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 (existsSync3(target.absolutePath) && !args.overwrite) {
|
||||
if (existsSync4(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 = existsSync3(target.absolutePath);
|
||||
writeFileSync(target.absolutePath, args.body.endsWith(`
|
||||
mkdirSync2(dirname3(target.absolutePath), { recursive: true });
|
||||
const existed = existsSync4(target.absolutePath);
|
||||
writeFileSync2(target.absolutePath, args.body.endsWith(`
|
||||
`) ? args.body : `${args.body}
|
||||
`, "utf8");
|
||||
return {
|
||||
|
|
@ -1077,13 +1129,13 @@ function createRef(snapshot, args) {
|
|||
function updateLocalFile(snapshot, args) {
|
||||
const localRoot = requireLocalRoot(snapshot);
|
||||
const target = resolveExistingWritableFile(localRoot, args.path);
|
||||
if (!existsSync3(target.absolutePath)) {
|
||||
if (!existsSync4(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",
|
||||
|
|
@ -1094,10 +1146,10 @@ function updateLocalFile(snapshot, args) {
|
|||
function deleteLocalFile(snapshot, args) {
|
||||
const localRoot = requireLocalRoot(snapshot);
|
||||
const target = resolveExistingWritableFile(localRoot, args.path);
|
||||
if (!existsSync3(target.absolutePath)) {
|
||||
if (!existsSync4(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",
|
||||
|
|
@ -1108,7 +1160,7 @@ function deleteLocalFile(snapshot, args) {
|
|||
function walkFiles(dir, baseLocal, out) {
|
||||
let entries;
|
||||
try {
|
||||
entries = readdirSync3(dir);
|
||||
entries = readdirSync4(dir);
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
|
|
@ -1118,7 +1170,7 @@ function walkFiles(dir, baseLocal, out) {
|
|||
const full = join6(dir, name);
|
||||
let st;
|
||||
try {
|
||||
st = statSync4(full);
|
||||
st = statSync5(full);
|
||||
} catch {
|
||||
continue;
|
||||
}
|
||||
|
|
@ -1152,7 +1204,7 @@ function listLocalFiles(snapshot, args = {}) {
|
|||
}
|
||||
|
||||
// src/netx/kb-read-ops.ts
|
||||
import { readdirSync as readdirSync4, readFileSync as readFileSync4, realpathSync as realpathSync2, statSync as statSync5 } from "node:fs";
|
||||
import { readdirSync as readdirSync5, readFileSync as readFileSync5, realpathSync as realpathSync2, statSync as statSync6 } from "node:fs";
|
||||
import { extname, join as join7, relative as relative2, resolve as resolve3, sep as sep2 } from "node:path";
|
||||
var TEXT_EXTENSIONS = new Set([".md", ".markdown", ".txt", ".json", ".yml", ".yaml", ".csv", ".ps1", ".sh", ".cfg", ".conf", ".log"]);
|
||||
var SKIP_DIRS = new Set([".git", "node_modules"]);
|
||||
|
|
@ -1197,14 +1249,14 @@ function resolveKbReadPath(snapshot, pathArg) {
|
|||
}
|
||||
function readKbFile(snapshot, args) {
|
||||
const target = resolveKbReadPath(snapshot, args.path);
|
||||
const st = statSync5(target.absolutePath);
|
||||
const st = statSync6(target.absolutePath);
|
||||
if (st.isDirectory()) {
|
||||
const entries = readdirSync4(target.absolutePath, { withFileTypes: true }).filter((entry) => !SKIP_DIRS.has(entry.name)).map((entry) => {
|
||||
const entries = readdirSync5(target.absolutePath, { withFileTypes: true }).filter((entry) => !SKIP_DIRS.has(entry.name)).map((entry) => {
|
||||
if (entry.isDirectory())
|
||||
return { name: entry.name, type: "dir" };
|
||||
let size;
|
||||
try {
|
||||
size = statSync5(join7(target.absolutePath, entry.name)).size;
|
||||
size = statSync6(join7(target.absolutePath, entry.name)).size;
|
||||
} catch {}
|
||||
return { name: entry.name, type: "file", size };
|
||||
}).sort((a, b) => a.type === b.type ? a.name.localeCompare(b.name) : a.type === "dir" ? -1 : 1);
|
||||
|
|
@ -1213,7 +1265,7 @@ function readKbFile(snapshot, args) {
|
|||
if (!TEXT_EXTENSIONS.has(extname(target.absolutePath).toLowerCase())) {
|
||||
throw new Error(`not a text KB file: ${target.relativePath}`);
|
||||
}
|
||||
const lines = readFileSync4(target.absolutePath, "utf8").replace(/^\uFEFF/, "").replace(/\r\n?/g, `
|
||||
const lines = readFileSync5(target.absolutePath, "utf8").replace(/^\uFEFF/, "").replace(/\r\n?/g, `
|
||||
`).split(`
|
||||
`);
|
||||
const start = Math.max(1, Math.floor(args.offset ?? 1));
|
||||
|
|
@ -1258,7 +1310,7 @@ function cachedText(path, mtimeMs, size) {
|
|||
const hit = cache.files.get(path);
|
||||
if (hit && hit.mtimeMs === mtimeMs && hit.size === size)
|
||||
return hit;
|
||||
const text = readFileSync4(path, "utf8").replace(/^\uFEFF/, "");
|
||||
const text = readFileSync5(path, "utf8").replace(/^\uFEFF/, "");
|
||||
if (hit)
|
||||
cache.chars -= hit.text.length;
|
||||
if (cache.chars + text.length > CACHE_MAX_CHARS) {
|
||||
|
|
@ -1273,7 +1325,7 @@ function cachedText(path, mtimeMs, size) {
|
|||
function walkTextFiles(dir, out) {
|
||||
let entries;
|
||||
try {
|
||||
entries = readdirSync4(dir, { withFileTypes: true });
|
||||
entries = readdirSync5(dir, { withFileTypes: true });
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
|
|
@ -1288,7 +1340,7 @@ function walkTextFiles(dir, out) {
|
|||
if (!entry.isFile() || !TEXT_EXTENSIONS.has(extname(entry.name).toLowerCase()))
|
||||
continue;
|
||||
try {
|
||||
const st = statSync5(full);
|
||||
const st = statSync6(full);
|
||||
if (st.size <= SEARCH_MAX_FILE_BYTES)
|
||||
out.push({ path: full, mtimeMs: st.mtimeMs, size: st.size });
|
||||
} catch {}
|
||||
|
|
@ -1318,7 +1370,7 @@ function searchKb(snapshot, args) {
|
|||
const files = [];
|
||||
const seen = new Set;
|
||||
for (const dir of dirs) {
|
||||
const st = statSync5(dir);
|
||||
const st = statSync6(dir);
|
||||
const batch = [];
|
||||
if (st.isFile())
|
||||
batch.push({ path: dir, mtimeMs: st.mtimeMs, size: st.size });
|
||||
|
|
@ -1432,7 +1484,7 @@ function toLosslessJson(value) {
|
|||
}
|
||||
|
||||
// src/netx/tool-mount-status.ts
|
||||
import { mkdirSync as mkdirSync2, writeFileSync as writeFileSync2 } from "node:fs";
|
||||
import { mkdirSync as mkdirSync3, writeFileSync as writeFileSync3 } from "node:fs";
|
||||
import { homedir as homedir2 } from "node:os";
|
||||
import { dirname as dirname4, join as join8 } from "node:path";
|
||||
var KEY = Symbol.for("dsh-netxops.mount-inventory");
|
||||
|
|
@ -1459,8 +1511,8 @@ function getToolMountStatus() {
|
|||
function persist() {
|
||||
try {
|
||||
const path = join8(process.env.DSH_HOME?.trim() || join8(homedir2(), ".dsh"), "netxops-mount-status.json");
|
||||
mkdirSync2(dirname4(path), { recursive: true });
|
||||
writeFileSync2(path, `${JSON.stringify({ mount: getToolMountStatus() ?? null, mounts: getToolMountStatuses() }, null, 2)}
|
||||
mkdirSync3(dirname4(path), { recursive: true });
|
||||
writeFileSync3(path, `${JSON.stringify({ mount: getToolMountStatus() ?? null, mounts: getToolMountStatuses() }, null, 2)}
|
||||
`, "utf8");
|
||||
} catch {}
|
||||
}
|
||||
|
|
@ -1811,7 +1863,7 @@ async function registerKbPackSkills(ctx, snapshot, options) {
|
|||
}
|
||||
|
||||
// src/netx/tools.ts
|
||||
import { readFileSync as readFileSync5 } from "node:fs";
|
||||
import { readFileSync as readFileSync6 } from "node:fs";
|
||||
import { dirname as dirname5, join as join10 } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { defineTool as defineTool2 } from "@deepseek-ai/dsh-tools";
|
||||
|
|
@ -1916,7 +1968,7 @@ function parametersFromInputSchema(schema) {
|
|||
function packageVersion() {
|
||||
try {
|
||||
const here = dirname5(fileURLToPath(import.meta.url));
|
||||
const pkg = JSON.parse(readFileSync5(join10(here, "..", "package.json"), "utf8"));
|
||||
const pkg = JSON.parse(readFileSync6(join10(here, "..", "package.json"), "utf8"));
|
||||
return typeof pkg.version === "string" ? pkg.version : "0";
|
||||
} catch {
|
||||
return "0";
|
||||
|
|
@ -2048,7 +2100,7 @@ function registerNetxTools(ctx, connection, options) {
|
|||
function packageVersion2() {
|
||||
try {
|
||||
const here = dirname6(fileURLToPath2(import.meta.url));
|
||||
const pkg = JSON.parse(readFileSync6(join11(here, "..", "package.json"), "utf8"));
|
||||
const pkg = JSON.parse(readFileSync7(join11(here, "..", "package.json"), "utf8"));
|
||||
return typeof pkg.version === "string" ? pkg.version : "0";
|
||||
} catch {
|
||||
return "0";
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue