@nelsonlongxiang/dsh-open-a2a-net 0.6.24 → 0.6.26

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.
Files changed (38) hide show
  1. package/README.md +15 -11
  2. package/README_zh.md +3 -2
  3. package/assets/nexusDist/assets/index-DszoLz8i.js +5 -0
  4. package/assets/nexusDist/assets/index-uQf7NwjF.css +1 -0
  5. package/assets/nexusDist/index.html +2 -2
  6. package/cli/a2a.mjs +300 -0
  7. package/lib/card.js +17 -0
  8. package/lib/cli-deposit.js +141 -0
  9. package/lib/exposure-store.js +82 -0
  10. package/lib/index.js +904 -57
  11. package/lib/owner-settings.js +100 -0
  12. package/lib/peer-store.js +65 -9
  13. package/lib/task-ledger.js +44 -3
  14. package/lib/types/cli-deposit.d.ts +53 -0
  15. package/lib/types/exposure-store.d.ts +45 -0
  16. package/lib/types/index.d.ts +5 -0
  17. package/lib/types/owner-settings.d.ts +19 -0
  18. package/lib/types/peer-store.d.ts +22 -3
  19. package/lib/types/task-ledger.d.ts +18 -0
  20. package/lib/types/types.d.ts +10 -0
  21. package/nexus-stage/src/canvas-ops.ts +2 -2
  22. package/nexus-stage/src/federation.ts +6 -0
  23. package/nexus-stage/src/main.ts +97 -4
  24. package/nexus-stage/src/planning-menus.ts +16 -4
  25. package/nexus-stage/src/planning-types.ts +3 -0
  26. package/nexus-stage/src/planning-view.ts +208 -18
  27. package/nexus-stage/src/planning.css +4 -0
  28. package/nexus-stage/src/wb-chat.ts +670 -0
  29. package/nexus-stage/src/wb-directory.ts +222 -0
  30. package/nexus-stage/src/wb-ledger.ts +266 -0
  31. package/nexus-stage/src/wb-rail.ts +147 -0
  32. package/nexus-stage/src/workbench.css +190 -84
  33. package/nexus-stage/src/workbench.ts +385 -721
  34. package/nexus-stage/src/world.ts +5 -1
  35. package/package.json +18 -22
  36. package/assets/nexusDist/assets/index-034h1cNc.js +0 -3
  37. package/assets/nexusDist/assets/index-PG9EieGX.css +0 -1
  38. package/lib/types/client.d.ts +0 -73
@@ -174,10 +174,14 @@ export interface WorldNode {
174
174
  name?: string
175
175
  live: boolean
176
176
  /** Peer node (PR D v1 ruling): a remote host entry rendered as a card.
177
- * Excluded from local content bounds; no memberships, ever. */
177
+ * Excluded from local content bounds; canvas memberships allowed since
178
+ * gh#20 W-B (the peer rides its zone/id8 handle at the server boundary). */
178
179
  remote?: boolean
179
180
  /** Full peer URL (identity is the bare host:port in the node id). */
180
181
  peerUrl?: string
182
+ /** gh#20 W-B: the peer's zone/id8 remote handle (its first remote team
183
+ * row) — the server's canvas member form for cross-host teams. */
184
+ remoteHandle?: string
181
185
  /** Reachability score from a2a_probe (peers only). */
182
186
  score?: number
183
187
  /** Declared roster teams (a2a/teams.json) — the network-declaration half
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nelsonlongxiang/dsh-open-a2a-net",
3
- "version": "0.6.24",
3
+ "version": "0.6.26",
4
4
  "description": "Open A2A network plugin for DeepSeek Harness: signed agent cards, decentralized peer/zone discovery, direct routing model tools, and joinable session nodes with a sidebar control",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
@@ -39,6 +39,7 @@
39
39
  },
40
40
  "files": [
41
41
  "lib",
42
+ "cli",
42
43
  "assets/nexusDist",
43
44
  "assets/stageDist",
44
45
  "images",
@@ -52,7 +53,9 @@
52
53
  "nexus-stage/tsconfig.json",
53
54
  "nexus-stage/vite.config.ts"
54
55
  ],
55
- "packageManager": "pnpm@11.28.5",
56
+ "bin": {
57
+ "a2a-net": "cli/a2a.mjs"
58
+ },
56
59
  "engines": {
57
60
  "pnpm": ">=11.24 <12"
58
61
  },
@@ -70,19 +73,6 @@
70
73
  ]
71
74
  }
72
75
  },
73
- "scripts": {
74
- "prepare": "pnpm build",
75
- "build": "tsc -p tsconfig.json && tsc -p tsconfig.client.json && tsdown && node scripts/copy-skill.mjs",
76
- "typecheck": "tsc -p tsconfig.json --noEmit && tsc -p tsconfig.client.json --noEmit",
77
- "test": "vitest run",
78
- "test:unit": "vitest run tests/unit",
79
- "test:wire": "vitest run tests/wire",
80
- "test:mesh": "vitest run tests/mesh",
81
- "test:live": "vitest run tests/live",
82
- "test:build-layout": "vitest run tests/gates/build-layout.spec.ts",
83
- "verify:nexus": "node scripts/verify-nexus-ci.mjs && npm --prefix nexus-stage run build && npm --prefix nexus-stage run test && git diff --exit-code -- assets/nexusDist/assets && git diff --ignore-cr-at-eol --exit-code -- assets/nexusDist/index.html",
84
- "verify": "pnpm typecheck && pnpm build && pnpm test && pnpm test:build-layout && pnpm verify:nexus"
85
- },
86
76
  "peerDependencies": {
87
77
  "@deepseek-ai/cordis": ">=4.0.1",
88
78
  "@deepseek-ai/cordis-plugin-loader": ">=1.0.2",
@@ -204,15 +194,21 @@
204
194
  "typescript": "^5.9.3",
205
195
  "vitest": "^4.1.8"
206
196
  },
207
- "pnpm": {
208
- "overrides": {
209
- "@deepseek-ai/cordis": "4.0.5",
210
- "@deepseek-ai/cordis-plugin-loader": "1.0.5"
211
- }
212
- },
213
197
  "license": "MIT",
214
198
  "repository": {
215
199
  "type": "git",
216
200
  "url": "git+https://gitee.com/NelsonLongXiang/dsh-open-a2a-net.git"
201
+ },
202
+ "scripts": {
203
+ "build": "tsc -p tsconfig.json && tsc -p tsconfig.client.json && tsdown && node scripts/copy-skill.mjs",
204
+ "typecheck": "tsc -p tsconfig.json --noEmit && tsc -p tsconfig.client.json --noEmit",
205
+ "test": "vitest run",
206
+ "test:unit": "vitest run tests/unit",
207
+ "test:wire": "vitest run tests/wire",
208
+ "test:mesh": "vitest run tests/mesh",
209
+ "test:live": "vitest run tests/live",
210
+ "test:build-layout": "vitest run tests/gates/build-layout.spec.ts",
211
+ "verify:nexus": "node scripts/verify-nexus-ci.mjs && npm --prefix nexus-stage run build && npm --prefix nexus-stage run test && git diff --exit-code -- assets/nexusDist/assets && git diff --ignore-cr-at-eol --exit-code -- assets/nexusDist/index.html",
212
+ "verify": "pnpm typecheck && pnpm build && pnpm test && pnpm test:build-layout && pnpm verify:nexus"
217
213
  }
218
- }
214
+ }
@@ -1,3 +0,0 @@
1
- var hn=Object.defineProperty;var bn=(t,e,s)=>e in t?hn(t,e,{enumerable:!0,configurable:!0,writable:!0,value:s}):t[e]=s;var Je=(t,e,s)=>bn(t,typeof e!="symbol"?e+"":e,s);(function(){const e=document.createElement("link").relList;if(e&&e.supports&&e.supports("modulepreload"))return;for(const n of document.querySelectorAll('link[rel="modulepreload"]'))i(n);new MutationObserver(n=>{for(const u of n)if(u.type==="childList")for(const d of u.addedNodes)d.tagName==="LINK"&&d.rel==="modulepreload"&&i(d)}).observe(document,{childList:!0,subtree:!0});function s(n){const u={};return n.integrity&&(u.integrity=n.integrity),n.referrerPolicy&&(u.referrerPolicy=n.referrerPolicy),n.crossOrigin==="use-credentials"?u.credentials="include":n.crossOrigin==="anonymous"?u.credentials="omit":u.credentials="same-origin",u}function i(n){if(n.ep)return;n.ep=!0;const u=s(n);fetch(n.href,u)}})();const It=6e4;function gn(t,e,s=Date.now){let i=-It;return{fault(n){const u=s();u-i>=It&&(e(`[nexus] ${n}`),i=u),t.show(n)},clear(){t.hide(),i=-It}}}function ue(t){return t.name??t.team??t.label??""}function qe(t,e){const s=Math.max(0,Math.round((e-t)/1e3));if(s<90)return`${s}s`;const i=Math.round(s/60);if(i<90)return`${i}m`;const n=Math.round(i/60);return n<48?`${n}h`:`${Math.round(n/24)}d`}function f(t,e){const s=document.createElement(t);return e!==void 0&&(s.className=e),s}function wt(t,e,s,i){const n=f("span","wb-stat");return i!==void 0&&n.classList.add(`wb-stat-${i}`),n.setAttribute("title",s),n.appendChild(f("span","wb-stat-k")).textContent=t,n.appendChild(f("span","wb-stat-v")).textContent=String(e),n}function vn(t,e,s,i){const n=f("div","wb-bar-row");n.appendChild(f("span","wb-bar-k")).textContent=e;const u=f("span","wb-bar-track"),d=f("span","wb-bar-fill");d.style.width=`${i>0?Math.max(s>0?2:0,Math.round(s/i*100)):0}%`,u.appendChild(d),n.appendChild(u),n.appendChild(f("span","wb-bar-v")).textContent=String(s),t.appendChild(n)}function it(t,e,s){const i=f("div","wb-kv");i.appendChild(f("span","wb-kv-k")).textContent=e,i.appendChild(f("span","wb-kv-v")).textContent=s,t.appendChild(i)}const yn=[{key:"all",label:"全部",hint:"不过滤:目录全部条目"},{key:"local",label:"本机",hint:"本机会话节点(现场 + 冷启动)"},{key:"canvas",label:"队",hint:"画布队(人类手工分配的组队)"},{key:"peers",label:"Peers",hint:"对等节点(peer 池)"},{key:"remote",label:"远端",hint:"远端会话队(来自对端卡片)"}];function Ke(...t){const e=[];for(const s of t)if(s!==void 0)if(typeof s=="string")s!==""&&e.push(s);else for(const i of s)i!==""&&e.push(i);return e.join(" ").toLowerCase()}const Wt=[{key:"directory",label:"目录"},{key:"ledger",label:"台账"},{key:"activity",label:"活动"},{key:"plan",label:"规划"}];function wn(t){const e=t.board;let s="data",i,n=null;const u=new Set(["activity","plan"]);let d="",y="all",g=null,w=null,L=null,B=!1,W=null;const U=new Map,q=new Map,de=new Set,ne=new Map;let F=[],P=!1;const Y=f("div","wb");Y.setAttribute("data-testid","wb-root");const D=f("header","wb-header"),T=f("button","wb-icon-btn wb-menu");T.type="button",T.dataset.testid="wb-menu",T.setAttribute("aria-label","打开目录抽屉"),T.textContent="☰",T.addEventListener("click",()=>Y.classList.toggle("is-rail-open")),D.appendChild(T);const R=f("div","wb-title");R.appendChild(f("span","wb-title-main")).textContent="A2A 工作台";const S=f("span","wb-badge");R.appendChild(S),D.appendChild(R);const I=f("div","wb-header-stats");D.appendChild(I);const v=f("button","wb-icon-btn wb-rail-toggle");v.type="button",v.dataset.testid="wb-rail-toggle",v.setAttribute("aria-label","折叠/展开侧栏"),v.textContent="◧",v.addEventListener("click",()=>{Y.classList.toggle("is-rail-collapsed"),s==="canvas"&&e!==void 0&&e.activate()}),D.appendChild(v);const O=f("div","wb-body"),X=f("aside","wb-rail"),Z=new Map,se=new Map;for(const l of Wt){const b=f("section","wb-sec");b.dataset.sec=l.key;const x=f("button","wb-sec-head");x.type="button",x.appendChild(f("span","wb-sec-label")).textContent=l.label;const M=f("span","wb-sec-count");x.appendChild(M),x.addEventListener("click",()=>{u.has(l.key)?u.delete(l.key):u.add(l.key),et()}),b.appendChild(x);const A=f("div","wb-sec-body");b.appendChild(A),X.appendChild(b),Z.set(l.key,A),se.set(l.key,M)}const ae=f("div","wb-directory"),K=f("div","wb-dir-tools"),he=document.createElement("input");he.className="wb-search",he.type="search",he.placeholder="搜索:名称 / 队 / 会话 / 节点",he.setAttribute("aria-label","统一搜索目录"),he.addEventListener("input",()=>{d=he.value.trim().toLowerCase(),Oe()}),K.appendChild(he);const be=f("div","wb-filters");for(const l of yn){const b=f("button","wb-filter");b.type="button",b.textContent=l.label,b.dataset.filter=l.key,b.title=l.hint,b.addEventListener("click",()=>{y=l.key,Oe()}),be.appendChild(b)}K.appendChild(be),Z.get("directory").appendChild(K),Z.get("directory").appendChild(ae);const ee=f("section","wb-pane"),J=f("section","wb-pane"),V=f("section","wb-pane"),te=[["ledger",ee],["activity",J],["plan",V]],oe=f("main","wb-stage"),Ce=f("section","wb-stage-board");e!==void 0&&(Ce.appendChild(e.root),oe.appendChild(Ce));const ye=f("div","wb-data"),pe=f("aside","wb-inspector"),me=f("div","wb-inspector-head");me.appendChild(f("span","wb-inspector-title")).textContent="详情";const ke=f("button","wb-icon-btn");ke.type="button",ke.setAttribute("aria-label","关闭详情"),ke.textContent="✕",ke.addEventListener("click",()=>tt(void 0)),me.appendChild(ke),pe.appendChild(me);const lt=f("div","wb-inspector-body");pe.appendChild(lt);const ge=f("aside","wb-chat"),fe=f("div","wb-chat-head"),le=f("span","wb-chat-dot"),we=f("span","wb-chat-title"),Fe=f("span","wb-chat-sub"),Ye=f("button","wb-icon-btn");Ye.type="button",Ye.setAttribute("aria-label","关闭对话"),Ye.textContent="✕",Ye.addEventListener("click",()=>st()),fe.appendChild(le),fe.appendChild(we),fe.appendChild(Fe),fe.appendChild(Ye);const ce=f("div","wb-chat-body");ge.appendChild(fe),ge.appendChild(ce),document.addEventListener("keydown",l=>{if(l.key!=="Escape"||!ge.classList.contains("is-open"))return;const b=l.target;if(!(b instanceof HTMLElement))return;if(!ge.contains(b)){const M=b instanceof HTMLTextAreaElement||b instanceof HTMLInputElement||b.isContentEditable,A=b.closest(".wb-stage-board")!==null;if(M||A)return}st()}),oe.appendChild(ye),O.appendChild(X),O.appendChild(oe),O.appendChild(pe),O.appendChild(ge),Y.appendChild(D),Y.appendChild(O);function et(){for(const l of Wt)Z.get(l.key).parentElement.classList.toggle("is-collapsed",u.has(l.key))}function St(l){for(const[b,x]of te){const M=l==="canvas"?Z.get(b):ye;x.parentElement!==M&&M.appendChild(x)}}function ct(){const b=e!==void 0&&e.available()?"canvas":"data";Y.dataset.mode=b,Ce.classList.toggle("is-hidden",b!=="canvas"),ye.classList.toggle("is-hidden",b==="canvas"),St(b),b!==s&&(e!==void 0&&(b==="canvas"?e.activate():e.deactivate()),s=b)}function ve(l){for(;l.firstChild!==null;)l.removeChild(l.firstChild);return l}function tt(l){i=l,((l==null?void 0:l.kind)!=="canvas"||(g==null?void 0:g.name)!==l.row.name)&&(g=null),(l==null?void 0:l.kind)!=="canvas"&&(w=null),Ve(),Y.classList.remove("is-rail-open")}function Oe(){var E;const l=ve(ae);for(let m=0;m<be.children.length;m++){const r=be.children[m];r.classList.toggle("is-active",r.dataset.filter===y)}if(n===null){l.appendChild(f("div","wb-muted")).textContent="载入中…",se.get("directory").textContent="";return}const b=n,x=d!==""||y!=="all",M=(m,r)=>(y==="all"||y===m)&&(d===""||r.includes(d)),A=(m,r)=>{if(r===void 0||r.length===0)return;const C=f("span","wb-item-badge"),$=r.map(j=>j.slice(j.lastIndexOf("/")+1));C.textContent=`▤ ${$.slice(0,3).join(" ")}${$.length>3?` +${$.length-3}`:""}`,C.title=`画布队:${r.join(" · ")}`,m.appendChild(C)},N=(m,r)=>{const C=f("div","wb-side-head");return C.textContent=`${m} · ${r}`,l.appendChild(C),l},_=b.sessions??[],k=_.filter(m=>m.live===!0&&M("local",Ke(ue(m),m.team,m.label,m.id,m.canvasTeams))),G=_.filter(m=>m.live!==!0&&M("local",Ke(ue(m),m.team,m.label,m.id,m.canvasTeams)));if(se.get("directory").textContent=`${k.length}/${G.length}${F.length>0?` · 档 ${F.length}`:""}`,k.length>0){N("本机 · 现场",k.length);for(const m of k){const r=f("button","wb-item");r.type="button",r.appendChild(f("span","wb-dot wb-dot-live")).textContent="●",r.appendChild(f("span","wb-item-label")).textContent=ue(m),A(r,m.canvasTeams),r.addEventListener("click",()=>$e({kind:"session",id:m.id,title:ue(m),sub:m.team,team:m.team,live:m.live})),l.appendChild(r)}}if(G.length>0){N("本机 · 冷启动",G.length);for(const m of G){const r=f("button","wb-item");r.type="button",r.appendChild(f("span","wb-dot wb-dot-cold")).textContent="○",r.appendChild(f("span","wb-item-label")).textContent=ue(m),A(r,m.canvasTeams),r.addEventListener("click",()=>$e({kind:"session",id:m.id,title:ue(m),sub:m.team,team:m.team,live:m.live})),l.appendChild(r)}}const H=(((E=b.canvas)==null?void 0:E.teams)??[]).filter(m=>M("canvas",Ke(m.name,m.team,m.members.map(r=>r.team??r.id))));if(H.length>0){N("Canvas 队",H.length);for(const m of H){const r=f("button","wb-item");r.type="button",r.appendChild(f("span","wb-dot wb-dot-canvas")).textContent="▤";const C=m.members.filter($=>$.remote===!0).length;r.appendChild(f("span","wb-item-label")).textContent=`${m.name} · ${m.members.length}${C>0?`(远端 ${C})`:""}`,r.addEventListener("click",()=>tt({kind:"canvas",row:m})),l.appendChild(r)}}const o=(b.peers??[]).filter(m=>M("peers",Ke(m.url)));if(o.length>0){N("Peers",o.length);for(const m of o){const r=f("button","wb-item");r.type="button",r.appendChild(f("span","wb-dot wb-dot-peer")).textContent="⇄",r.appendChild(f("span","wb-item-label")).textContent=m.url.replace(/^https?:\/\//,"")+(m.score!==void 0?` · ${m.score}`:""),r.addEventListener("click",()=>{const C=m.url.replace(/^https?:\/\//,"").replace(/\/.*$/,"");$e({kind:"peer",id:`peer-${C}`,title:m.url,sub:C,url:m.url})}),l.appendChild(r)}}const a=(b.remote??[]).filter(m=>M("remote",Ke(ue(m),m.team,m.origin,m.workspace,m.canvasTeams)));if(a.length>0){N("远端节点",a.length);for(const m of a){const r=f("button","wb-item");r.type="button",r.appendChild(f("span","wb-dot wb-dot-remote")).textContent="◇",r.appendChild(f("span","wb-item-label")).textContent=ue(m),A(r,m.canvasTeams),r.addEventListener("click",()=>$e({kind:"remote",team:m.team,title:ue(m),sub:m.team,row:m})),l.appendChild(r)}}const c=new Set(_.map(m=>m.id)),p=m=>m>=1e6?`${(m/1e6).toFixed(1)} MB`:m>=1e3?`${Math.round(m/1e3)} KB`:`${m} B`,h=F.filter(m=>!c.has(m.id)&&M("local",Ke(m.id)));if(h.length>0){N("本机日志",h.length);for(const m of h){const r=f("button","wb-item");r.type="button",r.appendChild(f("span","wb-dot")).textContent="❐";const C=f("span","wb-item-label");C.textContent=`…${m.id.slice(-12)} · ${p(m.sizeBytes)}`,r.title=`${m.id}
2
- ${p(m.sizeBytes)} · ${new Date(m.mtimeMs).toLocaleString()}`,r.appendChild(C),r.addEventListener("click",()=>$e({kind:"log",id:m.id,title:`…${m.id.slice(-12)}`,sub:"档案"})),l.appendChild(r)}}x&&k.length+G.length+H.length+o.length+a.length+h.length===0&&(l.appendChild(f("div","wb-muted")).textContent="无匹配条目")}const Pe=[{label:"<10m",maxMs:10*6e4},{label:"10m-1h",maxMs:60*6e4},{label:"1-6h",maxMs:6*60*6e4},{label:"6-24h",maxMs:24*60*6e4},{label:">24h",maxMs:Number.POSITIVE_INFINITY}];function dt(l,b){const x=Pe.map(()=>0);for(const M of l){const A=b-M.startedAt,N=Pe.findIndex(_=>A<_.maxMs);x[N===-1?x.length-1:N]+=1}return x}function Tt(l){const b=new Map;for(const x of l)b.set(x.team,(b.get(x.team)??0)+1);return[...b.entries()].sort((x,M)=>M[1]-x[1]).slice(0,5)}function mt(){var a;const l=ve(ee);if(n===null)return;const b=t.now(),x=n.tasks??[],M=n.tasksDead??[],A=n.tasksStaleCount??0,N=n.archivedCount??0;se.get("ledger").textContent=`待 ${x.length} · 死 ${M.length}`;const _=f("div","wb-stats");_.appendChild(wt("待回执",x.length,"等待回执的任务(pending)。其中「陈旧」= 超过 1 小时仍未回执,或本就无回执债(fire-and-forget)")),_.appendChild(wt("陈旧",A,"陈旧尾:≥1h 无回执的旧账 + receiptExpected:false 的免回执行。它们到 24h TTL 自动转死信,不算可催办债务",A>0?"warn":void 0)),_.appendChild(wt("死信",M.length,"超过 24h TTL 仍未结算,或目标早已离开。需清账(abandon)才能移出",M.length>0?"danger":void 0)),_.appendChild(wt("已归档",N,"已结算并留档的任务(回执已关联)。用于审计,不再占待回执名额")),l.appendChild(_);const k=n.archivedSplit;if(N>0&&k!==void 0){const c=Object.entries(k).sort((p,h)=>h[1]-p[1]);if(c.length>0){const p=f("div","wb-pane-head");p.textContent=`归档结局 · ${c.map(([h,E])=>`${h} ${E}`).join(" · ")}`,l.appendChild(p)}}const G=n.idempotency,H=(a=n.reconcile)==null?void 0:a.state;if(G!==void 0||H!==void 0){const c=[];G!==void 0&&c.push(`幂等 claims ${G.claimsFresh??0} · replays ${G.replays??0} · conflicts ${G.conflicts??0}`),H!==void 0&&c.push(`reconcile ${H}`);const p=f("div","wb-pane-head wb-forensics");p.textContent=`取证 · ${c.join(" · ")}`,l.appendChild(p)}if(x.length>0){const c=dt(x,b),p=Math.max(...c,1),h=f("div","wb-hist");for(let r=0;r<Pe.length;r+=1)vn(h,Pe[r].label,c[r],p);l.appendChild(h);const E=Tt(x),m=f("div","wb-pane-head");m.textContent=`债务队 Top${E.length} · ${E.map(([r,C])=>`${r} ${C}`).join(" · ")}`,l.appendChild(m)}const o=f("div","wb-table");for(const c of x){const p=b-c.startedAt>36e5,h=f("div",`wb-row wb-row-result${p?" wb-row-alert":""}`),E=c.brief??"(无摘要——派发未带 brief)",m=f("span","wb-row-head");m.textContent=E,m.title=E,h.appendChild(m);const r=[];c.settleable===!0&&r.push("可结算"),c.receiptExpected===!1&&r.push("无回执债"),c.direction==="inbound"&&r.push("入站");const C=f("span","wb-row-meta-line");C.textContent=`${c.taskId} · ${c.team} · ${qe(c.startedAt,b)}${r.length>0?` · ${r.join(" ")}`:""}`,h.appendChild(C),o.appendChild(h)}if(l.appendChild(o),M.length>0){const c=f("div","wb-pane-subhead");c.textContent="死信(可清账)",l.appendChild(c);const p=f("div","wb-table wb-table-dead");for(const h of M){const E=f("div","wb-row wb-row-result wb-row-alert"),m=h.brief??"(无摘要)",r=f("span","wb-row-head");r.textContent=m,r.title=m,E.appendChild(r);const C=f("span","wb-row-meta-line");C.textContent=`${h.taskId} · ${h.team} · ${qe(h.deadAt,b)}${h.reason!==void 0&&h.reason!==""?` · ${h.reason}`:""}`,E.appendChild(C);const $=f("button","wb-btn");$.type="button",$.textContent="清账",$.addEventListener("click",()=>{$.disabled=!0,t.abandon(h.taskId,"workbench dead-letter cleanup").then(j=>{$.disabled=!1,$.textContent=j?"已清":"失败"})}),E.appendChild($),p.appendChild(E)}l.appendChild(p)}}function ut(){var _,k;const l=ve(J);if(n===null)return;const b=t.now(),x=n.inFlight??[];se.get("activity").textContent=`${x.length}+${((_=n.activity)==null?void 0:_.length)??0}`;const M=f("div","wb-pane-head");if(M.textContent=`在途 ${x.length} · 活动 ${((k=n.activity)==null?void 0:k.length)??0}`,l.appendChild(M),x.length>0){const G=f("div","wb-pane-subhead");G.textContent="在途路由",l.appendChild(G);for(const H of x){const o=f("div","wb-row");o.appendChild(f("span","wb-row-dir")).textContent="→",o.appendChild(f("span","wb-row-team")).textContent=H.team,o.appendChild(f("span","wb-row-meta")).textContent=`${H.peer} · ${qe(H.startedAt,b)}`,l.appendChild(o)}}const A=f("div","wb-pane-subhead");A.textContent="活动环(最新在前)",l.appendChild(A);const N=n.activity??[];if(N.length===0){l.appendChild(f("div","wb-muted")).textContent="暂无活动";return}for(const G of N){const H=f("div","wb-row"),o=f("span","wb-row-dir");o.textContent=G.dir==="out"?"→":"←",G.ok!==!0&&o.classList.add("is-fail"),H.appendChild(o),H.appendChild(f("span","wb-row-team")).textContent=G.team,H.appendChild(f("span","wb-row-meta")).textContent=`${G.peer} · ${qe(G.ts,b)}`,H.appendChild(f("span","wb-row-badges")).textContent=G.ok===!0?"":"失败",l.appendChild(H)}}function Lt(l){var N,_;const b=t.now(),x=[],M=l.tasksDead??[];M.length>0&&x.push({severity:"high",text:`清账 ${M.length} 条死信(目标早已离开或死信化,无回执可期)`});for(const k of l.tasks??[])if(b-k.startedAt>60*6e4&&k.settleable===!0){const H=k.brief===void 0||k.brief===""?"":`「${k.brief}」`;x.push({severity:"normal",text:`催办 ${k.taskId} → ${k.team}(等待 ${qe(k.startedAt,b)} 无回执)${H}`,brief:`a2a_route 催收回执:task ${k.taskId}(team ${k.team})${H===""?"":`原任务「${k.brief}」`}已派发 ${qe(k.startedAt,b)},请回报结果或回执。`})}for(const k of l.sessions??[])k.live!==!0&&x.push({severity:"normal",text:`冷会话 ${ue(k)}:在 GUI 打开该会话即可唤醒加入面`});for(const k of((N=l.reconcile)==null?void 0:N.rows)??[])k.needsRepair===!0&&x.push({severity:"high",text:`reconcile 需修复:${k.id} ${k.error}`});const A=((_=l.idempotency)==null?void 0:_.conflicts)??0;return A>0&&x.push({severity:"high",text:`幂等冲突 ${A} 例:人工核查 UNIQUE-ization 流量`}),x}function Ee(){const l=ve(V);if(n===null)return;const b=Lt(n);se.get("plan").textContent=`${b.length}`;const x=f("div","wb-pane-head");x.textContent=b.length===0?"网络健康——无待办行动":`待办行动 ${b.length}`,l.appendChild(x);for(const A of b){const N=f("div",`wb-action${A.severity==="high"?" wb-action-high":""}`);if(N.appendChild(f("span","wb-action-text")).textContent=A.text,A.brief!==void 0){const _=f("button","wb-btn");_.type="button",_.textContent="复制催办",_.addEventListener("click",()=>t.copy(A.brief??"")),N.appendChild(_)}l.appendChild(N)}const M=f("div","wb-pane-subhead");M.textContent="派单起草(复制后在任一会话粘贴执行)",l.appendChild(M),l.appendChild(We)}const We=f("div","wb-draft"),Me=document.createElement("select");Me.className="wb-select";const xe=document.createElement("textarea");xe.className="wb-textarea",xe.rows=3,xe.placeholder="任务正文:目标、验收、期限…";const Te=f("button","wb-btn wb-btn-primary");Te.type="button",Te.textContent="复制任务书",Te.addEventListener("click",()=>{const l=Me.value,b=xe.value.trim();l===""||b===""||t.copy(`a2a_route 派单 → ${l}:
3
- ${b}`)}),We.appendChild(Me),We.appendChild(xe),We.appendChild(Te);function ie(){var A;const l=Me.value;ve(Me);const b=document.createElement("option");if(b.value="",b.textContent="选择目标队…",Me.appendChild(b),n===null)return;const x=n,M=new Map;for(const N of x.sessions??[])N.team!==void 0&&N.team!==""&&M.set(N.team,`${ue(N)}(会话队)`);for(const N of((A=x.canvas)==null?void 0:A.teams)??[])M.set(N.team,`${N.name}(canvas 队)`);for(const N of x.remote??[])M.set(N.team,`${ue(N)}(远端)`);for(const[N,_]of M){const k=document.createElement("option");k.value=N,k.textContent=`${_} · ${N}`,Me.appendChild(k)}l!==""&&M.has(l)&&(Me.value=l)}function Ve(){var M;const l=ve(lt);if(pe.classList.toggle("is-open",i!==void 0),i===void 0)return;const b=i,x=f("div","wb-card");if(b.kind==="canvas"){const A=(((M=n==null?void 0:n.canvas)==null?void 0:M.teams)??[]).find(a=>a.name===b.row.name)??b.row;it(x,"Canvas 队",A.name),it(x,"路由队",A.team);const N=f("div","wb-side-head");if(N.textContent=`成员 · ${A.members.length}`,x.appendChild(N),A.members.length===0){const a=f("div","wb-muted");a.textContent="空队——用下方表单添加成员",x.appendChild(a)}for(const a of A.members){const c=f("div","wb-member-row"),p=a.remote===!0?"◇ 远端":a.live===!0?"● 现场":a.joined===!0?"○ 冷启":"· 未入网";c.appendChild(f("span","wb-member-dot")).textContent=p;const h=f("span","wb-member-label"),E=((n==null?void 0:n.sessions)??[]).find(r=>r.id===a.id);h.textContent=a.remote===!0?a.id:E!==void 0?ue(E):a.id,h.title=a.team??a.id,c.appendChild(h);const m=f("button","wb-member-remove");m.type="button",m.textContent="移除",m.addEventListener("click",async()=>{m.disabled=!0,await t.canvasOp("remove-member",A.name,a.id)||(m.disabled=!1)}),c.appendChild(m),x.appendChild(c)}if((g==null?void 0:g.name)!==A.name){const a=f("form","wb-member-add"),c=document.createElement("select");c.className="wb-member-pick",c.setAttribute("aria-label","选择成员");const p=document.createElement("input");p.type="text",p.className="wb-member-manual",p.placeholder="或输入远端句柄 zone/id8",p.setAttribute("aria-label","远端成员句柄");const h=f("button","wb-member-submit");h.type="submit",h.textContent="添加",a.appendChild(c),a.appendChild(p),a.appendChild(h),a.addEventListener("submit",async E=>{E.preventDefault();const m=p.value.trim(),r=m!==""?m:c.value;if(r==="")return;h.disabled=!0;const C=await t.canvasOp("add-member",A.name,r);h.disabled=!1,C&&(p.value="")}),g={name:A.name,form:a,pick:c,manual:p}}const _=g.pick,k=_.value;ve(_),_.appendChild(new Option("本机会话(现场/冷启动)…","",!0,!0));const G=new Set(A.members.map(a=>a.id));for(const a of(n==null?void 0:n.sessions)??[])G.has(a.id)||_.appendChild(new Option(`${ue(a)} — 本机`,a.id));let H=!1;for(const a of(n==null?void 0:n.remote)??[])G.has(a.team)||(H||(_.appendChild(new Option("远端会话队(目录卡片)…","",!0,!1)),H=!0),_.appendChild(new Option(`${ue(a)} — 远端`,a.team)));k!==""&&Array.from(_.options).some(a=>a.value===k)&&(_.value=k),x.appendChild(g.form);const o=f("div","wb-hint");o.textContent="成员由人类在此手工分配(agent 不可自组队)。远端成员走对端目录路由,不做本机冷唤醒;地址由目录在派发时重解析。",x.appendChild(o),t.dispatchQuick!==void 0&&x.appendChild(ot(A.team))}l.appendChild(x)}function nt(l){const b=f("form","wb-dispatch-form"),x=document.createElement("textarea");x.className="wb-dispatch-text",x.placeholder="一句话任务…(≤4000 字符,异步送达,回执进台账)",x.setAttribute("aria-label","快派消息");const M=f("button","wb-dispatch-submit");M.type="submit",M.textContent="发送";const A=f("div","wb-dispatch-note");return b.appendChild(x),b.appendChild(M),b.appendChild(A),x.addEventListener("keydown",N=>{N.key!=="Enter"||N.shiftKey||N.ctrlKey||N.altKey||N.metaKey||N.isComposing||(N.preventDefault(),M.disabled||b.requestSubmit())}),b.addEventListener("submit",async N=>{var G;N.preventDefault();const _=x.value.trim();if(_===""||M.disabled)return;M.disabled=!0,A.textContent="派发中…";let k;try{k=await(((G=t.dispatchQuick)==null?void 0:G.call(t,l,_))??Promise.resolve({ok:!1,error:"dispatch unavailable"}))}catch(H){k={ok:!1,error:H instanceof Error?H.message:String(H)}}M.disabled=!1,k.ok===!0&&(x.value=""),x.focus({preventScroll:!0}),A.textContent=k.ok===!0?`已派发${k.task_id!==void 0?` · ${k.task_id}`:""} · 回执将入台账(待回执)`:`失败:${k.error??"未知原因"}`}),{form:b,text:x,note:A}}function ot(l){const b=f("div","wb-dispatch"),x=f("div","wb-side-head");return x.textContent="快派",b.appendChild(x),(w==null?void 0:w.team)!==l&&(w={team:l,...nt(l)}),b.appendChild(w.form),b}function pt(l,b){const x=f("div","wb-transcript"),M=f("div","wb-side-head"),A=f("button","wb-transcript-refresh");A.type="button";const N=()=>{A.textContent=de.has(l)?"收起取证":"展开取证"};A.addEventListener("click",()=>{de.has(l)?de.delete(l):de.add(l),N(),k.classList.toggle("is-folded",!de.has(l)),de.has(l)&&o()}),N(),M.appendChild(A),M.appendChild(f("span","wb-transcript-title")).textContent="最近对话";const _=f("button","wb-transcript-refresh");_.type="button",_.textContent="刷新",M.appendChild(_),x.appendChild(M);const k=f("div","wb-transcript-body");de.has(l)||k.classList.add("is-folded"),x.appendChild(k);let G=q.has(l),H=!G;const o=()=>{H?(k.scrollTop=k.scrollHeight,H=!1,G=!0):q.has(l)&&(k.scrollTop=q.get(l)??0)};k.addEventListener("scroll",()=>{(k.scrollTop>0||G)&&q.set(l,k.scrollTop)});const a=p=>{if(k.replaceChildren(),p===void 0){k.appendChild(f("div","wb-muted")).textContent="读取中…";return}if(p.ok!==!0||p.messages===void 0){k.appendChild(f("div","wb-muted")).textContent=`无法读取(${p.error??"未知错误"})`;return}if(p.messages.length===0){k.appendChild(f("div","wb-muted")).textContent="暂无对话记录";return}for(const h of p.messages){const E=f("div",`wb-transcript-row wb-transcript-${h.role==="user"?"user":"assistant"}`);E.appendChild(f("span","wb-transcript-role")).textContent=h.role==="user"?"问":"答",E.appendChild(f("span","wb-transcript-text")).textContent=h.text,k.appendChild(E)}requestAnimationFrame(()=>{k.isConnected&&o()})},c=p=>{if(p&&(H=!0),!p&&U.has(l)){a(U.get(l));return}U.set(l,void 0),a(void 0),b().then(h=>{U.set(l,h),k.isConnected&&a(h)})};return _.addEventListener("click",()=>c(!0)),c(!1),x}function ze(l){return pt(`local:${l}`,async()=>{var b;return await((b=t.sessionLog)==null?void 0:b.call(t,l))??{ok:!1,error:"sessionLog unavailable"}})}function ft(l,b){return pt(l,async()=>{var x;return await((x=t.remoteSessionLog)==null?void 0:x.call(t,b))??{ok:!1,error:"remoteSessionLog unavailable"}})}function ht(l){var _;const b=f("div","wb-transcript"),x=f("div","wb-side-head");x.textContent="对端最近会话",b.appendChild(x);const M=f("div","wb-transcript-body");b.appendChild(M);const A=`peerlist:${l}`,N=k=>{if(M.replaceChildren(),k===void 0){M.appendChild(f("div","wb-muted")).textContent="读取中…";return}if(k.ok!==!0||k.sessions===void 0){M.appendChild(f("div","wb-muted")).textContent=`无法读取(${k.error??"未知错误"})`;return}if(k.sessions.length===0){M.appendChild(f("div","wb-muted")).textContent="对端没有可读会话";return}const G=H=>H>=1e6?`${(H/1e6).toFixed(1)} MB`:H>=1e3?`${Math.round(H/1e3)} KB`:`${H} B`;for(const H of k.sessions){const o=f("button","wb-member-row");o.type="button",o.appendChild(f("span","wb-chat-dot is-cold")).textContent="❐",o.appendChild(f("span","wb-item-label")).textContent=`…${H.id.slice(-12)} · ${G(H.sizeBytes)}`,o.addEventListener("click",()=>{(L==null?void 0:L.kind)==="peer"&&(L.picked=H.id),He()}),M.appendChild(o)}};return ne.has(A)?N(ne.get(A)):(N(void 0),(_=t.remoteSessionLog)==null||_.call(t,{peer:l}).then(k=>{ne.set(A,k),M.isConnected&&N(k)})),b}function st(){L=null,W=null,ge.classList.remove("is-open")}function $e(l){L=l;const b=l.kind==="session"||l.kind==="remote"?l.team:void 0;W!==null&&W.team!==b&&(W=null),B=!0,He(),ge.classList.add("is-open"),Y.classList.remove("is-rail-open")}function He(){const l=document.activeElement,b=l instanceof HTMLElement&&ce.contains(l),x=l instanceof HTMLTextAreaElement||l instanceof HTMLInputElement?{start:l.selectionStart,end:l.selectionEnd}:void 0;Ge(),!(!b||!(l instanceof HTMLElement)||!ce.contains(l))&&(l.focus({preventScroll:!0}),x!==void 0&&l instanceof HTMLTextAreaElement&&l.setSelectionRange(x.start,x.end))}function Ge(){var x,M,A;const l=L;if(l===null)return;if(le.className=`wb-chat-dot ${l.kind==="peer"?"is-peer":l.kind==="log"||l.kind==="remote"||l.live===!1?"is-cold":"is-live"}`,we.textContent=l.title,Fe.textContent=l.sub,ve(ce),l.kind==="peer"){const N=l.url??(l.title.startsWith("http")?l.title:"");if(N===""||t.remoteSessionLog===void 0){const k=f("div","wb-chat-note");k.textContent=`对端主机节点(${l.sub})—— 会话记录存放在对端机器上,本页只读本机会话日志。`,ce.appendChild(k);return}const _=f("div","wb-chat-note");if(_.textContent="对端主机节点 —— 以下会话列表经本机代理从对端 /a2a/log 读取。",ce.appendChild(_),l.picked!==void 0){const k=f("button","wb-transcript-refresh");k.type="button",k.textContent="← 返回会话列表",k.addEventListener("click",()=>{(L==null?void 0:L.kind)==="peer"&&(L.picked=void 0),He()}),ce.appendChild(k),ce.appendChild(ft(`peer:${N}:${l.picked}`,{peer:N,id:l.picked}))}else ce.appendChild(ht(N));return}if(l.kind==="remote"){const N=f("div");if(((x=l.row)==null?void 0:x.origin)!==void 0&&it(N,"来源",l.row.origin),((M=l.row)==null?void 0:M.via)!==void 0&&it(N,"经",l.row.via),((A=l.row)==null?void 0:A.workspace)!==void 0&&it(N,"工作区",l.row.workspace),N.childElementCount>0&&ce.appendChild(N),t.remoteSessionLog!==void 0){const _=f("div","wb-chat-note");_.textContent="远端会话节点 —— 经本机代理从对端 /a2a/log 读取最近对话。",ce.appendChild(_),ce.appendChild(ft(`remote:${l.team}`,{team:l.team}))}else{const _=f("div","wb-chat-note");_.textContent="远端节点的对话记录在对端机器上;本页的代理读取面未启用。",ce.appendChild(_)}}else{if(l.kind==="log"){const N=f("div","wb-chat-note");N.textContent="只读日志 —— 此会话当前不在网络目录(可能已归档或未入网)。",ce.appendChild(N)}t.sessionLog!==void 0&&ce.appendChild(ze(l.id))}const b=l.kind==="session"||l.kind==="remote"?l.team:void 0;if(b!==void 0&&b!==""&&t.dispatchQuick!==void 0){const N=f("div","wb-dispatch"),_=f("div","wb-side-head");_.textContent="发送",N.appendChild(_),W===null&&(W={team:b,...nt(b)}),N.appendChild(W.form),ce.appendChild(N),B&&(B=!1,W.text.focus({preventScroll:!0}))}else B=!1}function bt(l){if(n===null)return;const b=(n.sessions??[]).find(M=>M.id===l);if(b!==void 0){$e({kind:"session",id:l,title:ue(b),sub:b.team,team:b.team,live:b.live});return}if(l.startsWith("peer-")){const M=l.slice(5),A=(n.peers??[]).find(N=>N.url.includes(M));$e({kind:"peer",id:l,title:A!==void 0?A.url:M,sub:M,url:A==null?void 0:A.url});return}F.find(M=>M.id===l)!==void 0&&$e({kind:"log",id:l,title:`…${l.slice(-12)}`,sub:"档案"})}function gt(){var _,k,G;S.textContent=(n==null?void 0:n.version)!==void 0?`v${n.version}`:"v?";const l=ve(I);if(n===null)return;const b=[],x=((_=n.tasksDead)==null?void 0:_.length)??0;x>0&&b.push({text:`死信 ${x}`,tone:"danger",title:"超过 24h TTL 仍未结算的任务,需在台账清账"});const M=n.tasksStaleCount??0;M>0&&b.push({text:`陈旧 ${M}`,tone:"warn",title:"≥1h 无回执的旧账(含免回执行),到 24h TTL 自动转死信"});const A=((k=n.idempotency)==null?void 0:k.conflicts)??0;A>0&&b.push({text:`幂等冲突 ${A}`,tone:"danger",title:"同一幂等键对应了不同载荷,需人工核查"});const N=(((G=n.reconcile)==null?void 0:G.rows)??[]).filter(H=>H.needsRepair===!0).length;if(N>0&&b.push({text:`需修复 ${N}`,tone:"danger",title:"reconcile 无法自动恢复的会话,见行动计划"}),b.length===0){l.appendChild(f("span","wb-header-ok")).textContent="● 无异常";return}for(const H of b){const o=f("span",`wb-alert wb-alert-${H.tone}`);o.textContent=H.text,o.title=H.title,l.appendChild(o)}}function vt(l){n=l,t.sessionLogList!==void 0&&!P&&(P=!0,t.sessionLogList().then(b=>{F=b.ok&&b.sessions!==void 0?b.sessions:[]}).catch(()=>{}).finally(()=>{P=!1,Oe()})),gt(),Oe(),ie(),mt(),L!==null&&He(),ut(),Ee(),Ve(),ct(),et()}function At(l){if(l==="board"){ct();return}u.delete(l),et()}return vt(null),{root:Y,update:vt,mode:()=>s,selectTab:At,openNodeChat:bt}}const je=1e6,jt=.25,Bt=3,an=256,rn=96;function Ze(t){const e=typeof t=="number"?t:Number.NaN;if(Number.isFinite(e))return Math.max(-je,Math.min(je,Math.round(e)))}function ln(t){if(t===null||typeof t!="object")return;const e=t,s=Ze(e.x),i=Ze(e.y);return s===void 0||i===void 0?void 0:{x:s,y:i}}function xn(t){const e=ln(t);if(e===void 0)return;const s=t,i=Ze(s.w),n=Ze(s.h);if(!(i===void 0||n===void 0||i<=0||n<=0))return{...e,w:Math.min(i,je),h:Math.min(n,je)}}function cn(t){if(t===null||typeof t!="object")return;const e=t;if(e.version!==1)return;const s=e.viewport;if(s===null||typeof s!="object")return;const i=s,n=Ze(i.x),u=Ze(i.y),d=i.scale,y=typeof d=="number"?d:Number.NaN;if(n===void 0||u===void 0||!Number.isFinite(y))return;const g=Math.max(jt,Math.min(Bt,y)),w={};if(e.nodes!==null&&typeof e.nodes=="object")for(const[B,W]of Object.entries(e.nodes)){if(typeof B!="string"||B===""||B.length>128)continue;const U=ln(W);if(U!==void 0&&(w[B]=U),Object.keys(w).length>=an)break}const L={};if(e.frames!==null&&typeof e.frames=="object")for(const[B,W]of Object.entries(e.frames)){if(typeof B!="string"||B===""||B.includes("/")||B.length>40)continue;const U=xn(W);if(U!==void 0&&(L[B]=U),Object.keys(L).length>=rn)break}return{version:1,viewport:{x:n,y:u,scale:g},nodes:w,frames:L}}function Cn(t,e,s){const i=d=>Math.max(-je,Math.min(je,Math.round(d))),n={};for(const[d,y]of e)if(!(typeof d!="string"||d===""||d.length>128)&&(n[d]={x:i(y.x),y:i(y.y)},Object.keys(n).length>=an))break;const u={};for(const[d,y]of s){if(typeof d!="string"||d===""||d.includes("/")||d.length>40)continue;const g=i(y.w),w=i(y.h);if(!(g<=0||w<=0)&&(u[d]={x:i(y.x),y:i(y.y),w:Math.min(g,je),h:Math.min(w,je)},Object.keys(u).length>=rn))break}return{version:1,viewport:{x:i(t.x),y:i(t.y),scale:Math.max(jt,Math.min(Bt,t.scale))},nodes:n,frames:u}}function dn(t){let e=2166136261;for(let s=0;s<t.length;s++)e^=t.charCodeAt(s),e=Math.imul(e,16777619)>>>0;return e>>>0}const Xe=172,Ie=56,Ue=[150,290,430],Ne=16;function kn(t){const e=dn(t),s=Math.floor(e/Ne)%Ue.length,n=e%Ne/Ne*Math.PI*2+s*(Math.PI/Ne),u=Ue[s];return{x:Math.round(Math.cos(n)*u),y:Math.round(Math.sin(n)*u*.6)}}function mn(t){const e=new Map;for(const s of t)for(const i of s.members)e.has(i.id)||e.set(i.id,s.name);return e}const Vt=64,zt=24,Gt=20,En=4,Jt=24,qt=44,Nn=24;function Mn(t,e,s=Number.POSITIVE_INFINITY){const i=new Set(e),n=mn(t),u=t.map(B=>[...new Set(B.members.map(W=>W.id))].filter(W=>i.has(W)&&n.get(W)===B.name));u.push(e.filter(B=>!n.has(B)));const d=new Map;let y=0,g=0,w=0,L=0;for(const B of u){if(B.length===0)continue;const W=Math.min(3,Math.max(B.length>1?2:1,Math.ceil(Math.sqrt(B.length)))),U=Math.ceil(B.length/W),q=Math.max(260,W*Xe+(W-1)*zt+Jt*2),de=Math.max(160,U*Ie+(U-1)*Gt+qt+Nn);L>0&&(L%En===0||y+q>s)&&(y=0,g+=w+Vt,w=0),B.forEach((ne,F)=>{const P=F%W,Y=Math.floor(F/W);d.set(ne,{x:y+Jt+Xe/2+P*(Xe+zt),y:g+qt+Ie/2+Y*(Ie+Gt)})}),y+=q+Vt,w=Math.max(w,de),L+=1}return d}const xt=12;function un(t,e){const s=g=>e.every(w=>Math.abs(w.x-g.x)>=Xe+xt||Math.abs(w.y-g.y)>=Ie+xt),i=kn(t);if(s(i))return i;const n=dn(t),u=Ne*Ue.length,d=Math.floor(n/Ne)%Ue.length*Ne+n%Ne;for(let g=1;g<u;g++){const w=(d+g)%u,L=Math.floor(w/Ne),B=w%Ne/Ne*Math.PI*2+L*(Math.PI/Ne),W=Ue[L],U={x:Math.round(Math.cos(B)*W),y:Math.round(Math.sin(B)*W*.6)};if(s(U))return U}const y=Ue[Ue.length-1];for(let g=0;;g++)for(let w=0;w<6;w++){const L={x:Math.round(-y+w*(Xe+xt)),y:Math.round(y*.6+Ie*2+g*(Ie+xt))};if(s(L))return L}}function Be(t){return{x:t.x-Xe/2,y:t.y-Ie/2,w:Xe,h:Ie}}function Yt(t){if(t.length===0)return{x:0,y:0,w:260,h:160};let e=Number.POSITIVE_INFINITY,s=Number.POSITIVE_INFINITY,i=Number.NEGATIVE_INFINITY,n=Number.NEGATIVE_INFINITY;for(const L of t)e=Math.min(e,L.x),s=Math.min(s,L.y),i=Math.max(i,L.x+L.w),n=Math.max(n,L.y+L.h);const u=24,d=44,y=24,g=Math.max(260,Math.round(i-e+u*2)),w=Math.max(160,Math.round(n-s+d+y));return{x:Math.round(e-u),y:Math.round(s-d),w:g,h:w}}class Ht{constructor(){Je(this,"revisionCounter",0);Je(this,"nodes",new Map);Je(this,"frames",new Map);Je(this,"selection",new Set);Je(this,"viewport",{x:0,y:0,scale:1})}get revision(){return this.revisionCounter}getNode(e){return this.nodes.get(e)}allNodes(){return[...this.nodes.values()]}nodeIds(){return[...this.nodes.keys()]}getFrame(e){return this.frames.get(e)}allFrames(){return[...this.frames.entries()]}isSelected(e){return this.selection.has(e)}selectedIds(){return[...this.selection]}bump(){this.revisionCounter+=1}dragNodes(e,s,i){let n=!1;for(const u of e){const d=this.nodes.get(u);d!==void 0&&(d.x+=s,d.y+=i,n=!0)}n&&this.bump()}beginFrameDrag(e){const s=this.frames.get(e);if(s===void 0)return;const i=[];for(const n of this.nodes.values())for(const u of n.memberships)if(u.team===e){i.push([n.id,n.x,n.y]);break}return{name:e,rect:{...s},centers:i}}applyFrameDrag(e,s,i){const n=this.frames.get(e.name);if(n!==void 0){n.x=e.rect.x+s,n.y=e.rect.y+i;for(const[u,d,y]of e.centers){const g=this.nodes.get(u);g!==void 0&&(g.x=d+s,g.y=y+i)}this.bump()}}nudge(e,s,i){this.dragNodes(e,s,i)}marqueeSelect(e,s){s||this.selection.clear();for(const i of this.nodes.values()){const n=Be(i);n.x<e.x+e.w&&n.x+n.w>e.x&&n.y<e.y+e.h&&n.y+n.h>e.y&&this.selection.add(i.id)}this.bump()}setSelection(e){this.selection=new Set(e),this.bump()}upsertNode(e){const s=this.nodes.get(e.id);if(s===void 0){this.nodes.set(e.id,e),this.bump();return}s.label=e.label,s.name=e.name,s.live=e.live,s.memberships=e.memberships,this.bump()}removeNode(e){this.nodes.delete(e)&&(this.selection.delete(e),this.bump())}setFrame(e,s){this.frames.set(e,s),this.bump()}removeFrame(e){this.frames.delete(e)&&this.bump()}upsertScore(e,s){const i=this.nodes.get(e);i===void 0||i.score===s||(i.score=s,this.bump())}positions(){const e=new Map;for(const[s,i]of this.nodes)e.set(s,{x:i.x,y:i.y});return e}frameRects(){const e=new Map;for(const[s,i]of this.frames)e.set(s,{...i});return e}teamMemberIds(e){const s=[];for(const i of this.nodes.values()){const n=i.memberships.find(u=>u.team===e);n!==void 0&&s.push({id:i.id,index:n.index})}return s.sort((i,n)=>i.index-n.index).map(i=>i.id)}setTeamMembers(e,s){for(const i of this.nodes.values()){const n=i.memberships.filter(d=>d.team!==e),u=s.indexOf(i.id);u>=0&&n.push({team:e,index:u}),i.memberships=n}this.bump()}contentBounds(){let e=Number.POSITIVE_INFINITY,s=Number.POSITIVE_INFINITY,i=Number.NEGATIVE_INFINITY,n=Number.NEGATIVE_INFINITY;const u=d=>{e=Math.min(e,d.x),s=Math.min(s,d.y),i=Math.max(i,d.x+d.w),n=Math.max(n,d.y+d.h)};for(const d of this.nodes.values())d.remote!==!0&&u(Be(d));for(const d of this.frames.values())u(d);return e===Number.POSITIVE_INFINITY?null:{minX:e,minY:s,maxX:i,maxY:n}}static fromState(e){const s=new Ht,i=cn(e.layout),n=new Map;for(const u of e.teams)for(let d=0;d<u.members.length;d++){const y=u.members[d].id,g=n.get(y)??[];g.push({team:u.name,index:d}),n.set(y,g)}for(const u of e.sessions){if(u.joined!==!0)continue;const d=i==null?void 0:i.nodes[u.id];let y,g;if(d!==void 0&&typeof d.x=="number"&&typeof d.y=="number")y=d.x,g=d.y;else{const w=un(u.id,[...s.nodes.values()]);y=w.x,g=w.y}s.nodes.set(u.id,{id:u.id,x:y,y:g,label:u.label,team:u.team,name:u.name,live:u.live!==!1,memberships:n.get(u.id)??[]})}for(const u of e.teams){const d=i==null?void 0:i.frames[u.name];if(d!==void 0){s.frames.set(u.name,{x:d.x,y:d.y,w:d.w,h:d.h});continue}const y=[];for(const g of u.members){const w=s.nodes.get(g.id);w!==void 0&&y.push(Be(w))}y.length>0&&s.frames.set(u.name,Yt(y))}return s.viewport=i!==void 0?{...i.viewport}:{x:0,y:0,scale:1},s}}const $n=24,Sn=-13,pn=Sn+$n;function Tn(t,e,s){const i=[],n=new Set;for(const u of t){const d=e.get(u.name);if(d===void 0)continue;const y=d.x+d.w/2,g=d.y+pn;for(const w of u.members){const L=s.get(w.id);if(L===void 0)continue;const B=n.has(w.id);n.add(w.id),i.push({x1:y,y1:g,x2:L.x,y2:L.y-Ie/2,dashed:B,team:u.name,id:w.id})}}return i}function Ln(t){return t.name??t.team??t.label??""}function An(t){return`peer-${Ut(t).replace(/[^A-Za-z0-9.:\[\]-]/g,"-")}`}function Ut(t){try{return new URL(t).host}catch{return t}}function In(t){const e=new Map;for(const s of t){const i=s.via!==void 0&&s.via!==""?Ut(s.via):"",n=e.get(i)??[];n.push(s),e.set(i,n)}return e}const _n=140,Fn=200,On=90,Pn=20,Ct=60;function Dn(t,e){const s=e!==null?e.maxX+_n:Fn,i=e!==null?e.minY:0;return t.map((n,u)=>({url:n.url,score:n.score,x:s,y:i+u*On}))}function Rn(t,e,s,i){const n=new Map;for(const d of t){if(!e.has(d.team))continue;const y=`${d.team}\0${d.peer}`,g=n.get(y);g===void 0?n.set(y,{team:d.team,peer:d.peer,startedAt:d.startedAt,count:1}):(g.startedAt=Math.min(g.startedAt,d.startedAt),g.count+=1)}const u=[];for(const d of n.values()){const y=e.get(d.team);if(y===void 0)continue;const g=s.find(L=>{try{return new URL(L.url).host===d.peer}catch{return!1}});if(g===void 0)continue;const w=Math.max(0,Math.round((i-d.startedAt)/1e3));u.push({x1:y.x,y1:y.y,x2:g.x,y2:g.y,label:`a2a_route · ${d.peer} · ${w}s`+(d.count>1?` ×${d.count}`:"")})}return u}function jn(t,e){const s=e!==null?{x:e.maxX+Pn,y:t.length>0?(t[0].y+t[t.length-1].y)/2:(e.minY+e.maxY)/2}:{x:-80,y:0};return t.map((i,n)=>({x1:s.x,y1:s.y,x2:i.x,y2:i.y,label:n===0?"gns referral":""}))}function Bn(t,e){if(t===null&&e.length===0)return null;let s=t!==null?t.minX:Number.POSITIVE_INFINITY,i=t!==null?t.minY:Number.POSITIVE_INFINITY,n=t!==null?t.maxX:Number.NEGATIVE_INFINITY,u=t!==null?t.maxY:Number.NEGATIVE_INFINITY;for(const d of e)s=Math.min(s,d.x-Ct),i=Math.min(i,d.y-Ct),n=Math.max(n,d.x+Ct),u=Math.max(u,d.y+Ct);return{minX:s,minY:i,maxX:n,maxY:u}}const Kt={x:0,y:0,scale:1};function Xt(t){return Math.max(jt,Math.min(Bt,t))}function Qe(t){const e=Number.isFinite(t.scale)?t.scale:1,s=Number.isFinite(t.x)?t.x:0,i=Number.isFinite(t.y)?t.y:0;return{x:s,y:i,scale:Xt(e)}}function Ae(t,e,s){return{x:t.x+e/t.scale,y:t.y+s/t.scale}}function _t(t,e,s){return{x:t.x+e/t.scale,y:t.y+s/t.scale,scale:t.scale}}function Qt(t,e,s,i){const n=Xt(t.scale*e);return n===t.scale?t:{x:t.x+s/t.scale-s/n,y:t.y+i/t.scale-i/n,scale:n}}function Ft(t,e,s,i=Number.POSITIVE_INFINITY){if(t===null||e<=0||s<=0)return Kt;const n=t.maxX-t.minX,u=t.maxY-t.minY;if(!(n>0)||!(u>0))return Kt;const d=Xt(Math.min(i,.9*Math.min(e/n,s/u)));return{x:(t.minX+t.maxX)/2-e/(2*d),y:(t.minY+t.maxY)/2-s/(2*d),scale:d}}function Yn(t){return`translate(${-t.x*t.scale}px, ${-t.y*t.scale}px) scale(${t.scale})`}function Hn(t){return t.type==="join-network"||t.type==="leave-network"?"$network":t.type==="create-team"||t.type==="remove-team"?t.name:t.team}function Un(t,e){if(e.type==="create-team"){const n=e.ids.map(u=>t.getNode(u)).filter(u=>u!==void 0).map(u=>Be(u));return n.length>0&&t.setFrame(e.name,Yt(n)),t.setTeamMembers(e.name,e.ids),()=>{t.setTeamMembers(e.name,t.teamMemberIds(e.name).filter(u=>!e.ids.includes(u))),t.removeFrame(e.name)}}if(e.type==="add-member"){const n=t.teamMemberIds(e.team),u=e.ids.filter(d=>!n.includes(d));return t.setTeamMembers(e.team,[...n,...u]),()=>{t.setTeamMembers(e.team,t.teamMemberIds(e.team).filter(d=>!u.includes(d)))}}if(e.type==="remove-member"){const n=t.teamMemberIds(e.team);return t.setTeamMembers(e.team,n.filter(u=>!e.ids.includes(u))),()=>{const u=t.teamMemberIds(e.team);t.setTeamMembers(e.team,[...u,...e.ids.filter(d=>!u.includes(d))])}}if(e.type==="remove-team"){const n=t.teamMemberIds(e.name),u=t.getFrame(e.name),d=u!==void 0?{...u}:void 0;return t.setTeamMembers(e.name,[]),t.removeFrame(e.name),()=>{d!==void 0&&t.setFrame(e.name,d),t.setTeamMembers(e.name,n)}}if(e.type==="join-network"||e.type==="leave-network")return()=>{};const s=t.teamMemberIds(e.team);let i=[...s];for(const n of e.ops)n.op==="remove"?i=i.filter(u=>u!==n.id):i.push(n.id);return t.setTeamMembers(e.team,i),()=>{let n=t.teamMemberIds(e.team);for(let u=0;u<s.length;u++){const d=s[u];n[u]!==d&&n.includes(d)&&(n=n.filter(y=>y!==d),n.push(d))}t.setTeamMembers(e.team,n)}}function Pt(t,e){const s=[...t],i=[];for(let n=0;n<e.length;n++){const u=e[n];s[n]!==u&&s.includes(u)&&(i.push({op:"remove",id:u}),i.push({op:"add",id:u}),s.splice(s.indexOf(u),1),s.push(u))}return i}function Xn(t,e){return t.teamMemberIds(e).map(s=>{var i;return{id:s,y:((i=t.getNode(s))==null?void 0:i.y)??0}}).sort((s,i)=>s.y-i.y).map(s=>s.id)}function Zt(t,e){let s,i=Number.POSITIVE_INFINITY;for(const[n,u]of t){if(e.x<u.x||e.x>u.x+u.w||e.y<u.y||e.y>u.y+u.h)continue;const d=u.w*u.h;d<i&&(s=n,i=d)}return s}const en=[9133302,3900150,1357990,16096779,15485081,8702998];function Wn(t){const{root:e,netBtn:s,signal:i,model:n}=t;function u(){return n.selectedIds().map(T=>{var R;return{id:T,y:((R=n.getNode(T))==null?void 0:R.y)??0}}).sort((T,R)=>T.y-R.y).map(T=>T.id)}function d(){if(y!==null)return;const T=u().filter(R=>{var S;return((S=n.getNode(R))==null?void 0:S.remote)!==!0});if(T.length<2){t.notice("info","框选至少 2 个会话节点");return}g(T)}let y=null;function g(T){const R=document.createElement("div");R.className="p-dialog";const S=document.createElement("div");S.className="p-dialog-panel",S.setAttribute("role","dialog"),S.setAttribute("aria-modal","true"),S.setAttribute("aria-labelledby","p-dialog-title");const I=document.createElement("div");I.id="p-dialog-title",I.className="p-dialog-title",I.textContent=`组建团队(${T.length} 个节点,自上而下即优先级)`;const v=document.createElement("input");v.className="p-dialog-input",v.maxLength=40,v.setAttribute("aria-label","团队名");const O=document.createElement("div");O.className="p-dialog-err",O.setAttribute("aria-live","polite");const X=document.createElement("div");X.className="p-dialog-row";const Z=document.createElement("button");Z.type="button",Z.textContent="组建";const se=document.createElement("button");se.type="button",se.textContent="取消",X.append(Z,se),S.append(I,v,O,X),R.appendChild(S),e.appendChild(R);const ae=document.activeElement,K=()=>{R.remove(),y=null,ae==null||ae.focus()},he=()=>{const ee=v.value.trim();return ee===""||ee.length>40||ee.includes("/")||/^\d+$/.test(ee)?"队名需 1..40 字,不含“/”,不为纯数字":null},be=()=>{const ee=he();if(ee!==null){O.textContent=ee,v.focus();return}const J=v.value.trim();if(K(),n.getFrame(J)!==void 0){t.notice("info",`已加入现有团队「${J}」`),t.emit({type:"add-member",team:J,ids:T});return}t.emit({type:"create-team",name:J,ids:T,created:!0})};Z.addEventListener("click",be),se.addEventListener("click",K),v.addEventListener("keydown",ee=>{const J=ee;J.key==="Enter"&&(J.preventDefault(),be()),J.key==="Escape"&&(J.preventDefault(),K())}),R.addEventListener("keydown",ee=>{const J=ee;if(J.key==="Escape"){J.preventDefault(),J.stopPropagation(),K();return}if(J.key!=="Tab")return;J.preventDefault();const V=Array.from(S.querySelectorAll("input, button")),te=V.indexOf(document.activeElement),oe=J.shiftKey?V[(te-1+V.length)%V.length]:V[(te+1)%V.length];oe==null||oe.focus()},i),y={wrap:R,restoreFocus:ae},v.focus()}let w=null,L="root",B=null,W=null,U=[];function q(){W==null||W.remove(),W=null}function de(){var S;if(W!==null){q();return}if(U.length===0)return;const T=document.createElement("div");T.className="p-menu p-netmenu",T.setAttribute("role","menu"),T.setAttribute("aria-label","未入网会话");for(const I of U)T.appendChild(F(`${I.name!==void 0&&I.name!==""?I.name:I.label} — 入网`,!0,()=>{q(),t.emit({type:"join-network",id:I.id})}));W=T,e.appendChild(T);const R=s.getBoundingClientRect();T.style.left=`${String(Math.min(R.left,window.innerWidth-220))}px`,T.style.top=`${String(Math.max(8,R.top-(U.length*30+10)))}px`,T.addEventListener("keydown",I=>{I.key==="Escape"&&(I.stopPropagation(),q(),s.focus())}),(S=T.querySelector("button"))==null||S.focus(),document.addEventListener("pointerdown",I=>{if(W===null)return;const v=I.target;v!==null&&(v.closest(".p-netmenu")!==null||v===s||s.contains(v))||q()},i)}function ne(){w==null||w.remove(),w=null,L="root",B!==null&&B.isConnected?B.focus():e.focus(),B=null}function F(T,R,S){const I=document.createElement("button");return I.type="button",I.setAttribute("role","menuitem"),I.textContent=T,R?I.addEventListener("click",()=>{ne(),S()}):(I.disabled=!0,I.setAttribute("aria-disabled","true")),I}function P(T,R,S,I="root",v){var se,ae,K,he,be,ee;v!==void 0&&(B=v),B===null&&(B=t.anchorFor(S)),w==null||w.remove(),L=I;const O=document.createElement("div");O.className="p-menu",O.setAttribute("role","menu"),O.setAttribute("aria-label","团队操作");let X=[];if(S.kind==="frame")X=[F(`解散团队「${S.name}」`,!0,()=>t.emit({type:"remove-team",name:S.name}))];else{const J=S.id;if(I==="root"){const V=F("组成团队…",n.selectedIds().length>=2,()=>g(u()));V.title="先框选或 Shift 加选至少 2 个节点",X.push(V),t.teams().length>0&&(X.push(F("加入团队 ▸",!0,()=>P(T,R,S,"join"))),(((se=n.getNode(J))==null?void 0:se.memberships.map(oe=>oe.team))??[]).length>0&&(X.push(F("置顶路由 ▸",!0,()=>P(T,R,S,"promote"))),X.push(F("离队 ▸",!0,()=>P(T,R,S,"leave"))))),((ae=n.getNode(J))==null?void 0:ae.remote)!==!0&&X.push(F("退网",!0,()=>t.emit({type:"leave-network",id:J})))}else{X.push(F("‹ 返回",!0,()=>P(T,R,S,"root")));for(const V of t.teams())if(I==="join"){const te=((K=n.getNode(J))==null?void 0:K.memberships.some(oe=>oe.team===V.name))??!0;X.push(F(te?`${V.name}(已加入)`:V.name,!te,()=>t.emit({type:"add-member",team:V.name,ids:[J]})))}else if(I==="leave"){const te=((he=n.getNode(J))==null?void 0:he.memberships.some(oe=>oe.team===V.name))??!1;X.push(F(V.name,te,()=>t.emit({type:"remove-member",team:V.name,ids:[J]})))}else{const te=((be=n.getNode(J))==null?void 0:be.memberships.some(oe=>oe.team===V.name))??!1;X.push(F(V.name,te,()=>{const oe=n.teamMemberIds(V.name),Ce=[J,...oe.filter(ye=>ye!==J)];t.emit({type:"reorder",team:V.name,ops:Pt(oe,Ce)})}))}}}O.append(...X),O.style.left=`${Math.min(T,window.innerWidth-200)}px`;const Z=X.length*30+8;O.style.top=`${Math.max(8,Math.min(R,window.innerHeight-Z-8))}px`,O.addEventListener("keydown",J=>{var Ce,ye,pe,me;const V=J,te=Array.from(O.querySelectorAll("[role=menuitem]")),oe=te.indexOf(document.activeElement);V.key==="ArrowDown"?(V.preventDefault(),(Ce=te[(oe+1+te.length)%te.length])==null||Ce.focus()):V.key==="ArrowUp"?(V.preventDefault(),(ye=te[(oe-1+te.length)%te.length])==null||ye.focus()):V.key==="Home"?(V.preventDefault(),(pe=te[0])==null||pe.focus()):V.key==="End"?(V.preventDefault(),(me=te[te.length-1])==null||me.focus()):V.key==="Escape"&&(V.preventDefault(),V.stopPropagation(),L!=="root"?P(T,R,S,"root"):ne())}),e.appendChild(O),w=O,(ee=X[0])==null||ee.focus()}function Y(T,R,S){var X;if(y!==null)return;const I=(S==null?void 0:S.closest(".p-node"))??null;if(I!==null&&((X=n.getNode(I.dataset.id??""))==null?void 0:X.remote)===!0)return;const v=I,O=(S==null?void 0:S.closest(".p-frame-head"))??null;if(v!==null){const Z=v.dataset.id??"";n.isSelected(Z)||n.setSelection([Z]),B=v,P(T,R,{kind:"node",id:Z})}else O!==null&&(B=O,P(T,R,{kind:"frame",name:O.dataset.frame??""}))}function D(T){U=T,s.textContent=`未入网${U.length>0?`(${String(U.length)})`:""}`,s.disabled=U.length===0,s.setAttribute("aria-disabled",String(U.length===0)),U.length===0&&q()}return{menuItem:F,isMenuOpen:()=>w!==null,isDialogOpen:()=>y!==null,closeMenu:ne,openMenu:P,contextMenuAt:Y,openNameDialog:g,startCreateFromSelection:d,toggleNetMenu:de,setUnjoined:D}}function Vn(t){const{root:e,trigger:s,signal:i,model:n}=t;let u=null,d="",y=null;function g(){y==null||y.remove(),y=null}function w(){g(),u==null||u.remove(),u=null}function L(){if(u!==null){w();return}const P=document.createElement("div");P.className="p-menu p-nodelist",P.setAttribute("role","dialog"),P.setAttribute("aria-label","节点清单"),u=P,e.appendChild(P);const Y=s.getBoundingClientRect();P.style.left=`${String(Math.min(Y.left,window.innerWidth-340))}px`,P.style.top=`${String(Math.max(8,Y.top-320))}px`,P.addEventListener("keydown",D=>{D.key==="Escape"&&(D.stopPropagation(),w(),s.focus())}),B()}function B(){var I;const P=u;if(P===null)return;g(),P.textContent="";const Y=document.createElement("div");Y.className="p-nodelist-head";const D=document.createElement("span");D.className="p-nodelist-title",D.textContent="节点";const T=document.createElement("select");T.className="p-nodesel",T.setAttribute("aria-label","选择 host 或对等节点");const R=document.createElement("option");R.value="",R.textContent="本机",T.appendChild(R);for(const[v,O]of t.facts().remoteTeams){if(v==="")continue;const X=document.createElement("option");X.value=v,X.textContent=((I=O[0])==null?void 0:I.origin)!==void 0&&O[0].origin!==""?`${O[0].origin}(${v})`:v,T.appendChild(X)}d!==""&&!t.facts().remoteTeams.has(d)&&(d=""),T.value=d,T.addEventListener("change",()=>{d=T.value,B()}),Y.append(D,T);const S=document.createElement("div");S.className="p-nodelist-body",P.append(Y,S),d===""?ne(S):F(S,t.facts().remoteTeams.get(d)??[])}function W(P,Y){const D=document.createElement("span");return D.className="p-nodedot"+(Y!==!0?" off":P===!1?" cold":""),D}function U(P,Y){const D=document.createElement("button");return D.type="button",D.className="p-listbtn",D.textContent=P,D.addEventListener("click",T=>{T.stopPropagation(),Y()}),D}function q(P,Y){const D=document.createElement("div");if(D.className="p-nodelist-group",D.textContent=P,Y!==void 0){const T=document.createElement("span");T.className="p-nodelist-note",T.textContent=Y,D.appendChild(T)}return D}function de(P,Y){var R,S;g();const D=document.createElement("div");D.className="p-menu",D.setAttribute("role","menu"),D.setAttribute("aria-label","加入团队");for(const I of t.facts().teams){const v=((R=n.getNode(Y))==null?void 0:R.memberships.some(O=>O.team===I.name))??!1;D.appendChild(t.menuItem(v?`${I.name}(已加入)`:I.name,!v,()=>{w(),t.emit({type:"add-member",team:I.name,ids:[Y]})}))}D.appendChild(t.menuItem("新团队…",!0,()=>{w(),t.openNameDialog([Y])})),y=D,e.appendChild(D);const T=P.getBoundingClientRect();D.style.left=`${String(Math.min(T.right+4,window.innerWidth-180))}px`,D.style.top=`${String(Math.max(8,T.top-60))}px`,D.addEventListener("keydown",I=>{I.key==="Escape"&&(I.stopPropagation(),g(),P.focus())}),(S=D.querySelector("button"))==null||S.focus()}function ne(P){var S,I;const Y=new Set(t.facts().canvasMemberIds);for(const v of t.facts().sessions)v.teams!==void 0&&v.teams.length>0&&Y.add(v.id);const D=t.facts().sessions.filter(v=>v.joined===!0&&!Y.has(v.id)),T=t.facts().sessions.filter(v=>v.joined!==!0),R=t.facts().sessions.filter(v=>v.joined===!0&&Y.has(v.id));P.appendChild(q(`未组队 (${String(D.length)})`,"无网络能力"));for(const v of D){const O=document.createElement("div");O.className="p-noderow";const X=document.createElement("span");X.className="p-nodename",X.textContent=v.name!==void 0&&v.name!==""?v.name:v.label,X.title=v.team;const Z=document.createElement("span");Z.className="p-nonet",Z.textContent="无网络能力";const se=U("入队▸",()=>de(se,v.id));O.append(W(v.live,!0),X,Z,se,U("退网",()=>{w(),t.emit({type:"leave-network",id:v.id})})),P.appendChild(O)}P.appendChild(q(`未入网 (${String(T.length)})`));for(const v of T){const O=document.createElement("div");O.className="p-noderow";const X=document.createElement("span");X.className="p-nodename",X.textContent=v.name!==void 0&&v.name!==""?v.name:v.label,X.title=v.id,O.append(W(v.live,!1),X,U("入网",()=>{w(),t.emit({type:"join-network",id:v.id})})),P.appendChild(O)}P.appendChild(q(`已组队 (${String(R.length)})`,"画布展示"));for(const v of R){const O=document.createElement("div");O.className="p-noderow";const X=document.createElement("span");X.className="p-nodename",X.textContent=v.name!==void 0&&v.name!==""?v.name:v.label,X.title=v.team;const Z=((S=n.getNode(v.id))==null?void 0:S.memberships.length)??0,se=((I=v.teams)==null?void 0:I.length)??0,ae=document.createElement("span");ae.className="p-teamcount",ae.textContent=`队×${String(Math.max(Z,0)+se)}`,O.append(W(v.live,!0),X,ae,U("定位",()=>{t.locate(v.id)})),P.appendChild(O)}if(t.facts().sessions.length===0){const v=document.createElement("div");v.className="p-nodelist-empty",v.textContent="无会话节点",P.appendChild(v)}}function F(P,Y){var R;const D=Y.filter(S=>S.teams===void 0||S.teams.length===0),T=Y.filter(S=>S.teams!==void 0&&S.teams.length>0);P.appendChild(q(`未组队 (${String(D.length)})`,"无网络能力 · 只读"));for(const S of D){const I=document.createElement("div");I.className="p-noderow";const v=document.createElement("span");v.className="p-nodename",v.textContent=S.name!==void 0&&S.name!==""?S.name:S.team,v.title=S.team;const O=document.createElement("span");O.className="p-nonet",O.textContent="无网络能力",I.append(W(!0,!0),v,O),P.appendChild(I)}P.appendChild(q(`已组队 (${String(T.length)})`,"只读"));for(const S of T){const I=document.createElement("div");I.className="p-noderow";const v=document.createElement("span");v.className="p-nodename",v.textContent=S.name!==void 0&&S.name!==""?S.name:S.team,v.title=S.team;const O=document.createElement("span");O.className="p-teamcount",O.textContent=`队×${String(((R=S.teams)==null?void 0:R.length)??0)}`,I.append(W(!0,!0),v,O),P.appendChild(I)}if(Y.length===0){const S=document.createElement("div");S.className="p-nodelist-empty",S.textContent="该节点未发布会话",P.appendChild(S)}}return document.addEventListener("pointerdown",P=>{if(u===null)return;const Y=P.target;if(Y===null){w();return}Y.closest(".p-nodelist")!==null||Y.closest(".p-menu")!==null||Y===s||s.contains(Y)||w()},i),{toggle:L,close:w,refresh:()=>{u!==null&&B()}}}function zn(t){return t<680?"narrow":t<1024?"medium":"wide"}function Gn(t){let e=0;for(let y=0;y<t.length;y++)e=(e*31+t.charCodeAt(y)&268435455)>>>0;const s=en[e%en.length],i="#"+s.toString(16).padStart(6,"0"),n=s>>16&255,u=s>>8&255,d=s&255;return{line:i,bg:`rgba(${n},${u},${d},0.05)`}}function Jn(t){const e=new Ht;let s,i={...e.viewport},n={kind:"none"},u=!1,d=-1,y=!0,g=!1;const w=()=>zn(globalThis.innerWidth||me),L=()=>{var o;(o=t.viewportStore)==null||o.set(w(),i),t.onDirty()},B=t.now??Date.now,W=new AbortController,U=[];let q=null,de=!1;const ne={signal:W.signal},F=document.createElement("section");F.id="dsh-plan",F.setAttribute("role","tabpanel"),F.setAttribute("aria-label","A2A 规划画布"),F.tabIndex=0,F.style.display="none";const P=document.createElement("div");P.className="p-grid";const Y=document.createElement("div");Y.className="p-world";const D=document.createElementNS("http://www.w3.org/2000/svg","svg");D.setAttribute("class","p-edges");const T=document.createElement("div");T.className="p-layer p-frames";let R;const S=o=>{var a,c;R!==void 0&&((a=we.get(R))==null||a.classList.remove("selected")),R=o,o!==void 0&&((c=we.get(o))==null||c.classList.add("selected"))},I=document.createElement("div");I.className="p-layer p-nodes",I.setAttribute("role","listbox"),I.setAttribute("aria-multiselectable","true"),I.setAttribute("aria-label","会话节点"),Y.append(D,T,I);const v=document.createElement("div");v.className="p-marquee";const O=document.createElement("div");O.className="p-toolbar";const X=document.createElement("span");X.className="p-zoom mono",X.textContent="100%";const Z=(o,a,c)=>{const p=document.createElement("button");return p.type="button",p.textContent=o,p.title=a,p.addEventListener("click",c,ne),p};O.append(Z("适配","适配视图(快捷键 0)",()=>bt()),Z("-","缩小",()=>Ge(1/1.2)),X,Z("+","放大",()=>Ge(1.2)),Z("建队","组成团队(G):先框选至少 2 个节点",()=>ie.startCreateFromSelection()));const se=Z("未入网","未入网会话(点击选择入网)",()=>ie.toggleNetMenu());se.className="p-netbtn",se.setAttribute("aria-haspopup","menu"),O.appendChild(se);const ae=Z("节点","节点清单:本机与对等节点(未组队/未入网在此管理)",()=>ot.toggle());ae.className="p-nodebtn",ae.setAttribute("aria-haspopup","dialog"),O.appendChild(ae);const K=document.createElement("span");K.setAttribute("aria-live","polite"),K.className="p-lamp";const he=document.createElement("i"),be=document.createElement("span");be.textContent="布局",K.append(he,be),K.addEventListener("click",()=>{K.classList.contains("error")&&t.onLampClick()},ne),K.addEventListener("keydown",o=>{const a=o;(a.key==="Enter"||a.key===" ")&&K.classList.contains("error")&&(a.preventDefault(),t.onLampClick())},ne),O.appendChild(K);const ee=document.createElement("div");ee.className="p-status";const J=document.createElement("span"),V=document.createElement("span"),te=document.createElement("span");te.className="mut";const oe=document.createElement("span");oe.className="mut",ee.append(J,V,te,oe),ee.tabIndex=0,ee.setAttribute("role","button"),ee.setAttribute("aria-label","定位在途路由与联邦对端"),ee.title="定位在途与联邦(回车)",ee.addEventListener("click",()=>ut(),ne),ee.addEventListener("keydown",o=>{const a=o;(a.key==="Enter"||a.key===" ")&&(a.preventDefault(),ut())},ne);const Ce=document.createElement("div");Ce.className="p-legend";const ye=(o,a,c)=>{const p=document.createElement("span"),h=document.createElement("i");o&&(h.className="dashed"),c!==void 0&&(h.style.borderTopColor=c),p.append(h,document.createTextNode(a)),Ce.appendChild(p)};ye(!1,"成员边(星形,框→成员)"),ye(!0,"跨队多属(虚线)"),ye(!1,"活动边(inFlight 路由,瞬时)","var(--accent)"),ye(!0,"联邦线(→peer)","var(--federal)");const pe=document.createElement("div");pe.className="p-notice-stack",pe.setAttribute("role","log"),pe.setAttribute("aria-live","polite"),F.append(P,Y,v,O,ee,Ce,pe);let me=0,ke=0;const lt=()=>t.viewSize?t.viewSize():{w:F.clientWidth,h:F.clientHeight},ge=()=>{const o=lt();me=o.w,ke=o.h};function fe(){Y.style.transform=Yn(i);const o=24*i.scale;P.style.backgroundSize=`${o}px ${o}px`,P.style.backgroundPosition=`${-i.x*i.scale}px ${-i.y*i.scale}px`,X.textContent=`${Math.round(i.scale*100)}%`}function le(){fe(),e.revision!==d&&(d=e.revision,Ye(),St(),ct()),Tt()}const we=new Map,Fe=new Map;function Ye(){const o=new Set;for(const[a,c]of e.allFrames()){o.add(a);let p=we.get(a);if(p===void 0){p=document.createElement("div"),p.className="p-frame",p.dataset.name=a;const Q=document.createElement("div");Q.className="p-frame-head",Q.dataset.frame=a,Q.tabIndex=0,Q.setAttribute("role","button"),Q.setAttribute("aria-haspopup","menu"),Q.setAttribute("aria-label",`团队框 ${a}(拖动整组,回车菜单)`);const re=document.createElement("span");re.className="ttl";const Le=document.createElement("span");Le.className="cnt mono";const De=document.createElement("span");De.className="route mono",Q.append(re,Le,De),p.appendChild(Q);for(const Re of["n","s","e","w","ne","nw","se","sw"]){const yt=document.createElement("div");yt.className=`p-frame-handle p-h-${Re}`,yt.dataset.frame=a,yt.dataset.dir=Re,p.appendChild(yt)}T.appendChild(p),we.set(a,p)}const h=Gn(a);p.style.setProperty("--frame-line",h.line),p.style.setProperty("--frame-bg",h.bg),p.style.left=`${c.x}px`,p.style.top=`${c.y}px`,p.style.width=`${c.w}px`,p.style.height=`${c.h}px`;const E=p.querySelector(".ttl"),m=p.querySelector(".cnt"),r=p.querySelector(".route");E.textContent!==a&&(E.textContent=a);let C=0,$=0;for(const Q of e.allNodes())Q.memberships.find(Le=>Le.team===a)!==void 0&&(C+=1,Q.memberships.length>1&&($+=1));const j=`${C} 成员`+($>0?` +${$} 跨队`:"");m.textContent!==j&&(m.textContent=j);const z=et(a);r.textContent!==z&&(r.textContent=z)}for(const[a,c]of[...we])o.has(a)||(c.remove(),we.delete(a))}function ce(o){const a=Oe.get(o)??[],c=a.map(m=>m.name!==void 0&&m.name!==""?m.name:m.team),p=c.slice(0,2).join("、"),h=c.length>2?` +${c.length-2}`:"",E=Pe.get(o);return(E!==void 0?`score ${E} · `:"")+`${a.length} 远端团队`+(p!==""?`:${p}${h}`:"")}function et(o){const a=b.find(c=>c.name===o);return(a==null?void 0:a.team)??o}function St(){const o=new Set;for(const a of e.allNodes()){o.add(a.id);let c=Fe.get(a.id);if(c===void 0){c=document.createElement("div"),c.className="p-node",c.dataset.id=a.id,c.tabIndex=0;const Q=document.createElement("div");Q.className="nm";const re=document.createElement("span");re.className="dot";const Le=document.createElement("span");Le.className="nm-text",Q.append(re,Le);const De=document.createElement("div");De.className="sub mono";const Re=document.createElement("span");Re.className="prio mono",c.append(Q,De,Re),I.appendChild(c),Fe.set(a.id,c)}const p=Be(a);c.style.left=`${p.x}px`,c.style.top=`${p.y}px`,c.classList.toggle("cold",!a.live),c.classList.toggle("remote",a.remote===!0),c.classList.toggle("selected",e.isSelected(a.id)),c.setAttribute("aria-selected",String(e.isSelected(a.id)));const h=a.id.slice(5),E=a.remote===!0?h:Ln(a),m=c.querySelector(".nm-text");m.textContent!==E&&(m.textContent=E);const r=c.querySelector(".sub"),C=a.team+(a.name!==void 0&&a.name!==""?" · "+a.name:""),$=a.remote===!0?ce(h):(C===E?"":C)+(a.memberships.length>1?` · 跨队×${a.memberships.length}`:"")+(a.teams!==void 0&&a.teams.length>0?` · 网络队×${a.teams.length}`:"");r.textContent!==$&&(r.textContent=$);const j=c.querySelector(".prio"),z=a.remote===!0?"peer":a.memberships[0]!==void 0?`P${a.memberships[0].index}`:"";j.textContent!==z&&(j.textContent=z)}for(const[a,c]of[...Fe])o.has(a)||(c.remove(),Fe.delete(a))}function ct(){for(;D.firstChild!==null;)D.firstChild.remove();const o=e.allFrames().map(([a])=>({name:a,members:e.teamMemberIds(a).map(c=>({id:c}))}));for(const a of Tn(o,new Map(e.allFrames()),e.positions())){const c=document.createElementNS("http://www.w3.org/2000/svg","line");c.setAttribute("class","e-member"+(a.dashed?" dashed":"")),c.setAttribute("x1",String(a.x1)),c.setAttribute("y1",String(a.y1)),c.setAttribute("x2",String(a.x2)),c.setAttribute("y2",String(a.y2)),D.appendChild(c)}}let ve=[],tt=[],Oe=new Map;const Pe=new Map;let dt=[];function Tt(){for(const c of ve)c.remove();ve=[];const o=e.allNodes().filter(c=>c.remote===!0).map(c=>({url:c.peerUrl??c.id.slice(5),score:c.score,x:c.x,y:c.y}));tt=o;const a=e.contentBounds();if(a!==null){const c=new Map;for(const[p,h]of e.allFrames())c.set(p,{name:p,x:h.x+h.w/2,y:h.y+pn});for(const p of Rn(dt,c,o,B()))ve.push(...mt(p,"e-activity",p.label));for(const p of jn(o,a))ve.push(...mt(p,"e-federal",p.label))}}function mt(o,a,c){const p=document.createElementNS("http://www.w3.org/2000/svg","line");p.setAttribute("class",a),p.setAttribute("x1",String(o.x1)),p.setAttribute("y1",String(o.y1)),p.setAttribute("x2",String(o.x2)),p.setAttribute("y2",String(o.y2)),D.appendChild(p);const h=[p];if(c!==""){const E=document.createElementNS("http://www.w3.org/2000/svg","text");E.setAttribute("class","edge-label mono"),E.setAttribute("x",String((o.x1+o.x2)/2+14)),E.setAttribute("y",String((o.y1+o.y2)/2+18)),E.textContent=c,D.appendChild(E),h.push(E)}return h}function ut(){i=Ft(Bn(e.contentBounds(),tt),F.clientWidth||me,F.clientHeight||ke),fe(),L()}function Lt(o){var E;const a=o.sessions.filter(m=>m.live!==!1).length,c=o.sessions.length-a;J.textContent="";const p=document.createElement("b");p.className="ok",p.textContent=`● ${a} live`,J.appendChild(p),V.textContent="";const h=document.createElement("b");h.className="warn",h.textContent=`● ${c} cold`,V.appendChild(h),te.textContent=`${((E=o.inFlight)==null?void 0:E.length)??0} inFlight`,oe.className="mut",oe.textContent=`${o.teams.length} 队 · ${o.peerCount} peer`}const Ee=new Map,We=o=>{Ee.set(o,(Ee.get(o)??0)+1)},Me=o=>{const a=(Ee.get(o)??0)-1;a<=0?Ee.delete(o):Ee.set(o,a)};function xe(o){if(o.type==="add-member"||o.type==="remove-member"||o.type==="reorder"||o.type==="create-team"){const p=o.type==="reorder"?o.ops.map(h=>h.id):[...o.ids];for(const h of p){if(h===""||h.startsWith("peer-")||e.getNode(h)!==void 0)continue;const E=Ve.find(C=>C.id===h);if(E===void 0)continue;const m=s==null?void 0:s.nodes[h],r=m!==void 0?{x:m.x,y:m.y}:M(h);e.upsertNode({id:h,x:r.x,y:r.y,label:E.label,team:E.team,name:E.name,live:E.live!==!1,memberships:[],...E.teams!==void 0&&E.teams.length>0?{teams:E.teams}:{}})}}const a=Un(e,o),c=Hn(o);We(c),le(),t.onCanvasAction(o).then(p=>{Me(c),p||a(),le()},()=>{Me(c),a(),Te("error","操作通道异常,已回滚"),le()})}function Te(o,a){var p;for(;pe.childElementCount>=3;)(p=pe.firstElementChild)==null||p.remove();const c=document.createElement("div");c.className="p-notice"+(o==="error"?" error":""),c.setAttribute("role",o==="error"?"alert":"status"),c.textContent=a,pe.appendChild(c),U.push(setTimeout(()=>c.remove(),4e3))}const ie=Wn({root:F,netBtn:se,signal:ne,model:e,teams:()=>b,anchorFor:o=>(o.kind==="node"?Fe.get(o.id):we.get(o.name))??null,emit:xe,notice:Te});let Ve=[],nt=new Set;const ot=Vn({root:F,trigger:ae,signal:ne,model:e,facts:()=>({sessions:Ve,canvasMemberIds:nt,remoteTeams:Oe,teams:b}),menuItem:ie.menuItem,emit:xe,openNameDialog:ie.openNameDialog,locate:pt});function pt(o){var p;const a=e.getNode(o);if(a===void 0)return;ot.close();const c=((p=t.viewSize)==null?void 0:p.call(t))??{w:F.clientWidth>0?F.clientWidth:800,h:F.clientHeight>0?F.clientHeight:600};i=Qe({scale:i.scale,x:a.x-c.w/(2*i.scale),y:a.y-c.h/(2*i.scale)}),fe(),d=-1,le()}function ze(o){const a=F.getBoundingClientRect();return{x:o.clientX-a.left,y:o.clientY-a.top}}function ft(o,a){var m;const c=ze(a),p=Ae(i,c.x,c.y),h=Zt(new Map(e.allFrames()),p),E=o.ids.filter(r=>{var C;return((C=e.getNode(r))==null?void 0:C.remote)!==!0});if(h!==void 0){const r=E.filter(C=>{var $;return!(($=e.getNode(C))!=null&&$.memberships.some(j=>j.team===h))});if(r.length>0){xe({type:"add-member",team:h,ids:r});return}if(o.ids.length===1&&((m=e.getNode(o.clicked))==null?void 0:m.remote)!==!0){const C=e.teamMemberIds(h),$=Xn(e,h);$.join("\0")!==C.join("\0")&&xe({type:"reorder",team:h,ops:Pt(C,$)})}}}function ht(o){if(me===0&&ge(),ie.isDialogOpen()){o.preventDefault();return}const a=o.target;if(ie.isMenuOpen()){if(a!==null&&a.closest(".p-menu")!==null)return;ie.closeMenu(),o.preventDefault();return}const c=ze(o);if(o.button===2){q={x:c.x,y:c.y,target:o.target,moved:!1},o.preventDefault();try{F.setPointerCapture(o.pointerId??0)}catch{}return}if(a!==null&&(a.closest("button")!==null||a.closest(".p-lamp")!==null||a.closest(".p-status")!==null))return;const p=a!==null?a.closest(".p-node"):null,h=a!==null?a.closest(".p-frame-head"):null;if((p!==null||h!==null)&&o.button===1){n={kind:"pan",last:c,moved:!1},o.preventDefault();try{F.setPointerCapture(o.pointerId??0)}catch{}return}const E=a!==null?a.closest(".p-frame-handle"):null;if(R!==void 0){const m=we.get(R),r=a!==null&&m!==void 0&&(m.contains(a)||m===a),C=h!==null&&h.dataset.frame===R;!r&&!C&&S(void 0)}if(E!==null&&o.button===0){const m=E.dataset.frame??"";S(m);const r=e.getFrame(m);if(r===void 0)return;n={kind:"frame-resize",name:m,dir:E.dataset.dir??"se",startRect:{...r},origin:Ae(i,c.x,c.y),moved:!1},o.preventDefault();try{F.setPointerCapture(o.pointerId??0)}catch{}return}if(p!==null){if(o.button!==0)return;const m=p.dataset.id??"",r=e.isSelected(m);!r&&!o.shiftKey&&e.setSelection([m]);const C=o.shiftKey||r?e.isSelected(m)?e.selectedIds():[...e.selectedIds(),m]:[m];n={kind:"node",clicked:m,ids:C,last:Ae(i,c.x,c.y),moved:!1,el:p},p.classList.add("dragging")}else if(h!==null){if(o.button!==0)return;const m=h.dataset.frame??"";S(m);const r=e.beginFrameDrag(m);if(r===void 0)return;n={kind:"frame",name:m,snap:r,origin:Ae(i,c.x,c.y),moved:!1}}else if(o.button===1||o.button===0&&u)n={kind:"pan",last:c,moved:!1};else if(o.button===0)n={kind:"marquee",origin:c,last:c,additive:o.shiftKey},v.style.display="block",v.style.left=`${c.x}px`,v.style.top=`${c.y}px`,v.style.width="0px",v.style.height="0px";else return;o.preventDefault();try{F.setPointerCapture(o.pointerId??0)}catch{}}function st(o){const a=ze(o);if(q!==null){const c=a.x-q.x,p=a.y-q.y;Math.hypot(c,p)>4&&(q.moved=!0,i=Qe(_t(i,-c,-p)),q.x=a.x,q.y=a.y,fe());return}if(n.kind==="node"){const c=Ae(i,a.x,a.y),p=c.x-n.last.x,h=c.y-n.last.y;if(p===0&&h===0)return;n.moved=!0,n.last=c,e.dragNodes(n.ids,p,h);const E=Zt(new Map(e.allFrames()),c),m=n.ids.filter(C=>{var $;return(($=e.getNode(C))==null?void 0:$.remote)!==!0}),r=E!==void 0&&m.length>0;for(const[C,$]of we)$.classList.toggle("drop-target",r&&C===E);le()}else if(n.kind==="frame"){const c=Ae(i,a.x,a.y),p=c.x-n.origin.x,h=c.y-n.origin.y;if(!n.moved&&p===0&&h===0)return;n.moved=!0,e.applyFrameDrag(n.snap,p,h),le()}else if(n.kind==="frame-resize"){const c=Ae(i,a.x,a.y),p=c.x-n.origin.x,h=c.y-n.origin.y;if(!n.moved&&p===0&&h===0)return;n.moved=!0;const E=220,m=120,r={...n.startRect};let{x:C,y:$,w:j,h:z}=r;n.dir.includes("e")&&(j=Math.max(E,r.w+p)),n.dir.includes("s")&&(z=Math.max(m,r.h+h)),n.dir.includes("w")&&(j=Math.max(E,r.w-p),C=r.x+(r.w-j)),n.dir.includes("n")&&(z=Math.max(m,r.h-h),$=r.y+(r.h-z)),e.setFrame(n.name,{x:Math.round(C),y:Math.round($),w:Math.round(j),h:Math.round(z)}),le()}else if(n.kind==="pan")i=_t(i,a.x-n.last.x,a.y-n.last.y),n.last=a,n.moved=!0,fe();else if(n.kind==="marquee"){const c=Math.min(n.origin.x,a.x),p=Math.min(n.origin.y,a.y);v.style.left=`${c}px`,v.style.top=`${p}px`,v.style.width=`${Math.abs(a.x-n.origin.x)}px`,v.style.height=`${Math.abs(a.y-n.origin.y)}px`,n.last=a}}function $e(o){var a,c;if(q!==null){const p=q.moved,h=q.target,E=q.x,m=q.y;q=null,p?(de=!0,L()):h!==null&&ie.contextMenuAt(E,m,h);return}if(n.kind==="node"){const p=n.clicked;if(n.moved)ft(n,o),L();else if(o.shiftKey){const h=e.selectedIds();e.setSelection(h.includes(p)?h.filter(E=>E!==p):[...h,p])}else e.setSelection([p]),(a=t.onNodePick)==null||a.call(t,p);for(const h of we.values())h.classList.remove("drop-target");(c=n.el)==null||c.classList.remove("dragging"),le()}else if(n.kind==="frame")n.moved&&L();else if(n.kind==="frame-resize")n.moved&&L();else if(n.kind==="pan")n.moved&&L();else if(n.kind==="marquee"){const p=n.last,h=Ae(i,Math.min(n.origin.x,p.x),Math.min(n.origin.y,p.y)),E=Ae(i,Math.max(n.origin.x,p.x),Math.max(n.origin.y,p.y));e.marqueeSelect({x:h.x,y:h.y,w:E.x-h.x,h:E.y-h.y},n.additive),v.style.display="none",le()}n={kind:"none"};try{F.releasePointerCapture(o.pointerId??0)}catch{}}function He(o){ie.isMenuOpen()&&ie.closeMenu();const a=ze(o);if(o.shiftKey&&!o.ctrlKey){const c=o.deltaMode===1?16:1;i=Qe(_t(i,(o.deltaX??0)*c,(o.deltaY??0)*c))}else{const c=o.deltaMode===1?16:1,p=Math.exp(-((o.deltaY??0)*c)*.0015);i=Qt(i,p,a.x,a.y)}o.preventDefault(),fe(),L()}function Ge(o){ge(),i=Qt(i,o,me/2,ke/2),fe(),L()}function bt(){ge(),i=Ft(e.contentBounds(),me,ke),fe(),L()}function gt(o){var E,m,r,C,$;if(ie.isDialogOpen()||o.ctrlKey||o.metaKey)return;if(ie.isMenuOpen()){o.key==="Escape"&&(ie.closeMenu(),o.preventDefault());return}if(o.key===" "&&o.target===F){u=!0,o.preventDefault();return}const a=((m=(E=o.target)==null?void 0:E.closest)==null?void 0:m.call(E,".p-frame-head"))??null;if((o.key==="Enter"||o.key===" ")&&a!==null){o.preventDefault();const j=a.getBoundingClientRect();ie.contextMenuAt(j.left+j.width/2,j.top+j.height/2,a);return}if(o.key===" "&&((C=(r=o.target)==null?void 0:r.classList)!=null&&C.contains("p-node"))){const z=o.target.dataset.id??"",Q=e.selectedIds();e.setSelection(Q.includes(z)?Q.filter(re=>re!==z):[...Q,z]),le(),o.preventDefault();return}if(o.key==="F10"&&o.shiftKey||o.key==="ContextMenu"){o.preventDefault();const j=document.activeElement??null,z=(($=j==null?void 0:j.getBoundingClientRect)==null?void 0:$.call(j))??{left:0,top:0,width:0,height:0};ie.contextMenuAt(z.left+z.width/2,z.top+z.height/2,j);return}if(o.key==="Delete"||o.key==="Backspace"){o.preventDefault(),vt();return}if(o.altKey&&(o.key==="ArrowUp"||o.key==="ArrowDown")){o.preventDefault(),At(o.key==="ArrowUp");return}if(o.key==="g"||o.key==="G"){ie.startCreateFromSelection();return}if(o.key==="0"){bt();return}if(o.key==="="||o.key==="+"){Ge(1.2);return}if(o.key==="-"){Ge(1/1.2);return}if(o.key==="Escape"){if(ie.isMenuOpen()){ie.closeMenu(),le();return}e.setSelection([]),le();return}const c=o.shiftKey?40:8,h={ArrowLeft:[-c,0],ArrowRight:[c,0],ArrowUp:[0,-c],ArrowDown:[0,c]}[o.key];if(h!==void 0){o.preventDefault();const j=e.selectedIds();j.length>0&&(e.nudge(j,h[0],h[1]),le(),L())}}function vt(){var p,h,E;const o=document.activeElement,a=((p=o==null?void 0:o.closest)==null?void 0:p.call(o,".p-frame-head"))??null,c=((h=o==null?void 0:o.closest)==null?void 0:h.call(o,".p-node"))??null;if(a!==null){xe({type:"remove-team",name:a.dataset.frame??""});return}if(c!==null){const m=c.dataset.id??"",r=((E=e.getNode(m))==null?void 0:E.memberships.map(C=>C.team))??[];if(r.length===0){Te("info","该节点未加入任何团队");return}if(r.length===1){xe({type:"remove-member",team:r[0],ids:[m]});return}ie.openMenu(window.innerWidth/2,window.innerHeight/2,{kind:"node",id:m},"leave",c);return}Te("info","焦点不在节点或团队框上")}function At(o){var j,z;const a=document.activeElement,c=((j=a==null?void 0:a.closest)==null?void 0:j.call(a,".p-node"))??null;if(c===null)return;const p=c.dataset.id??"",h=((z=e.getNode(p))==null?void 0:z.memberships)??[];if(h.length!==1)return;const E=h[0].team,m=e.teamMemberIds(E),r=m.indexOf(p),C=o?Math.max(0,r-1):Math.min(m.length-1,r+1);if(C===r)return;const $=[...m];$.splice(r,1),$.splice(C,0,p),xe({type:"reorder",team:E,ops:Pt(m,$)})}function l(o){o.key===" "&&(u=!1)}F.addEventListener("pointerdown",o=>ht(o),ne),F.addEventListener("pointermove",o=>st(o),ne),F.addEventListener("pointerup",o=>$e(o),ne),F.addEventListener("wheel",o=>He(o),{...ne,passive:!1}),F.addEventListener("keydown",o=>gt(o),ne),F.addEventListener("keyup",o=>l(o),ne),F.addEventListener("contextmenu",o=>{const a=o;if(a.preventDefault(),a.preventDefault(),de){de=!1;return}ie.contextMenuAt(a.clientX,a.clientY,a.target)},ne);let b=[];function x(o){b=o.teams,o.peers,dt=o.inFlight??[],Ve=o.sessions,ie.setUnjoined(o.sessions.filter(r=>r.joined!==!0&&!r.id.startsWith("peer-")));const a=new Map;for(const r of o.teams)for(let C=0;C<r.members.length;C++){const $=r.members[C].id,j=a.get($)??[];j.push({team:r.name,index:C}),a.set($,j)}nt=new Set(a.keys());const c=new Set,p=r=>{const C=a.get(r)??[];if(Ee.size===0)return C;const $=C.filter(z=>!Ee.has(z.team)),j=[];for(const[z]of Ee){const re=e.teamMemberIds(z).indexOf(r);re>=0&&j.push({team:z,index:re})}return[...$,...j]};let h;if(s===void 0&&!e.allNodes().some(r=>r.remote!==!0)){const r=o.sessions.filter(C=>{var $;return C.joined===!0&&(p(C.id).length>0||((($=C.teams)==null?void 0:$.length)??0)>0)}).map(C=>C.id);ge(),h=Mn(o.teams,r,me>0?me:void 0)}for(const r of o.sessions){if(r.joined!==!0)continue;const C=p(r.id);if(!(C.length===0&&(r.teams===void 0||r.teams.length===0)))if(c.add(r.id),e.getNode(r.id)!==void 0)e.upsertNode({id:r.id,x:e.getNode(r.id).x,y:e.getNode(r.id).y,label:r.label,team:r.team,name:r.name,live:r.live!==!1,memberships:C,...r.teams!==void 0&&r.teams.length>0?{teams:r.teams}:{}});else{const $=s==null?void 0:s.nodes[r.id];let j,z;if($!==void 0)j=$.x,z=$.y;else{const Q=(h==null?void 0:h.get(r.id))??M(r.id);j=Q.x,z=Q.y}e.upsertNode({id:r.id,x:j,y:z,label:r.label,team:r.team,name:r.name,live:r.live!==!1,memberships:C,...r.teams!==void 0&&r.teams.length>0?{teams:r.teams}:{}})}}for(const r of e.nodeIds())!c.has(r)&&!r.startsWith("peer-")&&e.removeNode(r);const E=new Set;Oe=In(o.remoteTeams??[]),Pe.clear();for(const r of o.peers??[])Pe.set(Ut(r.url),r.score);if(o.peers!==void 0){const r=e.contentBounds(),C=Dn(o.peers,r);o.peers.forEach(($,j)=>{var De,Re;const z=An($.url);E.add(z);const Q=s==null?void 0:s.nodes[z],re=e.getNode(z),Le=re!==void 0?{x:re.x,y:re.y}:Q!==void 0?{x:Q.x,y:Q.y}:{x:((De=C[j])==null?void 0:De.x)??200,y:((Re=C[j])==null?void 0:Re.y)??0};e.upsertNode({id:z,x:Le.x,y:Le.y,label:$.url,team:"",name:$.url,peerUrl:$.url,live:!0,remote:!0,memberships:[]}),e.upsertScore(z,$.score)})}for(const r of e.nodeIds())r.startsWith("peer-")&&!E.has(r)&&e.removeNode(r);const m=mn(o.teams);for(const r of o.teams){if(e.getFrame(r.name)!==void 0||Ee.has(r.name))continue;const C=s==null?void 0:s.frames[r.name];if(C!==void 0){e.setFrame(r.name,{...C});continue}const $=[],j=[];for(const Q of r.members){const re=e.getNode(Q.id);re!==void 0&&(j.push(Be(re)),m.get(Q.id)===r.name&&$.push(Be(re)))}const z=$.length>0?$:j;z.length>0&&e.setFrame(r.name,Yt(z))}for(const[r]of e.allFrames())Ee.has(r)||o.teams.some(C=>C.name===r)||e.removeFrame(r);if(ot.refresh(),Lt(o),y&&n.kind==="none"&&e.nodeIds().length>0&&(ge(),me>0&&ke>0)){y=!1;let r=e.contentBounds();for(const C of e.allNodes()){if(C.remote!==!0)continue;const $=Be(C);r=r===null?{minX:$.x,minY:$.y,maxX:$.x+$.w,maxY:$.y+$.h}:{minX:Math.min(r.minX,$.x),minY:Math.min(r.minY,$.y),maxX:Math.max(r.maxX,$.x+$.w),maxY:Math.max(r.maxY,$.y+$.h)}}i=Ft(r,me,ke,1)}le()}function M(o){return un(o,e.allNodes().filter(a=>a.remote!==!0))}function A(o){const a=cn(o);if(a===void 0)return;s=a;const c=t.viewportStore;if(c===void 0)y=!1,n.kind==="none"&&(i=Qe({...a.viewport}));else if(!g&&n.kind==="none"){g=!0;const p=c.get(w());p!=null&&Number.isFinite(p.x)&&Number.isFinite(p.y)&&Number.isFinite(p.scale)?(i=Qe({x:p.x,y:p.y,scale:p.scale}),y=!1):w()==="wide"&&(i=Qe({...a.viewport}),y=!1)}d=-1,le()}function N(){return Cn(i,e.positions(),e.frameRects())}function _(o,a){K.classList.remove("pending","saved","error"),o==="pending"&&K.classList.add("pending"),o==="saved"&&K.classList.add("saved"),o==="error"&&K.classList.add("error"),o==="error"?(K.tabIndex=0,K.setAttribute("role","button"),K.setAttribute("aria-label","布局保存失败,按回车重试")):(K.removeAttribute("tabindex"),K.removeAttribute("role"),K.removeAttribute("aria-label"));const c=o==="pending"?"布局待保存…":o==="saved"?`布局已保存 ${a??""}`.trimEnd():o==="error"?"保存失败 · 回车重试":"布局";be.textContent=c}function k(){F.style.display="block",ge(),fe(),F.focus()}function G(){F.style.display="none"}function H(){W.abort();for(const o of U)clearTimeout(o)}return{root:F,reconcile:x,activate:k,deactivate:G,adoptExternalLayout:A,snapshotDoc:N,setLamp:_,notice:Te,destroy:H,seam:{pointerDown:ht,pointerMove:st,pointerUp:$e,wheel:He,key:gt,keyUp:l,contextMenu(o){o.preventDefault(),ie.contextMenuAt(o.clientX,o.clientY,o.target)}}}}const qn=800;function Kn(t){let e,s=!1,i=!1,n=!1,u="idle";function d(L){L!==u&&(u=L,t.onLamp(L))}function y(){e!==void 0&&(e(),e=void 0)}function g(){y(),e=t.schedule(()=>{e=void 0,w(!1)},qn)}async function w(L){if(s){i=!0;return}s=!0,y();const B=t.snapshot();let W;try{W=JSON.stringify(B)}catch{s=!1,d("error"),t.onHttpError("layout document is not JSON-serializable");return}try{const U=await t.send(B,{keepalive:L});if(U===null||typeof U!="object"||U.ok!==!0){d("error");const q=U!==null&&typeof U=="object"&&typeof U.error=="string"?U.error:"layout save refused";t.onHttpError(`layout save: ${q}`)}else JSON.stringify(t.snapshot())===W&&(t.onAdopt(U.layout),d("saved"))}catch(U){d("error"),t.onHttpError(`layout save unreachable: ${String((U==null?void 0:U.message)??U).slice(0,80)}`)}if(s=!1,u==="error"){n=!1;return}if(n){n=!1,w(!0);return}i&&(i=!1,d("pending"),g())}return{markDirty(){if(i=!1,d("pending"),s){i=!0;return}g()},retry(){u!=="error"||s||(d("pending"),w(!1))},flush(){if(s){n=!0,i=!0;return}y(),w(!0)},isBusy(){return s},dispose(){y()}}}function tn(t){return typeof t.error=="string"?t.error:void 0}function Qn(t){const e=new Map;let s=0;function i(d,y){s+=1;const g=e.get(d)??Promise.resolve(),w=async()=>{try{return await y()}finally{s-=1}},L=g.then(w,w);return e.set(d,L.then(()=>{},()=>{})),L}async function n(d){let y;try{y=await t.send(d)}catch(w){const L=String((w==null?void 0:w.message)??w).slice(0,80);return t.onNotice("error",`画布不可达:${L}`),!1}if(y.status>=400)return t.onNotice("error",tn(y.body)??`HTTP ${y.status}`),!1;if(y.body.ok===!0)return!0;const g=tn(y.body);return g!==void 0?(t.onNotice("error",g),!1):!0}async function u(d,y){for(const g of y)if(!await n({...d,id:g}))return!1;return!0}return{createTeam(d,y,g=!1){return i(d,async()=>{if(!await n({action:"create",name:d}))return!1;for(let w=0;w<y.length;w++)if(!await n({action:"add-member",name:d,id:y[w]}))return g&&w===0&&await n({action:"remove",name:d}),!1;return!0})},addMembers(d,y){return i(d,()=>u({action:"add-member",name:d},y))},removeMembers(d,y){return i(d,()=>u({action:"remove-member",name:d},y))},runRosterOps(d,y){return i(d,async()=>{for(const g of y){const w=g.op==="remove"?{action:"remove-member",name:d,id:g.id}:{action:"add-member",name:d,id:g.id};if(!await n(w))return!1}return!0})},removeTeam(d){return i(d,()=>n({action:"remove",name:d}))},hasPending(){return s>0}}}const fn=document.getElementById("app"),nn=window.__DSH_A2A_KEY__??"",Se=(t,e={})=>fetch(t,{...e,headers:{...e.headers??{},...nn!==""?{"X-API-Key":nn}:{}}}),rt=document.createElement("div");rt.className="nexus-fault";fn.appendChild(rt);const{fault:Dt,clear:Zn}=gn({show(t){rt.textContent=t,rt.style.display="block"},hide(){rt.style.display="none"}},t=>console.error(t));let kt;const on="dsh-a2a.viewport.",eo={get(t){try{const e=window.localStorage.getItem(on+t);return e===null?void 0:JSON.parse(e)}catch{return}},set(t,e){try{window.localStorage.setItem(on+t,JSON.stringify({x:e.x,y:e.y,scale:e.scale}))}catch{}}},_e=Jn({viewportStore:eo,onDirty:()=>Et.markDirty(),onLampClick:()=>Et.retry(),onNodePick:t=>{kt==null||kt(t)},onCanvasAction:async t=>{const e=await to(t);return $t(),e}}),Et=Kn({snapshot:()=>_e.snapshotDoc(),send:(t,e)=>Se("/__dsh_a2a/canvas-layout",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({action:"save",layout:t}),cache:"no-store",keepalive:e.keepalive}).then(async s=>await s.json()),schedule:(t,e)=>{const s=setTimeout(t,e);return()=>{clearTimeout(s)}},now:Date.now,onLamp:t=>{Rt=t;const e=new Date,s=String(e.getHours()).padStart(2,"0")+":"+String(e.getMinutes()).padStart(2,"0");_e.setLamp(t,s)},onAdopt:t=>{_e.adoptExternalLayout(t)},onHttpError:t=>Dt(t)});window.addEventListener("pagehide",()=>Et.flush());const at=Qn({send:async t=>{const e=await Se("/__dsh_a2a/canvas",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t),cache:"no-store"});return{status:e.status,body:await e.json()}},onNotice:(t,e)=>_e.notice(t,e)});function to(t){switch(t.type){case"create-team":return at.createTeam(t.name,t.ids,t.created);case"add-member":return at.addMembers(t.team,t.ids);case"remove-member":return at.removeMembers(t.team,t.ids);case"remove-team":return at.removeTeam(t.name);case"reorder":return at.runRosterOps(t.team,t.ops);case"join-network":case"leave-network":return no(t.type==="join-network"?"join":"leave",t.id)}}async function no(t,e){const s=await Se(`/__dsh_a2a/${t}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({id:e}),cache:"no-store"}).catch(()=>{});return s!==void 0&&s.ok}let Rt="idle",Nt=!1,sn,Ot=!1;async function oo(){const t=await Se("/__dsh_a2a/canvas-layout",{cache:"no-store"});if(!t.ok)throw new Error(`/__dsh_a2a/canvas-layout ${t.status}`);return(await t.json()).layout??null}const Mt=wn({now:()=>Date.now(),async abandon(t,e){try{return(await Se("/__dsh_a2a/tasks/abandon",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({task_id:t,reason:e})})).ok}catch{return!1}},copy(t){var e;(e=navigator.clipboard)==null||e.writeText(t).catch(()=>{})},async canvasOp(t,e,s){try{const i=await Se("/__dsh_a2a/canvas",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({action:t,name:e,id:s})}),n=await i.json().catch(()=>({}));return i.ok&&n.ok!==!1?!0:(console.warn(`canvas ${t} ${e}: ${n.error??`HTTP ${i.status}`}`),!1)}catch{return!1}},async dispatchQuick(t,e){try{const s=await Se("/__dsh_a2a/dispatch",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({team:t,message:e})}),i=await s.json().catch(()=>({}));return{ok:s.ok&&i.ok===!0,task_id:i.task_id,reply:i.reply,error:i.error??`HTTP ${s.status}`}}catch(s){return{ok:!1,error:s instanceof Error?s.message:String(s)}}},async sessionLog(t){try{const e=await Se(`/__dsh_a2a/session-log?id=${encodeURIComponent(t)}`),s=await e.json().catch(()=>({}));return{ok:e.ok&&s.ok===!0,messages:s.messages,error:s.error??(e.ok?void 0:`HTTP ${e.status}`)}}catch(e){return{ok:!1,error:e instanceof Error?e.message:String(e)}}},async sessionLogList(){try{const t=await Se("/__dsh_a2a/session-log"),e=await t.json().catch(()=>({}));return{ok:t.ok&&e.ok===!0,sessions:e.sessions,error:e.error??(t.ok?void 0:`HTTP ${t.status}`)}}catch(t){return{ok:!1,error:t instanceof Error?t.message:String(t)}}},async remoteSessionLog(t){try{const e=new URLSearchParams;t.team!==void 0&&e.set("team",t.team),t.peer!==void 0&&e.set("peer",t.peer),t.id!==void 0&&e.set("id",t.id),t.limit!==void 0&&e.set("limit",String(t.limit));const s=await Se(`/__dsh_a2a/remote-session-log?${e.toString()}`),i=await s.json().catch(()=>({}));return{ok:s.ok&&i.ok===!0,messages:i.messages,sessions:i.sessions,error:i.error??(s.ok?void 0:`HTTP ${s.status}`),via:i.via}}catch(e){return{ok:!1,error:e instanceof Error?e.message:String(e)}}},board:{root:_e.root,activate:()=>_e.activate(),deactivate:()=>_e.deactivate(),available:()=>Nt}});fn.appendChild(Mt.root);kt=t=>{Mt.openNodeChat(t)};if(new URLSearchParams(window.location.search).get("mode")==="plan"){const t=window.setInterval(()=>{Nt&&(Mt.selectTab("board"),window.clearInterval(t))},300);window.setTimeout(()=>window.clearInterval(t),3e4)}async function $t(){var t;try{const e=await Se("/__dsh_a2a/state",{cache:"no-store"});if(!e.ok)throw new Error(`/__dsh_a2a/state ${e.status}`);const s=await e.json();if(Zn(),Nt=s.canvas!==void 0,Mt.update(s),Nt)try{const g=await oo(),w=JSON.stringify(g??null);w!==sn&&(sn=w,(Rt==="idle"||Rt==="saved")&&!Et.isBusy()&&_e.adoptExternalLayout(g)),Ot=!0}catch(g){if(!Ot){Dt(`canvas layout 获取失败:${String(g)}`);return}}else Ot=!0;const i=(s.sessions??[]).map(g=>({...g,joined:g.joined===!0})),n=((t=s.canvas)==null?void 0:t.teams)??[],u=(s.peers??[]).filter(g=>g!==null&&typeof g=="object"&&typeof g.url=="string"),d=(s.inFlight??[]).filter(g=>g!==null&&typeof g=="object"&&typeof g.team=="string"&&typeof g.peer=="string"&&Number.isFinite(g.startedAt)),y=(s.remote??[]).filter(g=>g!==null&&typeof g=="object"&&typeof g.team=="string"&&typeof g.via=="string").map(g=>({team:g.team,name:g.name,via:g.via,workspace:g.workspace,...typeof g.origin=="string"&&g.origin!==""?{origin:g.origin}:{},...Array.isArray(g.teams)&&g.teams.length>0?{teams:g.teams.filter(w=>typeof w=="string"&&w!=="")}:{}}));_e.reconcile({sessions:i,teams:n,peerCount:u.length,peers:u,inFlight:d,remoteTeams:y})}catch(e){Dt(`state 轮询失败:${String(e)}`)}}$t();window.setInterval(()=>{document.hidden||$t()},3e3);document.addEventListener("visibilitychange",()=>{document.hidden||$t()});
@@ -1 +0,0 @@
1
- #dsh-plan *,#dsh-plan *:before,#dsh-plan *:after{box-sizing:border-box}#dsh-plan{--uupm-ink-0:var(--n-ink,#dde3f0);--uupm-ink-1:var(--n-ink-muted,#7a86a0);--uupm-bg-0:var(--n-bg,#060a12);--uupm-bg-1:var(--n-panel,#0d1322);--uupm-bg-2:var(--n-raised,#131b2e);--uupm-accent:var(--n-accent,#9673f7);--uupm-live:var(--n-live,#4ade80);--uupm-cold:var(--n-cold,#7a86a0);--uupm-edge-member:var(--n-canvas,#22d3ee);--uupm-warn:var(--n-act,#f59e0b);--uupm-error:var(--n-danger,#f87171);--uupm-indigo:var(--n-federal,#6366f1);--uupm-wash-5:color-mix(in srgb,var(--uupm-accent) 5%,transparent);--uupm-wash-8:color-mix(in srgb,var(--uupm-accent) 8%,transparent);--uupm-wash-12:color-mix(in srgb,var(--uupm-accent) 12%,transparent);--uupm-wash-15:color-mix(in srgb,var(--uupm-accent) 15%,transparent);--uupm-wash-18:color-mix(in srgb,var(--uupm-accent) 18%,transparent);--surface:var(--uupm-bg-1);--ink:var(--uupm-ink-0);--ink-muted:var(--uupm-ink-1);--accent:var(--uupm-accent);--edge-live:var(--uupm-live);--edge-cold:var(--uupm-cold);--federal:var(--uupm-indigo);--card-bg:var(--surface);--card-line:var(--n-card-line,#5c6680);--card-line-hover:var(--uupm-ink-1);--toolbar-bg:color-mix(in srgb,var(--uupm-bg-1) 92%,transparent);--grid-dot:color-mix(in srgb,var(--uupm-ink-1) 22%,transparent);--scrim:color-mix(in srgb,var(--uupm-bg-0) 60%,transparent);--error-ink:var(--n-error-ink,#fecaca);--error-panel:var(--n-error-panel,#2a0d10f2)}#dsh-plan{position:absolute;top:0;right:0;bottom:0;left:0;overflow:hidden;background:var(--uupm-bg-0);color:var(--ink);font-size:13px;line-height:1.5;outline:none}#dsh-plan .mono{font-family:ui-monospace,Cascadia,Consolas,monospace}#dsh-plan:focus-visible{outline:2px solid var(--accent);outline-offset:-2px}#dsh-plan .p-grid{position:absolute;top:0;right:0;bottom:0;left:0;z-index:0;pointer-events:none;background-image:radial-gradient(circle,var(--grid-dot) 1px,transparent 1px);background-size:24px 24px;background-position:0 0}#dsh-plan .p-world{position:absolute;top:0;right:0;bottom:0;left:0;z-index:1;transform-origin:0 0}#dsh-plan .p-layer{position:absolute;top:0;right:0;bottom:0;left:0;pointer-events:none}#dsh-plan .p-edges{position:absolute;overflow:visible;width:100%;height:100%;pointer-events:none}#dsh-plan .p-frame{pointer-events:none}#dsh-plan .p-frame-head,#dsh-plan .p-node{pointer-events:auto}#dsh-plan .e-member{stroke:var(--uupm-edge-member);stroke-opacity:.38;stroke-width:1.5}#dsh-plan .e-member.dashed{stroke-dasharray:3 4}#dsh-plan .p-frame{--frame-ink:var(--frame-line,#8B5CF6)}@media (prefers-color-scheme: light){#dsh-plan .p-frame{--frame-ink:color-mix(in srgb,var(--frame-line,#8B5CF6) 72%,black)}}#dsh-plan .p-frame{position:absolute;border:1px solid var(--frame-ink);border-radius:10px;background:var(--frame-bg,var(--uupm-wash-5));min-width:120px;min-height:60px}#dsh-plan .p-frame-head{position:absolute;top:-13px;left:50%;transform:translate(-50%);height:24px;padding:0 10px;border-radius:6px;display:flex;gap:8px;align-items:center;background:var(--uupm-bg-2);border:1px solid var(--frame-ink);font-size:12px;font-weight:600;letter-spacing:.02em;white-space:nowrap;cursor:grab}#dsh-plan .p-frame-head:active{cursor:grabbing}#dsh-plan .p-frame-head:hover{border-color:var(--card-line-hover)}#dsh-plan .p-frame-head .cnt{color:var(--ink-muted);font-weight:400}#dsh-plan .p-frame-head .route{font-size:10.5px;color:var(--ink-muted)}#dsh-plan .p-node{position:absolute;width:172px;height:56px;padding:8px 26px 8px 14px;background:var(--card-bg);border:1px solid var(--card-line);border-left:3px solid var(--edge-live);border-radius:8px;cursor:grab;-webkit-user-select:none;user-select:none;transition:border-color .12s cubic-bezier(.2,0,0,1),transform .12s cubic-bezier(.2,0,0,1)}#dsh-plan .p-node:hover{border-color:var(--card-line-hover)}#dsh-plan .p-node:active{cursor:grabbing}#dsh-plan .p-node:focus-visible{outline:2px solid var(--accent);outline-offset:2px}#dsh-plan .p-node.selected{outline:2px solid var(--accent);outline-offset:1px}#dsh-plan .p-node.dragging{transform:scale(1.02);border-color:var(--accent)}#dsh-plan .p-node.cold{border-left-color:var(--edge-cold)}#dsh-plan .p-node .nm{font-weight:600;display:flex;align-items:center;gap:7px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}#dsh-plan .p-node .nm-text{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}#dsh-plan .p-node .dot{width:8px;height:8px;border-radius:50%;background:var(--edge-live);flex:none}#dsh-plan .p-node.cold .dot{background:transparent;border:1.5px solid var(--edge-cold)}#dsh-plan .p-node .sub{font-size:11px;color:var(--ink-muted);margin-top:2px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}#dsh-plan .p-node .prio{position:absolute;top:6px;right:8px;font-size:10px;color:var(--ink-muted);border:1px solid var(--card-line);border-radius:4px;padding:0 5px}#dsh-plan .p-marquee{position:absolute;z-index:2;display:none;pointer-events:none;border:1px solid var(--accent);background:var(--uupm-wash-8)}#dsh-plan .p-toolbar{position:absolute;top:16px;left:16px;z-index:3;display:flex;gap:6px;align-items:center;background:var(--toolbar-bg);border:1px solid var(--card-line);border-radius:8px;padding:6px 8px}#dsh-plan .p-tabs{position:absolute;top:16px;left:50%;transform:translate(-50%);z-index:3;display:flex;gap:4px;background:var(--toolbar-bg);border:1px solid var(--card-line);border-radius:8px;padding:4px}#dsh-plan .p-tabs [role=tab]{background:transparent;color:var(--ink-muted);border:1px solid transparent;border-radius:6px;padding:4px 12px;font:inherit;cursor:pointer}#dsh-plan .p-tabs [role=tab]:hover{color:var(--ink);border-color:var(--card-line)}#dsh-plan .p-tabs [role=tab][aria-selected=true]{color:var(--ink);border-color:var(--accent);background:var(--uupm-wash-12)}#dsh-plan .p-tabs [role=tab]:focus-visible{outline:2px solid var(--accent);outline-offset:1px}#dsh-plan .p-toolbar button{background:transparent;color:var(--ink);border:1px solid var(--card-line);border-radius:6px;padding:4px 10px;font:inherit;cursor:pointer;white-space:nowrap}#dsh-plan .p-toolbar button:hover{border-color:var(--accent)}#dsh-plan .p-toolbar button:active{background:var(--uupm-wash-15)}#dsh-plan .p-toolbar button:focus-visible{outline:2px solid var(--accent);outline-offset:1px}#dsh-plan .p-zoom{min-width:44px;text-align:center;font-size:11px;color:var(--ink-muted)}#dsh-plan .p-lamp{display:flex;align-items:center;gap:6px;font-size:11px;color:var(--ink-muted);padding:0 6px}#dsh-plan .p-lamp i{width:7px;height:7px;border-radius:50%;background:var(--ink-muted);transition:background .14s ease}#dsh-plan .p-lamp.saved i{background:var(--edge-live)}#dsh-plan .p-lamp.pending i{background:var(--uupm-warn)}#dsh-plan .p-lamp.error{color:var(--uupm-error);cursor:pointer}#dsh-plan .p-lamp.error i{background:var(--uupm-error)}#dsh-plan .p-lamp.error:hover{border:1px solid var(--uupm-error);border-radius:4px}#dsh-plan .p-status{position:absolute;top:16px;right:16px;z-index:3;display:flex;gap:14px;background:var(--toolbar-bg);border:1px solid var(--card-line);border-radius:8px;padding:8px 14px;font-size:12px}#dsh-plan .p-status b{font-weight:600}#dsh-plan .ok{color:var(--edge-live)}#dsh-plan .warn{color:var(--uupm-warn)}#dsh-plan .mut{color:var(--ink-muted)}#dsh-plan .p-legend{position:absolute;bottom:16px;left:16px;z-index:3;font-size:11px;color:var(--ink-muted);background:var(--toolbar-bg);border:1px solid var(--card-line);border-radius:8px;padding:8px 12px;display:grid;gap:4px}#dsh-plan .p-legend i{display:inline-block;width:18px;border-top:2px solid var(--uupm-edge-member);vertical-align:middle;margin-right:6px}#dsh-plan .p-legend i.dashed{border-top-style:dashed}@media (max-width:680px){#dsh-plan .p-toolbar{left:8px;right:8px;top:8px;overflow-x:auto;scrollbar-width:none}#dsh-plan .p-toolbar>*{flex:none}#dsh-plan .p-status{left:8px;right:auto;top:58px;padding:6px 10px;gap:10px;flex-wrap:wrap}#dsh-plan .p-legend{display:none}}@media (pointer:coarse){#dsh-plan .p-toolbar button{min-height:36px;min-width:36px}}@media (prefers-reduced-motion: reduce){#dsh-plan *{transition:none!important;animation:none!important}}#dsh-plan .p-frame.drop-target{border-color:var(--accent);border-width:2px;background:var(--uupm-wash-12)}#dsh-plan .p-frame-head:focus-visible{outline:2px solid var(--accent);outline-offset:1px}#dsh-plan .p-node.remote{border-left-color:var(--federal);padding-right:46px}#dsh-plan .p-node.remote .dot{background:var(--federal)}#dsh-plan .p-node.remote .prio{color:var(--ink)}#dsh-plan .e-activity{stroke:var(--accent);stroke-width:2;stroke-dasharray:8 6;stroke-opacity:.9}#dsh-plan .e-federal{stroke:var(--federal);stroke-width:1.5;stroke-dasharray:6 5;stroke-opacity:.5}#dsh-plan .edge-label{font-size:10.5px;fill:var(--ink-muted)}@media (prefers-reduced-motion: no-preference){#dsh-plan .e-activity{animation:p-activity-flow 1.1s linear infinite}}@keyframes p-activity-flow{to{stroke-dashoffset:-28}}#dsh-plan .p-status{cursor:pointer}#dsh-plan .p-status:hover{border-color:var(--accent)}#dsh-plan .p-status:active{background:var(--uupm-wash-12)}#dsh-plan .p-status:focus-visible{outline:2px solid var(--accent);outline-offset:2px}#dsh-plan .p-menu{position:fixed;z-index:5;min-width:170px;display:grid;padding:4px;gap:2px;background:var(--toolbar-bg);border:1px solid var(--card-line);border-radius:8px}#dsh-plan .p-menu [role=menuitem]{background:transparent;color:var(--ink);border:1px solid transparent;border-radius:6px;padding:6px 10px;font:inherit;text-align:left;cursor:pointer;white-space:nowrap}#dsh-plan .p-menu [role=menuitem]:hover{border-color:var(--card-line);background:var(--uupm-wash-8)}#dsh-plan .p-menu [role=menuitem]:active{background:var(--uupm-wash-18)}#dsh-plan .p-menu [role=menuitem]:focus-visible{outline:2px solid var(--accent);outline-offset:1px}#dsh-plan .p-menu [role=menuitem][aria-disabled=true]{color:var(--ink-muted);cursor:not-allowed}#dsh-plan .p-dialog{position:absolute;top:0;right:0;bottom:0;left:0;z-index:6;display:grid;place-items:center;background:var(--scrim)}#dsh-plan .p-dialog-panel{min-width:300px;padding:14px 16px;display:grid;gap:10px;background:var(--uupm-bg-2);border:1px solid var(--card-line);border-radius:10px}#dsh-plan .p-dialog-title{font-weight:600;font-size:12.5px;color:var(--ink)}#dsh-plan .p-dialog-input{font:inherit;color:var(--ink);background:var(--uupm-bg-0);border:1px solid var(--card-line);border-radius:6px;padding:7px 10px}#dsh-plan .p-dialog-input:hover{border-color:color-mix(in srgb,var(--uupm-ink-1) 55%,transparent)}#dsh-plan .p-dialog-input:focus-visible{outline:2px solid var(--accent);outline-offset:1px;border-color:var(--accent)}#dsh-plan .p-dialog-err{min-height:1.2em;font-size:11px;color:var(--uupm-error)}#dsh-plan .p-dialog-row{display:flex;gap:8px;justify-content:flex-end}#dsh-plan .p-dialog-row button{background:transparent;color:var(--ink);border:1px solid var(--card-line);border-radius:6px;padding:5px 12px;font:inherit;cursor:pointer}#dsh-plan .p-dialog-row button:hover{border-color:var(--accent)}#dsh-plan .p-dialog-row button:active{background:var(--uupm-wash-15)}#dsh-plan .p-dialog-row button:focus-visible{outline:2px solid var(--accent);outline-offset:1px}#dsh-plan .p-notice-stack{position:absolute;bottom:52px;left:50%;transform:translate(-50%);z-index:5;display:grid;gap:6px;justify-items:center;pointer-events:none}#dsh-plan .p-notice{max-width:60ch;padding:7px 12px;font-size:12px;color:var(--ink);background:var(--toolbar-bg);border:1px solid var(--card-line);border-radius:8px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#dsh-plan .p-notice.error{color:var(--error-ink);border-color:var(--uupm-error);background:var(--error-panel)}#dsh-plan .p-netbtn{color:var(--ink-muted)}#dsh-plan .p-netbtn:not([disabled]){color:var(--ink)}#dsh-plan .p-netmenu{max-height:240px;overflow:auto}#dsh-plan .p-nodebtn{color:var(--ink)}#dsh-plan .p-nodelist{min-width:300px;max-width:340px;max-height:420px;overflow:auto;padding:6px}#dsh-plan .p-nodelist-head{display:flex;align-items:center;justify-content:space-between;gap:8px;padding:2px 4px 6px;border-bottom:1px solid var(--card-line)}#dsh-plan .p-nodelist-title{font-size:12px;font-weight:600;color:var(--ink)}#dsh-plan .p-nodesel{font:inherit;font-size:11.5px;color:var(--ink);background:var(--uupm-bg-0);border:1px solid var(--card-line);border-radius:6px;padding:2px 6px;max-width:220px}#dsh-plan .p-nodesel:focus-visible{outline:2px solid var(--accent);outline-offset:1px}#dsh-plan .p-nodelist-group{font-size:11px;color:var(--ink-muted);padding:8px 4px 3px;display:flex;align-items:baseline;gap:8px}#dsh-plan .p-nodelist-note{font-size:10px;color:var(--ink-muted);opacity:.8}#dsh-plan .p-noderow{display:flex;align-items:center;gap:6px;padding:3px 4px;border-radius:6px;font-size:12px;color:var(--ink)}#dsh-plan .p-noderow:hover{background:var(--uupm-wash-8)}#dsh-plan .p-nodedot{flex:none;width:7px;height:7px;border-radius:50%;background:var(--edge-live)}#dsh-plan .p-nodedot.cold{background:var(--ink-muted)}#dsh-plan .p-nodedot.off{background:transparent;border:1px solid var(--ink-muted)}#dsh-plan .p-nodename{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}#dsh-plan .p-nonet{flex:none;font-size:10px;color:var(--uupm-warn);border:1px solid var(--uupm-warn);border-radius:4px;padding:0 4px}#dsh-plan .p-teamcount{flex:none;font-size:10px;color:var(--ink-muted);border:1px solid var(--card-line);border-radius:4px;padding:0 4px}#dsh-plan .p-listbtn{flex:none;background:transparent;color:var(--ink);border:1px solid var(--card-line);border-radius:5px;padding:1px 7px;font:inherit;font-size:11px;cursor:pointer}#dsh-plan .p-listbtn:hover{border-color:var(--card-line-hover);background:var(--uupm-wash-8)}#dsh-plan .p-listbtn:focus-visible{outline:2px solid var(--accent);outline-offset:1px}#dsh-plan .p-nodelist-empty{padding:10px 4px;font-size:11.5px;color:var(--ink-muted)}#dsh-plan .p-frame{position:absolute}#dsh-plan .p-frame-handle{position:absolute;pointer-events:auto;width:10px;height:10px;z-index:2;opacity:0;transition:opacity .12s ease}#dsh-plan .p-frame:hover .p-frame-handle{opacity:1}#dsh-plan .p-frame-handle:after{content:"";position:absolute;top:2px;right:2px;bottom:2px;left:2px;background:var(--frame-ink);border-radius:2px}#dsh-plan .p-h-n{top:-5px;left:calc(50% - 12px);width:24px;height:8px;cursor:ns-resize}#dsh-plan .p-h-s{bottom:-5px;left:calc(50% - 12px);width:24px;height:8px;cursor:ns-resize}#dsh-plan .p-h-e{right:-5px;top:calc(50% - 12px);width:8px;height:24px;cursor:ew-resize}#dsh-plan .p-h-w{left:-5px;top:calc(50% - 12px);width:8px;height:24px;cursor:ew-resize}#dsh-plan .p-h-ne{top:-5px;right:-5px;cursor:nesw-resize}#dsh-plan .p-h-nw{top:-5px;left:-5px;cursor:nwse-resize}#dsh-plan .p-h-se{bottom:-5px;right:-5px;cursor:nwse-resize}#dsh-plan .p-h-sw{bottom:-5px;left:-5px;cursor:nesw-resize}#dsh-plan .p-h-ne:after,#dsh-plan .p-h-sw:after{transform:rotate(45deg)}#dsh-plan .p-h-nw:after,#dsh-plan .p-h-se:after{transform:rotate(-45deg)}#dsh-plan .p-frame.selected .p-frame-handle{opacity:1}#dsh-plan .p-frame.selected{outline:1px solid var(--frame-ink)}:root{color-scheme:dark;--n-bg:#060a12;--n-ink:#dde3f0;--n-ink-muted:#7a86a0;--n-panel:#0d1322;--n-live:#4ade80;--n-cold:#7a86a0;--n-border:#223052;--n-act:#f59e0b;--n-danger:#f87171;--n-accent:#9673f7;--n-rail-w:300px;--n-canvas:#22d3ee;--n-line:var(--n-border);--n-raised:#131b2e;--n-federal:#6366f1;--n-card-line:#5c6680;--n-error-ink:#fecaca;--n-error-panel:#2a0d10f2;--n-shadow:rgba(0,0,0,.35);--n-role-user:#7dd3fc;--n-role-user-bg:rgba(56,189,248,.16);--n-role-assistant:#6ee7b7;--n-role-assistant-bg:rgba(52,211,153,.14)}@media (prefers-color-scheme: light){:root{--n-bg:#eef2fa;--n-ink:#1a2438;--n-ink-muted:#5a6580;--n-panel:#ffffff;--n-live:#157a37;--n-border:#c6d0e6;--n-act:#a84d08;--n-danger:#b91c1c;--n-accent:#6d28d9;--n-cold:#636c81;--n-canvas:#0e7490;--n-raised:#ffffff;--n-federal:#4f46e5;--n-card-line:#8a95ae;--n-error-ink:#b91c1c;--n-error-panel:#fef2f2f2;--n-shadow:rgba(26,36,56,.16);--n-role-user:#075985;--n-role-user-bg:rgba(14,116,144,.12);--n-role-assistant:#065f46;--n-role-assistant-bg:rgba(5,150,105,.12)}}@media (min-width:1440px){:root{--n-rail-w:340px }}html,body,#app{height:100%;margin:0}body{background:var(--n-bg);color:var(--n-ink);font:13px/1.45 system-ui,Segoe UI,Roboto,PingFang SC,Microsoft YaHei,sans-serif}.wb{display:flex;flex-direction:column;height:100%}.wb-header{display:flex;align-items:center;gap:12px;padding:8px 14px;border-bottom:1px solid var(--n-border);background:var(--n-panel)}.wb-title{display:flex;align-items:center;gap:10px;font-weight:600;font-size:14px;white-space:nowrap}.wb-badge{font-size:11px;font-weight:400;color:var(--n-ink-muted);border:1px solid var(--n-border);border-radius:99px;padding:1px 8px}.wb-header-stats{display:flex;gap:16px;font-size:12px;color:var(--n-ink-muted);flex-wrap:wrap;min-width:0}.wb-header-stats .wb-kv{display:flex;gap:6px}.wb-header-stats .wb-kv-k{color:var(--n-ink-muted)}.wb-header-stats .wb-kv-v{color:var(--n-ink)}.wb-header-ok{color:var(--n-ink-muted)}.wb-alert{border:1px solid currentColor;border-radius:99px;padding:0 9px;line-height:20px;white-space:nowrap;cursor:help}.wb-alert-danger{color:var(--n-danger)}.wb-alert-warn{color:var(--n-act)}.wb-forensics{font-family:ui-monospace,Consolas,monospace;font-size:11px}.wb-icon-btn{background:none;border:1px solid var(--n-border);color:var(--n-ink);border-radius:8px;width:30px;height:30px;display:none;align-items:center;justify-content:center;font:inherit;font-size:14px;cursor:pointer;flex:none}.wb-icon-btn:hover{border-color:var(--n-accent)}.wb-menu{margin-left:0}.wb-rail-toggle{margin-left:auto}.wb.is-rail-collapsed .wb-rail{display:none}.wb-body{position:relative;display:grid;grid-template-columns:minmax(0,var(--n-rail-w)) minmax(0,1fr);flex:1;min-height:0}.wb-rail{border-right:1px solid var(--n-border);overflow-y:auto;min-width:0;background:color-mix(in srgb,var(--n-panel) 60%,var(--n-bg))}.wb-sec{border-bottom:1px solid color-mix(in srgb,var(--n-border) 60%,transparent)}.wb-sec-head{display:flex;justify-content:space-between;align-items:center;gap:8px;width:100%;background:none;border:none;color:var(--n-ink);font:inherit;font-weight:600;font-size:12.5px;padding:8px 12px;cursor:pointer;text-transform:uppercase;letter-spacing:.05em}.wb-sec-head:hover{color:var(--n-accent)}.wb-sec-count{font-weight:400;font-size:11px;color:var(--n-ink-muted)}.wb-sec.is-collapsed .wb-sec-body{display:none}.wb-sec-body{padding:2px 10px 10px}.wb[data-mode=data] .wb-sec[data-sec=ledger],.wb[data-mode=data] .wb-sec[data-sec=activity],.wb[data-mode=data] .wb-sec[data-sec=plan]{display:none}.wb-side-head{font-size:11px;text-transform:uppercase;letter-spacing:.06em;color:var(--n-ink-muted);margin:10px 2px 4px}.wb-item{display:flex;gap:7px;align-items:center;width:100%;text-align:left;background:none;border:none;color:var(--n-ink);font:inherit;padding:3px 6px;border-radius:6px;cursor:pointer}.wb-item:hover{background:color-mix(in srgb,var(--n-accent) 14%,transparent)}.wb-dot{font-size:10px}.wb-dot-live{color:var(--n-live)}.wb-dot-cold{color:var(--n-cold)}.wb-dot-canvas{color:var(--n-canvas)}.wb-dot-peer{color:var(--n-accent)}.wb-dot-remote{color:var(--n-act)}.wb-item-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.wb-dir-tools{display:flex;flex-direction:column;gap:6px;padding:8px 6px 4px}.wb-search{background:var(--n-panel);border:1px solid var(--n-border);color:var(--n-ink);border-radius:6px;padding:4px 8px;font:inherit;font-size:12.5px;min-width:0}.wb-search:focus{outline:1px solid var(--n-accent)}.wb-filters{display:flex;flex-wrap:wrap;gap:4px}.wb-filter{background:none;border:1px solid var(--n-border);color:var(--n-ink-muted);border-radius:99px;padding:1px 9px;font:inherit;font-size:11.5px;cursor:pointer}.wb-filter:hover{border-color:var(--n-accent);color:var(--n-ink)}.wb-filter.is-active{border-color:var(--n-accent);color:var(--n-ink);background:color-mix(in srgb,var(--n-accent) 16%,transparent)}.wb-item-badge{flex:none;font-size:10.5px;color:var(--n-canvas);border:1px solid color-mix(in srgb,var(--n-canvas) 45%,transparent);border-radius:99px;padding:0 6px;line-height:17px;white-space:nowrap}.wb-item-label{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:46%}.wb-member-row{display:flex;align-items:center;gap:8px;padding:3px 2px;border-radius:6px}.wb-member-row:hover{background:color-mix(in srgb,var(--n-accent) 10%,transparent)}.wb-member-dot{flex:none;font-size:11px;color:var(--n-ink-muted);min-width:44px}.wb-member-label{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.wb-member-remove,.wb-member-submit{background:none;border:1px solid var(--n-border);color:var(--n-ink);border-radius:6px;padding:1px 8px;font:inherit;font-size:11.5px;cursor:pointer;flex:none}.wb-member-remove:hover:not(:disabled),.wb-member-submit:hover:not(:disabled){border-color:var(--n-danger)}.wb-member-submit:hover:not(:disabled){border-color:var(--n-accent)}.wb-member-add{display:flex;flex-wrap:wrap;gap:6px;margin-top:6px}.wb-member-pick,.wb-member-manual{background:var(--n-panel);border:1px solid var(--n-border);color:var(--n-ink);border-radius:6px;padding:3px 8px;font:inherit;font-size:12px;min-width:0}.wb-member-pick{flex:1 1 150px}.wb-member-manual{flex:1 1 130px}.wb-member-pick:focus,.wb-member-manual:focus{outline:1px solid var(--n-accent)}.wb-hint{margin-top:10px;font-size:11px;color:var(--n-ink-muted);line-height:1.5}.wb-dispatch{margin-top:12px;border-top:1px dashed var(--n-border);padding-top:8px}.wb-dispatch-form{display:flex;flex-direction:column;gap:6px;margin-top:6px}.wb-dispatch-text{background:var(--n-panel);border:1px solid var(--n-border);color:var(--n-ink);border-radius:6px;padding:5px 8px;font:inherit;font-size:12px;min-height:52px;resize:vertical}.wb-dispatch-text:focus{outline:1px solid var(--n-accent)}.wb-dispatch-submit{align-self:flex-end;background:none;border:1px solid var(--n-border);color:var(--n-ink);border-radius:6px;padding:2px 14px;font:inherit;font-size:11.5px;cursor:pointer}.wb-dispatch-submit:hover:not(:disabled){border-color:var(--n-accent)}.wb-dispatch-note{font-size:11px;color:var(--n-ink-muted);line-height:1.4;min-height:0}.wb-transcript{display:flex;flex-direction:column;gap:6px}.wb-transcript-title{font-size:12px;color:var(--n-ink-muted)}.wb-transcript-body.is-folded{display:none}.wb-transcript-refresh{margin-left:auto;font-size:11px;padding:1px 8px;border-radius:999px;border:1px solid var(--n-line);background:transparent;color:var(--n-ink-muted);cursor:pointer}.wb-transcript-body{display:flex;flex-direction:column;gap:4px;max-height:220px;overflow-y:auto}.wb-transcript-row{display:flex;gap:6px;align-items:flex-start;font-size:12px;line-height:1.45}.wb-transcript-role{flex:0 0 auto;font-size:10px;padding:0 5px;border-radius:999px;margin-top:2px}.wb-transcript-user .wb-transcript-role{background:var(--n-role-user-bg);color:var(--n-role-user)}.wb-transcript-assistant .wb-transcript-role{background:var(--n-role-assistant-bg);color:var(--n-role-assistant)}.wb-transcript-text{flex:1 1 auto;min-width:0;color:var(--n-ink);word-break:break-word}.wb-stage{position:relative;min-width:0;min-height:0;display:flex;flex-direction:column}.wb-stage-board{position:absolute;top:0;right:0;bottom:0;left:0;overflow:hidden}.wb-stage-board.is-hidden{display:none}.wb-data{display:flex;flex-direction:column;gap:14px;padding:10px 14px;overflow-y:auto;min-height:0}.wb-data.is-hidden{display:none}.wb-pane-head{font-size:12px;color:var(--n-ink-muted);margin:4px 0 8px}.wb-pane-subhead{font-size:11px;text-transform:uppercase;letter-spacing:.06em;color:var(--n-ink-muted);margin:12px 0 6px}.wb-table,.wb-row{display:flex;gap:10px;align-items:baseline}.wb-table{flex-direction:column;gap:2px}.wb-row{font-family:ui-monospace,Consolas,monospace;font-size:12px;background:color-mix(in srgb,var(--n-panel) 55%,transparent);border:1px solid var(--n-border);border-radius:6px;padding:3px 8px;flex-wrap:wrap}.wb-row-id{min-width:130px}.wb-row-team{color:var(--n-accent);min-width:150px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.wb-row-meta{color:var(--n-ink-muted)}.wb-row-result{flex-direction:column;align-items:stretch;gap:2px;flex-wrap:nowrap}.wb-row-head{color:var(--n-ink);font-size:12.5px;font-family:Avenir Next,Segoe UI Variable,Segoe UI,sans-serif;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.wb-row-meta-line{color:var(--n-ink-muted);font-family:ui-monospace,Consolas,monospace;font-size:11px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.wb-row-result:not(.wb-row-alert) .wb-row-head{color:var(--n-ink-muted)}.wb-row-alert{border-color:var(--n-danger)}.wb-row-alert .wb-row-head{color:var(--n-danger)}.wb-row-brief{flex:1 1 160px;min-width:0;color:var(--n-ink);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.wb-row-brief:empty{flex:0 0 0;display:none}.wb-row-badges{color:var(--n-live)}.wb-row-dir{min-width:16px}.wb-row-dir.is-fail{color:var(--n-danger)}.wb-btn{background:none;border:1px solid var(--n-border);color:var(--n-ink);border-radius:6px;padding:2px 10px;font:inherit;font-size:12px;cursor:pointer;margin-left:auto}.wb-btn:hover:not(:disabled){border-color:var(--n-accent)}.wb-btn:disabled{opacity:.5;cursor:default}.wb-btn-primary{border-color:var(--n-accent);color:var(--n-ink)}.wb-action{display:flex;gap:10px;align-items:baseline;font-size:12.5px;padding:5px 8px;border-radius:6px;border:1px solid var(--n-border);margin-bottom:4px}.wb-action-high{border-color:var(--n-danger)}.wb-action-text{flex:1}.wb-draft{display:flex;flex-direction:column;gap:8px;max-width:560px;margin-top:6px}.wb-select,.wb-textarea{background:var(--n-panel);border:1px solid var(--n-border);color:var(--n-ink);border-radius:8px;padding:6px 9px;font:inherit}.wb-textarea{resize:vertical}.wb-select:focus,.wb-textarea:focus{outline:1px solid var(--n-accent)}.wb-inspector{position:absolute;top:8px;right:8px;width:280px;max-height:calc(100% - 16px);overflow-y:auto;background:var(--n-panel);border:1px solid var(--n-border);border-radius:10px;padding:10px;z-index:20;box-shadow:0 8px 24px var(--n-shadow);display:none}.wb-inspector.is-open{display:block}.wb-inspector-head{display:flex;justify-content:space-between;align-items:center;margin-bottom:6px}.wb-inspector-title{font-weight:600;font-size:12.5px}.wb-inspector .wb-icon-btn{display:inline-flex;width:24px;height:24px;font-size:12px}.wb-card{display:flex;flex-direction:column;gap:6px}.wb-kv{display:flex;gap:8px;font-size:12px}.wb-kv-k{color:var(--n-ink-muted);min-width:58px;flex:none}.wb-kv-v{word-break:break-all}.wb-muted{color:var(--n-ink-muted)}.wb-chat{position:absolute;top:8px;right:8px;bottom:8px;width:360px;max-width:calc(100% - 16px);display:flex;flex-direction:column;background:var(--n-panel);border:1px solid var(--n-border);border-radius:10px;z-index:22;box-shadow:0 8px 24px var(--n-shadow);transform:translate(calc(100% + 12px));transition:transform .18s ease;pointer-events:none}.wb-chat.is-open{transform:translate(0);pointer-events:auto}.wb-chat-head{display:flex;align-items:center;gap:8px;padding:10px 10px 8px;border-bottom:1px solid var(--n-border)}.wb-chat-dot{flex:none;font-size:11px}.wb-chat-dot.is-live{color:var(--n-accent)}.wb-chat-dot.is-cold{color:var(--n-ink-muted)}.wb-chat-dot.is-peer{color:var(--n-act)}.wb-chat-title{font-weight:600;font-size:13px;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.wb-chat-sub{flex:1 1 auto;min-width:0;font-size:11px;color:var(--n-ink-muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.wb-chat .wb-icon-btn{display:inline-flex;width:24px;height:24px;font-size:12px;flex:none}.wb-chat-body{flex:1 1 auto;overflow-y:auto;padding:10px;display:flex;flex-direction:column;gap:10px}.wb-chat-note{font-size:12px;color:var(--n-ink-muted);border:1px dashed var(--n-border);border-radius:8px;padding:8px 10px}.wb-stats{display:flex;gap:8px;flex-wrap:wrap;margin:2px 0 10px}.wb-stat{display:inline-flex;align-items:baseline;gap:6px;padding:4px 10px;border-radius:8px;border:1px solid var(--n-border);background:color-mix(in srgb,var(--n-panel) 70%,transparent);cursor:help}.wb-stat-k{font-size:11px;color:var(--n-ink-muted)}.wb-stat-v{font-family:ui-monospace,Consolas,monospace;font-size:14px;font-weight:600}.wb-stat-warn{border-color:var(--n-act)}.wb-stat-warn .wb-stat-v{color:var(--n-act)}.wb-stat-danger{border-color:var(--n-danger)}.wb-stat-danger .wb-stat-v{color:var(--n-danger)}.wb-hist{display:flex;flex-direction:column;gap:3px;margin:2px 0 8px;max-width:420px}.wb-bar-row{display:flex;align-items:center;gap:8px;font-size:11px}.wb-bar-k{color:var(--n-ink-muted);min-width:52px;flex:none;text-align:right}.wb-bar-track{flex:1;height:9px;border-radius:4px;overflow:hidden;background:color-mix(in srgb,var(--n-border) 55%,transparent)}.wb-bar-fill{display:block;height:100%;border-radius:4px;background:var(--n-accent)}.wb-bar-v{font-family:ui-monospace,Consolas,monospace;color:var(--n-ink-muted);min-width:28px}.nexus-fault{display:none;position:fixed;top:10px;right:12px;z-index:50;max-width:420px;font:12px/1.5 ui-monospace,Consolas,monospace;color:var(--n-error-ink);background:var(--n-error-panel);border:1px solid var(--n-danger);border-radius:8px;padding:6px 10px;pointer-events:none}@media (max-width:1023px){.wb-menu{display:inline-flex}.wb-rail-toggle{display:none}.wb-body{grid-template-columns:minmax(0,1fr)}.wb-rail{position:fixed;left:0;top:0;bottom:0;width:min(86vw,320px);z-index:40;background:var(--n-panel);border-right:1px solid var(--n-border);transform:translate(-102%);transition:transform .18s ease;box-shadow:8px 0 24px var(--n-shadow)}.wb.is-rail-open .wb-rail{transform:translate(0)}.wb-inspector{left:8px;right:8px;width:auto;top:auto;bottom:8px;max-height:45%}.wb-chat{left:8px;right:8px;width:auto;top:auto;bottom:8px;max-height:70%;transform:translateY(102%)}.wb-chat.is-open{transform:translateY(0)}}@media (pointer:coarse){.wb-filter,.wb-item,.wb-sec-head{min-height:36px}.wb-icon-btn,.wb-inspector .wb-icon-btn,.wb-chat .wb-icon-btn{width:36px;height:36px}}@media (max-width:680px){.wb-header{flex-wrap:wrap;row-gap:4px}.wb-header-stats{order:3;width:100%}.wb-row-team{min-width:0;flex:1 1 auto}.wb-data{padding:8px}}
@@ -1,73 +0,0 @@
1
- /**
2
- * In-process decentralized A2A client: the outbound peer surface — verified
3
- * agent-card fetches (discovery) and direct routes to a peer's
4
- * `/a2a/direct` endpoint. Timing and fetch seams are constructor-injected so
5
- * tests drive them without a network.
6
- * @module @nelsonlongxiang/dsh-open-a2a-net/client
7
- */
8
- import type { A2aPeerCard, A2aRouteResult } from './types.ts';
9
- /** One-shot delayed callback returning its disposer. */
10
- export type A2aSchedule = (callback: () => void, delayMs: number) => () => void;
11
- /** Minimal fetch face; the first HTTP-level failure rejects. */
12
- export type A2aFetch = (url: string, init: {
13
- readonly method: 'GET' | 'POST';
14
- readonly headers: Record<string, string>;
15
- readonly body?: string;
16
- readonly signal?: AbortSignal;
17
- }) => Promise<{
18
- readonly ok: boolean;
19
- readonly status: number;
20
- readonly text: () => Promise<string>;
21
- }>;
22
- /** Constructor facts; every seam is explicit so tests inject doubles. */
23
- export interface A2aClientOptions {
24
- /** `X-API-Key` value sent on peer requests; empty omits the header. */
25
- readonly apiKey: string;
26
- /** This node's caller label stamped on outbound routes. */
27
- readonly sessionId: string;
28
- /** Delayed-callback seam (HTTP timeouts). */
29
- readonly schedule: A2aSchedule;
30
- /** HTTP seam. */
31
- readonly fetch: A2aFetch;
32
- }
33
- /**
34
- * The A2A peer client. One instance serves the whole fiber's outbound
35
- * card fetches and direct routes; it owns no connection state.
36
- */
37
- export declare class A2aClient {
38
- private readonly options;
39
- /** @param options - resolved caller facts and injected seams. */
40
- constructor(options: A2aClientOptions);
41
- private headers;
42
- private http;
43
- /**
44
- * Fetch one peer's agent card (discovery): team, session, capabilities.
45
- * The card is verified at parse — unsigned, badly signed, or expired cards
46
- * are rejected here, so a stale peer disappears from discovery without any
47
- * background cleanup.
48
- * @param baseUrl - the peer's base URL.
49
- * @returns the verified card, or `undefined` when unreachable, malformed, or rejected.
50
- */
51
- fetchCard(baseUrl: string): Promise<A2aPeerCard | undefined>;
52
- /**
53
- * Extract the reply text from a route result member: the wire carries a
54
- * plain string, a `{text}` object, or anything else JSON-encoded.
55
- * @param inner - the raw `result` member of a route response.
56
- * @param fallback - what a nullish member encodes as.
57
- * @returns the reply text.
58
- */
59
- private replyText;
60
- /**
61
- * Route directly to a peer node's `/a2a/direct` endpoint. The peer steers
62
- * the message into its live agent (or the named session team's agent) and
63
- * answers within its own final-reply budget.
64
- * @param baseUrl - the peer's base URL.
65
- * @param team - target team name (the peer's own or a session team).
66
- * @param message - request text.
67
- * @param contextId - context id from a prior reply, for multi-turn.
68
- * @param signal - caller cancellation.
69
- * @param callerSession - caller label overriding the node's label (the calling session's node label).
70
- * @returns the canonical route result (success or explicit failure).
71
- */
72
- routeDirect(baseUrl: string, team: string, message: string, contextId?: string, signal?: AbortSignal, callerSession?: string): Promise<A2aRouteResult>;
73
- }