Fix client bundle to use react/jsx-runtime for DSH ModuleLoader.

The web shell only seeds jsx-runtime; Bun's default JSX emit left jsx-dev-runtime as an external and failed Plugins load.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
oliver 2026-09-04 22:36:01 +08:00
parent 0040de078c
commit e45657b1ee
3 changed files with 79 additions and 66 deletions

View file

@ -103,38 +103,38 @@ function ensureStyles() {
}
// src/client/NetxopsCard.tsx
var jsx_dev_runtime = require("react/jsx-dev-runtime");
var jsx_runtime = require("react/jsx-runtime");
function ValueField(props) {
return /* @__PURE__ */ jsx_dev_runtime.jsxDEV("div", {
return /* @__PURE__ */ jsx_runtime.jsxs("div", {
className: "dsh-nx-field",
children: [
/* @__PURE__ */ jsx_dev_runtime.jsxDEV("div", {
/* @__PURE__ */ jsx_runtime.jsxs("div", {
className: "dsh-nx-fieldHead",
children: [
/* @__PURE__ */ jsx_dev_runtime.jsxDEV("label", {
/* @__PURE__ */ jsx_runtime.jsx("label", {
className: "dsh-nx-label",
htmlFor: props.id,
children: props.label
}, undefined, false, undefined, this),
props.field.overridden ? /* @__PURE__ */ jsx_dev_runtime.jsxDEV("span", {
}),
props.field.overridden ? /* @__PURE__ */ jsx_runtime.jsxs("span", {
className: "dsh-nx-badges",
children: [
/* @__PURE__ */ jsx_dev_runtime.jsxDEV("span", {
/* @__PURE__ */ jsx_runtime.jsx("span", {
className: "dsh-nx-badge",
children: props.overriddenLabel
}, undefined, false, undefined, this),
/* @__PURE__ */ jsx_dev_runtime.jsxDEV("button", {
}),
/* @__PURE__ */ jsx_runtime.jsx("button", {
type: "button",
className: "dsh-nx-reset",
disabled: props.disabled,
onClick: props.onReset,
children: props.resetLabel
}, undefined, false, undefined, this)
})
]
}, undefined, true, undefined, this) : null
}) : null
]
}, undefined, true, undefined, this),
/* @__PURE__ */ jsx_dev_runtime.jsxDEV("input", {
}),
/* @__PURE__ */ jsx_runtime.jsx("input", {
id: props.id,
className: props.field.invalid ? "dsh-nx-input dsh-nx-inputInvalid" : "dsh-nx-input",
type: "text",
@ -144,13 +144,13 @@ function ValueField(props) {
onChange: (event) => {
props.onEdit(event.target.value);
}
}, undefined, false, undefined, this),
/* @__PURE__ */ jsx_dev_runtime.jsxDEV("p", {
}),
/* @__PURE__ */ jsx_runtime.jsx("p", {
className: props.field.invalid ? "dsh-nx-invalid" : "dsh-nx-hint",
children: props.field.invalid ? props.invalidLabel : props.hint
}, undefined, false, undefined, this)
})
]
}, undefined, true, undefined, this);
});
}
function NetxopsCard(props) {
ensureStyles();
@ -174,10 +174,10 @@ function NetxopsCard(props) {
const title = t("title");
const disabled = !state.writable;
const blocked = !state.dirty || state.invalid || state.saving;
return /* @__PURE__ */ jsx_dev_runtime.jsxDEV("li", {
return /* @__PURE__ */ jsx_runtime.jsxs("li", {
className: open ? "dsh-nx-card dsh-nx-cardOpen" : "dsh-nx-card",
children: [
/* @__PURE__ */ jsx_dev_runtime.jsxDEV("button", {
/* @__PURE__ */ jsx_runtime.jsxs("button", {
type: "button",
className: "dsh-nx-header",
"aria-expanded": open,
@ -186,59 +186,59 @@ function NetxopsCard(props) {
setOpen(!open);
},
children: [
/* @__PURE__ */ jsx_dev_runtime.jsxDEV("span", {
/* @__PURE__ */ jsx_runtime.jsxs("span", {
className: "dsh-nx-headText",
children: [
/* @__PURE__ */ jsx_dev_runtime.jsxDEV("span", {
/* @__PURE__ */ jsx_runtime.jsx("span", {
className: "dsh-nx-name",
children: title
}, undefined, false, undefined, this),
/* @__PURE__ */ jsx_dev_runtime.jsxDEV("span", {
}),
/* @__PURE__ */ jsx_runtime.jsx("span", {
className: "dsh-nx-desc",
children: t("description")
}, undefined, false, undefined, this)
})
]
}, undefined, true, undefined, this),
state.dirty ? /* @__PURE__ */ jsx_dev_runtime.jsxDEV("span", {
}),
state.dirty ? /* @__PURE__ */ jsx_runtime.jsx("span", {
className: "dsh-nx-pending",
children: t("unsaved")
}, undefined, false, undefined, this) : null,
/* @__PURE__ */ jsx_dev_runtime.jsxDEV("span", {
}) : null,
/* @__PURE__ */ jsx_runtime.jsx("span", {
className: open ? "dsh-nx-chevron dsh-nx-chevronOpen" : "dsh-nx-chevron",
"aria-hidden": true,
children: "▾"
}, undefined, false, undefined, this)
})
]
}, undefined, true, undefined, this),
open ? /* @__PURE__ */ jsx_dev_runtime.jsxDEV("div", {
}),
open ? /* @__PURE__ */ jsx_runtime.jsxs("div", {
className: "dsh-nx-body",
children: [
!state.writable ? /* @__PURE__ */ jsx_dev_runtime.jsxDEV("p", {
!state.writable ? /* @__PURE__ */ jsx_runtime.jsx("p", {
className: "dsh-nx-readOnly",
role: "status",
children: t("readOnly")
}, undefined, false, undefined, this) : null,
/* @__PURE__ */ jsx_dev_runtime.jsxDEV("div", {
}) : null,
/* @__PURE__ */ jsx_runtime.jsxs("div", {
className: "dsh-nx-field",
children: [
/* @__PURE__ */ jsx_dev_runtime.jsxDEV("div", {
/* @__PURE__ */ jsx_runtime.jsxs("div", {
className: "dsh-nx-fieldHead",
children: [
/* @__PURE__ */ jsx_dev_runtime.jsxDEV("label", {
/* @__PURE__ */ jsx_runtime.jsx("label", {
className: "dsh-nx-label",
htmlFor: "netxops-api-token",
children: t("apiToken")
}, undefined, false, undefined, this),
/* @__PURE__ */ jsx_dev_runtime.jsxDEV("span", {
}),
/* @__PURE__ */ jsx_runtime.jsx("span", {
className: "dsh-nx-badges",
children: /* @__PURE__ */ jsx_dev_runtime.jsxDEV("span", {
children: /* @__PURE__ */ jsx_runtime.jsx("span", {
className: state.apiTokenConfigured ? "dsh-nx-badge" : "dsh-nx-badgeMuted",
children: state.apiTokenConfigured ? t("apiTokenSet") : t("apiTokenUnset")
}, undefined, false, undefined, this)
}, undefined, false, undefined, this)
})
})
]
}, undefined, true, undefined, this),
/* @__PURE__ */ jsx_dev_runtime.jsxDEV("input", {
}),
/* @__PURE__ */ jsx_runtime.jsx("input", {
id: "netxops-api-token",
className: "dsh-nx-input",
type: "password",
@ -248,14 +248,14 @@ function NetxopsCard(props) {
onChange: (event) => {
props.edit("apiToken", event.target.value);
}
}, undefined, false, undefined, this),
/* @__PURE__ */ jsx_dev_runtime.jsxDEV("p", {
}),
/* @__PURE__ */ jsx_runtime.jsx("p", {
className: "dsh-nx-hint",
children: t("apiTokenHint")
}, undefined, false, undefined, this)
})
]
}, undefined, true, undefined, this),
/* @__PURE__ */ jsx_dev_runtime.jsxDEV(ValueField, {
}),
/* @__PURE__ */ jsx_runtime.jsx(ValueField, {
id: "netxops-api-url",
label: t("apiUrl"),
hint: t("apiUrlHint"),
@ -270,8 +270,8 @@ function NetxopsCard(props) {
onReset: () => {
props.resetField("apiUrl");
}
}, undefined, false, undefined, this),
/* @__PURE__ */ jsx_dev_runtime.jsxDEV(ValueField, {
}),
/* @__PURE__ */ jsx_runtime.jsx(ValueField, {
id: "netxops-lang",
label: t("lang"),
hint: t("langHint"),
@ -286,8 +286,8 @@ function NetxopsCard(props) {
onReset: () => {
props.resetField("lang");
}
}, undefined, false, undefined, this),
/* @__PURE__ */ jsx_dev_runtime.jsxDEV(ValueField, {
}),
/* @__PURE__ */ jsx_runtime.jsx(ValueField, {
id: "netxops-python",
label: t("pythonCommand"),
hint: t("pythonCommandHint"),
@ -302,35 +302,35 @@ function NetxopsCard(props) {
onReset: () => {
props.resetField("pythonCommand");
}
}, undefined, false, undefined, this),
/* @__PURE__ */ jsx_dev_runtime.jsxDEV("div", {
}),
/* @__PURE__ */ jsx_runtime.jsxs("div", {
className: "dsh-nx-footer",
children: [
state.failed ? /* @__PURE__ */ jsx_dev_runtime.jsxDEV("p", {
state.failed ? /* @__PURE__ */ jsx_runtime.jsx("p", {
className: "dsh-nx-failed",
role: "status",
children: t("saveFailed")
}, undefined, false, undefined, this) : null,
/* @__PURE__ */ jsx_dev_runtime.jsxDEV("button", {
}) : null,
/* @__PURE__ */ jsx_runtime.jsx("button", {
type: "button",
className: "dsh-nx-btn dsh-nx-discard",
disabled: !state.dirty || state.saving,
onClick: props.discard,
children: t("discard")
}, undefined, false, undefined, this),
/* @__PURE__ */ jsx_dev_runtime.jsxDEV("button", {
}),
/* @__PURE__ */ jsx_runtime.jsx("button", {
type: "button",
className: "dsh-nx-btn dsh-nx-save",
disabled: blocked,
onClick: props.save,
children: t(state.saving ? "saving" : "save")
}, undefined, false, undefined, this)
})
]
}, undefined, true, undefined, this)
})
]
}, undefined, true, undefined, this) : null
}) : null
]
}, undefined, true, undefined, this);
});
}
// src/client/card-form.ts

View file

@ -1,6 +1,6 @@
{
"name": "dsh-netxops",
"version": "0.1.5",
"version": "0.1.6",
"description": "DeepSeek Harness Netx Ops: host bridge + Plugins settings card + agent preset",
"license": "MIT",
"type": "module",

View file

@ -1,6 +1,9 @@
/**
* Build lib/client.js as a DSH ModuleLoader factory artifact using Bun's bundler.
* Usage: bun run scripts/build-client.mjs
*
* Must emit production JSX (`react/jsx-runtime`). The web shell seeds only that
* specifier — `react/jsx-dev-runtime` is not in PLATFORM_MODULES and fails load.
*/
import { mkdirSync, writeFileSync } from 'node:fs'
import { dirname, join } from 'node:path'
@ -11,10 +14,12 @@ const entry = join(root, 'src/client/index.ts')
const outFile = join(root, 'lib', 'client.js')
const id = 'dsh-netxops'
/** Align with @deepseek-ai/dsh-client-web PLATFORM_MODULES + dsh.client.inject. */
const external = [
'react',
'react/jsx-runtime',
'react/jsx-dev-runtime',
'react-dom',
'react-dom/client',
'@deepseek-ai/cordis',
'@deepseek-ai/dsh-client-store',
'@deepseek-ai/dsh-client-locale',
@ -39,6 +44,10 @@ const result = await Bun.build({
format: 'cjs',
sourcemap: 'none',
minify: false,
// Force production JSX transform (jsx-runtime, not jsx-dev-runtime).
define: {
'process.env.NODE_ENV': JSON.stringify('production'),
},
external,
})
@ -47,7 +56,11 @@ if (!result.success) {
throw new Error('Bun.build failed')
}
const raw = await result.outputs[0].text()
let raw = await result.outputs[0].text()
if (raw.includes('react/jsx-dev-runtime')) {
throw new Error('client bundle still references react/jsx-dev-runtime; refuse to ship')
}
const body = raw
.replace(/^"use strict";\s*/m, '')
.replace(/Object\.defineProperty\(exports,\s*"__esModule"[\s\S]*?;\s*/m, '')