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

View file

@ -1,6 +1,6 @@
{ {
"name": "dsh-netxops", "name": "dsh-netxops",
"version": "0.1.5", "version": "0.1.6",
"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",

View file

@ -1,6 +1,9 @@
/** /**
* Build lib/client.js as a DSH ModuleLoader factory artifact using Bun's bundler. * Build lib/client.js as a DSH ModuleLoader factory artifact using Bun's bundler.
* Usage: bun run scripts/build-client.mjs * 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 { mkdirSync, writeFileSync } from 'node:fs'
import { dirname, join } from 'node:path' 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 outFile = join(root, 'lib', 'client.js')
const id = 'dsh-netxops' const id = 'dsh-netxops'
/** Align with @deepseek-ai/dsh-client-web PLATFORM_MODULES + dsh.client.inject. */
const external = [ const external = [
'react', 'react',
'react/jsx-runtime', 'react/jsx-runtime',
'react/jsx-dev-runtime', 'react-dom',
'react-dom/client',
'@deepseek-ai/cordis', '@deepseek-ai/cordis',
'@deepseek-ai/dsh-client-store', '@deepseek-ai/dsh-client-store',
'@deepseek-ai/dsh-client-locale', '@deepseek-ai/dsh-client-locale',
@ -39,6 +44,10 @@ const result = await Bun.build({
format: 'cjs', format: 'cjs',
sourcemap: 'none', sourcemap: 'none',
minify: false, minify: false,
// Force production JSX transform (jsx-runtime, not jsx-dev-runtime).
define: {
'process.env.NODE_ENV': JSON.stringify('production'),
},
external, external,
}) })
@ -47,7 +56,11 @@ if (!result.success) {
throw new Error('Bun.build failed') 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 const body = raw
.replace(/^"use strict";\s*/m, '') .replace(/^"use strict";\s*/m, '')
.replace(/Object\.defineProperty\(exports,\s*"__esModule"[\s\S]*?;\s*/m, '') .replace(/Object\.defineProperty\(exports,\s*"__esModule"[\s\S]*?;\s*/m, '')