aims-workstation 0.1.7 → 0.1.8

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/.env.example CHANGED
@@ -9,7 +9,6 @@ LLM_MODEL=def
9
9
 
10
10
  # ARM 系统(助手档案 + 经验库):站点地址缺省公司内网 http://arm.agent-platform.dev.aimstek.cn,留空即用默认
11
11
  # 匿名可浏览目录;下载/上岗/新建/经验回流需令牌——到 ARM 生成访问令牌(arm_pat_…)后填入,或在「系统设置 · ARM 源」粘贴
12
- # ARM_MCP_URL=https://your-arm-host/api/mcp # 可选:私有化部署时覆盖
13
12
  # ARM_API_BASE=http://localhost:3001 # 可选:本地联调 ARM 时启用
14
13
  # PAT 留空则自动读取 ~/.arm/config.json 的 token
15
14
  ARM_PAT=
package/package.json CHANGED
@@ -13,7 +13,7 @@
13
13
  "@earendil-works/pi-ai": "^1.2.0"
14
14
  },
15
15
  "packageManager": "pnpm@11.21.0+sha512.521705bce689924eac72f5a3587122f362689ef6571e55ba80076fd637c11132ecffada26fad4ea79c485bfddbfd3d5a2a5b05805a77e893de71ec8a6cca3bb1",
16
- "version": "0.1.7",
16
+ "version": "0.1.8",
17
17
  "description": "AIMS 工作站:本地智能体工作站——ARM 助手本地化(下载/离线/升级)、工作台对话式定制、多工作区隔离、分级自主与审计",
18
18
  "bin": {
19
19
  "aims-workstation": "bin/aims-workstation.js"
package/server.js CHANGED
@@ -3,7 +3,7 @@
3
3
  // Agent 层基于 @earendil-works/pi-ai(统一 LLM API),前端为 web/ 预构建的 shadcn/ui 应用(web/dist)
4
4
  'use strict';
5
5
  // TLS 证书校验关闭(用户决策:内网私有部署自签证书常见,能访问优先)
6
- // 覆盖所有出站 fetch(ARM REST/MCP、LLM、面板代理)。本工具面向内网/本机使用。
6
+ // 覆盖所有出站 fetch(ARM REST、LLM、面板代理)。本工具面向内网/本机使用。
7
7
  process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
8
8
  const http = require('http');
9
9
  const fs = require('fs');
@@ -76,7 +76,7 @@ const PORT = +(process.env.PORT || env.PORT || 5600);
76
76
  const HOST = process.env.AIMS_HOST || '0.0.0.0'; // 默认局域网可达(团队共用);仅本机使用可设 AIMS_HOST=127.0.0.1
77
77
  // ── 运行时配置(ARM 源与 LLM 均可私有化部署:在「系统设置」页切换,存 AIMS_HOME/config/platform.json,优先级 运行时 > 环境变量 > .env)──
78
78
  const CFG_FILE = path.join(AIMS_HOME, 'config/platform.json');
79
- const cfg = { arm_api_base: '', arm_mcp_url: '', arm_token: '', llm_base_url: '', llm_api_key: '', llm_model: '', scene_profile: '', access_token: '' };
79
+ const cfg = { arm_api_base: '', arm_token: '', llm_base_url: '', llm_api_key: '', llm_model: '', scene_profile: '', access_token: '' };
80
80
  // 守护栏默认策略(可在「系统设置·守护栏」维护,存 platform.json,保存即热生效):deny=正则源串(命中即永久拒绝,任何级别不豁免);
81
81
  // ro=只读白名单命令名(免确认直行);sudo_u_l2=true 时 `sudo -u <用户>` 降权形式不再永久拒绝、按写命令走 L2 人工确认(裸 sudo 仍拒绝)
82
82
  const GUARD_DEFAULT = {
@@ -92,14 +92,14 @@ function normalizeGuard(g) {
92
92
  sudo_u_l2: !!g.sudo_u_l2,
93
93
  };
94
94
  }
95
- function loadCfg() { try { Object.assign(cfg, JSON.parse(fs.readFileSync(CFG_FILE, 'utf8'))); } catch { } cfg.guard = normalizeGuard(cfg.guard); }
95
+ function loadCfg() { try { Object.assign(cfg, JSON.parse(fs.readFileSync(CFG_FILE, 'utf8'))); } catch { } delete cfg.arm_mcp_url; /* MCP 通道已退役:剥离旧配置残留 */ cfg.guard = normalizeGuard(cfg.guard); }
96
96
  loadCfg();
97
97
  const guardNow = () => cfg.guard;
98
98
  function saveCfg() { fs.writeFileSync(CFG_FILE, JSON.stringify(cfg, null, 2)); }
99
- // ARM 站点地址:运行时配置 > ARM_API_BASE(env) > 从 MCP URL 推导 > 公司内网默认(内网可达即开箱可用);MCP 端点:显式配置 > 跟随站点地址
99
+ // ARM 站点地址:运行时配置 > ARM_API_BASE(env) > 公司内网默认(内网可达即开箱可用)
100
+ //(2026-10-21 全面切换新版 ARM:仅 REST 通道,MCP 通道及旧版兼容回落已退役)
100
101
  const ARM_DEFAULT_BASE = 'http://arm.agent-platform.dev.aimstek.cn';
101
- const armApiBase = () => cfg.arm_api_base || process.env.ARM_API_BASE || env.ARM_API_BASE || (env.ARM_MCP_URL ? String(env.ARM_MCP_URL).replace(/\/api\/mcp$/, '') : ARM_DEFAULT_BASE);
102
- const armMcpUrl = () => cfg.arm_mcp_url || `${armApiBase()}/api/mcp`;
102
+ const armApiBase = () => cfg.arm_api_base || process.env.ARM_API_BASE || env.ARM_API_BASE || ARM_DEFAULT_BASE;
103
103
  const armApiToken = () => cfg.arm_token || env.ARM_API_TOKEN || ARM_PAT;
104
104
  // LLM:OpenAI 兼容端点(baseUrl/模型/密钥),缺省公司内网 bifrost 网关(内网可达即可用,无需配置)
105
105
  const LLM_DEFAULT_BASE = 'http://bifrost.infra.dev.aimstek.cn/v1';
@@ -186,26 +186,7 @@ const world = { devices: [], alarms: [], kpi: {}, work_orders: [], inspections:
186
186
  function audit(entry) { entry.ts = new Date().toISOString(); fs.appendFileSync(AUDIT_LOG, JSON.stringify(entry) + '\n'); }
187
187
  function metric(entry) { entry.ts = new Date().toISOString(); fs.appendFileSync(METRICS_LOG, JSON.stringify(entry) + '\n'); }
188
188
 
189
- // ── ARM MCP 客户端(调用链 + 回流链)─────────────────────
190
- async function mcpCall(name, args, { pat = false, timeout_ms = 20000 } = {}) {
191
- const headers = { 'Content-Type': 'application/json', 'Accept': 'application/json, text/event-stream' };
192
- if (pat && ARM_PAT) headers['Authorization'] = `Bearer ${ARM_PAT}`;
193
- const ctrl = new AbortController();
194
- const timer = setTimeout(() => ctrl.abort(), timeout_ms); // 离线快速失败(降级本地库)
195
- let data;
196
- try {
197
- const res = await fetch(armMcpUrl(), {
198
- method: 'POST', headers, signal: ctrl.signal,
199
- body: JSON.stringify({ jsonrpc: '2.0', id: crypto.randomUUID(), method: 'tools/call', params: { name, arguments: args } }),
200
- });
201
- data = await res.json();
202
- } finally { clearTimeout(timer); }
203
- if (data.error) throw new Error(`ARM MCP ${name}: ${data.error.message}`);
204
- if ((data.result || {}).isError) throw new Error(`ARM MCP ${name} 拒绝: ${((data.result).content || []).map(c => c.text).join('').slice(0, 150)}`);
205
- return ((data.result || {}).content || []).map(c => c.text || '').join('\n');
206
- }
207
-
208
- // ARM REST 客户端(v2 开发版结构化通道;{ ok, data, msg } 包络,ok=false 抛错)
189
+ // ARM REST 客户端(v2 开发版结构化通道;{ ok, data, msg } 包络,ok=false 抛错)——目录/检索/下载/回流全链路唯一通道
209
190
  async function armRest(pathname, init = {}, timeout_ms = 20000) {
210
191
  const headers = { 'Content-Type': 'application/json', ...(init.headers || {}) };
211
192
  const token = armApiToken();
@@ -232,6 +213,11 @@ async function armRest(pathname, init = {}, timeout_ms = 20000) {
232
213
  throw e;
233
214
  } finally { clearTimeout(timer); }
234
215
  }
216
+ // 知识写入(经验回流链):REST v2,令牌走 armApiToken() 三级回落(设置页 > env > ~/.arm PAT)
217
+ // 返回 data: { id, name, shareUrl, … }——id 为 UUID,供指标留痕与回流记录定位
218
+ async function armCreateKnowledge({ name, description, content, tags }) {
219
+ return armRest('/api/v1/knowledges', { method: 'POST', body: JSON.stringify({ name, description, content, tags }) }, 25000);
220
+ }
235
221
  const vVer = (v) => (String(v || '').startsWith('v') ? String(v) : `v${v || '0.0.0'}`); // REST 无 v 前缀,统一内部表示
236
222
 
237
223
  const agentCache = new Map();
@@ -240,30 +226,14 @@ async function getArmAgent(agentId) {
240
226
  if (lm) return { name: lm.name, version: lm.version, prompt: lm.prompt, knowledges: (lm.knowledges || []).map(k => k.ref) };
241
227
  const hit = agentCache.get(agentId);
242
228
  if (hit && Date.now() - hit.at < 5 * 60_000) return hit.data;
243
- const text = await mcpCall('get_agent', { id: agentId });
244
- const name = (text.match(/^#\s+(.+?)\s+\(/m) || [])[1] || agentId;
245
- const version = (text.match(/^#\s+.+?\s+\((v[\d.]+)\)/m) || [])[1] || '';
246
- const prompt = (text.match(/## Prompt\n([\s\S]*?)(\n## |\n*$)/) || [])[1]?.trim() || '';
247
- const knowledges = [...text.matchAll(/^- (.+?) v[\d.]+((\w+))/gm)].map(m => m[1]);
248
- const data = { name, version, prompt, knowledges };
229
+ const d = await armRest(`/api/v1/agents/${agentId}`);
230
+ const knowledges = (d.knowledges || []).map(kb => (kb.knowledge && kb.knowledge.name) || kb.knowledgeId || '').filter(Boolean);
231
+ const data = { name: d.name || agentId, version: vVer(d.version), prompt: d.prompt || '', knowledges };
249
232
  agentCache.set(agentId, { data, at: Date.now() });
250
233
  return data;
251
234
  }
252
235
 
253
- // search_agents 目录解析(大厅/同步共用)
254
- function parseAgentCards(raw) {
255
- const cards = [];
256
- for (const block of raw.split(/\n(?=## )/)) {
257
- const m = block.match(/^## (.+?) \((v[\d.]+)\)\nID: ([0-9a-f-]{36})/);
258
- if (!m) continue;
259
- const bind = block.match(/绑定:(\d+) Skill \/ (\d+) Knowledge/);
260
- const desc = (block.split('\n').filter(l => l && !l.startsWith('#') && !l.startsWith('ID:') && !l.startsWith('绑定'))[0] || '').trim();
261
- cards.push({ name: m[1], version: m[2], agent_id: m[3], skills: +(bind?.[1] || 0), knowledges: +(bind?.[2] || 0), description: desc.slice(0, 120) });
262
- }
263
- return cards;
264
- }
265
-
266
- // 助手目录:REST 分页结构化优先(可全量),旧版 ARM 回落 MCP markdown 解析(limit 上限 20)
236
+ // 助手目录:REST 分页结构化(可全量)
267
237
  async function armListAgents(keyword = '') {
268
238
  const out = [];
269
239
  for (let page = 1; page <= 5; page++) {
@@ -274,26 +244,16 @@ async function armListAgents(keyword = '') {
274
244
  return out.map(a => ({ agent_id: a.id, name: a.name, version: vVer(a.version), skills: a.skillsCount || 0, knowledges: a.knowledgesCount || 0, description: String(a.description || '').slice(0, 120), status: a.status || 'active', created_by: a.creatorName || a.createdBy || '' }));
275
245
  }
276
246
 
277
- // 知识检索(全局经验库):REST 混合检索(RAG 语义 ⊕ 关键词)优先,回落 MCP RAG
247
+ // 知识检索(全局经验库):REST 混合检索(RAG 语义 ⊕ 关键词);不可达由调用方降级(本地知识关键词命中)
278
248
  async function searchKnowledgeItems(query, topK = 5) {
279
- try {
280
- const d = await armRest('/api/v1/knowledges/search', { method: 'POST', body: JSON.stringify({ query, topK }) });
281
- return {
282
- via: `rest:${d.mode || 'hybrid'}${d.degraded ? ':degraded' : ''}`,
283
- items: (d.items || []).map(it => ({ title: it.name, similarity: it.score != null ? Math.round(it.score * 100) : null, snippet: String(it.snippet || '').slice(0, 320), id: it.knowledgeId })),
284
- };
285
- } catch {
286
- const text = await mcpCall('search_knowledges', { query, limit: topK });
287
- const items = text.split(/\n(?=## )/).filter(Boolean).map(b => {
288
- const title = (b.match(/^## (.+?)(?:(相似度 (\d+)%))?/) || [])[1] || b.slice(0, 40);
289
- return { title: title.trim(), similarity: +((b.match(/相似度 (\d+)%/) || [])[1] || 0) || null, snippet: b.replace(/^## .*\n?/, '').split('[完整内容')[0].slice(0, 320) };
290
- });
291
- return { via: 'mcp', items };
292
- }
249
+ const d = await armRest('/api/v1/knowledges/search', { method: 'POST', body: JSON.stringify({ query, topK }) });
250
+ return {
251
+ via: `rest:${d.mode || 'hybrid'}${d.degraded ? ':degraded' : ''}`,
252
+ items: (d.items || []).map(it => ({ title: it.name, similarity: it.score != null ? Math.round(it.score * 100) : null, snippet: String(it.snippet || '').slice(0, 320), id: it.knowledgeId })),
253
+ };
293
254
  }
294
255
 
295
256
  // ── 本地助手库(07-助手本地化:下载物化 → 离线可用;按版本目录存档,升级原子切指针)──
296
- const armSourceTag = (base) => { try { return `arm://${new URL(base).host}`; } catch { return 'arm://unknown'; } };
297
257
  const regFile = () => path.join(ARM_AGENTS_DIR, 'registry.json');
298
258
  function loadRegistry() {
299
259
  try { return JSON.parse(fs.readFileSync(regFile(), 'utf8')); } catch { return { agents: [], last_sync_at: null }; }
@@ -319,13 +279,7 @@ function cmpVersion(a, b) { // 'v1.10.0' vs 'v1.9.3' 语义化比较
319
279
  }
320
280
  const slug = (s) => String(s).trim().replace(/[\\/:*?"<>|\s]+/g, '-').slice(0, 60) || 'knowledge';
321
281
 
322
- // 下载物化:REST 主路径(结构化详情 + knowledgeId 直取全文),旧版 ARM 回落 MCP 解析
323
- async function downloadAgent(agentId) {
324
- try { return await downloadAgentRest(agentId); }
325
- catch { return await downloadAgentMcp(agentId); }
326
- }
327
-
328
- // 注册表提交(两路下载共用):写版本目录后原子切指针
282
+ // 注册表提交:写版本目录后原子切指针
329
283
  function commitDownload(manifest) {
330
284
  const reg = loadRegistry();
331
285
  let e = reg.agents.find(a => a.agent_id === manifest.agent_id);
@@ -349,7 +303,8 @@ function uninstallLocalAgent(agentId, purge_workspaces) {
349
303
  return true;
350
304
  }
351
305
 
352
- async function downloadAgentRest(agentId) {
306
+ // 下载物化:REST 结构化详情 + knowledgeId 直取全文
307
+ async function downloadAgent(agentId) {
353
308
  const d = await armRest(`/api/v1/agents/${agentId}`);
354
309
  const version = vVer(d.version);
355
310
  const verDir = path.join(ARM_AGENTS_DIR, agentId, 'versions', version);
@@ -396,48 +351,9 @@ async function downloadAgentRest(agentId) {
396
351
  return manifest;
397
352
  }
398
353
 
399
- // 旧版 ARM 兼容:get_agent markdown 解析 + 知识 ID 经检索定位
400
- async function downloadAgentMcp(agentId) {
401
- const text = await mcpCall('get_agent', { id: agentId }, { timeout_ms: 25000 });
402
- const section = (h) => (text.match(new RegExp(`## ${h}\\n([\\s\\S]*?)(\\n## |\\n*$)`)) || [])[1] || '';
403
- const parseList = (s) => [...s.matchAll(/^- (.+?) (v[\d.]+)((\w+))/gm)].map(m => ({ ref: m[1].trim(), version: m[2], kind: m[3] }));
404
- const name = (text.match(/^#\s+(.+?)\s+\(/m) || [])[1] || agentId;
405
- const version = (text.match(/^#\s+.+?\s+\((v[\d.]+)\)/m) || [])[1] || 'v0.0.0';
406
- const prompt = (text.match(/## Prompt\n([\s\S]*?)(\n## |\n*$)/) || [])[1]?.trim() || '';
407
- const description = section('描述').trim();
408
- const skills = parseList(section('Skills'));
409
- const verDir = path.join(ARM_AGENTS_DIR, agentId, 'versions', version);
410
- fs.mkdirSync(path.join(verDir, 'knowledges'), { recursive: true });
411
- const knowledges = [];
412
- for (const k of parseList(section('Knowledges'))) {
413
- let file = null, note = '';
414
- try { // 知识 ID 经检索定位(ARM 无按名直取接口),再拉全文。注意:知识正文自身含 "## " 内部标题,不可按标题切块——须按「标题→首个 [完整内容] 标记」成对匹配
415
- const sres = await mcpCall('search_knowledges', { query: k.ref, limit: 5 }, { timeout_ms: 20000 });
416
- const pairs = [...sres.matchAll(/^## (.+?)(?:(相似度 \d+%))?\n[\s\S]*?\[完整内容: get_knowledge id=([0-9a-f-]{36})\]/gm)];
417
- const kid = pairs.find(m => m[1].trim() === k.ref)?.[2];
418
- if (kid) {
419
- const full = await mcpCall('get_knowledge', { id: kid }, { timeout_ms: 20000 });
420
- file = `knowledges/${slug(k.ref)}.md`;
421
- fs.writeFileSync(path.join(verDir, file), full);
422
- } else note = 'ARM 检索未命中该知识,离线不可用';
423
- } catch (e) { note = `知识拉取失败: ${String(e.message).slice(0, 80)}`; }
424
- knowledges.push({ ...k, file, note });
425
- }
426
- const manifest = {
427
- agent_id: agentId, name, version, description,
428
- downloaded_at: new Date().toISOString(), source: armSourceTag(armMcpUrl()), prompt,
429
- skills, knowledges,
430
- };
431
- fs.writeFileSync(path.join(verDir, 'prompt.md'), prompt);
432
- fs.writeFileSync(path.join(verDir, 'manifest.json'), JSON.stringify(manifest, null, 2));
433
- commitDownload(manifest);
434
- audit({ actor: 'arm-library', agentId, action: 'download', via: 'mcp', version, knowledges_local: knowledges.filter(k => k.file).length });
435
- return manifest;
436
- }
437
-
438
354
  // 同步:比对远端目录与本地库,产出 new/update/delisted 事件;顺带冲账离线经验 outbox
439
355
  async function armSync() {
440
- const remote = await armListAgents(); // REST 全量优先,旧版 ARM 内部回落 MCP(≤20)
356
+ const remote = await armListAgents();
441
357
  const reg = loadRegistry();
442
358
  const remoteIds = new Set(remote.map(r => r.agent_id));
443
359
  const events = { new: [], update: [], delisted: [] };
@@ -465,7 +381,7 @@ async function flushExperienceOutbox() {
465
381
  const lines = fs.readFileSync(OUTBOX_FILE, 'utf8').split('\n').filter(Boolean);
466
382
  const remain = []; let ok = 0;
467
383
  for (const line of lines) {
468
- try { const it = JSON.parse(line); await mcpCall('create_knowledge', it.args, { pat: true }); ok++; }
384
+ try { const it = JSON.parse(line); await armCreateKnowledge(it.args); ok++; }
469
385
  catch { remain.push(line); }
470
386
  }
471
387
  fs.writeFileSync(OUTBOX_FILE, remain.length ? remain.join('\n') + '\n' : '');
@@ -687,16 +603,15 @@ const TOOLS = {
687
603
  const content = ['---', 'kind: experience', 'source: aims-platform-mvp', `agent: ${arm.name || agentId}@${arm.version || ''}`, 'scenario: 立库A区智能运维@mvp', '---', '', markdown].join('\n');
688
604
  const args = { name: title, description: `MVP回流:${title}`, content, tags: ['MVP回流'] };
689
605
  let r;
690
- try { r = await mcpCall('create_knowledge', args, { pat: true }); }
606
+ try { r = await armCreateKnowledge(args); }
691
607
  catch (e) { // 离线:入 outbox 缓写,恢复连接后经「检查更新」自动回流
692
608
  fs.appendFileSync(OUTBOX_FILE, JSON.stringify({ at: new Date().toISOString(), agentId, args }) + '\n');
693
609
  audit({ actor: 'experience-reflow', target: 'outbox', title });
694
610
  return `ARM 不可达(${String(e.message).slice(0, 60)}),经验已存本地待回流队列;恢复连接后在助手大厅点「检查更新」将自动回流。`;
695
611
  }
696
- const kid = (r.match(/id:\s*([0-9a-f-]{36})/) || [])[1] || '';
697
- metric({ kind: 'experience', agentId, title, knowledge_id: kid });
612
+ metric({ kind: 'experience', agentId, title, knowledge_id: r.id });
698
613
  audit({ actor: 'experience-reflow', target: 'ARM', title });
699
- return `经验已沉淀到 ARM 知识库:\n${r}`;
614
+ return `经验已沉淀到 ARM 知识库:${r.name}(id: ${r.id}${r.shareUrl ? `,${r.shareUrl}` : ''})`;
700
615
  },
701
616
  },
702
617
  };
@@ -1389,6 +1304,25 @@ const DEV_TOOLS = {
1389
1304
  const devCtx = { agentId: null };
1390
1305
  const devSessions = new Map();
1391
1306
 
1307
+ // 定制会话上下文裁剪:前端 sessionId 固定为 dev-<agentId前缀>,会话跨请求长存——不裁剪会无限增长,
1308
+ // 最终超过模型上下文窗口被网关整单拒绝(2026-10-21 海立实例"发消息没反应"根因)。
1309
+ // 超预算从最旧轮次整轮丢弃;下刀点只选 user 消息边界,剩余前缀不会出现孤儿 toolResult(转换层要求其紧跟 assistant 的 toolCall);当前轮永不裁。
1310
+ const DEV_CTX_CHAR_BUDGET = 150_000; // 字符预算:混合中英/代码转录按 ~0.4 token/char 估 ≈ 60K token,对 128K 窗口留足余量
1311
+ function trimDevContext(ctx) {
1312
+ const msgs = ctx.messages;
1313
+ const size = () => msgs.reduce((n, m) => n + JSON.stringify(m.content ?? '').length, 0);
1314
+ if (size() <= DEV_CTX_CHAR_BUDGET) return 0;
1315
+ const lastUser = msgs.length - 1 - [...msgs].reverse().findIndex((m) => m.role === 'user');
1316
+ let dropped = 0;
1317
+ while (size() > DEV_CTX_CHAR_BUDGET) {
1318
+ const cut = msgs.slice(1, lastUser - dropped).findIndex((m) => m.role === 'user');
1319
+ if (cut < 0) break; // 当前轮之前再无完整轮次可丢(单轮就超预算只能放行,交由模型侧报错)
1320
+ dropped += cut + 1;
1321
+ msgs.splice(0, cut + 1);
1322
+ }
1323
+ return dropped;
1324
+ }
1325
+
1392
1326
  function devSystemPrompt() {
1393
1327
  const live = loadWorkbench(devCtx.agentId);
1394
1328
  const plugins = listPanelPlugins();
@@ -1470,12 +1404,24 @@ async function devChatLoop(session, emit, signal = null) {
1470
1404
  if (interrupted()) { emit('interrupted', { at: `第 ${round + 1} 轮` }); return { reply: '(已被用户中断)', events }; }
1471
1405
  emit('status', { text: `第 ${round + 1} 轮` });
1472
1406
  const stream = models.stream(model, session.context, signal ? { signal } : undefined);
1473
- for await (const ev of stream) {
1474
- if (interrupted()) break;
1475
- if (ev.type === 'text_delta') emit('text_delta', { delta: ev.delta });
1476
- else if (ev.type === 'toolcall_end') emit('status', { text: `调用工具 ${ev.toolCall?.name || ''}` });
1407
+ let final = null;
1408
+ try {
1409
+ for await (const ev of stream) {
1410
+ if (interrupted()) break;
1411
+ if (ev.type === 'text_delta') emit('text_delta', { delta: ev.delta });
1412
+ else if (ev.type === 'toolcall_end') emit('status', { text: `调用工具 ${ev.toolCall?.name || ''}` });
1413
+ else if (ev.type === 'error') {
1414
+ if (interrupted()) break; // 中断引发的流错误按中断处理,不报错
1415
+ throw new Error(`LLM 流错误: ${ev.error?.errorMessage || JSON.stringify(ev.error).slice(0, 200)}`);
1416
+ }
1417
+ }
1418
+ final = await stream.result();
1419
+ // pi-ai 把认证/请求失败表现为 stopReason=error 而非异常(同 llmProbe 判定)——不检查会被吞成静默空回复
1420
+ if (final?.stopReason === 'error') throw new Error(`LLM 请求失败: ${final.error?.errorMessage || JSON.stringify(final.error || {}).slice(0, 200) || final.stopReason}`);
1421
+ } catch (e) {
1422
+ if (!interrupted()) throw e; // 真实错误上抛给路由 catch → SSE error → 前端 toast;中断路径用占位消息兜底
1477
1423
  }
1478
- const final = await stream.result();
1424
+ if (!final) final = { role: 'assistant', content: [], timestamp: Date.now() };
1479
1425
  session.context.messages.push(final);
1480
1426
  const calls = (final.content || []).filter(b => b.type === 'toolCall');
1481
1427
  const text = (final.content || []).filter(b => b.type === 'text').map(b => b.text).join('');
@@ -1680,7 +1626,7 @@ const server = http.createServer(async (req, res) => {
1680
1626
  if (pathname === '/api/health') return json(res, 200, { ok: true, auth_required: true }); // 前端据此弹登录门
1681
1627
  return json(res, 401, { error: '需要访问令牌', code: 'AUTH_REQUIRED' });
1682
1628
  }
1683
- if (req.method === 'GET' && pathname === '/api/health') return json(res, 200, { ok: true, model: model?.id, arm: armMcpUrl(), pat: !!ARM_PAT, local_agents: loadRegistry().agents.length });
1629
+ if (req.method === 'GET' && pathname === '/api/health') return json(res, 200, { ok: true, model: model?.id, arm: armApiBase(), pat: !!ARM_PAT, local_agents: loadRegistry().agents.length });
1684
1630
 
1685
1631
  // ── ARM 连接与同步(07:大厅双视图 = 本地助手库 ∪ 远端目录)──
1686
1632
  if (req.method === 'GET' && pathname === '/api/settings') {
@@ -1689,7 +1635,6 @@ const server = http.createServer(async (req, res) => {
1689
1635
  return json(res, 200, {
1690
1636
  arm: {
1691
1637
  api_base: armApiBase(), api_base_runtime: !!cfg.arm_api_base, default_base: ARM_DEFAULT_BASE,
1692
- mcp_url: armMcpUrl(), mcp_explicit: !!cfg.arm_mcp_url,
1693
1638
  token_set: !!t, token_masked: t ? `${t.slice(0, 10)}…${t.slice(-4)}` : '',
1694
1639
  token_source: cfg.arm_token ? 'runtime' : (env.ARM_API_TOKEN ? 'env' : (ARM_PAT ? 'pat' : 'none')),
1695
1640
  },
@@ -1705,7 +1650,7 @@ const server = http.createServer(async (req, res) => {
1705
1650
  });
1706
1651
  }
1707
1652
  if (req.method === 'PUT' && pathname === '/api/settings') {
1708
- const { arm_api_base, arm_mcp_url, arm_token, llm_base_url, llm_api_key, llm_model, scene_profile, access_token, guard } = await body(req);
1653
+ const { arm_api_base, arm_token, llm_base_url, llm_api_key, llm_model, scene_profile, access_token, guard } = await body(req);
1709
1654
  // 守护栏维护:deny 正则可编译 / ro 须为单命令名;保存即热生效(classifyExec 每次调用现读配置);删减危险规则记入审计
1710
1655
  let guardAudit = null;
1711
1656
  if (guard !== undefined) {
@@ -1736,11 +1681,6 @@ const server = http.createServer(async (req, res) => {
1736
1681
  if (u && !/^https?:\/\/[^\s/]+/.test(u)) return json(res, 400, { error: `站点地址须为 http(s) URL:${u}` });
1737
1682
  cfg.arm_api_base = u;
1738
1683
  }
1739
- if (arm_mcp_url !== undefined) {
1740
- const u = normUrl(arm_mcp_url);
1741
- if (u && !/^https?:\/\/[^\s/]+/.test(u)) return json(res, 400, { error: `MCP 端点须为 http(s) URL:${u}` });
1742
- cfg.arm_mcp_url = u;
1743
- }
1744
1684
  if (arm_token !== undefined) cfg.arm_token = String(arm_token || '').trim(); // 置空 = 回落 env/PAT
1745
1685
  if (llm_base_url !== undefined) {
1746
1686
  const u = normUrl(llm_base_url);
@@ -1766,10 +1706,10 @@ const server = http.createServer(async (req, res) => {
1766
1706
  try { llm_probe = await llmProbe(); } catch (e) { llm_probe = { online: false, error: String(e.message).slice(0, 150) }; }
1767
1707
  }
1768
1708
  saveCfg();
1769
- audit({ actor: 'settings', action: 'save', arm_api_base: cfg.arm_api_base, mcp_explicit: !!cfg.arm_mcp_url, llm_model: cfg.llm_model, llm_base_changed: llm_base_url !== undefined, token_changed: arm_token !== undefined || llm_api_key !== undefined, scene_profile_changed: sceneChanged, scene_profile_len: sceneProfile().length, auth_changed: authChanged, guard_changed: guardAudit });
1709
+ audit({ actor: 'settings', action: 'save', arm_api_base: cfg.arm_api_base, llm_model: cfg.llm_model, llm_base_changed: llm_base_url !== undefined, token_changed: arm_token !== undefined || llm_api_key !== undefined, scene_profile_changed: sceneChanged, scene_profile_len: sceneProfile().length, auth_changed: authChanged, guard_changed: guardAudit });
1770
1710
  // ARM 保存后即时探测(失败不回滚:允许先配置后启动 ARM)
1771
1711
  let probe = { online: false, error: '' };
1772
- if ([arm_api_base, arm_mcp_url, arm_token].some((v) => v !== undefined)) {
1712
+ if ([arm_api_base, arm_token].some((v) => v !== undefined)) {
1773
1713
  try {
1774
1714
  const t0 = Date.now();
1775
1715
  await armRest('/api/v1/agents?page=1&pageSize=1', {}, 6000);
@@ -1777,7 +1717,7 @@ const server = http.createServer(async (req, res) => {
1777
1717
  } catch (e) { probe = { online: false, error: String(e.message).slice(0, 120) }; }
1778
1718
  }
1779
1719
  const notes = [];
1780
- if (probe.error) notes.push('ARM 当前源不可达(目录/检索将回落 MCP 或本地库,源恢复后自动可用)');
1720
+ if (probe.error) notes.push('ARM 当前源不可达(目录/检索将回落本地库,源恢复后自动可用)');
1781
1721
  if (llm_probe && !llm_probe.online) notes.push('LLM 已保存但探针未通过(密钥/端点/模型可用性待确认,对话可能失败,可再试或改回)');
1782
1722
  return json(res, 200, { saved: true, probe, llm_probe, note: notes.join(';') });
1783
1723
  }
@@ -1787,14 +1727,9 @@ const server = http.createServer(async (req, res) => {
1787
1727
  try {
1788
1728
  await armRest('/api/v1/agents?page=1&pageSize=1', {}, 6000);
1789
1729
  online = true; latency_ms = Date.now() - t0;
1790
- } catch {
1791
- try { // 旧版 ARM 无 REST:回落 MCP 探测
1792
- await mcpCall('search_agents', { keyword: '', limit: 1 }, { timeout_ms: 6000 });
1793
- online = true; latency_ms = Date.now() - t0;
1794
- } catch { }
1795
- }
1730
+ } catch { }
1796
1731
  const reg = loadRegistry();
1797
- return json(res, 200, { online, latency_ms, url: armMcpUrl(), api: armApiBase(), pat: !!ARM_PAT, last_sync_at: reg.last_sync_at || null, local_count: reg.agents.length, outbox_pending: outboxCount() });
1732
+ return json(res, 200, { online, latency_ms, api: armApiBase(), pat: !!ARM_PAT, last_sync_at: reg.last_sync_at || null, local_count: reg.agents.length, outbox_pending: outboxCount() });
1798
1733
  }
1799
1734
  if (req.method === 'POST' && pathname === '/api/arm/sync') {
1800
1735
  try { return json(res, 200, await armSync()); }
@@ -1806,7 +1741,7 @@ const server = http.createServer(async (req, res) => {
1806
1741
  const kw = (url.searchParams.get('keyword') || '').trim().toLowerCase();
1807
1742
  const reg = loadRegistry();
1808
1743
  let online = true, remoteCards = [], authError = false;
1809
- try { remoteCards = await armListAgents(url.searchParams.get('keyword') || ''); } // REST 全量优先,旧版回落 MCP
1744
+ try { remoteCards = await armListAgents(url.searchParams.get('keyword') || ''); } // REST 全量
1810
1745
  catch (e) { online = false; authError = /令牌未配置或无权限/.test(String(e.message)); } // 区分"未授权"与"不可达",前端引导配置令牌
1811
1746
  const byId = new Map();
1812
1747
  for (const e of reg.agents) {
@@ -2409,6 +2344,8 @@ const server = http.createServer(async (req, res) => {
2409
2344
  s.context.systemPrompt = devSystemPrompt();
2410
2345
  }
2411
2346
  s.context.messages.push({ role: 'user', content: message, timestamp: Date.now() });
2347
+ const dropped = trimDevContext(s.context);
2348
+ if (dropped > 0) emit('status', { text: `会话历史过长,已自动裁剪最早 ${dropped} 条消息` });
2412
2349
  await devChatLoop(s, emit, ctl.signal);
2413
2350
  emit('meta', { hasDraft: !!loadDraft(agentId) });
2414
2351
  } catch (e) { emit('error', { message: e.message }); }
@@ -2540,11 +2477,10 @@ const server = http.createServer(async (req, res) => {
2540
2477
  const { agentId, name, description, content } = await body(req);
2541
2478
  const arm = agentProfileNow(agentId);
2542
2479
  const full = ['---', 'kind: experience', 'source: aims-platform-mvp', `agent: ${arm.name || agentId}@${arm.version || ''}`, 'scenario: 立库A区智能运维@mvp', '---', '', content].join('\n');
2543
- const r = await mcpCall('create_knowledge', { name, description: description || `工作台人工审阅沉淀`, content: full, tags: ['MVP回流'] }, { pat: true });
2544
- const kid = (r.match(/id:\s*([0-9a-f-]{36})/) || [])[1] || '';
2545
- metric({ kind: 'experience', agentId, title: name, knowledge_id: kid });
2480
+ const r = await armCreateKnowledge({ name, description: description || `工作台人工审阅沉淀`, content: full, tags: ['MVP回流'] });
2481
+ metric({ kind: 'experience', agentId, title: name, knowledge_id: r.id });
2546
2482
  audit({ actor: 'experience-reflow', target: 'ARM', name });
2547
- return json(res, 200, { result: r });
2483
+ return json(res, 200, { result: `已创建 ${r.name}(id: ${r.id})${r.shareUrl ? `\n${r.shareUrl}` : ''}`, knowledge_id: r.id, share_url: r.shareUrl || '' });
2548
2484
  }
2549
2485
  // ── 自进化看板 ──
2550
2486
  if (req.method === 'GET' && pathname === '/api/evolution') {
@@ -2623,7 +2559,7 @@ applyLLMConfig().then(() => {
2623
2559
  server.listen(PORT, HOST, () => {
2624
2560
  console.log(`[aims-workstation] http://localhost:${PORT}(绑定 ${HOST}) | 模型: ${model.id} @ ${model.baseUrl}`);
2625
2561
  console.log(`[aims-workstation] 数据目录 AIMS_HOME: ${AIMS_HOME}`);
2626
- console.log(`[aims-workstation] ARM: ${armMcpUrl()} | REST: ${armApiBase()} | PAT: ${ARM_PAT ? '已加载' : '未配置'} | 已上岗助手: ${fs.readdirSync(DEPLOY_DIR).length} | 本地助手库: ${loadRegistry().agents.length}`);
2562
+ console.log(`[aims-workstation] ARM(REST): ${armApiBase()} | PAT: ${ARM_PAT ? '已加载' : '未配置'} | 已上岗助手: ${fs.readdirSync(DEPLOY_DIR).length} | 本地助手库: ${loadRegistry().agents.length}`);
2627
2563
  });
2628
2564
  // 已上岗助手后台物化为本地档案(best-effort;ARM 不可达时静默跳过,待手动同步)
2629
2565
  (async () => {
@@ -97,8 +97,8 @@ Error generating stack: `+e.message+`
97
97
  [&_td]:border [&_td]:border-border [&_td]:px-2 [&_td]:py-1 [&_td]:break-words`,children:(0,K.jsx)(Kw,{remarkPlugins:[QD],children:e})})}function eO({className:e,children:t,...n}){return(0,K.jsxs)(Bd,{"data-slot":`scroll-area`,className:mn(`relative`,e),...n,children:[(0,K.jsx)(Ud,{"data-slot":`scroll-area-viewport`,className:`size-full rounded-[inherit] transition-[color,box-shadow] outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50 focus-visible:outline-1`,children:t}),(0,K.jsx)(tO,{}),(0,K.jsx)(lf,{})]})}function tO({className:e,orientation:t=`vertical`,...n}){return(0,K.jsx)(Jd,{"data-slot":`scroll-area-scrollbar`,orientation:t,className:mn(`flex touch-none p-px transition-colors select-none`,t===`vertical`&&`h-full w-2.5 border-l border-l-transparent`,t===`horizontal`&&`h-2.5 flex-col border-t border-t-transparent`,e),...n,children:(0,K.jsx)(of,{"data-slot":`scroll-area-thumb`,className:`relative flex-1 rounded-full bg-border`})})}function nO({className:e,...t}){return(0,K.jsx)(`textarea`,{"data-slot":`textarea`,className:mn(`flex field-sizing-content min-h-16 w-full rounded-md border border-input bg-transparent px-3 py-2 text-base shadow-xs transition-[color,box-shadow] outline-none placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 md:text-sm dark:bg-input/30 dark:aria-invalid:ring-destructive/40`,e),...t})}function rO({agentId:e,sessionId:t,wsId:n,injectedDevice:r,autonomy:i,onAutonomy:a}){let[o,s]=(0,v.useState)([]),[c,l]=(0,v.useState)(``),[u,d]=(0,v.useState)(!1),[f,p]=(0,v.useState)(null),[m,h]=(0,v.useState)(``),[g,_]=(0,v.useState)(!1),[y,b]=(0,v.useState)(``),[x,S]=(0,v.useState)(``),C=(0,v.useRef)(null),w=(0,v.useRef)(null),T=(0,v.useRef)(!1);(0,v.useEffect)(()=>{T.current=u},[u]);let E=(0,v.useRef)(!1),D=(0,v.useRef)(!1);(0,v.useEffect)(()=>{let e=!0,n=async()=>{if(T.current||!e)return;let n;try{n=await ot(`/api/chat/history?sessionId=${encodeURIComponent(t)}`)}catch{return}if(!e||!n.exists)return;let r=!!(n.running||n.pending);(!E.current||r||D.current)&&(E.current=!0,D.current=r,s([...n.msgs||[],...n.pending?[{kind:`pending`,intro:`(恢复现场)待确认操作:${n.pending.tool}`}]:[]]),p(n.pending||null),h(r?`后台进行中:${n.statusText||(n.pending?`等待人工确认`:``)}`:``))};n();let r=setInterval(n,2500);return()=>{e=!1,clearInterval(r)}},[t]);let O=(0,v.useRef)(!0),k=(0,v.useCallback)(()=>{let e=C.current?.closest(`[data-slot="scroll-area-viewport"]`);e&&(e.scrollTop=e.scrollHeight)},[]);(0,v.useEffect)(()=>{let e=C.current?.closest(`[data-slot="scroll-area-viewport"]`);if(!e)return;let t=()=>{O.current=e.scrollHeight-e.scrollTop-e.clientHeight<80};return e.addEventListener(`scroll`,t),()=>e.removeEventListener(`scroll`,t)},[]),(0,v.useEffect)(()=>{O.current&&k()},[o,m,k]),(0,v.useEffect)(()=>{O.current=!0},[t]);let A=e=>s(t=>[...t,e]),j=(0,v.useRef)(null),M=()=>{j.current?.abort(),st(`/api/chat/interrupt`,{sessionId:t}).catch(()=>{})},N=e=>{let t=e.type;if(t===`status`)h(String(e.text||``));else if(t===`text_delta`){let t=e.delta;h(``),s(e=>{let n=e[e.length-1];return n?.kind===`bot`?[...e.slice(0,-1),{...n,text:(n.text||``)+t}]:[...e,{kind:`bot`,text:t}]})}else t===`tool_start`?A({kind:`evt`,evt:{tool:e.tool,args:e.args,result:`…`,status:`start`}}):t===`tool_end`?s(t=>{let n=[...t].reverse().findIndex(t=>t.kind===`evt`&&t.evt?.tool===e.tool&&t.evt?.status===`start`);if(n<0)return[...t,{kind:`evt`,evt:e}];let r=t.length-1-n;return t.map((t,n)=>n===r?{kind:`evt`,evt:e}:t)}):t===`pending`?(p(e.pending),A({kind:`pending`,intro:e.intro}),h(``)):t===`done`?(h(``),e.reply&&s(t=>{let n=t[t.length-1];return n?.kind===`bot`&&n.text&&e.reply&&n.text.trim()===String(e.reply).trim()?t:[...t,{kind:`bot`,text:String(e.reply)}]})):t===`interrupted`?(h(``),s(e=>{let t=e[e.length-1];return t?.kind===`bot`?[...e.slice(0,-1),{...t,text:(t.text||``)+`
98
98
 
99
99
  (已中断)`}]:[...e,{kind:`bot`,text:`(已中断)`}]})):t===`error`&&(Z.error(String(e.message)),h(``))},P=async()=>{let e=c.trim();e&&!u&&(l(``),await F(e))},F=async a=>{if(u)return;d(!0),O.current=!0,A({kind:`user`,text:a});let o=new AbortController;j.current=o;try{await ut(`/api/chat`,{sessionId:t,agentId:e,message:a,autonomyLevel:i,ws_id:n,context:r?{device:r}:null},N,o.signal)}catch(e){o.signal.aborted||Z.error(String(e.message))}finally{d(!1),j.current===o&&(j.current=null)}},I=async e=>{if(!f)return;p(null),d(!0),O.current=!0,s(e=>e.filter(e=>e.kind!==`pending`));let n=new AbortController;j.current=n;try{await ut(`/api/chat/confirm`,{sessionId:t,approved:e},N,n.signal)}catch(e){n.signal.aborted||Z.error(String(e.message))}finally{d(!1),j.current===n&&(j.current=null)}};return(0,K.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-2 border-b px-3 py-1`,children:[(0,K.jsx)(th,{className:`h-3.5 w-3.5 text-primary`}),(0,K.jsx)(`span`,{className:`text-xs font-medium`,children:`诊断对话`}),(0,K.jsx)(`span`,{className:`text-[10px] text-muted-foreground`,children:r?`上下文:${r}(点选设备自动注入)`:`点击左侧设备可注入上下文`}),(0,K.jsxs)(`div`,{className:`ml-auto flex items-center gap-1.5`,children:[(0,K.jsx)(`span`,{className:`text-[10px] text-muted-foreground`,children:`自主级别`}),(0,K.jsxs)(h_,{value:String(i),onValueChange:e=>a(+e),children:[(0,K.jsx)(__,{className:`h-7 w-[118px] text-xs`,children:(0,K.jsx)(g_,{})}),(0,K.jsxs)(v_,{children:[(0,K.jsx)(y_,{value:`0`,className:`text-xs`,children:`L0 只读问答`}),(0,K.jsx)(y_,{value:`1`,className:`text-xs`,children:`L1 诊断建议`}),(0,K.jsx)(y_,{value:`2`,className:`text-xs`,children:`L2 确认执行`}),(0,K.jsx)(y_,{value:`3`,className:`text-xs text-red-400`,children:`L3 完全自主(免确认)`})]})]})]})]}),(0,K.jsx)(eO,{className:`min-h-0 flex-1 [&>div>div]:block!`,children:(0,K.jsxs)(`div`,{className:`space-y-2.5 p-3`,ref:C,children:[o.length===0&&(0,K.jsxs)(`div`,{className:`flex h-40 flex-col items-center justify-center gap-1 text-xs text-muted-foreground`,children:[(0,K.jsx)(Vh,{className:`h-5 w-5 opacity-50`}),`试试:「STK-R3 什么情况?帮我处理」 / 「服务器 CPU 高,怎么处理」`]}),o.map((e,t)=>{if(e.kind===`user`)return(0,K.jsx)(`div`,{className:`ml-auto max-w-[85%] rounded-lg bg-primary/20 px-3 py-1.5 text-xs leading-relaxed break-words`,children:e.text},t);if(e.kind===`bot`)return(0,K.jsx)(`div`,{className:`max-w-[92%] rounded-lg bg-card px-3 py-2 text-xs leading-relaxed break-words`,children:(e.text||``).split(/```a2ui\s*\n?([\s\S]*?)```/g).map((e,t)=>t%2==0?e.trim()?(0,K.jsx)($D,{text:e},t):null:(0,K.jsx)(av,{raw:e,onSend:F},t))},t);if(e.kind===`evt`&&e.evt){let n=e.evt.status,r={ok:`✅`,executed:`▶`,blocked:`⛔`,cancelled:`🚫`,rejected:`❌`,start:`⏳`}[n]||`•`;return(0,K.jsxs)(`div`,{className:it(`max-w-[92%] rounded-md border border-dashed px-2.5 py-1.5 text-[11px]`,n===`blocked`?`border-red-500/50 text-red-300`:n===`start`?`border-border text-muted-foreground`:`border-border`),children:[(0,K.jsxs)(`div`,{className:`flex min-w-0 items-center gap-1.5`,children:[(0,K.jsx)(`span`,{className:`shrink-0`,children:r}),(0,K.jsx)(t_,{className:`h-3 w-3 shrink-0`}),(0,K.jsx)(`span`,{className:`shrink-0 font-mono font-semibold`,children:e.evt.tool}),(0,K.jsx)(`span`,{className:`min-w-0 flex-1 truncate text-muted-foreground`,children:JSON.stringify(e.evt.args)})]}),n!==`start`&&(0,K.jsx)(`pre`,{className:`mt-1 max-h-40 overflow-auto whitespace-pre-wrap break-all text-[10px] leading-relaxed text-muted-foreground`,children:String(e.evt.result).slice(0,700)})]},t)}return e.kind===`pending`?(0,K.jsx)(bm,{className:`max-w-[92%] border-amber-500/50 bg-amber-500/5`,children:(0,K.jsxs)(Cm,{className:`space-y-2 p-3`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-1.5 text-xs font-semibold text-amber-300`,children:[(0,K.jsx)(jg,{className:`h-3.5 w-3.5`}),`人工确认(L2)· 助手请求执行写操作`]}),e.intro&&(0,K.jsx)(`div`,{className:`text-[11px] text-muted-foreground`,children:(0,K.jsx)($D,{text:e.intro})}),(0,K.jsxs)(`div`,{className:`flex gap-2`,children:[(0,K.jsx)(Y,{size:`sm`,variant:`destructive`,onClick:()=>I(!1),children:`取消`}),(0,K.jsx)(Y,{size:`sm`,onClick:()=>I(!0),children:`确认执行`})]})]})},t):null}),m&&(0,K.jsxs)(`div`,{className:`flex items-center gap-1.5 px-1 text-[11px] text-muted-foreground`,children:[(0,K.jsx)(`span`,{className:`h-1.5 w-1.5 animate-pulse rounded-full bg-primary`}),m,m.startsWith(`后台进行中`)&&(0,K.jsx)(Y,{size:`sm`,variant:`ghost`,className:`h-5 gap-1 px-1.5 text-[10px] text-red-400 hover:text-red-300`,onClick:()=>{h(``),M()},children:`⏹ 中断`}),(0,K.jsx)(`span`,{ref:w})]})]})}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2 border-t p-2`,children:[(0,K.jsx)(nO,{value:c,onChange:e=>l(e.target.value),rows:1,placeholder:`描述问题…(Enter 发送,Shift+Enter 换行)`,className:`min-h-[38px] resize-none text-xs`,onKeyDown:e=>{e.key===`Enter`&&!e.shiftKey&&(e.preventDefault(),P())}}),u?(0,K.jsx)(Y,{size:`icon`,variant:`destructive`,title:`中断当前对话`,onClick:M,children:(0,K.jsx)(Vg,{className:`h-3.5 w-3.5`})}):(0,K.jsx)(Y,{size:`icon`,disabled:!c.trim(),onClick:P,children:(0,K.jsx)(Cg,{className:`h-3.5 w-3.5`})}),(0,K.jsx)(Y,{size:`sm`,variant:`outline`,className:`shrink-0 text-[11px]`,onClick:async()=>{try{let e=await st(`/api/experience/draft`,{sessionId:t});S(e.markdown),b(``),_(!0)}catch(e){Z.error(String(e.message))}},children:`📥 沉淀经验`})]}),(0,K.jsx)(a_,{open:g,onOpenChange:_,children:(0,K.jsxs)(c_,{className:`max-w-xl`,children:[(0,K.jsx)(l_,{children:(0,K.jsx)(d_,{children:`经验回流 · AI 起草 → 人工审阅 → 写入 ARM`})}),(0,K.jsx)(p_,{value:y,onChange:e=>b(e.target.value),placeholder:`经验标题(留空自动生成)`,className:`text-xs`}),(0,K.jsx)(nO,{value:x,onChange:e=>S(e.target.value),className:`min-h-[260px] font-mono text-[11px]`}),(0,K.jsxs)(u_,{children:[(0,K.jsx)(Y,{variant:`outline`,onClick:()=>_(!1),children:`取消`}),(0,K.jsx)(Y,{onClick:async()=>{try{let t=await st(`/api/experience/commit`,{agentId:e,name:y.trim()||`MVP经验-${gt(new Date().toISOString())}`,description:`工作台人工审阅沉淀`,content:x});_(!1),Z.success(`已回流 ARM 知识库`,{description:t.result.slice(0,90)})}catch(e){Z.error(String(e.message))}},children:`确认沉淀到 ARM 知识库`})]})]})})]})}var iO=function(e,t,n,r){var i;t[0]=0;for(var a=1;a<t.length;a++){var o=t[a++],s=t[a]?(t[0]|=o?1:2,n[t[a++]]):t[++a];o===3?r[0]=s:o===4?r[1]=Object.assign(r[1]||{},s):o===5?(r[1]=r[1]||{})[t[++a]]=s:o===6?r[1][t[++a]]+=s+``:o?(i=e.apply(s,iO(e,s,n,[``,null])),r.push(i),s[0]?t[0]|=2:(t[a-2]=0,t[a]=i)):r.push(s)}return r},aO=new Map;function oO(e){var t=aO.get(this);return t||(t=new Map,aO.set(this,t)),(t=iO(this,t.get(e)||(t.set(e,t=function(e){for(var t,n,r=1,i=``,a=``,o=[0],s=function(e){r===1&&(e||(i=i.replace(/^\s*\n\s*|\s*\n\s*$/g,``)))?o.push(0,e,i):r===3&&(e||i)?(o.push(3,e,i),r=2):r===2&&i===`...`&&e?o.push(4,e,0):r===2&&i&&!e?o.push(5,0,!0,i):r>=5&&((i||!e&&r===5)&&(o.push(r,0,i,n),r=6),e&&(o.push(r,e,0,n),r=6)),i=``},c=0;c<e.length;c++){c&&(r===1&&s(),s(c));for(var l=0;l<e[c].length;l++)t=e[c][l],r===1?t===`<`?(s(),o=[o],r=3):i+=t:r===4?i===`--`&&t===`>`?(r=1,i=``):i=t+i[0]:a?t===a?a=``:i+=t:t===`"`||t===`'`?a=t:t===`>`?(s(),r=1):r&&(t===`=`?(r=5,n=i,i=``):t===`/`&&(r<5||e[c][l+1]===`>`)?(s(),r===3&&(o=o[0]),r=o,(o=o[0]).push(2,0,r),r=0):t===` `||t===` `||t===`
100
- `||t===`\r`?(s(),r=2):i+=t),r===3&&i===`!--`&&(r=4,o=o[0])}return s(),o}(e)),t),arguments,[])).length>1?t:t[0]}var sO=oO.bind(v.createElement),cO=class extends v.Component{state={err:null};static getDerivedStateFromError(e){return{err:String(e?.message||e)}}componentDidCatch(e){try{this.props.onError?.(String(e?.message||e))}catch{}}render(){return this.state.err?(0,K.jsxs)(`div`,{className:`p-3 text-[11px] leading-relaxed text-red-400`,children:[`面板运行错误:`,this.state.err,(0,K.jsx)(`br`,{}),`可在「定制工作台」中修正代码后重新发布。`]}):this.props.children}};function lO(e){return Function(`React`,`html`,`useState`,`useEffect`,`useRef`,`useMemo`,`"use strict";\n${e}\n;if (typeof Panel !== "function") throw new Error("插件代码必须定义 function Panel(props)");\nreturn Panel;`)(v,sO,v.useState,v.useEffect,v.useRef,v.useMemo)}function uO(e,t,n){if(e)try{fetch(`/api/panel-error`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({...e,kind:t,message:n})}).catch(()=>{})}catch{}}function dO({code:e,data:t,meta:n}){let r=n?.agentId,i=n?.panelId,a=n?.pluginId,o=(0,v.useMemo)(()=>{let t={agentId:r,panelId:i,pluginId:a};try{return lO(e)}catch(e){return uO(t,`compile`,String(e.message)),()=>(0,K.jsxs)(`div`,{className:`p-3 text-[11px] text-red-400`,children:[`编译失败:`,String(e.message)]})}},[e,r,i,a]);return(0,K.jsx)(cO,{onError:e=>uO(n,`runtime`,e),children:(0,K.jsx)(o,{...t})})}var fO=12;function pO({dsl:e,renderPanel:t,renderDialog:n,renderPlaceholder:r,edit:i,className:a}){let o=(0,v.useRef)(null),s=(0,v.useRef)(null),c=e.panels.reduce((e,t)=>Math.max(e,(t.grid?.y||1)+(t.grid?.h||1)-1),1),l=()=>{let e=o.current?.getBoundingClientRect();return{col:e?(e.width+fO)/12:100,row:e?(e.height+fO)/c:178}},u=(t,n,r)=>{if(!i||t.button!==0)return;t.stopPropagation();let a=e.panels[n].grid||{x:1,y:1,w:6,h:1};s.current={i:n,mode:r,sx:t.clientX,sy:t.clientY,g:{...a},moved:!1};try{t.currentTarget.setPointerCapture(t.pointerId)}catch{}},d=e=>{let t=s.current;if(!i||!t)return;let n=e.clientX-t.sx,r=e.clientY-t.sy;if(!t.moved&&Math.abs(n)<4&&Math.abs(r)<4)return;t.moved=!0;let{col:a,row:o}=l(),c=Math.round(n/a),u=Math.round(r/o);t.mode===`move`?i.onGrid(t.i,{x:Math.min(Math.max(1,t.g.x+c),12-t.g.w+1),y:Math.max(1,t.g.y+u)}):i.onGrid(t.i,{w:Math.min(Math.max(1,t.g.w+c),12-t.g.x+1),h:Math.min(Math.max(1,t.g.h+u),12)})},f=()=>{setTimeout(()=>{s.current=null},0)};return(0,K.jsx)(`div`,{ref:o,className:it(`grid gap-3`,i&&`touch-none select-none`,a),style:{gridTemplateColumns:`repeat(12, minmax(0, 1fr))`,gridTemplateRows:`repeat(${c}, minmax(120px, 1fr))`},onPointerDown:()=>{i&&i.onSelect(null)},children:e.panels.map((e,a)=>{let o=e.grid||{x:1,y:1,w:6,h:1},s=Math.round(o.w/12*100),c=e.type===`agent_dialog`?n?n(e):null:e.type===`placeholder`?r?r(e):null:t(e);return(0,K.jsxs)(`div`,{style:{gridColumn:`${o.x} / span ${o.w}`,gridRow:`${o.y} / span ${o.h}`},className:it(`relative flex min-h-0 flex-col overflow-hidden rounded-lg border bg-card`,i?i.sel===a?`border-primary ring-2 ring-primary/50`:`border-border hover:border-primary/50`:`border-border`,i&&`cursor-grab active:cursor-grabbing`),onPointerDown:e=>{i&&(e.stopPropagation(),i.onSelect(a),u(e,a,`move`))},onPointerMove:d,onPointerUp:f,onPointerCancel:f,children:[i&&(0,K.jsxs)(`div`,{className:`pointer-events-none absolute inset-x-0 top-0 z-10 flex items-center gap-1.5 border-b bg-background/85 px-2 py-1 text-[10px] backdrop-blur-sm`,children:[(0,K.jsx)(`span`,{className:`font-medium`,children:e.title}),(0,K.jsx)(J,{variant:`secondary`,className:`h-4 px-1 text-[9px]`,children:e.panel||e.type}),(0,K.jsxs)(`span`,{className:`ml-auto font-mono text-muted-foreground`,children:[s,`%宽·`,o.h,`行`]})]}),(0,K.jsx)(`div`,{className:it(`min-h-0 flex-1 overflow-auto`,i&&`pointer-events-none pt-4`),children:c}),i&&(0,K.jsx)(`span`,{onPointerDown:e=>u(e,a,`resize`),onPointerMove:d,onPointerUp:f,onPointerCancel:f,className:`absolute bottom-0 right-0 z-10 h-4 w-4 cursor-nwse-resize rounded-br-md border-b border-r border-primary/60 bg-primary/25 hover:bg-primary/50`,title:`拖拽调跨列/跨行(当前 ${s}% 宽)`,children:(0,K.jsx)(rg,{className:`h-2.5 w-2.5 translate-x-[3px] translate-y-[3px] text-primary`})})]},e.id)})})}function mO(){return(0,K.jsxs)(`div`,{className:`relative mb-1 h-4 select-none text-[9px] text-muted-foreground`,children:[(0,K.jsx)(`div`,{className:`grid h-full grid-cols-12`,children:[...Array(12)].map((e,t)=>(0,K.jsx)(`div`,{className:`border-l border-border/60 pl-0.5 pt-0.5 font-mono`,children:t+1},t))}),[25,50,75].map(e=>(0,K.jsxs)(`span`,{className:`absolute -top-0 font-mono`,style:{left:`${e}%`},children:[e,`%`]},e))]})}function hO({open:e,onOpenChange:t,onPick:n}){let[r,i]=(0,v.useState)(null),[a,o]=(0,v.useState)(!1),[s,c]=(0,v.useState)(``),l=e=>{o(!0),c(``),ot(`/api/fs/dirs${e?`?path=${encodeURIComponent(e)}`:``}`).then(e=>i(e)).catch(e=>c(String(e.message))).finally(()=>o(!1))};return(0,v.useEffect)(()=>{e&&!r&&l()},[e]),(0,K.jsx)(a_,{open:e,onOpenChange:t,children:(0,K.jsxs)(c_,{className:`max-w-md`,children:[(0,K.jsx)(l_,{children:(0,K.jsx)(d_,{children:`选择工作区目录`})}),(0,K.jsxs)(`div`,{className:`flex items-center gap-1.5`,children:[(0,K.jsxs)(Y,{size:`sm`,variant:`outline`,className:`h-7 gap-1 px-2 text-[11px]`,disabled:!r?.parent,onClick:()=>r?.parent&&l(r.parent),title:`上级目录`,children:[(0,K.jsx)(Zm,{className:`h-3 w-3`}),`上级`]}),(0,K.jsxs)(Y,{size:`sm`,variant:`outline`,className:`h-7 gap-1 px-2 text-[11px]`,onClick:()=>l(),children:[(0,K.jsx)(zh,{className:`h-3 w-3`}),`主目录`]}),(0,K.jsx)(`span`,{className:`min-w-0 flex-1 truncate rounded-md border bg-muted/40 px-2 py-1.5 font-mono text-[11px] text-muted-foreground`,title:r?.path,children:r?.path||`…`})]}),(0,K.jsxs)(eO,{className:`h-64 rounded-md border`,children:[a&&(0,K.jsxs)(`div`,{className:`flex h-full items-center justify-center gap-2 text-xs text-muted-foreground`,children:[(0,K.jsx)($h,{className:`h-4 w-4 animate-spin`}),`读取中…`]}),!a&&s&&(0,K.jsx)(`div`,{className:`p-3 text-xs text-red-400`,children:s}),!a&&!s&&r&&r.dirs.length===0&&(0,K.jsx)(`div`,{className:`p-3 text-xs text-muted-foreground`,children:`此目录下没有子目录——可直接点「选择当前目录」。`}),!a&&!s&&r&&r.dirs.map(e=>(0,K.jsxs)(`button`,{onClick:()=>l(`${r.path}/${e}`),className:`flex w-full items-center gap-2 px-3 py-1.5 text-left text-xs hover:bg-accent`,children:[(0,K.jsx)(Fh,{className:`h-3.5 w-3.5 shrink-0 text-muted-foreground`}),(0,K.jsx)(`span`,{className:`truncate`,children:e})]},e))]}),(0,K.jsxs)(u_,{children:[(0,K.jsx)(Y,{variant:`outline`,onClick:()=>t(!1),children:`取消`}),(0,K.jsxs)(Y,{className:`gap-1`,disabled:!r||a,onClick:()=>{r&&(n(r.path),t(!1))},children:[(0,K.jsx)(rh,{className:`h-3.5 w-3.5`}),`选择当前目录`]})]})]})})}function gO({agentId:e,onName:t,onEdit:n}){let[r,i]=(0,v.useState)(null),[a,o]=(0,v.useState)(null),[s,c]=(0,v.useState)(null),[l,u]=(0,v.useState)([]),[d,f]=(0,v.useState)(null),[p,m]=(0,v.useState)(2),[h,g]=(0,v.useState)(null),[_,y]=(0,v.useState)(!1),[b,x]=(0,v.useState)(``),[S,C]=(0,v.useState)(``),[w,T]=(0,v.useState)(!1),[E,D]=(0,v.useState)(!1),[O,k]=(0,v.useState)(null),[A,j]=(0,v.useState)(!1),M=(0,v.useMemo)(()=>h?.workspaces.find(e=>e.id===h.current)||null,[h]),N=M?.id||`default`,P=(0,v.useMemo)(()=>`chat-${e}-${N}`,[e,N]),F=()=>ot(`/api/state`).then(c).catch(()=>{}),I=()=>ot(`/api/workspaces?agent_id=${e}`).then(g).catch(()=>{});(0,v.useEffect)(()=>{ot(`/api/workbench?agent_id=${e}`).then(e=>{i(e.dsl),e.dsl&&t(e.dsl.workbench)}),ot(`/api/deployment?agent_id=${e}`).then(e=>{o(e.deployment),m({L0:0,L1:1,L2:2,L3:3}[e.deployment?.default_autonomy||`L2`]??2)}),ot(`/api/panels?with_code=1`).then(e=>u(e.plugins||[])),I(),F();let n=setInterval(F,5e3);return()=>clearInterval(n)},[e]);let L=async t=>{try{g(await st(`/api/workspaces/select`,{agent_id:e,ws_id:t}))}catch(e){Z.error(String(e.message))}},R=async()=>{D(!0);try{let t=await st(`/api/workspaces`,{agent_id:e,name:b||void 0,...S?{path:S}:{}});g(t),y(!1),x(``),C(``),Z.success(`工作区已创建${S?`(登记外部目录)`:``}`),await L(t.workspaces[t.workspaces.length-1].id)}catch(e){Z.error(String(e.message))}finally{D(!1)}},ee=async()=>{if(O)try{g(await lt(`/api/workspaces/${O.id}?agent_id=${e}`,{purge:A})),Z.success(`工作区已删除${A?`(目录已清除)`:`(仅移除登记)`}`),k(null),j(!1)}catch(e){Z.error(String(e.message))}},te=(0,v.useMemo)(()=>r?.panels||[],[r]).filter(e=>e.type===`custom`||e.type===`custom_panel`).map(e=>({panel:e,code:e.type===`custom`?e.code||``:l.find(t=>t.id===e.panel)?.code||``})).filter(e=>e.code),z=t=>({devices:s?.devices||[],alarms:s?.alarms||[],kpi:s?.kpi||{},work_orders:s?.work_orders||[],inspections:s?.inspections||{},selected:d,onSelect:f,agentId:e,store:mt(e,N),runAction:(n,r)=>ht(e,String(t?.id||``),n,r),params:{...t?.params||{},agentId:e,wsId:N}});return!r||!s?(0,K.jsx)(`div`,{className:`flex h-full items-center justify-center text-sm text-muted-foreground`,children:`工作台加载中…`}):(0,K.jsxs)(`div`,{className:`flex h-full flex-col gap-2 overflow-hidden px-4 py-2.5`,children:[(0,K.jsx)(`h1`,{className:`sr-only`,children:r.workbench}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2 text-[11px]`,children:[(0,K.jsx)(J,{variant:`secondary`,className:`h-5 shrink-0 text-[10px]`,children:r.version}),te.length>0&&(0,K.jsxs)(J,{variant:`outline`,className:`h-5 shrink-0 text-[10px] text-violet-400 border-violet-500/40`,children:[(0,K.jsx)(pg,{className:`mr-0.5 h-2.5 w-2.5`}),`插件 ×`,te.length]}),(0,K.jsxs)(`span`,{className:`shrink-0 text-muted-foreground`,children:[a?.name,` · 工具 `,a?.toolset.length,` 个`]}),M&&(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(jh,{className:`h-3 w-3 shrink-0 text-muted-foreground`}),(0,K.jsx)(`span`,{className:`min-w-0 flex-1 truncate font-mono text-muted-foreground`,title:M.path,children:M.path}),(0,K.jsx)(`span`,{className:`shrink-0 text-[10px] text-muted-foreground`,children:`(exec 工作目录 · 数据与文件随工作区隔离)`})]}),(0,K.jsxs)(`div`,{className:`ml-auto flex items-center gap-1.5`,children:[(0,K.jsx)(qh,{className:`h-3.5 w-3.5 text-muted-foreground`}),(0,K.jsxs)(h_,{value:N,onValueChange:L,children:[(0,K.jsx)(__,{className:`h-8 w-52 text-xs`,title:M?.path,children:(0,K.jsx)(g_,{children:(0,K.jsx)(`span`,{className:`truncate`,children:M?`${M.name}${M.external?`(外部)`:``}`:`默认工作区`})})}),(0,K.jsx)(v_,{children:(h?.workspaces||[]).map(e=>(0,K.jsx)(y_,{value:e.id,className:`text-xs`,children:(0,K.jsxs)(`span`,{className:`max-w-64 truncate`,title:e.path,children:[e.name,e.external?` · 外部目录`:``,e.id===h?.current?` ✓`:``]})},e.id))})]}),(0,K.jsxs)(Y,{size:`sm`,variant:`outline`,className:`h-8 gap-1 text-xs`,onClick:()=>y(!0),title:`新建工作区(默认目录或自定义路径)`,children:[(0,K.jsx)(Nh,{className:`h-3.5 w-3.5`}),`新建`]}),M&&M.id!=="default"&&(0,K.jsx)(Y,{size:`sm`,variant:`ghost`,className:`h-8 w-8 p-0 text-muted-foreground`,onClick:()=>k(M),title:`删除当前工作区`,children:(0,K.jsx)(qg,{className:`h-3.5 w-3.5`})}),(0,K.jsxs)(Y,{size:`sm`,variant:`outline`,className:`h-8 gap-1 text-xs`,onClick:n,children:[(0,K.jsx)(Dg,{className:`h-3.5 w-3.5`}),`编辑布局`]})]})]}),(0,K.jsx)(`div`,{className:`relative min-h-0 flex-1`,children:(0,K.jsx)(pO,{className:`absolute inset-0 overflow-auto p-0.5`,dsl:r,renderPanel:t=>{let n=te.find(e=>e.panel.id===t.id);return n?(0,K.jsx)(dO,{code:n.code,data:z(t),meta:{agentId:e,panelId:t.id,pluginId:t.panel}},`${t.id}:${N}`):null},renderDialog:()=>(0,K.jsx)(rO,{agentId:e,sessionId:P,wsId:N,injectedDevice:d,autonomy:p,onAutonomy:m},`${e}:${N}`),renderPlaceholder:()=>(0,K.jsx)(`div`,{className:`flex h-full items-center justify-center p-4 text-center text-[11px] text-muted-foreground`,children:`空区块——到「编辑布局」添加插件或让 AI 定制`})})}),(0,K.jsx)(a_,{open:_,onOpenChange:y,children:(0,K.jsxs)(c_,{children:[(0,K.jsx)(l_,{children:(0,K.jsx)(d_,{children:`新建工作区`})}),(0,K.jsxs)(`div`,{className:`space-y-3`,children:[(0,K.jsxs)(`div`,{className:`space-y-1`,children:[(0,K.jsx)(m_,{className:`text-xs`,children:`名称`}),(0,K.jsx)(p_,{value:b,onChange:e=>x(e.target.value),placeholder:`如:产线B改造`,className:`text-xs`})]}),(0,K.jsxs)(`div`,{className:`space-y-1`,children:[(0,K.jsx)(m_,{className:`text-xs`,children:`自定义目录(可选,留空则在平台 workspace 目录下动态新增)`}),(0,K.jsxs)(`div`,{className:`flex gap-1.5`,children:[(0,K.jsx)(p_,{value:S,onChange:e=>C(e.target.value),placeholder:`/Users/you/projects/line-b 或点浏览选择`,className:`font-mono text-xs`}),(0,K.jsxs)(Y,{size:`sm`,variant:`outline`,className:`h-8 shrink-0 gap-1 text-xs`,onClick:()=>T(!0),children:[(0,K.jsx)(jh,{className:`h-3.5 w-3.5`}),`浏览…`]})]}),(0,K.jsx)(`p`,{className:`text-[10px] text-amber-400`,children:`⚠ 助手将能读写该目录(exec 工作目录即此处);目录须已存在,平台不会在其中写入数据库文件。`})]})]}),(0,K.jsxs)(u_,{children:[(0,K.jsx)(Y,{variant:`outline`,disabled:E,onClick:()=>y(!1),children:`取消`}),(0,K.jsx)(Y,{disabled:E,onClick:R,children:E?`创建中…`:`创建并切换`})]}),(0,K.jsx)(hO,{open:w,onOpenChange:T,onPick:e=>C(e)})]})}),(0,K.jsx)(a_,{open:!!O,onOpenChange:e=>{e||(k(null),j(!1))},children:(0,K.jsxs)(c_,{children:[(0,K.jsx)(l_,{children:(0,K.jsxs)(d_,{children:[`删除工作区 · `,O?.name]})}),(0,K.jsxs)(`div`,{className:`space-y-2 text-xs`,children:[(0,K.jsx)(`p`,{className:`font-mono text-[11px] text-muted-foreground`,children:O?.path}),O?.external?(0,K.jsxs)(`p`,{children:[`外部目录工作区:仅移除登记,`,(0,K.jsx)(`b`,{children:`不删除`}),`你的文件;该工作区的数据集库将一并删除。`]}):(0,K.jsxs)(`label`,{className:`flex items-start gap-2 rounded-md border border-red-500/30 bg-red-500/5 p-2.5`,children:[(0,K.jsx)(i_,{checked:A,onCheckedChange:e=>j(!!e)}),(0,K.jsx)(`span`,{children:`同时删除平台目录下的工作区文件夹(数据集库始终删除)`})]})]}),(0,K.jsxs)(u_,{children:[(0,K.jsx)(Y,{variant:`outline`,onClick:()=>k(null),children:`取消`}),(0,K.jsx)(Y,{variant:`destructive`,onClick:ee,children:`确认删除`})]})]})})]})}function _O({className:e,orientation:t=`horizontal`,decorative:n=!0,...r}){return(0,K.jsx)(Fp,{"data-slot":`separator`,decorative:n,orientation:t,className:mn(`shrink-0 bg-border data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-px`,e),...r})}function vO({className:e,orientation:t=`horizontal`,...n}){return(0,K.jsx)(lm,{"data-slot":`tabs`,"data-orientation":t,orientation:t,className:mn(`group/tabs flex gap-2 data-[orientation=horizontal]:flex-col`,e),...n})}var yO=yt(`group/tabs-list inline-flex w-fit items-center justify-center rounded-lg p-[3px] text-muted-foreground group-data-[orientation=horizontal]/tabs:h-9 group-data-[orientation=vertical]/tabs:h-fit group-data-[orientation=vertical]/tabs:flex-col data-[variant=line]:rounded-none`,{variants:{variant:{default:`bg-muted`,line:`gap-1 bg-transparent`}},defaultVariants:{variant:`default`}});function bO({className:e,variant:t=`default`,...n}){return(0,K.jsx)(dm,{"data-slot":`tabs-list`,"data-variant":t,className:mn(yO({variant:t}),e),...n})}function xO({className:e,...t}){return(0,K.jsx)(pm,{"data-slot":`tabs-trigger`,className:mn(`relative inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-2 py-1 text-sm font-medium whitespace-nowrap text-foreground/60 transition-all group-data-[orientation=vertical]/tabs:w-full group-data-[orientation=vertical]/tabs:justify-start hover:text-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 focus-visible:outline-1 focus-visible:outline-ring disabled:pointer-events-none disabled:opacity-50 group-data-[variant=default]/tabs-list:data-[state=active]:shadow-sm group-data-[variant=line]/tabs-list:data-[state=active]:shadow-none dark:text-muted-foreground dark:hover:text-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4`,`group-data-[variant=line]/tabs-list:bg-transparent group-data-[variant=line]/tabs-list:data-[state=active]:bg-transparent dark:group-data-[variant=line]/tabs-list:data-[state=active]:border-transparent dark:group-data-[variant=line]/tabs-list:data-[state=active]:bg-transparent`,`data-[state=active]:bg-background data-[state=active]:text-foreground dark:data-[state=active]:border-input dark:data-[state=active]:bg-input/30 dark:data-[state=active]:text-foreground`,`after:absolute after:bg-foreground after:opacity-0 after:transition-opacity group-data-[orientation=horizontal]/tabs:after:inset-x-0 group-data-[orientation=horizontal]/tabs:after:bottom-[-5px] group-data-[orientation=horizontal]/tabs:after:h-0.5 group-data-[orientation=vertical]/tabs:after:inset-y-0 group-data-[orientation=vertical]/tabs:after:-right-1 group-data-[orientation=vertical]/tabs:after:w-0.5 group-data-[variant=line]/tabs-list:data-[state=active]:after:opacity-100`,e),...t})}function SO({className:e,...t}){return(0,K.jsx)(hm,{"data-slot":`tabs-content`,className:mn(`flex-1 outline-none`,e),...t})}function CO({...e}){return(0,K.jsx)(gd,{"data-slot":`dropdown-menu`,...e})}function wO({...e}){return(0,K.jsx)(vd,{"data-slot":`dropdown-menu-trigger`,...e})}function TO({className:e,sideOffset:t=4,...n}){return(0,K.jsx)(yd,{children:(0,K.jsx)(xd,{"data-slot":`dropdown-menu-content`,sideOffset:t,className:mn(`z-50 min-w-36 overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95`,e),...n})})}function EO({className:e,...t}){return(0,K.jsx)(Sd,{"data-slot":`dropdown-menu-item`,className:mn(`relative flex cursor-pointer select-none items-center gap-2 rounded-sm px-2 py-1.5 text-xs outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:h-3.5 [&_svg]:w-3.5 [&_svg]:shrink-0`,e),...t})}function DO({className:e,...t}){return(0,K.jsx)(Cd,{"data-slot":`dropdown-menu-separator`,className:mn(`-mx-1 my-1 h-px bg-border`,e),...t})}async function OO(e,t){let n=e.usage.length?`插件「${e.name}」被 ${e.usage.length} 处引用,删除将从这些工作台摘除该面板。确认删除?`:`删除插件「${e.name}」?`;if(window.confirm(n))try{await lt(`/api/panels`,{id:e.id,force:!0}),Z.success(`已删除`),t()}catch(e){Z.error(String(e.message))}}function kO({target:e,onClose:t,agents:n}){let[r,i]=(0,v.useState)(null),[a,o]=(0,v.useState)(``),[s,c]=(0,v.useState)(!0),[l,u]=(0,v.useState)(!1);(0,v.useEffect)(()=>{if(!e){i(null);return}let n=e.type===`panel`?`id=${encodeURIComponent(e.id||``)}`:`agentId=${encodeURIComponent(e.agentId||``)}`;ot(`/api/assets/preview?type=${e.type}&${n}`).then(e=>{i(e),o(e.name)}).catch(e=>{Z.error(String(e.message)),t()})},[e]);let d=async()=>{if(e){u(!0);try{let n=await st(`/api/assets/share`,{type:e.type,id:e.id,agentId:e.agentId,name:a,bind_agent:s&&e.agentId?e.agentId:void 0}),i=r?.manifest.requires.apis.length||0,o=r?.manifest.requires.actions.length||0;Z.success(`已发布 ${n.name}@${n.version}${n.bound?`,已绑定到助手`:``}`,{description:`外部 API ×${i} · 交互脚本 ×${o}${o?`(命令全文已在 ARM 资产包 SKILL.md 留档)`:``}`}),t()}catch(e){Z.error(String(e.message))}finally{u(!1)}}};if(!e)return null;let f=r?.manifest.requires;return(0,K.jsx)(a_,{open:!!e,onOpenChange:e=>{!e&&!l&&t()},children:(0,K.jsxs)(c_,{children:[(0,K.jsx)(l_,{children:(0,K.jsxs)(d_,{className:`flex items-center gap-2`,children:[(0,K.jsx)(_h,{className:`h-4 w-4 text-primary`}),`发布为 UI 资产 · `,e.title]})}),(0,K.jsx)(eO,{className:`max-h-96`,children:(0,K.jsxs)(`div`,{className:`space-y-3 pr-2 text-xs`,children:[(0,K.jsxs)(`div`,{className:`space-y-1`,children:[(0,K.jsx)(m_,{className:`text-xs`,children:`资产名(全局唯一锚,同名发布追加新版本)`}),(0,K.jsx)(p_,{value:a,onChange:e=>o(e.target.value),className:`font-mono text-xs`})]}),r&&(0,K.jsxs)(K.Fragment,{children:[(0,K.jsxs)(`div`,{className:`rounded-md border bg-muted/30 p-2.5`,children:[(0,K.jsx)(`div`,{className:`font-medium`,children:`包含内容`}),(0,K.jsxs)(`div`,{className:`mt-1 text-muted-foreground`,children:[`面板插件:`,r.manifest.provides.panels.join(`、`)||`无`,(0,K.jsx)(`br`,{}),`数据集 schema:`,r.manifest.provides.collections.join(`、`)||`无`,`(仅建表定义,不含数据)`,r.manifest.provides.workbench&&(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(`br`,{}),`工作台 DSL:workbench.json`]})]}),(0,K.jsx)(`div`,{className:`mt-1 font-mono text-[10px] text-muted-foreground`,children:r.files.join(` · `)})]}),!!f?.apis.length&&(0,K.jsxs)(`div`,{className:`rounded-md border border-blue-500/30 bg-blue-500/5 p-2.5`,children:[(0,K.jsx)(`div`,{className:`font-medium text-blue-300`,children:`外部 API 依赖(安装后环境需可达)`}),(0,K.jsx)(`ul`,{className:`mt-1 list-disc pl-4 text-muted-foreground`,children:f.apis.map(e=>(0,K.jsxs)(`li`,{children:[(0,K.jsx)(`span`,{className:`font-mono`,children:e.host}),`:`,e.usage]},e.host))})]}),!!f?.actions.length&&(0,K.jsxs)(`div`,{className:`rounded-md border border-amber-500/30 bg-amber-500/5 p-2.5`,children:[(0,K.jsx)(`div`,{className:`font-medium text-amber-300`,children:`交互脚本(真实 shell 命令,随包公开)`}),(0,K.jsx)(`ul`,{className:`mt-1 space-y-1`,children:f.actions.map(e=>(0,K.jsxs)(`li`,{className:`text-muted-foreground`,children:[`[`,e.panel,`/`,e.id,`] `,e.label,e.has_credentials&&(0,K.jsx)(J,{className:`ml-1 h-4 bg-amber-500/15 px-1 text-[9px] text-amber-300`,children:`⚠️ 疑似含凭据`}),(0,K.jsx)(`div`,{className:`mt-0.5 break-all rounded bg-muted/50 p-1 font-mono text-[10px]`,children:e.exec})]},`${e.panel}/${e.id}`))}),(0,K.jsx)(`p`,{className:`mt-1.5 text-[10px] text-amber-400`,children:`命令明文将进入资产包——含密码/令牌的命令请先改用环境变量或凭据占位,再发布。`})]}),e.agentId&&n&&n.length>0&&(0,K.jsxs)(`label`,{className:`flex items-center gap-2 rounded-md border p-2.5`,children:[(0,K.jsx)(i_,{checked:s,onCheckedChange:e=>c(!!e)}),(0,K.jsx)(`span`,{children:`发布后同时绑定到当前助手(下载该助手的其他现场将自动物化此工作台)`})]})]})]})}),(0,K.jsxs)(u_,{children:[(0,K.jsx)(Y,{variant:`outline`,disabled:l,onClick:t,children:`取消`}),(0,K.jsx)(Y,{disabled:l||!a,onClick:d,children:l?`发布中…`:`发布到 ARM`})]})]})})}function AO({open:e,onClose:t,onInstalled:n,agents:r}){let[i,a]=(0,v.useState)(``),[o,s]=(0,v.useState)([]),[c,l]=(0,v.useState)(!1),[u,d]=(0,v.useState)(null),[f,p]=(0,v.useState)(``),m=(0,v.useRef)(0);(0,v.useEffect)(()=>{if(!e)return;let t=setTimeout(()=>{let e=++m.current;l(!0),ot(`/api/assets/arm-library${i?`?keyword=${encodeURIComponent(i)}`:``}`).then(t=>{e===m.current&&s(t.items||[])}).catch(e=>Z.error(String(e.message))).finally(()=>{e===m.current&&l(!1)})},400);return()=>clearTimeout(t)},[i,e]),(0,v.useEffect)(()=>{e&&!f&&r.length&&p(r[0].agent_id)},[e,r]);let h=async e=>{if(e.asset_type===`workbench`&&!f)Z.warning(`请先选择目标助手`);else{d(e.name);try{let r=await st(`/api/assets/install`,{name:e.name,agentId:e.asset_type===`workbench`?f:void 0}),i=r.workbench?`,工作台已导入为草稿(审阅后在「定制工作台」发布)`:``,a=r.skipped_collections.length?`;同名数据集保留本地:${r.skipped_collections.join(`、`)}`:``;Z.success(`已安装 ${e.name}:面板 ×${r.panels.length}${i}${a}`),n(),t()}catch(e){Z.error(String(e.message))}finally{d(null)}}};return(0,K.jsx)(a_,{open:e,onOpenChange:e=>{!e&&!u&&t()},children:(0,K.jsxs)(c_,{children:[(0,K.jsx)(l_,{children:(0,K.jsxs)(d_,{className:`flex items-center gap-2`,children:[(0,K.jsx)(Yh,{className:`h-4 w-4 text-primary`}),`从 ARM 安装 UI 资产`]})}),(0,K.jsxs)(`div`,{className:`relative`,children:[(0,K.jsx)(xg,{className:`absolute left-3 top-2.5 h-3.5 w-3.5 text-muted-foreground`}),(0,K.jsx)(p_,{placeholder:`搜索资产名 / 描述…`,value:i,onChange:e=>a(e.target.value),className:`pl-9`,autoFocus:!0})]}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2 text-xs text-muted-foreground`,children:[(0,K.jsx)(`span`,{className:`shrink-0`,children:`工作台资产安装到:`}),(0,K.jsx)(`select`,{value:f,onChange:e=>p(e.target.value),className:`h-8 flex-1 rounded-md border bg-background px-2 text-xs`,children:r.map(e=>(0,K.jsx)(`option`,{value:e.agent_id,children:e.name},e.agent_id))})]}),(0,K.jsx)(eO,{className:`max-h-80`,children:(0,K.jsxs)(`div`,{className:`space-y-1.5 pr-2`,children:[c&&!o.length&&(0,K.jsx)(`div`,{className:`py-6 text-center text-xs text-muted-foreground`,children:`加载中…`}),!c&&!o.length&&(0,K.jsx)(`div`,{className:`py-6 text-center text-xs text-muted-foreground`,children:i?`没有匹配资产`:`ARM 上暂无 UI 资产`}),o.map(e=>(0,K.jsxs)(`div`,{className:`flex items-center gap-2.5 rounded-md border p-2.5`,children:[e.asset_type===`workbench`?(0,K.jsx)(Yh,{className:`h-4 w-4 shrink-0 text-violet-400`}):(0,K.jsx)(pg,{className:`h-4 w-4 shrink-0 text-primary`}),(0,K.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-1.5 text-xs font-medium`,children:[(0,K.jsx)(`span`,{className:`truncate font-mono`,children:e.name}),e.latest_version&&(0,K.jsx)(J,{variant:`secondary`,className:`h-4 px-1 text-[9px]`,children:e.latest_version}),e.installed&&(0,K.jsx)(J,{className:`h-4 bg-emerald-500/15 px-1 text-[9px] text-emerald-400`,children:`本地已有`}),e.upgrade_available&&(0,K.jsx)(J,{className:`h-4 bg-amber-500/15 px-1 text-[9px] text-amber-300`,children:`⤴ 可升级`})]}),(0,K.jsxs)(`div`,{className:`truncate text-[10px] text-muted-foreground`,children:[e.description||`—`,` · 下载 `,e.download_count,` 次 · `,e.publisher]})]}),(0,K.jsx)(Y,{size:`sm`,variant:`secondary`,className:`h-7 text-[11px]`,disabled:u!==null,onClick:()=>h(e),children:u===e.name?`安装中…`:`安装`})]},e.name))]})}),(0,K.jsx)(u_,{children:(0,K.jsx)(Y,{variant:`outline`,onClick:t,children:`关闭`})})]})})}function jO(){let[e,t]=(0,v.useState)(null),[n,r]=(0,v.useState)(null),[i,a]=(0,v.useState)(!1),[o,s]=(0,v.useState)([]),c=()=>ot(`/api/plugins/center`).then(t);if((0,v.useEffect)(()=>{c(),ot(`/api/agents`).then(e=>s((e.agents||[]).filter(e=>e.installed).map(({agent_id:e,name:t})=>({agent_id:e,name:t})))).catch(()=>{})},[]),!e)return(0,K.jsx)(`div`,{className:`flex h-full items-center justify-center text-sm text-muted-foreground`,children:`插件中心加载中…`});let l=async(e,t,n)=>{let r=n===`deprecated`?`active`:`deprecated`;try{await st(`/api/plugins/lifecycle`,{kind:e,id:t,status:r}),Z.success(r===`deprecated`?`已停用(存量引用仍可渲染,新增被阻止)`:`已恢复`),c()}catch(e){Z.error(String(e.message))}},u=({icon:e,name:t,sub:n,status:r,usage:i,onToggle:a,tag:o,onDelete:s,onShare:c,armRef:l})=>(0,K.jsxs)(`div`,{className:`flex items-center gap-2.5 rounded-md border p-2.5`,children:[(0,K.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-1.5 text-xs font-medium`,children:[e,t,(0,K.jsx)(J,{variant:`secondary`,className:`h-4 px-1 text-[9px]`,children:o}),(0,K.jsx)(J,{className:`h-4 px-1 text-[9px] ${r===`deprecated`?`bg-red-500/15 text-red-400 hover:bg-red-500/25`:`bg-emerald-500/15 text-emerald-400 hover:bg-emerald-500/25`}`,children:r===`deprecated`?`已停用`:`在用`}),l&&(0,K.jsxs)(J,{className:`h-4 bg-violet-500/15 px-1 text-[9px] text-violet-300`,title:`ARM ${l.skill_name}@${l.version||``}`,children:[`已发布`,l.version?` ${l.version}`:``]})]}),(0,K.jsx)(`div`,{className:`truncate text-[10px] text-muted-foreground`,children:n}),(0,K.jsxs)(`div`,{className:`mt-0.5 text-[10px] text-muted-foreground`,children:[`引用:`,i.length?i.map(e=>`${e.agent}${e.draft?`*`:``}`).join(`、`):`无`]})]}),c&&(0,K.jsxs)(Y,{size:`sm`,variant:`ghost`,className:`h-7 text-[11px] text-violet-400`,onClick:c,title:`发布到 ARM UI 资产市场`,children:[(0,K.jsx)(_h,{className:`h-3 w-3`}),l?`更新`:`发布`]}),s&&(0,K.jsx)(Y,{size:`sm`,variant:`ghost`,className:`h-7 text-[11px] text-red-400`,onClick:s,children:`删除`}),(0,K.jsx)(Y,{size:`sm`,variant:r===`deprecated`?`secondary`:`ghost`,className:`h-7 text-[11px] ${r===`deprecated`?``:`text-red-400`}`,onClick:a,children:r===`deprecated`?`恢复`:`停用`})]});return(0,K.jsxs)(`div`,{className:`h-full overflow-auto p-5`,children:[(0,K.jsxs)(`div`,{className:`mb-4`,children:[(0,K.jsxs)(`h1`,{className:`flex items-center gap-2 text-lg font-bold`,children:[(0,K.jsx)(pg,{className:`h-5 w-5 text-primary`}),`插件中心`]}),(0,K.jsxs)(`p`,{className:`mt-0.5 text-xs text-muted-foreground`,children:[`统一注册表:系统面板与契约插件同源治理 · 生命周期(在用/停用)· 引用追踪(* 为草稿引用)· `,(0,K.jsx)(`span`,{className:`text-violet-400`,children:`发布/安装 ARM UI 资产(三资产模型)`})]})]}),(0,K.jsxs)(`div`,{className:`grid grid-cols-2 gap-4`,children:[(0,K.jsxs)(bm,{className:`py-0`,children:[(0,K.jsx)(xm,{className:`border-b py-2.5`,children:(0,K.jsxs)(Sm,{className:`flex items-center gap-1.5 text-xs`,children:[(0,K.jsx)(Dh,{className:`h-3.5 w-3.5`}),`系统插件(平台预装)`]})}),(0,K.jsx)(Cm,{className:`p-3`,children:(0,K.jsx)(`div`,{className:`space-y-1.5`,children:e.system.map(e=>(0,K.jsx)(u,{icon:(0,K.jsx)(`span`,{className:`font-mono text-[10px] text-muted-foreground`,children:e.id}),name:e.name,sub:e.note,status:e.status,usage:e.usage,tag:`system`,onToggle:()=>l(`system`,e.id,e.status)},e.id))})})]}),(0,K.jsxs)(bm,{className:`py-0`,children:[(0,K.jsx)(xm,{className:`border-b py-2.5`,children:(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(Sm,{className:`flex items-center gap-1.5 text-xs`,children:[(0,K.jsx)(th,{className:`h-3.5 w-3.5`}),`插件库(AI 开发 / 人工沉淀)`]}),(0,K.jsxs)(Y,{size:`sm`,variant:`outline`,className:`h-7 gap-1 text-[11px]`,onClick:()=>a(!0),children:[(0,K.jsx)(Yh,{className:`h-3 w-3`}),`从 ARM 安装`]})]})}),(0,K.jsx)(Cm,{className:`p-3`,children:(0,K.jsxs)(`div`,{className:`space-y-1.5`,children:[e.library.map(e=>(0,K.jsx)(u,{icon:(0,K.jsx)(pg,{className:`h-3 w-3 text-primary`}),name:`${e.name} ${e.version}`,sub:`${e.author===`ai`?`AI 开发`:e.author===`arm`?`ARM 安装`:`人工`} · ${e.description||e.id}`,status:e.status,usage:e.usage,tag:e.author===`ai`?`ai`:e.author===`arm`?`arm`:`human`,onToggle:()=>l(`plugin`,e.id,e.status),onDelete:()=>OO(e,c),onShare:()=>r({type:`panel`,id:e.id,title:e.name}),armRef:e.arm_ref},e.id)),e.library.length===0&&(0,K.jsx)(`div`,{className:`py-6 text-center text-xs text-muted-foreground`,children:`插件库为空`})]})})]})]}),(0,K.jsx)(_O,{className:`my-4`}),(0,K.jsxs)(bm,{className:`py-0`,children:[(0,K.jsx)(xm,{className:`border-b py-2.5`,children:(0,K.jsxs)(Sm,{className:`flex items-center gap-1.5 text-xs`,children:[(0,K.jsx)(Ng,{className:`h-3.5 w-3.5`}),`治理策略`]})}),(0,K.jsx)(Cm,{className:`p-3 text-[11px] leading-relaxed text-muted-foreground`,children:(0,K.jsx)(eO,{className:`max-h-40`,children:(0,K.jsxs)(`ul`,{className:`list-disc space-y-1 pl-4`,children:[(0,K.jsx)(`li`,{children:`一切面板进同一注册表:系统插件也有 manifest 与生命周期,不再是编译进前端的二等公民`}),(0,K.jsx)(`li`,{children:`停用(deprecate)不破坏存量:已引用的工作台继续渲染,但编辑器「添加面板」不再出现——安全下线`}),(0,K.jsx)(`li`,{children:`入库强制过校验器(check-panel.mjs):编译/契约/沙箱/模板四关 + 质量警告入审计——ARM 安装的插件同样过检`}),(0,K.jsx)(`li`,{children:`出网最小化:/api/proxy 仅放行插件代码中声明过的主机(防止面板成为任意内网跳板)`}),(0,K.jsx)(`li`,{children:`版本化与回滚:插件独立版本(同 id 覆盖自增),工作台按 id 引用,升级即时生效可回滚`}),(0,K.jsx)(`li`,{children:`数据隔离:插件数据集按助手分库(store-助手ID.db),共享需显式 scope=shared;资产包只带 schema 不带数据`}),(0,K.jsx)(`li`,{children:`UI 资产四红线(docs/08):包非运行时 · 数据必走 collection · 外部依赖必声明 · 单向 DAG`})]})})})]}),(0,K.jsx)(kO,{target:n,onClose:()=>{r(null),c()},agents:o}),(0,K.jsx)(AO,{open:i,onClose:()=>a(!1),onInstalled:c,agents:o})]})}function MO({pluginId:e,onRollback:t}){let[n,r]=(0,v.useState)(null);return(0,v.useEffect)(()=>{e&&ot(`/api/panels?id=${e}`).then(e=>r(e.plugin)).catch(()=>r(null))},[e]),n?(0,K.jsxs)(`div`,{className:`space-y-1`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-1.5 text-[11px]`,children:[(0,K.jsx)(`span`,{className:`font-mono`,children:n.version}),(0,K.jsx)(`span`,{className:`text-muted-foreground`,children:`(当前)`})]}),(n.history||[]).slice().reverse().map(n=>(0,K.jsxs)(`div`,{className:`flex items-center gap-2 text-[11px]`,children:[(0,K.jsx)(`span`,{className:`font-mono`,children:n.version}),(0,K.jsx)(`span`,{className:`text-[10px] text-muted-foreground`,children:gt(n.at,`dts`)}),(0,K.jsx)(Y,{size:`sm`,variant:`ghost`,className:`ml-auto h-6 text-[10px]`,onClick:()=>t(e,n.version),children:`回退`})]},n.version)),!(n.history||[]).length&&(0,K.jsx)(`div`,{className:`text-[10px] text-muted-foreground`,children:`无历史版本`})]}):(0,K.jsx)(`div`,{className:`text-[10px] text-muted-foreground`,children:`(插件信息加载中…)`})}var NO=e=>({x:1,y:e.reduce((e,t)=>Math.max(e,t.grid?t.grid.y+t.grid.h-1:0),0)+1,w:6,h:1});function PO({agentId:e}){let[t,n]=(0,v.useState)(null),[r,i]=(0,v.useState)(!1),[a,o]=(0,v.useState)([]),[s,c]=(0,v.useState)(``),[l,u]=(0,v.useState)(!1),[d,f]=(0,v.useState)([]),[p,m]=(0,v.useState)(!1),[h,g]=(0,v.useState)(null),[_,y]=(0,v.useState)(null),[b,x]=(0,v.useState)(!1),[S,C]=(0,v.useState)(0),[w,T]=(0,v.useState)(null),[E,D]=(0,v.useState)([]),[O,k]=(0,v.useState)(null),A=(0,v.useRef)(`dev-${e.slice(0,8)}`).current,j=(0,v.useRef)(null),[M,N]=(0,v.useState)([]),[P,F]=(0,v.useState)(``),[I,L]=(0,v.useState)(!1),[R,ee]=(0,v.useState)(``),[te,z]=(0,v.useState)(null),[ne,re]=(0,v.useState)(!1),[ie,ae]=(0,v.useState)(null),oe=(0,v.useRef)(null),se=(0,v.useRef)(!0),ce=(0,v.useCallback)(()=>{let e=oe.current?.closest(`[data-slot="scroll-area-viewport"]`);e&&(e.scrollTop=e.scrollHeight)},[]);(0,v.useEffect)(()=>{let e=oe.current?.closest(`[data-slot="scroll-area-viewport"]`);if(!e)return;let t=()=>{se.current=e.scrollHeight-e.scrollTop-e.clientHeight<80};return e.addEventListener(`scroll`,t),()=>e.removeEventListener(`scroll`,t)},[]),(0,v.useEffect)(()=>{se.current&&ce()},[M,I,R,ce]);let le=()=>{ot(`/api/workbench?agent_id=${e}&draft=1`).then(e=>{n(e.dsl),i(e.isDraft),o(e.versions||[]),c(JSON.stringify(e.dsl,null,2))}),ot(`/api/panels`).then(e=>f(e.plugins||[]))};if((0,v.useEffect)(()=>{le()},[e]),(0,v.useEffect)(()=>{let e=()=>ot(`/api/state`).then(T).catch(()=>{});e();let t=setInterval(e,5e3);return ot(`/api/panels?with_code=1`).then(e=>D(e.plugins||[])),()=>clearInterval(t)},[]),!t)return(0,K.jsx)(`div`,{className:`flex h-full items-center justify-center text-sm text-muted-foreground`,children:`加载工作台 DSL…`});let B=t.panels,V=_===null?null:B[_],H=e=>{let r=JSON.parse(JSON.stringify(t));e(r),n(r),c(JSON.stringify(r,null,2)),i(!0)},ue=(e,t)=>H(n=>{let r=n.panels[e].grid||{x:1,y:1,w:6,h:1};n.panels[e].grid={...r,...t}}),de=t=>({devices:w?.devices||[],alarms:w?.alarms||[],kpi:w?.kpi||{},work_orders:w?.work_orders||[],inspections:w?.inspections||{},selected:O,onSelect:k,agentId:e,store:mt(e),runAction:(n,r)=>ht(e,String(t.id),n,r),params:{...t.params||{},agentId:e,wsId:`default`}}),fe=e=>e.type===`custom`?e.code:E.find(t=>t.id===e.panel)?.code||``,pe=()=>H(e=>e.panels.push({id:`block_${Math.random().toString(36).slice(2,6)}`,type:`placeholder`,title:`空区块`,grid:NO(e.panels)})),me=(e,t)=>{H(n=>{if(e!==null&&e<n.panels.length){let r=n.panels[e];Object.assign(r,{type:`custom_panel`,panel:t.id,title:r.title===`空区块`?t.name:r.title})}else n.panels.push({id:`plug_${t.id}_${Math.random().toString(36).slice(2,5)}`,type:`custom_panel`,title:t.name,panel:t.id,grid:NO(n.panels)})}),m(!1),g(null),Z.success(`已插入「${t.name}」(草稿,待发布)`)},he=async e=>{let t=B[e];z(e);let n=``;try{let e=t.panel||t.id,r=await ot(`/api/panel-errors?key=${encodeURIComponent(e)}`);n=r.errors?.length?r.errors.map(e=>`[${e.kind}] ${e.message}`).join(` | `):``}catch{}F(`请调试该插件:${n?`最近运行错误:${n}。`:`暂无上报错误,请先 read_panel_plugin 审代码,重点检查结果处理与错误路径。`}请定位根因、修复并说明验证方式。`),Z.info(`已锁定调试目标并带上错误上下文,发送即开始`)},ge=async(e,t)=>{try{let n=await st(`/api/panels/rollback`,{id:e,version:t});Z.success(`已回退到 ${t}(新版本号 ${n.plugin.version},引用即时生效)`),le()}catch(e){Z.error(String(e.message))}},_e=()=>{if(te===null||!B[te])return``;let e=B[te],t=e.grid||{x:1,y:1,w:6,h:1},n=Math.round(t.w/12*100),r=t.w<=3?`窄条(紧凑单列列表/迷你卡)`:t.w>=9?`宽区块(表格/多列仪表)`:`中等宽度(两列卡/紧凑表)`;return`【定制目标】区块「${e.title}」(id=${e.id}):第${t.x}列起、跨${t.w}列(约${n}%宽)、跨${t.h}行(${r})。${e.panel?`当前引用插件 ${e.panel}——先 read_panel_plugin 再决定改造还是重写。`:`空区块,可新建插件。`}`},ve=e=>{z(e),F(``),Z.info(`已锁定定制目标「${B[e].title}」——在右侧描述需求即可`)},ye=async()=>{u(!0);try{let r=await ct(`/api/workbench`,{agent_id:e,dsl:t});n(r.dsl),o(r.versions),c(JSON.stringify(r.dsl,null,2)),i(!1),re(!1),Z.success(`已发布 ${r.dsl.version},工作台即时生效`)}catch(e){Z.error(String(e.message))}finally{u(!1)}},be=async()=>{await lt(`/api/workbench/draft`,{agent_id:e}),Z.success(`已放弃草稿`),le()},xe=async t=>{try{let r=await st(`/api/workbench/rollback`,{agent_id:e,version:t});n(r.dsl),o(r.versions),c(JSON.stringify(r.dsl,null,2)),i(!1),Z.success(`已回滚到 ${t}`)}catch(e){Z.error(String(e.message))}},U=()=>{j.current?.abort()},Se=async()=>{let t=P.trim();if(!t||I)return;let n=_e()?`${_e()}\n需求:${t}`:t;F(``),L(!0),re(!1),se.current=!0,N(e=>[...e,{role:`user`,text:t}]);let r=!1,i=new AbortController;j.current=i;try{await ut(`/api/dev/chat`,{sessionId:A,agentId:e,message:n},e=>{let t=e.type;t===`status`?ee(String(e.text||``)):t===`text_delta`?(ee(``),N(t=>{let n=t[t.length-1];return n?.role===`agent`&&n.streaming?[...t.slice(0,-1),{...n,text:n.text+String(e.delta)}]:[...t,{role:`agent`,text:String(e.delta),streaming:!0}]})):t===`tool_start`?(r=!0,N(t=>[...t,{role:`agent`,text:``,streaming:!1,events:[{tool:String(e.tool),args:e.args||{}}]}])):t===`tool_end`?N(t=>{for(let n=t.length-1;n>=0;n--){let r=t[n];if(r.role===`agent`&&r.events){for(let n=r.events.length-1;n>=0;n--)if(r.events[n].tool===e.tool&&r.events[n].result===void 0)return r.events[n].result=String(e.result||``),r.events[n].ok=e.ok!==!1,[...t]}}return t}):t===`interrupted`?(ee(``),N(e=>[...e,{role:`agent`,text:`(已中断)`}])):t===`meta`?e.hasDraft?(re(!0),le()):r&&le():t===`error`&&Z.error(String(e.message))},i.signal)}catch(e){i.signal.aborted?N(e=>[...e,{role:`agent`,text:`(已中断)`}]):N(t=>[...t,{role:`agent`,text:`❌ ${String(e.message)}`}])}finally{ee(``),L(!1),j.current===i&&(j.current=null)}};return(0,K.jsxs)(`div`,{className:`flex h-full flex-col gap-3 overflow-hidden p-5`,children:[(0,K.jsxs)(`div`,{className:`flex shrink-0 items-end justify-between`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`h1`,{className:`text-lg font-bold`,children:`定制工作台`}),(0,K.jsx)(`p`,{className:`mt-0.5 text-xs text-muted-foreground`,children:`区块你规划 · 插件按区块占比定制 · 一切修改走草稿审阅发布`})]}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)(J,{variant:`secondary`,children:r?`草稿(未发布)`:`线上 ${t.version}`}),(0,K.jsxs)(Y,{size:`sm`,variant:`outline`,onClick:()=>{g(null),m(!0)},children:[(0,K.jsx)(pg,{className:`mr-1 h-3.5 w-3.5`}),`插件库`]}),(0,K.jsxs)(Y,{size:`sm`,variant:`outline`,title:`把当前工作台(含依赖插件/数据集 schema/交互脚本)发布为 ARM UI 资产`,onClick:()=>ae({type:`workbench`,agentId:e,title:t.workbench}),children:[(0,K.jsx)(_h,{className:`mr-1 h-3.5 w-3.5 text-violet-400`}),`导出资产`]}),(0,K.jsxs)(Y,{size:`sm`,disabled:l||!r,onClick:ye,children:[(0,K.jsx)(yg,{className:`mr-1 h-3.5 w-3.5`}),l?`发布中…`:`审阅后发布`]})]})]}),r&&(0,K.jsxs)(`div`,{className:`flex shrink-0 items-center gap-2 rounded-md border border-amber-500/50 bg-amber-500/10 px-3 py-2 text-xs text-amber-300`,children:[(0,K.jsx)(`span`,{children:`⚠`}),`草稿未发布——审阅后发布生效,或`,(0,K.jsx)(`button`,{className:`underline underline-offset-2`,onClick:be,children:`放弃草稿`})]}),(0,K.jsxs)(`div`,{className:`grid min-h-0 flex-1 grid-cols-[1fr_380px] gap-4`,children:[(0,K.jsx)(`div`,{className:`flex min-h-0 flex-col`,children:(0,K.jsxs)(vO,{defaultValue:`canvas`,className:`flex min-h-0 flex-1 flex-col`,children:[(0,K.jsxs)(bO,{className:`shrink-0`,children:[(0,K.jsxs)(xO,{value:`canvas`,className:`text-xs`,children:[(0,K.jsx)(Yh,{className:`mr-1 h-3.5 w-3.5`}),`布局画布`]}),(0,K.jsx)(xO,{value:`json`,className:`text-xs`,children:`JSON`})]}),(0,K.jsxs)(SO,{value:`canvas`,className:`mt-2 flex min-h-0 flex-1 flex-col gap-2`,children:[(0,K.jsxs)(`div`,{className:`flex shrink-0 flex-nowrap items-center gap-1.5 overflow-x-auto rounded-md border bg-card p-2`,children:[(0,K.jsxs)(Y,{size:`sm`,variant:`secondary`,className:`h-7 shrink-0 text-xs`,onClick:pe,children:[(0,K.jsx)(dg,{className:`mr-1 h-3 w-3`}),`添加区块`]}),(0,K.jsx)(_O,{orientation:`vertical`,className:`mx-1 h-5 shrink-0`}),V?(0,K.jsxs)(K.Fragment,{children:[(0,K.jsxs)(`span`,{className:`max-w-28 shrink-0 truncate text-[11px] text-muted-foreground`,title:V.title,children:[`「`,V.title,`」`]}),(0,K.jsx)(`span`,{className:`shrink-0 text-[11px]`,children:`列`}),(0,K.jsx)(Y,{size:`icon`,variant:`ghost`,className:`h-7 w-7 shrink-0`,title:`左移一列`,onClick:()=>ue(_,{x:Math.max(1,(V.grid?.x||1)-1)}),children:(0,K.jsx)(qm,{className:`h-3 w-3`})}),(0,K.jsx)(Y,{size:`icon`,variant:`ghost`,className:`h-7 w-7 shrink-0`,title:`右移一列`,onClick:()=>ue(_,{x:Math.min(12,(V.grid?.x||1)+1)}),children:(0,K.jsx)(Ym,{className:`h-3 w-3`})}),(0,K.jsx)(`span`,{className:`shrink-0 text-[11px]`,children:`跨列`}),(0,K.jsx)(Y,{size:`icon`,variant:`ghost`,className:`h-7 w-7 shrink-0`,title:`跨列减一`,onClick:()=>ue(_,{w:Math.max(1,(V.grid?.w||6)-1)}),children:`−`}),(0,K.jsx)(Y,{size:`icon`,variant:`ghost`,className:`h-7 w-7 shrink-0`,title:`跨列加一`,onClick:()=>ue(_,{w:Math.min(12,(V.grid?.w||6)+1)}),children:`+`}),(0,K.jsx)(`span`,{className:`shrink-0 text-[11px]`,children:`跨行`}),(0,K.jsx)(Y,{size:`icon`,variant:`ghost`,className:`h-7 w-7 shrink-0`,title:`跨行减一`,onClick:()=>ue(_,{h:Math.max(1,(V.grid?.h||1)-1)}),children:(0,K.jsx)(Zm,{className:`h-3 w-3`})}),(0,K.jsx)(Y,{size:`icon`,variant:`ghost`,className:`h-7 w-7 shrink-0`,title:`跨行加一`,onClick:()=>ue(_,{h:Math.min(8,(V.grid?.h||1)+1)}),children:(0,K.jsx)(Gm,{className:`h-3 w-3`})}),(0,K.jsxs)(Y,{size:`sm`,variant:`ghost`,className:`h-7 shrink-0 text-xs text-primary`,onClick:()=>ve(_),children:[(0,K.jsx)(th,{className:`mr-1 h-3 w-3`}),`AI 定制`]}),(0,K.jsxs)(CO,{children:[(0,K.jsx)(wO,{asChild:!0,children:(0,K.jsxs)(Y,{size:`sm`,variant:`ghost`,className:`h-7 shrink-0 text-xs`,children:[(0,K.jsx)(Th,{className:`h-3 w-3`}),`更多`]})}),(0,K.jsxs)(TO,{align:`end`,children:[(V.type===`custom`||V.type===`custom_panel`)&&(0,K.jsxs)(EO,{className:`text-amber-400 focus:text-amber-300`,onClick:()=>he(_),children:[(0,K.jsx)(t_,{}),`AI 调试`]}),(0,K.jsxs)(EO,{onClick:()=>ue(_,{x:1,w:12}),children:[(0,K.jsx)(Ug,{className:`text-muted-foreground`}),`占满宽度`]}),(0,K.jsxs)(EO,{onClick:()=>{let e=B.reduce((e,t)=>Math.max(e,(t.grid?.y||1)+(t.grid?.h||1)-1),1);ue(_,{h:Math.max(1,e-(V.grid?.y||1)+1)})},children:[(0,K.jsx)(Gg,{className:`text-muted-foreground`}),`延到底部`]}),(0,K.jsxs)(EO,{onClick:()=>ue(_,{x:1}),children:[(0,K.jsx)(Um,{className:`text-muted-foreground`}),`贴左`]}),(0,K.jsxs)(EO,{onClick:()=>ue(_,{x:12-(V.grid?.w||6)+1}),children:[(0,K.jsx)(Vm,{className:`text-muted-foreground`}),`贴右`]}),(0,K.jsx)(DO,{}),(0,K.jsxs)(EO,{onClick:()=>{g(_),m(!0)},children:[(0,K.jsx)(pg,{className:`text-muted-foreground`}),`换插件`]}),(0,K.jsxs)(EO,{onClick:()=>{C(_),x(!0)},children:[(0,K.jsx)(Dg,{className:`text-muted-foreground`}),`面板设置`]}),(0,K.jsxs)(EO,{className:`text-red-400 focus:text-red-300`,onClick:()=>{H(e=>e.panels.splice(_,1)),y(null)},children:[(0,K.jsx)(qg,{}),`删除区块`]})]})]})]}):(0,K.jsx)(`span`,{className:`shrink-0 text-[11px] text-muted-foreground`,children:`点击画布中的区块进行编辑`})]}),(0,K.jsx)(`div`,{className:`shrink-0`,children:(0,K.jsx)(mO,{})}),(0,K.jsx)(`div`,{className:`relative min-h-0 flex-1 overflow-hidden rounded-lg border bg-muted/20 p-2`,children:(0,K.jsx)(pO,{className:`absolute inset-0 overflow-auto`,dsl:t,edit:{sel:_,onSelect:y,onGrid:(e,t)=>ue(e,t)},renderPanel:t=>{let n=fe(t);return n?(0,K.jsx)(dO,{code:n,data:de(t),meta:{agentId:e,panelId:t.id,pluginId:t.panel}}):(0,K.jsx)(`div`,{className:`p-3 text-[11px] text-muted-foreground`,children:`(插件代码加载中…)`})},renderDialog:()=>(0,K.jsxs)(`div`,{className:`flex h-full flex-col items-center justify-center gap-1 text-[11px] text-muted-foreground`,children:[(0,K.jsx)(th,{className:`h-5 w-5 text-primary`}),`诊断对话(内核)`,(0,K.jsx)(`span`,{className:`text-[10px]`,children:`发布后在工作台可交互`})]}),renderPlaceholder:()=>(0,K.jsxs)(`div`,{className:`flex h-full flex-col items-center justify-center gap-1 text-[11px] text-muted-foreground`,children:[(0,K.jsx)(dg,{className:`h-4 w-4`}),`空区块`,(0,K.jsx)(`span`,{className:`text-[10px]`,children:`选中后「换插件」或「AI 定制」`})]})})}),(0,K.jsx)(`p`,{className:`shrink-0 text-[10px] text-muted-foreground`,children:`所见即所得(比例一致):画布 = 缩小的可视区,行高为可视区等分——跨 n 行即占 n/总行数,与实际浏览时任何屏幕尺寸下的比例完全一致;内容超高时面板内部滚动。拖拽移动(吸附网格)· 手柄调跨列跨行 · 右上角显示占比。`})]}),(0,K.jsxs)(SO,{value:`json`,className:`mt-2 flex min-h-0 flex-1 flex-col gap-2`,children:[(0,K.jsx)(`textarea`,{value:s,onChange:e=>c(e.target.value),spellCheck:!1,className:`min-h-0 w-full flex-1 resize-none rounded-md border bg-muted p-3 font-mono text-[11px] leading-relaxed`}),(0,K.jsxs)(`div`,{className:`flex shrink-0 gap-2`,children:[(0,K.jsx)(Y,{size:`sm`,onClick:()=>{try{let e=JSON.parse(s);if(!e.panels)throw Error(`缺少 panels`);n(e),i(!0),Z.success(`JSON 已应用(未发布)`)}catch(e){Z.error(`JSON 解析失败: ${e.message}`)}},children:`应用 JSON`}),(0,K.jsx)(Y,{size:`sm`,variant:`outline`,onClick:()=>c(JSON.stringify(t,null,2)),children:`从画布刷新`})]})]})]})}),(0,K.jsxs)(`div`,{className:`flex min-h-0 flex-col gap-4`,children:[(0,K.jsx)(bm,{className:`flex min-h-0 flex-1 flex-col py-0`,children:(0,K.jsxs)(Cm,{className:`flex min-h-0 flex-1 flex-col p-0`,children:[(0,K.jsxs)(`div`,{className:`flex shrink-0 items-center gap-1.5 border-b px-3 py-2 text-xs font-semibold`,children:[(0,K.jsx)(Lg,{className:`h-3.5 w-3.5 text-primary`}),`二开助手`,(0,K.jsx)(`span`,{className:`font-normal text-muted-foreground`,children:`· 描述需求,直接定制区块`})]}),te!==null&&B[te]&&(()=>{let e=B[te],t=e.grid||{x:1,y:1,w:6,h:1},n=Math.round(t.w/12*100);return(0,K.jsxs)(`div`,{className:`flex shrink-0 items-center gap-1.5 border-b bg-primary/5 px-3 py-1.5 text-[11px]`,children:[(0,K.jsx)(yh,{className:`h-3.5 w-3.5 shrink-0 text-primary`}),(0,K.jsxs)(`span`,{className:`min-w-0 truncate`,children:[`定制目标:`,(0,K.jsx)(`b`,{children:e.title}),` · `,n,`% 宽 · `,t.h,` 行`,e.panel?(0,K.jsxs)(K.Fragment,{children:[` · `,(0,K.jsx)(`span`,{className:`font-mono`,children:e.panel})]}):` · 空区块`]}),(0,K.jsx)(`button`,{className:`ml-auto shrink-0 rounded p-0.5 text-muted-foreground hover:text-foreground`,title:`取消目标,改为自由描述`,onClick:()=>z(null),children:`×`})]})})(),ne&&r&&(0,K.jsxs)(`div`,{className:`flex shrink-0 items-center gap-1.5 border-b bg-emerald-500/10 px-3 py-1.5 text-[11px] text-emerald-400`,children:[(0,K.jsx)(ph,{className:`h-3.5 w-3.5 shrink-0`}),`草稿已生成——到顶部「审阅后发布」生效`]}),(0,K.jsx)(eO,{className:`min-h-0 flex-1`,children:(0,K.jsxs)(`div`,{className:`space-y-2.5 p-3`,ref:oe,children:[M.length===0&&(0,K.jsx)(`div`,{className:`space-y-2`,children:(0,K.jsxs)(`div`,{className:`rounded-md border border-dashed border-primary/30 bg-primary/5 p-3 text-[11px] leading-relaxed`,children:[(0,K.jsx)(`div`,{className:`mb-1 text-xs font-semibold text-primary`,children:`✨ 两种玩法`}),(0,K.jsxs)(`div`,{children:[`① 画布选中区块 → 工具条「`,(0,K.jsx)(`b`,{children:`AI 定制`}),`」→ 目标钉在上方,只管补需求`]}),(0,K.jsx)(`div`,{children:`② 直接描述需求,助手自动建区块进草稿`}),(0,K.jsx)(`div`,{className:`mt-1.5 flex flex-wrap gap-1.5`,children:[[`窄条:最近告警`,`新建一个窄条区块(跨3列):最近活动告警列表,高级别标红,点击可选中设备`],[`横条:KPI 摘要`,`新建一个单行横条区块:关键指标摘要读数(props.kpi),异常着色`],[`宽表:设备台账`,`新建一个宽区块(跨9列以上):设备台账表格,显示全部字段,支持点击选中`]].map(([e,t])=>(0,K.jsx)(`button`,{onClick:()=>F(t),className:`rounded-full border px-2.5 py-1 text-[11px] text-muted-foreground transition-colors hover:border-primary/60 hover:text-primary`,children:e},e))})]})}),M.map((e,t)=>(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`div`,{className:e.role===`user`?`ml-auto max-w-[90%] rounded-lg bg-primary/20 px-2.5 py-1.5 text-xs break-words whitespace-pre-wrap`:`max-w-full rounded-lg bg-card px-2.5 py-1.5 text-xs leading-relaxed break-words whitespace-pre-wrap`,children:e.text}),(e.events||[]).map((e,t)=>(0,K.jsxs)(`div`,{className:`mt-1 min-w-0 rounded-md border border-dashed px-2 py-1 text-[10px]`,children:[(0,K.jsx)(`span`,{children:e.ok===!1?`❌`:`🛠`}),` `,(0,K.jsx)(`span`,{className:`font-mono font-semibold`,children:e.tool}),(0,K.jsx)(`pre`,{className:`mt-0.5 max-h-32 overflow-auto whitespace-pre-wrap break-all text-muted-foreground`,children:String(e.result||``).slice(0,260)})]},t))]},t)),(I||R)&&(0,K.jsxs)(`div`,{className:`flex items-center gap-1.5 px-1 text-[11px] text-muted-foreground`,children:[(0,K.jsx)(`span`,{className:`h-1.5 w-1.5 animate-pulse rounded-full bg-primary`}),R||`开发中…`]})]})}),(0,K.jsxs)(`div`,{className:`shrink-0 space-y-1 border-t p-2`,children:[(0,K.jsx)(`textarea`,{value:P,onChange:e=>F(e.target.value),rows:2,onKeyDown:e=>{e.key===`Enter`&&!e.shiftKey&&!e.nativeEvent.isComposing&&(e.preventDefault(),Se())},placeholder:te===null?`描述需求,如「左上窄条做一个最近工单列表」(Enter 发送)…`:`描述对「${B[te]?.title}」的需求(Enter 发送,Shift+Enter 换行)…`,className:`min-h-[56px] w-full resize-none rounded-md border bg-background px-2 py-1.5 text-xs`}),(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsx)(`span`,{className:`text-[10px] text-muted-foreground`,children:te===null?`未锁定目标——助手会自动规划区块位置`:`目标上下文(位置/几何/插件)发送时自动携带`}),I?(0,K.jsxs)(Y,{size:`sm`,variant:`destructive`,className:`h-7 gap-1 text-xs`,onClick:U,children:[(0,K.jsx)(Vg,{className:`h-3 w-3`}),`停止`]}):(0,K.jsxs)(Y,{size:`sm`,className:`h-7 gap-1 text-xs`,disabled:!P.trim(),onClick:Se,children:[(0,K.jsx)(Cg,{className:`h-3 w-3`}),`发送`]})]})]})]})}),(0,K.jsx)(bm,{className:`shrink-0 py-0`,children:(0,K.jsxs)(Cm,{className:`p-0`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-1.5 border-b px-3 py-2 text-xs font-semibold`,children:[(0,K.jsx)(_g,{className:`h-3.5 w-3.5`}),`版本历史`]}),(0,K.jsx)(`div`,{className:`max-h-40 overflow-y-auto`,children:(0,K.jsxs)(`div`,{className:`divide-y`,children:[a.length===0&&(0,K.jsx)(`div`,{className:`p-3 text-center text-xs text-muted-foreground`,children:`暂无历史`}),[...a].reverse().map((e,t)=>(0,K.jsxs)(`div`,{className:`flex items-center gap-2 px-3 py-1.5 text-xs`,children:[(0,K.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,K.jsx)(`span`,{className:`font-mono font-semibold`,children:e.version}),t===0&&!r&&(0,K.jsx)(J,{className:`ml-1 h-4 px-1 text-[9px]`,children:`线上`}),(0,K.jsx)(`div`,{className:`text-[10px] text-muted-foreground`,children:gt(e.at,`dts`)})]}),t!==0&&(0,K.jsx)(Y,{size:`sm`,variant:`ghost`,className:`h-6 text-[10px]`,onClick:()=>xe(e.version),children:`回滚`})]},`${e.version}-${e.at}`))]})})]})})]})]}),(0,K.jsx)(a_,{open:b,onOpenChange:x,children:(0,K.jsxs)(c_,{className:`max-w-md`,children:[(0,K.jsx)(l_,{children:(0,K.jsxs)(d_,{children:[`区块设置 · `,B[S]?.title]})}),(0,K.jsxs)(`div`,{className:`space-y-2`,children:[(0,K.jsxs)(`div`,{className:`space-y-1`,children:[(0,K.jsx)(m_,{className:`text-xs`,children:`标题`}),(0,K.jsx)(p_,{defaultValue:B[S]?.title||``,className:`text-xs`,onBlur:e=>H(t=>{t.panels[S].title=e.target.value})})]}),B[S]?.type===`custom`&&(0,K.jsxs)(`div`,{className:`space-y-1`,children:[(0,K.jsx)(m_,{className:`text-xs`,children:`内联代码(契约:function Panel(props))`}),(0,K.jsx)(`textarea`,{defaultValue:B[S]?.code||``,spellCheck:!1,onBlur:e=>H(t=>{t.panels[S].code=e.target.value}),className:`h-40 w-full rounded-md border bg-muted p-2 font-mono text-[10px]`})]}),B[S]?.type===`custom_panel`&&(0,K.jsxs)(`div`,{className:`space-y-1`,children:[(0,K.jsx)(m_,{className:`text-xs`,children:`插件版本(可回退,回退即时生效)`}),(0,K.jsx)(MO,{pluginId:String(B[S]?.panel||``),onRollback:ge})]}),(0,K.jsxs)(`div`,{className:`space-y-1`,children:[(0,K.jsx)(m_,{className:`text-xs`,children:`params(插件经 props.params 读取)`}),(0,K.jsx)(`textarea`,{defaultValue:JSON.stringify(B[S]?.params||{},null,1),spellCheck:!1,onBlur:e=>{try{H(t=>{t.panels[S].params=JSON.parse(e.target.value||`{}`)})}catch{Z.error(`params JSON 无效`)}},className:`h-20 w-full rounded-md border bg-muted p-2 font-mono text-[10px]`})]})]}),(0,K.jsx)(u_,{children:(0,K.jsx)(Y,{onClick:()=>x(!1),children:`完成`})})]})}),(0,K.jsx)(a_,{open:p,onOpenChange:e=>{m(e),e||g(null)},children:(0,K.jsxs)(c_,{children:[(0,K.jsx)(l_,{children:(0,K.jsxs)(d_,{className:`flex items-center gap-1.5`,children:[(0,K.jsx)(pg,{className:`h-4 w-4`}),`插件库`,h===null?``:` · 插入到选中区块`]})}),(0,K.jsx)(`div`,{className:`max-h-72 overflow-y-auto`,children:(0,K.jsx)(`div`,{className:`space-y-1.5`,children:d.filter(e=>e.status!==`deprecated`).map(e=>(0,K.jsxs)(`div`,{className:`flex items-center gap-2 rounded-md border p-2.5`,children:[(0,K.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,K.jsxs)(`div`,{className:`flex min-w-0 items-center gap-1.5 text-xs font-medium`,children:[(0,K.jsx)(`span`,{className:`min-w-0 truncate`,title:e.name,children:e.name}),(0,K.jsx)(J,{variant:`secondary`,className:`h-4 shrink-0 px-1 text-[9px]`,children:e.version}),(0,K.jsx)(J,{variant:`outline`,className:`h-4 shrink-0 px-1 text-[9px]`,children:e.author===`system`?`范本`:e.author===`ai`?`AI`:`人工`})]}),(0,K.jsx)(`div`,{className:`truncate text-[10px] text-muted-foreground`,children:e.description||e.id})]}),(0,K.jsx)(Y,{size:`sm`,variant:`secondary`,className:`h-7 shrink-0 text-[11px]`,onClick:()=>me(h,e),children:`插入`})]},e.id))})}),(0,K.jsxs)(u_,{children:[(0,K.jsx)(Y,{variant:`outline`,size:`sm`,onClick:pe,children:`先加空区块`}),(0,K.jsx)(Y,{variant:`outline`,onClick:()=>m(!1),children:`关闭`})]})]})}),(0,K.jsx)(kO,{target:ie,onClose:()=>ae(null),agents:[{agent_id:e,name:t.workbench||`当前助手`}]}),(0,K.jsx)(`p`,{className:`shrink-0 text-center text-[11px] text-muted-foreground`,children:`区块几何 = 插件设计输入:宽≤3 列紧凑列表、≥9 列表格/仪表 · AI 定制锁定目标、上下文自动携带 · 草稿审阅发布。`})]})}var FO=[{key:`tool_calls`,label:`工具调用`,icon:(0,K.jsx)(t_,{className:`h-3.5 w-3.5`}),tone:`text-sky-400`},{key:`guardrail_blocks`,label:`守护栏拦截`,icon:(0,K.jsx)(jg,{className:`h-3.5 w-3.5`}),tone:`text-red-400`},{key:`human_confirms`,label:`人工确认执行`,icon:(0,K.jsx)(zm,{className:`h-3.5 w-3.5`}),tone:`text-amber-400`},{key:`orchestrations`,label:`编排执行`,icon:(0,K.jsx)(Lg,{className:`h-3.5 w-3.5`}),tone:`text-violet-400`},{key:`experiences`,label:`经验回流`,icon:(0,K.jsx)($m,{className:`h-3.5 w-3.5`}),tone:`text-emerald-400`},{key:`kb_searches`,label:`知识检索`,icon:(0,K.jsx)(xg,{className:`h-3.5 w-3.5`}),tone:`text-cyan-400`},{key:`ai_drafts`,label:`AI 起草`,icon:(0,K.jsx)(Yg,{className:`h-3.5 w-3.5`}),tone:`text-pink-400`}];function IO(){let[e,t]=(0,v.useState)(null),[n,r]=(0,v.useState)(``),[i,a]=(0,v.useState)(null),[o,s]=(0,v.useState)(!1),c=()=>ot(`/api/evolution`).then(t);(0,v.useEffect)(()=>{c();let e=setInterval(c,1e4);return()=>clearInterval(e)},[]);let l=async()=>{if(n.trim()){s(!0);try{let e=await ot(`/api/kb/search?q=${encodeURIComponent(n)}`);a(e.items),c()}finally{s(!1)}}};return e?(0,K.jsxs)(`div`,{className:`h-full overflow-auto p-5`,children:[(0,K.jsxs)(`div`,{className:`mb-4`,children:[(0,K.jsxs)(`h1`,{className:`flex items-center gap-2 text-lg font-bold`,children:[(0,K.jsx)(Yg,{className:`h-5 w-5 text-primary`}),`自进化看板`]}),(0,K.jsxs)(`p`,{className:`mt-0.5 text-xs text-muted-foreground`,children:[e.flywheel_note,` · 数据来自审计日志与指标流的实时聚合`]})]}),(0,K.jsx)(`div`,{className:`grid grid-cols-4 gap-3 xl:grid-cols-7`,children:FO.map(t=>(0,K.jsx)(bm,{className:`py-3`,children:(0,K.jsxs)(Cm,{className:`px-3`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-1.5 text-[11px] text-muted-foreground`,children:[t.icon,t.label]}),(0,K.jsx)(`div`,{className:`mt-1 text-xl font-bold ${t.tone}`,children:e.totals[t.key]??0})]})},t.key))}),(0,K.jsxs)(`div`,{className:`mt-4 grid grid-cols-2 gap-4`,children:[(0,K.jsxs)(bm,{className:`py-0`,children:[(0,K.jsx)(xm,{className:`border-b py-2.5`,children:(0,K.jsx)(Sm,{className:`text-xs text-muted-foreground`,children:`飞轮证据 · 检索相似度趋势(回流前后对比)`})}),(0,K.jsx)(Cm,{className:`p-0`,children:(0,K.jsx)(eO,{className:`h-64`,children:(0,K.jsxs)(`div`,{className:`space-y-1.5 p-3`,children:[e.similarity_trend.length===0&&(0,K.jsx)(`div`,{className:`py-8 text-center text-xs text-muted-foreground`,children:`尚无检索记录`}),e.similarity_trend.map((e,t)=>(0,K.jsxs)(`div`,{className:`flex items-center gap-2 text-xs`,children:[(0,K.jsx)(`span`,{className:`w-40 shrink-0 truncate text-muted-foreground`,title:e.query,children:e.query}),(0,K.jsx)(`div`,{className:`h-2 flex-1 overflow-hidden rounded bg-muted`,children:(0,K.jsx)(`div`,{className:`h-full rounded ${e.similarity>=75?`bg-emerald-500`:e.similarity>=55?`bg-amber-500`:`bg-slate-500`}`,style:{width:`${e.similarity}%`}})}),(0,K.jsxs)(`span`,{className:`w-9 text-right font-mono ${e.similarity>=75?`text-emerald-400`:`text-muted-foreground`}`,children:[e.similarity,`%`]})]},t))]})})})]}),(0,K.jsxs)(bm,{className:`py-0`,children:[(0,K.jsx)(xm,{className:`border-b py-2.5`,children:(0,K.jsxs)(Sm,{className:`flex items-center gap-1.5 text-xs text-muted-foreground`,children:[(0,K.jsx)($m,{className:`h-3.5 w-3.5`}),`经验沉淀(写入 ARM 知识库)`]})}),(0,K.jsx)(Cm,{className:`p-0`,children:(0,K.jsx)(eO,{className:`h-64`,children:(0,K.jsxs)(`div`,{className:`divide-y`,children:[e.experiences.length===0&&(0,K.jsx)(`div`,{className:`p-8 text-center text-xs text-muted-foreground`,children:`尚无回流记录`}),e.experiences.map((e,t)=>(0,K.jsxs)(`div`,{className:`flex items-center gap-2 px-3 py-2 text-xs`,children:[(0,K.jsx)(kh,{className:`h-3 w-3 shrink-0 text-emerald-400`}),(0,K.jsx)(`span`,{className:`min-w-0 flex-1 truncate`,title:e.title,children:e.title}),(0,K.jsx)(`span`,{className:`shrink-0 font-mono text-[10px] text-muted-foreground`,children:e.knowledge_id?e.knowledge_id.slice(0,8):`—`}),(0,K.jsx)(`span`,{className:`shrink-0 text-[10px] text-muted-foreground`,children:gt(e.ts)})]},t))]})})})]})]}),(0,K.jsxs)(`div`,{className:`mt-4 grid grid-cols-3 gap-4`,children:[(0,K.jsxs)(bm,{className:`py-0`,children:[(0,K.jsx)(xm,{className:`border-b py-2.5`,children:(0,K.jsx)(Sm,{className:`text-xs text-muted-foreground`,children:`工具调用分布`})}),(0,K.jsxs)(Cm,{className:`p-3`,children:[Object.keys(e.by_tool).length===0&&(0,K.jsx)(`div`,{className:`py-6 text-center text-xs text-muted-foreground`,children:`暂无数据`}),Object.entries(e.by_tool).sort((e,t)=>t[1]-e[1]).map(([t,n])=>{let r=Math.max(...Object.values(e.by_tool));return(0,K.jsxs)(`div`,{className:`mb-1.5 flex items-center gap-2 text-xs`,children:[(0,K.jsx)(`span`,{className:`w-36 shrink-0 truncate font-mono`,children:t}),(0,K.jsx)(`div`,{className:`h-2 flex-1 overflow-hidden rounded bg-muted`,children:(0,K.jsx)(`div`,{className:`h-full rounded bg-sky-500`,style:{width:`${n/r*100}%`}})}),(0,K.jsx)(`span`,{className:`w-6 text-right font-mono`,children:n})]},t)})]})]}),(0,K.jsxs)(bm,{className:`py-0`,children:[(0,K.jsx)(xm,{className:`border-b py-2.5`,children:(0,K.jsxs)(Sm,{className:`flex items-center gap-1.5 text-xs text-muted-foreground`,children:[(0,K.jsx)(xh,{className:`h-3.5 w-3.5`}),`ARM 知识库实检(真实 RAG)`]})}),(0,K.jsxs)(Cm,{className:`p-3`,children:[(0,K.jsxs)(`div`,{className:`flex gap-2`,children:[(0,K.jsx)(p_,{value:n,onChange:e=>r(e.target.value),onKeyDown:e=>e.key===`Enter`&&l(),placeholder:`如:堆垛机 货叉定位偏移`,className:`text-xs`}),(0,K.jsx)(Y,{size:`sm`,disabled:o,onClick:l,children:o?`检索中`:`检索`})]}),(0,K.jsx)(eO,{className:`mt-2 h-44`,children:(0,K.jsxs)(`div`,{className:`space-y-1.5`,children:[!i&&(0,K.jsx)(`div`,{className:`py-6 text-center text-xs text-muted-foreground`,children:`输入问题检索企业经验库(与助手使用同一数据源)`}),i?.length===0&&(0,K.jsx)(`div`,{className:`py-6 text-center text-xs text-muted-foreground`,children:`无命中`}),i?.map((e,t)=>(0,K.jsxs)(`div`,{className:`rounded-md bg-card px-2.5 py-1.5`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-1.5 text-xs`,children:[e.similarity!=null&&(0,K.jsxs)(J,{variant:`secondary`,className:`h-4 text-[9px] ${e.similarity>=75?`text-emerald-400`:``}`,children:[e.similarity,`%`]}),(0,K.jsx)(`span`,{className:`truncate font-medium`,children:e.title})]}),(0,K.jsx)(`p`,{className:`mt-0.5 line-clamp-2 text-[10px] leading-relaxed text-muted-foreground`,children:e.snippet})]},t))]})})]})]}),(0,K.jsxs)(bm,{className:`py-0`,children:[(0,K.jsx)(xm,{className:`border-b py-2.5`,children:(0,K.jsx)(Sm,{className:`text-xs text-muted-foreground`,children:`审计流(实时)`})}),(0,K.jsx)(Cm,{className:`p-0`,children:(0,K.jsx)(eO,{className:`h-52`,children:(0,K.jsx)(`div`,{className:`divide-y font-mono text-[10px]`,children:e.recent_audit.map((e,t)=>(0,K.jsxs)(`div`,{className:`flex items-center gap-2 px-3 py-1.5`,children:[(0,K.jsx)(`span`,{className:`text-muted-foreground`,children:gt(e.ts,`t`)}),(0,K.jsx)(J,{variant:`outline`,className:`h-4 px-1 text-[9px]`,children:e.actor}),(0,K.jsx)(`span`,{className:`truncate`,children:e.tool||e.logic||e.action||e.name||e.verdict||``})]},t))})})})]})]})]}):(0,K.jsx)(`div`,{className:`flex h-full items-center justify-center text-sm text-muted-foreground`,children:`进化数据加载中…`})}function LO({className:e,size:t=`default`,...n}){return(0,K.jsx)(qp,{"data-slot":`switch`,"data-size":t,className:mn(`peer group/switch inline-flex shrink-0 items-center rounded-full border border-transparent shadow-xs transition-all outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-[1.15rem] data-[size=default]:w-8 data-[size=sm]:h-3.5 data-[size=sm]:w-6 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input dark:data-[state=unchecked]:bg-input/80`,e),...n,children:(0,K.jsx)(Yp,{"data-slot":`switch-thumb`,className:mn(`pointer-events-none block rounded-full bg-background ring-0 transition-transform group-data-[size=default]/switch:size-4 group-data-[size=sm]/switch:size-3 data-[state=checked]:translate-x-[calc(100%-2px)] data-[state=unchecked]:translate-x-0 dark:data-[state=checked]:bg-primary-foreground dark:data-[state=unchecked]:bg-foreground`)})})}function RO(){let[e,t]=(0,v.useState)(null),[n,r]=(0,v.useState)(null),[i,a]=(0,v.useState)(``),[o,s]=(0,v.useState)(``),[c,l]=(0,v.useState)(``),[u,d]=(0,v.useState)(!1),[f,p]=(0,v.useState)(null),[m,h]=(0,v.useState)(``),[g,_]=(0,v.useState)(``),[y,b]=(0,v.useState)(``),[x,S]=(0,v.useState)(!1),[C,w]=(0,v.useState)(null),[T,E]=(0,v.useState)(``),[D,O]=(0,v.useState)(!1),[k,A]=(0,v.useState)(``),[j,M]=(0,v.useState)(!1),[N,P]=(0,v.useState)([]),[F,I]=(0,v.useState)([]),[L,R]=(0,v.useState)(!1),[ee,te]=(0,v.useState)(``),[z,ne]=(0,v.useState)(``),[re,ie]=(0,v.useState)(!1),[ae,oe]=(0,v.useState)(null),se=()=>{ot(`/api/settings`).then(e=>{t(e),a(e.arm.api_base),s(e.arm.mcp_explicit?e.arm.mcp_url:``),h(e.llm.model),_(e.llm.base_url_runtime?e.llm.base_url:``),E(e.scene.profile),P(e.guard.deny),I(e.guard.ro),R(e.guard.sudo_u_l2)}),ot(`/api/arm/status`).then(r).catch(()=>r(null))};(0,v.useEffect)(()=>{se()},[]);let ce=async()=>{d(!0),p(null);try{let e=await ct(`/api/settings`,{arm_api_base:i.trim(),arm_mcp_url:o.trim(),...c.trim()?{arm_token:c.trim()}:{}});p(e.probe||null),l(``),e.probe?.online?Z.success(`已保存并连通(${e.probe.latency_ms}ms),源切换即时生效`):Z.warning(`已保存,但当前源不可达`,{description:e.note}),se()}catch(e){Z.error(String(e.message))}finally{d(!1)}},le=async()=>{S(!0),w(null);try{let e=await ct(`/api/settings`,{llm_model:m.trim(),llm_base_url:g.trim(),...y.trim()?{llm_api_key:y.trim()}:{}});b(``),w(e.llm_probe||null),e.llm_probe?.online?Z.success(`模型已切换(探针 ${e.llm_probe.latency_ms}ms:${e.llm_probe.reply||`ok`})`):e.note&&Z.warning(`已保存,但探针未通过`,{description:e.note}),se()}catch(e){Z.error(String(e.message))}finally{S(!1)}},B=async()=>{M(!0);try{if(await ct(`/api/settings`,{access_token:k}),k.trim()){if(!(await fetch(`/api/auth/login`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({token:k.trim()})})).ok)throw Error(`已保存但自动登录失败,刷新后输入令牌进入`);Z.success(`访问令牌已启用(当前浏览器已自动登录)`)}else Z.success(`访问令牌已关闭(恢复开放访问)`);A(``),se()}catch(e){Z.error(String(e.message))}finally{M(!1)}},V=async()=>{O(!0);try{await ct(`/api/settings`,{scene_profile:T}),Z.success(T.trim()?`场景画像已保存,对全部助手即时生效(新对话起)`:`场景画像已清空(不再注入)`),se()}catch(e){Z.error(String(e.message))}finally{O(!1)}},H=async()=>{ie(!0);try{await ct(`/api/settings`,{guard:{deny:N,ro:F,sudo_u_l2:L}}),Z.success(`守护栏已更新(危险规则 ${N.length} 条 · 白名单 ${F.length} 命令),即时生效`),oe(null),se()}catch(e){Z.error(String(e.message))}finally{ie(!1)}};return(0,K.jsxs)(`div`,{className:`h-full overflow-auto p-5`,children:[(0,K.jsxs)(`div`,{className:`mb-4`,children:[(0,K.jsxs)(`h1`,{className:`flex items-center gap-2 text-lg font-bold`,children:[(0,K.jsx)(kg,{className:`h-5 w-5 text-primary`}),`系统设置`]}),(0,K.jsx)(`p`,{className:`mt-0.5 text-xs text-muted-foreground`,children:`平台全局配置 · 修改保存后即时生效(无需重启)· 运行时配置优先于 .env`})]}),(0,K.jsxs)(vO,{defaultValue:`arm`,className:`max-w-2xl`,children:[(0,K.jsxs)(bO,{children:[(0,K.jsxs)(xO,{value:`arm`,className:`text-xs`,children:[(0,K.jsx)(Tg,{className:`mr-1 h-3.5 w-3.5`}),`ARM 源`,n&&(0,K.jsx)(`span`,{className:`ml-1 h-1.5 w-1.5 rounded-full ${n.online?`bg-emerald-500`:`bg-amber-500`}`})]}),(0,K.jsxs)(xO,{value:`llm`,className:`text-xs`,children:[(0,K.jsx)(th,{className:`mr-1 h-3.5 w-3.5`}),`LLM 模型服务`]}),(0,K.jsxs)(xO,{value:`scene`,className:`text-xs`,children:[(0,K.jsx)(Lh,{className:`mr-1 h-3.5 w-3.5`}),`场景画像`,e&&e.scene.length>0&&(0,K.jsx)(`span`,{className:`ml-1 h-1.5 w-1.5 rounded-full bg-emerald-500`})]}),(0,K.jsxs)(xO,{value:`auth`,className:`text-xs`,children:[(0,K.jsx)(tg,{className:`mr-1 h-3.5 w-3.5`}),`访问安全`,e?.auth.enabled&&(0,K.jsx)(`span`,{className:`ml-1 h-1.5 w-1.5 rounded-full bg-emerald-500`})]}),(0,K.jsxs)(xO,{value:`guard`,className:`text-xs`,children:[(0,K.jsx)(Fg,{className:`mr-1 h-3.5 w-3.5`}),`守护栏`,(0,K.jsxs)(`span`,{className:`ml-1 text-[9px] text-muted-foreground`,children:[N.length,`规`]})]})]}),(0,K.jsx)(SO,{value:`arm`,className:`mt-3`,children:(0,K.jsxs)(bm,{className:`mb-3 max-w-2xl`,children:[(0,K.jsxs)(xm,{className:`pb-2`,children:[(0,K.jsxs)(Sm,{className:`flex items-center gap-2 text-sm`,children:[(0,K.jsx)(Tg,{className:`h-4 w-4 text-primary`}),`ARM 源`,n&&(0,K.jsx)(J,{variant:`outline`,className:`text-[10px] ${n.online?`text-emerald-400`:`text-amber-400`}`,children:n.online?`在线 · ${n.latency_ms}ms`:`不可达(回落 MCP/本地库)`})]}),(0,K.jsx)(`p`,{className:`text-[11px] leading-relaxed text-muted-foreground`,children:`ARM 是可私有化部署的资源管理系统(助手档案 + 知识库):在此切换源(如 本地开发版 → 客户私有站点), 检索/下载/同步全部即时跟随;助手已下载的本地档案不受影响。`})]}),(0,K.jsxs)(Cm,{className:`space-y-3`,children:[e&&!e.arm.token_set&&e.arm.token_source===`none`&&(0,K.jsxs)(`div`,{className:`flex items-start gap-2 rounded-md border border-amber-500/40 bg-amber-500/10 p-2.5 text-[11px] leading-relaxed text-amber-300`,children:[(0,K.jsx)(`span`,{className:`shrink-0`,children:`🔑`}),(0,K.jsxs)(`div`,{className:`flex-1`,children:[`尚未配置访问令牌——匿名仅能浏览目录,`,(0,K.jsx)(`b`,{children:`下载 / 上岗 / 新建 / 经验回流`}),`等操作会被 ARM 拒绝(401/403)。 请登录 ARM 站点生成访问令牌(arm_pat_… 开头),粘贴到下方「访问令牌」并保存。`,(0,K.jsx)(`a`,{href:e.arm.api_base,target:`_blank`,rel:`noreferrer`,className:`ml-1 underline underline-offset-2 hover:text-amber-200`,children:`打开 ARM 生成令牌 →`})]})]}),(0,K.jsxs)(`div`,{className:`space-y-1`,children:[(0,K.jsxs)(m_,{className:`flex items-center gap-2 text-xs`,children:[`站点地址(REST API 根地址)`,e&&(0,K.jsx)(J,{variant:`outline`,className:`h-4 px-1 text-[9px]`,children:e.arm.api_base_runtime?`运行时配置`:`默认(${(e.arm.default_base||``).replace(/^https?:\/\//,``)})`})]}),(0,K.jsx)(p_,{value:i,onChange:e=>a(e.target.value),placeholder:`如 http://localhost:3001 或 https://arm.customer.com`,className:`font-mono text-xs`})]}),(0,K.jsxs)(`div`,{className:`space-y-1`,children:[(0,K.jsx)(m_,{className:`text-xs`,children:`MCP 端点(高级,留空自动 = 站点地址 + /api/mcp)`}),(0,K.jsx)(p_,{value:o,onChange:e=>s(e.target.value),placeholder:e?.arm.mcp_url||`/api/mcp`,className:`font-mono text-xs`})]}),(0,K.jsxs)(`div`,{className:`space-y-1`,children:[(0,K.jsxs)(m_,{className:`flex items-center gap-2 text-xs`,children:[`访问令牌(Token)`,e&&(0,K.jsx)(J,{variant:`outline`,className:`h-4 px-1 text-[9px]`,children:e.arm.token_set?`${e.arm.token_masked} · ${e.arm.token_source}`:`未配置(${e.arm.token_source===`pat`?`回落 ~/.arm PAT`:`匿名/只读`})`})]}),(0,K.jsx)(p_,{type:`password`,value:c,onChange:e=>l(e.target.value),placeholder:e?.arm.token_set?`已配置(留空保持不变)`:`arm_pat_…`,className:`font-mono text-xs`})]}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)(Y,{size:`sm`,className:`text-xs`,disabled:u,onClick:ce,children:u?`保存中…`:`保存并测试连接`}),f&&(0,K.jsx)(`span`,{className:`flex items-center gap-1 text-[11px] ${f.online?`text-emerald-400`:`text-amber-400`}`,children:f.online?(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(ph,{className:`h-3.5 w-3.5`}),`连通 `,f.latency_ms,`ms,源已切换`]}):(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(hh,{className:`h-3.5 w-3.5`}),`不可达:`,f.error]})})]})]})]})}),(0,K.jsx)(SO,{value:`llm`,className:`mt-3`,children:(0,K.jsxs)(bm,{className:`mb-3 max-w-2xl`,children:[(0,K.jsxs)(xm,{className:`pb-2`,children:[(0,K.jsxs)(Sm,{className:`flex items-center gap-2 text-sm`,children:[(0,K.jsx)(th,{className:`h-4 w-4 text-primary`}),`LLM 模型服务`,e&&(0,K.jsx)(J,{variant:`outline`,className:`text-[10px]`,children:e.llm.model})]}),(0,K.jsx)(`p`,{className:`text-[11px] leading-relaxed text-muted-foreground`,children:`OpenAI 兼容端点:缺省公司内网 bifrost 网关(内网开箱可用),可切换模型 / 自建网关 / 公有云端点。保存后新对话即时使用新模型,应用失败自动回滚。`})]}),(0,K.jsxs)(Cm,{className:`space-y-3`,children:[(0,K.jsxs)(`div`,{className:`space-y-1`,children:[(0,K.jsxs)(m_,{className:`flex items-center gap-2 text-xs`,children:[`模型`,e&&(0,K.jsx)(J,{variant:`outline`,className:`h-4 px-1 text-[9px]`,children:e.llm.model_runtime?`运行时配置`:`默认(.env)`})]}),(0,K.jsx)(p_,{value:m,onChange:e=>h(e.target.value),list:`llm-catalog`,placeholder:`如 def / glm-5.3 / 自定义名称`,className:`font-mono text-xs`}),(0,K.jsx)(`datalist`,{id:`llm-catalog`,children:(e?.llm.catalog||[]).map(e=>(0,K.jsx)(`option`,{value:e},e))})]}),(0,K.jsxs)(`div`,{className:`space-y-1`,children:[(0,K.jsxs)(m_,{className:`text-xs`,children:[`端点地址(留空 = `,e?.llm.default_base||`默认内网 bifrost`,`)`]}),(0,K.jsx)(p_,{value:g,onChange:e=>_(e.target.value),placeholder:`https://your-gateway/v1(OpenAI 兼容)`,className:`font-mono text-xs`})]}),(0,K.jsxs)(`div`,{className:`space-y-1`,children:[(0,K.jsxs)(m_,{className:`flex items-center gap-2 text-xs`,children:[`API Key`,e&&(0,K.jsx)(J,{variant:`outline`,className:`h-4 px-1 text-[9px]`,children:e.llm.key_set?`${e.llm.key_masked} · ${e.llm.key_source}`:`未配置`})]}),(0,K.jsx)(p_,{type:`password`,value:y,onChange:e=>b(e.target.value),placeholder:e?.llm.key_set?`已配置(留空保持不变)`:`sk-… / api key`,className:`font-mono text-xs`})]}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)(Y,{size:`sm`,className:`text-xs`,disabled:x,onClick:le,children:x?`切换中…`:`保存并测试模型`}),C&&(0,K.jsx)(`span`,{className:`flex items-center gap-1 text-[11px] ${C.online?`text-emerald-400`:`text-amber-400`}`,children:C.online?(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(ph,{className:`h-3.5 w-3.5`}),`探针通过 `,C.latency_ms,`ms:`,C.reply]}):(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(hh,{className:`h-3.5 w-3.5`}),`未通过:`,C.error]})})]})]})]})}),(0,K.jsx)(SO,{value:`scene`,className:`mt-3`,children:(0,K.jsxs)(bm,{className:`mb-3 max-w-2xl`,children:[(0,K.jsxs)(xm,{className:`pb-2`,children:[(0,K.jsxs)(Sm,{className:`flex items-center gap-2 text-sm`,children:[(0,K.jsx)(Lh,{className:`h-4 w-4 text-primary`}),`场景画像`,e&&(0,K.jsx)(J,{variant:`outline`,className:`text-[10px] ${e.scene.length?`text-emerald-400`:``}`,children:e.scene.length?`已启用 · ${e.scene.length} 字`:`未配置(不注入)`})]}),(0,K.jsxs)(`p`,{className:`text-[11px] leading-relaxed text-muted-foreground`,children:[`平台级、全局一份的使用方场景描述(团队环境 / 系统清单 / 规范 / 联系人),作为常驻事实注入`,(0,K.jsx)(`b`,{children:`所有助手`}),`的上下文—— 助手不必每次重新探索环境。与知识检索互补(常驻事实 vs 按需检索)。⚠ 不放凭据:写"凭据在哪、找谁要"即可。`]})]}),(0,K.jsxs)(Cm,{className:`space-y-2`,children:[(0,K.jsx)(`textarea`,{value:T,onChange:e=>E(e.target.value),spellCheck:!1,rows:8,placeholder:`例如:
100
+ `||t===`\r`?(s(),r=2):i+=t),r===3&&i===`!--`&&(r=4,o=o[0])}return s(),o}(e)),t),arguments,[])).length>1?t:t[0]}var sO=oO.bind(v.createElement),cO=class extends v.Component{state={err:null};static getDerivedStateFromError(e){return{err:String(e?.message||e)}}componentDidCatch(e){try{this.props.onError?.(String(e?.message||e))}catch{}}render(){return this.state.err?(0,K.jsxs)(`div`,{className:`p-3 text-[11px] leading-relaxed text-red-400`,children:[`面板运行错误:`,this.state.err,(0,K.jsx)(`br`,{}),`可在「定制工作台」中修正代码后重新发布。`]}):this.props.children}};function lO(e){return Function(`React`,`html`,`useState`,`useEffect`,`useRef`,`useMemo`,`"use strict";\n${e}\n;if (typeof Panel !== "function") throw new Error("插件代码必须定义 function Panel(props)");\nreturn Panel;`)(v,sO,v.useState,v.useEffect,v.useRef,v.useMemo)}function uO(e,t,n){if(e)try{fetch(`/api/panel-error`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({...e,kind:t,message:n})}).catch(()=>{})}catch{}}function dO({code:e,data:t,meta:n}){let r=n?.agentId,i=n?.panelId,a=n?.pluginId,o=(0,v.useMemo)(()=>{let t={agentId:r,panelId:i,pluginId:a};try{return lO(e)}catch(e){return uO(t,`compile`,String(e.message)),()=>(0,K.jsxs)(`div`,{className:`p-3 text-[11px] text-red-400`,children:[`编译失败:`,String(e.message)]})}},[e,r,i,a]);return(0,K.jsx)(cO,{onError:e=>uO(n,`runtime`,e),children:(0,K.jsx)(o,{...t})})}var fO=12;function pO({dsl:e,renderPanel:t,renderDialog:n,renderPlaceholder:r,edit:i,className:a}){let o=(0,v.useRef)(null),s=(0,v.useRef)(null),c=e.panels.reduce((e,t)=>Math.max(e,(t.grid?.y||1)+(t.grid?.h||1)-1),1),l=()=>{let e=o.current?.getBoundingClientRect();return{col:e?(e.width+fO)/12:100,row:e?(e.height+fO)/c:178}},u=(t,n,r)=>{if(!i||t.button!==0)return;t.stopPropagation();let a=e.panels[n].grid||{x:1,y:1,w:6,h:1};s.current={i:n,mode:r,sx:t.clientX,sy:t.clientY,g:{...a},moved:!1};try{t.currentTarget.setPointerCapture(t.pointerId)}catch{}},d=e=>{let t=s.current;if(!i||!t)return;let n=e.clientX-t.sx,r=e.clientY-t.sy;if(!t.moved&&Math.abs(n)<4&&Math.abs(r)<4)return;t.moved=!0;let{col:a,row:o}=l(),c=Math.round(n/a),u=Math.round(r/o);t.mode===`move`?i.onGrid(t.i,{x:Math.min(Math.max(1,t.g.x+c),12-t.g.w+1),y:Math.max(1,t.g.y+u)}):i.onGrid(t.i,{w:Math.min(Math.max(1,t.g.w+c),12-t.g.x+1),h:Math.min(Math.max(1,t.g.h+u),12)})},f=()=>{setTimeout(()=>{s.current=null},0)};return(0,K.jsx)(`div`,{ref:o,className:it(`grid gap-3`,i&&`touch-none select-none`,a),style:{gridTemplateColumns:`repeat(12, minmax(0, 1fr))`,gridTemplateRows:`repeat(${c}, minmax(120px, 1fr))`},onPointerDown:()=>{i&&i.onSelect(null)},children:e.panels.map((e,a)=>{let o=e.grid||{x:1,y:1,w:6,h:1},s=Math.round(o.w/12*100),c=e.type===`agent_dialog`?n?n(e):null:e.type===`placeholder`?r?r(e):null:t(e);return(0,K.jsxs)(`div`,{style:{gridColumn:`${o.x} / span ${o.w}`,gridRow:`${o.y} / span ${o.h}`},className:it(`relative flex min-h-0 flex-col overflow-hidden rounded-lg border bg-card`,i?i.sel===a?`border-primary ring-2 ring-primary/50`:`border-border hover:border-primary/50`:`border-border`,i&&`cursor-grab active:cursor-grabbing`),onPointerDown:e=>{i&&(e.stopPropagation(),i.onSelect(a),u(e,a,`move`))},onPointerMove:d,onPointerUp:f,onPointerCancel:f,children:[i&&(0,K.jsxs)(`div`,{className:`pointer-events-none absolute inset-x-0 top-0 z-10 flex items-center gap-1.5 border-b bg-background/85 px-2 py-1 text-[10px] backdrop-blur-sm`,children:[(0,K.jsx)(`span`,{className:`font-medium`,children:e.title}),(0,K.jsx)(J,{variant:`secondary`,className:`h-4 px-1 text-[9px]`,children:e.panel||e.type}),(0,K.jsxs)(`span`,{className:`ml-auto font-mono text-muted-foreground`,children:[s,`%宽·`,o.h,`行`]})]}),(0,K.jsx)(`div`,{className:it(`min-h-0 flex-1 overflow-auto`,i&&`pointer-events-none pt-4`),children:c}),i&&(0,K.jsx)(`span`,{onPointerDown:e=>u(e,a,`resize`),onPointerMove:d,onPointerUp:f,onPointerCancel:f,className:`absolute bottom-0 right-0 z-10 h-4 w-4 cursor-nwse-resize rounded-br-md border-b border-r border-primary/60 bg-primary/25 hover:bg-primary/50`,title:`拖拽调跨列/跨行(当前 ${s}% 宽)`,children:(0,K.jsx)(rg,{className:`h-2.5 w-2.5 translate-x-[3px] translate-y-[3px] text-primary`})})]},e.id)})})}function mO(){return(0,K.jsxs)(`div`,{className:`relative mb-1 h-4 select-none text-[9px] text-muted-foreground`,children:[(0,K.jsx)(`div`,{className:`grid h-full grid-cols-12`,children:[...Array(12)].map((e,t)=>(0,K.jsx)(`div`,{className:`border-l border-border/60 pl-0.5 pt-0.5 font-mono`,children:t+1},t))}),[25,50,75].map(e=>(0,K.jsxs)(`span`,{className:`absolute -top-0 font-mono`,style:{left:`${e}%`},children:[e,`%`]},e))]})}function hO({open:e,onOpenChange:t,onPick:n}){let[r,i]=(0,v.useState)(null),[a,o]=(0,v.useState)(!1),[s,c]=(0,v.useState)(``),l=e=>{o(!0),c(``),ot(`/api/fs/dirs${e?`?path=${encodeURIComponent(e)}`:``}`).then(e=>i(e)).catch(e=>c(String(e.message))).finally(()=>o(!1))};return(0,v.useEffect)(()=>{e&&!r&&l()},[e]),(0,K.jsx)(a_,{open:e,onOpenChange:t,children:(0,K.jsxs)(c_,{className:`max-w-md`,children:[(0,K.jsx)(l_,{children:(0,K.jsx)(d_,{children:`选择工作区目录`})}),(0,K.jsxs)(`div`,{className:`flex items-center gap-1.5`,children:[(0,K.jsxs)(Y,{size:`sm`,variant:`outline`,className:`h-7 gap-1 px-2 text-[11px]`,disabled:!r?.parent,onClick:()=>r?.parent&&l(r.parent),title:`上级目录`,children:[(0,K.jsx)(Zm,{className:`h-3 w-3`}),`上级`]}),(0,K.jsxs)(Y,{size:`sm`,variant:`outline`,className:`h-7 gap-1 px-2 text-[11px]`,onClick:()=>l(),children:[(0,K.jsx)(zh,{className:`h-3 w-3`}),`主目录`]}),(0,K.jsx)(`span`,{className:`min-w-0 flex-1 truncate rounded-md border bg-muted/40 px-2 py-1.5 font-mono text-[11px] text-muted-foreground`,title:r?.path,children:r?.path||`…`})]}),(0,K.jsxs)(eO,{className:`h-64 rounded-md border`,children:[a&&(0,K.jsxs)(`div`,{className:`flex h-full items-center justify-center gap-2 text-xs text-muted-foreground`,children:[(0,K.jsx)($h,{className:`h-4 w-4 animate-spin`}),`读取中…`]}),!a&&s&&(0,K.jsx)(`div`,{className:`p-3 text-xs text-red-400`,children:s}),!a&&!s&&r&&r.dirs.length===0&&(0,K.jsx)(`div`,{className:`p-3 text-xs text-muted-foreground`,children:`此目录下没有子目录——可直接点「选择当前目录」。`}),!a&&!s&&r&&r.dirs.map(e=>(0,K.jsxs)(`button`,{onClick:()=>l(`${r.path}/${e}`),className:`flex w-full items-center gap-2 px-3 py-1.5 text-left text-xs hover:bg-accent`,children:[(0,K.jsx)(Fh,{className:`h-3.5 w-3.5 shrink-0 text-muted-foreground`}),(0,K.jsx)(`span`,{className:`truncate`,children:e})]},e))]}),(0,K.jsxs)(u_,{children:[(0,K.jsx)(Y,{variant:`outline`,onClick:()=>t(!1),children:`取消`}),(0,K.jsxs)(Y,{className:`gap-1`,disabled:!r||a,onClick:()=>{r&&(n(r.path),t(!1))},children:[(0,K.jsx)(rh,{className:`h-3.5 w-3.5`}),`选择当前目录`]})]})]})})}function gO({agentId:e,onName:t,onEdit:n}){let[r,i]=(0,v.useState)(null),[a,o]=(0,v.useState)(null),[s,c]=(0,v.useState)(null),[l,u]=(0,v.useState)([]),[d,f]=(0,v.useState)(null),[p,m]=(0,v.useState)(2),[h,g]=(0,v.useState)(null),[_,y]=(0,v.useState)(!1),[b,x]=(0,v.useState)(``),[S,C]=(0,v.useState)(``),[w,T]=(0,v.useState)(!1),[E,D]=(0,v.useState)(!1),[O,k]=(0,v.useState)(null),[A,j]=(0,v.useState)(!1),M=(0,v.useMemo)(()=>h?.workspaces.find(e=>e.id===h.current)||null,[h]),N=M?.id||`default`,P=(0,v.useMemo)(()=>`chat-${e}-${N}`,[e,N]),F=()=>ot(`/api/state`).then(c).catch(()=>{}),I=()=>ot(`/api/workspaces?agent_id=${e}`).then(g).catch(()=>{});(0,v.useEffect)(()=>{ot(`/api/workbench?agent_id=${e}`).then(e=>{i(e.dsl),e.dsl&&t(e.dsl.workbench)}),ot(`/api/deployment?agent_id=${e}`).then(e=>{o(e.deployment),m({L0:0,L1:1,L2:2,L3:3}[e.deployment?.default_autonomy||`L2`]??2)}),ot(`/api/panels?with_code=1`).then(e=>u(e.plugins||[])),I(),F();let n=setInterval(F,5e3);return()=>clearInterval(n)},[e]);let L=async t=>{try{g(await st(`/api/workspaces/select`,{agent_id:e,ws_id:t}))}catch(e){Z.error(String(e.message))}},R=async()=>{D(!0);try{let t=await st(`/api/workspaces`,{agent_id:e,name:b||void 0,...S?{path:S}:{}});g(t),y(!1),x(``),C(``),Z.success(`工作区已创建${S?`(登记外部目录)`:``}`),await L(t.workspaces[t.workspaces.length-1].id)}catch(e){Z.error(String(e.message))}finally{D(!1)}},ee=async()=>{if(O)try{g(await lt(`/api/workspaces/${O.id}?agent_id=${e}`,{purge:A})),Z.success(`工作区已删除${A?`(目录已清除)`:`(仅移除登记)`}`),k(null),j(!1)}catch(e){Z.error(String(e.message))}},te=(0,v.useMemo)(()=>r?.panels||[],[r]).filter(e=>e.type===`custom`||e.type===`custom_panel`).map(e=>({panel:e,code:e.type===`custom`?e.code||``:l.find(t=>t.id===e.panel)?.code||``})).filter(e=>e.code),z=t=>({devices:s?.devices||[],alarms:s?.alarms||[],kpi:s?.kpi||{},work_orders:s?.work_orders||[],inspections:s?.inspections||{},selected:d,onSelect:f,agentId:e,store:mt(e,N),runAction:(n,r)=>ht(e,String(t?.id||``),n,r),params:{...t?.params||{},agentId:e,wsId:N}});return!r||!s?(0,K.jsx)(`div`,{className:`flex h-full items-center justify-center text-sm text-muted-foreground`,children:`工作台加载中…`}):(0,K.jsxs)(`div`,{className:`flex h-full flex-col gap-2 overflow-hidden px-4 py-2.5`,children:[(0,K.jsx)(`h1`,{className:`sr-only`,children:r.workbench}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2 text-[11px]`,children:[(0,K.jsx)(J,{variant:`secondary`,className:`h-5 shrink-0 text-[10px]`,children:r.version}),te.length>0&&(0,K.jsxs)(J,{variant:`outline`,className:`h-5 shrink-0 text-[10px] text-violet-400 border-violet-500/40`,children:[(0,K.jsx)(pg,{className:`mr-0.5 h-2.5 w-2.5`}),`插件 ×`,te.length]}),(0,K.jsxs)(`span`,{className:`shrink-0 text-muted-foreground`,children:[a?.name,` · 工具 `,a?.toolset.length,` 个`]}),M&&(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(jh,{className:`h-3 w-3 shrink-0 text-muted-foreground`}),(0,K.jsx)(`span`,{className:`min-w-0 flex-1 truncate font-mono text-muted-foreground`,title:M.path,children:M.path}),(0,K.jsx)(`span`,{className:`shrink-0 text-[10px] text-muted-foreground`,children:`(exec 工作目录 · 数据与文件随工作区隔离)`})]}),(0,K.jsxs)(`div`,{className:`ml-auto flex items-center gap-1.5`,children:[(0,K.jsx)(qh,{className:`h-3.5 w-3.5 text-muted-foreground`}),(0,K.jsxs)(h_,{value:N,onValueChange:L,children:[(0,K.jsx)(__,{className:`h-8 w-52 text-xs`,title:M?.path,children:(0,K.jsx)(g_,{children:(0,K.jsx)(`span`,{className:`truncate`,children:M?`${M.name}${M.external?`(外部)`:``}`:`默认工作区`})})}),(0,K.jsx)(v_,{children:(h?.workspaces||[]).map(e=>(0,K.jsx)(y_,{value:e.id,className:`text-xs`,children:(0,K.jsxs)(`span`,{className:`max-w-64 truncate`,title:e.path,children:[e.name,e.external?` · 外部目录`:``,e.id===h?.current?` ✓`:``]})},e.id))})]}),(0,K.jsxs)(Y,{size:`sm`,variant:`outline`,className:`h-8 gap-1 text-xs`,onClick:()=>y(!0),title:`新建工作区(默认目录或自定义路径)`,children:[(0,K.jsx)(Nh,{className:`h-3.5 w-3.5`}),`新建`]}),M&&M.id!=="default"&&(0,K.jsx)(Y,{size:`sm`,variant:`ghost`,className:`h-8 w-8 p-0 text-muted-foreground`,onClick:()=>k(M),title:`删除当前工作区`,children:(0,K.jsx)(qg,{className:`h-3.5 w-3.5`})}),(0,K.jsxs)(Y,{size:`sm`,variant:`outline`,className:`h-8 gap-1 text-xs`,onClick:n,children:[(0,K.jsx)(Dg,{className:`h-3.5 w-3.5`}),`编辑布局`]})]})]}),(0,K.jsx)(`div`,{className:`relative min-h-0 flex-1`,children:(0,K.jsx)(pO,{className:`absolute inset-0 overflow-auto p-0.5`,dsl:r,renderPanel:t=>{let n=te.find(e=>e.panel.id===t.id);return n?(0,K.jsx)(dO,{code:n.code,data:z(t),meta:{agentId:e,panelId:t.id,pluginId:t.panel}},`${t.id}:${N}`):null},renderDialog:()=>(0,K.jsx)(rO,{agentId:e,sessionId:P,wsId:N,injectedDevice:d,autonomy:p,onAutonomy:m},`${e}:${N}`),renderPlaceholder:()=>(0,K.jsx)(`div`,{className:`flex h-full items-center justify-center p-4 text-center text-[11px] text-muted-foreground`,children:`空区块——到「编辑布局」添加插件或让 AI 定制`})})}),(0,K.jsx)(a_,{open:_,onOpenChange:y,children:(0,K.jsxs)(c_,{children:[(0,K.jsx)(l_,{children:(0,K.jsx)(d_,{children:`新建工作区`})}),(0,K.jsxs)(`div`,{className:`space-y-3`,children:[(0,K.jsxs)(`div`,{className:`space-y-1`,children:[(0,K.jsx)(m_,{className:`text-xs`,children:`名称`}),(0,K.jsx)(p_,{value:b,onChange:e=>x(e.target.value),placeholder:`如:产线B改造`,className:`text-xs`})]}),(0,K.jsxs)(`div`,{className:`space-y-1`,children:[(0,K.jsx)(m_,{className:`text-xs`,children:`自定义目录(可选,留空则在平台 workspace 目录下动态新增)`}),(0,K.jsxs)(`div`,{className:`flex gap-1.5`,children:[(0,K.jsx)(p_,{value:S,onChange:e=>C(e.target.value),placeholder:`/Users/you/projects/line-b 或点浏览选择`,className:`font-mono text-xs`}),(0,K.jsxs)(Y,{size:`sm`,variant:`outline`,className:`h-8 shrink-0 gap-1 text-xs`,onClick:()=>T(!0),children:[(0,K.jsx)(jh,{className:`h-3.5 w-3.5`}),`浏览…`]})]}),(0,K.jsx)(`p`,{className:`text-[10px] text-amber-400`,children:`⚠ 助手将能读写该目录(exec 工作目录即此处);目录须已存在,平台不会在其中写入数据库文件。`})]})]}),(0,K.jsxs)(u_,{children:[(0,K.jsx)(Y,{variant:`outline`,disabled:E,onClick:()=>y(!1),children:`取消`}),(0,K.jsx)(Y,{disabled:E,onClick:R,children:E?`创建中…`:`创建并切换`})]}),(0,K.jsx)(hO,{open:w,onOpenChange:T,onPick:e=>C(e)})]})}),(0,K.jsx)(a_,{open:!!O,onOpenChange:e=>{e||(k(null),j(!1))},children:(0,K.jsxs)(c_,{children:[(0,K.jsx)(l_,{children:(0,K.jsxs)(d_,{children:[`删除工作区 · `,O?.name]})}),(0,K.jsxs)(`div`,{className:`space-y-2 text-xs`,children:[(0,K.jsx)(`p`,{className:`font-mono text-[11px] text-muted-foreground`,children:O?.path}),O?.external?(0,K.jsxs)(`p`,{children:[`外部目录工作区:仅移除登记,`,(0,K.jsx)(`b`,{children:`不删除`}),`你的文件;该工作区的数据集库将一并删除。`]}):(0,K.jsxs)(`label`,{className:`flex items-start gap-2 rounded-md border border-red-500/30 bg-red-500/5 p-2.5`,children:[(0,K.jsx)(i_,{checked:A,onCheckedChange:e=>j(!!e)}),(0,K.jsx)(`span`,{children:`同时删除平台目录下的工作区文件夹(数据集库始终删除)`})]})]}),(0,K.jsxs)(u_,{children:[(0,K.jsx)(Y,{variant:`outline`,onClick:()=>k(null),children:`取消`}),(0,K.jsx)(Y,{variant:`destructive`,onClick:ee,children:`确认删除`})]})]})})]})}function _O({className:e,orientation:t=`horizontal`,decorative:n=!0,...r}){return(0,K.jsx)(Fp,{"data-slot":`separator`,decorative:n,orientation:t,className:mn(`shrink-0 bg-border data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-px`,e),...r})}function vO({className:e,orientation:t=`horizontal`,...n}){return(0,K.jsx)(lm,{"data-slot":`tabs`,"data-orientation":t,orientation:t,className:mn(`group/tabs flex gap-2 data-[orientation=horizontal]:flex-col`,e),...n})}var yO=yt(`group/tabs-list inline-flex w-fit items-center justify-center rounded-lg p-[3px] text-muted-foreground group-data-[orientation=horizontal]/tabs:h-9 group-data-[orientation=vertical]/tabs:h-fit group-data-[orientation=vertical]/tabs:flex-col data-[variant=line]:rounded-none`,{variants:{variant:{default:`bg-muted`,line:`gap-1 bg-transparent`}},defaultVariants:{variant:`default`}});function bO({className:e,variant:t=`default`,...n}){return(0,K.jsx)(dm,{"data-slot":`tabs-list`,"data-variant":t,className:mn(yO({variant:t}),e),...n})}function xO({className:e,...t}){return(0,K.jsx)(pm,{"data-slot":`tabs-trigger`,className:mn(`relative inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-2 py-1 text-sm font-medium whitespace-nowrap text-foreground/60 transition-all group-data-[orientation=vertical]/tabs:w-full group-data-[orientation=vertical]/tabs:justify-start hover:text-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 focus-visible:outline-1 focus-visible:outline-ring disabled:pointer-events-none disabled:opacity-50 group-data-[variant=default]/tabs-list:data-[state=active]:shadow-sm group-data-[variant=line]/tabs-list:data-[state=active]:shadow-none dark:text-muted-foreground dark:hover:text-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4`,`group-data-[variant=line]/tabs-list:bg-transparent group-data-[variant=line]/tabs-list:data-[state=active]:bg-transparent dark:group-data-[variant=line]/tabs-list:data-[state=active]:border-transparent dark:group-data-[variant=line]/tabs-list:data-[state=active]:bg-transparent`,`data-[state=active]:bg-background data-[state=active]:text-foreground dark:data-[state=active]:border-input dark:data-[state=active]:bg-input/30 dark:data-[state=active]:text-foreground`,`after:absolute after:bg-foreground after:opacity-0 after:transition-opacity group-data-[orientation=horizontal]/tabs:after:inset-x-0 group-data-[orientation=horizontal]/tabs:after:bottom-[-5px] group-data-[orientation=horizontal]/tabs:after:h-0.5 group-data-[orientation=vertical]/tabs:after:inset-y-0 group-data-[orientation=vertical]/tabs:after:-right-1 group-data-[orientation=vertical]/tabs:after:w-0.5 group-data-[variant=line]/tabs-list:data-[state=active]:after:opacity-100`,e),...t})}function SO({className:e,...t}){return(0,K.jsx)(hm,{"data-slot":`tabs-content`,className:mn(`flex-1 outline-none`,e),...t})}function CO({...e}){return(0,K.jsx)(gd,{"data-slot":`dropdown-menu`,...e})}function wO({...e}){return(0,K.jsx)(vd,{"data-slot":`dropdown-menu-trigger`,...e})}function TO({className:e,sideOffset:t=4,...n}){return(0,K.jsx)(yd,{children:(0,K.jsx)(xd,{"data-slot":`dropdown-menu-content`,sideOffset:t,className:mn(`z-50 min-w-36 overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95`,e),...n})})}function EO({className:e,...t}){return(0,K.jsx)(Sd,{"data-slot":`dropdown-menu-item`,className:mn(`relative flex cursor-pointer select-none items-center gap-2 rounded-sm px-2 py-1.5 text-xs outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:h-3.5 [&_svg]:w-3.5 [&_svg]:shrink-0`,e),...t})}function DO({className:e,...t}){return(0,K.jsx)(Cd,{"data-slot":`dropdown-menu-separator`,className:mn(`-mx-1 my-1 h-px bg-border`,e),...t})}async function OO(e,t){let n=e.usage.length?`插件「${e.name}」被 ${e.usage.length} 处引用,删除将从这些工作台摘除该面板。确认删除?`:`删除插件「${e.name}」?`;if(window.confirm(n))try{await lt(`/api/panels`,{id:e.id,force:!0}),Z.success(`已删除`),t()}catch(e){Z.error(String(e.message))}}function kO({target:e,onClose:t,agents:n}){let[r,i]=(0,v.useState)(null),[a,o]=(0,v.useState)(``),[s,c]=(0,v.useState)(!0),[l,u]=(0,v.useState)(!1);(0,v.useEffect)(()=>{if(!e){i(null);return}let n=e.type===`panel`?`id=${encodeURIComponent(e.id||``)}`:`agentId=${encodeURIComponent(e.agentId||``)}`;ot(`/api/assets/preview?type=${e.type}&${n}`).then(e=>{i(e),o(e.name)}).catch(e=>{Z.error(String(e.message)),t()})},[e]);let d=async()=>{if(e){u(!0);try{let n=await st(`/api/assets/share`,{type:e.type,id:e.id,agentId:e.agentId,name:a,bind_agent:s&&e.agentId?e.agentId:void 0}),i=r?.manifest.requires.apis.length||0,o=r?.manifest.requires.actions.length||0;Z.success(`已发布 ${n.name}@${n.version}${n.bound?`,已绑定到助手`:``}`,{description:`外部 API ×${i} · 交互脚本 ×${o}${o?`(命令全文已在 ARM 资产包 SKILL.md 留档)`:``}`}),t()}catch(e){Z.error(String(e.message))}finally{u(!1)}}};if(!e)return null;let f=r?.manifest.requires;return(0,K.jsx)(a_,{open:!!e,onOpenChange:e=>{!e&&!l&&t()},children:(0,K.jsxs)(c_,{children:[(0,K.jsx)(l_,{children:(0,K.jsxs)(d_,{className:`flex items-center gap-2`,children:[(0,K.jsx)(_h,{className:`h-4 w-4 text-primary`}),`发布为 UI 资产 · `,e.title]})}),(0,K.jsx)(eO,{className:`max-h-96`,children:(0,K.jsxs)(`div`,{className:`space-y-3 pr-2 text-xs`,children:[(0,K.jsxs)(`div`,{className:`space-y-1`,children:[(0,K.jsx)(m_,{className:`text-xs`,children:`资产名(全局唯一锚,同名发布追加新版本)`}),(0,K.jsx)(p_,{value:a,onChange:e=>o(e.target.value),className:`font-mono text-xs`})]}),r&&(0,K.jsxs)(K.Fragment,{children:[(0,K.jsxs)(`div`,{className:`rounded-md border bg-muted/30 p-2.5`,children:[(0,K.jsx)(`div`,{className:`font-medium`,children:`包含内容`}),(0,K.jsxs)(`div`,{className:`mt-1 text-muted-foreground`,children:[`面板插件:`,r.manifest.provides.panels.join(`、`)||`无`,(0,K.jsx)(`br`,{}),`数据集 schema:`,r.manifest.provides.collections.join(`、`)||`无`,`(仅建表定义,不含数据)`,r.manifest.provides.workbench&&(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(`br`,{}),`工作台 DSL:workbench.json`]})]}),(0,K.jsx)(`div`,{className:`mt-1 font-mono text-[10px] text-muted-foreground`,children:r.files.join(` · `)})]}),!!f?.apis.length&&(0,K.jsxs)(`div`,{className:`rounded-md border border-blue-500/30 bg-blue-500/5 p-2.5`,children:[(0,K.jsx)(`div`,{className:`font-medium text-blue-300`,children:`外部 API 依赖(安装后环境需可达)`}),(0,K.jsx)(`ul`,{className:`mt-1 list-disc pl-4 text-muted-foreground`,children:f.apis.map(e=>(0,K.jsxs)(`li`,{children:[(0,K.jsx)(`span`,{className:`font-mono`,children:e.host}),`:`,e.usage]},e.host))})]}),!!f?.actions.length&&(0,K.jsxs)(`div`,{className:`rounded-md border border-amber-500/30 bg-amber-500/5 p-2.5`,children:[(0,K.jsx)(`div`,{className:`font-medium text-amber-300`,children:`交互脚本(真实 shell 命令,随包公开)`}),(0,K.jsx)(`ul`,{className:`mt-1 space-y-1`,children:f.actions.map(e=>(0,K.jsxs)(`li`,{className:`text-muted-foreground`,children:[`[`,e.panel,`/`,e.id,`] `,e.label,e.has_credentials&&(0,K.jsx)(J,{className:`ml-1 h-4 bg-amber-500/15 px-1 text-[9px] text-amber-300`,children:`⚠️ 疑似含凭据`}),(0,K.jsx)(`div`,{className:`mt-0.5 break-all rounded bg-muted/50 p-1 font-mono text-[10px]`,children:e.exec})]},`${e.panel}/${e.id}`))}),(0,K.jsx)(`p`,{className:`mt-1.5 text-[10px] text-amber-400`,children:`命令明文将进入资产包——含密码/令牌的命令请先改用环境变量或凭据占位,再发布。`})]}),e.agentId&&n&&n.length>0&&(0,K.jsxs)(`label`,{className:`flex items-center gap-2 rounded-md border p-2.5`,children:[(0,K.jsx)(i_,{checked:s,onCheckedChange:e=>c(!!e)}),(0,K.jsx)(`span`,{children:`发布后同时绑定到当前助手(下载该助手的其他现场将自动物化此工作台)`})]})]})]})}),(0,K.jsxs)(u_,{children:[(0,K.jsx)(Y,{variant:`outline`,disabled:l,onClick:t,children:`取消`}),(0,K.jsx)(Y,{disabled:l||!a,onClick:d,children:l?`发布中…`:`发布到 ARM`})]})]})})}function AO({open:e,onClose:t,onInstalled:n,agents:r}){let[i,a]=(0,v.useState)(``),[o,s]=(0,v.useState)([]),[c,l]=(0,v.useState)(!1),[u,d]=(0,v.useState)(null),[f,p]=(0,v.useState)(``),m=(0,v.useRef)(0);(0,v.useEffect)(()=>{if(!e)return;let t=setTimeout(()=>{let e=++m.current;l(!0),ot(`/api/assets/arm-library${i?`?keyword=${encodeURIComponent(i)}`:``}`).then(t=>{e===m.current&&s(t.items||[])}).catch(e=>Z.error(String(e.message))).finally(()=>{e===m.current&&l(!1)})},400);return()=>clearTimeout(t)},[i,e]),(0,v.useEffect)(()=>{e&&!f&&r.length&&p(r[0].agent_id)},[e,r]);let h=async e=>{if(e.asset_type===`workbench`&&!f)Z.warning(`请先选择目标助手`);else{d(e.name);try{let r=await st(`/api/assets/install`,{name:e.name,agentId:e.asset_type===`workbench`?f:void 0}),i=r.workbench?`,工作台已导入为草稿(审阅后在「定制工作台」发布)`:``,a=r.skipped_collections.length?`;同名数据集保留本地:${r.skipped_collections.join(`、`)}`:``;Z.success(`已安装 ${e.name}:面板 ×${r.panels.length}${i}${a}`),n(),t()}catch(e){Z.error(String(e.message))}finally{d(null)}}};return(0,K.jsx)(a_,{open:e,onOpenChange:e=>{!e&&!u&&t()},children:(0,K.jsxs)(c_,{children:[(0,K.jsx)(l_,{children:(0,K.jsxs)(d_,{className:`flex items-center gap-2`,children:[(0,K.jsx)(Yh,{className:`h-4 w-4 text-primary`}),`从 ARM 安装 UI 资产`]})}),(0,K.jsxs)(`div`,{className:`relative`,children:[(0,K.jsx)(xg,{className:`absolute left-3 top-2.5 h-3.5 w-3.5 text-muted-foreground`}),(0,K.jsx)(p_,{placeholder:`搜索资产名 / 描述…`,value:i,onChange:e=>a(e.target.value),className:`pl-9`,autoFocus:!0})]}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2 text-xs text-muted-foreground`,children:[(0,K.jsx)(`span`,{className:`shrink-0`,children:`工作台资产安装到:`}),(0,K.jsx)(`select`,{value:f,onChange:e=>p(e.target.value),className:`h-8 flex-1 rounded-md border bg-background px-2 text-xs`,children:r.map(e=>(0,K.jsx)(`option`,{value:e.agent_id,children:e.name},e.agent_id))})]}),(0,K.jsx)(eO,{className:`max-h-80`,children:(0,K.jsxs)(`div`,{className:`space-y-1.5 pr-2`,children:[c&&!o.length&&(0,K.jsx)(`div`,{className:`py-6 text-center text-xs text-muted-foreground`,children:`加载中…`}),!c&&!o.length&&(0,K.jsx)(`div`,{className:`py-6 text-center text-xs text-muted-foreground`,children:i?`没有匹配资产`:`ARM 上暂无 UI 资产`}),o.map(e=>(0,K.jsxs)(`div`,{className:`flex items-center gap-2.5 rounded-md border p-2.5`,children:[e.asset_type===`workbench`?(0,K.jsx)(Yh,{className:`h-4 w-4 shrink-0 text-violet-400`}):(0,K.jsx)(pg,{className:`h-4 w-4 shrink-0 text-primary`}),(0,K.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-1.5 text-xs font-medium`,children:[(0,K.jsx)(`span`,{className:`truncate font-mono`,children:e.name}),e.latest_version&&(0,K.jsx)(J,{variant:`secondary`,className:`h-4 px-1 text-[9px]`,children:e.latest_version}),e.installed&&(0,K.jsx)(J,{className:`h-4 bg-emerald-500/15 px-1 text-[9px] text-emerald-400`,children:`本地已有`}),e.upgrade_available&&(0,K.jsx)(J,{className:`h-4 bg-amber-500/15 px-1 text-[9px] text-amber-300`,children:`⤴ 可升级`})]}),(0,K.jsxs)(`div`,{className:`truncate text-[10px] text-muted-foreground`,children:[e.description||`—`,` · 下载 `,e.download_count,` 次 · `,e.publisher]})]}),(0,K.jsx)(Y,{size:`sm`,variant:`secondary`,className:`h-7 text-[11px]`,disabled:u!==null,onClick:()=>h(e),children:u===e.name?`安装中…`:`安装`})]},e.name))]})}),(0,K.jsx)(u_,{children:(0,K.jsx)(Y,{variant:`outline`,onClick:t,children:`关闭`})})]})})}function jO(){let[e,t]=(0,v.useState)(null),[n,r]=(0,v.useState)(null),[i,a]=(0,v.useState)(!1),[o,s]=(0,v.useState)([]),c=()=>ot(`/api/plugins/center`).then(t);if((0,v.useEffect)(()=>{c(),ot(`/api/agents`).then(e=>s((e.agents||[]).filter(e=>e.installed).map(({agent_id:e,name:t})=>({agent_id:e,name:t})))).catch(()=>{})},[]),!e)return(0,K.jsx)(`div`,{className:`flex h-full items-center justify-center text-sm text-muted-foreground`,children:`插件中心加载中…`});let l=async(e,t,n)=>{let r=n===`deprecated`?`active`:`deprecated`;try{await st(`/api/plugins/lifecycle`,{kind:e,id:t,status:r}),Z.success(r===`deprecated`?`已停用(存量引用仍可渲染,新增被阻止)`:`已恢复`),c()}catch(e){Z.error(String(e.message))}},u=({icon:e,name:t,sub:n,status:r,usage:i,onToggle:a,tag:o,onDelete:s,onShare:c,armRef:l})=>(0,K.jsxs)(`div`,{className:`flex items-center gap-2.5 rounded-md border p-2.5`,children:[(0,K.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-1.5 text-xs font-medium`,children:[e,t,(0,K.jsx)(J,{variant:`secondary`,className:`h-4 px-1 text-[9px]`,children:o}),(0,K.jsx)(J,{className:`h-4 px-1 text-[9px] ${r===`deprecated`?`bg-red-500/15 text-red-400 hover:bg-red-500/25`:`bg-emerald-500/15 text-emerald-400 hover:bg-emerald-500/25`}`,children:r===`deprecated`?`已停用`:`在用`}),l&&(0,K.jsxs)(J,{className:`h-4 bg-violet-500/15 px-1 text-[9px] text-violet-300`,title:`ARM ${l.skill_name}@${l.version||``}`,children:[`已发布`,l.version?` ${l.version}`:``]})]}),(0,K.jsx)(`div`,{className:`truncate text-[10px] text-muted-foreground`,children:n}),(0,K.jsxs)(`div`,{className:`mt-0.5 text-[10px] text-muted-foreground`,children:[`引用:`,i.length?i.map(e=>`${e.agent}${e.draft?`*`:``}`).join(`、`):`无`]})]}),c&&(0,K.jsxs)(Y,{size:`sm`,variant:`ghost`,className:`h-7 text-[11px] text-violet-400`,onClick:c,title:`发布到 ARM UI 资产市场`,children:[(0,K.jsx)(_h,{className:`h-3 w-3`}),l?`更新`:`发布`]}),s&&(0,K.jsx)(Y,{size:`sm`,variant:`ghost`,className:`h-7 text-[11px] text-red-400`,onClick:s,children:`删除`}),(0,K.jsx)(Y,{size:`sm`,variant:r===`deprecated`?`secondary`:`ghost`,className:`h-7 text-[11px] ${r===`deprecated`?``:`text-red-400`}`,onClick:a,children:r===`deprecated`?`恢复`:`停用`})]});return(0,K.jsxs)(`div`,{className:`h-full overflow-auto p-5`,children:[(0,K.jsxs)(`div`,{className:`mb-4`,children:[(0,K.jsxs)(`h1`,{className:`flex items-center gap-2 text-lg font-bold`,children:[(0,K.jsx)(pg,{className:`h-5 w-5 text-primary`}),`插件中心`]}),(0,K.jsxs)(`p`,{className:`mt-0.5 text-xs text-muted-foreground`,children:[`统一注册表:系统面板与契约插件同源治理 · 生命周期(在用/停用)· 引用追踪(* 为草稿引用)· `,(0,K.jsx)(`span`,{className:`text-violet-400`,children:`发布/安装 ARM UI 资产(三资产模型)`})]})]}),(0,K.jsxs)(`div`,{className:`grid grid-cols-2 gap-4`,children:[(0,K.jsxs)(bm,{className:`py-0`,children:[(0,K.jsx)(xm,{className:`border-b py-2.5`,children:(0,K.jsxs)(Sm,{className:`flex items-center gap-1.5 text-xs`,children:[(0,K.jsx)(Dh,{className:`h-3.5 w-3.5`}),`系统插件(平台预装)`]})}),(0,K.jsx)(Cm,{className:`p-3`,children:(0,K.jsx)(`div`,{className:`space-y-1.5`,children:e.system.map(e=>(0,K.jsx)(u,{icon:(0,K.jsx)(`span`,{className:`font-mono text-[10px] text-muted-foreground`,children:e.id}),name:e.name,sub:e.note,status:e.status,usage:e.usage,tag:`system`,onToggle:()=>l(`system`,e.id,e.status)},e.id))})})]}),(0,K.jsxs)(bm,{className:`py-0`,children:[(0,K.jsx)(xm,{className:`border-b py-2.5`,children:(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(Sm,{className:`flex items-center gap-1.5 text-xs`,children:[(0,K.jsx)(th,{className:`h-3.5 w-3.5`}),`插件库(AI 开发 / 人工沉淀)`]}),(0,K.jsxs)(Y,{size:`sm`,variant:`outline`,className:`h-7 gap-1 text-[11px]`,onClick:()=>a(!0),children:[(0,K.jsx)(Yh,{className:`h-3 w-3`}),`从 ARM 安装`]})]})}),(0,K.jsx)(Cm,{className:`p-3`,children:(0,K.jsxs)(`div`,{className:`space-y-1.5`,children:[e.library.map(e=>(0,K.jsx)(u,{icon:(0,K.jsx)(pg,{className:`h-3 w-3 text-primary`}),name:`${e.name} ${e.version}`,sub:`${e.author===`ai`?`AI 开发`:e.author===`arm`?`ARM 安装`:`人工`} · ${e.description||e.id}`,status:e.status,usage:e.usage,tag:e.author===`ai`?`ai`:e.author===`arm`?`arm`:`human`,onToggle:()=>l(`plugin`,e.id,e.status),onDelete:()=>OO(e,c),onShare:()=>r({type:`panel`,id:e.id,title:e.name}),armRef:e.arm_ref},e.id)),e.library.length===0&&(0,K.jsx)(`div`,{className:`py-6 text-center text-xs text-muted-foreground`,children:`插件库为空`})]})})]})]}),(0,K.jsx)(_O,{className:`my-4`}),(0,K.jsxs)(bm,{className:`py-0`,children:[(0,K.jsx)(xm,{className:`border-b py-2.5`,children:(0,K.jsxs)(Sm,{className:`flex items-center gap-1.5 text-xs`,children:[(0,K.jsx)(Ng,{className:`h-3.5 w-3.5`}),`治理策略`]})}),(0,K.jsx)(Cm,{className:`p-3 text-[11px] leading-relaxed text-muted-foreground`,children:(0,K.jsx)(eO,{className:`max-h-40`,children:(0,K.jsxs)(`ul`,{className:`list-disc space-y-1 pl-4`,children:[(0,K.jsx)(`li`,{children:`一切面板进同一注册表:系统插件也有 manifest 与生命周期,不再是编译进前端的二等公民`}),(0,K.jsx)(`li`,{children:`停用(deprecate)不破坏存量:已引用的工作台继续渲染,但编辑器「添加面板」不再出现——安全下线`}),(0,K.jsx)(`li`,{children:`入库强制过校验器(check-panel.mjs):编译/契约/沙箱/模板四关 + 质量警告入审计——ARM 安装的插件同样过检`}),(0,K.jsx)(`li`,{children:`出网最小化:/api/proxy 仅放行插件代码中声明过的主机(防止面板成为任意内网跳板)`}),(0,K.jsx)(`li`,{children:`版本化与回滚:插件独立版本(同 id 覆盖自增),工作台按 id 引用,升级即时生效可回滚`}),(0,K.jsx)(`li`,{children:`数据隔离:插件数据集按助手分库(store-助手ID.db),共享需显式 scope=shared;资产包只带 schema 不带数据`}),(0,K.jsx)(`li`,{children:`UI 资产四红线(docs/08):包非运行时 · 数据必走 collection · 外部依赖必声明 · 单向 DAG`})]})})})]}),(0,K.jsx)(kO,{target:n,onClose:()=>{r(null),c()},agents:o}),(0,K.jsx)(AO,{open:i,onClose:()=>a(!1),onInstalled:c,agents:o})]})}function MO({pluginId:e,onRollback:t}){let[n,r]=(0,v.useState)(null);return(0,v.useEffect)(()=>{e&&ot(`/api/panels?id=${e}`).then(e=>r(e.plugin)).catch(()=>r(null))},[e]),n?(0,K.jsxs)(`div`,{className:`space-y-1`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-1.5 text-[11px]`,children:[(0,K.jsx)(`span`,{className:`font-mono`,children:n.version}),(0,K.jsx)(`span`,{className:`text-muted-foreground`,children:`(当前)`})]}),(n.history||[]).slice().reverse().map(n=>(0,K.jsxs)(`div`,{className:`flex items-center gap-2 text-[11px]`,children:[(0,K.jsx)(`span`,{className:`font-mono`,children:n.version}),(0,K.jsx)(`span`,{className:`text-[10px] text-muted-foreground`,children:gt(n.at,`dts`)}),(0,K.jsx)(Y,{size:`sm`,variant:`ghost`,className:`ml-auto h-6 text-[10px]`,onClick:()=>t(e,n.version),children:`回退`})]},n.version)),!(n.history||[]).length&&(0,K.jsx)(`div`,{className:`text-[10px] text-muted-foreground`,children:`无历史版本`})]}):(0,K.jsx)(`div`,{className:`text-[10px] text-muted-foreground`,children:`(插件信息加载中…)`})}var NO=e=>({x:1,y:e.reduce((e,t)=>Math.max(e,t.grid?t.grid.y+t.grid.h-1:0),0)+1,w:6,h:1});function PO({agentId:e}){let[t,n]=(0,v.useState)(null),[r,i]=(0,v.useState)(!1),[a,o]=(0,v.useState)([]),[s,c]=(0,v.useState)(``),[l,u]=(0,v.useState)(!1),[d,f]=(0,v.useState)([]),[p,m]=(0,v.useState)(!1),[h,g]=(0,v.useState)(null),[_,y]=(0,v.useState)(null),[b,x]=(0,v.useState)(!1),[S,C]=(0,v.useState)(0),[w,T]=(0,v.useState)(null),[E,D]=(0,v.useState)([]),[O,k]=(0,v.useState)(null),A=(0,v.useRef)(`dev-${e.slice(0,8)}`).current,j=(0,v.useRef)(null),[M,N]=(0,v.useState)([]),[P,F]=(0,v.useState)(``),[I,L]=(0,v.useState)(!1),[R,ee]=(0,v.useState)(``),[te,z]=(0,v.useState)(null),[ne,re]=(0,v.useState)(!1),[ie,ae]=(0,v.useState)(null),oe=(0,v.useRef)(null),se=(0,v.useRef)(!0),ce=(0,v.useCallback)(()=>{let e=oe.current?.closest(`[data-slot="scroll-area-viewport"]`);e&&(e.scrollTop=e.scrollHeight)},[]);(0,v.useEffect)(()=>{let e=oe.current?.closest(`[data-slot="scroll-area-viewport"]`);if(!e)return;let t=()=>{se.current=e.scrollHeight-e.scrollTop-e.clientHeight<80};return e.addEventListener(`scroll`,t),()=>e.removeEventListener(`scroll`,t)},[]),(0,v.useEffect)(()=>{se.current&&ce()},[M,I,R,ce]);let le=()=>{ot(`/api/workbench?agent_id=${e}&draft=1`).then(e=>{n(e.dsl),i(e.isDraft),o(e.versions||[]),c(JSON.stringify(e.dsl,null,2))}),ot(`/api/panels`).then(e=>f(e.plugins||[]))};if((0,v.useEffect)(()=>{le()},[e]),(0,v.useEffect)(()=>{let e=()=>ot(`/api/state`).then(T).catch(()=>{});e();let t=setInterval(e,5e3);return ot(`/api/panels?with_code=1`).then(e=>D(e.plugins||[])),()=>clearInterval(t)},[]),!t)return(0,K.jsx)(`div`,{className:`flex h-full items-center justify-center text-sm text-muted-foreground`,children:`加载工作台 DSL…`});let B=t.panels,V=_===null?null:B[_],H=e=>{let r=JSON.parse(JSON.stringify(t));e(r),n(r),c(JSON.stringify(r,null,2)),i(!0)},ue=(e,t)=>H(n=>{let r=n.panels[e].grid||{x:1,y:1,w:6,h:1};n.panels[e].grid={...r,...t}}),de=t=>({devices:w?.devices||[],alarms:w?.alarms||[],kpi:w?.kpi||{},work_orders:w?.work_orders||[],inspections:w?.inspections||{},selected:O,onSelect:k,agentId:e,store:mt(e),runAction:(n,r)=>ht(e,String(t.id),n,r),params:{...t.params||{},agentId:e,wsId:`default`}}),fe=e=>e.type===`custom`?e.code:E.find(t=>t.id===e.panel)?.code||``,pe=()=>H(e=>e.panels.push({id:`block_${Math.random().toString(36).slice(2,6)}`,type:`placeholder`,title:`空区块`,grid:NO(e.panels)})),me=(e,t)=>{H(n=>{if(e!==null&&e<n.panels.length){let r=n.panels[e];Object.assign(r,{type:`custom_panel`,panel:t.id,title:r.title===`空区块`?t.name:r.title})}else n.panels.push({id:`plug_${t.id}_${Math.random().toString(36).slice(2,5)}`,type:`custom_panel`,title:t.name,panel:t.id,grid:NO(n.panels)})}),m(!1),g(null),Z.success(`已插入「${t.name}」(草稿,待发布)`)},he=async e=>{let t=B[e];z(e);let n=``;try{let e=t.panel||t.id,r=await ot(`/api/panel-errors?key=${encodeURIComponent(e)}`);n=r.errors?.length?r.errors.map(e=>`[${e.kind}] ${e.message}`).join(` | `):``}catch{}F(`请调试该插件:${n?`最近运行错误:${n}。`:`暂无上报错误,请先 read_panel_plugin 审代码,重点检查结果处理与错误路径。`}请定位根因、修复并说明验证方式。`),Z.info(`已锁定调试目标并带上错误上下文,发送即开始`)},ge=async(e,t)=>{try{let n=await st(`/api/panels/rollback`,{id:e,version:t});Z.success(`已回退到 ${t}(新版本号 ${n.plugin.version},引用即时生效)`),le()}catch(e){Z.error(String(e.message))}},_e=()=>{if(te===null||!B[te])return``;let e=B[te],t=e.grid||{x:1,y:1,w:6,h:1},n=Math.round(t.w/12*100),r=t.w<=3?`窄条(紧凑单列列表/迷你卡)`:t.w>=9?`宽区块(表格/多列仪表)`:`中等宽度(两列卡/紧凑表)`;return`【定制目标】区块「${e.title}」(id=${e.id}):第${t.x}列起、跨${t.w}列(约${n}%宽)、跨${t.h}行(${r})。${e.panel?`当前引用插件 ${e.panel}——先 read_panel_plugin 再决定改造还是重写。`:`空区块,可新建插件。`}`},ve=e=>{z(e),F(``),Z.info(`已锁定定制目标「${B[e].title}」——在右侧描述需求即可`)},ye=async()=>{u(!0);try{let r=await ct(`/api/workbench`,{agent_id:e,dsl:t});n(r.dsl),o(r.versions),c(JSON.stringify(r.dsl,null,2)),i(!1),re(!1),Z.success(`已发布 ${r.dsl.version},工作台即时生效`)}catch(e){Z.error(String(e.message))}finally{u(!1)}},be=async()=>{await lt(`/api/workbench/draft`,{agent_id:e}),Z.success(`已放弃草稿`),le()},xe=async t=>{try{let r=await st(`/api/workbench/rollback`,{agent_id:e,version:t});n(r.dsl),o(r.versions),c(JSON.stringify(r.dsl,null,2)),i(!1),Z.success(`已回滚到 ${t}`)}catch(e){Z.error(String(e.message))}},U=()=>{j.current?.abort()},Se=async()=>{let t=P.trim();if(!t||I)return;let n=_e()?`${_e()}\n需求:${t}`:t;F(``),L(!0),re(!1),se.current=!0,N(e=>[...e,{role:`user`,text:t}]);let r=!1,i=new AbortController;j.current=i;try{await ut(`/api/dev/chat`,{sessionId:A,agentId:e,message:n},e=>{let t=e.type;t===`status`?ee(String(e.text||``)):t===`text_delta`?(ee(``),N(t=>{let n=t[t.length-1];return n?.role===`agent`&&n.streaming?[...t.slice(0,-1),{...n,text:n.text+String(e.delta)}]:[...t,{role:`agent`,text:String(e.delta),streaming:!0}]})):t===`tool_start`?(r=!0,N(t=>[...t,{role:`agent`,text:``,streaming:!1,events:[{tool:String(e.tool),args:e.args||{}}]}])):t===`tool_end`?N(t=>{for(let n=t.length-1;n>=0;n--){let r=t[n];if(r.role===`agent`&&r.events){for(let n=r.events.length-1;n>=0;n--)if(r.events[n].tool===e.tool&&r.events[n].result===void 0)return r.events[n].result=String(e.result||``),r.events[n].ok=e.ok!==!1,[...t]}}return t}):t===`interrupted`?(ee(``),N(e=>[...e,{role:`agent`,text:`(已中断)`}])):t===`meta`?e.hasDraft?(re(!0),le()):r&&le():t===`error`&&Z.error(String(e.message))},i.signal)}catch(e){i.signal.aborted?N(e=>[...e,{role:`agent`,text:`(已中断)`}]):N(t=>[...t,{role:`agent`,text:`❌ ${String(e.message)}`}])}finally{ee(``),L(!1),j.current===i&&(j.current=null)}};return(0,K.jsxs)(`div`,{className:`flex h-full flex-col gap-3 overflow-hidden p-5`,children:[(0,K.jsxs)(`div`,{className:`flex shrink-0 items-end justify-between`,children:[(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`h1`,{className:`text-lg font-bold`,children:`定制工作台`}),(0,K.jsx)(`p`,{className:`mt-0.5 text-xs text-muted-foreground`,children:`区块你规划 · 插件按区块占比定制 · 一切修改走草稿审阅发布`})]}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)(J,{variant:`secondary`,children:r?`草稿(未发布)`:`线上 ${t.version}`}),(0,K.jsxs)(Y,{size:`sm`,variant:`outline`,onClick:()=>{g(null),m(!0)},children:[(0,K.jsx)(pg,{className:`mr-1 h-3.5 w-3.5`}),`插件库`]}),(0,K.jsxs)(Y,{size:`sm`,variant:`outline`,title:`把当前工作台(含依赖插件/数据集 schema/交互脚本)发布为 ARM UI 资产`,onClick:()=>ae({type:`workbench`,agentId:e,title:t.workbench}),children:[(0,K.jsx)(_h,{className:`mr-1 h-3.5 w-3.5 text-violet-400`}),`导出资产`]}),(0,K.jsxs)(Y,{size:`sm`,disabled:l||!r,onClick:ye,children:[(0,K.jsx)(yg,{className:`mr-1 h-3.5 w-3.5`}),l?`发布中…`:`审阅后发布`]})]})]}),r&&(0,K.jsxs)(`div`,{className:`flex shrink-0 items-center gap-2 rounded-md border border-amber-500/50 bg-amber-500/10 px-3 py-2 text-xs text-amber-300`,children:[(0,K.jsx)(`span`,{children:`⚠`}),`草稿未发布——审阅后发布生效,或`,(0,K.jsx)(`button`,{className:`underline underline-offset-2`,onClick:be,children:`放弃草稿`})]}),(0,K.jsxs)(`div`,{className:`grid min-h-0 flex-1 grid-cols-[1fr_380px] gap-4`,children:[(0,K.jsx)(`div`,{className:`flex min-h-0 flex-col`,children:(0,K.jsxs)(vO,{defaultValue:`canvas`,className:`flex min-h-0 flex-1 flex-col`,children:[(0,K.jsxs)(bO,{className:`shrink-0`,children:[(0,K.jsxs)(xO,{value:`canvas`,className:`text-xs`,children:[(0,K.jsx)(Yh,{className:`mr-1 h-3.5 w-3.5`}),`布局画布`]}),(0,K.jsx)(xO,{value:`json`,className:`text-xs`,children:`JSON`})]}),(0,K.jsxs)(SO,{value:`canvas`,className:`mt-2 flex min-h-0 flex-1 flex-col gap-2`,children:[(0,K.jsxs)(`div`,{className:`flex shrink-0 flex-nowrap items-center gap-1.5 overflow-x-auto rounded-md border bg-card p-2`,children:[(0,K.jsxs)(Y,{size:`sm`,variant:`secondary`,className:`h-7 shrink-0 text-xs`,onClick:pe,children:[(0,K.jsx)(dg,{className:`mr-1 h-3 w-3`}),`添加区块`]}),(0,K.jsx)(_O,{orientation:`vertical`,className:`mx-1 h-5 shrink-0`}),V?(0,K.jsxs)(K.Fragment,{children:[(0,K.jsxs)(`span`,{className:`max-w-28 shrink-0 truncate text-[11px] text-muted-foreground`,title:V.title,children:[`「`,V.title,`」`]}),(0,K.jsx)(`span`,{className:`shrink-0 text-[11px]`,children:`列`}),(0,K.jsx)(Y,{size:`icon`,variant:`ghost`,className:`h-7 w-7 shrink-0`,title:`左移一列`,onClick:()=>ue(_,{x:Math.max(1,(V.grid?.x||1)-1)}),children:(0,K.jsx)(qm,{className:`h-3 w-3`})}),(0,K.jsx)(Y,{size:`icon`,variant:`ghost`,className:`h-7 w-7 shrink-0`,title:`右移一列`,onClick:()=>ue(_,{x:Math.min(12,(V.grid?.x||1)+1)}),children:(0,K.jsx)(Ym,{className:`h-3 w-3`})}),(0,K.jsx)(`span`,{className:`shrink-0 text-[11px]`,children:`跨列`}),(0,K.jsx)(Y,{size:`icon`,variant:`ghost`,className:`h-7 w-7 shrink-0`,title:`跨列减一`,onClick:()=>ue(_,{w:Math.max(1,(V.grid?.w||6)-1)}),children:`−`}),(0,K.jsx)(Y,{size:`icon`,variant:`ghost`,className:`h-7 w-7 shrink-0`,title:`跨列加一`,onClick:()=>ue(_,{w:Math.min(12,(V.grid?.w||6)+1)}),children:`+`}),(0,K.jsx)(`span`,{className:`shrink-0 text-[11px]`,children:`跨行`}),(0,K.jsx)(Y,{size:`icon`,variant:`ghost`,className:`h-7 w-7 shrink-0`,title:`跨行减一`,onClick:()=>ue(_,{h:Math.max(1,(V.grid?.h||1)-1)}),children:(0,K.jsx)(Zm,{className:`h-3 w-3`})}),(0,K.jsx)(Y,{size:`icon`,variant:`ghost`,className:`h-7 w-7 shrink-0`,title:`跨行加一`,onClick:()=>ue(_,{h:Math.min(8,(V.grid?.h||1)+1)}),children:(0,K.jsx)(Gm,{className:`h-3 w-3`})}),(0,K.jsxs)(Y,{size:`sm`,variant:`ghost`,className:`h-7 shrink-0 text-xs text-primary`,onClick:()=>ve(_),children:[(0,K.jsx)(th,{className:`mr-1 h-3 w-3`}),`AI 定制`]}),(0,K.jsxs)(CO,{children:[(0,K.jsx)(wO,{asChild:!0,children:(0,K.jsxs)(Y,{size:`sm`,variant:`ghost`,className:`h-7 shrink-0 text-xs`,children:[(0,K.jsx)(Th,{className:`h-3 w-3`}),`更多`]})}),(0,K.jsxs)(TO,{align:`end`,children:[(V.type===`custom`||V.type===`custom_panel`)&&(0,K.jsxs)(EO,{className:`text-amber-400 focus:text-amber-300`,onClick:()=>he(_),children:[(0,K.jsx)(t_,{}),`AI 调试`]}),(0,K.jsxs)(EO,{onClick:()=>ue(_,{x:1,w:12}),children:[(0,K.jsx)(Ug,{className:`text-muted-foreground`}),`占满宽度`]}),(0,K.jsxs)(EO,{onClick:()=>{let e=B.reduce((e,t)=>Math.max(e,(t.grid?.y||1)+(t.grid?.h||1)-1),1);ue(_,{h:Math.max(1,e-(V.grid?.y||1)+1)})},children:[(0,K.jsx)(Gg,{className:`text-muted-foreground`}),`延到底部`]}),(0,K.jsxs)(EO,{onClick:()=>ue(_,{x:1}),children:[(0,K.jsx)(Um,{className:`text-muted-foreground`}),`贴左`]}),(0,K.jsxs)(EO,{onClick:()=>ue(_,{x:12-(V.grid?.w||6)+1}),children:[(0,K.jsx)(Vm,{className:`text-muted-foreground`}),`贴右`]}),(0,K.jsx)(DO,{}),(0,K.jsxs)(EO,{onClick:()=>{g(_),m(!0)},children:[(0,K.jsx)(pg,{className:`text-muted-foreground`}),`换插件`]}),(0,K.jsxs)(EO,{onClick:()=>{C(_),x(!0)},children:[(0,K.jsx)(Dg,{className:`text-muted-foreground`}),`面板设置`]}),(0,K.jsxs)(EO,{className:`text-red-400 focus:text-red-300`,onClick:()=>{H(e=>e.panels.splice(_,1)),y(null)},children:[(0,K.jsx)(qg,{}),`删除区块`]})]})]})]}):(0,K.jsx)(`span`,{className:`shrink-0 text-[11px] text-muted-foreground`,children:`点击画布中的区块进行编辑`})]}),(0,K.jsx)(`div`,{className:`shrink-0`,children:(0,K.jsx)(mO,{})}),(0,K.jsx)(`div`,{className:`relative min-h-0 flex-1 overflow-hidden rounded-lg border bg-muted/20 p-2`,children:(0,K.jsx)(pO,{className:`absolute inset-0 overflow-auto`,dsl:t,edit:{sel:_,onSelect:y,onGrid:(e,t)=>ue(e,t)},renderPanel:t=>{let n=fe(t);return n?(0,K.jsx)(dO,{code:n,data:de(t),meta:{agentId:e,panelId:t.id,pluginId:t.panel}}):(0,K.jsx)(`div`,{className:`p-3 text-[11px] text-muted-foreground`,children:`(插件代码加载中…)`})},renderDialog:()=>(0,K.jsxs)(`div`,{className:`flex h-full flex-col items-center justify-center gap-1 text-[11px] text-muted-foreground`,children:[(0,K.jsx)(th,{className:`h-5 w-5 text-primary`}),`诊断对话(内核)`,(0,K.jsx)(`span`,{className:`text-[10px]`,children:`发布后在工作台可交互`})]}),renderPlaceholder:()=>(0,K.jsxs)(`div`,{className:`flex h-full flex-col items-center justify-center gap-1 text-[11px] text-muted-foreground`,children:[(0,K.jsx)(dg,{className:`h-4 w-4`}),`空区块`,(0,K.jsx)(`span`,{className:`text-[10px]`,children:`选中后「换插件」或「AI 定制」`})]})})}),(0,K.jsx)(`p`,{className:`shrink-0 text-[10px] text-muted-foreground`,children:`所见即所得(比例一致):画布 = 缩小的可视区,行高为可视区等分——跨 n 行即占 n/总行数,与实际浏览时任何屏幕尺寸下的比例完全一致;内容超高时面板内部滚动。拖拽移动(吸附网格)· 手柄调跨列跨行 · 右上角显示占比。`})]}),(0,K.jsxs)(SO,{value:`json`,className:`mt-2 flex min-h-0 flex-1 flex-col gap-2`,children:[(0,K.jsx)(`textarea`,{value:s,onChange:e=>c(e.target.value),spellCheck:!1,className:`min-h-0 w-full flex-1 resize-none rounded-md border bg-muted p-3 font-mono text-[11px] leading-relaxed`}),(0,K.jsxs)(`div`,{className:`flex shrink-0 gap-2`,children:[(0,K.jsx)(Y,{size:`sm`,onClick:()=>{try{let e=JSON.parse(s);if(!e.panels)throw Error(`缺少 panels`);n(e),i(!0),Z.success(`JSON 已应用(未发布)`)}catch(e){Z.error(`JSON 解析失败: ${e.message}`)}},children:`应用 JSON`}),(0,K.jsx)(Y,{size:`sm`,variant:`outline`,onClick:()=>c(JSON.stringify(t,null,2)),children:`从画布刷新`})]})]})]})}),(0,K.jsxs)(`div`,{className:`flex min-h-0 flex-col gap-4`,children:[(0,K.jsx)(bm,{className:`flex min-h-0 flex-1 flex-col py-0`,children:(0,K.jsxs)(Cm,{className:`flex min-h-0 flex-1 flex-col p-0`,children:[(0,K.jsxs)(`div`,{className:`flex shrink-0 items-center gap-1.5 border-b px-3 py-2 text-xs font-semibold`,children:[(0,K.jsx)(Lg,{className:`h-3.5 w-3.5 text-primary`}),`二开助手`,(0,K.jsx)(`span`,{className:`font-normal text-muted-foreground`,children:`· 描述需求,直接定制区块`})]}),te!==null&&B[te]&&(()=>{let e=B[te],t=e.grid||{x:1,y:1,w:6,h:1},n=Math.round(t.w/12*100);return(0,K.jsxs)(`div`,{className:`flex shrink-0 items-center gap-1.5 border-b bg-primary/5 px-3 py-1.5 text-[11px]`,children:[(0,K.jsx)(yh,{className:`h-3.5 w-3.5 shrink-0 text-primary`}),(0,K.jsxs)(`span`,{className:`min-w-0 truncate`,children:[`定制目标:`,(0,K.jsx)(`b`,{children:e.title}),` · `,n,`% 宽 · `,t.h,` 行`,e.panel?(0,K.jsxs)(K.Fragment,{children:[` · `,(0,K.jsx)(`span`,{className:`font-mono`,children:e.panel})]}):` · 空区块`]}),(0,K.jsx)(`button`,{className:`ml-auto shrink-0 rounded p-0.5 text-muted-foreground hover:text-foreground`,title:`取消目标,改为自由描述`,onClick:()=>z(null),children:`×`})]})})(),ne&&r&&(0,K.jsxs)(`div`,{className:`flex shrink-0 items-center gap-1.5 border-b bg-emerald-500/10 px-3 py-1.5 text-[11px] text-emerald-400`,children:[(0,K.jsx)(ph,{className:`h-3.5 w-3.5 shrink-0`}),`草稿已生成——到顶部「审阅后发布」生效`]}),(0,K.jsx)(eO,{className:`min-h-0 flex-1`,children:(0,K.jsxs)(`div`,{className:`space-y-2.5 p-3`,ref:oe,children:[M.length===0&&(0,K.jsx)(`div`,{className:`space-y-2`,children:(0,K.jsxs)(`div`,{className:`rounded-md border border-dashed border-primary/30 bg-primary/5 p-3 text-[11px] leading-relaxed`,children:[(0,K.jsx)(`div`,{className:`mb-1 text-xs font-semibold text-primary`,children:`✨ 两种玩法`}),(0,K.jsxs)(`div`,{children:[`① 画布选中区块 → 工具条「`,(0,K.jsx)(`b`,{children:`AI 定制`}),`」→ 目标钉在上方,只管补需求`]}),(0,K.jsx)(`div`,{children:`② 直接描述需求,助手自动建区块进草稿`}),(0,K.jsx)(`div`,{className:`mt-1.5 flex flex-wrap gap-1.5`,children:[[`窄条:最近告警`,`新建一个窄条区块(跨3列):最近活动告警列表,高级别标红,点击可选中设备`],[`横条:KPI 摘要`,`新建一个单行横条区块:关键指标摘要读数(props.kpi),异常着色`],[`宽表:设备台账`,`新建一个宽区块(跨9列以上):设备台账表格,显示全部字段,支持点击选中`]].map(([e,t])=>(0,K.jsx)(`button`,{onClick:()=>F(t),className:`rounded-full border px-2.5 py-1 text-[11px] text-muted-foreground transition-colors hover:border-primary/60 hover:text-primary`,children:e},e))})]})}),M.map((e,t)=>(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`div`,{className:e.role===`user`?`ml-auto max-w-[90%] rounded-lg bg-primary/20 px-2.5 py-1.5 text-xs break-words whitespace-pre-wrap`:`max-w-full rounded-lg bg-card px-2.5 py-1.5 text-xs leading-relaxed break-words whitespace-pre-wrap`,children:e.text}),(e.events||[]).map((e,t)=>(0,K.jsxs)(`div`,{className:`mt-1 min-w-0 rounded-md border border-dashed px-2 py-1 text-[10px]`,children:[(0,K.jsx)(`span`,{children:e.ok===!1?`❌`:`🛠`}),` `,(0,K.jsx)(`span`,{className:`font-mono font-semibold`,children:e.tool}),(0,K.jsx)(`pre`,{className:`mt-0.5 max-h-32 overflow-auto whitespace-pre-wrap break-all text-muted-foreground`,children:String(e.result||``).slice(0,260)})]},t))]},t)),(I||R)&&(0,K.jsxs)(`div`,{className:`flex items-center gap-1.5 px-1 text-[11px] text-muted-foreground`,children:[(0,K.jsx)(`span`,{className:`h-1.5 w-1.5 animate-pulse rounded-full bg-primary`}),R||`开发中…`]})]})}),(0,K.jsxs)(`div`,{className:`shrink-0 space-y-1 border-t p-2`,children:[(0,K.jsx)(`textarea`,{value:P,onChange:e=>F(e.target.value),rows:2,onKeyDown:e=>{e.key===`Enter`&&!e.shiftKey&&!e.nativeEvent.isComposing&&(e.preventDefault(),Se())},placeholder:te===null?`描述需求,如「左上窄条做一个最近工单列表」(Enter 发送)…`:`描述对「${B[te]?.title}」的需求(Enter 发送,Shift+Enter 换行)…`,className:`min-h-[56px] w-full resize-none rounded-md border bg-background px-2 py-1.5 text-xs`}),(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsx)(`span`,{className:`text-[10px] text-muted-foreground`,children:te===null?`未锁定目标——助手会自动规划区块位置`:`目标上下文(位置/几何/插件)发送时自动携带`}),I?(0,K.jsxs)(Y,{size:`sm`,variant:`destructive`,className:`h-7 gap-1 text-xs`,onClick:U,children:[(0,K.jsx)(Vg,{className:`h-3 w-3`}),`停止`]}):(0,K.jsxs)(Y,{size:`sm`,className:`h-7 gap-1 text-xs`,disabled:!P.trim(),onClick:Se,children:[(0,K.jsx)(Cg,{className:`h-3 w-3`}),`发送`]})]})]})]})}),(0,K.jsx)(bm,{className:`shrink-0 py-0`,children:(0,K.jsxs)(Cm,{className:`p-0`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-1.5 border-b px-3 py-2 text-xs font-semibold`,children:[(0,K.jsx)(_g,{className:`h-3.5 w-3.5`}),`版本历史`]}),(0,K.jsx)(`div`,{className:`max-h-40 overflow-y-auto`,children:(0,K.jsxs)(`div`,{className:`divide-y`,children:[a.length===0&&(0,K.jsx)(`div`,{className:`p-3 text-center text-xs text-muted-foreground`,children:`暂无历史`}),[...a].reverse().map((e,t)=>(0,K.jsxs)(`div`,{className:`flex items-center gap-2 px-3 py-1.5 text-xs`,children:[(0,K.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,K.jsx)(`span`,{className:`font-mono font-semibold`,children:e.version}),t===0&&!r&&(0,K.jsx)(J,{className:`ml-1 h-4 px-1 text-[9px]`,children:`线上`}),(0,K.jsx)(`div`,{className:`text-[10px] text-muted-foreground`,children:gt(e.at,`dts`)})]}),t!==0&&(0,K.jsx)(Y,{size:`sm`,variant:`ghost`,className:`h-6 text-[10px]`,onClick:()=>xe(e.version),children:`回滚`})]},`${e.version}-${e.at}`))]})})]})})]})]}),(0,K.jsx)(a_,{open:b,onOpenChange:x,children:(0,K.jsxs)(c_,{className:`max-w-md`,children:[(0,K.jsx)(l_,{children:(0,K.jsxs)(d_,{children:[`区块设置 · `,B[S]?.title]})}),(0,K.jsxs)(`div`,{className:`space-y-2`,children:[(0,K.jsxs)(`div`,{className:`space-y-1`,children:[(0,K.jsx)(m_,{className:`text-xs`,children:`标题`}),(0,K.jsx)(p_,{defaultValue:B[S]?.title||``,className:`text-xs`,onBlur:e=>H(t=>{t.panels[S].title=e.target.value})})]}),B[S]?.type===`custom`&&(0,K.jsxs)(`div`,{className:`space-y-1`,children:[(0,K.jsx)(m_,{className:`text-xs`,children:`内联代码(契约:function Panel(props))`}),(0,K.jsx)(`textarea`,{defaultValue:B[S]?.code||``,spellCheck:!1,onBlur:e=>H(t=>{t.panels[S].code=e.target.value}),className:`h-40 w-full rounded-md border bg-muted p-2 font-mono text-[10px]`})]}),B[S]?.type===`custom_panel`&&(0,K.jsxs)(`div`,{className:`space-y-1`,children:[(0,K.jsx)(m_,{className:`text-xs`,children:`插件版本(可回退,回退即时生效)`}),(0,K.jsx)(MO,{pluginId:String(B[S]?.panel||``),onRollback:ge})]}),(0,K.jsxs)(`div`,{className:`space-y-1`,children:[(0,K.jsx)(m_,{className:`text-xs`,children:`params(插件经 props.params 读取)`}),(0,K.jsx)(`textarea`,{defaultValue:JSON.stringify(B[S]?.params||{},null,1),spellCheck:!1,onBlur:e=>{try{H(t=>{t.panels[S].params=JSON.parse(e.target.value||`{}`)})}catch{Z.error(`params JSON 无效`)}},className:`h-20 w-full rounded-md border bg-muted p-2 font-mono text-[10px]`})]})]}),(0,K.jsx)(u_,{children:(0,K.jsx)(Y,{onClick:()=>x(!1),children:`完成`})})]})}),(0,K.jsx)(a_,{open:p,onOpenChange:e=>{m(e),e||g(null)},children:(0,K.jsxs)(c_,{children:[(0,K.jsx)(l_,{children:(0,K.jsxs)(d_,{className:`flex items-center gap-1.5`,children:[(0,K.jsx)(pg,{className:`h-4 w-4`}),`插件库`,h===null?``:` · 插入到选中区块`]})}),(0,K.jsx)(`div`,{className:`max-h-72 overflow-y-auto`,children:(0,K.jsx)(`div`,{className:`space-y-1.5`,children:d.filter(e=>e.status!==`deprecated`).map(e=>(0,K.jsxs)(`div`,{className:`flex items-center gap-2 rounded-md border p-2.5`,children:[(0,K.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,K.jsxs)(`div`,{className:`flex min-w-0 items-center gap-1.5 text-xs font-medium`,children:[(0,K.jsx)(`span`,{className:`min-w-0 truncate`,title:e.name,children:e.name}),(0,K.jsx)(J,{variant:`secondary`,className:`h-4 shrink-0 px-1 text-[9px]`,children:e.version}),(0,K.jsx)(J,{variant:`outline`,className:`h-4 shrink-0 px-1 text-[9px]`,children:e.author===`system`?`范本`:e.author===`ai`?`AI`:`人工`})]}),(0,K.jsx)(`div`,{className:`truncate text-[10px] text-muted-foreground`,children:e.description||e.id})]}),(0,K.jsx)(Y,{size:`sm`,variant:`secondary`,className:`h-7 shrink-0 text-[11px]`,onClick:()=>me(h,e),children:`插入`})]},e.id))})}),(0,K.jsxs)(u_,{children:[(0,K.jsx)(Y,{variant:`outline`,size:`sm`,onClick:pe,children:`先加空区块`}),(0,K.jsx)(Y,{variant:`outline`,onClick:()=>m(!1),children:`关闭`})]})]})}),(0,K.jsx)(kO,{target:ie,onClose:()=>ae(null),agents:[{agent_id:e,name:t.workbench||`当前助手`}]}),(0,K.jsx)(`p`,{className:`shrink-0 text-center text-[11px] text-muted-foreground`,children:`区块几何 = 插件设计输入:宽≤3 列紧凑列表、≥9 列表格/仪表 · AI 定制锁定目标、上下文自动携带 · 草稿审阅发布。`})]})}var FO=[{key:`tool_calls`,label:`工具调用`,icon:(0,K.jsx)(t_,{className:`h-3.5 w-3.5`}),tone:`text-sky-400`},{key:`guardrail_blocks`,label:`守护栏拦截`,icon:(0,K.jsx)(jg,{className:`h-3.5 w-3.5`}),tone:`text-red-400`},{key:`human_confirms`,label:`人工确认执行`,icon:(0,K.jsx)(zm,{className:`h-3.5 w-3.5`}),tone:`text-amber-400`},{key:`orchestrations`,label:`编排执行`,icon:(0,K.jsx)(Lg,{className:`h-3.5 w-3.5`}),tone:`text-violet-400`},{key:`experiences`,label:`经验回流`,icon:(0,K.jsx)($m,{className:`h-3.5 w-3.5`}),tone:`text-emerald-400`},{key:`kb_searches`,label:`知识检索`,icon:(0,K.jsx)(xg,{className:`h-3.5 w-3.5`}),tone:`text-cyan-400`},{key:`ai_drafts`,label:`AI 起草`,icon:(0,K.jsx)(Yg,{className:`h-3.5 w-3.5`}),tone:`text-pink-400`}];function IO(){let[e,t]=(0,v.useState)(null),[n,r]=(0,v.useState)(``),[i,a]=(0,v.useState)(null),[o,s]=(0,v.useState)(!1),c=()=>ot(`/api/evolution`).then(t);(0,v.useEffect)(()=>{c();let e=setInterval(c,1e4);return()=>clearInterval(e)},[]);let l=async()=>{if(n.trim()){s(!0);try{let e=await ot(`/api/kb/search?q=${encodeURIComponent(n)}`);a(e.items),c()}finally{s(!1)}}};return e?(0,K.jsxs)(`div`,{className:`h-full overflow-auto p-5`,children:[(0,K.jsxs)(`div`,{className:`mb-4`,children:[(0,K.jsxs)(`h1`,{className:`flex items-center gap-2 text-lg font-bold`,children:[(0,K.jsx)(Yg,{className:`h-5 w-5 text-primary`}),`自进化看板`]}),(0,K.jsxs)(`p`,{className:`mt-0.5 text-xs text-muted-foreground`,children:[e.flywheel_note,` · 数据来自审计日志与指标流的实时聚合`]})]}),(0,K.jsx)(`div`,{className:`grid grid-cols-4 gap-3 xl:grid-cols-7`,children:FO.map(t=>(0,K.jsx)(bm,{className:`py-3`,children:(0,K.jsxs)(Cm,{className:`px-3`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-1.5 text-[11px] text-muted-foreground`,children:[t.icon,t.label]}),(0,K.jsx)(`div`,{className:`mt-1 text-xl font-bold ${t.tone}`,children:e.totals[t.key]??0})]})},t.key))}),(0,K.jsxs)(`div`,{className:`mt-4 grid grid-cols-2 gap-4`,children:[(0,K.jsxs)(bm,{className:`py-0`,children:[(0,K.jsx)(xm,{className:`border-b py-2.5`,children:(0,K.jsx)(Sm,{className:`text-xs text-muted-foreground`,children:`飞轮证据 · 检索相似度趋势(回流前后对比)`})}),(0,K.jsx)(Cm,{className:`p-0`,children:(0,K.jsx)(eO,{className:`h-64`,children:(0,K.jsxs)(`div`,{className:`space-y-1.5 p-3`,children:[e.similarity_trend.length===0&&(0,K.jsx)(`div`,{className:`py-8 text-center text-xs text-muted-foreground`,children:`尚无检索记录`}),e.similarity_trend.map((e,t)=>(0,K.jsxs)(`div`,{className:`flex items-center gap-2 text-xs`,children:[(0,K.jsx)(`span`,{className:`w-40 shrink-0 truncate text-muted-foreground`,title:e.query,children:e.query}),(0,K.jsx)(`div`,{className:`h-2 flex-1 overflow-hidden rounded bg-muted`,children:(0,K.jsx)(`div`,{className:`h-full rounded ${e.similarity>=75?`bg-emerald-500`:e.similarity>=55?`bg-amber-500`:`bg-slate-500`}`,style:{width:`${e.similarity}%`}})}),(0,K.jsxs)(`span`,{className:`w-9 text-right font-mono ${e.similarity>=75?`text-emerald-400`:`text-muted-foreground`}`,children:[e.similarity,`%`]})]},t))]})})})]}),(0,K.jsxs)(bm,{className:`py-0`,children:[(0,K.jsx)(xm,{className:`border-b py-2.5`,children:(0,K.jsxs)(Sm,{className:`flex items-center gap-1.5 text-xs text-muted-foreground`,children:[(0,K.jsx)($m,{className:`h-3.5 w-3.5`}),`经验沉淀(写入 ARM 知识库)`]})}),(0,K.jsx)(Cm,{className:`p-0`,children:(0,K.jsx)(eO,{className:`h-64`,children:(0,K.jsxs)(`div`,{className:`divide-y`,children:[e.experiences.length===0&&(0,K.jsx)(`div`,{className:`p-8 text-center text-xs text-muted-foreground`,children:`尚无回流记录`}),e.experiences.map((e,t)=>(0,K.jsxs)(`div`,{className:`flex items-center gap-2 px-3 py-2 text-xs`,children:[(0,K.jsx)(kh,{className:`h-3 w-3 shrink-0 text-emerald-400`}),(0,K.jsx)(`span`,{className:`min-w-0 flex-1 truncate`,title:e.title,children:e.title}),(0,K.jsx)(`span`,{className:`shrink-0 font-mono text-[10px] text-muted-foreground`,children:e.knowledge_id?e.knowledge_id.slice(0,8):`—`}),(0,K.jsx)(`span`,{className:`shrink-0 text-[10px] text-muted-foreground`,children:gt(e.ts)})]},t))]})})})]})]}),(0,K.jsxs)(`div`,{className:`mt-4 grid grid-cols-3 gap-4`,children:[(0,K.jsxs)(bm,{className:`py-0`,children:[(0,K.jsx)(xm,{className:`border-b py-2.5`,children:(0,K.jsx)(Sm,{className:`text-xs text-muted-foreground`,children:`工具调用分布`})}),(0,K.jsxs)(Cm,{className:`p-3`,children:[Object.keys(e.by_tool).length===0&&(0,K.jsx)(`div`,{className:`py-6 text-center text-xs text-muted-foreground`,children:`暂无数据`}),Object.entries(e.by_tool).sort((e,t)=>t[1]-e[1]).map(([t,n])=>{let r=Math.max(...Object.values(e.by_tool));return(0,K.jsxs)(`div`,{className:`mb-1.5 flex items-center gap-2 text-xs`,children:[(0,K.jsx)(`span`,{className:`w-36 shrink-0 truncate font-mono`,children:t}),(0,K.jsx)(`div`,{className:`h-2 flex-1 overflow-hidden rounded bg-muted`,children:(0,K.jsx)(`div`,{className:`h-full rounded bg-sky-500`,style:{width:`${n/r*100}%`}})}),(0,K.jsx)(`span`,{className:`w-6 text-right font-mono`,children:n})]},t)})]})]}),(0,K.jsxs)(bm,{className:`py-0`,children:[(0,K.jsx)(xm,{className:`border-b py-2.5`,children:(0,K.jsxs)(Sm,{className:`flex items-center gap-1.5 text-xs text-muted-foreground`,children:[(0,K.jsx)(xh,{className:`h-3.5 w-3.5`}),`ARM 知识库实检(真实 RAG)`]})}),(0,K.jsxs)(Cm,{className:`p-3`,children:[(0,K.jsxs)(`div`,{className:`flex gap-2`,children:[(0,K.jsx)(p_,{value:n,onChange:e=>r(e.target.value),onKeyDown:e=>e.key===`Enter`&&l(),placeholder:`如:堆垛机 货叉定位偏移`,className:`text-xs`}),(0,K.jsx)(Y,{size:`sm`,disabled:o,onClick:l,children:o?`检索中`:`检索`})]}),(0,K.jsx)(eO,{className:`mt-2 h-44`,children:(0,K.jsxs)(`div`,{className:`space-y-1.5`,children:[!i&&(0,K.jsx)(`div`,{className:`py-6 text-center text-xs text-muted-foreground`,children:`输入问题检索企业经验库(与助手使用同一数据源)`}),i?.length===0&&(0,K.jsx)(`div`,{className:`py-6 text-center text-xs text-muted-foreground`,children:`无命中`}),i?.map((e,t)=>(0,K.jsxs)(`div`,{className:`rounded-md bg-card px-2.5 py-1.5`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-1.5 text-xs`,children:[e.similarity!=null&&(0,K.jsxs)(J,{variant:`secondary`,className:`h-4 text-[9px] ${e.similarity>=75?`text-emerald-400`:``}`,children:[e.similarity,`%`]}),(0,K.jsx)(`span`,{className:`truncate font-medium`,children:e.title})]}),(0,K.jsx)(`p`,{className:`mt-0.5 line-clamp-2 text-[10px] leading-relaxed text-muted-foreground`,children:e.snippet})]},t))]})})]})]}),(0,K.jsxs)(bm,{className:`py-0`,children:[(0,K.jsx)(xm,{className:`border-b py-2.5`,children:(0,K.jsx)(Sm,{className:`text-xs text-muted-foreground`,children:`审计流(实时)`})}),(0,K.jsx)(Cm,{className:`p-0`,children:(0,K.jsx)(eO,{className:`h-52`,children:(0,K.jsx)(`div`,{className:`divide-y font-mono text-[10px]`,children:e.recent_audit.map((e,t)=>(0,K.jsxs)(`div`,{className:`flex items-center gap-2 px-3 py-1.5`,children:[(0,K.jsx)(`span`,{className:`text-muted-foreground`,children:gt(e.ts,`t`)}),(0,K.jsx)(J,{variant:`outline`,className:`h-4 px-1 text-[9px]`,children:e.actor}),(0,K.jsx)(`span`,{className:`truncate`,children:e.tool||e.logic||e.action||e.name||e.verdict||``})]},t))})})})]})]})]}):(0,K.jsx)(`div`,{className:`flex h-full items-center justify-center text-sm text-muted-foreground`,children:`进化数据加载中…`})}function LO({className:e,size:t=`default`,...n}){return(0,K.jsx)(qp,{"data-slot":`switch`,"data-size":t,className:mn(`peer group/switch inline-flex shrink-0 items-center rounded-full border border-transparent shadow-xs transition-all outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-[1.15rem] data-[size=default]:w-8 data-[size=sm]:h-3.5 data-[size=sm]:w-6 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input dark:data-[state=unchecked]:bg-input/80`,e),...n,children:(0,K.jsx)(Yp,{"data-slot":`switch-thumb`,className:mn(`pointer-events-none block rounded-full bg-background ring-0 transition-transform group-data-[size=default]/switch:size-4 group-data-[size=sm]/switch:size-3 data-[state=checked]:translate-x-[calc(100%-2px)] data-[state=unchecked]:translate-x-0 dark:data-[state=checked]:bg-primary-foreground dark:data-[state=unchecked]:bg-foreground`)})})}function RO(){let[e,t]=(0,v.useState)(null),[n,r]=(0,v.useState)(null),[i,a]=(0,v.useState)(``),[o,s]=(0,v.useState)(``),[c,l]=(0,v.useState)(!1),[u,d]=(0,v.useState)(null),[f,p]=(0,v.useState)(``),[m,h]=(0,v.useState)(``),[g,_]=(0,v.useState)(``),[y,b]=(0,v.useState)(!1),[x,S]=(0,v.useState)(null),[C,w]=(0,v.useState)(``),[T,E]=(0,v.useState)(!1),[D,O]=(0,v.useState)(``),[k,A]=(0,v.useState)(!1),[j,M]=(0,v.useState)([]),[N,P]=(0,v.useState)([]),[F,I]=(0,v.useState)(!1),[L,R]=(0,v.useState)(``),[ee,te]=(0,v.useState)(``),[z,ne]=(0,v.useState)(!1),[re,ie]=(0,v.useState)(null),ae=()=>{ot(`/api/settings`).then(e=>{t(e),a(e.arm.api_base),p(e.llm.model),h(e.llm.base_url_runtime?e.llm.base_url:``),w(e.scene.profile),M(e.guard.deny),P(e.guard.ro),I(e.guard.sudo_u_l2)}),ot(`/api/arm/status`).then(r).catch(()=>r(null))};(0,v.useEffect)(()=>{ae()},[]);let oe=async()=>{l(!0),d(null);try{let e=await ct(`/api/settings`,{arm_api_base:i.trim(),...o.trim()?{arm_token:o.trim()}:{}});d(e.probe||null),s(``),e.probe?.online?Z.success(`已保存并连通(${e.probe.latency_ms}ms),源切换即时生效`):Z.warning(`已保存,但当前源不可达`,{description:e.note}),ae()}catch(e){Z.error(String(e.message))}finally{l(!1)}},se=async()=>{b(!0),S(null);try{let e=await ct(`/api/settings`,{llm_model:f.trim(),llm_base_url:m.trim(),...g.trim()?{llm_api_key:g.trim()}:{}});_(``),S(e.llm_probe||null),e.llm_probe?.online?Z.success(`模型已切换(探针 ${e.llm_probe.latency_ms}ms:${e.llm_probe.reply||`ok`})`):e.note&&Z.warning(`已保存,但探针未通过`,{description:e.note}),ae()}catch(e){Z.error(String(e.message))}finally{b(!1)}},ce=async()=>{A(!0);try{if(await ct(`/api/settings`,{access_token:D}),D.trim()){if(!(await fetch(`/api/auth/login`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({token:D.trim()})})).ok)throw Error(`已保存但自动登录失败,刷新后输入令牌进入`);Z.success(`访问令牌已启用(当前浏览器已自动登录)`)}else Z.success(`访问令牌已关闭(恢复开放访问)`);O(``),ae()}catch(e){Z.error(String(e.message))}finally{A(!1)}},le=async()=>{E(!0);try{await ct(`/api/settings`,{scene_profile:C}),Z.success(C.trim()?`场景画像已保存,对全部助手即时生效(新对话起)`:`场景画像已清空(不再注入)`),ae()}catch(e){Z.error(String(e.message))}finally{E(!1)}},B=async()=>{ne(!0);try{await ct(`/api/settings`,{guard:{deny:j,ro:N,sudo_u_l2:F}}),Z.success(`守护栏已更新(危险规则 ${j.length} 条 · 白名单 ${N.length} 命令),即时生效`),ie(null),ae()}catch(e){Z.error(String(e.message))}finally{ne(!1)}};return(0,K.jsxs)(`div`,{className:`h-full overflow-auto p-5`,children:[(0,K.jsxs)(`div`,{className:`mb-4`,children:[(0,K.jsxs)(`h1`,{className:`flex items-center gap-2 text-lg font-bold`,children:[(0,K.jsx)(kg,{className:`h-5 w-5 text-primary`}),`系统设置`]}),(0,K.jsx)(`p`,{className:`mt-0.5 text-xs text-muted-foreground`,children:`平台全局配置 · 修改保存后即时生效(无需重启)· 运行时配置优先于 .env`})]}),(0,K.jsxs)(vO,{defaultValue:`arm`,className:`max-w-2xl`,children:[(0,K.jsxs)(bO,{children:[(0,K.jsxs)(xO,{value:`arm`,className:`text-xs`,children:[(0,K.jsx)(Tg,{className:`mr-1 h-3.5 w-3.5`}),`ARM 源`,n&&(0,K.jsx)(`span`,{className:`ml-1 h-1.5 w-1.5 rounded-full ${n.online?`bg-emerald-500`:`bg-amber-500`}`})]}),(0,K.jsxs)(xO,{value:`llm`,className:`text-xs`,children:[(0,K.jsx)(th,{className:`mr-1 h-3.5 w-3.5`}),`LLM 模型服务`]}),(0,K.jsxs)(xO,{value:`scene`,className:`text-xs`,children:[(0,K.jsx)(Lh,{className:`mr-1 h-3.5 w-3.5`}),`场景画像`,e&&e.scene.length>0&&(0,K.jsx)(`span`,{className:`ml-1 h-1.5 w-1.5 rounded-full bg-emerald-500`})]}),(0,K.jsxs)(xO,{value:`auth`,className:`text-xs`,children:[(0,K.jsx)(tg,{className:`mr-1 h-3.5 w-3.5`}),`访问安全`,e?.auth.enabled&&(0,K.jsx)(`span`,{className:`ml-1 h-1.5 w-1.5 rounded-full bg-emerald-500`})]}),(0,K.jsxs)(xO,{value:`guard`,className:`text-xs`,children:[(0,K.jsx)(Fg,{className:`mr-1 h-3.5 w-3.5`}),`守护栏`,(0,K.jsxs)(`span`,{className:`ml-1 text-[9px] text-muted-foreground`,children:[j.length,`规`]})]})]}),(0,K.jsx)(SO,{value:`arm`,className:`mt-3`,children:(0,K.jsxs)(bm,{className:`mb-3 max-w-2xl`,children:[(0,K.jsxs)(xm,{className:`pb-2`,children:[(0,K.jsxs)(Sm,{className:`flex items-center gap-2 text-sm`,children:[(0,K.jsx)(Tg,{className:`h-4 w-4 text-primary`}),`ARM 源`,n&&(0,K.jsx)(J,{variant:`outline`,className:`text-[10px] ${n.online?`text-emerald-400`:`text-amber-400`}`,children:n.online?`在线 · ${n.latency_ms}ms`:`不可达(回落本地库)`})]}),(0,K.jsx)(`p`,{className:`text-[11px] leading-relaxed text-muted-foreground`,children:`ARM 是可私有化部署的资源管理系统(助手档案 + 知识库):在此切换源(如 本地开发版 → 客户私有站点), 检索/下载/同步全部即时跟随;助手已下载的本地档案不受影响。`})]}),(0,K.jsxs)(Cm,{className:`space-y-3`,children:[e&&!e.arm.token_set&&e.arm.token_source===`none`&&(0,K.jsxs)(`div`,{className:`flex items-start gap-2 rounded-md border border-amber-500/40 bg-amber-500/10 p-2.5 text-[11px] leading-relaxed text-amber-300`,children:[(0,K.jsx)(`span`,{className:`shrink-0`,children:`🔑`}),(0,K.jsxs)(`div`,{className:`flex-1`,children:[`尚未配置访问令牌——匿名仅能浏览目录,`,(0,K.jsx)(`b`,{children:`下载 / 上岗 / 新建 / 经验回流`}),`等操作会被 ARM 拒绝(401/403)。 请登录 ARM 站点生成访问令牌(arm_pat_… 开头),粘贴到下方「访问令牌」并保存。`,(0,K.jsx)(`a`,{href:e.arm.api_base,target:`_blank`,rel:`noreferrer`,className:`ml-1 underline underline-offset-2 hover:text-amber-200`,children:`打开 ARM 生成令牌 →`})]})]}),(0,K.jsxs)(`div`,{className:`space-y-1`,children:[(0,K.jsxs)(m_,{className:`flex items-center gap-2 text-xs`,children:[`站点地址(REST API 根地址)`,e&&(0,K.jsx)(J,{variant:`outline`,className:`h-4 px-1 text-[9px]`,children:e.arm.api_base_runtime?`运行时配置`:`默认(${(e.arm.default_base||``).replace(/^https?:\/\//,``)})`})]}),(0,K.jsx)(p_,{value:i,onChange:e=>a(e.target.value),placeholder:`如 http://localhost:3001 或 https://arm.customer.com`,className:`font-mono text-xs`})]}),(0,K.jsxs)(`div`,{className:`space-y-1`,children:[(0,K.jsxs)(m_,{className:`flex items-center gap-2 text-xs`,children:[`访问令牌(Token)`,e&&(0,K.jsx)(J,{variant:`outline`,className:`h-4 px-1 text-[9px]`,children:e.arm.token_set?`${e.arm.token_masked} · ${e.arm.token_source}`:`未配置(${e.arm.token_source===`pat`?`回落 ~/.arm PAT`:`匿名/只读`})`})]}),(0,K.jsx)(p_,{type:`password`,value:o,onChange:e=>s(e.target.value),placeholder:e?.arm.token_set?`已配置(留空保持不变)`:`arm_pat_…`,className:`font-mono text-xs`})]}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)(Y,{size:`sm`,className:`text-xs`,disabled:c,onClick:oe,children:c?`保存中…`:`保存并测试连接`}),u&&(0,K.jsx)(`span`,{className:`flex items-center gap-1 text-[11px] ${u.online?`text-emerald-400`:`text-amber-400`}`,children:u.online?(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(ph,{className:`h-3.5 w-3.5`}),`连通 `,u.latency_ms,`ms,源已切换`]}):(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(hh,{className:`h-3.5 w-3.5`}),`不可达:`,u.error]})})]})]})]})}),(0,K.jsx)(SO,{value:`llm`,className:`mt-3`,children:(0,K.jsxs)(bm,{className:`mb-3 max-w-2xl`,children:[(0,K.jsxs)(xm,{className:`pb-2`,children:[(0,K.jsxs)(Sm,{className:`flex items-center gap-2 text-sm`,children:[(0,K.jsx)(th,{className:`h-4 w-4 text-primary`}),`LLM 模型服务`,e&&(0,K.jsx)(J,{variant:`outline`,className:`text-[10px]`,children:e.llm.model})]}),(0,K.jsx)(`p`,{className:`text-[11px] leading-relaxed text-muted-foreground`,children:`OpenAI 兼容端点:缺省公司内网 bifrost 网关(内网开箱可用),可切换模型 / 自建网关 / 公有云端点。保存后新对话即时使用新模型,应用失败自动回滚。`})]}),(0,K.jsxs)(Cm,{className:`space-y-3`,children:[(0,K.jsxs)(`div`,{className:`space-y-1`,children:[(0,K.jsxs)(m_,{className:`flex items-center gap-2 text-xs`,children:[`模型`,e&&(0,K.jsx)(J,{variant:`outline`,className:`h-4 px-1 text-[9px]`,children:e.llm.model_runtime?`运行时配置`:`默认(.env)`})]}),(0,K.jsx)(p_,{value:f,onChange:e=>p(e.target.value),list:`llm-catalog`,placeholder:`如 def / glm-5.3 / 自定义名称`,className:`font-mono text-xs`}),(0,K.jsx)(`datalist`,{id:`llm-catalog`,children:(e?.llm.catalog||[]).map(e=>(0,K.jsx)(`option`,{value:e},e))})]}),(0,K.jsxs)(`div`,{className:`space-y-1`,children:[(0,K.jsxs)(m_,{className:`text-xs`,children:[`端点地址(留空 = `,e?.llm.default_base||`默认内网 bifrost`,`)`]}),(0,K.jsx)(p_,{value:m,onChange:e=>h(e.target.value),placeholder:`https://your-gateway/v1(OpenAI 兼容)`,className:`font-mono text-xs`})]}),(0,K.jsxs)(`div`,{className:`space-y-1`,children:[(0,K.jsxs)(m_,{className:`flex items-center gap-2 text-xs`,children:[`API Key`,e&&(0,K.jsx)(J,{variant:`outline`,className:`h-4 px-1 text-[9px]`,children:e.llm.key_set?`${e.llm.key_masked} · ${e.llm.key_source}`:`未配置`})]}),(0,K.jsx)(p_,{type:`password`,value:g,onChange:e=>_(e.target.value),placeholder:e?.llm.key_set?`已配置(留空保持不变)`:`sk-… / api key`,className:`font-mono text-xs`})]}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)(Y,{size:`sm`,className:`text-xs`,disabled:y,onClick:se,children:y?`切换中…`:`保存并测试模型`}),x&&(0,K.jsx)(`span`,{className:`flex items-center gap-1 text-[11px] ${x.online?`text-emerald-400`:`text-amber-400`}`,children:x.online?(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(ph,{className:`h-3.5 w-3.5`}),`探针通过 `,x.latency_ms,`ms:`,x.reply]}):(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(hh,{className:`h-3.5 w-3.5`}),`未通过:`,x.error]})})]})]})]})}),(0,K.jsx)(SO,{value:`scene`,className:`mt-3`,children:(0,K.jsxs)(bm,{className:`mb-3 max-w-2xl`,children:[(0,K.jsxs)(xm,{className:`pb-2`,children:[(0,K.jsxs)(Sm,{className:`flex items-center gap-2 text-sm`,children:[(0,K.jsx)(Lh,{className:`h-4 w-4 text-primary`}),`场景画像`,e&&(0,K.jsx)(J,{variant:`outline`,className:`text-[10px] ${e.scene.length?`text-emerald-400`:``}`,children:e.scene.length?`已启用 · ${e.scene.length} 字`:`未配置(不注入)`})]}),(0,K.jsxs)(`p`,{className:`text-[11px] leading-relaxed text-muted-foreground`,children:[`平台级、全局一份的使用方场景描述(团队环境 / 系统清单 / 规范 / 联系人),作为常驻事实注入`,(0,K.jsx)(`b`,{children:`所有助手`}),`的上下文—— 助手不必每次重新探索环境。与知识检索互补(常驻事实 vs 按需检索)。⚠ 不放凭据:写"凭据在哪、找谁要"即可。`]})]}),(0,K.jsxs)(Cm,{className:`space-y-2`,children:[(0,K.jsx)(`textarea`,{value:C,onChange:e=>w(e.target.value),spellCheck:!1,rows:8,placeholder:`例如:
101
101
  · 团队负责公司内部系统的运维与研发提效
102
102
  · 系统:ARM(助手管理)、Nexus(nexus.aimstek.cn)、Jenkins、玄武环境、WMS
103
103
  · 服务器多为 root/统一密码策略,凭据找张三
104
- · 告警需通知刘工;报告用中文`,className:`w-full resize-y rounded-md border bg-background p-2.5 font-mono text-xs leading-relaxed`}),(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`span`,{className:`text-[10px] text-muted-foreground`,children:[T.length,`/4000 字 · 修改对新对话即时生效 · 清空则恢复"不注入"`]}),(0,K.jsx)(Y,{size:`sm`,className:`text-xs`,disabled:D||T.length>4e3,onClick:V,children:D?`保存中…`:`保存画像`})]})]})]})}),(0,K.jsx)(SO,{value:`auth`,className:`mt-3`,children:(0,K.jsxs)(bm,{children:[(0,K.jsxs)(xm,{className:`pb-2`,children:[(0,K.jsxs)(Sm,{className:`flex items-center gap-2 text-sm`,children:[(0,K.jsx)(tg,{className:`h-4 w-4 text-primary`}),`访问令牌`,e&&(0,K.jsx)(J,{variant:`outline`,className:`text-[10px] ${e.auth.enabled?`text-emerald-400`:`text-amber-400`}`,children:e.auth.enabled?`已启用 · ${e.auth.token_masked}`:`未启用(局域网内开放访问)`})]}),(0,K.jsxs)(`p`,{className:`text-[11px] leading-relaxed text-muted-foreground`,children:[`工作站监听 0.0.0.0(局域网可达),启用令牌后所有 API 需要认证:浏览器登录换 Cookie(自动携带), 脚本用 `,(0,K.jsx)(`span`,{className:`font-mono`,children:`Authorization: Bearer <token>`}),`。留空保存即关闭。`]})]}),(0,K.jsxs)(Cm,{className:`space-y-2`,children:[(0,K.jsx)(p_,{type:`password`,value:k,onChange:e=>A(e.target.value),placeholder:e?.auth.enabled?`输入新令牌替换(留空保存=关闭认证)`:`设置访问令牌(留空=不启用)`,className:`font-mono text-xs`}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)(Y,{size:`sm`,className:`text-xs`,disabled:j,onClick:B,children:j?`保存中…`:`保存`}),(0,K.jsx)(`span`,{className:`text-[10px] text-muted-foreground`,children:`启用后其他设备首次访问将看到登录页 · 替换令牌会使所有已登录设备失效`})]})]})]})}),(0,K.jsx)(SO,{value:`guard`,className:`mt-3`,children:(0,K.jsxs)(bm,{className:`mb-3 max-w-2xl`,children:[(0,K.jsxs)(xm,{className:`pb-2`,children:[(0,K.jsxs)(Sm,{className:`flex items-center gap-2 text-sm`,children:[(0,K.jsx)(Fg,{className:`h-4 w-4 text-primary`}),`守护栏 · 助手命令执行策略`,(0,K.jsxs)(J,{variant:`outline`,className:`text-[10px]`,children:[N.length,` 危险规则 · `,F.length,` 白名单命令`]})]}),(0,K.jsxs)(`p`,{className:`text-[11px] leading-relaxed text-muted-foreground`,children:[`危险清单(正则,命中即`,(0,K.jsx)(`b`,{children:`永久拒绝`}),`,任何自主级别不豁免)与只读白名单(免确认直行)保存后即时生效,全程写审计。 只读之外的命令按写命令分级:L0/L1 拒绝、L2 人工确认、L3 免确认。`]})]}),(0,K.jsxs)(Cm,{className:`space-y-4`,children:[(0,K.jsxs)(`div`,{className:`space-y-1.5`,children:[(0,K.jsx)(m_,{className:`text-xs`,children:`危险命令清单(正则,对整条命令做词面匹配)`}),(0,K.jsx)(`div`,{className:`space-y-1`,children:N.map(e=>(0,K.jsxs)(`div`,{className:`flex items-center gap-2 rounded-md border border-red-500/30 bg-red-500/5 px-2 py-1`,children:[(0,K.jsx)(`code`,{className:`min-w-0 flex-1 break-all font-mono text-[11px] text-red-300`,children:e}),(0,K.jsx)(Y,{size:`icon`,variant:`ghost`,className:`h-5 w-5 shrink-0`,onClick:()=>P(t=>t.filter(t=>t!==e)),title:`删除该规则`,children:(0,K.jsx)(r_,{className:`h-3 w-3`})})]},e))}),(0,K.jsxs)(`div`,{className:`flex gap-2`,children:[(0,K.jsx)(p_,{value:ee,onChange:e=>te(e.target.value),placeholder:`新增正则,如 \\b(fdisk|parted)\\b 或 \\bmv\\b\\s+--force`,className:`font-mono text-xs`,onKeyDown:e=>{e.key===`Enter`&&ee.trim()&&(P(e=>[...new Set([...e,ee.trim()])]),te(``))}}),(0,K.jsxs)(Y,{size:`sm`,variant:`outline`,className:`shrink-0 text-xs`,disabled:!ee.trim(),onClick:()=>{P(e=>[...new Set([...e,ee.trim()])]),te(``)},children:[(0,K.jsx)(dg,{className:`h-3 w-3`}),`添加`]})]}),N.length===0&&(0,K.jsx)(`p`,{className:`text-[10px] text-red-400`,children:`⚠ 清单为空 = 无任何命令会被永久拒绝(写命令仍走 L2/L3 分级)`})]}),(0,K.jsxs)(`div`,{className:`space-y-1.5`,children:[(0,K.jsx)(m_,{className:`text-xs`,children:`只读白名单(单个命令名,复合命令逐段判定)`}),(0,K.jsx)(`div`,{className:`flex flex-wrap gap-1`,children:F.map(e=>(0,K.jsxs)(`span`,{className:`inline-flex items-center gap-1 rounded-md border bg-muted/50 px-1.5 py-0.5 font-mono text-[10px]`,children:[e,(0,K.jsx)(`button`,{className:`text-muted-foreground hover:text-red-400`,onClick:()=>I(t=>t.filter(t=>t!==e)),title:`移除`,children:(0,K.jsx)(r_,{className:`h-2.5 w-2.5`})})]},e))}),(0,K.jsxs)(`div`,{className:`flex gap-2`,children:[(0,K.jsx)(p_,{value:z,onChange:e=>ne(e.target.value),placeholder:`新增命令名,如 jq / awk / ss`,className:`font-mono text-xs`,onKeyDown:e=>{e.key===`Enter`&&z.trim()&&(I(e=>[...new Set([...e,z.trim()])]),ne(``))}}),(0,K.jsxs)(Y,{size:`sm`,variant:`outline`,className:`shrink-0 text-xs`,disabled:!z.trim(),onClick:()=>{I(e=>[...new Set([...e,z.trim()])]),ne(``)},children:[(0,K.jsx)(dg,{className:`h-3 w-3`}),`添加`]})]}),(0,K.jsx)(`p`,{className:`text-[10px] text-muted-foreground`,children:`⚠ 白名单命令带重定向(> / >> / tee)时不算只读;sqlite3 的 INSERT/UPDATE/DELETE 等写语句不算只读`})]}),(0,K.jsxs)(`div`,{className:`flex items-start gap-2.5 rounded-md border border-amber-500/30 bg-amber-500/5 p-2.5`,children:[(0,K.jsx)(LO,{checked:L,onCheckedChange:R,className:`mt-0.5`}),(0,K.jsxs)(`div`,{className:`space-y-0.5`,children:[(0,K.jsx)(`div`,{className:`text-xs font-medium`,children:`允许 sudo 降权形式(sudo -u <用户>)经 L2 人工确认后执行`}),(0,K.jsx)(`p`,{className:`text-[10px] leading-relaxed text-muted-foreground`,children:"默认关闭:所有含 sudo 的命令永久拒绝(含远程 SSH 命令中的 sudo)。开启后 `sudo -u 用户` 片段不再触发永久拒绝、 按写命令走 L2 确认(L3 免确认);裸 sudo(如 sudo reboot)与嵌套危险命令仍永久拒绝。"})]})]}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)(Y,{size:`sm`,className:`text-xs`,disabled:re,onClick:()=>{let t=(e?.guard.deny||[]).filter(e=>!N.includes(e));t.length?oe(t):H()},children:re?`保存中…`:`保存(即时生效)`}),(0,K.jsx)(Y,{size:`sm`,variant:`outline`,className:`text-xs`,onClick:()=>{e&&(P(e.guard.default_deny.slice()),I(e.guard.default_ro.slice()),R(!1),Z.info(`已填入出厂默认(未保存,点击「保存」生效)`))},children:`恢复出厂默认`}),(0,K.jsx)(`span`,{className:`text-[10px] text-muted-foreground`,children:`修改立即作用于全部助手对话 · 删减危险规则需二次确认并写审计`})]})]})]})})]}),(0,K.jsxs)(bm,{className:`mt-1 max-w-2xl text-xs text-muted-foreground`,children:[(0,K.jsx)(xm,{className:`pb-1`,children:(0,K.jsx)(Sm,{className:`text-sm`,children:`只读信息`})}),(0,K.jsxs)(Cm,{className:`space-y-1`,children:[(0,K.jsxs)(`div`,{children:[`本地助手库:`,n?.local_count??`…`,` 名 · 离线经验待回流:`,n?.outbox_pending??0,` 条`]}),(0,K.jsx)(`div`,{children:`优先级:运行时配置(本页)> 环境变量 > .env 默认值 · 令牌仅存本机 config/platform.json,界面永远掩码展示`})]})]}),(0,K.jsx)(a_,{open:ae!==null,onOpenChange:e=>{e||oe(null)},children:(0,K.jsxs)(c_,{className:`max-w-md`,children:[(0,K.jsxs)(l_,{children:[(0,K.jsxs)(d_,{className:`flex items-center gap-2 text-sm`,children:[(0,K.jsx)(Fg,{className:`h-4 w-4 text-red-400`}),`确认放行危险命令规则?`]}),(0,K.jsxs)(f_,{className:`text-xs leading-relaxed`,children:[`你正在移除 `,ae?.length,` 条永久拒绝规则,保存后助手将可以发起匹配这些规则的命令(仍按写命令分级:L2 需人工确认 / L3 免确认)。此操作将写入审计日志。`]})]}),(0,K.jsx)(`div`,{className:`max-h-40 space-y-1 overflow-auto`,children:ae?.map(e=>(0,K.jsx)(`div`,{className:`rounded-md border border-red-500/40 bg-red-500/10 px-2 py-1 font-mono text-[11px] break-all text-red-300`,children:e},e))}),(0,K.jsxs)(u_,{children:[(0,K.jsx)(Y,{variant:`outline`,size:`sm`,onClick:()=>oe(null),children:`取消`}),(0,K.jsx)(Y,{variant:`destructive`,size:`sm`,disabled:re,onClick:H,children:re?`保存中…`:`确认放行并保存`})]})]})})]})}function zO({onOk:e}){let[t,n]=(0,v.useState)(``),[r,i]=(0,v.useState)(!1),[a,o]=(0,v.useState)(``),s=async()=>{if(t.trim()&&!r){i(!0),o(``);try{let n=await fetch(`/api/auth/login`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({token:t.trim()})});if(!n.ok)throw Error((await n.json().catch(()=>({}))).error||`令牌不正确`);e()}catch(e){o(String(e.message))}finally{i(!1)}}};return(0,K.jsxs)(`div`,{className:`flex h-screen flex-col items-center justify-center gap-4 bg-background text-foreground`,children:[(0,K.jsx)(tg,{className:`h-8 w-8 text-primary`}),(0,K.jsx)(`div`,{className:`text-base font-semibold`,children:`AIMS 工作站已启用访问令牌`}),(0,K.jsxs)(`div`,{className:`flex gap-2`,children:[(0,K.jsx)(p_,{type:`password`,value:t,onChange:e=>n(e.target.value),onKeyDown:e=>{e.key===`Enter`&&!e.nativeEvent.isComposing&&s()},placeholder:`输入访问令牌…`,className:`w-64`,autoFocus:!0}),(0,K.jsx)(Y,{onClick:s,disabled:r||!t.trim(),children:r?`验证中…`:`进入`})]}),a&&(0,K.jsx)(`div`,{className:`text-xs text-red-400`,children:a}),(0,K.jsx)(`div`,{className:`text-[11px] text-muted-foreground`,children:`令牌在「系统设置 → 访问安全」配置 · 脚本访问可用 Authorization: Bearer 头`})]})}function BO(){let[e,t]=(0,v.useState)(`hub`),[n,r]=(0,v.useState)(null),[i,a]=(0,v.useState)(``),[o,s]=(0,v.useState)(null),[c,l]=(0,v.useState)(!1),[u,d]=(0,v.useState)([]),[f,p]=(0,v.useState)(null);(0,v.useEffect)(()=>{ot(`/api/health`).then(e=>{s(e),l(!!e.auth_required)}).catch(()=>s(null));let e=()=>ot(`/api/quick-switch`).then(e=>d(e.agents||[])).catch(()=>{});e();let t=setInterval(e,5e3);return()=>clearInterval(t)},[]),(0,v.useEffect)(()=>{n&&p(n)},[n]);let m=(e,n,i)=>{r(e),a(n),t(i)},h=u.filter(e=>e.running||e.pending).length;if(c)return(0,K.jsx)(zO,{onOk:()=>{l(!1),ot(`/api/health`).then(e=>{s(e),l(!!e.auth_required)}).catch(()=>{})}});let g=e=>it(`flex items-center gap-2 rounded-md px-3 py-2 text-sm transition-colors`,e?`bg-primary/15 font-medium text-primary`:`text-muted-foreground hover:bg-accent hover:text-foreground`);return(0,K.jsxs)(`div`,{className:`flex h-screen overflow-hidden bg-background text-foreground`,children:[(0,K.jsxs)(`aside`,{className:`flex w-52 shrink-0 flex-col border-r border-sidebar-border bg-sidebar text-sidebar-foreground`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-2 px-4 py-4`,children:[(0,K.jsx)(Dh,{className:`h-6 w-6 text-primary`}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`div`,{className:`text-sm font-bold leading-tight`,children:`AIMS 工业智能体平台`}),(0,K.jsx)(`div`,{className:`text-[10px] text-muted-foreground`,children:`平台AI化 · 系统工具化`})]})]}),(0,K.jsxs)(`nav`,{className:`flex flex-col gap-1 px-2`,children:[(0,K.jsxs)(`button`,{onClick:()=>t(`hub`),className:g(e===`hub`),children:[(0,K.jsx)(Yh,{className:`h-4 w-4`}),`助手大厅`]}),(0,K.jsxs)(`button`,{onClick:()=>t(`evolution`),className:g(e===`evolution`),children:[(0,K.jsx)(Yg,{className:`h-4 w-4`}),`自进化`]}),(0,K.jsxs)(`button`,{onClick:()=>t(`plugins`),className:g(e===`plugins`),children:[(0,K.jsx)(pg,{className:`h-4 w-4`}),`插件中心`]}),(0,K.jsxs)(`button`,{onClick:()=>t(`settings`),className:g(e===`settings`),children:[(0,K.jsx)(kg,{className:`h-4 w-4`}),`系统设置`]})]}),(0,K.jsxs)(`div`,{className:`mt-3 flex items-center justify-between border-t border-sidebar-border px-4 pb-1 pt-3`,children:[(0,K.jsxs)(`span`,{className:`text-[11px] font-semibold uppercase tracking-wide text-muted-foreground`,children:[`小助手 · 在岗 `,u.length]}),h>0&&(0,K.jsxs)(`span`,{className:`text-[10px] text-emerald-400`,title:`会话在后台运行中,切回即可看到进度`,children:[`● `,h,` 运行`]})]}),(0,K.jsxs)(`div`,{className:`min-h-0 flex-1 overflow-y-auto px-2 pb-2`,children:[u.length===0&&(0,K.jsx)(`p`,{className:`px-3 py-2 text-[11px] leading-relaxed text-muted-foreground`,children:`在「助手大厅」完成上岗配置后,这里按助手分组,一键直达各自的工作台。`}),u.map(t=>{let r=n===t.agent_id,i=f===t.agent_id,a=e=>it(`flex items-center gap-2 rounded-md px-2.5 py-1.5 text-xs transition-colors`,e?`bg-primary/15 font-medium text-primary`:`text-muted-foreground hover:bg-accent hover:text-foreground`);return(0,K.jsxs)(`div`,{className:`mb-0.5`,children:[(0,K.jsxs)(`div`,{className:it(`group flex items-center gap-0.5 rounded-md pr-1 transition-colors`,r&&e!==`hub`?`bg-primary/10`:`hover:bg-accent`),children:[(0,K.jsx)(`button`,{onClick:()=>p(i?null:t.agent_id),className:`flex h-9 w-6 shrink-0 items-center justify-center text-muted-foreground hover:text-foreground`,title:i?`折叠`:`展开`,children:i?(0,K.jsx)(ah,{className:`h-3.5 w-3.5`}):(0,K.jsx)(sh,{className:`h-3.5 w-3.5`})}),(0,K.jsxs)(`button`,{onClick:()=>m(t.agent_id,t.name,`workbench`),title:t.running||t.pending?`${t.name} · ${t.statusText}`:t.name,className:it(`flex min-w-0 flex-1 items-center gap-1.5 py-2 pr-1 text-left text-sm`,r&&e!==`hub`?`font-medium text-primary`:`text-muted-foreground group-hover:text-foreground`),children:[(t.running||t.pending)&&(0,K.jsx)(`span`,{className:it(`h-1.5 w-1.5 shrink-0 rounded-full`,t.running?`animate-pulse bg-emerald-500`:`bg-amber-500`)}),(0,K.jsx)(`span`,{className:`truncate`,children:t.name})]})]}),i&&(0,K.jsxs)(`div`,{className:`ml-6 mt-0.5 flex flex-col gap-0.5 border-l border-border/60 pl-2`,children:[(0,K.jsxs)(`button`,{onClick:()=>m(t.agent_id,t.name,`workbench`),className:a(r&&e===`workbench`),children:[(0,K.jsx)(ag,{className:`h-3.5 w-3.5`}),`工作台`]}),(0,K.jsxs)(`button`,{onClick:()=>m(t.agent_id,t.name,`editor`),className:a(r&&e===`editor`),children:[(0,K.jsx)(Dg,{className:`h-3.5 w-3.5`}),`定制工作台`]})]})]},t.agent_id)})]}),(0,K.jsxs)(`div`,{className:`mt-auto space-y-1.5 border-t border-sidebar-border px-4 pb-4 pt-3 text-[11px] text-muted-foreground`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-1.5`,children:[(0,K.jsx)(`span`,{className:it(`h-1.5 w-1.5 rounded-full`,o?`bg-emerald-500`:`bg-red-500`)}),`LLM `,o?.model||`未连接`,`(pi-ai)`]}),(0,K.jsxs)(`div`,{className:`flex items-center gap-1.5`,children:[(0,K.jsx)(`span`,{className:it(`h-1.5 w-1.5 rounded-full`,o?`bg-emerald-500`:`bg-red-500`)}),`ARM `,o?o.pat?`已连接·PAT`:`已连接·只读`:`未连接`]})]})]}),(0,K.jsxs)(`div`,{className:`flex min-w-0 flex-1 flex-col`,children:[(0,K.jsxs)(`header`,{className:`flex h-12 shrink-0 items-center gap-3 border-b bg-card px-5`,children:[(0,K.jsx)(th,{className:`h-4 w-4 text-primary`}),(0,K.jsx)(`span`,{className:`text-sm font-semibold`,children:i||`数字员工队伍`}),n&&(0,K.jsx)(J,{variant:`outline`,className:`text-[10px]`,children:`在岗`}),(0,K.jsxs)(`span`,{className:`ml-auto text-xs text-muted-foreground`,children:[e===`hub`&&`从 ARM 员工库选择助手,或为未上岗助手完成上岗配置`,e===`editor`&&`AI 起草 → 人工审阅 → 版本化发布 → 可回滚`,e===`evolution`&&`数据回流 · 评测迭代 · 知识沉淀 · 飞轮证据`,e===`plugins`&&`统一注册表 · 生命周期 · 引用追踪 · 治理策略`,e===`settings`&&`ARM 源切换 · 令牌管理 · 保存即生效`]})]}),(0,K.jsxs)(`main`,{className:`min-h-0 flex-1 overflow-hidden`,children:[e===`hub`&&(0,K.jsx)(ev,{onOpen:m}),e===`workbench`&&n&&(0,K.jsx)(gO,{agentId:n,onName:a,onEdit:()=>t(`editor`)},n),e===`editor`&&n&&(0,K.jsx)(PO,{agentId:n},n),e===`evolution`&&(0,K.jsx)(IO,{}),e===`plugins`&&(0,K.jsx)(jO,{}),e===`settings`&&(0,K.jsx)(RO,{}),(e===`workbench`||e===`editor`)&&!n&&(0,K.jsx)(`div`,{className:`flex h-full items-center justify-center text-sm text-muted-foreground`,children:`请先在助手大厅选择一名助手`})]})]})]})}var VO=(e,t,n,r,i,a,o,s)=>{let c=document.documentElement,l=[`light`,`dark`];function u(t){(Array.isArray(e)?e:[e]).forEach(e=>{let n=e===`class`,r=n&&a?i.map(e=>a[e]||e):i;n?(c.classList.remove(...r),c.classList.add(a&&a[t]?a[t]:t)):c.setAttribute(e,t)}),d(t)}function d(e){s&&l.includes(e)&&(c.style.colorScheme=e)}function f(){return window.matchMedia(`(prefers-color-scheme: dark)`).matches?`dark`:`light`}if(r)u(r);else try{let e=localStorage.getItem(t)||n;u(o&&e===`system`?f():e)}catch{}},HO=v.createContext(void 0),UO={setTheme:e=>{},themes:[]},WO=()=>v.useContext(HO)??UO;v.memo(({forcedTheme:e,storageKey:t,attribute:n,enableSystem:r,enableColorScheme:i,defaultTheme:a,value:o,themes:s,nonce:c,scriptProps:l})=>{let u=JSON.stringify([n,t,a,e,s,o,r,i]).slice(1,-1);return v.createElement(`script`,{...l,suppressHydrationWarning:!0,nonce:typeof window>`u`?c:``,dangerouslySetInnerHTML:{__html:`(${VO.toString()})(${u})`}})}),(0,y.createRoot)(document.getElementById(`root`)).render((0,K.jsxs)(v.StrictMode,{children:[(0,K.jsx)(BO,{}),(0,K.jsx)(({...e})=>{let{theme:t=`system`}=WO();return(0,K.jsx)(Q_,{theme:t,className:`toaster group`,icons:{success:(0,K.jsx)(ph,{className:`size-4`}),info:(0,K.jsx)(Uh,{className:`size-4`}),warning:(0,K.jsx)(Zg,{className:`size-4`}),error:(0,K.jsx)(lg,{className:`size-4`}),loading:(0,K.jsx)($h,{className:`size-4 animate-spin`})},style:{"--normal-bg":`var(--popover)`,"--normal-text":`var(--popover-foreground)`,"--normal-border":`var(--border)`,"--border-radius":`var(--radius)`},...e})},{richColors:!0,position:`top-center`})]}));
104
+ · 告警需通知刘工;报告用中文`,className:`w-full resize-y rounded-md border bg-background p-2.5 font-mono text-xs leading-relaxed`}),(0,K.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,K.jsxs)(`span`,{className:`text-[10px] text-muted-foreground`,children:[C.length,`/4000 字 · 修改对新对话即时生效 · 清空则恢复"不注入"`]}),(0,K.jsx)(Y,{size:`sm`,className:`text-xs`,disabled:T||C.length>4e3,onClick:le,children:T?`保存中…`:`保存画像`})]})]})]})}),(0,K.jsx)(SO,{value:`auth`,className:`mt-3`,children:(0,K.jsxs)(bm,{children:[(0,K.jsxs)(xm,{className:`pb-2`,children:[(0,K.jsxs)(Sm,{className:`flex items-center gap-2 text-sm`,children:[(0,K.jsx)(tg,{className:`h-4 w-4 text-primary`}),`访问令牌`,e&&(0,K.jsx)(J,{variant:`outline`,className:`text-[10px] ${e.auth.enabled?`text-emerald-400`:`text-amber-400`}`,children:e.auth.enabled?`已启用 · ${e.auth.token_masked}`:`未启用(局域网内开放访问)`})]}),(0,K.jsxs)(`p`,{className:`text-[11px] leading-relaxed text-muted-foreground`,children:[`工作站监听 0.0.0.0(局域网可达),启用令牌后所有 API 需要认证:浏览器登录换 Cookie(自动携带), 脚本用 `,(0,K.jsx)(`span`,{className:`font-mono`,children:`Authorization: Bearer <token>`}),`。留空保存即关闭。`]})]}),(0,K.jsxs)(Cm,{className:`space-y-2`,children:[(0,K.jsx)(p_,{type:`password`,value:D,onChange:e=>O(e.target.value),placeholder:e?.auth.enabled?`输入新令牌替换(留空保存=关闭认证)`:`设置访问令牌(留空=不启用)`,className:`font-mono text-xs`}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)(Y,{size:`sm`,className:`text-xs`,disabled:k,onClick:ce,children:k?`保存中…`:`保存`}),(0,K.jsx)(`span`,{className:`text-[10px] text-muted-foreground`,children:`启用后其他设备首次访问将看到登录页 · 替换令牌会使所有已登录设备失效`})]})]})]})}),(0,K.jsx)(SO,{value:`guard`,className:`mt-3`,children:(0,K.jsxs)(bm,{className:`mb-3 max-w-2xl`,children:[(0,K.jsxs)(xm,{className:`pb-2`,children:[(0,K.jsxs)(Sm,{className:`flex items-center gap-2 text-sm`,children:[(0,K.jsx)(Fg,{className:`h-4 w-4 text-primary`}),`守护栏 · 助手命令执行策略`,(0,K.jsxs)(J,{variant:`outline`,className:`text-[10px]`,children:[j.length,` 危险规则 · `,N.length,` 白名单命令`]})]}),(0,K.jsxs)(`p`,{className:`text-[11px] leading-relaxed text-muted-foreground`,children:[`危险清单(正则,命中即`,(0,K.jsx)(`b`,{children:`永久拒绝`}),`,任何自主级别不豁免)与只读白名单(免确认直行)保存后即时生效,全程写审计。 只读之外的命令按写命令分级:L0/L1 拒绝、L2 人工确认、L3 免确认。`]})]}),(0,K.jsxs)(Cm,{className:`space-y-4`,children:[(0,K.jsxs)(`div`,{className:`space-y-1.5`,children:[(0,K.jsx)(m_,{className:`text-xs`,children:`危险命令清单(正则,对整条命令做词面匹配)`}),(0,K.jsx)(`div`,{className:`space-y-1`,children:j.map(e=>(0,K.jsxs)(`div`,{className:`flex items-center gap-2 rounded-md border border-red-500/30 bg-red-500/5 px-2 py-1`,children:[(0,K.jsx)(`code`,{className:`min-w-0 flex-1 break-all font-mono text-[11px] text-red-300`,children:e}),(0,K.jsx)(Y,{size:`icon`,variant:`ghost`,className:`h-5 w-5 shrink-0`,onClick:()=>M(t=>t.filter(t=>t!==e)),title:`删除该规则`,children:(0,K.jsx)(r_,{className:`h-3 w-3`})})]},e))}),(0,K.jsxs)(`div`,{className:`flex gap-2`,children:[(0,K.jsx)(p_,{value:L,onChange:e=>R(e.target.value),placeholder:`新增正则,如 \\b(fdisk|parted)\\b 或 \\bmv\\b\\s+--force`,className:`font-mono text-xs`,onKeyDown:e=>{e.key===`Enter`&&L.trim()&&(M(e=>[...new Set([...e,L.trim()])]),R(``))}}),(0,K.jsxs)(Y,{size:`sm`,variant:`outline`,className:`shrink-0 text-xs`,disabled:!L.trim(),onClick:()=>{M(e=>[...new Set([...e,L.trim()])]),R(``)},children:[(0,K.jsx)(dg,{className:`h-3 w-3`}),`添加`]})]}),j.length===0&&(0,K.jsx)(`p`,{className:`text-[10px] text-red-400`,children:`⚠ 清单为空 = 无任何命令会被永久拒绝(写命令仍走 L2/L3 分级)`})]}),(0,K.jsxs)(`div`,{className:`space-y-1.5`,children:[(0,K.jsx)(m_,{className:`text-xs`,children:`只读白名单(单个命令名,复合命令逐段判定)`}),(0,K.jsx)(`div`,{className:`flex flex-wrap gap-1`,children:N.map(e=>(0,K.jsxs)(`span`,{className:`inline-flex items-center gap-1 rounded-md border bg-muted/50 px-1.5 py-0.5 font-mono text-[10px]`,children:[e,(0,K.jsx)(`button`,{className:`text-muted-foreground hover:text-red-400`,onClick:()=>P(t=>t.filter(t=>t!==e)),title:`移除`,children:(0,K.jsx)(r_,{className:`h-2.5 w-2.5`})})]},e))}),(0,K.jsxs)(`div`,{className:`flex gap-2`,children:[(0,K.jsx)(p_,{value:ee,onChange:e=>te(e.target.value),placeholder:`新增命令名,如 jq / awk / ss`,className:`font-mono text-xs`,onKeyDown:e=>{e.key===`Enter`&&ee.trim()&&(P(e=>[...new Set([...e,ee.trim()])]),te(``))}}),(0,K.jsxs)(Y,{size:`sm`,variant:`outline`,className:`shrink-0 text-xs`,disabled:!ee.trim(),onClick:()=>{P(e=>[...new Set([...e,ee.trim()])]),te(``)},children:[(0,K.jsx)(dg,{className:`h-3 w-3`}),`添加`]})]}),(0,K.jsx)(`p`,{className:`text-[10px] text-muted-foreground`,children:`⚠ 白名单命令带重定向(> / >> / tee)时不算只读;sqlite3 的 INSERT/UPDATE/DELETE 等写语句不算只读`})]}),(0,K.jsxs)(`div`,{className:`flex items-start gap-2.5 rounded-md border border-amber-500/30 bg-amber-500/5 p-2.5`,children:[(0,K.jsx)(LO,{checked:F,onCheckedChange:I,className:`mt-0.5`}),(0,K.jsxs)(`div`,{className:`space-y-0.5`,children:[(0,K.jsx)(`div`,{className:`text-xs font-medium`,children:`允许 sudo 降权形式(sudo -u <用户>)经 L2 人工确认后执行`}),(0,K.jsx)(`p`,{className:`text-[10px] leading-relaxed text-muted-foreground`,children:"默认关闭:所有含 sudo 的命令永久拒绝(含远程 SSH 命令中的 sudo)。开启后 `sudo -u 用户` 片段不再触发永久拒绝、 按写命令走 L2 确认(L3 免确认);裸 sudo(如 sudo reboot)与嵌套危险命令仍永久拒绝。"})]})]}),(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)(Y,{size:`sm`,className:`text-xs`,disabled:z,onClick:()=>{let t=(e?.guard.deny||[]).filter(e=>!j.includes(e));t.length?ie(t):B()},children:z?`保存中…`:`保存(即时生效)`}),(0,K.jsx)(Y,{size:`sm`,variant:`outline`,className:`text-xs`,onClick:()=>{e&&(M(e.guard.default_deny.slice()),P(e.guard.default_ro.slice()),I(!1),Z.info(`已填入出厂默认(未保存,点击「保存」生效)`))},children:`恢复出厂默认`}),(0,K.jsx)(`span`,{className:`text-[10px] text-muted-foreground`,children:`修改立即作用于全部助手对话 · 删减危险规则需二次确认并写审计`})]})]})]})})]}),(0,K.jsxs)(bm,{className:`mt-1 max-w-2xl text-xs text-muted-foreground`,children:[(0,K.jsx)(xm,{className:`pb-1`,children:(0,K.jsx)(Sm,{className:`text-sm`,children:`只读信息`})}),(0,K.jsxs)(Cm,{className:`space-y-1`,children:[(0,K.jsxs)(`div`,{children:[`本地助手库:`,n?.local_count??`…`,` 名 · 离线经验待回流:`,n?.outbox_pending??0,` 条`]}),(0,K.jsx)(`div`,{children:`优先级:运行时配置(本页)> 环境变量 > .env 默认值 · 令牌仅存本机 config/platform.json,界面永远掩码展示`})]})]}),(0,K.jsx)(a_,{open:re!==null,onOpenChange:e=>{e||ie(null)},children:(0,K.jsxs)(c_,{className:`max-w-md`,children:[(0,K.jsxs)(l_,{children:[(0,K.jsxs)(d_,{className:`flex items-center gap-2 text-sm`,children:[(0,K.jsx)(Fg,{className:`h-4 w-4 text-red-400`}),`确认放行危险命令规则?`]}),(0,K.jsxs)(f_,{className:`text-xs leading-relaxed`,children:[`你正在移除 `,re?.length,` 条永久拒绝规则,保存后助手将可以发起匹配这些规则的命令(仍按写命令分级:L2 需人工确认 / L3 免确认)。此操作将写入审计日志。`]})]}),(0,K.jsx)(`div`,{className:`max-h-40 space-y-1 overflow-auto`,children:re?.map(e=>(0,K.jsx)(`div`,{className:`rounded-md border border-red-500/40 bg-red-500/10 px-2 py-1 font-mono text-[11px] break-all text-red-300`,children:e},e))}),(0,K.jsxs)(u_,{children:[(0,K.jsx)(Y,{variant:`outline`,size:`sm`,onClick:()=>ie(null),children:`取消`}),(0,K.jsx)(Y,{variant:`destructive`,size:`sm`,disabled:z,onClick:B,children:z?`保存中…`:`确认放行并保存`})]})]})})]})}function zO({onOk:e}){let[t,n]=(0,v.useState)(``),[r,i]=(0,v.useState)(!1),[a,o]=(0,v.useState)(``),s=async()=>{if(t.trim()&&!r){i(!0),o(``);try{let n=await fetch(`/api/auth/login`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({token:t.trim()})});if(!n.ok)throw Error((await n.json().catch(()=>({}))).error||`令牌不正确`);e()}catch(e){o(String(e.message))}finally{i(!1)}}};return(0,K.jsxs)(`div`,{className:`flex h-screen flex-col items-center justify-center gap-4 bg-background text-foreground`,children:[(0,K.jsx)(tg,{className:`h-8 w-8 text-primary`}),(0,K.jsx)(`div`,{className:`text-base font-semibold`,children:`AIMS 工作站已启用访问令牌`}),(0,K.jsxs)(`div`,{className:`flex gap-2`,children:[(0,K.jsx)(p_,{type:`password`,value:t,onChange:e=>n(e.target.value),onKeyDown:e=>{e.key===`Enter`&&!e.nativeEvent.isComposing&&s()},placeholder:`输入访问令牌…`,className:`w-64`,autoFocus:!0}),(0,K.jsx)(Y,{onClick:s,disabled:r||!t.trim(),children:r?`验证中…`:`进入`})]}),a&&(0,K.jsx)(`div`,{className:`text-xs text-red-400`,children:a}),(0,K.jsx)(`div`,{className:`text-[11px] text-muted-foreground`,children:`令牌在「系统设置 → 访问安全」配置 · 脚本访问可用 Authorization: Bearer 头`})]})}function BO(){let[e,t]=(0,v.useState)(`hub`),[n,r]=(0,v.useState)(null),[i,a]=(0,v.useState)(``),[o,s]=(0,v.useState)(null),[c,l]=(0,v.useState)(!1),[u,d]=(0,v.useState)([]),[f,p]=(0,v.useState)(null);(0,v.useEffect)(()=>{ot(`/api/health`).then(e=>{s(e),l(!!e.auth_required)}).catch(()=>s(null));let e=()=>ot(`/api/quick-switch`).then(e=>d(e.agents||[])).catch(()=>{});e();let t=setInterval(e,5e3);return()=>clearInterval(t)},[]),(0,v.useEffect)(()=>{n&&p(n)},[n]);let m=(e,n,i)=>{r(e),a(n),t(i)},h=u.filter(e=>e.running||e.pending).length;if(c)return(0,K.jsx)(zO,{onOk:()=>{l(!1),ot(`/api/health`).then(e=>{s(e),l(!!e.auth_required)}).catch(()=>{})}});let g=e=>it(`flex items-center gap-2 rounded-md px-3 py-2 text-sm transition-colors`,e?`bg-primary/15 font-medium text-primary`:`text-muted-foreground hover:bg-accent hover:text-foreground`);return(0,K.jsxs)(`div`,{className:`flex h-screen overflow-hidden bg-background text-foreground`,children:[(0,K.jsxs)(`aside`,{className:`flex w-52 shrink-0 flex-col border-r border-sidebar-border bg-sidebar text-sidebar-foreground`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-2 px-4 py-4`,children:[(0,K.jsx)(Dh,{className:`h-6 w-6 text-primary`}),(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`div`,{className:`text-sm font-bold leading-tight`,children:`AIMS 工业智能体平台`}),(0,K.jsx)(`div`,{className:`text-[10px] text-muted-foreground`,children:`平台AI化 · 系统工具化`})]})]}),(0,K.jsxs)(`nav`,{className:`flex flex-col gap-1 px-2`,children:[(0,K.jsxs)(`button`,{onClick:()=>t(`hub`),className:g(e===`hub`),children:[(0,K.jsx)(Yh,{className:`h-4 w-4`}),`助手大厅`]}),(0,K.jsxs)(`button`,{onClick:()=>t(`evolution`),className:g(e===`evolution`),children:[(0,K.jsx)(Yg,{className:`h-4 w-4`}),`自进化`]}),(0,K.jsxs)(`button`,{onClick:()=>t(`plugins`),className:g(e===`plugins`),children:[(0,K.jsx)(pg,{className:`h-4 w-4`}),`插件中心`]}),(0,K.jsxs)(`button`,{onClick:()=>t(`settings`),className:g(e===`settings`),children:[(0,K.jsx)(kg,{className:`h-4 w-4`}),`系统设置`]})]}),(0,K.jsxs)(`div`,{className:`mt-3 flex items-center justify-between border-t border-sidebar-border px-4 pb-1 pt-3`,children:[(0,K.jsxs)(`span`,{className:`text-[11px] font-semibold uppercase tracking-wide text-muted-foreground`,children:[`小助手 · 在岗 `,u.length]}),h>0&&(0,K.jsxs)(`span`,{className:`text-[10px] text-emerald-400`,title:`会话在后台运行中,切回即可看到进度`,children:[`● `,h,` 运行`]})]}),(0,K.jsxs)(`div`,{className:`min-h-0 flex-1 overflow-y-auto px-2 pb-2`,children:[u.length===0&&(0,K.jsx)(`p`,{className:`px-3 py-2 text-[11px] leading-relaxed text-muted-foreground`,children:`在「助手大厅」完成上岗配置后,这里按助手分组,一键直达各自的工作台。`}),u.map(t=>{let r=n===t.agent_id,i=f===t.agent_id,a=e=>it(`flex items-center gap-2 rounded-md px-2.5 py-1.5 text-xs transition-colors`,e?`bg-primary/15 font-medium text-primary`:`text-muted-foreground hover:bg-accent hover:text-foreground`);return(0,K.jsxs)(`div`,{className:`mb-0.5`,children:[(0,K.jsxs)(`div`,{className:it(`group flex items-center gap-0.5 rounded-md pr-1 transition-colors`,r&&e!==`hub`?`bg-primary/10`:`hover:bg-accent`),children:[(0,K.jsx)(`button`,{onClick:()=>p(i?null:t.agent_id),className:`flex h-9 w-6 shrink-0 items-center justify-center text-muted-foreground hover:text-foreground`,title:i?`折叠`:`展开`,children:i?(0,K.jsx)(ah,{className:`h-3.5 w-3.5`}):(0,K.jsx)(sh,{className:`h-3.5 w-3.5`})}),(0,K.jsxs)(`button`,{onClick:()=>m(t.agent_id,t.name,`workbench`),title:t.running||t.pending?`${t.name} · ${t.statusText}`:t.name,className:it(`flex min-w-0 flex-1 items-center gap-1.5 py-2 pr-1 text-left text-sm`,r&&e!==`hub`?`font-medium text-primary`:`text-muted-foreground group-hover:text-foreground`),children:[(t.running||t.pending)&&(0,K.jsx)(`span`,{className:it(`h-1.5 w-1.5 shrink-0 rounded-full`,t.running?`animate-pulse bg-emerald-500`:`bg-amber-500`)}),(0,K.jsx)(`span`,{className:`truncate`,children:t.name})]})]}),i&&(0,K.jsxs)(`div`,{className:`ml-6 mt-0.5 flex flex-col gap-0.5 border-l border-border/60 pl-2`,children:[(0,K.jsxs)(`button`,{onClick:()=>m(t.agent_id,t.name,`workbench`),className:a(r&&e===`workbench`),children:[(0,K.jsx)(ag,{className:`h-3.5 w-3.5`}),`工作台`]}),(0,K.jsxs)(`button`,{onClick:()=>m(t.agent_id,t.name,`editor`),className:a(r&&e===`editor`),children:[(0,K.jsx)(Dg,{className:`h-3.5 w-3.5`}),`定制工作台`]})]})]},t.agent_id)})]}),(0,K.jsxs)(`div`,{className:`mt-auto space-y-1.5 border-t border-sidebar-border px-4 pb-4 pt-3 text-[11px] text-muted-foreground`,children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-1.5`,children:[(0,K.jsx)(`span`,{className:it(`h-1.5 w-1.5 rounded-full`,o?`bg-emerald-500`:`bg-red-500`)}),`LLM `,o?.model||`未连接`,`(pi-ai)`]}),(0,K.jsxs)(`div`,{className:`flex items-center gap-1.5`,children:[(0,K.jsx)(`span`,{className:it(`h-1.5 w-1.5 rounded-full`,o?`bg-emerald-500`:`bg-red-500`)}),`ARM `,o?o.pat?`已连接·PAT`:`已连接·只读`:`未连接`]})]})]}),(0,K.jsxs)(`div`,{className:`flex min-w-0 flex-1 flex-col`,children:[(0,K.jsxs)(`header`,{className:`flex h-12 shrink-0 items-center gap-3 border-b bg-card px-5`,children:[(0,K.jsx)(th,{className:`h-4 w-4 text-primary`}),(0,K.jsx)(`span`,{className:`text-sm font-semibold`,children:i||`数字员工队伍`}),n&&(0,K.jsx)(J,{variant:`outline`,className:`text-[10px]`,children:`在岗`}),(0,K.jsxs)(`span`,{className:`ml-auto text-xs text-muted-foreground`,children:[e===`hub`&&`从 ARM 员工库选择助手,或为未上岗助手完成上岗配置`,e===`editor`&&`AI 起草 → 人工审阅 → 版本化发布 → 可回滚`,e===`evolution`&&`数据回流 · 评测迭代 · 知识沉淀 · 飞轮证据`,e===`plugins`&&`统一注册表 · 生命周期 · 引用追踪 · 治理策略`,e===`settings`&&`ARM 源切换 · 令牌管理 · 保存即生效`]})]}),(0,K.jsxs)(`main`,{className:`min-h-0 flex-1 overflow-hidden`,children:[e===`hub`&&(0,K.jsx)(ev,{onOpen:m}),e===`workbench`&&n&&(0,K.jsx)(gO,{agentId:n,onName:a,onEdit:()=>t(`editor`)},n),e===`editor`&&n&&(0,K.jsx)(PO,{agentId:n},n),e===`evolution`&&(0,K.jsx)(IO,{}),e===`plugins`&&(0,K.jsx)(jO,{}),e===`settings`&&(0,K.jsx)(RO,{}),(e===`workbench`||e===`editor`)&&!n&&(0,K.jsx)(`div`,{className:`flex h-full items-center justify-center text-sm text-muted-foreground`,children:`请先在助手大厅选择一名助手`})]})]})]})}var VO=(e,t,n,r,i,a,o,s)=>{let c=document.documentElement,l=[`light`,`dark`];function u(t){(Array.isArray(e)?e:[e]).forEach(e=>{let n=e===`class`,r=n&&a?i.map(e=>a[e]||e):i;n?(c.classList.remove(...r),c.classList.add(a&&a[t]?a[t]:t)):c.setAttribute(e,t)}),d(t)}function d(e){s&&l.includes(e)&&(c.style.colorScheme=e)}function f(){return window.matchMedia(`(prefers-color-scheme: dark)`).matches?`dark`:`light`}if(r)u(r);else try{let e=localStorage.getItem(t)||n;u(o&&e===`system`?f():e)}catch{}},HO=v.createContext(void 0),UO={setTheme:e=>{},themes:[]},WO=()=>v.useContext(HO)??UO;v.memo(({forcedTheme:e,storageKey:t,attribute:n,enableSystem:r,enableColorScheme:i,defaultTheme:a,value:o,themes:s,nonce:c,scriptProps:l})=>{let u=JSON.stringify([n,t,a,e,s,o,r,i]).slice(1,-1);return v.createElement(`script`,{...l,suppressHydrationWarning:!0,nonce:typeof window>`u`?c:``,dangerouslySetInnerHTML:{__html:`(${VO.toString()})(${u})`}})}),(0,y.createRoot)(document.getElementById(`root`)).render((0,K.jsxs)(v.StrictMode,{children:[(0,K.jsx)(BO,{}),(0,K.jsx)(({...e})=>{let{theme:t=`system`}=WO();return(0,K.jsx)(Q_,{theme:t,className:`toaster group`,icons:{success:(0,K.jsx)(ph,{className:`size-4`}),info:(0,K.jsx)(Uh,{className:`size-4`}),warning:(0,K.jsx)(Zg,{className:`size-4`}),error:(0,K.jsx)(lg,{className:`size-4`}),loading:(0,K.jsx)($h,{className:`size-4 animate-spin`})},style:{"--normal-bg":`var(--popover)`,"--normal-text":`var(--popover-foreground)`,"--normal-border":`var(--border)`,"--border-radius":`var(--radius)`},...e})},{richColors:!0,position:`top-center`})]}));
@@ -5,7 +5,7 @@
5
5
  <link rel="icon" type="image/svg+xml" href="/vite.svg" />
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
7
  <title>AIMS 工业智能体平台</title>
8
- <script type="module" crossorigin src="/assets/index-_EVO7WmA.js"></script>
8
+ <script type="module" crossorigin src="/assets/index-DtZ9K70Z.js"></script>
9
9
  <link rel="stylesheet" crossorigin href="/assets/index-CUF2TY1u.css">
10
10
  </head>
11
11
  <body>