langchain_agentx_stream_ui 0.7.9 → 0.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -24,7 +24,7 @@ import {
24
24
  fixDiagramSvg,
25
25
  markEventIdSeen,
26
26
  shouldSkipDuplicateEvent
27
- } from "./chunk-AMUGAG7U.js";
27
+ } from "./chunk-MI4NGIDF.js";
28
28
  import {
29
29
  DefaultToolBody,
30
30
  InteractionBusContext,
@@ -121,7 +121,7 @@ import {
121
121
  useSessionStatus,
122
122
  useSessionViewOptions,
123
123
  useTimeline
124
- } from "./chunk-RWKNI52H.js";
124
+ } from "./chunk-XEIQBTD2.js";
125
125
  import {
126
126
  AGENT_PROGRESS_GUTTER,
127
127
  AGENT_PROGRESS_INDENT,
@@ -6134,6 +6134,639 @@ var DEMO_WORKFLOW_SCALE = {
6134
6134
  evictCompletedLoops: true
6135
6135
  };
6136
6136
 
6137
+ // src/view/mcp/McpPanel.tsx
6138
+ import {
6139
+ useCallback as useCallback6,
6140
+ useEffect as useEffect12,
6141
+ useRef as useRef6,
6142
+ useState as useState8
6143
+ } from "react";
6144
+ import { Fragment as Fragment5, jsx as jsx20, jsxs as jsxs17 } from "react/jsx-runtime";
6145
+ var STATE_META = {
6146
+ connecting: { icon: "\u27F3", label: "\u8FDE\u63A5\u4E2D", tone: "running" },
6147
+ connected: { icon: "\u25CF", label: "\u5DF2\u8FDE\u63A5", tone: "success" },
6148
+ failed: { icon: "\u2717", label: "\u8FDE\u63A5\u5931\u8D25", tone: "error" },
6149
+ disconnected: { icon: "\u25CB", label: "\u672A\u8FDE\u63A5", tone: "muted" },
6150
+ reconnecting: { icon: "\u27F3", label: "\u91CD\u8FDE\u4E2D", tone: "running" },
6151
+ needs_auth: { icon: "\u26A0", label: "\u9700\u8981\u9274\u6743", tone: "warning" },
6152
+ disabled: { icon: "\u2298", label: "\u5DF2\u505C\u7528", tone: "muted" }
6153
+ };
6154
+ var ADJ_META = {
6155
+ allowed: { icon: "\u2713", label: "\u5C06\u8FDB\u6C60", cls: "lax-mcp-adj--allowed" },
6156
+ denied: { icon: "\u2717", label: "\u88AB deny \u5265\u79BB", cls: "lax-mcp-adj--denied" },
6157
+ uncovered: { icon: "\u26A0", label: "\u672A\u8986\u76D6 \u2192 \u4E0D\u8FDB\u6C60", cls: "lax-mcp-adj--uncovered" }
6158
+ };
6159
+ var EMPTY_FORM = {
6160
+ name: "",
6161
+ transport: "stdio",
6162
+ command: "",
6163
+ argsText: "",
6164
+ envText: "",
6165
+ cwd: "",
6166
+ url: "",
6167
+ headersText: ""
6168
+ };
6169
+ function errorMessage(err) {
6170
+ return err instanceof Error ? err.message : String(err);
6171
+ }
6172
+ function splitLines(text) {
6173
+ return text.split("\n").map((line) => line.trim()).filter((line) => line.length > 0);
6174
+ }
6175
+ function parseKeyValueLines(text) {
6176
+ const lines = splitLines(text);
6177
+ if (lines.length === 0) return void 0;
6178
+ const record = {};
6179
+ for (const line of lines) {
6180
+ const eq = line.indexOf("=");
6181
+ if (eq <= 0) continue;
6182
+ record[line.slice(0, eq).trim()] = line.slice(eq + 1).trim();
6183
+ }
6184
+ return Object.keys(record).length > 0 ? record : void 0;
6185
+ }
6186
+ function toSpec(status) {
6187
+ return {
6188
+ name: status.name,
6189
+ transport: status.transport,
6190
+ command: status.command,
6191
+ args: status.args,
6192
+ env: status.env,
6193
+ cwd: status.cwd,
6194
+ url: status.url,
6195
+ headers: status.headers,
6196
+ enabled: status.enabled
6197
+ };
6198
+ }
6199
+ function buildSpec(form) {
6200
+ const spec = { name: form.name.trim(), transport: form.transport, enabled: true };
6201
+ if (form.transport === "stdio") {
6202
+ spec.command = form.command.trim();
6203
+ const args = form.argsText.trim().split(/\s+/).filter(Boolean);
6204
+ if (args.length > 0) spec.args = args;
6205
+ const env = parseKeyValueLines(form.envText);
6206
+ if (env) spec.env = env;
6207
+ if (form.cwd.trim()) spec.cwd = form.cwd.trim();
6208
+ } else {
6209
+ spec.url = form.url.trim();
6210
+ const headers = parseKeyValueLines(form.headersText);
6211
+ if (headers) spec.headers = headers;
6212
+ }
6213
+ return spec;
6214
+ }
6215
+ function McpPanel({ isOpen, onClose, client, demoServerSpec }) {
6216
+ const panelRef = useRef6(null);
6217
+ const [loading, setLoading] = useState8(true);
6218
+ const [loadError, setLoadError] = useState8(null);
6219
+ const [servers, setServers] = useState8([]);
6220
+ const [summary, setSummary] = useState8(null);
6221
+ const [allowText, setAllowText] = useState8("");
6222
+ const [denyText, setDenyText] = useState8("");
6223
+ const [rulesSaving, setRulesSaving] = useState8(false);
6224
+ const [rulesError, setRulesError] = useState8(null);
6225
+ const [toolsLoads, setToolsLoads] = useState8({});
6226
+ const [expanded, setExpanded] = useState8({});
6227
+ const [busy, setBusy] = useState8(null);
6228
+ const [formOpen, setFormOpen] = useState8(false);
6229
+ const [form, setForm] = useState8(EMPTY_FORM);
6230
+ const [formError, setFormError] = useState8(null);
6231
+ const refresh = useCallback6(
6232
+ async (showLoading = false) => {
6233
+ if (showLoading) setLoading(true);
6234
+ try {
6235
+ const [serversRes, summaryRes, rulesRes] = await Promise.all([
6236
+ client.listServers(),
6237
+ client.getSummary(),
6238
+ client.getRules()
6239
+ ]);
6240
+ setServers(serversRes.servers);
6241
+ setSummary(summaryRes);
6242
+ setAllowText(rulesRes.allow.join("\n"));
6243
+ setDenyText(rulesRes.deny.join("\n"));
6244
+ setLoadError(null);
6245
+ } catch (err) {
6246
+ setLoadError(errorMessage(err));
6247
+ } finally {
6248
+ if (showLoading) setLoading(false);
6249
+ }
6250
+ },
6251
+ [client]
6252
+ );
6253
+ const loadTools = useCallback6(
6254
+ async (name) => {
6255
+ setToolsLoads((prev) => ({ ...prev, [name]: { status: "loading", tools: [] } }));
6256
+ try {
6257
+ const res = await client.listTools(name);
6258
+ setToolsLoads((prev) => ({ ...prev, [name]: { status: "ok", tools: res.tools } }));
6259
+ } catch (err) {
6260
+ setToolsLoads((prev) => ({
6261
+ ...prev,
6262
+ [name]: { status: "error", error: errorMessage(err), tools: [] }
6263
+ }));
6264
+ }
6265
+ },
6266
+ [client]
6267
+ );
6268
+ useEffect12(() => {
6269
+ if (!isOpen) return;
6270
+ void refresh(true);
6271
+ const onKeyDown = (event) => {
6272
+ if (event.key === "Escape") onClose();
6273
+ };
6274
+ const prevOverflow = document.body.style.overflow;
6275
+ document.body.style.overflow = "hidden";
6276
+ window.addEventListener("keydown", onKeyDown);
6277
+ panelRef.current?.focus();
6278
+ return () => {
6279
+ window.removeEventListener("keydown", onKeyDown);
6280
+ document.body.style.overflow = prevOverflow;
6281
+ };
6282
+ }, [isOpen, refresh, onClose]);
6283
+ const trapTabFocus = (event) => {
6284
+ if (event.key !== "Tab" || panelRef.current === null) return;
6285
+ const focusables = Array.from(
6286
+ panelRef.current.querySelectorAll(
6287
+ "button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), a[href]"
6288
+ )
6289
+ ).filter((el) => el.offsetParent !== null);
6290
+ if (focusables.length === 0) return;
6291
+ const first = focusables[0];
6292
+ const last = focusables[focusables.length - 1];
6293
+ const active = document.activeElement;
6294
+ if (event.shiftKey && active === first) {
6295
+ event.preventDefault();
6296
+ last.focus();
6297
+ } else if (!event.shiftKey && active === last) {
6298
+ event.preventDefault();
6299
+ first.focus();
6300
+ }
6301
+ };
6302
+ const runAction = async (key, fn) => {
6303
+ if (busy !== null) return;
6304
+ setBusy(key);
6305
+ try {
6306
+ await fn();
6307
+ } catch (err) {
6308
+ setLoadError(errorMessage(err));
6309
+ } finally {
6310
+ setBusy(null);
6311
+ }
6312
+ };
6313
+ const saveServerList = (next, after) => runAction("put-servers", async () => {
6314
+ await client.putServers(next);
6315
+ after?.();
6316
+ await refresh();
6317
+ });
6318
+ const submitForm = () => {
6319
+ const spec = buildSpec(form);
6320
+ if (spec.name === "") {
6321
+ setFormError("name \u4E0D\u80FD\u4E3A\u7A7A");
6322
+ return;
6323
+ }
6324
+ if (servers.some((s) => s.name === spec.name)) {
6325
+ setFormError(`server "${spec.name}" \u5DF2\u5B58\u5728`);
6326
+ return;
6327
+ }
6328
+ if (spec.transport === "stdio" && !spec.command) {
6329
+ setFormError("stdio server \u9700\u8981 command");
6330
+ return;
6331
+ }
6332
+ if (spec.transport !== "stdio" && !spec.url) {
6333
+ setFormError(`${spec.transport} server \u9700\u8981 url`);
6334
+ return;
6335
+ }
6336
+ setFormError(null);
6337
+ void saveServerList([...servers.map(toSpec), spec], () => {
6338
+ setFormOpen(false);
6339
+ setForm(EMPTY_FORM);
6340
+ });
6341
+ };
6342
+ const deleteServer = (name) => saveServerList(
6343
+ servers.filter((s) => s.name !== name).map(toSpec)
6344
+ );
6345
+ const toggleEnabled = (server) => runAction(`toggle:${server.name}`, async () => {
6346
+ if (server.enabled) await client.disconnectServer(server.name);
6347
+ else await client.connectServer(server.name);
6348
+ await refresh();
6349
+ });
6350
+ const reconnectServer = (name) => runAction(`reconnect:${name}`, async () => {
6351
+ await client.reconnectServer(name);
6352
+ await refresh();
6353
+ });
6354
+ const toggleTools = (name) => {
6355
+ const next = !expanded[name];
6356
+ setExpanded((prev) => ({ ...prev, [name]: next }));
6357
+ if (next && !toolsLoads[name]) void loadTools(name);
6358
+ };
6359
+ const saveRules = async () => {
6360
+ if (rulesSaving) return;
6361
+ setRulesSaving(true);
6362
+ setRulesError(null);
6363
+ try {
6364
+ const res = await client.putRules({ allow: splitLines(allowText), deny: splitLines(denyText) });
6365
+ setAllowText(res.allow.join("\n"));
6366
+ setDenyText(res.deny.join("\n"));
6367
+ setToolsLoads({});
6368
+ for (const name of Object.keys(expanded)) {
6369
+ if (expanded[name]) void loadTools(name);
6370
+ }
6371
+ await refresh();
6372
+ } catch (err) {
6373
+ setRulesError(errorMessage(err));
6374
+ } finally {
6375
+ setRulesSaving(false);
6376
+ }
6377
+ };
6378
+ if (!isOpen) return null;
6379
+ const toolsInPool = summary !== null ? summary.tools_total - summary.tools_blocked : null;
6380
+ return /* @__PURE__ */ jsx20(
6381
+ "div",
6382
+ {
6383
+ className: "lax-mcp-overlay",
6384
+ role: "dialog",
6385
+ "aria-modal": "true",
6386
+ "aria-label": "MCP Servers",
6387
+ "data-testid": "lax-mcp-overlay",
6388
+ onClick: (event) => {
6389
+ if (event.target === event.currentTarget) onClose();
6390
+ },
6391
+ children: /* @__PURE__ */ jsxs17(
6392
+ "div",
6393
+ {
6394
+ className: "lax-mcp-panel",
6395
+ ref: panelRef,
6396
+ tabIndex: -1,
6397
+ "data-testid": "lax-mcp-panel",
6398
+ onKeyDown: trapTabFocus,
6399
+ onClick: (event) => event.stopPropagation(),
6400
+ children: [
6401
+ /* @__PURE__ */ jsxs17("header", { className: "lax-mcp-header", children: [
6402
+ /* @__PURE__ */ jsx20("span", { className: "lax-mcp-title", children: "MCP Servers" }),
6403
+ /* @__PURE__ */ jsx20(
6404
+ "span",
6405
+ {
6406
+ className: `lax-mcp-ready${summary?.ready ? " is-ready" : " is-not-ready"}`,
6407
+ "aria-live": "polite",
6408
+ "data-testid": "lax-mcp-ready",
6409
+ children: summary?.ready ? "\u25CF \u5C31\u7EEA" : "\u26A0 \u672A\u5C31\u7EEA"
6410
+ }
6411
+ ),
6412
+ /* @__PURE__ */ jsx20("button", { type: "button", className: "lax-mcp-close", "aria-label": "\u5173\u95ED", onClick: onClose, children: "\xD7" })
6413
+ ] }),
6414
+ loadError !== null && /* @__PURE__ */ jsxs17("div", { className: "lax-mcp-error", role: "alert", "data-testid": "lax-mcp-error", children: [
6415
+ /* @__PURE__ */ jsx20("span", { className: "lax-mcp-error-text", children: loadError }),
6416
+ /* @__PURE__ */ jsx20("button", { type: "button", className: "lax-mcp-btn", onClick: () => void refresh(true), children: "\u91CD\u8BD5" })
6417
+ ] }),
6418
+ /* @__PURE__ */ jsx20("div", { className: "lax-mcp-body", children: loading ? /* @__PURE__ */ jsx20("div", { className: "lax-mcp-loading", "data-testid": "lax-mcp-loading", children: "\u52A0\u8F7D\u4E2D\u2026" }) : /* @__PURE__ */ jsxs17(Fragment5, { children: [
6419
+ /* @__PURE__ */ jsxs17("section", { className: "lax-mcp-section", "aria-label": "server \u914D\u7F6E", children: [
6420
+ /* @__PURE__ */ jsx20("div", { className: "lax-mcp-section-title", children: "\u2460 Server \u914D\u7F6E" }),
6421
+ /* @__PURE__ */ jsxs17("div", { className: "lax-mcp-config-actions", children: [
6422
+ /* @__PURE__ */ jsx20(
6423
+ "button",
6424
+ {
6425
+ type: "button",
6426
+ className: "lax-mcp-btn",
6427
+ onClick: () => {
6428
+ setFormOpen((v) => !v);
6429
+ setFormError(null);
6430
+ },
6431
+ children: "\uFF0B \u6DFB\u52A0 server"
6432
+ }
6433
+ ),
6434
+ demoServerSpec !== void 0 && /* @__PURE__ */ jsxs17(
6435
+ "button",
6436
+ {
6437
+ type: "button",
6438
+ className: "lax-mcp-btn",
6439
+ disabled: servers.some((s) => s.name === demoServerSpec.name),
6440
+ onClick: () => void saveServerList([...servers.map(toSpec), demoServerSpec]),
6441
+ children: [
6442
+ "\u26A1 \u6DFB\u52A0\u6F14\u793A server\uFF08",
6443
+ demoServerSpec.name,
6444
+ "\uFF09"
6445
+ ]
6446
+ }
6447
+ )
6448
+ ] }),
6449
+ formOpen && /* @__PURE__ */ jsx20(
6450
+ ServerForm,
6451
+ {
6452
+ form,
6453
+ setForm,
6454
+ error: formError,
6455
+ busy: busy !== null,
6456
+ onSubmit: submitForm,
6457
+ onCancel: () => {
6458
+ setFormOpen(false);
6459
+ setFormError(null);
6460
+ }
6461
+ }
6462
+ )
6463
+ ] }),
6464
+ /* @__PURE__ */ jsxs17("section", { className: "lax-mcp-section", "aria-label": "\u8FDE\u63A5\u72B6\u6001\u4E0E\u5DE5\u5177\u6E05\u5355", children: [
6465
+ /* @__PURE__ */ jsx20("div", { className: "lax-mcp-section-title", children: "\u2461 \u8FDE\u63A5\u72B6\u6001 / \u2462 \u5DE5\u5177\u6E05\u5355" }),
6466
+ servers.length === 0 ? /* @__PURE__ */ jsx20("div", { className: "lax-mcp-empty", "data-testid": "lax-mcp-empty", children: "\u5C1A\u672A\u914D\u7F6E MCP server" }) : servers.map((server) => /* @__PURE__ */ jsxs17("div", { className: "lax-mcp-server", "data-server": server.name, children: [
6467
+ /* @__PURE__ */ jsx20(
6468
+ McpServerRow,
6469
+ {
6470
+ server,
6471
+ busy: busy !== null,
6472
+ expanded: expanded[server.name] === true,
6473
+ onReconnect: () => reconnectServer(server.name),
6474
+ onToggleEnabled: () => toggleEnabled(server),
6475
+ onDelete: () => deleteServer(server.name),
6476
+ onToggleTools: () => toggleTools(server.name)
6477
+ }
6478
+ ),
6479
+ expanded[server.name] === true && /* @__PURE__ */ jsx20(ToolsGroup, { load: toolsLoads[server.name] })
6480
+ ] }, server.name))
6481
+ ] }),
6482
+ /* @__PURE__ */ jsxs17("section", { className: "lax-mcp-section", "aria-label": "\u89C4\u5219\u88C1\u51B3", children: [
6483
+ /* @__PURE__ */ jsx20("div", { className: "lax-mcp-section-title", children: "\u2463 \u89C4\u5219\u88C1\u51B3" }),
6484
+ /* @__PURE__ */ jsx20(
6485
+ McpRuleEditor,
6486
+ {
6487
+ allowText,
6488
+ denyText,
6489
+ onAllowChange: setAllowText,
6490
+ onDenyChange: setDenyText,
6491
+ saving: rulesSaving,
6492
+ error: rulesError,
6493
+ disabled: servers.length === 0,
6494
+ inPool: toolsInPool,
6495
+ total: summary?.tools_total ?? null,
6496
+ blocked: summary?.tools_blocked ?? null,
6497
+ onSave: () => void saveRules()
6498
+ }
6499
+ )
6500
+ ] })
6501
+ ] }) })
6502
+ ]
6503
+ }
6504
+ )
6505
+ }
6506
+ );
6507
+ }
6508
+ function McpServerRow(props) {
6509
+ const { server, busy, expanded, onReconnect, onToggleEnabled, onDelete, onToggleTools } = props;
6510
+ const meta = STATE_META[server.state];
6511
+ const rowBusy = server.state === "connecting" || server.state === "reconnecting";
6512
+ return /* @__PURE__ */ jsxs17("div", { className: `lax-mcp-server-row lax-mcp-server-row--${server.state}`, children: [
6513
+ /* @__PURE__ */ jsx20("span", { className: `lax-mcp-state-icon tone-${meta.tone}`, role: "img", "aria-label": meta.label, children: meta.icon }),
6514
+ /* @__PURE__ */ jsx20("span", { className: "lax-mcp-server-name", children: server.name }),
6515
+ /* @__PURE__ */ jsx20("span", { className: "lax-mcp-server-meta", children: server.transport }),
6516
+ /* @__PURE__ */ jsx20("span", { className: "lax-mcp-server-meta", children: server.state === "connected" ? server.tool_count === 0 ? "\u5DF2\u8FDE\u63A5 \xB7 \u672A\u66B4\u9732\u5DE5\u5177" : `${server.tool_count ?? "\u2013"} tool` : null }),
6517
+ /* @__PURE__ */ jsxs17("span", { className: "lax-mcp-server-actions", children: [
6518
+ /* @__PURE__ */ jsx20(
6519
+ "button",
6520
+ {
6521
+ type: "button",
6522
+ className: "lax-mcp-btn",
6523
+ disabled: busy || server.state !== "connected",
6524
+ "aria-expanded": expanded,
6525
+ onClick: onToggleTools,
6526
+ children: expanded ? "\u25BE \u5DE5\u5177" : "\u25B8 \u5DE5\u5177"
6527
+ }
6528
+ ),
6529
+ /* @__PURE__ */ jsx20("button", { type: "button", className: "lax-mcp-btn", disabled: busy || rowBusy, onClick: onReconnect, children: "\u21BB \u91CD\u8FDE" }),
6530
+ /* @__PURE__ */ jsx20(
6531
+ "button",
6532
+ {
6533
+ type: "button",
6534
+ className: "lax-mcp-btn",
6535
+ disabled: busy || rowBusy,
6536
+ onClick: onToggleEnabled,
6537
+ children: server.enabled ? "\u23FB \u505C\u7528" : "\u23FB \u542F\u7528"
6538
+ }
6539
+ ),
6540
+ /* @__PURE__ */ jsx20("button", { type: "button", className: "lax-mcp-btn", disabled: busy, onClick: onDelete, children: "\u{1F5D1} \u5220\u9664" }),
6541
+ server.state === "needs_auth" && /* @__PURE__ */ jsx20(
6542
+ "button",
6543
+ {
6544
+ type: "button",
6545
+ className: "lax-mcp-btn",
6546
+ disabled: true,
6547
+ title: "OAuth \u767B\u5F55\uFF08\u9884\u7559\uFF0C\u672A\u5B9E\u73B0\uFF09",
6548
+ children: "\u{1F511} OAuth \u767B\u5F55"
6549
+ }
6550
+ )
6551
+ ] }),
6552
+ server.state === "failed" && server.error != null && server.error !== "" && /* @__PURE__ */ jsx20("div", { className: "lax-mcp-server-error", children: server.error })
6553
+ ] });
6554
+ }
6555
+ function ToolsGroup({ load }) {
6556
+ if (load === void 0 || load.status === "loading") {
6557
+ return /* @__PURE__ */ jsx20("div", { className: "lax-mcp-tools lax-mcp-tools--loading", "data-testid": "lax-mcp-tools-loading", children: "\u6E05\u5355\u62C9\u53D6\u4E2D\u2026" });
6558
+ }
6559
+ if (load.status === "error") {
6560
+ return /* @__PURE__ */ jsxs17("div", { className: "lax-mcp-tools lax-mcp-tools--error", role: "alert", children: [
6561
+ "\u53D1\u73B0\u5931\u8D25\uFF1A",
6562
+ load.error
6563
+ ] });
6564
+ }
6565
+ if (load.tools.length === 0) {
6566
+ return /* @__PURE__ */ jsx20("div", { className: "lax-mcp-tools", children: "\u5DF2\u8FDE\u63A5\uFF0C\u4F46\u8BE5 server \u672A\u66B4\u9732\u5DE5\u5177" });
6567
+ }
6568
+ return /* @__PURE__ */ jsx20("div", { className: "lax-mcp-tools", children: load.tools.map((tool) => /* @__PURE__ */ jsx20(McpToolRow, { tool }, tool.model_name)) });
6569
+ }
6570
+ function McpToolRow({ tool }) {
6571
+ const adj = ADJ_META[tool.adjudication];
6572
+ return /* @__PURE__ */ jsxs17("div", { className: "lax-mcp-tool-row", "data-adjudication": tool.adjudication, children: [
6573
+ /* @__PURE__ */ jsx20("span", { className: "lax-mcp-tool-name", children: tool.model_name }),
6574
+ tool.destructive_hint === true ? /* @__PURE__ */ jsx20("span", { className: "lax-mcp-tool-hint tone-error", children: "\u5199\u64CD\u4F5C" }) : tool.read_only_hint === true ? /* @__PURE__ */ jsx20("span", { className: "lax-mcp-tool-hint tone-success", children: "readOnly" }) : null,
6575
+ /* @__PURE__ */ jsxs17("span", { className: `lax-mcp-adj ${adj.cls}`, children: [
6576
+ adj.icon,
6577
+ " ",
6578
+ adj.label
6579
+ ] })
6580
+ ] });
6581
+ }
6582
+ function McpRuleEditor(props) {
6583
+ const {
6584
+ allowText,
6585
+ denyText,
6586
+ onAllowChange,
6587
+ onDenyChange,
6588
+ saving,
6589
+ error,
6590
+ disabled,
6591
+ inPool,
6592
+ total,
6593
+ blocked,
6594
+ onSave
6595
+ } = props;
6596
+ return /* @__PURE__ */ jsxs17("div", { className: "lax-mcp-rules", "data-testid": "lax-mcp-rules", children: [
6597
+ /* @__PURE__ */ jsxs17("div", { className: "lax-mcp-rules-grid", children: [
6598
+ /* @__PURE__ */ jsxs17("label", { className: "lax-mcp-field", children: [
6599
+ /* @__PURE__ */ jsx20("span", { children: "allow\uFF08\u6BCF\u884C\u4E00\u4E2A\u5DE5\u5177\u540D\uFF09" }),
6600
+ /* @__PURE__ */ jsx20(
6601
+ "textarea",
6602
+ {
6603
+ className: "lax-mcp-textarea",
6604
+ value: allowText,
6605
+ onChange: (event) => onAllowChange(event.target.value),
6606
+ placeholder: "mcp__demo__echo"
6607
+ }
6608
+ )
6609
+ ] }),
6610
+ /* @__PURE__ */ jsxs17("label", { className: "lax-mcp-field", children: [
6611
+ /* @__PURE__ */ jsx20("span", { children: "deny\uFF08\u6BCF\u884C\u4E00\u4E2A\u5DE5\u5177\u540D\uFF09" }),
6612
+ /* @__PURE__ */ jsx20(
6613
+ "textarea",
6614
+ {
6615
+ className: "lax-mcp-textarea",
6616
+ value: denyText,
6617
+ onChange: (event) => onDenyChange(event.target.value),
6618
+ placeholder: "mcp__demo__write"
6619
+ }
6620
+ )
6621
+ ] })
6622
+ ] }),
6623
+ /* @__PURE__ */ jsx20("div", { className: "lax-mcp-hint", children: "\u9ED8\u8BA4\u5168 deny\uFF08fail closed\uFF09\uFF1A\u672A\u8986\u76D6\u89C4\u5219\u7684\u5DE5\u5177\u4E0D\u4F1A\u8FDB\u5165\u4F1A\u8BDD\u3002\u89C4\u5219\u53D8\u66F4\u5BF9\u65B0\u4F1A\u8BDD\u751F\u6548\u3002" }),
6624
+ /* @__PURE__ */ jsxs17("div", { className: "lax-mcp-rules-preview", "data-testid": "lax-mcp-rules-preview", children: [
6625
+ "\u88C1\u51B3\u9884\u89C8\uFF1A",
6626
+ inPool !== null && total !== null ? `${inPool}/${total} \u8FDB\u6C60` : "\u2013",
6627
+ blocked !== null ? ` \xB7 ${blocked} \u88AB\u62E6\u622A\uFF08deny / \u672A\u8986\u76D6\uFF09` : ""
6628
+ ] }),
6629
+ error !== null && /* @__PURE__ */ jsxs17("div", { className: "lax-mcp-inline-error", role: "alert", children: [
6630
+ "\u4FDD\u5B58\u5931\u8D25\uFF1A",
6631
+ error
6632
+ ] }),
6633
+ /* @__PURE__ */ jsx20(
6634
+ "button",
6635
+ {
6636
+ type: "button",
6637
+ className: "lax-mcp-btn lax-mcp-btn--primary",
6638
+ disabled: disabled || saving,
6639
+ onClick: onSave,
6640
+ children: saving ? "\u4FDD\u5B58\u4E2D\u2026" : "\u4FDD\u5B58\u89C4\u5219"
6641
+ }
6642
+ )
6643
+ ] });
6644
+ }
6645
+ function ServerForm(props) {
6646
+ const { form, setForm, error, busy, onSubmit, onCancel } = props;
6647
+ const set = (patch) => setForm((prev) => ({ ...prev, ...patch }));
6648
+ const isStdio = form.transport === "stdio";
6649
+ return /* @__PURE__ */ jsxs17(
6650
+ "form",
6651
+ {
6652
+ className: "lax-mcp-form",
6653
+ onSubmit: (event) => {
6654
+ event.preventDefault();
6655
+ onSubmit();
6656
+ },
6657
+ children: [
6658
+ /* @__PURE__ */ jsxs17("div", { className: "lax-mcp-form-row", children: [
6659
+ /* @__PURE__ */ jsxs17("label", { className: "lax-mcp-field", children: [
6660
+ /* @__PURE__ */ jsx20("span", { children: "name" }),
6661
+ /* @__PURE__ */ jsx20(
6662
+ "input",
6663
+ {
6664
+ className: "lax-mcp-input",
6665
+ value: form.name,
6666
+ onChange: (event) => set({ name: event.target.value }),
6667
+ placeholder: "demo"
6668
+ }
6669
+ )
6670
+ ] }),
6671
+ /* @__PURE__ */ jsxs17("label", { className: "lax-mcp-field", children: [
6672
+ /* @__PURE__ */ jsx20("span", { children: "transport" }),
6673
+ /* @__PURE__ */ jsxs17(
6674
+ "select",
6675
+ {
6676
+ className: "lax-mcp-select",
6677
+ value: form.transport,
6678
+ onChange: (event) => set({ transport: event.target.value }),
6679
+ children: [
6680
+ /* @__PURE__ */ jsx20("option", { value: "stdio", children: "stdio" }),
6681
+ /* @__PURE__ */ jsx20("option", { value: "sse", children: "sse" }),
6682
+ /* @__PURE__ */ jsx20("option", { value: "http", children: "http" })
6683
+ ]
6684
+ }
6685
+ )
6686
+ ] })
6687
+ ] }),
6688
+ isStdio ? /* @__PURE__ */ jsxs17(Fragment5, { children: [
6689
+ /* @__PURE__ */ jsxs17("label", { className: "lax-mcp-field", children: [
6690
+ /* @__PURE__ */ jsx20("span", { children: "command" }),
6691
+ /* @__PURE__ */ jsx20(
6692
+ "input",
6693
+ {
6694
+ className: "lax-mcp-input",
6695
+ value: form.command,
6696
+ onChange: (event) => set({ command: event.target.value }),
6697
+ placeholder: "python"
6698
+ }
6699
+ )
6700
+ ] }),
6701
+ /* @__PURE__ */ jsxs17("label", { className: "lax-mcp-field", children: [
6702
+ /* @__PURE__ */ jsx20("span", { children: "args\uFF08\u7A7A\u683C\u5206\u9694\uFF09" }),
6703
+ /* @__PURE__ */ jsx20(
6704
+ "input",
6705
+ {
6706
+ className: "lax-mcp-input",
6707
+ value: form.argsText,
6708
+ onChange: (event) => set({ argsText: event.target.value }),
6709
+ placeholder: "-u echo_server.py"
6710
+ }
6711
+ )
6712
+ ] }),
6713
+ /* @__PURE__ */ jsxs17("label", { className: "lax-mcp-field", children: [
6714
+ /* @__PURE__ */ jsx20("span", { children: "env\uFF08\u6BCF\u884C KEY=VALUE\uFF09" }),
6715
+ /* @__PURE__ */ jsx20(
6716
+ "textarea",
6717
+ {
6718
+ className: "lax-mcp-textarea",
6719
+ value: form.envText,
6720
+ onChange: (event) => set({ envText: event.target.value })
6721
+ }
6722
+ )
6723
+ ] }),
6724
+ /* @__PURE__ */ jsxs17("label", { className: "lax-mcp-field", children: [
6725
+ /* @__PURE__ */ jsx20("span", { children: "cwd" }),
6726
+ /* @__PURE__ */ jsx20(
6727
+ "input",
6728
+ {
6729
+ className: "lax-mcp-input",
6730
+ value: form.cwd,
6731
+ onChange: (event) => set({ cwd: event.target.value })
6732
+ }
6733
+ )
6734
+ ] })
6735
+ ] }) : /* @__PURE__ */ jsxs17(Fragment5, { children: [
6736
+ /* @__PURE__ */ jsxs17("label", { className: "lax-mcp-field", children: [
6737
+ /* @__PURE__ */ jsx20("span", { children: "url" }),
6738
+ /* @__PURE__ */ jsx20(
6739
+ "input",
6740
+ {
6741
+ className: "lax-mcp-input",
6742
+ value: form.url,
6743
+ onChange: (event) => set({ url: event.target.value }),
6744
+ placeholder: "http://localhost:9000/sse"
6745
+ }
6746
+ )
6747
+ ] }),
6748
+ /* @__PURE__ */ jsxs17("label", { className: "lax-mcp-field", children: [
6749
+ /* @__PURE__ */ jsx20("span", { children: "headers\uFF08\u6BCF\u884C KEY=VALUE\uFF09" }),
6750
+ /* @__PURE__ */ jsx20(
6751
+ "textarea",
6752
+ {
6753
+ className: "lax-mcp-textarea",
6754
+ value: form.headersText,
6755
+ onChange: (event) => set({ headersText: event.target.value })
6756
+ }
6757
+ )
6758
+ ] })
6759
+ ] }),
6760
+ error !== null && /* @__PURE__ */ jsx20("div", { className: "lax-mcp-inline-error", role: "alert", children: error }),
6761
+ /* @__PURE__ */ jsxs17("div", { className: "lax-mcp-form-row", children: [
6762
+ /* @__PURE__ */ jsx20("button", { type: "submit", className: "lax-mcp-btn lax-mcp-btn--primary", disabled: busy, children: "\u4FDD\u5B58" }),
6763
+ /* @__PURE__ */ jsx20("button", { type: "button", className: "lax-mcp-btn", onClick: onCancel, children: "\u53D6\u6D88" })
6764
+ ] })
6765
+ ]
6766
+ }
6767
+ );
6768
+ }
6769
+
6137
6770
  // src/view/tools/groupParallelTools.ts
6138
6771
  function buildTimelineEntries(rootIds, byId, options = {}) {
6139
6772
  const filtered = options.hideStandalonePermissions ? rootIds.filter((id) => byId[id]?.kind !== "permission") : [...rootIds];
@@ -6171,18 +6804,18 @@ function buildTimelineEntries(rootIds, byId, options = {}) {
6171
6804
  }
6172
6805
 
6173
6806
  // src/view/nodes/SubAgentNode.tsx
6174
- import { jsx as jsx20, jsxs as jsxs17 } from "react/jsx-runtime";
6807
+ import { jsx as jsx21, jsxs as jsxs18 } from "react/jsx-runtime";
6175
6808
  function SubAgentBlock({ nodeId }) {
6176
6809
  const node = useNodeTyped(nodeId, "subagent");
6177
6810
  const childIds = useChildren(nodeId);
6178
6811
  const registry = useNodeRegistry();
6179
6812
  if (!node) return null;
6180
- return /* @__PURE__ */ jsxs17("div", { className: "lax-subagent-block", "data-status": node.status, children: [
6181
- /* @__PURE__ */ jsxs17("div", { className: "lax-subagent-block__header", children: [
6813
+ return /* @__PURE__ */ jsxs18("div", { className: "lax-subagent-block", "data-status": node.status, children: [
6814
+ /* @__PURE__ */ jsxs18("div", { className: "lax-subagent-block__header", children: [
6182
6815
  "SubAgent: ",
6183
6816
  node.subagentId
6184
6817
  ] }),
6185
- /* @__PURE__ */ jsx20("div", { className: "lax-subagent-block__children", children: childIds.map((childId) => /* @__PURE__ */ jsx20(TimelineItem, { nodeId: childId, registry }, childId)) })
6818
+ /* @__PURE__ */ jsx21("div", { className: "lax-subagent-block__children", children: childIds.map((childId) => /* @__PURE__ */ jsx21(TimelineItem, { nodeId: childId, registry }, childId)) })
6186
6819
  ] });
6187
6820
  }
6188
6821
 
@@ -6256,6 +6889,7 @@ export {
6256
6889
  MAX_PREVIEW_LINES,
6257
6890
  MIN_HINT_DISPLAY_MS,
6258
6891
  MarkdownBlock,
6892
+ McpPanel,
6259
6893
  MermaidDiagram,
6260
6894
  MissingApplicationKindError,
6261
6895
  MultiAgentSession,