mirror of
https://github.com/hansjone/netxops.git
synced 2026-10-09 02:40:45 +08:00
Ship prebuilt lib/index.js so GitHub installs load under node_modules.
Node refuses TypeScript stripping inside node_modules; point package main at the host bundle and document GitHub as the default install. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
0fcff2d45a
commit
0040de078c
4 changed files with 150 additions and 7 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -1,7 +1,8 @@
|
|||
node_modules/
|
||||
dist/
|
||||
# keep published client artifact; ignore other build junk under lib/
|
||||
# keep published host + client artifacts
|
||||
lib/*
|
||||
!lib/index.js
|
||||
!lib/client.js
|
||||
*.log
|
||||
.DS_Store
|
||||
|
|
|
|||
100
lib/index.js
Normal file
100
lib/index.js
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
// src/index.ts
|
||||
import z from "@deepseek-ai/schemastery";
|
||||
import { credentialRef } from "@deepseek-ai/dsh-credentials";
|
||||
import * as McpClient from "@deepseek-ai/dsh-mcp-client";
|
||||
var name = "netxops";
|
||||
var inject = ["tools"];
|
||||
var NETXOPS_SETTINGS_NAMESPACE = "netxops";
|
||||
var DEFAULT_TOKEN_REF = "NETX_API_TOKEN";
|
||||
var Config2 = z.object({
|
||||
apiUrl: z.string().default("http://127.0.0.1:8890"),
|
||||
lang: z.string().default("zh"),
|
||||
pythonCommand: z.string().default("python"),
|
||||
tokenCredentialRef: z.string().role("credential-ref").default(DEFAULT_TOKEN_REF),
|
||||
toolCallTimeoutMs: z.number().step(1).min(1000).default(120000),
|
||||
failOnStartupError: z.boolean().default(false)
|
||||
});
|
||||
async function resolveToken(ctx, refName) {
|
||||
const credentials = ctx.get("credentials");
|
||||
if (credentials === undefined)
|
||||
return "";
|
||||
const hit = await credentials.resolve(credentialRef(refName));
|
||||
return hit?.value ?? "";
|
||||
}
|
||||
function apply(ctx, config = Config2({})) {
|
||||
let source = () => config;
|
||||
let mcpFiber;
|
||||
let remounting = Promise.resolve();
|
||||
let generation = 0;
|
||||
const remount = () => {
|
||||
remounting = remounting.then(async () => {
|
||||
const gen = ++generation;
|
||||
const previous = mcpFiber;
|
||||
mcpFiber = undefined;
|
||||
if (previous !== undefined) {
|
||||
try {
|
||||
await previous.dispose();
|
||||
} catch (error) {
|
||||
ctx.logger.warn("netxops: disposing previous mcp-client failed: %s", error);
|
||||
}
|
||||
}
|
||||
if (gen !== generation)
|
||||
return;
|
||||
const current = source();
|
||||
const token = await resolveToken(ctx, current.tokenCredentialRef);
|
||||
if (gen !== generation)
|
||||
return;
|
||||
const mcpConfig = McpClient.Config({
|
||||
transport: "stdio",
|
||||
serverName: "netx",
|
||||
command: current.pythonCommand,
|
||||
args: ["-m", "netx_mcp"],
|
||||
env: {
|
||||
NETX_API_URL: current.apiUrl.replace(/\/$/, ""),
|
||||
NETX_API_TOKEN: token,
|
||||
NETX_LANG: current.lang
|
||||
},
|
||||
toolCallTimeoutMs: current.toolCallTimeoutMs,
|
||||
failOnStartupError: current.failOnStartupError
|
||||
});
|
||||
try {
|
||||
mcpFiber = await ctx.plugin(McpClient, mcpConfig);
|
||||
} catch (error) {
|
||||
ctx.logger.error("netxops: failed to mount mcp-client: %s", error);
|
||||
if (current.failOnStartupError)
|
||||
throw error;
|
||||
}
|
||||
}).catch((error) => {
|
||||
ctx.logger.error("netxops: remount error: %s", error);
|
||||
});
|
||||
};
|
||||
remount();
|
||||
ctx.inject(["settings"], (settingsCtx) => {
|
||||
settingsCtx.settings.installSection(ctx, NETXOPS_SETTINGS_NAMESPACE, Config2, config, {
|
||||
setSource: (current) => {
|
||||
source = current;
|
||||
},
|
||||
onChange: () => {
|
||||
remount();
|
||||
}
|
||||
});
|
||||
});
|
||||
ctx.on("credentials/reference-updated", (ref) => {
|
||||
if (String(ref) === source().tokenCredentialRef)
|
||||
remount();
|
||||
});
|
||||
ctx.effect(() => () => {
|
||||
generation += 1;
|
||||
const fiber = mcpFiber;
|
||||
mcpFiber = undefined;
|
||||
fiber?.dispose();
|
||||
}, "netxops: dispose mcp-client");
|
||||
}
|
||||
export {
|
||||
name,
|
||||
inject,
|
||||
apply,
|
||||
NETXOPS_SETTINGS_NAMESPACE,
|
||||
DEFAULT_TOKEN_REF,
|
||||
Config2 as Config
|
||||
};
|
||||
14
package.json
14
package.json
|
|
@ -1,18 +1,19 @@
|
|||
{
|
||||
"name": "dsh-netxops",
|
||||
"version": "0.1.4",
|
||||
"version": "0.1.5",
|
||||
"description": "DeepSeek Harness Netx Ops: host bridge + Plugins settings card + agent preset",
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
"private": false,
|
||||
"main": "./src/index.ts",
|
||||
"main": "./lib/index.js",
|
||||
"exports": {
|
||||
".": "./src/index.ts",
|
||||
".": "./lib/index.js",
|
||||
"./client": "./lib/client.js",
|
||||
"./package.json": "./package.json"
|
||||
},
|
||||
"files": [
|
||||
"src/",
|
||||
"lib/index.js",
|
||||
"lib/client.js",
|
||||
"presets/",
|
||||
"cordis.patch.yml",
|
||||
|
|
@ -39,9 +40,10 @@
|
|||
},
|
||||
"homepage": "https://github.com/hansjone/netxops#readme",
|
||||
"scripts": {
|
||||
"bundle": "bun run scripts/build-client.mjs"
|
||||
},
|
||||
"dsh": {
|
||||
"bundle": "bun run scripts/build-host.mjs && bun run scripts/build-client.mjs",
|
||||
"bundle:host": "bun run scripts/build-host.mjs",
|
||||
"bundle:client": "bun run scripts/build-client.mjs"
|
||||
}, "dsh": {
|
||||
"bundle": {
|
||||
"patch": "./cordis.patch.yml"
|
||||
},
|
||||
|
|
|
|||
40
scripts/build-host.mjs
Normal file
40
scripts/build-host.mjs
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
/**
|
||||
* Build lib/index.js (host Cordis plugin) for installs under node_modules.
|
||||
* Node refuses to strip TypeScript inside node_modules, so GitHub/npm installs
|
||||
* must ship prebuilt JS. Usage: bun run scripts/build-host.mjs
|
||||
*/
|
||||
import { mkdirSync, writeFileSync } from 'node:fs'
|
||||
import { dirname, join } from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
|
||||
const root = join(dirname(fileURLToPath(import.meta.url)), '..')
|
||||
const entry = join(root, 'src/index.ts')
|
||||
const outFile = join(root, 'lib', 'index.js')
|
||||
|
||||
const external = [
|
||||
'@deepseek-ai/cordis',
|
||||
'@deepseek-ai/schemastery',
|
||||
'@deepseek-ai/dsh-credentials',
|
||||
'@deepseek-ai/dsh-settings',
|
||||
'@deepseek-ai/dsh-mcp-client',
|
||||
'@deepseek-ai/dsh-tools',
|
||||
]
|
||||
|
||||
const result = await Bun.build({
|
||||
entrypoints: [entry],
|
||||
target: 'node',
|
||||
format: 'esm',
|
||||
sourcemap: 'none',
|
||||
minify: false,
|
||||
external,
|
||||
})
|
||||
|
||||
if (!result.success) {
|
||||
console.error(result.logs)
|
||||
throw new Error('Bun.build host failed')
|
||||
}
|
||||
|
||||
const text = await result.outputs[0].text()
|
||||
mkdirSync(dirname(outFile), { recursive: true })
|
||||
writeFileSync(outFile, text, 'utf8')
|
||||
console.log(`wrote ${outFile} (${text.length} bytes)`)
|
||||
Loading…
Add table
Add a link
Reference in a new issue