mirror of
https://github.com/hansjone/netxops.git
synced 2026-10-18 00:10: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/
|
node_modules/
|
||||||
dist/
|
dist/
|
||||||
# keep published client artifact; ignore other build junk under lib/
|
# keep published host + client artifacts
|
||||||
lib/*
|
lib/*
|
||||||
|
!lib/index.js
|
||||||
!lib/client.js
|
!lib/client.js
|
||||||
*.log
|
*.log
|
||||||
.DS_Store
|
.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",
|
"name": "dsh-netxops",
|
||||||
"version": "0.1.4",
|
"version": "0.1.5",
|
||||||
"description": "DeepSeek Harness Netx Ops: host bridge + Plugins settings card + agent preset",
|
"description": "DeepSeek Harness Netx Ops: host bridge + Plugins settings card + agent preset",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"private": false,
|
"private": false,
|
||||||
"main": "./src/index.ts",
|
"main": "./lib/index.js",
|
||||||
"exports": {
|
"exports": {
|
||||||
".": "./src/index.ts",
|
".": "./lib/index.js",
|
||||||
"./client": "./lib/client.js",
|
"./client": "./lib/client.js",
|
||||||
"./package.json": "./package.json"
|
"./package.json": "./package.json"
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
"src/",
|
"src/",
|
||||||
|
"lib/index.js",
|
||||||
"lib/client.js",
|
"lib/client.js",
|
||||||
"presets/",
|
"presets/",
|
||||||
"cordis.patch.yml",
|
"cordis.patch.yml",
|
||||||
|
|
@ -39,9 +40,10 @@
|
||||||
},
|
},
|
||||||
"homepage": "https://github.com/hansjone/netxops#readme",
|
"homepage": "https://github.com/hansjone/netxops#readme",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"bundle": "bun run scripts/build-client.mjs"
|
"bundle": "bun run scripts/build-host.mjs && bun run scripts/build-client.mjs",
|
||||||
},
|
"bundle:host": "bun run scripts/build-host.mjs",
|
||||||
"dsh": {
|
"bundle:client": "bun run scripts/build-client.mjs"
|
||||||
|
}, "dsh": {
|
||||||
"bundle": {
|
"bundle": {
|
||||||
"patch": "./cordis.patch.yml"
|
"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