dsh-plugin-agentflow 0.2.1 → 0.2.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 CC19990113
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,89 +1,130 @@
1
- # dsh-plugin-agentflow
1
+ # AgentFlow · DSH 插件
2
2
 
3
- 把 AgentFlow(物料画布式 agent 编排器)接进 DeepSeek Harness 的桌面插件:
3
+ > 在 DeepSeek Harness 里用**画布**编排 agent 工作流,一键生成 DSH 预设 —— 每一步由你定义,而不是塞进一个黑盒循环。
4
4
 
5
- - 设置页 / 侧边栏嵌入画布界面(本地后端 `http://127.0.0.1:8791`)
6
- - 模型工具 `agentflow_list` / `agentflow_run`:看画布、跑画布
7
- - 引擎随插件分发(`runtime/`),装完即用,不需要单独安装 `~/.dsh/agent-flow`
8
- - 模型调用走 DSH 内核的 llm bridge(插件在 DSH 进程里起),不再自带 provider 凭据
5
+ [![npm](https://img.shields.io/npm/v/dsh-plugin-agentflow?color=24543F&label=npm)](https://www.npmjs.com/package/dsh-plugin-agentflow)
6
+ [![license](https://img.shields.io/badge/license-MIT-24543F)](./LICENSE)
7
+ [![DSH](https://img.shields.io/badge/DSH-0.2.x-6aa583)](https://github.com/deepseek-ai)
9
8
 
10
- ## 安装
9
+ ![画布](docs/images/canvas-light.png)
11
10
 
12
- DSH 桌面版 → **设置 → 插件 → 添加插件**,然后二选一:
11
+ ## 是什么
13
12
 
14
- - 输入 GitHub 仓库地址(例:`https://github.com/<owner>/dsh-plugin-agentflow`)
15
- - 输入本地目录(克隆下来的插件目录)
13
+ DSH 自带的 agent 是「一个模型 + 一堆工具」的循环,中间怎么想、调什么,你看不见也改不了。
16
14
 
17
- DSH 会安装插件依赖并加载;侧边栏/设置页出现 AgentFlow 即成功,**不需要手动起服务、不需要构建前端**(仓库里已包含构建好的客户端与 `runtime/` 引擎)。
15
+ AgentFlow 把它掰开:**画布上的每张卡片就是一个 agent 步骤**。你决定有几步、谁先谁后、谁并行、每步用哪个模型、能不能调 MCP 工具、做完怎么验收。编排好之后导出成一个 DSH 预设,在对话里直接选中它。
18
16
 
19
- ## 首次启动会发生什么
17
+ - **节点**:LLM(调模型)/ MCP(直接调工具,不经过模型)/ 调度(根,对话入口)
18
+ - **执行**:纯 DAG,无上游先跑、同层并行、失败不阻塞其它分支
19
+ - **模型**:全部走 DSH 自己的模型通道(`ctx.llm`),推理强度和兜底模型可逐节点配
20
+ - **预设**:根节点承载人格,导出时自动附上子节点清单,写进 DSH profile
20
21
 
21
- 1. 插件用当前 DSH 的 Node 进程拉起 `runtime/server.mjs`(先探测 8791 端口,已在跑就不重复起;日志丢弃,不污染 DSH 终端)
22
- 2. 后端监听 `127.0.0.1:8791`,数据目录默认 `~/.dsh/agent-flow-data`
23
- 3. 若新数据目录不存在或为空,且旧目录 `~/.dsh/agent-flow/data` 里有 `board.json`,会自动把旧数据抄一份过来(只抄一次,旧文件保留不动)
24
- 4. 新环境没有画布时,后端会自动建一张默认画布,打开页面即可看到
22
+ ## 安装
25
23
 
26
- ## 数据目录
24
+ ### 从 npm
27
25
 
28
- 默认:`~/.dsh/agent-flow-data/`
26
+ DSH → 设置 → 插件 → 添加插件 → 输入:
29
27
 
30
28
  ```
31
- boards.json # 画布索引
32
- boards/<id>.json # 每张画布
33
- config.json # 引擎配置(含密钥时权限 0600)
34
- drafts/ # 画布草稿
35
- data/dsh-bridge.json # DSH llm bridge 的发现文件(进程级 token)
29
+ dsh-plugin-agentflow
36
30
  ```
37
31
 
38
- 覆盖方式(优先级从高到低):
32
+ ### 从 GitHub
39
33
 
40
- | 方式 | 例子 |
41
- | --- | --- |
42
- | 插件配置 `dataDir` | `{ "dataDir": "/path/to/data" }` |
43
- | 环境变量 `AGENTFLOW_DATA_DIR` | 启动 DSH 前 export |
44
- | 默认值 | `~/.dsh/agent-flow-data` |
34
+ ```
35
+ CC19990113/dsh-plugin-agentflow
36
+ ```
45
37
 
46
- 数据目录别放进插件安装目录:升级/重装插件会覆盖安装目录。
38
+ 装完重启 DSH。左侧栏出现 **AgentFlow** 入口,后端由插件自动拉起(默认 `127.0.0.1:8791`),不需要手动跑命令。
47
39
 
48
- ## 依赖
40
+ 要求:DSH 桌面版 0.2.x、Node 22+。
49
41
 
50
- - DSH 0.2.x(插件依赖 `@deepseek-ai/dsh-tools ^0.2.1-rc.2`、`@deepseek-ai/cordis ^4.0.5`)
51
- - Node 22+(后端用到 `fetch`、`AbortSignal.timeout`、`fs.cp`)
52
- - 模型通道:引擎通过 DSH 内置的 llm bridge 调模型,需要 DSH 正在运行且插件已加载。DSH 没起 / 插件未加载时,画布仍能打开和编辑;关掉 mock 后跑图会失败,错误含「DSH 内核未连接」
53
- - 引擎默认是 mock 模式(返回假输出,不调用模型);在画布设置里关掉 mock 才会真正调模型
42
+ ## 怎么用
54
43
 
55
- ## 预设导出
44
+ ### 1. 画布列表
56
45
 
57
- 画布可导出成 DSH 预设,写入 `~/.dsh/profiles/<profile>/`(默认 profile 为 `desktop`)。
46
+ ![画布列表](docs/images/boards-list.png)
58
47
 
59
- - 换 profile:启动 DSH 前设置 `AGENTFLOW_PROFILE=<profile 名>`,后端子进程会继承
60
- - profile 目录不存在时导出接口返回 400,并提示具体路径
48
+ 每张画布对应一个 DSH 预设。卡片上会标出「对话入口」(哪张卡是和用户对话的根节点),改过画布但没更新预设时显示 **预设未更新**。
61
49
 
62
- ## 开发
50
+ ### 2. 编排
63
51
 
64
- ```bash
65
- npm install
66
- npm run sync # 把 ~/.dsh/agent-flow 的引擎快照进 runtime/(清空重建)
67
- npm run check # node --check
68
- npm test # bridge 自测
69
- npm run build # 构建客户端 bundle(改了 src/client.tsx 才需要)
52
+ - 拖卡片改位置,从卡片边缘拖线连上下游
53
+ - 点卡片改模型、推理强度、兜底模型、技能、MCP 工具
54
+ - 「加下游 / 加上游」快速派生新卡
55
+ - 编辑**自动保存**,点「保存」才会把你的编排**生成/覆盖成 DSH 预设**
56
+
57
+ ### 3. 验证
58
+
59
+ 顶栏「验证 AgentFlow」会真实跑一遍整张图(会消耗 token),用来看流程通不通。卡片上只显示配置摘要,不堆运行产出。
60
+
61
+ ### 4. 导出成预设
62
+
63
+ 点「保存」(或 ⌘S)→ 画布落库 + 预设写入 `~/.dsh/profiles/<profile>/cordis.patch.yml`。重启 DSH 后,新会话的预设列表里就能选到它。
64
+
65
+ 预设长这样:
66
+
67
+ ```
68
+ 你是「AgentFlow」的对话入口。
69
+ 你只负责和用户对话:问清需求、确认关键信息。
70
+ 需求明确后,严格按照后续节点的 AgentFlow 流去执行,不要自己直接产出结果。
71
+
72
+ 【完成标准】…
73
+ 【子节点】共 4 个
74
+ - 大纲:根据给定的题材,写一个三幕剧的简要大纲
75
+ - 对白版:为关键场景写几句有张力的对白
76
+ …
77
+ ```
78
+
79
+ ## 深色模式
80
+
81
+ ![深色](docs/images/canvas-dark.png)
82
+
83
+ 主题跟随 DSH:插件把当前主题拼进 iframe 地址,画布启动时按它初始化;手动切换只在本次会话内生效,DSH 重开时重新读配置。
84
+
85
+ ## 架构
86
+
87
+ ```
88
+ DSH 桌面
89
+ ├── 插件(index.js)
90
+ │ ├── 工具:agentflow_list / agentflow_run
91
+ │ ├── 客户端:侧边栏入口、设置页分区、画布 iframe
92
+ │ └── 子进程:node runtime/server.mjs → 127.0.0.1:8791
93
+ │ ├── engine.mjs 纯 DAG 执行器
94
+ │ ├── llm.mjs 调模型(只走 bridge)
95
+ │ └── web/dist 画布前端
96
+ └── llm bridge(lib/bridge.js)
97
+ └── 把 ctx.llm 暴露给引擎,模型调用始终在 DSH 进程内
70
98
  ```
71
99
 
72
- - `runtime/` 是 `npm run sync` 的生成物,不要手改;引擎更新后重新跑一次 sync
73
- - 开发时想直接改引擎源码,不必每次 sync:配 `agentflowDir` 或设 `AGENTFLOW_DIR=~/.dsh/agent-flow`,插件会改用该目录的引擎(此时 bridge 发现文件也写在该目录的 `data/` 下)
74
- - 同步源可用 `AGENTFLOW_SRC=/path/to/agent-flow npm run sync` 指定
100
+ `runtime/` 是打包时从引擎仓库同步过来的副本(`npm run sync`),所以插件自带完整引擎,装完即用。
75
101
 
76
- 插件配置项:
102
+ ## 配置
77
103
 
78
- | 配置 | 说明 |
79
- | --- | --- |
80
- | `agentflowDir` | 引擎目录(开发用),覆盖自带 `runtime/` |
81
- | `agentflowPort` | 后端端口,默认 `8791`(界面目前固定连 8791,改端口需同步改客户端) |
82
- | `dataDir` | 数据目录,默认 `~/.dsh/agent-flow-data` |
104
+ | 项 | 默认 | 说明 |
105
+ |---|---|---|
106
+ | 数据目录 | `~/.dsh/agent-flow-data` | 首次启动会自动从 `~/.dsh/agent-flow/data` 迁移 |
107
+ | 后端端口 | `8791` | 可用 `agentflowPort` 插件配置改 |
108
+ | 预设 profile | `desktop` | 用环境变量 `AGENTFLOW_PROFILE` 指定别的 profile |
83
109
 
84
110
  ## 限制
85
111
 
86
- - 只在 macOS 上验证过;Windows 未测试(路径、进程管理可能还需适配)
87
- - 端口默认固定 `8791`;被别的实例占用时,探测到存活就复用,否则启动会失败(插件客户端的 iframe 也写死了 8791,改端口需要同时改客户端)
88
- - 一个 DSH 进程只托管一个自建后端;插件卸载时会杀掉自己拉起的那个,外部已在跑的不管
89
- - 引擎是插件版本快照:升级引擎需要重新 `npm run sync` 并发布新版本插件
112
+ - **只在 macOS 上验证过**,Windows 的路径与命令未测
113
+ - 运行态是全局的:跑图时切换画布,事件会被丢弃;「停止」不分画布
114
+ - 验证跑图会真实调用模型,注意 token 消耗
115
+ - 预设依赖 DSH profile 的 patch 机制,profile 结构变了要跟着调整
116
+
117
+ ## 开发
118
+
119
+ ```bash
120
+ npm run build # 构建客户端 bundle(lib/client.js)
121
+ npm run sync # 从 ~/.dsh/agent-flow 同步引擎到 runtime/
122
+ npm run check # 语法检查
123
+ npm test # 插件自测(83 项)
124
+ ```
125
+
126
+ 引擎侧测试在 `~/.dsh/agent-flow/test`(85 项)。
127
+
128
+ ## License
129
+
130
+ [MIT](./LICENSE)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-plugin-agentflow",
3
- "version": "0.2.1",
3
+ "version": "0.2.2",
4
4
  "description": "DeepSeek Harness tool plugin: run AgentFlow (material-canvas agent orchestrator) boards from the model",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -10,7 +10,7 @@
10
10
  "sync": "node scripts/sync-runtime.mjs"
11
11
  },
12
12
  "author": "",
13
- "license": "ISC",
13
+ "license": "MIT",
14
14
  "dependencies": {
15
15
  "@deepseek-ai/cordis": "^4.0.5",
16
16
  "@deepseek-ai/dsh-tools": "^0.2.1-rc.2"
@@ -345,4 +345,4 @@ html body {
345
345
  .dark .af-panel .af-row:hover {
346
346
  background: #1d1e1b;
347
347
  }
348
- `,cW=`w-full rounded-lg border border-[#E1E2DD] bg-[#FCFCFA] px-2.5 py-2 text-[13px] leading-[1.65] text-[#1B1B18] outline-none transition-colors placeholder:text-[#9a9a92] focus:border-[#24543F] focus:bg-white dark:border-[#33353B] dark:bg-[#17181B] dark:text-[#EDEDE8] dark:focus:border-[#6aa583] dark:focus:bg-[#1B1C20]`,lW=`rounded-[4px] px-2.5 py-1.5 text-[12px] text-[#5b6472] transition-colors hover:bg-[#EFEFEA] dark:text-[#a3a39b] dark:hover:bg-[#232421]`;function uW(e){return(0,$.jsxs)(`aside`,{className:`af-panel fixed bottom-0 right-0 top-14 z-30 flex w-[420px] flex-col border-l border-[#E3E4DF] bg-[#FCFCFA] dark:border-[#262724] dark:bg-[#17181B]`,role:`complementary`,"aria-label":`节点详情`,children:[(0,$.jsx)(`style`,{children:sW}),(0,$.jsx)(fW,{...e},e.node.id)]})}function dW(e,...t){let n=e.trim().toLowerCase();return!n||t.some(e=>String(e??``).toLowerCase().includes(n))}function fW(e){let{node:t,nodes:n,edges:r,boardId:i,skills:a,servers:o,catalog:s,bridge:c,running:l,onPatch:u,onDerive:d,onVerify:f,onRerun:p,onRefreshModels:m,onEdgesChange:h,onDelete:g,onClose:v}=e,[y,b]=(0,_.useState)(t.label),[x,S]=(0,_.useState)(t.task),[C,w]=(0,_.useState)(t.criteria),[T,E]=(0,_.useState)(tW),[D,O]=(0,_.useState)(0),[k,A]=(0,_.useState)(``),[j,M]=(0,_.useState)(``),[N,F]=(0,_.useState)(null),I=(0,_.useRef)(null),L=(0,_.useRef)(null);(0,_.useEffect)(()=>{_W(I.current)},[x]),(0,_.useEffect)(()=>{_W(L.current)},[C]);let z=(0,_.useRef)(u);(0,_.useEffect)(()=>{z.current=u},[u]);let B=(0,_.useRef)({}),V=(0,_.useRef)(null),H=(0,_.useCallback)(()=>{V.current!==null&&(window.clearTimeout(V.current),V.current=null);let e=B.current;Object.keys(e).length&&(B.current={},z.current(e))},[]),U=(0,_.useCallback)(e=>{B.current={...B.current,...e},V.current!==null&&window.clearTimeout(V.current),V.current=window.setTimeout(H,400)},[H]);(0,_.useEffect)(()=>()=>{if(V.current!==null){window.clearTimeout(V.current),V.current=null;let e=B.current;Object.keys(e).length&&z.current(e)}},[]),(0,_.useEffect)(()=>{let e=e=>{(e.metaKey||e.ctrlKey)&&String(e.key).toLowerCase()===`s`&&H()};return window.addEventListener(`keydown`,e),()=>window.removeEventListener(`keydown`,e)},[H]);let[W,ee]=(0,_.useState)(r);(0,_.useEffect)(()=>{ee(r)},[r]);let ne=new Set(W.filter(e=>e.to===t.id).map(e=>e.from)),re=n.filter(e=>e.id!==t.id);function ie(e){let n=[...W.filter(e=>e.to!==t.id),...e.map(e=>({from:e,to:t.id}))];ee(n),h(n)}function ae(e,n){let r=new Set(t.skills);n?r.add(e):r.delete(e),u({skills:[...r]})}let G=s?.providers??[],K=t.provider&&t.model?`${t.provider}/${t.model}`:``,oe=G.some(e=>e.id===t.provider&&e.models.some(e=>e.id===t.model)),ce=t.model&&!oe?t.model:``,q=oe?G.find(e=>e.id===t.provider)?.models.find(e=>e.id===t.model)??null:null,le=q?.levels??[],ue=q?.defaultLevel??``,de=G.every(e=>!e.models.length),fe=new Set,pe=[];for(let e of T){let{provider:t,model:n}=rW(e.value),r=G.find(e=>e.id===t),i=r?.models.find(e=>e.id===n);r&&i&&!fe.has(e.value)&&(fe.add(e.value),pe.push({title:i.name,label:`${r.label} · ${i.name}`,value:`${QU}${e.value}`}))}let me=[];pe.length&&me.push({title:`最近使用`,label:`最近使用`,value:XU,selectable:!1,children:pe}),ce&&me.push({title:`当前值`,label:`当前值`,value:ZU,selectable:!1,children:[{title:ce,label:iW(t.provider,ce),value:YU}]});for(let e of G){let t=e.models.length;me.push({title:t?`${e.label}(${t})`:e.label,label:e.label,value:`p:${e.id}`,selectable:!1,children:e.error?[{title:e.error,label:e.error,value:`e:${e.id}`,disabled:!0}]:e.models.map(t=>({title:t.name,label:`${e.label} · ${t.name}`,value:`${e.id}/${t.id}`}))})}let he=G.find(e=>e.id===t.provider),ge=T.map(e=>e.provider).find(e=>G.some(t=>t.id===e)),ve=he?.id??ge??``,ye=[...pe.length?[XU]:[],...ce?[ZU]:[],...ve?[`p:${ve}`]:[]],be=oe?K:ce?YU:void 0,Y=t.fallback??[],Se=t.fallbackEfforts??{},Ce=new Set(Y),we=G.map(e=>{let t=e.models.length,n=e.error?[{title:e.error,label:e.error,value:`e:${e.id}`,disabled:!0}]:e.models.filter(t=>{let n=`${e.id}/${t.id}`;return n!==K&&!Ce.has(n)}).map(t=>({title:t.name,label:`${e.label} · ${t.name}`,value:`${e.id}/${t.id}`}));return{title:t?`${e.label}(${t})`:e.label,label:e.label,value:`p:${e.id}`,selectable:!1,children:n}}).filter(e=>e.children.length>0),Te=ve?[`p:${ve}`]:[];function Ee(e){if(!e||e===YU)return;let n=e.startsWith(QU)?e.slice(2):e,{provider:r,model:i}=rW(n),a=G.find(e=>e.id===r),o=a?.models.find(e=>e.id===i);if(!a||!o)return;let s=o.levels.includes(t.reasoningEffort??``)?t.reasoningEffort??``:``,c={value:n,label:o.name,provider:r},l=[c,...T.filter(e=>e.value!==c.value)].slice(0,eW);E(l),nW(l),u({provider:r,model:i,reasoningEffort:s})}function De(e){let{provider:t,model:n}=rW(e),r=G.find(e=>e.id===t),i=r?.models.find(e=>e.id===n);return!r||!i?{label:`${e}(不在 DSH 目录里)`,levels:[]}:{label:`${r.label} · ${i.name}`,levels:i.levels}}function Oe(e,t){u({fallback:e,fallbackEfforts:t})}function ke(e){e&&e.includes(`/`)&&!Ce.has(e)&&(Oe([...Y,e],{...Se,[e]:``}),O(e=>e+1))}function Ae(e){let t={...Se};delete t[e],Oe(Y.filter(t=>t!==e),t)}function je(e,t){Oe(Y,{...Se,[e]:t})}let Me=aW[t.status]??aW.idle,Ne=t.type===`orchestrator`,Pe=n.some(e=>e.id!==t.id&&e.type===`orchestrator`),Fe=MU.map(e=>({...e,disabled:e.value===`orchestrator`&&Pe})),Ie=oW.find(e=>e.value===(t.verify??``))??oW[0],Le=t.status===`review`,Re=a.filter(e=>dW(k,e.name,e.description)),ze=o.map(e=>({...e,tools:e.tools.filter(e=>dW(j,e.name,e.description))})).filter(e=>dW(j,e.name)||e.tools.length>0),Be=j.trim()?ze.map(e=>e.name):N??o.filter(e=>e.ok&&e.tools.length).slice(0,1).map(e=>e.name);return(0,$.jsxs)($.Fragment,{children:[(0,$.jsxs)(`header`,{className:`flex shrink-0 items-center gap-2 border-b ${qU} bg-[#FAFAF7] px-5 py-3.5 dark:bg-[#1B1C20]`,children:[(0,$.jsx)(`input`,{value:y,onChange:e=>{let t=e.target.value;b(t),U({label:t})},onBlur:H,onKeyDown:e=>{e.key===`Enter`&&e.currentTarget.blur()},placeholder:`节点名称`,"aria-label":`节点名称`,className:`min-w-0 flex-1 rounded-[3px] border-0 bg-transparent p-0 text-[17px] font-semibold tracking-tight outline-none placeholder:text-[#a8a8a0] focus-visible:ring-2 focus-visible:ring-[#24543F]/30 dark:placeholder:text-[#6f6f68] dark:focus-visible:ring-[#6aa583]/40 ${WU}`}),(0,$.jsxs)(`span`,{className:`flex shrink-0 items-center gap-1.5 text-[12px] ${GU}`,children:[(0,$.jsx)(`span`,{className:`h-[6px] w-[6px] rounded-full ${Me.dot}`}),Me.label]}),(0,$.jsx)(`button`,{type:`button`,onClick:v,"aria-label":`关闭详情`,title:`关闭`,className:`-mr-1 grid h-8 w-8 shrink-0 place-items-center rounded-[4px] text-[#6b6b66] transition-colors hover:bg-[#EFEFEA] dark:text-[#8b8b85] dark:hover:bg-[#232421]`,children:(0,$.jsx)(xe,{size:16})})]}),t.verdict&&(0,$.jsxs)(`div`,{className:`shrink-0 border-b px-5 py-2 text-[12px] leading-[1.5] ${qU} ${t.verdict.pass?`bg-[#EEF3EF] text-[#24543F] dark:bg-[#1B2A22] dark:text-[#8FC3A7]`:`bg-[#FBEFEA] text-[#B4451F] dark:bg-[#2A1C17] dark:text-[#E08A6A]`}`,children:[gW(t.verdict.by),` `,t.verdict.pass?`通过`:`未通过`,t.verdict.reason?`:${t.verdict.reason}`:``]}),t.error&&(0,$.jsx)(`div`,{className:`shrink-0 border-b px-5 py-2 text-[12px] leading-[1.5] ${qU} bg-[#FBEFEA] text-[#B4451F] dark:bg-[#2A1C17] dark:text-[#E08A6A]`,children:t.error}),(0,$.jsxs)(`div`,{className:`min-h-0 flex-1 overflow-y-auto px-4 pb-6 pt-3`,children:[Ne?null:(0,$.jsxs)(pW,{title:`节点类型`,children:[(0,$.jsx)(Fb,{value:t.type||`llm`,onChange:e=>u({type:e}),options:Fe,"aria-label":`节点类型`,className:`w-full`,size:`middle`}),Pe?(0,$.jsx)(`p`,{className:`mt-1.5 text-[11px] leading-[1.5] ${KU}`,children:`画布已有根节点,这张卡不能再设为调度卡。`}):null]}),(0,$.jsx)(pW,{title:`模型`,extra:(0,$.jsxs)(`button`,{type:`button`,onClick:m,title:`重新读取 DSH 的模型目录`,className:`flex items-center gap-1 text-[11px] transition-opacity hover:opacity-70 ${KU}`,children:[(0,$.jsx)(se,{size:11}),`刷新`]}),children:(0,$.jsxs)(`div`,{className:`space-y-1.5`,children:[(0,$.jsx)(Lk,{value:be,placeholder:`选择模型`,showSearch:!0,treeNodeFilterProp:`title`,treeDefaultExpandAll:!1,treeDefaultExpandedKeys:ye,treeNodeLabelProp:`label`,treeData:me,onChange:Ee,"aria-label":`模型`,className:`w-full`,size:`middle`}),(0,$.jsx)(Fb,{value:t.reasoningEffort??``,onChange:e=>u({reasoningEffort:e}),disabled:!le.length,"aria-label":`推理强度`,title:le.length?`推理强度`:`当前模型没有可选推理档位`,options:[{value:``,label:`推理强度:模型默认${ue?`(${ue})`:``}`},...le.map(e=>({value:e,label:e}))],className:`w-full`,size:`middle`}),de&&(0,$.jsxs)(`div`,{className:`flex items-start gap-1.5 text-[11px] leading-[1.6] ${GU}`,children:[(0,$.jsx)(`span`,{className:`mt-[5px] h-[3px] w-[3px] shrink-0 rounded-full bg-current opacity-50`}),(0,$.jsx)(`span`,{children:`没读到 DSH 的模型目录,检查 DSH 凭据或网络。`})]}),(0,$.jsxs)(`div`,{className:`flex items-start gap-1.5 border-t border-[#EDEEE9] pt-2 text-[11px] leading-[1.6] dark:border-[#2A2C31] ${c&&!c.healthy?`text-[#B4451F] dark:text-[#e08a6a]`:GU}`,children:[(0,$.jsx)(`span`,{className:`mt-[5px] h-[3px] w-[3px] shrink-0 rounded-full bg-current opacity-60`}),(0,$.jsxs)(`span`,{children:[`模型通道:DSH 内核(未连接时不可跑图)`,c&&!c.healthy?` · ${c.reason||`原因未知`}`:``]})]})]})}),(0,$.jsx)(pW,{title:`兜底模型`,extra:Y.length?(0,$.jsxs)(`span`,{className:`text-[11px] ${GU}`,children:[Y.length,` 个 · 按顺序重试`]}):void 0,children:(0,$.jsxs)(`div`,{className:`space-y-1.5`,children:[Y.map(e=>{let t=De(e);return(0,$.jsxs)(`div`,{className:`flex min-h-[32px] items-center gap-2 border-b py-1 last:border-b-0 ${qU}`,children:[(0,$.jsx)(`span`,{className:`min-w-0 flex-1 truncate text-[12px] ${WU}`,title:t.label,children:t.label}),(0,$.jsx)(Fb,{size:`small`,value:Se[e]??``,disabled:!t.levels.length,title:t.levels.length?`这条兜底的推理强度`:`该模型没有可选推理档位`,options:[{value:``,label:`模型默认`},...t.levels.map(e=>({value:e,label:e}))],onChange:t=>je(e,t),"aria-label":`${t.label} 的推理强度`,style:{width:104}}),(0,$.jsx)(`button`,{type:`button`,onClick:()=>Ae(e),"aria-label":`移除兜底模型 ${t.label}`,title:`移除`,className:`grid h-7 w-7 shrink-0 place-items-center rounded-[4px] transition-colors hover:bg-[#FBEFEA] hover:text-[#B4451F] dark:hover:bg-[#2A1C17] dark:hover:text-[#e08a6a] ${KU}`,children:(0,$.jsx)(xe,{size:13})})]},e)}),(0,$.jsx)(Lk,{onChange:ke,placeholder:`添加兜底模型…`,showSearch:!0,treeNodeFilterProp:`title`,treeDefaultExpandAll:!1,treeDefaultExpandedKeys:Te,treeNodeLabelProp:`label`,treeData:we,"aria-label":`添加兜底模型`,className:`w-full`,size:`middle`},D),(0,$.jsxs)(`div`,{className:`flex items-start gap-1.5 pt-0.5 text-[11px] leading-[1.6] ${GU}`,children:[(0,$.jsx)(`span`,{className:`mt-[5px] h-[3px] w-[3px] shrink-0 rounded-full bg-current opacity-50`}),(0,$.jsx)(`span`,{children:`兜底模型:主模型失败后按顺序尝试,可单独设推理强度`})]})]})}),(0,$.jsxs)(pW,{title:Ne?`人格`:`任务`,children:[(0,$.jsx)(`textarea`,{ref:I,rows:3,value:x,onChange:e=>{S(e.target.value),U({task:e.target.value}),_W(e.currentTarget)},onBlur:H,placeholder:Ne?`默认:只负责和用户对话,再严格按后续节点的 AgentFlow 流执行(可自己改)`:`写清楚这张卡要做什么…`,className:`${cW} max-h-[240px] resize-none overflow-y-auto`}),Ne&&(0,$.jsx)(`p`,{className:`mt-1.5 text-[11px] leading-[1.5] ${KU}`,children:`默认人格只是起点,可以自己改:它只负责和用户对话,确认需求后严格按后续节点的流程执行。`})]}),(0,$.jsx)(pW,{title:`完成标准`,children:(0,$.jsx)(`textarea`,{ref:L,rows:2,value:C,onChange:e=>{w(e.target.value),U({criteria:e.target.value}),_W(e.currentTarget)},onBlur:H,placeholder:`做到什么程度算完成…`,className:`${cW} max-h-[200px] resize-none overflow-y-auto`})}),(0,$.jsxs)(pW,{title:`结果判断`,children:[(0,$.jsx)(`div`,{role:`radiogroup`,"aria-label":`结果判断`,className:`flex gap-[2px] rounded-[6px] bg-[#EFEFEA] p-[3px] dark:bg-[#232421]`,children:oW.map(e=>{let n=(t.verify??``)===e.value;return(0,$.jsx)(`button`,{type:`button`,role:`radio`,"aria-checked":n,title:e.desc,onClick:()=>u({verify:e.value}),className:`flex-1 rounded-[4px] px-1 py-[5px] text-[13px] leading-[1.3] transition-colors ${n?`bg-white text-[#1B1B18] shadow-[0_1px_2px_rgba(0,0,0,0.06)] dark:bg-[#3A3B35] dark:text-[#e8e8e4]`:`hover:text-[#1B1B18] dark:hover:text-[#e8e8e4] ${GU}`}`,children:e.label},e.value||`none`)})}),(0,$.jsx)(`p`,{className:`mt-1.5 text-[11px] leading-[1.5] ${KU}`,children:Ie.desc}),(t.verify??``)===`jev`&&(0,$.jsx)(`p`,{className:`mt-1.5 rounded-[4px] border border-[#E9D9B8] bg-[#FBF4E6] px-2 py-1.5 text-[11px] leading-[1.5] text-[#8a6220] dark:border-[#4a3a1c] dark:bg-[#2a2314] dark:text-[#e0b866]`,children:`需要本机安装 jev(TypeSafe)并配置 API key,否则这张卡跑到判定时会失败。`})]}),(0,$.jsx)(pW,{title:`技能`,extra:(0,$.jsxs)(`span`,{className:`text-[11px] ${KU}`,children:[`已选 `,t.skills.length]}),children:a.length===0?(0,$.jsx)(mW,{children:`没有找到技能`}):(0,$.jsxs)($.Fragment,{children:[(0,$.jsx)(PD,{value:k,onChange:e=>A(e.target.value),allowClear:!0,size:`middle`,placeholder:`搜索技能名或描述…`,"aria-label":`搜索技能`,prefix:(0,$.jsx)(J,{size:12,className:KU}),className:`mb-2`}),Re.length===0?(0,$.jsxs)(mW,{children:[`没有匹配「`,k.trim(),`」的技能`]}):null,(0,$.jsx)(`div`,{className:`max-h-[180px] overflow-y-auto`,children:Re.map(e=>{let n=t.skills.includes(e.name);return(0,$.jsx)(YT,{className:`af-row`,checked:n,onChange:t=>ae(e.name,t.target.checked),title:e.description,children:(0,$.jsxs)(`span`,{className:`flex min-w-0 flex-1 items-center gap-2`,children:[(0,$.jsx)(`span`,{className:`shrink-0 text-[13px] ${WU}`,children:e.name}),(0,$.jsx)(`span`,{className:`min-w-0 flex-1 truncate text-right text-[11px] ${KU}`,children:e.description||`无描述`})]})},e.name)})})]})}),(0,$.jsx)(pW,{title:`MCP 工具`,extra:(0,$.jsxs)(`span`,{className:`text-[11px] ${KU}`,children:[`已选 `,t.tools.length]}),children:o.length===0?(0,$.jsx)(mW,{children:`还没配置 MCP 服务器`}):(0,$.jsxs)($.Fragment,{children:[(0,$.jsx)(PD,{value:j,onChange:e=>M(e.target.value),allowClear:!0,size:`middle`,placeholder:`搜索服务器或工具…`,"aria-label":`搜索 MCP 工具`,prefix:(0,$.jsx)(J,{size:12,className:KU}),className:`mb-2`}),ze.length===0?(0,$.jsxs)(mW,{children:[`没有匹配「`,j.trim(),`」的工具`]}):null,(0,$.jsx)(`div`,{className:`max-h-[180px] overflow-y-auto af-tree`,children:(0,$.jsx)(FO,{checkable:!0,selectable:!1,expandedKeys:Be,onExpand:e=>F(e),treeData:ze.map(e=>({key:e.name,selectable:!1,title:(0,$.jsxs)(`span`,{className:`flex items-center gap-2`,children:[(0,$.jsx)(`span`,{className:`h-[5px] w-[5px] shrink-0 rounded-full ${e.ok?`bg-[#24543F] dark:bg-[#6aa583]`:`bg-[#B4451F] dark:bg-[#e08a6a]`}`}),(0,$.jsx)(`span`,{className:`text-[12px] font-medium ${WU}`,children:e.name}),(0,$.jsxs)(`span`,{className:`text-[11px] ${KU}`,children:[e.tools.length,` 个工具`]}),!e.ok&&(0,$.jsx)(`span`,{className:`text-[11px] text-[#B4451F] dark:text-[#e08a6a]`,children:`连接失败`})]}),children:e.tools.map(t=>({key:`${e.name}.${t.name}`,title:(0,$.jsxs)(`span`,{className:`flex min-w-0 flex-1 items-center gap-2`,children:[(0,$.jsx)(`span`,{className:`shrink-0 text-[13px] ${WU}`,children:t.name}),(0,$.jsx)(`span`,{className:`min-w-0 flex-1 truncate text-right text-[11px] ${KU}`,children:t.description})]})}))})),checkedKeys:t.tools,onCheck:e=>{let t=Array.isArray(e)?e:e.checked;u({tools:t.filter(e=>String(e).includes(`.`))})}})})]})}),Ne?null:(0,$.jsx)(pW,{title:`上游`,children:re.length===0?(0,$.jsx)(mW,{children:`还没有其它卡片`}):(0,$.jsx)(`div`,{className:`max-h-[180px] overflow-y-auto`,children:re.map(e=>{let n=ne.has(e.id),r=!n&&hW(W,t.id,e.id),i=n?[...ne].filter(t=>t!==e.id):[...ne,e.id];return(0,$.jsx)(YT,{className:`af-row ${r?`af-row-disabled`:``}`,checked:n,disabled:r,onChange:()=>ie(i),children:(0,$.jsxs)(`span`,{className:`flex min-w-0 flex-1 items-center gap-2`,children:[(0,$.jsx)(`span`,{className:`min-w-0 flex-1 truncate text-[13px] ${WU}`,children:e.label||e.id}),r&&(0,$.jsx)(`span`,{className:`shrink-0 text-[11px] ${KU}`,children:`会成环`})]})},e.id)})})})]}),Le&&(0,$.jsxs)(`div`,{className:`shrink-0 border-t ${qU} bg-[#FAEFE6] px-5 py-3 dark:bg-[#2A1C17]`,children:[(0,$.jsx)(`p`,{className:`text-[12px] text-[#B4451F] dark:text-[#e08a6a]`,children:`这张卡跑完了,等你判断结果`}),(0,$.jsxs)(`div`,{className:`mt-2 flex gap-2`,children:[(0,$.jsx)(`button`,{type:`button`,onClick:()=>f(!0),className:`h-8 flex-1 rounded-[4px] bg-[#24543F] text-[13px] font-medium text-white transition-colors hover:bg-[#1D4634] dark:bg-[#3F7A5F] dark:hover:bg-[#4B8B6D]`,children:`通过`}),(0,$.jsx)(`button`,{type:`button`,onClick:()=>f(!1),className:`h-8 flex-1 rounded-[4px] text-[13px] text-[#6b6b66] transition-colors hover:bg-white/60 dark:text-[#a3a39b] dark:hover:bg-[#232421]`,children:`打回重跑`})]})]}),(0,$.jsxs)(`footer`,{className:`shrink-0 border-t ${qU} bg-[#FAFAF7] px-5 py-3 dark:bg-[#1B1C20]`,children:[(0,$.jsxs)(`div`,{className:`flex items-center gap-1`,children:[(0,$.jsxs)(`button`,{type:`button`,onClick:p,disabled:l,className:`flex h-8 flex-1 items-center justify-center gap-1.5 rounded-[4px] bg-[#24543F] text-[13px] font-medium text-white transition-colors hover:bg-[#1D4634] disabled:cursor-not-allowed disabled:opacity-50 dark:bg-[#3F7A5F] dark:hover:bg-[#4B8B6D]`,children:[l?(0,$.jsx)(te,{size:13,className:`animate-spin`}):(0,$.jsx)(se,{size:13}),l?`运行中…`:`重跑此卡`]}),Ne?null:(0,$.jsxs)(`button`,{type:`button`,onClick:()=>d(`prev`),className:`${lW} flex items-center gap-1`,children:[(0,$.jsx)(R,{size:13}),`加上游`]}),(0,$.jsxs)(`button`,{type:`button`,onClick:()=>d(`next`),className:`${lW} flex items-center gap-1`,children:[(0,$.jsx)(P,{size:13}),`加下游`]})]}),(0,$.jsx)(`div`,{className:`mt-1 flex justify-end`,children:(0,$.jsxs)(`button`,{type:`button`,onClick:g,disabled:Ne,title:Ne?`根节点是对话入口(人格来源),不能删除`:void 0,className:`flex items-center gap-1.5 rounded-[4px] px-2.5 py-1.5 text-[12px] text-[#B4451F] transition-colors hover:bg-[#FBEFEA] disabled:cursor-not-allowed disabled:opacity-40 disabled:hover:bg-transparent dark:text-[#e08a6a] dark:hover:bg-[#2A1C17]`,children:[(0,$.jsx)(_e,{size:13}),`删除此卡`]})})]})]})}function pW({title:e,extra:t,children:n}){return(0,$.jsxs)(`section`,{className:`mt-3 rounded-xl border p-3 first:mt-1 ${JU}`,children:[(0,$.jsxs)(`div`,{className:`mb-2.5 flex items-center justify-between gap-2`,children:[(0,$.jsx)(`h3`,{className:`text-[12px] font-semibold tracking-[0.01em] ${WU}`,children:e}),t]}),n]})}function mW({children:e}){return(0,$.jsx)(`p`,{className:`py-1 text-[12px] leading-[1.6] ${KU}`,children:e})}function hW(e,t,n){if(t===n)return!0;let r=new Set([t]),i=[t];for(;i.length;){let t=i.pop();for(let a of e)if(a.from===t){if(a.to===n)return!0;r.has(a.to)||(r.add(a.to),i.push(a.to))}}return!1}function gW(e){return e===`human`?`人工`:e===`jev`?`jev`:e===`self`?`自评`:e||`系统`}function _W(e){e&&(e.style.height=`auto`,e.style.height=`${e.scrollHeight}px`)}var{Text:vW}=RA;function yW({open:e,config:t,servers:n,onClose:r,onSaved:i,onError:a}){let o=t,[s,c]=(0,_.useState)(o?.mock??!1),[l,u]=(0,_.useState)(!1),[d,f]=(0,_.useState)(null),[p,m]=(0,_.useState)(!1),h=(0,_.useRef)(a);(0,_.useEffect)(()=>{h.current=a},[a]),(0,_.useEffect)(()=>{e&&c(o?.mock??!1)},[e,o?.mock]),(0,_.useEffect)(()=>{if(!e)return;let t=!1;return m(!0),ZA.getBridge().then(e=>{t||f(e)}).catch(e=>{t||h.current(`读取模型通道状态失败:${e.message}`)}).finally(()=>{t||m(!1)}),()=>{t=!0}},[e]);async function g(){if(p)return;m(!0);let[e,t]=await Promise.allSettled([ZA.getBridge(),ZA.getModels(!0)]);e.status===`fulfilled`?f(e.value):h.current(`读取模型通道状态失败:${e.reason.message}`),t.status===`rejected`&&h.current(`重新读取模型目录失败:${t.reason.message}`),m(!1)}async function v(e){if(l||!t)return;let n=s;c(e),u(!0);try{let t=await ZA.putConfig({mock:e}),n=typeof t?.mock==`boolean`?t.mock:e;c(n),i({mock:n})}catch(e){c(n),a(`切换 mock 失败:${e.message}`)}finally{u(!1)}}let y=Object.entries(o?.providers??{}),b=o?.mcpServers??n.map(e=>({name:e.name})),x=o?.skillDirs?.length?o.skillDirs:o?.dshPaths?.skills?[o.dshPaths.skills]:[],S=d?d.healthy?(0,$.jsx)(JO,{color:`success`,style:{marginInlineEnd:0},children:`已连接`}):(0,$.jsx)(JO,{color:`warning`,style:{marginInlineEnd:0},children:`未连接`}):(0,$.jsx)(vW,{type:`secondary`,style:{fontSize:12},children:`读取中…`}),C=d&&(d.lastError||d.reason)||``;return(0,$.jsxs)(RD,{open:e,title:`设置`,width:640,centered:!0,onCancel:r,styles:{body:{maxHeight:`calc(100vh - 220px)`,overflowY:`auto`,paddingTop:12}},footer:(0,$.jsx)(uD,{justify:`flex-end`,children:(0,$.jsx)(GS,{onClick:r,children:`关闭`})}),children:[(0,$.jsx)(Kl,{type:`info`,showIcon:!0,title:`模型、MCP 服务器、技能都来自 DSH 的配置。要增删改请到 DSH 的 cordis.patch.yml,AgentFlow 这边只读。`,description:o?.dshPaths?.patch?(0,$.jsxs)(vW,{type:`secondary`,style:{fontSize:12,wordBreak:`break-all`},children:[`patch:`,(0,$.jsx)(vW,{code:!0,style:{fontSize:12},children:o.dshPaths.patch})]}):void 0}),(0,$.jsx)(bW,{title:`模型`,extra:(0,$.jsxs)(vW,{type:`secondary`,style:{fontSize:11},children:[y.length,` 个`]}),children:y.length===0?(0,$.jsx)(ib,{image:ib.PRESENTED_IMAGE_SIMPLE,description:`DSH 没有配置模型提供商`}):y.map(([e,t])=>(0,$.jsx)(Hw,{size:`small`,style:{marginBottom:12},title:(0,$.jsx)(vW,{strong:!0,style:{fontSize:14},children:t.label||e}),extra:t.hasKey?(0,$.jsx)(JO,{color:`green`,style:{marginInlineEnd:0},children:`已配置 key`}):(0,$.jsx)(JO,{color:`red`,style:{marginInlineEnd:0},children:`缺 key`}),children:(0,$.jsx)(VE,{size:`small`,column:1,colon:!1,items:[{key:`provider`,label:`provider`,children:(0,$.jsx)(vW,{code:!0,children:e})},{key:`baseURL`,label:`baseURL`,children:(0,$.jsx)(vW,{code:!0,children:t.baseURL||`—`})},{key:`model`,label:`model`,children:(0,$.jsx)(vW,{code:!0,children:t.model||`—`})}]})},e))}),(0,$.jsxs)(bW,{title:`模型通道`,extra:(0,$.jsx)(GS,{size:`small`,loading:p,onClick:()=>void g(),children:`刷新`}),children:[d&&!d.healthy&&(0,$.jsx)(Kl,{type:`warning`,showIcon:!0,style:{marginBottom:10},title:`DSH 未运行或插件未加载,画布不能调模型`}),(0,$.jsx)(VE,{size:`small`,bordered:!0,column:1,colon:!1,items:[{key:`status`,label:`状态`,children:S},{key:`infoPath`,label:`发现文件`,children:(0,$.jsx)(vW,{code:!0,style:{fontSize:12,wordBreak:`break-all`,userSelect:`text`},title:d?.dir,children:d?.infoPath||`—`})},{key:`version`,label:`版本`,children:d?.version==null?`—`:(0,$.jsx)(vW,{code:!0,children:d.version})},{key:`startedAt`,label:`启动时间`,children:xW(d?.startedAt??null)},{key:`providers`,label:`provider 数`,children:d?String(d.providers):`—`},{key:`modelCount`,label:`模型数`,children:d?String(d.modelCount):`—`},{key:`lastError`,label:`最后错误`,children:C?(0,$.jsx)(vW,{type:`danger`,style:{fontSize:12,wordBreak:`break-all`},children:C}):(0,$.jsx)(vW,{type:`secondary`,children:`—`})}]})]}),(0,$.jsx)(bW,{title:`MCP 服务器`,extra:(0,$.jsxs)(vW,{type:`secondary`,style:{fontSize:11},children:[b.length,` 个`]}),children:b.length===0?(0,$.jsx)(ib,{image:ib.PRESENTED_IMAGE_SIMPLE,description:`DSH 没有配置 MCP 服务器`}):(0,$.jsx)(VE,{size:`small`,bordered:!0,column:1,colon:!1,items:b.map(e=>({key:e.name,label:(0,$.jsx)(vW,{strong:!0,style:{fontSize:13},children:e.name}),children:e.kind?(0,$.jsx)(JO,{style:{marginInlineEnd:0},children:e.kind}):(0,$.jsx)(vW,{type:`secondary`,children:`—`})}))})}),(0,$.jsx)(bW,{title:`技能目录`,extra:(0,$.jsxs)(vW,{type:`secondary`,style:{fontSize:11},children:[x.length,` 个`]}),children:x.length===0?(0,$.jsx)(ib,{image:ib.PRESENTED_IMAGE_SIMPLE,description:`DSH 没有配置技能目录`}):(0,$.jsx)(uD,{vertical:!0,gap:6,children:x.map(e=>(0,$.jsx)(vW,{code:!0,style:{fontSize:12,wordBreak:`break-all`},children:e},e))})}),(0,$.jsx)(bW,{title:`运行模式`,children:(0,$.jsx)(Hw,{size:`small`,children:(0,$.jsxs)(uD,{align:`center`,justify:`space-between`,gap:16,children:[(0,$.jsxs)(`div`,{style:{minWidth:0},children:[(0,$.jsx)(vW,{strong:!0,style:{display:`block`,fontSize:15},children:`mock 模式`}),(0,$.jsx)(vW,{type:`secondary`,style:{display:`block`,fontSize:12},children:`AgentFlow 自己的开关,不属于 DSH 配置。打开后不真正调用模型。`})]}),(0,$.jsx)(qD,{checked:s,loading:l,disabled:!t,onChange:e=>void v(e)})]})})})]})}function bW({title:e,extra:t,children:n}){return(0,$.jsxs)(`section`,{style:{marginTop:20},children:[(0,$.jsxs)(uD,{align:`center`,justify:`space-between`,gap:8,style:{marginBottom:8},children:[(0,$.jsx)(vW,{strong:!0,style:{fontSize:13},children:e}),t]}),n]})}function xW(e){if(typeof e!=`number`||!Number.isFinite(e)||e<=0)return`—`;let t=new Date(e);if(Number.isNaN(t.getTime()))return`—`;let n=e=>String(e).padStart(2,`0`);return`${t.getFullYear()}-${n(t.getMonth()+1)}-${n(t.getDate())} ${n(t.getHours())}:${n(t.getMinutes())}:${n(t.getSeconds())}`}var{Text:SW}=RA,CW=`'SFMono-Regular', Menlo, Consolas, 'Liberation Mono', ui-monospace, monospace`;function wW({open:e,boardId:t,boardName:n,onClose:r}){let{token:i}=ik.useToken(),[a,o]=(0,_.useState)(null),[s,c]=(0,_.useState)(null),[l,u]=(0,_.useState)(!1),[d,f]=(0,_.useState)(``);(0,_.useEffect)(()=>{e&&(o(null),c(null),u(!1),f(n||``))},[e,n]);async function p(){if(!l){u(!0),c(null),o(null);try{let e=await ZA.exportPreset(t,d.trim());o(e)}catch(e){let t=e.message||`未知错误`;t.includes(`HTTP 404`)?c({title:`暂不可用`,detail:`后端还没有这个接口(POST /api/export/preset),等后端上线后再试。`}):t.includes(`HTTP 409`)?c({title:`自定义目录已存在,换个目录`,detail:t}):c({title:`生成失败`,detail:t})}finally{u(!1)}}}let m={border:`1px solid ${i.colorBorderSecondary}`,borderRadius:8,background:i.colorFillTertiary,padding:`10px 12px`,fontFamily:CW,fontSize:12,lineHeight:1.7,whiteSpace:`pre-wrap`,wordBreak:`break-all`,color:i.colorText};return(0,$.jsxs)(RD,{open:e,title:`导出为 DSH 预设`,width:720,centered:!0,onCancel:r,styles:{body:{maxHeight:`calc(100vh - 240px)`,overflowY:`auto`}},footer:(0,$.jsxs)(uD,{justify:`flex-end`,gap:8,children:[(0,$.jsx)(GS,{onClick:r,children:`关闭`}),(0,$.jsx)(GS,{type:`primary`,icon:(0,$.jsx)(H,{size:14}),loading:l,onClick:()=>void p(),children:`生成`})]}),children:[(0,$.jsx)(Kl,{type:`info`,showIcon:!0,title:`把这张画布编译成 DSH 预设,直接写进 dsh-plugin-agentflow 插件包。重启 DSH 后,新会话的预设列表里就能选到它:主 agent 会先和你对齐需求,再按画布结构分层下发子 agent(提示词驱动,不保证严格按 DAG 执行)。`,style:{marginBottom:16}}),(0,$.jsxs)(`div`,{style:{marginBottom:16},children:[(0,$.jsx)(SW,{style:{fontSize:12,display:`block`,marginBottom:6},children:`预设名称`}),(0,$.jsx)(PD,{value:d,onChange:e=>f(e.target.value),placeholder:`在 DSH 预设列表里显示的名字`,maxLength:40,disabled:!!a}),(0,$.jsx)(SW,{type:`secondary`,style:{fontSize:11},children:`只改显示名,预设 id 不变(重复导出还是覆盖同一个预设)。`})]}),s&&(0,$.jsx)(Kl,{type:`error`,showIcon:!0,title:s.title,description:s.detail?(0,$.jsx)(SW,{style:{fontSize:12,fontFamily:CW,wordBreak:`break-all`},children:s.detail}):void 0,style:{marginBottom:16}}),a&&(0,$.jsxs)($.Fragment,{children:[(0,$.jsx)(Kl,{type:`success`,showIcon:!0,title:a.replaced?`预设已更新`:`预设已写入插件`,description:(0,$.jsxs)(`div`,{children:[(0,$.jsxs)(`div`,{style:{marginBottom:6},children:[`已写进 profile 的 `,(0,$.jsx)(`b`,{children:`cordis.patch.yml`}),`(用标记段包裹,重新导出整段替换)。`,(0,$.jsx)(`b`,{children:`重启 DSH 后`}),`,新会话的预设列表里就能选到它。`]}),(0,$.jsxs)(`div`,{style:{marginBottom:4},children:[`预设 id:`,(0,$.jsx)(SW,{code:!0,style:{fontSize:12},children:a.presetId})]}),(0,$.jsxs)(`div`,{children:[`文件:`,(0,$.jsx)(SW,{code:!0,copyable:!0,style:{fontSize:12,wordBreak:`break-all`},children:a.file})]})]}),style:{marginBottom:12}}),(a.addedOrchestrator||a.personaSource)&&(0,$.jsxs)(`div`,{style:{marginBottom:16},children:[(0,$.jsx)(SW,{strong:!0,style:{display:`block`,fontSize:13,marginBottom:6},children:`调度与人设`}),(0,$.jsxs)(uD,{vertical:!0,gap:4,children:[a.addedOrchestrator&&(0,$.jsxs)(SW,{style:{fontSize:13},children:[`已自动补充调度卡:`,(0,$.jsx)(SW,{strong:!0,children:a.addedOrchestrator.label})]}),a.personaSource&&(0,$.jsxs)(SW,{style:{fontSize:13},type:`secondary`,children:[`人格来源:`,EW(a.personaSource)]})]})]}),(0,$.jsxs)(`div`,{style:{marginBottom:16},children:[(0,$.jsx)(SW,{strong:!0,style:{display:`block`,fontSize:13,marginBottom:6},children:`写入文件`}),(0,$.jsx)(JO,{style:{marginInlineEnd:0,fontFamily:CW},children:a.file})]})]}),(0,$.jsxs)(`div`,{children:[(0,$.jsxs)(uD,{align:`baseline`,justify:`space-between`,style:{marginBottom:6},children:[(0,$.jsx)(SW,{strong:!0,style:{fontSize:13},children:`预览人格`}),a?.personaPreview&&(0,$.jsxs)(SW,{type:`secondary`,style:{fontSize:11},children:[a.personaPreview.length,` 字符`]})]}),(0,$.jsx)(`pre`,{style:{...m,margin:0,maxHeight:320,overflowY:`auto`},children:a?.personaPreview||`生成后会在这里显示完整的人格文本。`})]})]})}var TW={orchestrator:`调度(根)节点的人格`,"single-card":`单卡片画布(唯一那张卡)`,"auto-orchestrator":`自动补充的调度卡`};function EW(e){return TW[e]??e}var DW=`border-[#E3E4DF] dark:border-[#262724]`,OW=`text-[#1B1B18] dark:text-[#e8e8e4]`,kW=`text-[#6b6b66] dark:text-[#8b8b85]`,AW=`text-[#8b8b85] dark:text-[#8b8b85]`;function jW(){let[e,t]=(0,_.useState)(`list`),[n,r]=(0,_.useState)([]),[i,a]=(0,_.useState)([]),[o,s]=(0,_.useState)({}),[c,l]=(0,_.useState)(!0),[u,d]=(0,_.useState)(null),[f,p]=(0,_.useState)(null),[m,h]=(0,_.useState)(``),[g,v]=(0,_.useState)(null),[y,b]=(0,_.useState)(null),[x,S]=(0,_.useState)(!1),[C,w]=(0,_.useState)(``),[T,E]=(0,_.useState)(!1),[D,O]=(0,_.useState)(null),[k,A]=(0,_.useState)(``),j=(0,_.useRef)(!1),M=(0,_.useRef)(!1),[N,P]=(0,_.useState)([]),[F,L]=(0,_.useState)([]),[R,z]=(0,_.useState)(null),[B,V]=(0,_.useState)(null),[U,ee]=(0,_.useState)(null),[ne,ie]=(0,_.useState)(!1),[ae,G]=(0,_.useState)(!1),[oe,se]=(0,_.useState)(!1),[ce,le]=(0,_.useState)(!1),J=(0,_.useRef)(!1),ue=(0,_.useRef)(!1),fe=(0,_.useCallback)(()=>{ue.current=!0,se(!0)},[]),pe=(0,_.useCallback)(()=>{ue.current=!1,se(!1)},[]),me=(0,_.useRef)(0),ge=(0,_.useRef)(null);(0,_.useEffect)(()=>{ge.current=f},[f]),(0,_.useEffect)(()=>{if(!f||e!==`board`)return;let t=window.setTimeout(()=>{ZA.putBoard(f.id,f).catch(e=>{console.warn(`[agentflow] 自动保存失败:`,e)}),r(e=>e.map(e=>e.id===f.id?{...e,presetOutdated:!0}:e))},200);return()=>window.clearTimeout(t)},[f,e]),(0,_.useEffect)(()=>{let e=()=>{let e=ge.current;if(e)try{fetch(`/api/boards/${encodeURIComponent(e.id)}`,{method:`PUT`,headers:{"content-type":`application/json`},body:JSON.stringify({board:e}),keepalive:!0}).catch(()=>{})}catch{}};return window.addEventListener(`pagehide`,e),()=>window.removeEventListener(`pagehide`,e)},[]);let[_e,ve]=(0,_.useState)(()=>{try{localStorage.removeItem(`agentflow-theme`)}catch{}try{let e=sessionStorage.getItem(`agentflow-theme`);if(e===`dark`)return!0;if(e===`light`)return!1}catch{}try{let e=new URLSearchParams(window.location.search).get(`theme`);if(e===`dark`)return!0;if(e===`light`)return!1}catch{}try{return window.matchMedia(`(prefers-color-scheme: dark)`).matches}catch{return!1}});(0,_.useEffect)(()=>{document.documentElement.classList.toggle(`dark`,_e);try{sessionStorage.setItem(`agentflow-theme`,_e?`dark`:`light`)}catch{}window.dispatchEvent(new Event(`themechange`))},[_e]);let[ye,be]=(0,_.useState)(null),xe=(0,_.useRef)(null),Y=(0,_.useCallback)((e,t=`ok`)=>{be({msg:e,kind:t}),xe.current&&window.clearTimeout(xe.current),xe.current=window.setTimeout(()=>be(null),3200)},[]),Se=(0,_.useCallback)((e,t)=>{p(n=>n&&{...n,nodes:n.nodes.map(n=>n.id===e?{...n,...t}:n)})},[]),Ce=(0,_.useRef)(null),we=(0,_.useRef)(null);(0,_.useEffect)(()=>{Ce.current=u},[u]),(0,_.useEffect)(()=>{h(f?.name??``)},[f?.id,f?.name]);let Te=(0,_.useCallback)(async(e=!1)=>{e||l(!0);let[t,n]=await Promise.allSettled([ZA.listBoards(),ZA.listPresets()]);if(t.status===`fulfilled`){let e=t.value.boards;r(e);let n=await Promise.allSettled(e.map(e=>ZA.getBoard(e.id))),i={};n.forEach((t,n)=>{t.status===`fulfilled`&&(i[e[n].id]=NW(t.value.board))}),s(i)}else Y(`加载画布列表失败:${t.reason.message}`,`err`);n.status===`fulfilled`?a(n.value.presets):Y(`加载预设列表失败:${n.reason.message}`,`err`),e||l(!1)},[Y]);(0,_.useEffect)(()=>{Te(),ZA.getSkills().then(e=>P(e.skills)).catch(()=>{}),ZA.getMcp().then(e=>L(e.servers)).catch(()=>{}),ZA.getConfig().then(z).catch(()=>{}),ZA.getModels().then(V).catch(()=>{}),ZA.getBridge().then(ee).catch(()=>{})},[Te]);let Ee=(0,_.useRef)(0);(0,_.useEffect)(()=>{g&&(Date.now()-Ee.current<3e4||(Ee.current=Date.now(),ZA.getModels(!0).then(V).catch(()=>{}),ZA.getBridge().then(ee).catch(()=>{})))},[g]);let{running:De,run:Oe,stop:ke}=QA((0,_.useCallback)(e=>{let t=we.current!=null&&Ce.current!==we.current;if((e.type===`run:end`||e.type===`run:error`)&&(we.current=null),!t)switch(e.type){case`node:start`:Se(e.id,{status:`running`});break;case`node:delta`:p(t=>t&&{...t,nodes:t.nodes.map(t=>t.id===e.id?{...t,delta:(t.delta||``)+e.chunk}:t)});break;case`node:done`:Se(e.id,{status:e.status??`done`,content:e.content,usage:e.usage,verdict:e.verdict??null,error:null,delta:void 0});break;case`node:failed`:Se(e.id,{status:`failed`,error:`该节点所有模型都失败`});break;case`node:blocked`:Se(e.id,{status:`blocked`});break;case`node:retry`:p(t=>t&&{...t,nodes:t.nodes.map(t=>t.id===e.id?{...t,delta:void 0}:t)}),Y(`${e.id} 换 ${e.model} 重试:${e.error}`,`err`);break;case`run:end`:{let{done:t,failed:n,blocked:r,review:i}=e.summary,a=[`完成 ${t.length}`];i.length&&a.push(`待确认 ${i.length}`),n.length&&a.push(`失败 ${n.length}`),r.length&&a.push(`阻塞 ${r.length}`),Y(a.join(`,`),n.length||r.length?`err`:`ok`);break}case`run:error`:Y(`运行出错:${e.error}`,`err`)}},[Se,Y])),Ae=(0,_.useCallback)(e=>{let t=Ce.current;t&&(we.current=t,Oe(e,t))},[Oe]),je=(0,_.useCallback)(()=>{we.current=null,ke()},[ke]),Me=(0,_.useCallback)(async e=>{let n=++me.current;t(`board`),d(e),p(null),h(``),v(null),G(!1),pe();let r=await ZA.getBoard(e).then(e=>({status:`fulfilled`,value:e})).catch(e=>({status:`rejected`,reason:e}));n===me.current&&(r.status===`rejected`?(Y(`打开画布失败:${r.reason.message}`,`err`),t(`list`),d(null),pe(),Te(!0)):p(r.value.board))},[Te,Y]),Ne=(0,_.useRef)(typeof window>`u`?null:new URLSearchParams(window.location.search).get(`board`));(0,_.useEffect)(()=>{let e=Ne.current;e&&(Ne.current=null,Me(e))},[Me]);let Pe=(0,_.useCallback)(()=>{me.current+=1,t(`list`),p(null),d(null),v(null),G(!1),pe(),Te(!0)},[Te]);function Fe(){Pe()}function Ie(e){Me(e)}let Le=(0,_.useCallback)(async()=>{let e=ge.current;if(!e)return!1;try{return await ZA.putBoard(e.id,e),pe(),!0}catch(e){return Y(`保存画布失败:${e.message}`,`err`),!1}},[Y,pe]),Re=(0,_.useCallback)(async()=>{let e=ge.current;if(!e||J.current)return!1;J.current=!0,le(!0);try{return await ZA.putBoard(e.id,e),await ZA.exportPreset(e.id,e.name),pe(),r(t=>t.map(t=>t.id===e.id?{...t,name:e.name,nodeCount:e.nodes.length,presetOutdated:!1,updatedAt:Date.now()}:t)),Y(`已保存,预设已更新`),!0}catch(e){return Y(`保存失败:${e.message}`,`err`),!1}finally{J.current=!1,le(!1)}},[Y,pe]);(0,_.useEffect)(()=>{let t=t=>{(t.metaKey||t.ctrlKey)&&String(t.key).toLowerCase()===`s`&&(t.preventDefault(),e===`board`&&window.setTimeout(()=>void Re(),0))};return window.addEventListener(`keydown`,t),()=>window.removeEventListener(`keydown`,t)},[Re,e]);let ze=(0,_.useCallback)(async e=>{f&&(!ue.current||await Le())&&Ae(e)},[f,Le,Ae]),Be=(0,_.useCallback)(async()=>{f&&(!ue.current||await Le())&&G(!0)},[f,Le]),Ve=(0,_.useCallback)((e,t)=>{Se(e,t),fe()},[Se]),He=(0,_.useCallback)(e=>{p(t=>t&&{...t,edges:e}),fe()},[]),Ue=(0,_.useCallback)((e,t,n)=>{f&&(p({...f,nodes:f.nodes.map(r=>r.id===e?{...r,x:t,y:n}:r)}),fe())},[f]),We=(0,_.useCallback)((e,t)=>{if(!f)return;let n=f.nodes.find(t=>t.id===e);if(!n)return;let r=B?.providers.find(e=>e.models.length),i=n.provider||r?.id||``,a=n.model||r?.models[0]?.id||``,o=MW(f.nodes),s={id:o,label:t===`next`?`下游卡片`:`上游卡片`,type:`llm`,x:t===`next`?n.x+360:n.x-360,y:n.y,provider:i,model:a,reasoningEffort:``,fallback:[],fallbackEfforts:{},task:``,criteria:``,skills:[],tools:[],verify:``,content:``,status:`idle`,usage:null,error:null,verdict:null};p({...f,nodes:[...f.nodes,s],edges:[...f.edges,t===`next`?{from:e,to:o}:{from:o,to:e}]}),v(o),fe(),Y(t===`next`?`已派生下游卡片(未保存)`:`已添加上游卡片(未保存)`)},[f,B,Y]),Ge=(0,_.useCallback)((e,t)=>{f&&e!==t&&(f.nodes.find(e=>e.id===t)?.type===`orchestrator`?Y(`根节点是对话入口,不能有上游节点`,`err`):f.edges.some(n=>n.from===e&&n.to===t)||(FW(f.edges,e,t)?Y(`这条连线会形成环,已忽略`,`err`):(p({...f,edges:[...f.edges,{from:e,to:t}]}),fe())))},[f,Y]),Ke=(0,_.useCallback)(e=>{f&&(p({...f,nodes:f.nodes.filter(t=>t.id!==e),edges:f.edges.filter(t=>t.from!==e&&t.to!==e)}),v(null),fe(),Y(`已删除(未保存)`))},[f,Y]),qe=(0,_.useCallback)(async(e,t)=>{if(!ue.current||await Le())try{let n=await ZA.verify(e,t,void 0,Ce.current);Se(e,{status:n.status,verdict:n.verdict}),Y(t?`已通过`:`已打回,可以改完再跑`)}catch(e){Y(`操作失败:${e.message}`,`err`)}},[Se,Y,Le]),Je=(0,_.useMemo)(()=>f?.nodes.find(e=>e.id===g)??null,[f,g]),Ye=(0,_.useMemo)(()=>new Set(n.map(e=>e.presetId).filter(e=>!!e)),[n]),Xe=(0,_.useMemo)(()=>i.filter(e=>!Ye.has(e.id)),[i,Ye]);function Ze(){w(``),S(!0)}async function Qe(){let e=C.trim();if(e&&!T){E(!0);try{let n=await ZA.createBoard({name:e});me.current+=1,S(!1),w(``),p(n.board),d(n.board.id),v(null),pe(),t(`board`),Te(!0)}catch(e){Y(`新建画布失败:${e.message}`,`err`)}finally{E(!1)}}}async function $e(e){if(!y){b(e.id);try{let n=await ZA.importPreset(e.id);Y(n.reused?`已有这张画布:${e.name}`:`已从预设创建画布:${e.name}`),me.current+=1,p(n.board),d(n.board.id),v(null),pe(),t(`board`),Te(!0)}catch(e){let t=e.message;t.includes(`HTTP 501`)?Y(`创建画布功能还没上线(服务端 P1 未完成)`,`err`):Y(`创建画布失败:${t}`,`err`)}finally{b(null)}}}function et(e){O(e.id),A(e.name)}async function tt(e){if(D!==e.id)return;let t=j.current;if(j.current=!1,O(null),t){A(e.name);return}let n=k.trim();if(n&&n!==e.name)try{let t=await ZA.patchBoard(e.id,{name:n});r(r=>r.map(r=>r.id===e.id?{...r,name:n,updatedAt:t.meta?.updatedAt??r.updatedAt}:r)),f?.id===e.id&&p(e=>e&&{...e,name:n}),Y(`画布已重命名`)}catch(e){Y(`重命名失败:${e.message}`,`err`)}}async function nt(e){if(n.length<=1)Y(`至少要保留一张画布`,`err`);else if(window.confirm(`删除画布《${e.name}》?里面的节点会一起删掉,且不可恢复。`))try{await ZA.deleteBoard(e.id),Y(`画布已删除`),await Te(!0)}catch(e){Y(`删除失败:${e.message}`,`err`)}}async function rt(){if(!f)return;let e=M.current;if(M.current=!1,e){h(f.name);return}let t=m.trim();if(!t)h(f.name);else if(t!==f.name)try{let e=await ZA.patchBoard(f.id,{name:t});p(e=>e&&{...e,name:t}),r(n=>n.map(n=>n.id===f.id?{...n,name:t,updatedAt:e.meta?.updatedAt??n.updatedAt}:n)),Y(`画布已重命名`)}catch(e){h(f.name),Y(`重命名失败:${e.message}`,`err`)}}return(0,$.jsx)(Ld,{locale:qA.default,theme:{algorithm:_e?ik.darkAlgorithm:ik.defaultAlgorithm,token:{colorPrimary:`#24543F`,borderRadius:7,fontSize:15,fontFamily:`-apple-system, BlinkMacSystemFont, 'PingFang SC', 'Hiragino Sans GB', ui-sans-serif, sans-serif`},components:{Drawer:{paddingLG:20},Modal:{borderRadiusLG:12},Card:{borderRadiusLG:10}}},children:(0,$.jsxs)(`div`,{className:`flex h-full flex-col`,children:[e===`list`?(0,$.jsxs)(`header`,{className:`flex h-14 shrink-0 items-center gap-3 border-b ${DW} bg-[#FCFCFA] px-5 dark:bg-[#17181b]`,children:[(0,$.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,$.jsx)(`span`,{className:`grid h-7 w-7 place-items-center rounded-[4px] bg-[#24543F] text-white`,children:`◈`}),(0,$.jsx)(`span`,{className:`text-[17px] font-semibold tracking-tight ${OW}`,children:`AgentFlow`})]}),(0,$.jsxs)(`div`,{className:`ml-auto flex items-center gap-2`,children:[(0,$.jsx)(GS,{type:`primary`,icon:(0,$.jsx)(K,{size:14}),onClick:Ze,children:`新建画布`}),(0,$.jsx)(GS,{icon:_e?(0,$.jsx)(he,{size:14}):(0,$.jsx)(re,{size:14}),onClick:()=>ve(e=>!e),title:_e?`切到浅色`:`切到深色`}),(0,$.jsx)(GS,{icon:(0,$.jsx)(de,{size:14}),onClick:()=>ie(!0),children:`设置`})]})]}):(0,$.jsxs)(`header`,{className:`flex h-14 shrink-0 items-center gap-2 border-b ${DW} bg-[#FCFCFA] px-4 dark:bg-[#17181b]`,children:[(0,$.jsxs)(`button`,{type:`button`,onClick:Fe,title:`返回画布列表`,className:`flex shrink-0 items-center gap-1 rounded-[4px] px-2 py-1.5 text-[12px] transition-colors hover:bg-[#EFEFEA] dark:hover:bg-[#232421] ${kW}`,children:[(0,$.jsx)(I,{size:14}),`返回列表`]}),(0,$.jsx)(`div`,{className:`h-5 w-px shrink-0 bg-[#E3E4DF] dark:bg-[#2c2d29]`}),(0,$.jsx)(`input`,{value:m,onChange:e=>h(e.target.value),onBlur:()=>void rt(),onKeyDown:e=>{e.key===`Enter`&&e.currentTarget.blur(),e.key===`Escape`&&(M.current=!0,e.currentTarget.blur())},disabled:!f,placeholder:`画布名称`,"aria-label":`画布名称`,className:`min-w-0 max-w-[280px] flex-1 rounded-[3px] border-0 bg-transparent px-1 py-1 text-[16px] font-semibold tracking-tight outline-none placeholder:text-[#a8a8a0] focus-visible:ring-2 focus-visible:ring-[#24543F]/30 disabled:bg-transparent dark:placeholder:text-[#6f6f68] dark:focus-visible:ring-[#6aa583]/40 ${OW}`}),oe&&(0,$.jsx)(`span`,{title:`有未保存的修改`,"aria-label":`有未保存的修改`,className:`h-1.5 w-1.5 shrink-0 rounded-full bg-[#B4451F] dark:bg-[#e08a6a]`}),(0,$.jsxs)(`div`,{className:`ml-auto flex items-center gap-2`,children:[(0,$.jsx)(GS,{icon:(0,$.jsx)(q,{size:14}),disabled:!f,loading:ce,onClick:()=>void Re(),title:`保存画布并更新预设(⌘S / Ctrl+S)`,children:`保存`}),De?(0,$.jsx)(GS,{danger:!0,icon:(0,$.jsx)(te,{size:14,className:`animate-spin`}),onClick:je,children:`停止`}):(0,$.jsx)(GS,{type:`primary`,icon:(0,$.jsx)(W,{size:14}),disabled:!f,onClick:()=>void ze(),title:`先保存,再跑一遍验证(会真实调用模型)`,children:`验证 AgentFlow`}),(0,$.jsx)(GS,{icon:(0,$.jsx)(H,{size:14}),disabled:!f,onClick:()=>void Be(),children:`导出预设`}),(0,$.jsx)(GS,{icon:_e?(0,$.jsx)(he,{size:14}):(0,$.jsx)(re,{size:14}),onClick:()=>ve(e=>!e),title:_e?`切到浅色`:`切到深色`}),(0,$.jsx)(GS,{icon:(0,$.jsx)(de,{size:14}),onClick:()=>ie(!0),children:`设置`})]})]}),e===`list`?(0,$.jsxs)(`header`,{className:`flex h-14 shrink-0 items-center gap-3 border-b ${DW} bg-[#FCFCFA] px-5 dark:bg-[#17181b]`,children:[(0,$.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,$.jsx)(`span`,{className:`grid h-7 w-7 place-items-center rounded-[4px] bg-[#24543F] text-white`,children:`◈`}),(0,$.jsx)(`span`,{className:`text-[17px] font-semibold tracking-tight ${OW}`,children:`AgentFlow`})]}),(0,$.jsxs)(`div`,{className:`ml-auto flex items-center gap-2`,children:[(0,$.jsx)(GS,{type:`primary`,icon:(0,$.jsx)(K,{size:14}),onClick:Ze,children:`新建画布`}),(0,$.jsx)(GS,{icon:_e?(0,$.jsx)(he,{size:14}):(0,$.jsx)(re,{size:14}),onClick:()=>ve(e=>!e),title:_e?`切到浅色`:`切到深色`}),(0,$.jsx)(GS,{icon:(0,$.jsx)(de,{size:14}),onClick:()=>ie(!0),children:`设置`})]})]}):(0,$.jsxs)(`header`,{className:`flex h-14 shrink-0 items-center gap-2 border-b ${DW} bg-[#FCFCFA] px-4 dark:bg-[#17181b]`,children:[(0,$.jsxs)(`button`,{type:`button`,onClick:Fe,title:`返回画布列表`,className:`flex shrink-0 items-center gap-1 rounded-[4px] px-2 py-1.5 text-[12px] transition-colors hover:bg-[#EFEFEA] dark:hover:bg-[#232421] ${kW}`,children:[(0,$.jsx)(I,{size:14}),`返回列表`]}),(0,$.jsx)(`div`,{className:`h-5 w-px shrink-0 bg-[#E3E4DF] dark:bg-[#2c2d29]`}),(0,$.jsx)(`input`,{value:m,onChange:e=>h(e.target.value),onBlur:()=>void rt(),onKeyDown:e=>{e.key===`Enter`&&e.currentTarget.blur(),e.key===`Escape`&&(M.current=!0,e.currentTarget.blur())},disabled:!f,placeholder:`画布名称`,"aria-label":`画布名称`,className:`min-w-0 max-w-[280px] flex-1 rounded-[3px] border-0 bg-transparent px-1 py-1 text-[16px] font-semibold tracking-tight outline-none placeholder:text-[#a8a8a0] focus-visible:ring-2 focus-visible:ring-[#24543F]/30 disabled:bg-transparent dark:placeholder:text-[#6f6f68] dark:focus-visible:ring-[#6aa583]/40 ${OW}`}),oe&&(0,$.jsx)(`span`,{title:`有未保存的修改`,"aria-label":`有未保存的修改`,className:`h-1.5 w-1.5 shrink-0 rounded-full bg-[#B4451F] dark:bg-[#e08a6a]`}),(0,$.jsxs)(`div`,{className:`ml-auto flex items-center gap-2`,children:[(0,$.jsx)(GS,{icon:(0,$.jsx)(q,{size:14}),disabled:!f,loading:ce,onClick:()=>void Re(),title:`保存画布并更新预设(⌘S / Ctrl+S)`,children:`保存`}),De?(0,$.jsx)(GS,{danger:!0,icon:(0,$.jsx)(te,{size:14,className:`animate-spin`}),onClick:je,children:`停止`}):(0,$.jsx)(GS,{type:`primary`,icon:(0,$.jsx)(W,{size:14}),disabled:!f,onClick:()=>void ze(),title:`先保存,再跑一遍验证(会真实调用模型)`,children:`验证 AgentFlow`}),(0,$.jsx)(GS,{icon:(0,$.jsx)(H,{size:14}),disabled:!f,onClick:()=>void Be(),children:`导出预设`}),(0,$.jsx)(GS,{icon:_e?(0,$.jsx)(he,{size:14}):(0,$.jsx)(re,{size:14}),onClick:()=>ve(e=>!e),title:_e?`切到浅色`:`切到深色`}),(0,$.jsx)(GS,{icon:(0,$.jsx)(de,{size:14}),onClick:()=>ie(!0),children:`设置`})]})]}),e===`list`?(0,$.jsx)(`main`,{className:`min-h-0 flex-1 overflow-y-auto bg-[#F4F5F2] px-6 py-7 dark:bg-[#111214]`,children:(0,$.jsxs)(`div`,{className:`mx-auto w-full max-w-[1080px]`,children:[(0,$.jsxs)(`div`,{className:`mb-5`,children:[(0,$.jsx)(`h1`,{className:`text-[20px] font-semibold tracking-tight ${OW}`,children:`画布`}),(0,$.jsx)(`p`,{className:`mt-1 text-[12px] leading-[1.6] ${kW}`,children:`每张画布对应一个 DSH 预设;编辑会自动保存,点「保存」才会更新/生成预设。`})]}),c&&n.length===0?(0,$.jsx)(`div`,{className:`py-16 text-center text-[13px] ${kW}`,children:`正在加载画布…`}):(0,$.jsxs)($.Fragment,{children:[n.length===0?(0,$.jsx)(`div`,{className:`rounded-[8px] border border-dashed ${DW} py-14 text-center text-[13px] ${kW}`,children:`还没有画布,点右上角「新建画布」开始。`}):(0,$.jsx)(`div`,{className:`grid grid-cols-1 gap-3 md:grid-cols-2 xl:grid-cols-3`,children:n.map(e=>{let t=e.presetId?i.find(t=>t.id===e.presetId):null;return(0,$.jsxs)(`article`,{className:`flex min-h-[150px] flex-col rounded-[8px] border ${DW} bg-[#FCFCFA] p-4 dark:bg-[#17181B]`,children:[(0,$.jsxs)(`div`,{className:`flex items-start gap-2`,children:[(0,$.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[D===e.id?(0,$.jsx)(PD,{size:`small`,autoFocus:!0,maxLength:60,value:k,onChange:e=>A(e.target.value),onBlur:()=>void tt(e),onPressEnter:e=>e.currentTarget.blur(),onKeyDown:e=>{e.key===`Escape`&&(j.current=!0,e.currentTarget.blur())},"aria-label":`重命名画布 ${e.name}`}):(0,$.jsx)(`button`,{type:`button`,onClick:()=>Ie(e.id),title:e.name,className:`block max-w-full text-left`,children:(0,$.jsx)(`h2`,{className:`truncate text-[15px] font-semibold ${OW}`,children:e.name})}),(0,$.jsxs)(`p`,{className:`mt-1 text-[11px] leading-[1.6] ${AW}`,children:[e.nodeCount,` 个节点 · 更新于 `,PW(e.updatedAt)]}),o[e.id]!==void 0&&(0,$.jsxs)(`p`,{className:`mt-0.5 truncate text-[11px] leading-[1.6] ${kW}`,title:o[e.id]||`没有调度卡,首次导出会自动补一张`,children:[`对话入口:`,o[e.id]||`未设置(首次导出会自动补一张调度卡)`]})]}),(0,$.jsxs)(`div`,{className:`flex shrink-0 flex-col items-end gap-1`,children:[(0,$.jsx)(JO,{color:t?`blue`:`default`,style:{marginInlineEnd:0},children:t?t.name:`自定义`}),e.presetOutdated&&(0,$.jsx)(JO,{color:`orange`,style:{marginInlineEnd:0},children:`预设未更新`}),e.hasDraft&&(0,$.jsx)(JO,{color:`gold`,style:{marginInlineEnd:0},children:`草稿`})]})]}),(0,$.jsxs)(`div`,{className:`mt-auto flex flex-wrap items-center gap-1 pt-3`,children:[(0,$.jsx)(GS,{size:`small`,type:`primary`,onClick:()=>Ie(e.id),children:`编辑`}),(0,$.jsx)(GS,{size:`small`,type:`text`,onClick:()=>et(e),children:`重命名`}),(0,$.jsx)(GS,{size:`small`,type:`text`,danger:!0,disabled:n.length<=1,title:n.length<=1?`至少要保留一张画布`:void 0,onClick:()=>void nt(e),children:`删除`})]})]},e.id)})}),Xe.length>0&&(0,$.jsxs)($.Fragment,{children:[(0,$.jsxs)(`div`,{className:`mb-3 mt-8 flex flex-wrap items-baseline gap-2`,children:[(0,$.jsx)(`h2`,{className:`text-[13px] font-semibold ${OW}`,children:`还没有画布的预设`}),(0,$.jsx)(`span`,{className:`text-[11px] ${AW}`,children:`从预设生成一张单卡片画布,再继续编辑`})]}),(0,$.jsx)(`div`,{className:`grid grid-cols-1 gap-3 md:grid-cols-2 xl:grid-cols-3`,children:Xe.map(e=>(0,$.jsxs)(`article`,{className:`flex min-h-[150px] flex-col rounded-[8px] border border-dashed ${DW} bg-[#F9F9F6] p-4 dark:bg-[#151617]`,children:[(0,$.jsxs)(`div`,{className:`flex items-start gap-2`,children:[(0,$.jsx)(`h2`,{className:`min-w-0 flex-1 truncate text-[15px] font-semibold ${OW}`,title:e.name,children:e.name}),(0,$.jsx)(JO,{style:{marginInlineEnd:0,flexShrink:0},children:e.source===`bundle`?`bundle`:`自定义`})]}),(0,$.jsx)(`p`,{className:`mt-1 line-clamp-3 text-[12px] leading-[1.6] ${kW}`,children:e.description||`没有描述`}),(0,$.jsx)(`div`,{className:`mt-auto pt-3`,children:(0,$.jsx)(GS,{size:`small`,loading:y===e.id,onClick:()=>void $e(e),children:`创建画布`})})]},e.id))})]})]})]})}):(0,$.jsxs)(`main`,{className:`relative min-h-0 flex-1`,children:[(0,$.jsxs)(`div`,{className:`pointer-events-none absolute left-4 top-[12px] z-10 flex items-center gap-1.5 rounded-[4px] bg-[#FCFCFA]/90 px-2 py-1 text-[11px] text-[#6b6b66] dark:bg-[#17181b]/90 dark:text-[#8b8b85]`,children:[(0,$.jsx)(`span`,{className:`h-[5px] w-[5px] rounded-full`,style:{background:R?R.mock?`#B4451F`:`#24543F`:`#b9bcb4`}}),R?R.mock?`mock`:`real`:`连接中`]}),f?(0,$.jsx)(UU,{board:f,selectedId:g,running:De,onSelect:v,onMove:Ue,onDerive:We,onConnect:Ge}):(0,$.jsx)(`div`,{className:`grid h-full place-items-center text-[13px] text-[#8a93a3]`,children:`正在加载画布…`})]}),e===`board`&&f&&Je&&(0,$.jsx)(uW,{node:Je,nodes:f.nodes,edges:f.edges,boardId:f.id,skills:N,servers:F,catalog:B,bridge:U,running:De,onPatch:e=>Ve(Je.id,e),onDerive:e=>We(Je.id,e),onVerify:e=>void qe(Je.id,e),onEdgesChange:He,onRefreshModels:()=>{Ee.current=Date.now(),ZA.getModels(!0).then(V).catch(e=>Y(`刷新模型失败:${e.message}`,`err`)),ZA.getBridge().then(ee).catch(()=>{})},onRerun:()=>void ze([Je.id]),onDelete:()=>void Ke(Je.id),onClose:()=>v(null)}),(0,$.jsx)(yW,{open:ne,config:R,servers:F,onClose:()=>ie(!1),onSaved:e=>{z(t=>t&&{...t,mock:e.mock}),ZA.getMcp().then(e=>L(e.servers)).catch(()=>{}),Y(`设置已保存`)},onError:e=>Y(e,`err`)}),(0,$.jsx)(wW,{open:ae,boardId:u,boardName:m,onClose:()=>G(!1)}),(0,$.jsx)(RD,{open:x,title:`新建画布`,centered:!0,okText:`创建`,cancelText:`取消`,confirmLoading:T,okButtonProps:{disabled:!C.trim()},onOk:()=>void Qe(),onCancel:()=>S(!1),children:(0,$.jsx)(PD,{autoFocus:!0,maxLength:60,placeholder:`画布名称,例如「活动文案」`,value:C,onChange:e=>w(e.target.value),onPressEnter:()=>{C.trim()&&!T&&Qe()}})}),ye&&(0,$.jsx)(`div`,{className:`fixed bottom-6 left-1/2 z-50 -translate-x-1/2 rounded-lg px-4 py-2 text-[13px] shadow-lg ${ye.kind===`err`?`bg-[#ffebee] text-[#c62828] dark:bg-[#3a1b1f] dark:text-[#ff9a9a]`:`bg-[#1C1C1A] text-white dark:bg-[#e7e9ee] dark:text-[#0f1116]`}`,children:ye.msg})]})})}function MW(e){let t=`n-${Date.now().toString(36)}`,n=t,r=2;for(;e.some(e=>e.id===n);)n=`${t}-${r++}`;return n}function NW(e){let t=e.nodes.find(e=>e.type===`orchestrator`)??(e.nodes.length===1?e.nodes[0]:null);return t?t.label||t.id:null}function PW(e){if(!e)return`—`;let t=new Date(e);if(Number.isNaN(t.getTime()))return`—`;let n=e=>String(e).padStart(2,`0`);return`${t.getFullYear()}-${n(t.getMonth()+1)}-${n(t.getDate())} ${n(t.getHours())}:${n(t.getMinutes())}`}function FW(e,t,n){let r=new Set,i=[n];for(;i.length;){let n=i.pop();if(n===t)return!0;if(!r.has(n)){r.add(n);for(let t of e)t.from===n&&i.push(t.to)}}return!1}(0,v.createRoot)(document.getElementById(`root`)).render((0,$.jsx)(_.StrictMode,{children:(0,$.jsx)(jW,{})}));
348
+ `,cW=`w-full rounded-lg border border-[#E1E2DD] bg-[#FCFCFA] px-2.5 py-2 text-[13px] leading-[1.65] text-[#1B1B18] outline-none transition-colors placeholder:text-[#9a9a92] focus:border-[#24543F] focus:bg-white dark:border-[#33353B] dark:bg-[#17181B] dark:text-[#EDEDE8] dark:focus:border-[#6aa583] dark:focus:bg-[#1B1C20]`,lW=`rounded-[4px] px-2.5 py-1.5 text-[12px] text-[#5b6472] transition-colors hover:bg-[#EFEFEA] dark:text-[#a3a39b] dark:hover:bg-[#232421]`;function uW(e){return(0,$.jsxs)(`aside`,{className:`af-panel fixed bottom-0 right-0 top-14 z-30 flex w-[420px] flex-col border-l border-[#E3E4DF] bg-[#FCFCFA] dark:border-[#262724] dark:bg-[#17181B]`,role:`complementary`,"aria-label":`节点详情`,children:[(0,$.jsx)(`style`,{children:sW}),(0,$.jsx)(fW,{...e},e.node.id)]})}function dW(e,...t){let n=e.trim().toLowerCase();return!n||t.some(e=>String(e??``).toLowerCase().includes(n))}function fW(e){let{node:t,nodes:n,edges:r,boardId:i,skills:a,servers:o,catalog:s,bridge:c,running:l,onPatch:u,onDerive:d,onVerify:f,onRerun:p,onRefreshModels:m,onEdgesChange:h,onDelete:g,onClose:v}=e,[y,b]=(0,_.useState)(t.label),[x,S]=(0,_.useState)(t.task),[C,w]=(0,_.useState)(t.criteria),[T,E]=(0,_.useState)(tW),[D,O]=(0,_.useState)(0),[k,A]=(0,_.useState)(``),[j,M]=(0,_.useState)(``),[N,F]=(0,_.useState)(null),I=(0,_.useRef)(null),L=(0,_.useRef)(null);(0,_.useEffect)(()=>{_W(I.current)},[x]),(0,_.useEffect)(()=>{_W(L.current)},[C]);let z=(0,_.useRef)(u);(0,_.useEffect)(()=>{z.current=u},[u]);let B=(0,_.useRef)({}),V=(0,_.useRef)(null),H=(0,_.useCallback)(()=>{V.current!==null&&(window.clearTimeout(V.current),V.current=null);let e=B.current;Object.keys(e).length&&(B.current={},z.current(e))},[]),U=(0,_.useCallback)(e=>{B.current={...B.current,...e},V.current!==null&&window.clearTimeout(V.current),V.current=window.setTimeout(H,400)},[H]);(0,_.useEffect)(()=>()=>{if(V.current!==null){window.clearTimeout(V.current),V.current=null;let e=B.current;Object.keys(e).length&&z.current(e)}},[]),(0,_.useEffect)(()=>{let e=e=>{(e.metaKey||e.ctrlKey)&&String(e.key).toLowerCase()===`s`&&H()};return window.addEventListener(`keydown`,e),()=>window.removeEventListener(`keydown`,e)},[H]);let[W,ee]=(0,_.useState)(r);(0,_.useEffect)(()=>{ee(r)},[r]);let ne=new Set(W.filter(e=>e.to===t.id).map(e=>e.from)),re=n.filter(e=>e.id!==t.id);function ie(e){let n=[...W.filter(e=>e.to!==t.id),...e.map(e=>({from:e,to:t.id}))];ee(n),h(n)}function ae(e,n){let r=new Set(t.skills);n?r.add(e):r.delete(e),u({skills:[...r]})}let G=s?.providers??[],K=t.provider&&t.model?`${t.provider}/${t.model}`:``,oe=G.some(e=>e.id===t.provider&&e.models.some(e=>e.id===t.model)),ce=t.model&&!oe?t.model:``,q=oe?G.find(e=>e.id===t.provider)?.models.find(e=>e.id===t.model)??null:null,le=q?.levels??[],ue=q?.defaultLevel??``,de=G.every(e=>!e.models.length),fe=new Set,pe=[];for(let e of T){let{provider:t,model:n}=rW(e.value),r=G.find(e=>e.id===t),i=r?.models.find(e=>e.id===n);r&&i&&!fe.has(e.value)&&(fe.add(e.value),pe.push({title:i.name,label:`${r.label} · ${i.name}`,value:`${QU}${e.value}`}))}let me=[];pe.length&&me.push({title:`最近使用`,label:`最近使用`,value:XU,selectable:!1,children:pe}),ce&&me.push({title:`当前值`,label:`当前值`,value:ZU,selectable:!1,children:[{title:ce,label:iW(t.provider,ce),value:YU}]});for(let e of G){let t=e.models.length;me.push({title:t?`${e.label}(${t})`:e.label,label:e.label,value:`p:${e.id}`,selectable:!1,children:e.error?[{title:e.error,label:e.error,value:`e:${e.id}`,disabled:!0}]:e.models.map(t=>({title:t.name,label:`${e.label} · ${t.name}`,value:`${e.id}/${t.id}`}))})}let he=G.find(e=>e.id===t.provider),ge=T.map(e=>e.provider).find(e=>G.some(t=>t.id===e)),ve=he?.id??ge??``,ye=[...pe.length?[XU]:[],...ce?[ZU]:[],...ve?[`p:${ve}`]:[]],be=oe?K:ce?YU:void 0,Y=t.fallback??[],Se=t.fallbackEfforts??{},Ce=new Set(Y),we=G.map(e=>{let t=e.models.length,n=e.error?[{title:e.error,label:e.error,value:`e:${e.id}`,disabled:!0}]:e.models.filter(t=>{let n=`${e.id}/${t.id}`;return n!==K&&!Ce.has(n)}).map(t=>({title:t.name,label:`${e.label} · ${t.name}`,value:`${e.id}/${t.id}`}));return{title:t?`${e.label}(${t})`:e.label,label:e.label,value:`p:${e.id}`,selectable:!1,children:n}}).filter(e=>e.children.length>0),Te=ve?[`p:${ve}`]:[];function Ee(e){if(!e||e===YU)return;let n=e.startsWith(QU)?e.slice(2):e,{provider:r,model:i}=rW(n),a=G.find(e=>e.id===r),o=a?.models.find(e=>e.id===i);if(!a||!o)return;let s=o.levels.includes(t.reasoningEffort??``)?t.reasoningEffort??``:``,c={value:n,label:o.name,provider:r},l=[c,...T.filter(e=>e.value!==c.value)].slice(0,eW);E(l),nW(l),u({provider:r,model:i,reasoningEffort:s})}function De(e){let{provider:t,model:n}=rW(e),r=G.find(e=>e.id===t),i=r?.models.find(e=>e.id===n);return!r||!i?{label:`${e}(不在 DSH 目录里)`,levels:[]}:{label:`${r.label} · ${i.name}`,levels:i.levels}}function Oe(e,t){u({fallback:e,fallbackEfforts:t})}function ke(e){e&&e.includes(`/`)&&!Ce.has(e)&&(Oe([...Y,e],{...Se,[e]:``}),O(e=>e+1))}function Ae(e){let t={...Se};delete t[e],Oe(Y.filter(t=>t!==e),t)}function je(e,t){Oe(Y,{...Se,[e]:t})}let Me=aW[t.status]??aW.idle,Ne=t.type===`orchestrator`,Pe=n.some(e=>e.id!==t.id&&e.type===`orchestrator`),Fe=MU.map(e=>({...e,disabled:e.value===`orchestrator`&&Pe})),Ie=oW.find(e=>e.value===(t.verify??``))??oW[0],Le=t.status===`review`,Re=a.filter(e=>dW(k,e.name,e.description)),ze=o.map(e=>({...e,tools:e.tools.filter(e=>dW(j,e.name,e.description))})).filter(e=>dW(j,e.name)||e.tools.length>0),Be=j.trim()?ze.map(e=>e.name):N??o.filter(e=>e.ok&&e.tools.length).slice(0,1).map(e=>e.name);return(0,$.jsxs)($.Fragment,{children:[(0,$.jsxs)(`header`,{className:`flex shrink-0 items-center gap-2 border-b ${qU} bg-[#FAFAF7] px-5 py-3.5 dark:bg-[#1B1C20]`,children:[(0,$.jsx)(`input`,{value:y,onChange:e=>{let t=e.target.value;b(t),U({label:t})},onBlur:H,onKeyDown:e=>{e.key===`Enter`&&e.currentTarget.blur()},placeholder:`节点名称`,"aria-label":`节点名称`,className:`min-w-0 flex-1 rounded-[3px] border-0 bg-transparent p-0 text-[17px] font-semibold tracking-tight outline-none placeholder:text-[#a8a8a0] focus-visible:ring-2 focus-visible:ring-[#24543F]/30 dark:placeholder:text-[#6f6f68] dark:focus-visible:ring-[#6aa583]/40 ${WU}`}),(0,$.jsxs)(`span`,{className:`flex shrink-0 items-center gap-1.5 text-[12px] ${GU}`,children:[(0,$.jsx)(`span`,{className:`h-[6px] w-[6px] rounded-full ${Me.dot}`}),Me.label]}),(0,$.jsx)(`button`,{type:`button`,onClick:v,"aria-label":`关闭详情`,title:`关闭`,className:`-mr-1 grid h-8 w-8 shrink-0 place-items-center rounded-[4px] text-[#6b6b66] transition-colors hover:bg-[#EFEFEA] dark:text-[#8b8b85] dark:hover:bg-[#232421]`,children:(0,$.jsx)(xe,{size:16})})]}),t.verdict&&(0,$.jsxs)(`div`,{className:`shrink-0 border-b px-5 py-2 text-[12px] leading-[1.5] ${qU} ${t.verdict.pass?`bg-[#EEF3EF] text-[#24543F] dark:bg-[#1B2A22] dark:text-[#8FC3A7]`:`bg-[#FBEFEA] text-[#B4451F] dark:bg-[#2A1C17] dark:text-[#E08A6A]`}`,children:[gW(t.verdict.by),` `,t.verdict.pass?`通过`:`未通过`,t.verdict.reason?`:${t.verdict.reason}`:``]}),t.error&&(0,$.jsx)(`div`,{className:`shrink-0 border-b px-5 py-2 text-[12px] leading-[1.5] ${qU} bg-[#FBEFEA] text-[#B4451F] dark:bg-[#2A1C17] dark:text-[#E08A6A]`,children:t.error}),(0,$.jsxs)(`div`,{className:`min-h-0 flex-1 overflow-y-auto px-4 pb-6 pt-3`,children:[Ne?null:(0,$.jsxs)(pW,{title:`节点类型`,children:[(0,$.jsx)(Fb,{value:t.type||`llm`,onChange:e=>u({type:e}),options:Fe,"aria-label":`节点类型`,className:`w-full`,size:`middle`}),Pe?(0,$.jsx)(`p`,{className:`mt-1.5 text-[11px] leading-[1.5] ${KU}`,children:`画布已有根节点,这张卡不能再设为调度卡。`}):null]}),(0,$.jsx)(pW,{title:`模型`,extra:(0,$.jsxs)(`button`,{type:`button`,onClick:m,title:`重新读取 DSH 的模型目录`,className:`flex items-center gap-1 text-[11px] transition-opacity hover:opacity-70 ${KU}`,children:[(0,$.jsx)(se,{size:11}),`刷新`]}),children:(0,$.jsxs)(`div`,{className:`space-y-1.5`,children:[(0,$.jsx)(Lk,{value:be,placeholder:`选择模型`,showSearch:!0,treeNodeFilterProp:`title`,treeDefaultExpandAll:!1,treeDefaultExpandedKeys:ye,treeNodeLabelProp:`label`,treeData:me,onChange:Ee,"aria-label":`模型`,className:`w-full`,size:`middle`}),(0,$.jsx)(Fb,{value:t.reasoningEffort??``,onChange:e=>u({reasoningEffort:e}),disabled:!le.length,"aria-label":`推理强度`,title:le.length?`推理强度`:`当前模型没有可选推理档位`,options:[{value:``,label:`推理强度:模型默认${ue?`(${ue})`:``}`},...le.map(e=>({value:e,label:e}))],className:`w-full`,size:`middle`}),de&&(0,$.jsxs)(`div`,{className:`flex items-start gap-1.5 text-[11px] leading-[1.6] ${GU}`,children:[(0,$.jsx)(`span`,{className:`mt-[5px] h-[3px] w-[3px] shrink-0 rounded-full bg-current opacity-50`}),(0,$.jsx)(`span`,{children:`没读到 DSH 的模型目录,检查 DSH 凭据或网络。`})]}),(0,$.jsxs)(`div`,{className:`flex items-start gap-1.5 border-t border-[#EDEEE9] pt-2 text-[11px] leading-[1.6] dark:border-[#2A2C31] ${c&&!c.healthy?`text-[#B4451F] dark:text-[#e08a6a]`:GU}`,children:[(0,$.jsx)(`span`,{className:`mt-[5px] h-[3px] w-[3px] shrink-0 rounded-full bg-current opacity-60`}),(0,$.jsxs)(`span`,{children:[`模型通道:DSH 内核(未连接时不可跑图)`,c&&!c.healthy?` · ${c.reason||`原因未知`}`:``]})]})]})}),(0,$.jsx)(pW,{title:`兜底模型`,extra:Y.length?(0,$.jsxs)(`span`,{className:`text-[11px] ${GU}`,children:[Y.length,` 个 · 按顺序重试`]}):void 0,children:(0,$.jsxs)(`div`,{className:`space-y-1.5`,children:[Y.map(e=>{let t=De(e);return(0,$.jsxs)(`div`,{className:`flex min-h-[32px] items-center gap-2 border-b py-1 last:border-b-0 ${qU}`,children:[(0,$.jsx)(`span`,{className:`min-w-0 flex-1 truncate text-[12px] ${WU}`,title:t.label,children:t.label}),(0,$.jsx)(Fb,{size:`small`,value:Se[e]??``,disabled:!t.levels.length,title:t.levels.length?`这条兜底的推理强度`:`该模型没有可选推理档位`,options:[{value:``,label:`模型默认`},...t.levels.map(e=>({value:e,label:e}))],onChange:t=>je(e,t),"aria-label":`${t.label} 的推理强度`,style:{width:104}}),(0,$.jsx)(`button`,{type:`button`,onClick:()=>Ae(e),"aria-label":`移除兜底模型 ${t.label}`,title:`移除`,className:`grid h-7 w-7 shrink-0 place-items-center rounded-[4px] transition-colors hover:bg-[#FBEFEA] hover:text-[#B4451F] dark:hover:bg-[#2A1C17] dark:hover:text-[#e08a6a] ${KU}`,children:(0,$.jsx)(xe,{size:13})})]},e)}),(0,$.jsx)(Lk,{onChange:ke,placeholder:`添加兜底模型…`,showSearch:!0,treeNodeFilterProp:`title`,treeDefaultExpandAll:!1,treeDefaultExpandedKeys:Te,treeNodeLabelProp:`label`,treeData:we,"aria-label":`添加兜底模型`,className:`w-full`,size:`middle`},D),(0,$.jsxs)(`div`,{className:`flex items-start gap-1.5 pt-0.5 text-[11px] leading-[1.6] ${GU}`,children:[(0,$.jsx)(`span`,{className:`mt-[5px] h-[3px] w-[3px] shrink-0 rounded-full bg-current opacity-50`}),(0,$.jsx)(`span`,{children:`兜底模型:主模型失败后按顺序尝试,可单独设推理强度`})]})]})}),(0,$.jsxs)(pW,{title:Ne?`人格`:`任务`,children:[(0,$.jsx)(`textarea`,{ref:I,rows:3,value:x,onChange:e=>{S(e.target.value),U({task:e.target.value}),_W(e.currentTarget)},onBlur:H,placeholder:Ne?`默认:只负责和用户对话,再严格按后续节点的 AgentFlow 流执行(可自己改)`:`写清楚这张卡要做什么…`,className:`${cW} max-h-[240px] resize-none overflow-y-auto`}),Ne&&(0,$.jsx)(`p`,{className:`mt-1.5 text-[11px] leading-[1.5] ${KU}`,children:`默认人格只是起点,可以自己改:它只负责和用户对话,确认需求后严格按后续节点的流程执行。`})]}),(0,$.jsx)(pW,{title:`完成标准`,children:(0,$.jsx)(`textarea`,{ref:L,rows:2,value:C,onChange:e=>{w(e.target.value),U({criteria:e.target.value}),_W(e.currentTarget)},onBlur:H,placeholder:`做到什么程度算完成…`,className:`${cW} max-h-[200px] resize-none overflow-y-auto`})}),(0,$.jsxs)(pW,{title:`结果判断`,children:[(0,$.jsx)(`div`,{role:`radiogroup`,"aria-label":`结果判断`,className:`flex gap-[2px] rounded-[6px] bg-[#EFEFEA] p-[3px] dark:bg-[#232421]`,children:oW.map(e=>{let n=(t.verify??``)===e.value;return(0,$.jsx)(`button`,{type:`button`,role:`radio`,"aria-checked":n,title:e.desc,onClick:()=>u({verify:e.value}),className:`flex-1 rounded-[4px] px-1 py-[5px] text-[13px] leading-[1.3] transition-colors ${n?`bg-white text-[#1B1B18] shadow-[0_1px_2px_rgba(0,0,0,0.06)] dark:bg-[#3A3B35] dark:text-[#e8e8e4]`:`hover:text-[#1B1B18] dark:hover:text-[#e8e8e4] ${GU}`}`,children:e.label},e.value||`none`)})}),(0,$.jsx)(`p`,{className:`mt-1.5 text-[11px] leading-[1.5] ${KU}`,children:Ie.desc}),(t.verify??``)===`jev`&&(0,$.jsx)(`p`,{className:`mt-1.5 rounded-[4px] border border-[#E9D9B8] bg-[#FBF4E6] px-2 py-1.5 text-[11px] leading-[1.5] text-[#8a6220] dark:border-[#4a3a1c] dark:bg-[#2a2314] dark:text-[#e0b866]`,children:`需要本机安装 jev(TypeSafe)并配置 API key,否则这张卡跑到判定时会失败。`})]}),(0,$.jsx)(pW,{title:`技能`,extra:(0,$.jsxs)(`span`,{className:`text-[11px] ${KU}`,children:[`已选 `,t.skills.length]}),children:a.length===0?(0,$.jsx)(mW,{children:`没有找到技能`}):(0,$.jsxs)($.Fragment,{children:[(0,$.jsx)(PD,{value:k,onChange:e=>A(e.target.value),allowClear:!0,size:`middle`,placeholder:`搜索技能名或描述…`,"aria-label":`搜索技能`,prefix:(0,$.jsx)(J,{size:12,className:KU}),className:`mb-2`}),Re.length===0?(0,$.jsxs)(mW,{children:[`没有匹配「`,k.trim(),`」的技能`]}):null,(0,$.jsx)(`div`,{className:`max-h-[180px] overflow-y-auto`,children:Re.map(e=>{let n=t.skills.includes(e.name);return(0,$.jsx)(YT,{className:`af-row`,checked:n,onChange:t=>ae(e.name,t.target.checked),title:e.description,children:(0,$.jsxs)(`span`,{className:`flex min-w-0 flex-1 items-center gap-2`,children:[(0,$.jsx)(`span`,{className:`shrink-0 text-[13px] ${WU}`,children:e.name}),(0,$.jsx)(`span`,{className:`min-w-0 flex-1 truncate text-right text-[11px] ${KU}`,children:e.description||`无描述`})]})},e.name)})})]})}),(0,$.jsx)(pW,{title:`MCP 工具`,extra:(0,$.jsxs)(`span`,{className:`text-[11px] ${KU}`,children:[`已选 `,t.tools.length]}),children:o.length===0?(0,$.jsx)(mW,{children:`还没配置 MCP 服务器`}):(0,$.jsxs)($.Fragment,{children:[(0,$.jsx)(PD,{value:j,onChange:e=>M(e.target.value),allowClear:!0,size:`middle`,placeholder:`搜索服务器或工具…`,"aria-label":`搜索 MCP 工具`,prefix:(0,$.jsx)(J,{size:12,className:KU}),className:`mb-2`}),ze.length===0?(0,$.jsxs)(mW,{children:[`没有匹配「`,j.trim(),`」的工具`]}):null,(0,$.jsx)(`div`,{className:`max-h-[180px] overflow-y-auto af-tree`,children:(0,$.jsx)(FO,{checkable:!0,selectable:!1,expandedKeys:Be,onExpand:e=>F(e),treeData:ze.map(e=>({key:e.name,selectable:!1,title:(0,$.jsxs)(`span`,{className:`flex items-center gap-2`,children:[(0,$.jsx)(`span`,{className:`h-[5px] w-[5px] shrink-0 rounded-full ${e.ok?`bg-[#24543F] dark:bg-[#6aa583]`:`bg-[#B4451F] dark:bg-[#e08a6a]`}`}),(0,$.jsx)(`span`,{className:`text-[12px] font-medium ${WU}`,children:e.name}),(0,$.jsxs)(`span`,{className:`text-[11px] ${KU}`,children:[e.tools.length,` 个工具`]}),!e.ok&&(0,$.jsx)(`span`,{className:`text-[11px] text-[#B4451F] dark:text-[#e08a6a]`,children:`连接失败`})]}),children:e.tools.map(t=>({key:`${e.name}.${t.name}`,title:(0,$.jsxs)(`span`,{className:`flex min-w-0 flex-1 items-center gap-2`,children:[(0,$.jsx)(`span`,{className:`shrink-0 text-[13px] ${WU}`,children:t.name}),(0,$.jsx)(`span`,{className:`min-w-0 flex-1 truncate text-right text-[11px] ${KU}`,children:t.description})]})}))})),checkedKeys:t.tools,onCheck:e=>{let t=Array.isArray(e)?e:e.checked;u({tools:t.filter(e=>String(e).includes(`.`))})}})})]})}),Ne?null:(0,$.jsx)(pW,{title:`上游`,children:re.length===0?(0,$.jsx)(mW,{children:`还没有其它卡片`}):(0,$.jsx)(`div`,{className:`max-h-[180px] overflow-y-auto`,children:re.map(e=>{let n=ne.has(e.id),r=!n&&hW(W,t.id,e.id),i=n?[...ne].filter(t=>t!==e.id):[...ne,e.id];return(0,$.jsx)(YT,{className:`af-row ${r?`af-row-disabled`:``}`,checked:n,disabled:r,onChange:()=>ie(i),children:(0,$.jsxs)(`span`,{className:`flex min-w-0 flex-1 items-center gap-2`,children:[(0,$.jsx)(`span`,{className:`min-w-0 flex-1 truncate text-[13px] ${WU}`,children:e.label||e.id}),r&&(0,$.jsx)(`span`,{className:`shrink-0 text-[11px] ${KU}`,children:`会成环`})]})},e.id)})})})]}),Le&&(0,$.jsxs)(`div`,{className:`shrink-0 border-t ${qU} bg-[#FAEFE6] px-5 py-3 dark:bg-[#2A1C17]`,children:[(0,$.jsx)(`p`,{className:`text-[12px] text-[#B4451F] dark:text-[#e08a6a]`,children:`这张卡跑完了,等你判断结果`}),(0,$.jsxs)(`div`,{className:`mt-2 flex gap-2`,children:[(0,$.jsx)(`button`,{type:`button`,onClick:()=>f(!0),className:`h-8 flex-1 rounded-[4px] bg-[#24543F] text-[13px] font-medium text-white transition-colors hover:bg-[#1D4634] dark:bg-[#3F7A5F] dark:hover:bg-[#4B8B6D]`,children:`通过`}),(0,$.jsx)(`button`,{type:`button`,onClick:()=>f(!1),className:`h-8 flex-1 rounded-[4px] text-[13px] text-[#6b6b66] transition-colors hover:bg-white/60 dark:text-[#a3a39b] dark:hover:bg-[#232421]`,children:`打回重跑`})]})]}),(0,$.jsxs)(`footer`,{className:`shrink-0 border-t ${qU} bg-[#FAFAF7] px-5 py-3 dark:bg-[#1B1C20]`,children:[(0,$.jsxs)(`div`,{className:`flex items-center gap-1`,children:[(0,$.jsxs)(`button`,{type:`button`,onClick:p,disabled:l,className:`flex h-8 flex-1 items-center justify-center gap-1.5 rounded-[4px] bg-[#24543F] text-[13px] font-medium text-white transition-colors hover:bg-[#1D4634] disabled:cursor-not-allowed disabled:opacity-50 dark:bg-[#3F7A5F] dark:hover:bg-[#4B8B6D]`,children:[l?(0,$.jsx)(te,{size:13,className:`animate-spin`}):(0,$.jsx)(se,{size:13}),l?`运行中…`:`重跑此卡`]}),Ne?null:(0,$.jsxs)(`button`,{type:`button`,onClick:()=>d(`prev`),className:`${lW} flex items-center gap-1`,children:[(0,$.jsx)(R,{size:13}),`加上游`]}),(0,$.jsxs)(`button`,{type:`button`,onClick:()=>d(`next`),className:`${lW} flex items-center gap-1`,children:[(0,$.jsx)(P,{size:13}),`加下游`]})]}),(0,$.jsx)(`div`,{className:`mt-1 flex justify-end`,children:(0,$.jsxs)(`button`,{type:`button`,onClick:g,disabled:Ne,title:Ne?`根节点是对话入口(人格来源),不能删除`:void 0,className:`flex items-center gap-1.5 rounded-[4px] px-2.5 py-1.5 text-[12px] text-[#B4451F] transition-colors hover:bg-[#FBEFEA] disabled:cursor-not-allowed disabled:opacity-40 disabled:hover:bg-transparent dark:text-[#e08a6a] dark:hover:bg-[#2A1C17]`,children:[(0,$.jsx)(_e,{size:13}),`删除此卡`]})})]})]})}function pW({title:e,extra:t,children:n}){return(0,$.jsxs)(`section`,{className:`mt-3 rounded-xl border p-3 first:mt-1 ${JU}`,children:[(0,$.jsxs)(`div`,{className:`mb-2.5 flex items-center justify-between gap-2`,children:[(0,$.jsx)(`h3`,{className:`text-[12px] font-semibold tracking-[0.01em] ${WU}`,children:e}),t]}),n]})}function mW({children:e}){return(0,$.jsx)(`p`,{className:`py-1 text-[12px] leading-[1.6] ${KU}`,children:e})}function hW(e,t,n){if(t===n)return!0;let r=new Set([t]),i=[t];for(;i.length;){let t=i.pop();for(let a of e)if(a.from===t){if(a.to===n)return!0;r.has(a.to)||(r.add(a.to),i.push(a.to))}}return!1}function gW(e){return e===`human`?`人工`:e===`jev`?`jev`:e===`self`?`自评`:e||`系统`}function _W(e){e&&(e.style.height=`auto`,e.style.height=`${e.scrollHeight}px`)}var{Text:vW}=RA;function yW({open:e,config:t,servers:n,onClose:r,onSaved:i,onError:a}){let o=t,[s,c]=(0,_.useState)(o?.mock??!1),[l,u]=(0,_.useState)(!1),[d,f]=(0,_.useState)(null),[p,m]=(0,_.useState)(!1),h=(0,_.useRef)(a);(0,_.useEffect)(()=>{h.current=a},[a]),(0,_.useEffect)(()=>{e&&c(o?.mock??!1)},[e,o?.mock]),(0,_.useEffect)(()=>{if(!e)return;let t=!1;return m(!0),ZA.getBridge().then(e=>{t||f(e)}).catch(e=>{t||h.current(`读取模型通道状态失败:${e.message}`)}).finally(()=>{t||m(!1)}),()=>{t=!0}},[e]);async function g(){if(p)return;m(!0);let[e,t]=await Promise.allSettled([ZA.getBridge(),ZA.getModels(!0)]);e.status===`fulfilled`?f(e.value):h.current(`读取模型通道状态失败:${e.reason.message}`),t.status===`rejected`&&h.current(`重新读取模型目录失败:${t.reason.message}`),m(!1)}async function v(e){if(l||!t)return;let n=s;c(e),u(!0);try{let t=await ZA.putConfig({mock:e}),n=typeof t?.mock==`boolean`?t.mock:e;c(n),i({mock:n})}catch(e){c(n),a(`切换 mock 失败:${e.message}`)}finally{u(!1)}}let y=Object.entries(o?.providers??{}),b=o?.mcpServers??n.map(e=>({name:e.name})),x=o?.skillDirs?.length?o.skillDirs:o?.dshPaths?.skills?[o.dshPaths.skills]:[],S=d?d.healthy?(0,$.jsx)(JO,{color:`success`,style:{marginInlineEnd:0},children:`已连接`}):(0,$.jsx)(JO,{color:`warning`,style:{marginInlineEnd:0},children:`未连接`}):(0,$.jsx)(vW,{type:`secondary`,style:{fontSize:12},children:`读取中…`}),C=d&&(d.lastError||d.reason)||``;return(0,$.jsxs)(RD,{open:e,title:`设置`,width:640,centered:!0,onCancel:r,styles:{body:{maxHeight:`calc(100vh - 220px)`,overflowY:`auto`,paddingTop:12}},footer:(0,$.jsx)(uD,{justify:`flex-end`,children:(0,$.jsx)(GS,{onClick:r,children:`关闭`})}),children:[(0,$.jsx)(Kl,{type:`info`,showIcon:!0,title:`模型、MCP 服务器、技能都来自 DSH 的配置。要增删改请到 DSH 的 cordis.patch.yml,AgentFlow 这边只读。`,description:o?.dshPaths?.patch?(0,$.jsxs)(vW,{type:`secondary`,style:{fontSize:12,wordBreak:`break-all`},children:[`patch:`,(0,$.jsx)(vW,{code:!0,style:{fontSize:12},children:o.dshPaths.patch})]}):void 0}),(0,$.jsx)(bW,{title:`模型`,extra:(0,$.jsxs)(vW,{type:`secondary`,style:{fontSize:11},children:[y.length,` 个`]}),children:y.length===0?(0,$.jsx)(ib,{image:ib.PRESENTED_IMAGE_SIMPLE,description:`DSH 没有配置模型提供商`}):y.map(([e,t])=>(0,$.jsx)(Hw,{size:`small`,style:{marginBottom:12},title:(0,$.jsx)(vW,{strong:!0,style:{fontSize:14},children:t.label||e}),extra:t.hasKey?(0,$.jsx)(JO,{color:`green`,style:{marginInlineEnd:0},children:`已配置 key`}):(0,$.jsx)(JO,{color:`red`,style:{marginInlineEnd:0},children:`缺 key`}),children:(0,$.jsx)(VE,{size:`small`,column:1,colon:!1,items:[{key:`provider`,label:`provider`,children:(0,$.jsx)(vW,{code:!0,children:e})},{key:`baseURL`,label:`baseURL`,children:(0,$.jsx)(vW,{code:!0,children:t.baseURL||`—`})},{key:`model`,label:`model`,children:(0,$.jsx)(vW,{code:!0,children:t.model||`—`})}]})},e))}),(0,$.jsxs)(bW,{title:`模型通道`,extra:(0,$.jsx)(GS,{size:`small`,loading:p,onClick:()=>void g(),children:`刷新`}),children:[d&&!d.healthy&&(0,$.jsx)(Kl,{type:`warning`,showIcon:!0,style:{marginBottom:10},title:`DSH 未运行或插件未加载,画布不能调模型`}),(0,$.jsx)(VE,{size:`small`,bordered:!0,column:1,colon:!1,items:[{key:`status`,label:`状态`,children:S},{key:`infoPath`,label:`发现文件`,children:(0,$.jsx)(vW,{code:!0,style:{fontSize:12,wordBreak:`break-all`,userSelect:`text`},title:d?.dir,children:d?.infoPath||`—`})},{key:`version`,label:`版本`,children:d?.version==null?`—`:(0,$.jsx)(vW,{code:!0,children:d.version})},{key:`startedAt`,label:`启动时间`,children:xW(d?.startedAt??null)},{key:`providers`,label:`provider 数`,children:d?String(d.providers):`—`},{key:`modelCount`,label:`模型数`,children:d?String(d.modelCount):`—`},{key:`lastError`,label:`最后错误`,children:C?(0,$.jsx)(vW,{type:`danger`,style:{fontSize:12,wordBreak:`break-all`},children:C}):(0,$.jsx)(vW,{type:`secondary`,children:`—`})}]})]}),(0,$.jsx)(bW,{title:`MCP 服务器`,extra:(0,$.jsxs)(vW,{type:`secondary`,style:{fontSize:11},children:[b.length,` 个`]}),children:b.length===0?(0,$.jsx)(ib,{image:ib.PRESENTED_IMAGE_SIMPLE,description:`DSH 没有配置 MCP 服务器`}):(0,$.jsx)(VE,{size:`small`,bordered:!0,column:1,colon:!1,items:b.map(e=>({key:e.name,label:(0,$.jsx)(vW,{strong:!0,style:{fontSize:13},children:e.name}),children:e.kind?(0,$.jsx)(JO,{style:{marginInlineEnd:0},children:e.kind}):(0,$.jsx)(vW,{type:`secondary`,children:`—`})}))})}),(0,$.jsx)(bW,{title:`技能目录`,extra:(0,$.jsxs)(vW,{type:`secondary`,style:{fontSize:11},children:[x.length,` 个`]}),children:x.length===0?(0,$.jsx)(ib,{image:ib.PRESENTED_IMAGE_SIMPLE,description:`DSH 没有配置技能目录`}):(0,$.jsx)(uD,{vertical:!0,gap:6,children:x.map(e=>(0,$.jsx)(vW,{code:!0,style:{fontSize:12,wordBreak:`break-all`},children:e},e))})}),(0,$.jsx)(bW,{title:`运行模式`,children:(0,$.jsx)(Hw,{size:`small`,children:(0,$.jsxs)(uD,{align:`center`,justify:`space-between`,gap:16,children:[(0,$.jsxs)(`div`,{style:{minWidth:0},children:[(0,$.jsx)(vW,{strong:!0,style:{display:`block`,fontSize:15},children:`mock 模式`}),(0,$.jsx)(vW,{type:`secondary`,style:{display:`block`,fontSize:12},children:`AgentFlow 自己的开关,不属于 DSH 配置。打开后不真正调用模型。`})]}),(0,$.jsx)(qD,{checked:s,loading:l,disabled:!t,onChange:e=>void v(e)})]})})})]})}function bW({title:e,extra:t,children:n}){return(0,$.jsxs)(`section`,{style:{marginTop:20},children:[(0,$.jsxs)(uD,{align:`center`,justify:`space-between`,gap:8,style:{marginBottom:8},children:[(0,$.jsx)(vW,{strong:!0,style:{fontSize:13},children:e}),t]}),n]})}function xW(e){if(typeof e!=`number`||!Number.isFinite(e)||e<=0)return`—`;let t=new Date(e);if(Number.isNaN(t.getTime()))return`—`;let n=e=>String(e).padStart(2,`0`);return`${t.getFullYear()}-${n(t.getMonth()+1)}-${n(t.getDate())} ${n(t.getHours())}:${n(t.getMinutes())}:${n(t.getSeconds())}`}var{Text:SW}=RA,CW=`'SFMono-Regular', Menlo, Consolas, 'Liberation Mono', ui-monospace, monospace`;function wW({open:e,boardId:t,boardName:n,onClose:r}){let{token:i}=ik.useToken(),[a,o]=(0,_.useState)(null),[s,c]=(0,_.useState)(null),[l,u]=(0,_.useState)(!1),[d,f]=(0,_.useState)(``);(0,_.useEffect)(()=>{e&&(o(null),c(null),u(!1),f(n||``))},[e,n]);async function p(){if(!l){u(!0),c(null),o(null);try{let e=await ZA.exportPreset(t,d.trim());o(e)}catch(e){let t=e.message||`未知错误`;t.includes(`HTTP 404`)?c({title:`暂不可用`,detail:`后端还没有这个接口(POST /api/export/preset),等后端上线后再试。`}):t.includes(`HTTP 409`)?c({title:`自定义目录已存在,换个目录`,detail:t}):c({title:`生成失败`,detail:t})}finally{u(!1)}}}let m={border:`1px solid ${i.colorBorderSecondary}`,borderRadius:8,background:i.colorFillTertiary,padding:`10px 12px`,fontFamily:CW,fontSize:12,lineHeight:1.7,whiteSpace:`pre-wrap`,wordBreak:`break-all`,color:i.colorText};return(0,$.jsxs)(RD,{open:e,title:`导出为 DSH 预设`,width:720,centered:!0,onCancel:r,styles:{body:{maxHeight:`calc(100vh - 240px)`,overflowY:`auto`}},footer:(0,$.jsxs)(uD,{justify:`flex-end`,gap:8,children:[(0,$.jsx)(GS,{onClick:r,children:`关闭`}),(0,$.jsx)(GS,{type:`primary`,icon:(0,$.jsx)(H,{size:14}),loading:l,onClick:()=>void p(),children:`生成`})]}),children:[(0,$.jsx)(Kl,{type:`info`,showIcon:!0,title:`把这张画布编译成 DSH 预设,直接写进 dsh-plugin-agentflow 插件包。重启 DSH 后,新会话的预设列表里就能选到它:主 agent 会先和你对齐需求,再按画布结构分层下发子 agent(提示词驱动,不保证严格按 DAG 执行)。`,style:{marginBottom:16}}),(0,$.jsxs)(`div`,{style:{marginBottom:16},children:[(0,$.jsx)(SW,{style:{fontSize:12,display:`block`,marginBottom:6},children:`预设名称`}),(0,$.jsx)(PD,{value:d,onChange:e=>f(e.target.value),placeholder:`在 DSH 预设列表里显示的名字`,maxLength:40,disabled:!!a}),(0,$.jsx)(SW,{type:`secondary`,style:{fontSize:11},children:`只改显示名,预设 id 不变(重复导出还是覆盖同一个预设)。`})]}),s&&(0,$.jsx)(Kl,{type:`error`,showIcon:!0,title:s.title,description:s.detail?(0,$.jsx)(SW,{style:{fontSize:12,fontFamily:CW,wordBreak:`break-all`},children:s.detail}):void 0,style:{marginBottom:16}}),a&&(0,$.jsxs)($.Fragment,{children:[(0,$.jsx)(Kl,{type:`success`,showIcon:!0,title:a.replaced?`预设已更新`:`预设已写入插件`,description:(0,$.jsxs)(`div`,{children:[(0,$.jsxs)(`div`,{style:{marginBottom:6},children:[`已写进 profile 的 `,(0,$.jsx)(`b`,{children:`cordis.patch.yml`}),`(用标记段包裹,重新导出整段替换)。`,(0,$.jsx)(`b`,{children:`重启 DSH 后`}),`,新会话的预设列表里就能选到它。`]}),(0,$.jsxs)(`div`,{style:{marginBottom:4},children:[`预设 id:`,(0,$.jsx)(SW,{code:!0,style:{fontSize:12},children:a.presetId})]}),(0,$.jsxs)(`div`,{children:[`文件:`,(0,$.jsx)(SW,{code:!0,copyable:!0,style:{fontSize:12,wordBreak:`break-all`},children:a.file})]})]}),style:{marginBottom:12}}),(a.addedOrchestrator||a.personaSource)&&(0,$.jsxs)(`div`,{style:{marginBottom:16},children:[(0,$.jsx)(SW,{strong:!0,style:{display:`block`,fontSize:13,marginBottom:6},children:`调度与人设`}),(0,$.jsxs)(uD,{vertical:!0,gap:4,children:[a.addedOrchestrator&&(0,$.jsxs)(SW,{style:{fontSize:13},children:[`已自动补充调度卡:`,(0,$.jsx)(SW,{strong:!0,children:a.addedOrchestrator.label})]}),a.personaSource&&(0,$.jsxs)(SW,{style:{fontSize:13},type:`secondary`,children:[`人格来源:`,EW(a.personaSource)]})]})]}),(0,$.jsxs)(`div`,{style:{marginBottom:16},children:[(0,$.jsx)(SW,{strong:!0,style:{display:`block`,fontSize:13,marginBottom:6},children:`写入文件`}),(0,$.jsx)(JO,{style:{marginInlineEnd:0,fontFamily:CW},children:a.file})]})]}),(0,$.jsxs)(`div`,{children:[(0,$.jsxs)(uD,{align:`baseline`,justify:`space-between`,style:{marginBottom:6},children:[(0,$.jsx)(SW,{strong:!0,style:{fontSize:13},children:`预览人格`}),a?.personaPreview&&(0,$.jsxs)(SW,{type:`secondary`,style:{fontSize:11},children:[a.personaPreview.length,` 字符`]})]}),(0,$.jsx)(`pre`,{style:{...m,margin:0,maxHeight:320,overflowY:`auto`},children:a?.personaPreview||`生成后会在这里显示完整的人格文本。`})]})]})}var TW={orchestrator:`调度(根)节点的人格`,"single-card":`单卡片画布(唯一那张卡)`,"auto-orchestrator":`自动补充的调度卡`};function EW(e){return TW[e]??e}var DW=`border-[#E3E4DF] dark:border-[#262724]`,OW=`text-[#1B1B18] dark:text-[#e8e8e4]`,kW=`text-[#6b6b66] dark:text-[#8b8b85]`,AW=`text-[#8b8b85] dark:text-[#8b8b85]`;function jW(){let[e,t]=(0,_.useState)(`list`),[n,r]=(0,_.useState)([]),[i,a]=(0,_.useState)([]),[o,s]=(0,_.useState)({}),[c,l]=(0,_.useState)(!0),[u,d]=(0,_.useState)(null),[f,p]=(0,_.useState)(null),[m,h]=(0,_.useState)(``),[g,v]=(0,_.useState)(null),[y,b]=(0,_.useState)(null),[x,S]=(0,_.useState)(!1),[C,w]=(0,_.useState)(``),[T,E]=(0,_.useState)(!1),[D,O]=(0,_.useState)(null),[k,A]=(0,_.useState)(``),j=(0,_.useRef)(!1),M=(0,_.useRef)(!1),[N,P]=(0,_.useState)([]),[F,L]=(0,_.useState)([]),[R,z]=(0,_.useState)(null),[B,V]=(0,_.useState)(null),[U,ee]=(0,_.useState)(null),[ne,ie]=(0,_.useState)(!1),[ae,G]=(0,_.useState)(!1),[oe,se]=(0,_.useState)(!1),[ce,le]=(0,_.useState)(!1),J=(0,_.useRef)(!1),ue=(0,_.useRef)(!1),fe=(0,_.useCallback)(()=>{ue.current=!0,se(!0)},[]),pe=(0,_.useCallback)(()=>{ue.current=!1,se(!1)},[]),me=(0,_.useRef)(0),ge=(0,_.useRef)(null);(0,_.useEffect)(()=>{ge.current=f},[f]),(0,_.useEffect)(()=>{if(!f||e!==`board`)return;let t=window.setTimeout(()=>{ZA.putBoard(f.id,f).catch(e=>{console.warn(`[agentflow] 自动保存失败:`,e)}),r(e=>e.map(e=>e.id===f.id?{...e,presetOutdated:!0}:e))},200);return()=>window.clearTimeout(t)},[f,e]),(0,_.useEffect)(()=>{let e=()=>{let e=ge.current;if(e)try{fetch(`/api/boards/${encodeURIComponent(e.id)}`,{method:`PUT`,headers:{"content-type":`application/json`},body:JSON.stringify({board:e}),keepalive:!0}).catch(()=>{})}catch{}};return window.addEventListener(`pagehide`,e),()=>window.removeEventListener(`pagehide`,e)},[]);let[_e,ve]=(0,_.useState)(()=>{try{localStorage.removeItem(`agentflow-theme`)}catch{}try{let e=sessionStorage.getItem(`agentflow-theme`);if(e===`dark`)return!0;if(e===`light`)return!1}catch{}try{let e=new URLSearchParams(window.location.search).get(`theme`);if(e===`dark`)return!0;if(e===`light`)return!1}catch{}try{return window.matchMedia(`(prefers-color-scheme: dark)`).matches}catch{return!1}});(0,_.useEffect)(()=>{document.documentElement.classList.toggle(`dark`,_e);try{sessionStorage.setItem(`agentflow-theme`,_e?`dark`:`light`)}catch{}window.dispatchEvent(new Event(`themechange`))},[_e]);let[ye,be]=(0,_.useState)(null),xe=(0,_.useRef)(null),Y=(0,_.useCallback)((e,t=`ok`)=>{be({msg:e,kind:t}),xe.current&&window.clearTimeout(xe.current),xe.current=window.setTimeout(()=>be(null),3200)},[]),Se=(0,_.useCallback)((e,t)=>{p(n=>n&&{...n,nodes:n.nodes.map(n=>n.id===e?{...n,...t}:n)})},[]),Ce=(0,_.useRef)(null),we=(0,_.useRef)(null);(0,_.useEffect)(()=>{Ce.current=u},[u]),(0,_.useEffect)(()=>{h(f?.name??``)},[f?.id,f?.name]);let Te=(0,_.useCallback)(async(e=!1)=>{e||l(!0);let[t,n]=await Promise.allSettled([ZA.listBoards(),ZA.listPresets()]);if(t.status===`fulfilled`){let e=t.value.boards;r(e);let n=await Promise.allSettled(e.map(e=>ZA.getBoard(e.id))),i={};n.forEach((t,n)=>{t.status===`fulfilled`&&(i[e[n].id]=NW(t.value.board))}),s(i)}else Y(`加载画布列表失败:${t.reason.message}`,`err`);n.status===`fulfilled`?a(n.value.presets):Y(`加载预设列表失败:${n.reason.message}`,`err`),e||l(!1)},[Y]);(0,_.useEffect)(()=>{Te(),ZA.getSkills().then(e=>P(e.skills)).catch(()=>{}),ZA.getMcp().then(e=>L(e.servers)).catch(()=>{}),ZA.getConfig().then(z).catch(()=>{}),ZA.getModels().then(V).catch(()=>{}),ZA.getBridge().then(ee).catch(()=>{})},[Te]);let Ee=(0,_.useRef)(0);(0,_.useEffect)(()=>{g&&(Date.now()-Ee.current<3e4||(Ee.current=Date.now(),ZA.getModels(!0).then(V).catch(()=>{}),ZA.getBridge().then(ee).catch(()=>{})))},[g]);let{running:De,run:Oe,stop:ke}=QA((0,_.useCallback)(e=>{let t=we.current!=null&&Ce.current!==we.current;if((e.type===`run:end`||e.type===`run:error`)&&(we.current=null),!t)switch(e.type){case`node:start`:Se(e.id,{status:`running`});break;case`node:delta`:p(t=>t&&{...t,nodes:t.nodes.map(t=>t.id===e.id?{...t,delta:(t.delta||``)+e.chunk}:t)});break;case`node:done`:Se(e.id,{status:e.status??`done`,content:e.content,usage:e.usage,verdict:e.verdict??null,error:null,delta:void 0});break;case`node:failed`:Se(e.id,{status:`failed`,error:`该节点所有模型都失败`});break;case`node:blocked`:Se(e.id,{status:`blocked`});break;case`node:retry`:p(t=>t&&{...t,nodes:t.nodes.map(t=>t.id===e.id?{...t,delta:void 0}:t)}),Y(`${e.id} 换 ${e.model} 重试:${e.error}`,`err`);break;case`run:end`:{let{done:t,failed:n,blocked:r,review:i}=e.summary,a=[`完成 ${t.length}`];i.length&&a.push(`待确认 ${i.length}`),n.length&&a.push(`失败 ${n.length}`),r.length&&a.push(`阻塞 ${r.length}`),Y(a.join(`,`),n.length||r.length?`err`:`ok`);break}case`run:error`:Y(`运行出错:${e.error}`,`err`)}},[Se,Y])),Ae=(0,_.useCallback)(e=>{let t=Ce.current;t&&(we.current=t,Oe(e,t))},[Oe]),je=(0,_.useCallback)(()=>{we.current=null,ke()},[ke]),Me=(0,_.useCallback)(async e=>{let n=++me.current;t(`board`),d(e),p(null),h(``),v(null),G(!1),pe();let r=await ZA.getBoard(e).then(e=>({status:`fulfilled`,value:e})).catch(e=>({status:`rejected`,reason:e}));n===me.current&&(r.status===`rejected`?(Y(`打开画布失败:${r.reason.message}`,`err`),t(`list`),d(null),pe(),Te(!0)):p(r.value.board))},[Te,Y]),Ne=(0,_.useRef)(typeof window>`u`?null:new URLSearchParams(window.location.search).get(`board`));(0,_.useEffect)(()=>{let e=Ne.current;e&&(Ne.current=null,Me(e))},[Me]);let Pe=(0,_.useCallback)(()=>{me.current+=1,t(`list`),p(null),d(null),v(null),G(!1),pe(),Te(!0)},[Te]);function Fe(){Pe()}function Ie(e){Me(e)}let Le=(0,_.useCallback)(async()=>{let e=ge.current;if(!e)return!1;try{return await ZA.putBoard(e.id,e),pe(),!0}catch(e){return Y(`保存画布失败:${e.message}`,`err`),!1}},[Y,pe]),Re=(0,_.useCallback)(async()=>{let e=ge.current;if(!e||J.current)return!1;J.current=!0,le(!0);try{return await ZA.putBoard(e.id,e),await ZA.exportPreset(e.id,e.name),pe(),r(t=>t.map(t=>t.id===e.id?{...t,name:e.name,nodeCount:e.nodes.length,presetOutdated:!1,updatedAt:Date.now()}:t)),Y(`已保存,预设已更新`),!0}catch(e){return Y(`保存失败:${e.message}`,`err`),!1}finally{J.current=!1,le(!1)}},[Y,pe]);(0,_.useEffect)(()=>{let t=t=>{(t.metaKey||t.ctrlKey)&&String(t.key).toLowerCase()===`s`&&(t.preventDefault(),e===`board`&&window.setTimeout(()=>void Re(),0))};return window.addEventListener(`keydown`,t),()=>window.removeEventListener(`keydown`,t)},[Re,e]);let ze=(0,_.useCallback)(async e=>{f&&(!ue.current||await Le())&&Ae(e)},[f,Le,Ae]),Be=(0,_.useCallback)(async()=>{f&&(!ue.current||await Le())&&G(!0)},[f,Le]),Ve=(0,_.useCallback)((e,t)=>{Se(e,t),fe()},[Se]),He=(0,_.useCallback)(e=>{p(t=>t&&{...t,edges:e}),fe()},[]),Ue=(0,_.useCallback)((e,t,n)=>{f&&(p({...f,nodes:f.nodes.map(r=>r.id===e?{...r,x:t,y:n}:r)}),fe())},[f]),We=(0,_.useCallback)((e,t)=>{if(!f)return;let n=f.nodes.find(t=>t.id===e);if(!n)return;let r=B?.providers.find(e=>e.models.length),i=n.provider||r?.id||``,a=n.model||r?.models[0]?.id||``,o=MW(f.nodes),s={id:o,label:t===`next`?`下游卡片`:`上游卡片`,type:`llm`,x:t===`next`?n.x+360:n.x-360,y:n.y,provider:i,model:a,reasoningEffort:``,fallback:[],fallbackEfforts:{},task:``,criteria:``,skills:[],tools:[],verify:``,content:``,status:`idle`,usage:null,error:null,verdict:null};p({...f,nodes:[...f.nodes,s],edges:[...f.edges,t===`next`?{from:e,to:o}:{from:o,to:e}]}),v(o),fe(),Y(t===`next`?`已派生下游卡片(未保存)`:`已添加上游卡片(未保存)`)},[f,B,Y]),Ge=(0,_.useCallback)((e,t)=>{f&&e!==t&&(f.nodes.find(e=>e.id===t)?.type===`orchestrator`?Y(`根节点是对话入口,不能有上游节点`,`err`):f.edges.some(n=>n.from===e&&n.to===t)||(FW(f.edges,e,t)?Y(`这条连线会形成环,已忽略`,`err`):(p({...f,edges:[...f.edges,{from:e,to:t}]}),fe())))},[f,Y]),Ke=(0,_.useCallback)(e=>{f&&(p({...f,nodes:f.nodes.filter(t=>t.id!==e),edges:f.edges.filter(t=>t.from!==e&&t.to!==e)}),v(null),fe(),Y(`已删除(未保存)`))},[f,Y]),qe=(0,_.useCallback)(async(e,t)=>{if(!ue.current||await Le())try{let n=await ZA.verify(e,t,void 0,Ce.current);Se(e,{status:n.status,verdict:n.verdict}),Y(t?`已通过`:`已打回,可以改完再跑`)}catch(e){Y(`操作失败:${e.message}`,`err`)}},[Se,Y,Le]),Je=(0,_.useMemo)(()=>f?.nodes.find(e=>e.id===g)??null,[f,g]),Ye=(0,_.useMemo)(()=>new Set(n.map(e=>e.presetId).filter(e=>!!e)),[n]),Xe=(0,_.useMemo)(()=>i.filter(e=>!Ye.has(e.id)),[i,Ye]);function Ze(){w(``),S(!0)}async function Qe(){let e=C.trim();if(e&&!T){E(!0);try{let n=await ZA.createBoard({name:e});me.current+=1,S(!1),w(``),p(n.board),d(n.board.id),v(null),pe(),t(`board`),Te(!0)}catch(e){Y(`新建画布失败:${e.message}`,`err`)}finally{E(!1)}}}async function $e(e){if(!y){b(e.id);try{let n=await ZA.importPreset(e.id);Y(n.reused?`已有这张画布:${e.name}`:`已从预设创建画布:${e.name}`),me.current+=1,p(n.board),d(n.board.id),v(null),pe(),t(`board`),Te(!0)}catch(e){let t=e.message;t.includes(`HTTP 501`)?Y(`创建画布功能还没上线(服务端 P1 未完成)`,`err`):Y(`创建画布失败:${t}`,`err`)}finally{b(null)}}}function et(e){O(e.id),A(e.name)}async function tt(e){if(D!==e.id)return;let t=j.current;if(j.current=!1,O(null),t){A(e.name);return}let n=k.trim();if(n&&n!==e.name)try{let t=await ZA.patchBoard(e.id,{name:n});r(r=>r.map(r=>r.id===e.id?{...r,name:n,updatedAt:t.meta?.updatedAt??r.updatedAt}:r)),f?.id===e.id&&p(e=>e&&{...e,name:n}),Y(`画布已重命名`)}catch(e){Y(`重命名失败:${e.message}`,`err`)}}async function nt(e){if(n.length<=1)Y(`至少要保留一张画布`,`err`);else if(window.confirm(`删除画布《${e.name}》?里面的节点会一起删掉,且不可恢复。`))try{await ZA.deleteBoard(e.id),Y(`画布已删除`),await Te(!0)}catch(e){Y(`删除失败:${e.message}`,`err`)}}async function rt(){if(!f)return;let e=M.current;if(M.current=!1,e){h(f.name);return}let t=m.trim();if(!t)h(f.name);else if(t!==f.name)try{let e=await ZA.patchBoard(f.id,{name:t});p(e=>e&&{...e,name:t}),r(n=>n.map(n=>n.id===f.id?{...n,name:t,updatedAt:e.meta?.updatedAt??n.updatedAt}:n)),Y(`画布已重命名`)}catch(e){h(f.name),Y(`重命名失败:${e.message}`,`err`)}}return(0,$.jsx)(Ld,{locale:qA.default,theme:{algorithm:_e?ik.darkAlgorithm:ik.defaultAlgorithm,token:{colorPrimary:`#24543F`,borderRadius:7,fontSize:15,fontFamily:`-apple-system, BlinkMacSystemFont, 'PingFang SC', 'Hiragino Sans GB', ui-sans-serif, sans-serif`},components:{Drawer:{paddingLG:20},Modal:{borderRadiusLG:12},Card:{borderRadiusLG:10}}},children:(0,$.jsxs)(`div`,{className:`flex h-full flex-col`,children:[e===`list`?(0,$.jsxs)(`header`,{className:`flex h-14 shrink-0 items-center gap-3 border-b ${DW} bg-[#FCFCFA] px-5 dark:bg-[#17181b]`,children:[(0,$.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,$.jsx)(`span`,{className:`grid h-7 w-7 place-items-center rounded-[4px] bg-[#24543F] text-white`,children:`◈`}),(0,$.jsx)(`span`,{className:`text-[17px] font-semibold tracking-tight ${OW}`,children:`AgentFlow`})]}),(0,$.jsxs)(`div`,{className:`ml-auto flex items-center gap-2`,children:[(0,$.jsx)(GS,{type:`primary`,icon:(0,$.jsx)(K,{size:14}),onClick:Ze,children:`新建画布`}),(0,$.jsx)(GS,{icon:_e?(0,$.jsx)(he,{size:14}):(0,$.jsx)(re,{size:14}),onClick:()=>ve(e=>!e),title:_e?`切到浅色`:`切到深色`}),(0,$.jsx)(GS,{icon:(0,$.jsx)(de,{size:14}),onClick:()=>ie(!0),children:`设置`})]})]}):(0,$.jsxs)(`header`,{className:`flex h-14 shrink-0 items-center gap-2 border-b ${DW} bg-[#FCFCFA] px-4 dark:bg-[#17181b]`,children:[(0,$.jsxs)(`button`,{type:`button`,onClick:Fe,title:`返回画布列表`,className:`flex shrink-0 items-center gap-1 rounded-[4px] px-2 py-1.5 text-[12px] transition-colors hover:bg-[#EFEFEA] dark:hover:bg-[#232421] ${kW}`,children:[(0,$.jsx)(I,{size:14}),`返回列表`]}),(0,$.jsx)(`div`,{className:`h-5 w-px shrink-0 bg-[#E3E4DF] dark:bg-[#2c2d29]`}),(0,$.jsx)(`input`,{value:m,onChange:e=>h(e.target.value),onBlur:()=>void rt(),onKeyDown:e=>{e.key===`Enter`&&e.currentTarget.blur(),e.key===`Escape`&&(M.current=!0,e.currentTarget.blur())},disabled:!f,placeholder:`画布名称`,"aria-label":`画布名称`,className:`min-w-0 max-w-[280px] flex-1 rounded-[3px] border-0 bg-transparent px-1 py-1 text-[16px] font-semibold tracking-tight outline-none placeholder:text-[#a8a8a0] focus-visible:ring-2 focus-visible:ring-[#24543F]/30 disabled:bg-transparent dark:placeholder:text-[#6f6f68] dark:focus-visible:ring-[#6aa583]/40 ${OW}`}),oe&&(0,$.jsx)(`span`,{title:`有未保存的修改`,"aria-label":`有未保存的修改`,className:`h-1.5 w-1.5 shrink-0 rounded-full bg-[#B4451F] dark:bg-[#e08a6a]`}),(0,$.jsxs)(`div`,{className:`ml-auto flex items-center gap-2`,children:[(0,$.jsx)(GS,{icon:(0,$.jsx)(q,{size:14}),disabled:!f,loading:ce,onClick:()=>void Re(),title:`保存画布并更新预设(⌘S / Ctrl+S)`,children:`保存`}),De?(0,$.jsx)(GS,{danger:!0,icon:(0,$.jsx)(te,{size:14,className:`animate-spin`}),onClick:je,children:`停止`}):(0,$.jsx)(GS,{type:`primary`,icon:(0,$.jsx)(W,{size:14}),disabled:!f,onClick:()=>void ze(),title:`先保存,再跑一遍验证(会真实调用模型)`,children:`验证 AgentFlow`}),(0,$.jsx)(GS,{icon:(0,$.jsx)(H,{size:14}),disabled:!f,onClick:()=>void Be(),children:`导出预设`}),(0,$.jsx)(GS,{icon:_e?(0,$.jsx)(he,{size:14}):(0,$.jsx)(re,{size:14}),onClick:()=>ve(e=>!e),title:_e?`切到浅色`:`切到深色`}),(0,$.jsx)(GS,{icon:(0,$.jsx)(de,{size:14}),onClick:()=>ie(!0),children:`设置`})]})]}),e===`list`?(0,$.jsx)(`main`,{className:`min-h-0 flex-1 overflow-y-auto bg-[#F4F5F2] px-6 py-7 dark:bg-[#111214]`,children:(0,$.jsxs)(`div`,{className:`mx-auto w-full max-w-[1080px]`,children:[(0,$.jsxs)(`div`,{className:`mb-5`,children:[(0,$.jsx)(`h1`,{className:`text-[20px] font-semibold tracking-tight ${OW}`,children:`画布`}),(0,$.jsx)(`p`,{className:`mt-1 text-[12px] leading-[1.6] ${kW}`,children:`每张画布对应一个 DSH 预设;编辑会自动保存,点「保存」才会更新/生成预设。`})]}),c&&n.length===0?(0,$.jsx)(`div`,{className:`py-16 text-center text-[13px] ${kW}`,children:`正在加载画布…`}):(0,$.jsxs)($.Fragment,{children:[n.length===0?(0,$.jsx)(`div`,{className:`rounded-[8px] border border-dashed ${DW} py-14 text-center text-[13px] ${kW}`,children:`还没有画布,点右上角「新建画布」开始。`}):(0,$.jsx)(`div`,{className:`grid grid-cols-1 gap-3 md:grid-cols-2 xl:grid-cols-3`,children:n.map(e=>{let t=e.presetId?i.find(t=>t.id===e.presetId):null;return(0,$.jsxs)(`article`,{className:`flex min-h-[150px] flex-col rounded-[8px] border ${DW} bg-[#FCFCFA] p-4 dark:bg-[#17181B]`,children:[(0,$.jsxs)(`div`,{className:`flex items-start gap-2`,children:[(0,$.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[D===e.id?(0,$.jsx)(PD,{size:`small`,autoFocus:!0,maxLength:60,value:k,onChange:e=>A(e.target.value),onBlur:()=>void tt(e),onPressEnter:e=>e.currentTarget.blur(),onKeyDown:e=>{e.key===`Escape`&&(j.current=!0,e.currentTarget.blur())},"aria-label":`重命名画布 ${e.name}`}):(0,$.jsx)(`button`,{type:`button`,onClick:()=>Ie(e.id),title:e.name,className:`block max-w-full text-left`,children:(0,$.jsx)(`h2`,{className:`truncate text-[15px] font-semibold ${OW}`,children:e.name})}),(0,$.jsxs)(`p`,{className:`mt-1 text-[11px] leading-[1.6] ${AW}`,children:[e.nodeCount,` 个节点 · 更新于 `,PW(e.updatedAt)]}),o[e.id]!==void 0&&(0,$.jsxs)(`p`,{className:`mt-0.5 truncate text-[11px] leading-[1.6] ${kW}`,title:o[e.id]||`没有调度卡,首次导出会自动补一张`,children:[`对话入口:`,o[e.id]||`未设置(首次导出会自动补一张调度卡)`]})]}),(0,$.jsxs)(`div`,{className:`flex shrink-0 flex-col items-end gap-1`,children:[(0,$.jsx)(JO,{color:t?`blue`:`default`,style:{marginInlineEnd:0},children:t?t.name:`自定义`}),e.presetOutdated&&(0,$.jsx)(JO,{color:`orange`,style:{marginInlineEnd:0},children:`预设未更新`}),e.hasDraft&&(0,$.jsx)(JO,{color:`gold`,style:{marginInlineEnd:0},children:`草稿`})]})]}),(0,$.jsxs)(`div`,{className:`mt-auto flex flex-wrap items-center gap-1 pt-3`,children:[(0,$.jsx)(GS,{size:`small`,type:`primary`,onClick:()=>Ie(e.id),children:`编辑`}),(0,$.jsx)(GS,{size:`small`,type:`text`,onClick:()=>et(e),children:`重命名`}),(0,$.jsx)(GS,{size:`small`,type:`text`,danger:!0,disabled:n.length<=1,title:n.length<=1?`至少要保留一张画布`:void 0,onClick:()=>void nt(e),children:`删除`})]})]},e.id)})}),Xe.length>0&&(0,$.jsxs)($.Fragment,{children:[(0,$.jsxs)(`div`,{className:`mb-3 mt-8 flex flex-wrap items-baseline gap-2`,children:[(0,$.jsx)(`h2`,{className:`text-[13px] font-semibold ${OW}`,children:`还没有画布的预设`}),(0,$.jsx)(`span`,{className:`text-[11px] ${AW}`,children:`从预设生成一张单卡片画布,再继续编辑`})]}),(0,$.jsx)(`div`,{className:`grid grid-cols-1 gap-3 md:grid-cols-2 xl:grid-cols-3`,children:Xe.map(e=>(0,$.jsxs)(`article`,{className:`flex min-h-[150px] flex-col rounded-[8px] border border-dashed ${DW} bg-[#F9F9F6] p-4 dark:bg-[#151617]`,children:[(0,$.jsxs)(`div`,{className:`flex items-start gap-2`,children:[(0,$.jsx)(`h2`,{className:`min-w-0 flex-1 truncate text-[15px] font-semibold ${OW}`,title:e.name,children:e.name}),(0,$.jsx)(JO,{style:{marginInlineEnd:0,flexShrink:0},children:e.source===`bundle`?`bundle`:`自定义`})]}),(0,$.jsx)(`p`,{className:`mt-1 line-clamp-3 text-[12px] leading-[1.6] ${kW}`,children:e.description||`没有描述`}),(0,$.jsx)(`div`,{className:`mt-auto pt-3`,children:(0,$.jsx)(GS,{size:`small`,loading:y===e.id,onClick:()=>void $e(e),children:`创建画布`})})]},e.id))})]})]})]})}):(0,$.jsxs)(`main`,{className:`relative min-h-0 flex-1`,children:[(0,$.jsxs)(`div`,{className:`pointer-events-none absolute left-4 top-[12px] z-10 flex items-center gap-1.5 rounded-[4px] bg-[#FCFCFA]/90 px-2 py-1 text-[11px] text-[#6b6b66] dark:bg-[#17181b]/90 dark:text-[#8b8b85]`,children:[(0,$.jsx)(`span`,{className:`h-[5px] w-[5px] rounded-full`,style:{background:R?R.mock?`#B4451F`:`#24543F`:`#b9bcb4`}}),R?R.mock?`mock`:`real`:`连接中`]}),f?(0,$.jsx)(UU,{board:f,selectedId:g,running:De,onSelect:v,onMove:Ue,onDerive:We,onConnect:Ge}):(0,$.jsx)(`div`,{className:`grid h-full place-items-center text-[13px] text-[#8a93a3]`,children:`正在加载画布…`})]}),e===`board`&&f&&Je&&(0,$.jsx)(uW,{node:Je,nodes:f.nodes,edges:f.edges,boardId:f.id,skills:N,servers:F,catalog:B,bridge:U,running:De,onPatch:e=>Ve(Je.id,e),onDerive:e=>We(Je.id,e),onVerify:e=>void qe(Je.id,e),onEdgesChange:He,onRefreshModels:()=>{Ee.current=Date.now(),ZA.getModels(!0).then(V).catch(e=>Y(`刷新模型失败:${e.message}`,`err`)),ZA.getBridge().then(ee).catch(()=>{})},onRerun:()=>void ze([Je.id]),onDelete:()=>void Ke(Je.id),onClose:()=>v(null)}),(0,$.jsx)(yW,{open:ne,config:R,servers:F,onClose:()=>ie(!1),onSaved:e=>{z(t=>t&&{...t,mock:e.mock}),ZA.getMcp().then(e=>L(e.servers)).catch(()=>{}),Y(`设置已保存`)},onError:e=>Y(e,`err`)}),(0,$.jsx)(wW,{open:ae,boardId:u,boardName:m,onClose:()=>G(!1)}),(0,$.jsx)(RD,{open:x,title:`新建画布`,centered:!0,okText:`创建`,cancelText:`取消`,confirmLoading:T,okButtonProps:{disabled:!C.trim()},onOk:()=>void Qe(),onCancel:()=>S(!1),children:(0,$.jsx)(PD,{autoFocus:!0,maxLength:60,placeholder:`画布名称,例如「活动文案」`,value:C,onChange:e=>w(e.target.value),onPressEnter:()=>{C.trim()&&!T&&Qe()}})}),ye&&(0,$.jsx)(`div`,{className:`fixed bottom-6 left-1/2 z-50 -translate-x-1/2 rounded-lg px-4 py-2 text-[13px] shadow-lg ${ye.kind===`err`?`bg-[#ffebee] text-[#c62828] dark:bg-[#3a1b1f] dark:text-[#ff9a9a]`:`bg-[#1C1C1A] text-white dark:bg-[#e7e9ee] dark:text-[#0f1116]`}`,children:ye.msg})]})})}function MW(e){let t=`n-${Date.now().toString(36)}`,n=t,r=2;for(;e.some(e=>e.id===n);)n=`${t}-${r++}`;return n}function NW(e){let t=e.nodes.find(e=>e.type===`orchestrator`)??(e.nodes.length===1?e.nodes[0]:null);return t?t.label||t.id:null}function PW(e){if(!e)return`—`;let t=new Date(e);if(Number.isNaN(t.getTime()))return`—`;let n=e=>String(e).padStart(2,`0`);return`${t.getFullYear()}-${n(t.getMonth()+1)}-${n(t.getDate())} ${n(t.getHours())}:${n(t.getMinutes())}`}function FW(e,t,n){let r=new Set,i=[n];for(;i.length;){let n=i.pop();if(n===t)return!0;if(!r.has(n)){r.add(n);for(let t of e)t.from===n&&i.push(t.to)}}return!1}(0,v.createRoot)(document.getElementById(`root`)).render((0,$.jsx)(_.StrictMode,{children:(0,$.jsx)(jW,{})}));
@@ -4,7 +4,7 @@
4
4
  <meta charset="UTF-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
  <title>AgentFlow · 物料画布</title>
7
- <script type="module" crossorigin src="/assets/index-CkM6YPl4.js"></script>
7
+ <script type="module" crossorigin src="/assets/index-DhM_avMx.js"></script>
8
8
  <link rel="stylesheet" crossorigin href="/assets/index-DEZcpxgr.css">
9
9
  </head>
10
10
  <body>